def test(self) -> None: source = ModifiedSinceSource(self.project.gid) self.client.tasks_by_project.return_value = task1, task2 = [ f.task(gid="1"), f.task(gid="2"), ] iterator = source.iterator(self.client) self.client.tasks_by_project.assert_not_called() self.assertIs(next(iterator), task1) self.client.tasks_by_project.assert_called_once_with( self.project, only_incomplete=False, modified_since=datetime(2019, 1, 1, 12, 0, 0), ) self.assertIs(next(iterator), task2) self.client.tasks_by_project.reset_mock() self.client.tasks_by_project.return_value = task3, task4 = [ f.task(gid="3"), f.task(gid="4"), ] self.assertIs(next(iterator), task3) self.client.tasks_by_project.assert_called_once_with( self.project, only_incomplete=False, modified_since=datetime(2019, 1, 1, 12, 1, 0), ) self.assertIs(next(iterator), task4)
class TestDueDateSorter(TestCase): tasks = [ f.task(gid="1", due_on=date(2019, 1, 2)), f.task(gid="2", due_on=date(2019, 1, 1)), f.task(gid="3", due_on=None), f.task(gid="4", due_on=date(2019, 1, 3)), ] def test_ascending_missing_last(self) -> None: sorter = DueDateSorter() sorted_tasks = sorter.sort(self.tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1", "4", "3"]) def test_descending(self) -> None: sorter = DueDateSorter(ascending=False) sorted_tasks = sorter.sort(self.tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["4", "1", "2", "3"]) def test_missing_first(self) -> None: sorter = DueDateSorter(missing_first=True) sorted_tasks = sorter.sort(self.tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["3", "2", "1", "4"])
def test_missing_enum_option(self) -> None: tasks = [ f.task(gid="1", custom_fields=[self.custom_field("Z")]), f.task(gid="2", custom_fields=[self.custom_field("A")]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1"])
def test_missing_custom_field(self) -> None: tasks = [ f.task(gid="1", custom_fields=[f.custom_field(name="Other custom field")]), f.task(gid="2", custom_fields=[self.custom_field(3)]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1"])
def test_unset_number_value(self) -> None: tasks = [ f.task(gid="1", custom_fields=[self.custom_field(None)]), f.task(gid="2", custom_fields=[self.custom_field(0)]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1"])
class TestSetEnumCustomField(TestCase): enum_option = f.enum_option(name="My enum option") custom_field = f.custom_field(name="My custom field", enum_options=[enum_option]) task = f.task(custom_fields=[custom_field]) task_with_field_set = f.task( custom_fields=[ f.custom_field( name="My custom field", enum_options=[enum_option], enum_value=enum_option, ) ] ) def setUp(self) -> None: self.client = create_autospec(Client) def test_success(self) -> None: action = SetEnumCustomField("My custom field", "My enum option") action(self.task, self.client) self.client.set_enum_custom_field.assert_called_once_with( self.task, self.custom_field, self.enum_option ) def test_already_set(self) -> None: action = SetEnumCustomField("My custom field", "My enum option") action(self.task_with_field_set, self.client) self.client.set_enum_custom_field.assert_not_called() def test_missing_enum_option(self) -> None: action = SetEnumCustomField("My custom field", "Other enum option") with self.assertLogs(_logger, logging.WARNING) as logs: action(self.task_with_field_set, self.client) self.assertListEqual( logs.output, [ "WARNING:archie.actions:CustomField(custom-field-gid) " "has no enum option 'Other enum option'" ], ) self.client.set_enum_custom_field.assert_not_called() def test_missing_custom_field(self) -> None: action = SetEnumCustomField("Other custom field", "My enum option") with self.assertLogs(_logger, logging.WARNING) as logs: action(self.task, self.client) self.assertListEqual( logs.output, [ "WARNING:archie.actions:Task(task-gid) " "has no custom field 'Other custom field'" ], ) self.client.set_enum_custom_field.assert_not_called()
def test_normal(self) -> None: tasks = [ f.task(gid="1", custom_fields=[self.custom_field("A")]), f.task(gid="2", custom_fields=[self.custom_field("B")]), f.task(gid="3", custom_fields=[self.custom_field("C")]), f.task(gid="4", custom_fields=[self.custom_field("D")]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "4", "3", "1"])
def test_ascending(self) -> None: tasks = [ f.task(gid="1", custom_fields=[self.custom_field(5)]), f.task(gid="2", custom_fields=[self.custom_field(9)]), f.task(gid="3", custom_fields=[self.custom_field(1)]), f.task(gid="4", custom_fields=[self.custom_field(2)]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["3", "4", "1", "2"])
def test_workflow(self) -> None: self.task_source.iterator.return_value = task1, task2 = [ f.task(gid="1"), f.task(gid="2"), ] workflow = Mock() self.triager.apply(workflow) workflow.assert_has_calls( [call(task1, self.client), call(task2, self.client)], any_order=True)
def test_reorder(self) -> None: project = f.project() task = f.task(gid="1") reference = f.task(gid="2") self.inner_mock.tasks.add_project.return_value = None self.client.reorder_in_project(task, project, reference, "direction") self.inner_mock.tasks.add_project.assert_called_once_with( task.gid, { "project": project.gid, "insert_direction": reference.gid })
def test_unset_enum_option(self) -> None: tasks = [ f.task( gid="1", custom_fields=[f.custom_field(name="My custom field", enum_value=None)], ), f.task(gid="2", custom_fields=[self.custom_field("B")]), ] sorted_tasks = self.sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1"])
def test_descending(self) -> None: sorter = NumberCustomFieldSorter("My custom field", ascending=False) tasks = [ f.task(gid="1", custom_fields=[self.custom_field(5)]), f.task(gid="2", custom_fields=[self.custom_field(9)]), f.task(gid="3", custom_fields=[self.custom_field(1)]), f.task(gid="4", custom_fields=[self.custom_field(2)]), ] sorted_tasks = sorter.sort(tasks) ids = [t.gid for t in sorted_tasks] self.assertListEqual(ids, ["2", "1", "4", "3"])
def test_sort_section(self) -> None: sorter = create_autospec(Sorter) self.triager.order("Section 2", sorter) self.client.tasks_by_section.return_value = tasks = [ f.task(gid="1"), f.task(gid="2"), ] sorter.sort.return_value = tasks[::-1] self.triager.sort() self.client.tasks_by_section.assert_called_once_with(self.section) sorter.sort.assert_called_once_with(tasks) self.client.reorder_in_project.assert_called_once_with( tasks[1], self.project, tasks[0], "before")
def check_first_poll(self, source: TaskSource, only_incomplete: bool) -> Iterator[Task]: iterator = source.iterator(self.client) self.client.tasks_by_project.return_value = task1, task2 = [ f.task(gid="1"), f.task(gid="2"), ] self.client.tasks_by_project.assert_not_called() self.assertIs(next(iterator), task1) self.client.tasks_by_project.assert_called_once_with( self.project, only_incomplete=only_incomplete) self.assertIs(next(iterator), task2) return iterator
def test_repeat(self) -> None: source = PollingSource(self.project.gid, repeat_after="0m") iterator = self.check_first_poll(source, only_incomplete=True) self.client.tasks_by_project.reset_mock() self.client.tasks_by_project.return_value = task3, task4 = [ f.task(gid="3"), f.task(gid="4"), ] self.assertIs(next(iterator), task3) self.client.tasks_by_project.assert_called_once_with( self.project, only_incomplete=True) self.assertIs(next(iterator), task4)
def test_task_by_gid(self) -> None: task = f.task() self.inner_mock.tasks.find_by_id.return_value = task.to_dict() returned_task = self.client.task_by_gid("1") self.assertEqual(task, returned_task) self.inner_mock.tasks.find_by_id.assert_called_once_with( "1", fields=list_matcher)
def test_unset_custom_field_value(self) -> None: task = f.task(custom_fields=[custom_field]) stage, context = self.manager.get_current_stage(task) expected_context = _EnumCustomFieldWorkflowGetStageContext( custom_field, enum_options) self.assertIsNone(stage) self.assertEqual(expected_context, context)
def test_no_external_object(self) -> None: task = f.task(external=None) stage, context = self.manager.get_current_stage(task) expected_context = _ExternalDataWorkflowGetStageContext( external=External(None, {}), workflows={}) self.assertIsNone(stage) self.assertEqual(expected_context, context)
class TestForAtLeast(TestCase): task = f.task( created_at=datetime(2019, 1, 1, 12, 0, 0, tzinfo=timezone.utc)) @staticmethod def matcher(story: Story) -> bool: return True def test_story(self) -> None: matching_story = f.story(text="a", created_at=datetime(2019, 1, 2, 12, 0, 0, tzinfo=timezone.utc)) for td, expected in [(timedelta(hours=24), False), (timedelta(hours=23), True)]: with self.subTest(timedelta=td, expected=expected): result = _for_at_least(self.task, [matching_story], self.matcher, td) self.assertEqual(expected, result) def test_no_story(self) -> None: for td, expected in [(timedelta(hours=48), False), (timedelta(hours=47), True)]: with self.subTest(timedelta=td, expected=expected): result = _for_at_least(self.task, [], self.matcher, td) self.assertEqual(expected, result)
def test_no_matching_external(self) -> None: matcher = Mock(return_value=False) external = f.external() predicate = HasExternal(matcher) task = f.task(external=external) self.assertFalse(predicate(task, self.client)) matcher.assert_called_once_with(external)
def test_add_to_project(self) -> None: project = f.project() task = f.task() self.inner_mock.tasks.add_project.return_value = None self.client.add_to_project(task, project) self.inner_mock.tasks.add_project.assert_called_once_with( task.gid, {"project": project.gid})
def setUp(self) -> None: super().setUp() self.task_source.iterator.return_value = (self.task, ) = [ f.task(gid="1") ] self.predicate = create_autospec(Predicate, return_value=True) self.action = create_autospec(Action)
def test_set_stage(self) -> None: task = f.task() client = create_autospec(Client) context = _SectionWorkflowSetStageContext(sections[0]) client.add_to_section.return_value = None self.manager.set_stage(task, client, context) client.add_to_section.assert_called_once_with(task, sections[0])
class TestHasUnsetEnum(TestCase): predicate = HasUnsetEnum("My custom field") client = create_autospec(Client) custom_field = f.custom_field(name="My custom field", resource_subtype="enum", enum_value=None) task = f.task(custom_fields=[custom_field]) def test_has_no_value(self) -> None: self.assertTrue(self.predicate(self.task, self.client)) def test_has_any_value(self) -> None: task = f.task(custom_fields=[ f.custom_field( name="My custom field", resource_subtype="enum", enum_value=f.enum_option(name="My enum option"), ) ]) self.assertFalse(self.predicate(task, self.client)) def test_wrong_custom_field(self) -> None: predicate = HasUnsetEnum("Other custom field") self.assertFalse(predicate(self.task, self.client)) def test_missing_custom_field(self) -> None: task = f.task(custom_fields=[]) self.assertFalse(self.predicate(task, self.client)) @patch("archie.predicates._for_at_least") def test_call(self, for_at_least_mock: Mock) -> None: predicate = HasUnsetEnum("My custom field", for_at_least="2d") for_at_least_mock.return_value = return_sentinel = object() self.client.stories_by_task.return_value = story_sentinel = object() result = predicate(self.task, self.client) self.assertIs(result, return_sentinel) self.client.stories_by_task.assert_called_once_with(self.task) for_at_least_mock.assert_called_once_with(self.task, story_sentinel, predicate._story_matcher, timedelta(days=2)) def test_story_matcher(self) -> None: matcher = HasUnsetEnum("My custom field")._story_matcher self.assertTrue( matcher( f.story( resource_subtype="enum_custom_field_changed", custom_field=self.custom_field, ))) self.assertFalse( matcher( f.story( resource_subtype="enum_custom_field_changed", custom_field=f.custom_field(name="Other custom field"), ))) self.assertFalse(matcher(f.story(resource_subtype="unknown")))
def test_set_stage(self) -> None: task = f.task() client = create_autospec(Client) context = _EnumCustomFieldWorkflowSetStageContext( custom_field, enum_options[0]) self.manager.set_stage(task, client, context) client.set_enum_custom_field.assert_called_once_with( task, custom_field, enum_options[0])
def test_unset_enum_value(self) -> None: task = f.task(custom_fields=[ f.custom_field(name="My custom field", resource_subtype="enum", enum_value=None) ]) predicate = HasEnumValue("My custom field", "My enum option") self.assertFalse(predicate(task, self.client))
def test_no_workflow_mapping(self) -> None: external = f.external(data={}) task = f.task(external=external) stage, context = self.manager.get_current_stage(task) expected_context = _ExternalDataWorkflowGetStageContext( external=external, workflows={}) self.assertIsNone(stage) self.assertEqual(expected_context, context)
def test_matching_stage(self) -> None: workflow_data = {"External workflow": "A"} external = f.external(data={"workflows": workflow_data}) task = f.task(external=external) stage, context = self.manager.get_current_stage(task) expected_context = _ExternalDataWorkflowGetStageContext( external=external, workflows=workflow_data) self.assertIs(stage, stages[0]) self.assertEqual(expected_context, context)
def expect_context_without_stage(self, workflow_data: Mapping[str, str]) -> None: external = f.external(data={"workflows": workflow_data}) task = f.task(external=external) stage, context = self.manager.get_current_stage(task) expected_context = _ExternalDataWorkflowGetStageContext( external=external, workflows=workflow_data) self.assertIsNone(stage) self.assertEqual(expected_context, context)
def test_missing_stage(self) -> None: stage, context = self.manager.get_current_stage( f.task(memberships=[ f.task_membership(project, f.section(name="C", project=project)) ])) expected_context = _SectionWorkflowGetStageContext(project) self.assertIsNone(stage) self.assertEqual(expected_context, context)