예제 #1
0
    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)
예제 #2
0
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"])
예제 #3
0
    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"])
예제 #4
0
    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"])
예제 #5
0
    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"])
예제 #6
0
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()
예제 #7
0
    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"])
예제 #8
0
    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"])
예제 #9
0
 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)
예제 #10
0
 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
         })
예제 #11
0
    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"])
예제 #12
0
    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"])
예제 #13
0
 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")
예제 #14
0
 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
예제 #15
0
    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)
예제 #16
0
 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)
예제 #17
0
 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)
예제 #18
0
 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)
예제 #19
0
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)
예제 #20
0
 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)
예제 #21
0
 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})
예제 #22
0
 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)
예제 #23
0
 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])
예제 #24
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")))
예제 #25
0
 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])
예제 #26
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))
예제 #27
0
 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)
예제 #28
0
 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)
예제 #29
0
 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)
예제 #30
0
 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)