def test_notify_creates_multiple_new_issues(self, get_config_mock): """Test notifier creates multiple GH issues when none exist.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'foo': { 'repo': ['foo/bar'], 'status': ['fail', 'pass'] } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.assertEqual(self.search_issues_mock.call_count, 2) self.search_issues_mock.assert_any_call( 'fail_example type:issue in:title is:open repo:foo/bar' ) self.search_issues_mock.assert_any_call( 'pass_example type:issue in:title is:open repo:foo/bar' ) self.assertEqual(self.add_issue_mock.call_count, 2) self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()
def test_add_issue_to_project_found(self, get_config_mock): """Test issue is not added to project if issue already assigned.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'accred_foo': { 'repo': ['foo/bar'], 'project': { 'valid-project': 'valid-column' }, 'summary_issue': { 'title': 'foo-title' } } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['accred_foo'] self.search_issues_mock.return_value = [ { 'id': 1, 'number': 123, 'labels': [ { 'name': 'accreditation: foo', 'other': 'junk' }, { 'name': 'run status: pass', 'other': 'junk' } ], 'title': 'foo-title', 'url': '123.url' } ] self.get_all_projects_mock.return_value = [ { 'id': 1, 'name': 'valid-project' } ] self.get_columns_mock.return_value = [ { 'id': 11, 'name': 'valid-column' } ] self.get_all_cards_mock.return_value = { 11: [{ 'content_url': '123.url' }] } notifier = GHIssuesNotifier(self.results, controls) notifier.logger.warning = MagicMock() notifier.notify() self.get_all_projects_mock.assert_called_once_with('foo/bar') self.get_columns_mock.assert_called_once_with(1) self.get_all_cards_mock.assert_called_once() self.add_card_mock.assert_not_called() notifier.logger.warning.assert_not_called()
def test_add_issue_to_project_no_config(self, get_config_mock): """Test issue is not added to project without config.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'accred_foo': { 'repo': ['foo/bar'], 'summary_issue': { 'title': 'foo-title' } } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['accred_foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.logger.warning = MagicMock() notifier.notify() self.get_all_projects_mock.assert_not_called() self.get_columns_mock.assert_not_called() self.get_all_cards_mock.assert_not_called() self.add_card_mock.assert_not_called() notifier.logger.warning.assert_not_called()
def test_notify_summary_issue_year_rotation_1( self, get_config_mock, datetime_mock ): """Test new yearly summary issue created and assigned to rota 1.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'accred_foo': { 'repo': ['foo/bar'], 'summary_issue': { 'title': 'foo-title', 'labels': ['label:foo', 'foo:label'], 'message': ['blah blah', 'foo message'], 'frequency': 'year', 'rotation': [['the-dude'], ['walter', 'donnie']] } } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock datetime_mock.utcnow.return_value = datetime(2019, 7, 31) # Year 2019 controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['accred_foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.search_issues_mock.assert_called_once_with( '2019 - foo-title type:issue in:title is:open repo:foo/bar' ) self.assertEqual(self.add_issue_mock.call_count, 1) args, kwargs = self.add_issue_mock.call_args self.assertEqual(len(args), 4) self.assertEqual(args[0], 'foo') self.assertEqual(args[1], 'bar') self.assertEqual(args[2], '2019 - foo-title') self.assertTrue(args[3].startswith('blah blah\nfoo message\n')) self.assertTrue('### Passed Checks' in args[3]) self.assertTrue('### Errored Checks' in args[3]) self.assertTrue('### Failures/Warnings' in args[3]) self.assertEqual( kwargs, { 'assignees': ['walter', 'donnie'], 'labels': ['label:foo', 'foo:label', 'year', '2019'] } ) self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()
def test_notify_adds_label_and_comment_to_issue(self, get_config_mock): """Test notifier updates labels, adds comment on existing GH issue.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'foo': { 'repo': ['foo/bar'], 'status': ['pass'] } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['foo'] self.search_issues_mock.return_value = [ { 'id': 1, 'number': 123, 'labels': [ { 'name': 'accreditation: foo', 'other': 'junk' }, { 'name': 'run status: warn', 'other': 'junk' } ], 'title': 'pass_example', 'url': '123.url' } ] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.search_issues_mock.assert_called_once_with( 'pass_example type:issue in:title is:open repo:foo/bar' ) self.add_issue_mock.assert_not_called() self.patch_issue_mock.assert_called_once_with( 'foo', 'bar', 123, labels=['accreditation: foo', 'run status: pass'] ) self.assertEqual(self.add_issue_comment_mock.call_count, 1) args, kwargs = self.add_issue_comment_mock.call_args self.assertEqual(len(args), 4) self.assertEqual(args[0], 'foo') self.assertEqual(args[1], 'bar') self.assertEqual(args[2], 123) self.assertTrue(args[3].startswith('## Compliance check alert')) self.assertEqual(kwargs, {})
def test_notify_summary_issue_w_labels(self, get_config_mock): """Test notifier creates a new summary issue with labels only.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'accred_foo': { 'repo': ['foo/bar'], 'summary_issue': { 'title': 'foo-title', 'labels': ['label:foo', 'foo:label'] } } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['accred_foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.search_issues_mock.assert_called_once_with( 'foo-title type:issue in:title is:open repo:foo/bar' ) self.assertEqual(self.add_issue_mock.call_count, 1) args, kwargs = self.add_issue_mock.call_args self.assertEqual(len(args), 4) self.assertEqual(args[0], 'foo') self.assertEqual(args[1], 'bar') self.assertEqual(args[2], 'foo-title') self.assertTrue(args[3].startswith('# CHECK RESULTS:')) self.assertTrue('### Passed Checks' in args[3]) self.assertTrue('### Errored Checks' in args[3]) self.assertTrue('### Failures/Warnings' in args[3]) self.assertEqual( kwargs, { 'assignees': [], 'labels': ['label:foo', 'foo:label'] } ) self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()
def test_notify_old_alert_does_nothing(self, get_config_mock): """Test notifier does not notify for passed check w/out open issue.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'foo': { 'repo': ['foo/bar'], 'status': ['fail'] } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.assertEqual(self.search_issues_mock.call_count, 2) self.search_issues_mock.assert_any_call( 'fail_example type:issue in:title is:open repo:foo/bar' ) self.search_issues_mock.assert_any_call( 'pass_example type:issue in:title is:open repo:foo/bar' ) self.assertEqual(self.add_issue_mock.call_count, 1) args, kwargs = self.add_issue_mock.call_args self.assertEqual(len(args), 4) self.assertEqual(args[0], 'foo') self.assertEqual(args[1], 'bar') self.assertEqual(args[2], 'fail_example') self.assertTrue(args[3].startswith('## Compliance check alert')) self.assertEqual( kwargs, { 'assignees': [], 'labels': ['accreditation: foo', 'run status: fail'] } ) self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()
def test_notify_creates_new_issue_partial_match(self, get_config_mock): """Test notifier creates new issue when partial title match exists.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'foo': { 'repo': ['foo/bar'], 'status': ['pass'] } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['foo'] self.search_issues_mock.return_value = [{'title': 'x pass_example x'}] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.search_issues_mock.assert_called_once_with( 'pass_example type:issue in:title is:open repo:foo/bar' ) self.assertEqual(self.add_issue_mock.call_count, 1) args, kwargs = self.add_issue_mock.call_args self.assertEqual(len(args), 4) self.assertEqual(args[0], 'foo') self.assertEqual(args[1], 'bar') self.assertEqual(args[2], 'pass_example') self.assertTrue(args[3].startswith('## Compliance check alert')) self.assertEqual( kwargs, { 'assignees': [], 'labels': ['accreditation: foo', 'run status: pass'] } ) self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()
def test_notify_alerts_in_multiple_repos(self, get_config_mock): """Test notifier notifies in multiple repositories.""" config_mock = create_autospec(ComplianceConfig) config_mock.get.side_effect = [ { 'foo': { 'repo': ['foo/bar', 'bing/bong'], 'status': ['pass'] } }, 'https://github.com/foo/bar' ] get_config_mock.return_value = config_mock controls = create_autospec(ControlDescriptor) controls.get_accreditations.return_value = ['foo'] self.search_issues_mock.return_value = [] notifier = GHIssuesNotifier(self.results, controls) notifier.notify() self.assertEqual(self.search_issues_mock.call_count, 2) self.search_issues_mock.assert_any_call( 'pass_example type:issue in:title is:open repo:foo/bar' ) self.search_issues_mock.assert_any_call( 'pass_example type:issue in:title is:open repo:bing/bong' ) self.assertEqual(self.add_issue_mock.call_count, 2) foo_bar_call_args, _ = self.add_issue_mock.call_args_list[0] bing_bong_call_args, _ = self.add_issue_mock.call_args_list[1] self.assertEqual(foo_bar_call_args[0], 'foo') self.assertEqual(foo_bar_call_args[1], 'bar') self.assertEqual(bing_bong_call_args[0], 'bing') self.assertEqual(bing_bong_call_args[1], 'bong') self.patch_issue_mock.assert_not_called() self.add_issue_comment_mock.assert_not_called()