Пример #1
0
    def setUp(self):
        super().setUp()
        setup_models(self)

        machine_workflow_version = (
            self.workflow_versions['machine_workflow_version'])
        self.step = machine_workflow_version.steps.get(slug='machine_step')
        self.assertIsNotNone(self.step)
        self.step.execution_function = {
            'path': 'orchestra.tests.helpers.workflow.machine_task_function',
        }
        self.step.save()
        patcher = patch(
            'orchestra.tests.helpers.workflow.machine_task_function',
            return_value={'data': ''})
        self.machine_function_mock = patcher.start()
        self.addCleanup(patcher.stop)

        self.project = ProjectFactory(
            workflow_version=machine_workflow_version)
        create_subsequent_tasks(self.project)
        self.task = self.project.tasks.first()
        self.assertIsNotNone(self.task)

        # Since create_subsequent_tasks will automatically run the machine task
        # we need to reset the task each time it's called
        self._reset_task()
Пример #2
0
 def test_message_project_team(self, mock_message_slack_group):
     project = ProjectFactory(slack_group_id='test-project-1')
     url = '/orchestra/api/project/message_project_team/'
     test_message = 'this is a test message'
     response = self.api_client.post(url, {
         'message': test_message,
         'project_id': project.id
     },
                                     format='json')
     self.assertEqual(response.status_code, 200)
     self.assertTrue(mock_message_slack_group.called)
     # No project id provided
     response = self.api_client.post(url, {'message': test_message},
                                     format='json')
     self.assertEqual(response.status_code, 400)
     self.assertEqual(
         response.json()['message'],
         ('An object with `message` and `project_id` attributes'
          ' should be supplied'))
     # No message provided
     response = self.api_client.post(url, {'project_id': project.id},
                                     format='json')
     self.assertEqual(response.status_code, 400)
     self.assertEqual(
         response.json()['message'],
         ('An object with `message` and `project_id` attributes'
          ' should be supplied'))
     # Non-existent project_id provided
     response = self.api_client.post(url, {
         'message': 'text',
         'project_id': 123456
     },
                                     format='json')
     self.assertEqual(response.status_code, 400)
     self.assertEqual(response.json()['message'], 'No project for given id')
Пример #3
0
 def setUp(self):
     super().setUp()
     self.request_client = APIClient(enforce_csrf_checks=True)
     self.request_client.force_authenticate(user=SignedUser())
     self.workflow_version = WorkflowVersionFactory()
     self.step = StepFactory(slug='step-slug',
                             workflow_version=self.workflow_version)
     self.project = ProjectFactory(workflow_version=self.workflow_version)
Пример #4
0
 def setUp(self):
     super().setUp()
     setup_models(self)
     self.workflow_version = WorkflowVersionFactory()
     self.step = StepFactory(
         slug='step-slug',
         workflow_version=self.workflow_version)
     self.project = ProjectFactory(
         workflow_version=self.workflow_version)
Пример #5
0
 def test_create_project_slack_group(self):
     groups = self.slack.data['groups']
     num_groups = len(groups)
     project = ProjectFactory(
         workflow_version=self.workflow_versions['test_workflow'])
     self.assertFalse(project.id in groups)
     group_id = create_project_slack_group(project)
     self.assertEquals(len(groups), num_groups + 1)
     self.assertTrue(group_id in groups)
     project = Project.objects.get(id=project.id)
     self.assertEquals(group_id, project.slack_group_id)
Пример #6
0
 def setUp(self):
     super().setUp()
     self.request_client = APIClient(enforce_csrf_checks=True)
     self.request_client.force_authenticate(user=SignedUser())
     setup_models(self)
     self.workflow_version = WorkflowVersionFactory()
     self.step = StepFactory(slug='step-slug',
                             workflow_version=self.workflow_version)
     self.project = ProjectFactory(workflow_version=self.workflow_version)
     self.list_url = reverse('orchestra:api:todo-api-list')
     self.todo = TodoFactory(project=self.project)
     self.todo_with_step = TodoFactory(project=self.project, step=self.step)
Пример #7
0
    def setUp(self):
        super().setUp()
        self.request_client = APIClient(enforce_csrf_checks=True)
        self.request_client.force_authenticate(user=SignedUser())

        self.todolist_template_slug = 'test_todolist_template_slug'
        self.todolist_template_name = 'test_todolist_template_name'
        self.todolist_template_description = \
            'test_todolist_template_description'
        self.workflow_version = WorkflowVersionFactory()
        self.step = StepFactory(slug='step-slug',
                                workflow_version=self.workflow_version)
        self.project = ProjectFactory(workflow_version=self.workflow_version)
Пример #8
0
 def setUp(self):
     super().setUp()
     setup_models(self)
     self.worker = Worker.objects.get(user__username='******')
     self.request_client.login(username=self.worker.user.username,
                               password='******')
     self.todolist_template_list_url = reverse(
         'orchestra:todos:todolist_templates')
     self.todolist_template_detail_url_name = \
         'orchestra:todos:todolist_template'
     self.todolist_template_slug = 'test_todolist_template_slug'
     self.todolist_template_name = 'test_todolist_template_name'
     self.todolist_template_description = \
         'test_todolist_template_description'
     self.workflow_version = WorkflowVersionFactory()
     self.step = StepFactory(slug='step-slug',
                             workflow_version=self.workflow_version)
     self.project = ProjectFactory(workflow_version=self.workflow_version)
     self.project2 = ProjectFactory()
     tasks = Task.objects.filter(assignments__worker=self.worker)
     self.task = tasks[0]
     self.task.project = self.project
     self.task.step = self.step
     self.task.save()
Пример #9
0
 def setUp(self):
     super().setUp()
     setup_models(self)
     self.worker = Worker.objects.get(user__username='******')
     self.request_client.login(username=self.worker.user.username,
                               password='******')
     self.list_create_url = reverse('orchestra:todos:todo_qas')
     self.worker_task_recent_todo_qas_url = reverse(
         'orchestra:todos:worker_task_recent_todo_qas')
     self.list_details_url_name = 'orchestra:todos:todo_qa'
     self.project0 = ProjectFactory()
     self.project1 = ProjectFactory()
     self.step = StepFactory(slug='some-slug')
     tasks = Task.objects.filter(assignments__worker=self.worker)
     self.task_0 = tasks[0]
     self.task_0.project = self.project0
     self.task_0.step = self.step
     self.task_0.save()
     self.task_1 = tasks[1]
     self.task_1.project = self.project1
     self.task_1.step = self.step
     self.task_1.save()
     self.todo = TodoFactory(project=self.project0, step=self.step)
     self.comment = 'Test comment'
Пример #10
0
    def test_get_todos(self, mock_request):
        # This converts `requests.get` into DRF's `APIClient.get`
        # To make it testable
        def get(url, *args, **kwargs):
            return_value = self.request_client.get(url, format='json')
            return_value.text = json.dumps(return_value.data)
            return return_value

        mock_request.get = get

        step_1 = StepFactory(slug='step_1')
        step_2 = StepFactory(slug='step_2')
        project2 = ProjectFactory()
        # 2 todos have the same project
        todo1 = TodoFactory(step=step_1, project=self.project)
        todo2 = TodoFactory(step=step_1, project=self.project)
        # 1 todo has another project
        todo3 = TodoFactory(step=step_2, project=project2)

        todo4 = TodoFactory(step=step_1, project=project2)

        # Get todo1 and todo2
        res = get_todos(self.project.id, step_1.slug)
        self.assertEqual(len(res), 2)
        expected_ids = [todo1.id, todo2.id]
        for r in res:
            self.assertIn(r['id'], expected_ids)

        # Get todo3
        res = get_todos(project2.id, step_2.slug)
        self.assertEqual(len(res), 1)
        self.assertEqual(res[0]['id'], todo3.id)

        # Filter by project_id
        res = get_todos(project_id=project2.id)
        self.assertEqual(len(res), 2)
        expected_ids = [todo3.id, todo4.id]
        for r in res:
            self.assertIn(r['id'], expected_ids)

        # Test project_id is required
        msg = 'project_id is required'
        with self.assertRaisesMessage(OrchestraError, msg):
            get_todos(None)
Пример #11
0
 def setUp(self):
     super().setUp()
     project = ProjectFactory()
     step = StepFactory()
     self.old_title = 'Old title'
     self.new_title = 'New title'
     self.old_details = 'Old details'
     self.new_details = 'New details'
     self.old_todo = TodoFactory(title=self.old_title,
                                 details=self.old_details,
                                 completed=False,
                                 project=project,
                                 step=step)
     self.new_todo = TodoFactory(title=self.new_title,
                                 details=self.new_details,
                                 completed=True,
                                 project=project,
                                 step=step)
     self.sender = UserFactory()
Пример #12
0
 def setUp(self):
     super().setUp()
     setup_models(self)
     self.worker = Worker.objects.get(user__username='******')
     self.request_client.login(username=self.worker.user.username,
                               password='******')
     self.list_create_url = reverse('orchestra:todos:todos-list')
     self.list_details_url_name = 'orchestra:todos:todos-detail'
     self.workflow_version = WorkflowVersionFactory()
     self.step = StepFactory(slug='step-slug',
                             workflow_version=self.workflow_version)
     self.project = ProjectFactory(workflow_version=self.workflow_version)
     tasks = Task.objects.filter(assignments__worker=self.worker)
     task = tasks[0]
     task.project = self.project
     task.step = self.step
     task.save()
     self.todo_title = 'Let us do this'
     self.deadline = parse('2018-01-16T07:03:00+00:00')
Пример #13
0
    def test_dangerous_sql(self):
        project = ProjectFactory()
        TodoFactory(project=project)
        dangerous_sql = ("if ((select user) = 'sa'"
                         " OR (select user) = 'dbo') select 1 else select 1/0")
        url_params = build_url_params(
            project.id, None, **{'additional_data__sql': dangerous_sql})
        kwargs = self._get_qs_kwargs(GenericTodoViewset, url_params)
        # kwargs doesn't contain additional_data__sql field
        self.assertEqual(kwargs, {'project__id': str(project.id)})

        url_params = build_url_params(project.id, None,
                                      **{'title': dangerous_sql})
        kwargs = self._get_qs_kwargs(GenericTodoViewset, url_params)
        todos = Todo.objects.filter(**kwargs)
        self.assertEqual(kwargs, {
            'project__id': str(project.id),
            'title': dangerous_sql
        })
        self.assertTrue(todos.count, 0)
Пример #14
0
class MachineTaskTestCase(OrchestraTestCase):
    def setUp(self):
        super().setUp()
        setup_models(self)

        machine_workflow_version = (
            self.workflow_versions['machine_workflow_version'])
        self.step = machine_workflow_version.steps.get(slug='machine_step')
        self.assertIsNotNone(self.step)
        self.step.execution_function = {
            'path': 'orchestra.tests.helpers.workflow.machine_task_function',
        }
        self.step.save()
        patcher = patch(
            'orchestra.tests.helpers.workflow.machine_task_function',
            return_value={'data': ''})
        self.machine_function_mock = patcher.start()
        self.addCleanup(patcher.stop)

        self.project = ProjectFactory(
            workflow_version=machine_workflow_version)
        create_subsequent_tasks(self.project)
        self.task = self.project.tasks.first()
        self.assertIsNotNone(self.task)

        # Since create_subsequent_tasks will automatically run the machine task
        # we need to reset the task each time it's called
        self._reset_task()

    def _reset_task(self):
        self.task.status = Task.Status.AWAITING_PROCESSING
        self.task.save()
        self.task.assignments.all().delete()
        self.machine_function_mock.call_count = 0

    def _assert_correct_machine_task_state(
            self, assignment_status, task_status):
        self.task.refresh_from_db()
        assignment = self.task.assignments.first()
        self.assertEquals(assignment.status, assignment_status)
        self.assertEquals(self.task.status, task_status)

        # Check correct iteration state
        self.assertEquals(assignment.iterations.count(), 1)
        iteration = assignment.iterations.first()
        if task_status == Task.Status.COMPLETE:
            expected_status = Iteration.Status.REQUESTED_REVIEW
            expected_data = assignment.in_progress_task_data
            self.assertIsNotNone(iteration.end_datetime)
        else:
            expected_status = Iteration.Status.PROCESSING
            expected_data = {}
            self.assertIsNone(iteration.end_datetime)

        self.assertEquals(iteration.status, expected_status)
        self.assertEquals(iteration.submitted_data, expected_data)

        # Assert that machine function is called once and there is only one
        # assignment regardless of state
        self.assertEquals(self.machine_function_mock.call_count, 1)
        self.assertEquals(self.task.assignments.count(), 1)

    def test_new_task(self):
        self._reset_task()
        execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.SUBMITTED, Task.Status.COMPLETE)

    def test_already_processing_task(self):
        self._reset_task()
        execute(self.project.id, self.step.slug)

        # Pretend that the task is still processing
        self.task.status = Task.Status.PROCESSING
        self.task.save()
        assignment = self.task.assignments.first()
        assignment.status = TaskAssignment.Status.PROCESSING
        assignment.save()

        # Reset iteration for assignment
        assignment.iterations.all().delete()
        Iteration.objects.create(
            assignment=assignment,
            start_datetime=assignment.start_datetime)

        # Another machine attempts to perform task
        with self.assertRaises(MachineExecutionError):
            execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.PROCESSING, Task.Status.PROCESSING)

    def test_already_completed_task(self):
        self._reset_task()
        execute(self.project.id, self.step.slug)
        with self.assertRaises(MachineExecutionError):
            execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.SUBMITTED, Task.Status.COMPLETE)

    @patch('orchestra.machine_tasks.logger')
    def test_marking_failed_task_assignment(self, mock_logger):
        self.machine_function_mock.side_effect = Exception('Function failed.')
        self._reset_task()
        execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.FAILED, Task.Status.PROCESSING)
        mock_logger.exception.assert_called_with('Machine task has failed')
        self.machine_function_mock.side_effect = None

    def test_reassigning_failed_task_assignment(self):
        self._reset_task()
        execute(self.project.id, self.step.slug)

        # Pretend that the machine task failed
        self.task.status = Task.Status.PROCESSING
        self.task.save()
        assignment = self.task.assignments.first()
        assignment.status = TaskAssignment.Status.FAILED
        assignment.save()
        self.assertEquals(self.machine_function_mock.call_count, 1)
        self.machine_function_mock.call_count = 0

        # New machine picks up the failed task
        execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.SUBMITTED, Task.Status.COMPLETE)

    def test_aborted_project(self):
        self._reset_task()
        self.project.status = Project.Status.ABORTED
        self.project.save()
        self.task.status = Task.Status.PROCESSING
        self.task.save()
        execute(self.project.id, self.step.slug)
        self._assert_correct_machine_task_state(
            TaskAssignment.Status.SUBMITTED, Task.Status.ABORTED)
Пример #15
0
 def test_todo_qas_create_permissions(self):
     # Can't make requests for projects in which you're uninvolved.
     project = ProjectFactory()
     step = StepFactory()
     todo = TodoFactory(project=project, step=step)
     self._verify_todo_qa_creation(todo, False)
Пример #16
0
 def test_todos_list_create_permissions(self):
     # Can't make requests for projects in which you're uninvolved.
     project = ProjectFactory()
     step = StepFactory()
     self._verify_todos_list(project.id, [], False)
     self._verify_todo_creation(False, project.id, step)