def test_task_depends(self, jira_mock): '''Test for dual happy flow: one task depends on the other''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, self.ASSIGNEE1, self.ESTIMATE1, self.DEPENDS1), self._mock_jira_issue(self.KEY2, self.SUMMARY2, self.ASSIGNEE2, self.ESTIMATE2, self.DEPENDS2), ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=2) ]) self.assertEqual(2, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual(self.ASSIGNEE1, issues[0].properties['allocate'].get_value()) self.assertEqual(self.ESTIMATE1 / self.SECS_PER_DAY, issues[0].properties['effort'].get_value()) self.assertEqual(self.DEPENDS1, issues[0].properties['depends'].get_value()) self.assertEqual(self.KEY2, issues[1].key) self.assertEqual(self.SUMMARY2, issues[1].summary) self.assertEqual(self.ASSIGNEE2, issues[1].properties['allocate'].get_value()) self.assertEqual(self.ESTIMATE2 / self.SECS_PER_DAY, issues[1].properties['effort'].get_value()) self.assertEqual(self.DEPENDS2, issues[1].properties['depends'].get_value())
def test_broken_depends(self, jira_mock): '''Test for removing a broken link to a dependant task''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, depends=['non-existing-key-of-issue']) ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog'), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=1, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual([], issues[0].properties['depends'].value)
def test_estimate_too_low(self, jira_mock): '''Test for correcting an estimate which is too low''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, estimates=[1, None, None]) ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog'), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=1, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual(dut.JugglerTaskEffort.MINIMAL_VALUE, issues[0].properties['effort'].value)
def test_single_task_minimal(self, jira_mock): '''Test for minimal happy flow: single task with minimal content is returned by Jira Note: the default effort is choosen. ''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1) ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog'), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=1, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual(dut.JugglerTaskEffort.DEFAULT_VALUE, issues[0].properties['effort'].value)
def test_single_task_happy(self, jira_mock): '''Test for simple happy flow: single task is returned by Jira''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, self.ASSIGNEE1, [self.ESTIMATE1, None, None], self.DEPENDS1) ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog'), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=1, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual(self.ASSIGNEE1, issues[0].properties['allocate'].value) self.assertEqual(self.ESTIMATE1 / self.SECS_PER_DAY, issues[0].properties['effort'].value) self.assertEqual(self.DEPENDS1, issues[0].properties['depends'].value)
def test_empty_query_result(self, jira_mock): '''Test for Jira not returning any task on the given query''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.return_value = [] juggler.juggle() jira_mock_object.search_issues.assert_called_once_with( self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0)
def test_task_double_depends(self, jira_mock): '''Test for extended happy flow: one task depends on two others''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) self.assertEqual(self.QUERY, juggler.query) jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, self.ASSIGNEE1, [self.ESTIMATE1, None, None], self.DEPENDS1), self._mock_jira_issue(self.KEY2, self.SUMMARY2, self.ASSIGNEE2, [self.ESTIMATE2, None, None], self.DEPENDS2), self._mock_jira_issue(self.KEY3, self.SUMMARY3, self.ASSIGNEE3, [self.ESTIMATE3, None, None], self.DEPENDS3), ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog'), call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=3, expand='changelog') ]) self.assertEqual(3, len(issues)) self.assertEqual(self.KEY1, issues[0].key) self.assertEqual(self.SUMMARY1, issues[0].summary) self.assertEqual(self.ASSIGNEE1, issues[0].properties['allocate'].value) self.assertEqual(self.ESTIMATE1 / self.SECS_PER_DAY, issues[0].properties['effort'].value) self.assertEqual(self.DEPENDS1, issues[0].properties['depends'].value) self.assertEqual(self.KEY2, issues[1].key) self.assertEqual(self.SUMMARY2, issues[1].summary) self.assertEqual(self.ASSIGNEE2, issues[1].properties['allocate'].value) self.assertEqual(self.ESTIMATE2 / self.SECS_PER_DAY, issues[1].properties['effort'].value) self.assertEqual(self.DEPENDS2, issues[1].properties['depends'].value) self.assertEqual(self.KEY3, issues[2].key) self.assertEqual(self.SUMMARY3, issues[2].summary) self.assertEqual(self.ASSIGNEE3, issues[2].properties['allocate'].value) self.assertEqual(self.ESTIMATE3 / self.SECS_PER_DAY, issues[2].properties['effort'].value) self.assertEqual(self.DEPENDS3, issues[2].properties['depends'].value)
def test_closed_task(self, jira_mock): ''' Test that a change of assignee after Resolved status has no effect and that the original time estimate is used when no time has been logged. ''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) histories = [ { 'items': [{ 'field': 'status', 'toString': 'Resolved', }], 'created': '2022-04-12T13:04:11.449+0200', }, { 'items': [{ 'field': 'assignee', 'to': self.ASSIGNEE2, }], 'created': '2022-05-25T14:07:11.974+0200', }, ] jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, self.ASSIGNEE1, [self.ESTIMATE1, None, self.ESTIMATE3], self.DEPENDS1, histories=histories, status="Closed"), ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.ASSIGNEE1, issues[0].properties['allocate'].value) self.assertEqual(self.ESTIMATE1 / self.SECS_PER_DAY, issues[0].properties['effort'].value)
def test_depend_on_preceding(self, jira_mock): '''Test --depends-on-preceding, --weeklymax and --current-date options''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) histories = [ { 'created': '2021-08-18T18:30:15.338+0200', 'items': [{ 'field': 'status', 'toString': 'Resolved', }] }, ] jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue(self.KEY1, self.SUMMARY1, self.ASSIGNEE1, [self.ESTIMATE1, None, None], self.DEPENDS1, histories=histories, status="Resolved"), self._mock_jira_issue( self.KEY2, self.SUMMARY2, self.ASSIGNEE1, [self.SECS_PER_DAY * val for val in [5, 3.2, 2.4]], self.DEPENDS1, status="Open"), self._mock_jira_issue(self.KEY3, self.SUMMARY3, self.ASSIGNEE1, [self.ESTIMATE2, None, self.ESTIMATE3], self.DEPENDS1, status="Open"), ], []] issues = juggler.juggle( depend_on_preceding=True, weeklymax=1.0, current_date=parser.isoparse('2021-08-23T13:30')) jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog') ]) self.assertEqual(3, len(issues)) self.assertEqual(self.ASSIGNEE1, issues[0].properties['allocate'].value) self.assertEqual(self.ESTIMATE1 / self.SECS_PER_DAY, issues[0].properties['effort'].value) self.assertEqual(' end 2021-08-18-18:00-+0200\n', str(issues[0].properties['depends'])) self.assertEqual(self.ASSIGNEE1, issues[1].properties['allocate'].value) self.assertEqual(3.2 + 2.4, issues[1].properties['effort'].value) self.assertEqual( ' start %{2021-08-23-13:00 - 9.125d}\n', str(issues[1].properties['depends'])) # 3.2 days spent self.assertEqual(self.ASSIGNEE1, issues[2].properties['allocate'].value) self.assertEqual(self.ESTIMATE3 / self.SECS_PER_DAY, issues[2].properties['effort'].value) self.assertEqual(f' depends !{self.KEY2}\n', str(issues[2].properties['depends']))
def test_resolved_task(self, jira_mock): '''Test that the last assignee in the Analyzed state is used and the Time Spent is used as effort Test that the most recent transition to the Approved/Resolved state is used to mark the end''' jira_mock_object = MagicMock(spec=JIRA) jira_mock.return_value = jira_mock_object juggler = dut.JiraJuggler(self.URL, self.USER, self.PASSWD, self.QUERY) histories = [ { 'items': [{ 'field': 'assignee', 'to': self.ASSIGNEE1, }], 'created': '2022-04-08T13:11:47.749+0200', }, { 'items': [{ 'field': 'status', 'toString': 'Resolved', }], 'created': '2022-04-11T08:13:14.350+0200', }, { 'items': [{ 'field': 'assignee', 'to': self.ASSIGNEE3, # 'from': self.ASSIGNEE1, # cannot use 'from' as key to test }], 'created': '2022-04-12T13:04:11.449+0200', }, { 'items': [{ 'field': 'status', 'toString': 'Analyzed', }], 'created': '2022-04-13T14:10:43.632+0200', }, { 'items': [{ 'field': 'assignee', 'to': self.ASSIGNEE2, }], 'created': '2022-05-02T09:20:36.310+0200', }, { 'items': [{ 'field': 'status', 'toString': 'Approved', }], 'created': '2022-05-25T14:07:11.974+0200', }, ] jira_mock_object.search_issues.side_effect = [[ self._mock_jira_issue( self.KEY1, self.SUMMARY1, self.ASSIGNEE1, [self.ESTIMATE1, self.ESTIMATE2, self.ESTIMATE3], self.DEPENDS1, histories=histories, status="Resolved"), ], []] issues = juggler.juggle() jira_mock_object.search_issues.assert_has_calls([ call(self.QUERY, maxResults=dut.JIRA_PAGE_SIZE, startAt=0, expand='changelog') ]) self.assertEqual(1, len(issues)) self.assertEqual(self.ASSIGNEE2, issues[0].properties['allocate'].value) self.assertEqual(self.ESTIMATE2 / self.SECS_PER_DAY, issues[0].properties['effort'].value) self.assertEqual('2022-05-25 14:07:11.974000+02:00', str(issues[0].resolved_at_date))