def test_default_project(self, jira): """ The default_project should get used when project_key_regex doesn't match """ self.settings['project_key_regex'] = 'regex_that_does_not_match_any_id' self.general_fields['project'] = self.settings['default_project'] jira_mock = jira.return_value jira_mock.search_issues.return_value = [] dut.create_jira_issues(self.settings, self.coll) self.assertEqual( jira_mock.create_issue.call_args_list, [ mock.call( summary='MEETING-12345_2: Action 1\'s caption?', description='Description for action 1', assignee={'name': 'ABC'}, **self.general_fields ), mock.call( summary='Caption for action 2', description='Caption for action 2', assignee={'name': 'ZZZ'}, **self.general_fields ), ])
def test_missing_username(self, *_): self.settings.pop('username') with self.assertLogs(level=WARNING) as cm: dut.create_jira_issues(self.settings, None) self.assertEqual( cm.output, ["WARNING:sphinx.mlx.jira_interaction:Jira interaction failed: configuration is " "missing mandatory values for keys ['username']"] )
def test_missing_all_mandatory(self, *_): mandatory_keys = ['api_endpoint', 'username', 'password', 'item_to_ticket_regex', 'issue_type'] for key in mandatory_keys: self.settings.pop(key) with self.assertLogs(level=WARNING) as cm: dut.create_jira_issues(self.settings, None) self.assertEqual( cm.output, ["WARNING:sphinx.mlx.jira_interaction:Jira interaction failed: configuration is " "missing mandatory values for keys {}".format(mandatory_keys)] )
def test_missing_all_optional_one_mandatory(self, *_): keys_to_remove = ['components', 'project_key_prefix', 'project_key_regex', 'default_project', 'relationship_to_parent', 'warn_if_exists', 'catch_errors', 'password'] for key in keys_to_remove: self.settings.pop(key) with self.assertLogs(level=WARNING) as cm: dut.create_jira_issues(self.settings, None) self.assertEqual( cm.output, ["WARNING:sphinx.mlx.jira_interaction:Jira interaction failed: configuration is " "missing mandatory values for keys ['password']"] )
def test_create_jira_issues_unique(self, jira): jira_mock = jira.return_value jira_mock.search_issues.return_value = [] with self.assertLogs(level=WARNING) as cm: warning('Dummy log') dut.create_jira_issues(self.settings, self.coll) self.assertEqual( cm.output, ['WARNING:root:Dummy log'] ) self.assertEqual(jira.call_args, mock.call({'server': 'https://jira.atlassian.com/rest/api/latest/'}, basic_auth=('my_username', 'my_password'))) self.assertEqual(jira_mock.search_issues.call_args_list, [ mock.call( 'project=MLX12345 and summary ~ "MEETING\\\\-12345_2\\\\: Action 1\'s caption\\\\?"'), mock.call("project=MLX12345 and summary ~ 'Caption for action 2'"), ]) issue = jira_mock.create_issue.return_value self.assertEqual( jira_mock.create_issue.call_args_list, [ mock.call( summary='MEETING-12345_2: Action 1\'s caption?', description='Description for action 1', assignee={'name': 'ABC'}, **self.general_fields ), mock.call( summary='Caption for action 2', description='Caption for action 2', assignee={'name': 'ZZZ'}, **self.general_fields ), ]) self.assertEqual( issue.update.call_args_list, [mock.call(update={'timetracking': [{"edit": {"originalEstimate": '2w 3d 4h 55m'}}]})] ) # attendees added for action1 since it is linked with depends_on to parent item with ``attendees`` attribute self.assertEqual(jira_mock.add_watcher.call_args_list, [ mock.call(issue, 'ABC'), mock.call(issue, 'ZZZ'), ]) self.assertEqual(jira_mock.assign_issue.call_args_list, [])
def test_no_warning_about_duplication(self, jira): """ Default behavior should be no warning when a Jira ticket doesn't get created to prevent duplication """ self.settings.pop('warn_if_exists') jira_mock = jira.return_value jira_mock.search_issues.return_value = ['Jira already contains this ticket'] with self.assertLogs(level=WARNING) as cm: warning('Dummy log') dut.create_jira_issues(self.settings, self.coll) self.assertEqual( cm.output, ['WARNING:root:Dummy log'] )
def test_prevent_duplication(self, jira): jira_mock = jira.return_value jira_mock.search_issues.return_value = ['Jira already contains this ticket'] with self.assertLogs(level=WARNING) as cm: dut.create_jira_issues(self.settings, self.coll) self.assertEqual( cm.output, ["WARNING:sphinx.mlx.jira_interaction:Won't create a Task for item " "'ACTION-12345_ACTION_1' because the Jira API query to check to prevent " "duplication returned ['Jira already contains this ticket']", "WARNING:sphinx.mlx.jira_interaction:Won't create a Task for item " "'ACTION-12345_ACTION_2' because the Jira API query to check to prevent " "duplication returned ['Jira already contains this ticket']"] )
def test_add_watcher_jira_error(self, jira): Response = namedtuple('Response', 'text') def jira_add_watcher_mock(*_): raise JIRAError(status_code=401, response=Response('dummy msg')) jira_mock = jira.return_value jira_mock.search_issues.return_value = [] jira_mock.add_watcher.side_effect = jira_add_watcher_mock with self.assertLogs(level=WARNING) as cm: dut.create_jira_issues(self.settings, self.coll) error_msg = ("WARNING:sphinx.mlx.jira_interaction:Jira interaction failed: item ACTION-12345_ACTION_1: " "error code 401: dummy msg") self.assertEqual( cm.output, [error_msg, error_msg] )
def test_tuple_for_relationship_to_parent(self, jira): """ Tests that the linked item, added in this test case, is selected by configured tuple for ``relationship_to_parent`` """ self.settings['relationship_to_parent'] = ('depends_on', r'ZZZ-[\w_]+') alternative_parent = TraceableItem('ZZZ-TO_BE_PRIORITIZED') # to be prioritized over MEETING-12345_2 self.coll.add_relation('ACTION-12345_ACTION_1', 'depends_on', alternative_parent.id) jira_mock = jira.return_value jira_mock.search_issues.return_value = [] with self.assertLogs(level=WARNING) as cm: warning('Dummy log') dut.create_jira_issues(self.settings, self.coll) self.assertEqual( cm.output, ['WARNING:root:Dummy log'] ) self.assertEqual(jira_mock.search_issues.call_args_list, [ mock.call("project=MLX12345 and summary ~ " '"ZZZ\\\\-TO_BE_PRIORITIZED\\\\: Action 1\'s caption\\\\?"'), mock.call("project=MLX12345 and summary ~ 'Caption for action 2'"), ]) self.assertEqual( jira_mock.create_issue.call_args_list, [ mock.call( summary='ZZZ-TO_BE_PRIORITIZED: Action 1\'s caption?', description='Description for action 1', assignee={'name': 'ABC'}, **self.general_fields ), mock.call( summary='Caption for action 2', description='Caption for action 2', assignee={'name': 'ZZZ'}, **self.general_fields ), ])
def test_create_issue_timetracking_unavailable(self, jira): """ Value of effort attribute should be appended to description when setting timetracking field raises error """ def jira_update_mock(update={}, **_): if 'timetracking' in update: raise JIRAError jira_mock = jira.return_value jira_mock.search_issues.return_value = [] issue = jira_mock.create_issue.return_value issue.update.side_effect = jira_update_mock dut.create_jira_issues(self.settings, self.coll) self.assertEqual( issue.update.call_args_list, [ mock.call(update={'timetracking': [{"edit": {"originalEstimate": '2w 3d 4h 55m'}}]}), mock.call(description="Description for action 1\n\nEffort estimate: 2w 3d 4h 55m"), ] )
def test_notify_watchers(self, jira): """ Test effect of setting `notify_watchers` to True By default, watchers are added as the last step. When setting `notify_watchers` is set to a truthy value, the assignee should be set in an additional call to Jira after the watchers have been added. """ jira_mock = jira.return_value jira_mock.search_issues.return_value = [] self.settings['notify_watchers'] = True with self.assertLogs(level=WARNING): warning('Dummy log') dut.create_jira_issues(self.settings, self.coll) # No kwarg 'assignee' should be passed self.assertEqual( jira_mock.create_issue.call_args_list, [ mock.call( description='Description for action 1', summary='MEETING-12345_2: Action 1\'s caption?', **self.general_fields ), mock.call( description='Caption for action 2', summary='Caption for action 2', **self.general_fields ), ]) # Additional call to set assignee should be made after the issue has been created issue = jira_mock.create_issue.return_value self.assertEqual(jira_mock.assign_issue.call_args_list, [ mock.call(issue, 'ABC'), mock.call(issue, 'ZZZ'), ])