def test_iter_issue_batches_error(self): """Tests handling error fetching issues from Issue Tracer in batches.""" cli_mock = mock.MagicMock() cli_mock.search.side_effect = integrations_errors.HttpError('Test') with mock.patch.object(utils.issues, 'Client', return_value=cli_mock): actual = list(utils._iter_issue_batches([1, 2, 3])) self.assertEqual(actual, [])
def test_issue_tracker_error(self, update_issue_mock): """Test issue tracker errors. Issue in Issue tracker doesn't change state in case receiving an error. """ iti = factories.IssueTrackerIssueFactory( enabled=True, issue_tracked_obj=factories.IssueFactory() ) update_issue_mock.side_effect = integrations_errors.HttpError("data") issue_attrs = { "issue_tracker": { "enabled": True, "hotlist_id": "123", "issue_id": iti.issue_id, } } with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True),\ mock.patch.object(all_models.IssuetrackerIssue, "create_or_update_from_dict") as update_info_mock: self.api.put(iti.issue_tracked_obj, issue_attrs) # Check that "enabled" flag hasn't been changed. self.assertTrue("enabled" not in update_info_mock.call_args[0][1])
def test_update_issue_with_raise(self): """Tests updating issue with raising an exception.""" cli_mock = mock.MagicMock() exception = integrations_errors.HttpError('Test', status=429) cli_mock.update_issue.side_effect = iter([ exception, exception, exception, exception, exception, ]) with mock.patch.object(utils.time, 'sleep') as sleep_mock: with self.assertRaises(integrations_errors.HttpError) as exc_mock: utils._update_issue(cli_mock, 1, 'params') self.assertEqual(exc_mock.exception.status, 429) self.assertEqual(cli_mock.update_issue.call_args_list, [ mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), ]) self.assertEqual(sleep_mock.call_args_list, [ mock.call(1), mock.call(1), mock.call(1), mock.call(1), ])
def test_rate_limited_update(self): """Test tickets update when issuetracker raise 429 error.""" _, assessment_ids = self.setup_assessments(3) for issue in all_models.IssuetrackerIssue.query.all(): issue.issue_id = self.issue_id db.session.commit() error = integrations_errors.HttpError(data="Test Error", status=429) with mock.patch("ggrc.integrations.issues.Client.update_issue", side_effect=error) as update_issue_mock: with mock.patch("time.sleep"): response = self.api.send_request(self.api.client.post, api_link="/update_issues", data={ "objects": [{ "type": "Assessment", "id": id_ } for id_ in assessment_ids ], }) self.assert200(response) expected_errors = [["Assessment", id_, "429 Test Error"] for id_ in assessment_ids] self.assertEqual(response.json.get("errors"), expected_errors) # 10 times for each assessment self.assertEqual(update_issue_mock.call_count, 30)
def test_invalid_component_id(self, error): """Test generation of issues if '{}' error raised.""" audit_id, assessment_ids = self.setup_assessments(3) error = error.format("12345") with mock.patch("ggrc.integrations.issues.Client.create_issue", side_effect=integrations_errors.HttpError( error)) as create_issue_mock: response = self.api.send_request( self.api.client.post, api_link="/generate_children_issues", data={ "parent": { "type": "Audit", "id": audit_id }, "child_type": "Assessment" }) self.assert200(response) self.assertEqual( response.json.get("errors"), [["Assessment", assessment_ids[0], "500 {}".format(error)]]) self.assertEqual(create_issue_mock.call_count, 1) query = all_models.IssuetrackerIssue.query.filter( all_models.IssuetrackerIssue.issue_id.isnot(None)) self.assertEqual(query.count(), 0)
def test_update_issue_with_retry(self): """Tests updating issue with retry.""" cli_mock = mock.MagicMock() exception = integrations_errors.HttpError('Test', status=429) cli_mock.update_issue.side_effect = iter([ exception, exception, exception, exception, None, ]) with mock.patch.object(sync_utils.time, 'sleep') as sleep_mock: sync_utils.update_issue(cli_mock, 1, 'params') self.assertEqual(cli_mock.update_issue.call_args_list, [ mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), mock.call(1, 'params'), ]) self.assertEqual(sleep_mock.call_args_list, [ mock.call(1), mock.call(1), mock.call(1), mock.call(1), ])
def test_issue_tracker_error(self, issue_tracker_enabled, issue_id): """ Test that issue tracker does not change state in case receiving an error.""" with mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._update_issuetracker_issue') as update_issue_mock, \ mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._update_issuetracker_info') as update_info_mock, \ mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._collect_assessment_emails', side_effect=[(None, [])]): error_data = integrations_errors.HttpError('data') update_issue_mock.side_effect = error_data src = { 'issue_tracker': { 'enabled': issue_tracker_enabled, 'issue_id': issue_id } } all_models.IssuetrackerIssue.get_issue = mock.MagicMock() # pylint: disable=protected-access assessment_integration._handle_issuetracker(sender=None, obj=mock.MagicMock(), src=src) update_info_mock.assert_called_once() self.assertEqual(update_info_mock.call_args[0][1]['enabled'], issue_tracker_enabled)
def _perform_request(self, url, method=urlfetch.GET, payload=None, headers=None): """Performs request to given URL on integration service endpoint. Args: url: A string for request URL. method: A urlfetch method. payload: A string for request body. Ignored if method is not POST, PUT or PATCH. headers: An optional dict to use as HTTP headers. Returns: A string content from response. Raises: integrations_errors.HttpError: If not expected HTTP status occurs or fetch is not successful. """ headers = headers or {} if self.DEFAULT_HEADERS: headers.update(self.DEFAULT_HEADERS) url = urlparse.urljoin(self.ENDPOINT, url) try: response = urlfetch.fetch( url, method=method, payload=payload, headers=headers, follow_redirects=False, deadline=30, ) if response.status_code != 200: logging.error('Unable to perform request to %s: %s %s', url, response.status_code, response.content) raise integrations_errors.HttpError( response.content, status=response.status_code) return response.content except urlfetch_errors.Error as error: logging.exception('Unable to perform urlfetch request: %s', error) raise integrations_errors.HttpError('Unable to perform a request')
def test_integration_disabled_on_bulk_create_error(self, model): """Test if {} integration was disabled if bulk creation failed""" user = all_models.Person.query.first() with factories.single_commit(): obj = factories.get_model_factory(model)(modified_by=user) iti = factories.IssueTrackerIssueFactory( issue_tracked_obj=obj, enabled=True, issue_id=None, ) bulk_creator = issuetracker_bulk_sync.IssueTrackerBulkCreator() objects = [issuetracker_bulk_sync.IssuetrackedObjInfo(obj)] with mock.patch.object(bulk_creator, "sync_issue") as sync_mock: sync_mock.side_effect = integrations_errors.HttpError("error") bulk_creator.handle_issuetracker_sync(objects) sync_mock.assert_called_once() self.assertFalse(iti.enabled)
def test_issue_tracker_error(self, issue_tracker_enabled, issue_id): """ Test that issue tracker does not change state in case receiving an error.""" with mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._update_issuetracker_issue') as update_issue_mock, \ mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._update_issuetracker_info') as update_info_mock, \ mock.patch(self.ISSUE_TRACKED_NAMESPACE + '._collect_assessment_emails', side_effect=[(None, [])]), \ mock.patch.object(common_handlers, 'global_synchronization_enabled', return_value=True): error_data = integrations_errors.HttpError('data') update_issue_mock.side_effect = error_data src = { 'issue_tracker': { 'enabled': issue_tracker_enabled, 'issue_id': issue_id } } all_models.IssuetrackerIssue.get_issue = mock.MagicMock() # pylint: disable=protected-access issue_obj = mock.MagicMock() # pylint: disable=unused-argument def mock_to_dict(**kwargs): return {"issue_id": issue_id} issue_obj.to_dict = mock_to_dict with mock.patch( "ggrc.models.issuetracker_issue.IssuetrackerIssue.get_issue", return_value=issue_obj ): assessment_integration._handle_issuetracker(sender=None, obj=mock.MagicMock(), src=src) update_info_mock.assert_called_once() self.assertEqual(update_info_mock.call_args[0][1]['enabled'], issue_tracker_enabled)
def test_errors_task_status(self): """Test background task status if it failed.""" audit_id, assessment_ids = self.setup_assessments(2) with mock.patch( "ggrc.integrations.issues.Client.create_issue", side_effect=integrations_errors.HttpError("Test Error")): response = self.api.send_request( self.api.client.post, api_link="/generate_children_issues", data={ "parent": { "type": "Audit", "id": audit_id }, "child_type": "Assessment" }) self.assert200(response) url = "background_task_status/{}/{}".format("audit", audit_id) response = self.api.client.get(url) self.assert200(response) self.assertEqual(response.json.get("status"), "Success") self.assertEqual(response.json.get("errors"), [["Assessment", id_, "500 Test Error"] for id_ in assessment_ids])
class TestDisabledIssueIntegration(ggrc.TestCase): """Tests for IssueTracker integration functionality with disabled sync.""" def setUp(self): super(TestDisabledIssueIntegration, self).setUp() self.api = api_helper.Api() self.client.get("/login") @mock.patch("ggrc.integrations.issues.Client.create_issue") def test_issue_creation(self, mock_create_issue): """Test creating Issue object with disabled integration.""" with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): response = self.api.post( all_models.Issue, { "issue": { "title": "test title", "context": None, "issue_tracker": { "enabled": False, }, "due_date": "10/10/2019" }, }) mock_create_issue.assert_not_called() self.assertEqual(response.status_code, 201) issue_id = response.json.get("issue").get("id") issue_tracker_issue = models.IssuetrackerIssue.get_issue( "Issue", issue_id) self.assertIsNone(issue_tracker_issue) @mock.patch("ggrc.integrations.issues.Client.update_issue") def test_issue_deletion(self, mock_update_issue): """Test deleting Issue object with disabled integration for issue.""" iti = factories.IssueTrackerIssueFactory( enabled=False, issue_tracked_obj=factories.IssueFactory()) with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.delete(iti.issue_tracked_obj) mock_update_issue.assert_not_called() @ddt.data( { "description": "new description", "issue_tracker": { "issue_id": TICKET_ID, "enabled": False } }, { "test_plan": "new test plan", "issue_tracker": { "issue_id": TICKET_ID, "enabled": False } }, { "issue_tracker": { "issue_id": TICKET_ID, "component_id": "123", "enabled": False } }, { "issue_tracker": { "issue_id": TICKET_ID, "hotlist_id": "321", "enabled": False } }, { "issue_tracker": { "issue_id": TICKET_ID, "issue_priority": "P2", "enabled": False } }, { "issue_tracker": { "issue_id": TICKET_ID, "issue_severity": "S2", "enabled": False } }, { "issue_tracker": { "issue_id": TICKET_ID, "title": "title1", "enabled": False } }, ) @mock.patch("ggrc.integrations.issues.Client.update_issue") def test_update_issue_object(self, issue_attrs, mock_update_issue): """Test updating issue object with disabled integration for issue.""" iti = factories.IssueTrackerIssueFactory( enabled=False, issue_id=TICKET_ID, issue_tracked_obj=factories.IssueFactory()) with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.put(iti.issue_tracked_obj, issue_attrs) mock_update_issue.assert_not_called() @mock.patch("ggrc.integrations.issues.Client.create_issue", side_effect=[ integrations_errors.HttpError(data=''), { "issueId": "issueId" } ]) @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True) def test_issue_recreation(self, _): """Test retrying to turn on integration after failed creation.""" # Arrange data. component_id = "1234" hotlist_id = "4321" issue_type = "Default Issue type" issue_priority = "P2" issue_severity = "S1" title = "test title" issue_tracker_attrs = { "enabled": True, "component_id": int(component_id), "hotlist_id": int(hotlist_id), "issue_type": issue_type, "issue_priority": issue_priority, "issue_severity": issue_severity, } # Perform actions and assert results. with mock.patch.object(integration_utils, "exclude_auditor_emails", return_value={ u"*****@*****.**", }): # Try to create issue. create_issue should raise exception here. response = self.api.post( all_models.Issue, { "issue": { "title": title, "context": None, "issue_tracker": issue_tracker_attrs, "due_date": "10/10/2019" }, }) issue_id = response.json.get("issue").get("id") issue_tracker_issue = models.IssuetrackerIssue.get_issue( "Issue", issue_id) self.assertIsNone(issue_tracker_issue.issue_id) self.assertIsNone(issue_tracker_issue.issue_url) # Try to turn on integration on already created issue. self.api.put(issue_tracker_issue.issue_tracked_obj, {"issue_tracker": issue_tracker_attrs}) issue_id = issue_tracker_issue.issue_tracked_obj.id issue_tracker_issue = models.IssuetrackerIssue.get_issue( "Issue", issue_id) self.assertEqual(issue_tracker_issue.issue_url, "http://issue/issueId") @mock.patch("ggrc.integrations.issues.Client.update_issue") def test_adding_comment_to_issue(self, update_issue_mock): """Test not adding comment to issue when issue tracker disabled.""" iti = factories.IssueTrackerIssueFactory( enabled=False, issue_tracked_obj=factories.IssueFactory()) comment = factories.CommentFactory(description="test comment") with mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True): self.api.post( all_models.Relationship, { "relationship": { "source": { "id": iti.issue_tracked_obj.id, "type": "Issue" }, "destination": { "id": comment.id, "type": "comment" }, "context": None }, }) update_issue_mock.assert_not_called() @mock.patch("ggrc.integrations.issues.Client.create_issue", side_effect=[integrations_errors.HotlistPermissionError()]) @mock.patch.object(settings, "ISSUE_TRACKER_ENABLED", True) def test_no_permissions_hotlist(self, _): """Test warning message if no permissions to Hotlist.""" issue_tracker_attrs = { "enabled": True, "component_id": 1234, "hotlist_id": 4321, "issue_type": "Default Issue type", "issue_priority": "P2", "issue_severity": "S1", } response = self.api.post( all_models.Issue, { "issue": { "title": "test title", "context": None, "issue_tracker": issue_tracker_attrs, "due_date": "10/10/2019" }, }) self.assertIn( constants.WarningsDescription.HOTLIST_PERMISSIONS_ERROR, response.json.get("issue", {}).get("issue_tracker", {}).get("_warnings", []))