def test_completed_projects(self): projects = Project.objects.all() initial_task = assign_task(self.workers[6].id, self.tasks['awaiting_processing'].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[6]) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[6]) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[6]) self.assertEquals(completed_projects(projects).count(), 1)
def submit_task_assignment(request): assignment_information = load_encoded_json(request.body) worker = Worker.objects.get(user=request.user) command_type = assignment_information['command_type'] if command_type in ('submit', 'accept'): iteration_status = Iteration.Status.REQUESTED_REVIEW elif command_type == 'reject': iteration_status = Iteration.Status.PROVIDED_REVIEW else: raise BadRequest('Illegal command') try: submit_task(assignment_information['task_id'], assignment_information['task_data'], iteration_status, worker) return {} except TaskStatusError: raise BadRequest('Task already completed') except Task.DoesNotExist: raise BadRequest('No task for given id') except IllegalTaskSubmission as e: raise BadRequest(e) except TaskAssignmentError as e: raise BadRequest(e)
def submit_task_assignment(request): assignment_information = json.loads(request.body.decode()) worker = Worker.objects.get(user=request.user) command_type = assignment_information['command_type'] work_time_seconds = assignment_information['work_time_seconds'] if command_type == 'accept': snapshot_type = TaskAssignment.SnapshotType.ACCEPT elif command_type == 'reject': snapshot_type = TaskAssignment.SnapshotType.REJECT elif command_type == 'submit': snapshot_type = TaskAssignment.SnapshotType.SUBMIT else: raise BadRequest('Illegal command') try: submit_task(assignment_information['task_id'], assignment_information['task_data'], snapshot_type, worker, work_time_seconds) return {} except TaskStatusError: raise BadRequest('Task already completed') except Task.DoesNotExist: raise BadRequest('No task for given id') except IllegalTaskSubmission as e: raise BadRequest(e) except TaskAssignmentError as e: raise BadRequest(e)
def test_completed_projects(self): projects = Project.objects.all() initial_task = assign_task(self.workers[6].id, self.tasks['awaiting_processing'].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 1)
def test_role_counter_required_for_new_task(self): task = TaskFactory(status=Task.Status.COMPLETE) with self.assertRaises(TaskAssignmentError): role_counter_required_for_new_task(task) project = self.projects['assignment_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 task = project.tasks.first() counter = role_counter_required_for_new_task(task) self.assertEquals(counter, 0) initial_task = assign_task(self.workers[0].id, task.id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) counter = role_counter_required_for_new_task(initial_task) self.assertEquals(counter, 1) initial_task = assign_task(self.workers[1].id, task.id) initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[1]) counter = role_counter_required_for_new_task(initial_task) self.assertEquals(counter, 2)
def test_completed_projects(self): projects = Project.objects.all() initial_task = assign_task(self.workers[6].id, self.tasks['processing_task'].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 0) next_task = assign_task( self.workers[6].id, initial_task.project.tasks.order_by('-start_datetime')[0].id) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(next_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[6], 0) self.assertEquals(completed_projects(projects).count(), 1)
def submit_task_assignment(request): assignment_information = json.loads(request.body.decode()) worker = Worker.objects.get(user=request.user) command_type = assignment_information["command_type"] work_time_seconds = assignment_information["work_time_seconds"] if command_type == "accept": snapshot_type = TaskAssignment.SnapshotType.ACCEPT elif command_type == "reject": snapshot_type = TaskAssignment.SnapshotType.REJECT elif command_type == "submit": snapshot_type = TaskAssignment.SnapshotType.SUBMIT else: raise BadRequest("Illegal command") try: submit_task( assignment_information["task_id"], assignment_information["task_data"], snapshot_type, worker, work_time_seconds, ) return {} except TaskStatusError: raise BadRequest("Task already completed") except Task.DoesNotExist: raise BadRequest("No task for given id") except IllegalTaskSubmission as e: raise BadRequest(e) except TaskAssignmentError as e: raise BadRequest(e)
def test_task_form_init(self): """ Test task form initialization for new, human and machine tasks """ # Create new task form # (Test form init with no task instance) TaskForm() project = Project.objects.get(workflow_slug='test_workflow_2') self.assertEquals(Task.objects.filter(project=project).count(), 0) create_subsequent_tasks(project) # Human task was created but not assigned # (Test form init with empty assignment history) self.assertEquals(Task.objects.filter(project=project).count(), 1) human_task = Task.objects.filter(project=project).first() form = TaskForm(instance=human_task) self.assertEquals(form.fields['currently_assigned_to'].initial, None) # Human task assigned to entry_level worker # (Test form init with a single entry-level worker) human_task = assign_task(self.workers[0].id, human_task.id) form = TaskForm(instance=human_task) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): human_task = submit_task(human_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[0], 0) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[0].id) # Human task under review # (Test form init with both an entry-level worker and reviewer) human_task = assign_task(self.workers[1].id, human_task.id) form = TaskForm(instance=human_task) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): human_task = submit_task(human_task.id, {}, TaskAssignment.SnapshotType.ACCEPT, self.workers[1], 0) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[1].id) # Machine task was created # (Test form init with a machine task) self.assertEquals(Task.objects.filter(project=project).count(), 2) machine_task = (Task.objects.filter(project=project) .exclude(id=human_task.id).first()) form = TaskForm(instance=machine_task) self.assertEquals(form.fields['currently_assigned_to'].initial, None)
def test_preassign_workers(self, mock_mail, mock_slack): request_cause = StaffBotRequest.RequestCause.TASK_POLICY.value staffing_request_count = StaffingRequestInquiry.objects.filter( request__request_cause=request_cause).count() project = self.projects['staffbot_assignment_policy'] # Create first task in test project create_subsequent_tasks(project) address_staffing_requests() self.assertEqual(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) # Mock mail should be called if we autostaff self.assertTrue(mock_mail.called) self.assertTrue(mock_slack.called) # Assert we created new StaffingRequestInquirys because of autostaff new_staffing_request_count = StaffingRequestInquiry.objects.filter( request__request_cause=request_cause).count() self.assertTrue(staffing_request_count < new_staffing_request_count) self.assertEqual(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEqual(related_task.assignments.count(), 0) self.assertEqual(related_task.status, Task.Status.AWAITING_PROCESSING)
def test_preassign_workers(self): project = self.projects['assignment_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[0], 0) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEquals(related_task.assignments.count(), 0) self.assertEquals(related_task.status, Task.Status.AWAITING_PROCESSING) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 4 initial_task = assign_task(self.workers[4].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[4], 0) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 4 is certified for related task and should have been assigned self.assertEquals(related_task.assignments.count(), 1) self.assertEquals(related_task.status, Task.Status.PROCESSING) self.assertTrue( is_worker_assigned_to_task(self.workers[4], related_task)) # Reset project project.tasks.all().delete()
def test_preassign_workers(self): project = self.projects['assignment_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[0], 0) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEquals(related_task.assignments.count(), 0) self.assertEquals(related_task.status, Task.Status.AWAITING_PROCESSING) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 4 initial_task = assign_task(self.workers[4].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[4], 0) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 4 is certified for related task and should have been assigned self.assertEquals(related_task.assignments.count(), 1) self.assertEquals(related_task.status, Task.Status.PROCESSING) self.assertTrue(is_worker_assigned_to_task(self.workers[4], related_task)) # Reset project project.tasks.all().delete()
def test_always_create_policy(self): project = self.projects['creation_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEqual(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should not be created, it never is with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) self.assertEqual(project.tasks.count(), 1)
def test_preassign_workers(self, mock_mail, mock_slack): request_cause = StaffBotRequest.RequestCause.AUTOSTAFF.value staffing_request_count = StaffingRequestInquiry.objects.filter( request__request_cause=request_cause).count() project = self.projects['staffbot_assignment_policy'] # Create first task in test project create_subsequent_tasks(project) send_staffing_requests() self.assertEqual(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) # Mock mail should be called if we autostaff self.assertTrue(mock_mail.called) self.assertTrue(mock_slack.called) # Assert we created new StaffingRequestInquirys because of autostaff new_staffing_request_count = StaffingRequestInquiry.objects.filter( request__request_cause=request_cause).count() self.assertTrue(staffing_request_count < new_staffing_request_count) self.assertEqual(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEqual(related_task.assignments.count(), 0) self.assertEqual(related_task.status, Task.Status.AWAITING_PROCESSING) # Reset project project.tasks.all().delete()
def test_notify_status_change(self): project = self.projects['empty_project'] internal_name = settings.SLACK_INTERNAL_NOTIFICATION_CHANNEL.strip('#') internal_groups = [ group for group in self.slack.groups.list().body['groups'] if group['name'] == internal_name] internal_group_id = internal_groups[0]['id'] internal_slack_messages = self.slack.get_messages(internal_group_id) experts_slack_messages = self.slack.get_messages( project.slack_group_id) def _validate_slack_messages(message_stub): """ Check that correct slack message was sent if API key present. """ self.assertIn(message_stub, internal_slack_messages.pop()) self.assertIn(message_stub, experts_slack_messages.pop()) task = TaskFactory(project=project, step_slug=self.test_step_slug, status=Task.Status.AWAITING_PROCESSING) # Entry-level worker picks up task self.assertEquals(task.status, Task.Status.AWAITING_PROCESSING) task = assign_task(self.workers[0].id, task.id) self.assertTrue(is_worker_assigned_to_task(self.workers[0], task)) # Notification should be sent to entry-level worker self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[0].user.email) self.assertEquals(notification['subject'], "You've been assigned to a new task!") _validate_slack_messages('Task has been picked up by a worker.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): # Entry-level worker submits task task = submit_task(task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[0], 0) self.assertEquals(task.status, Task.Status.PENDING_REVIEW) # Notification should be sent to entry-level worker self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[0].user.email) self.assertEquals(notification['subject'], 'Your task is under review!') _validate_slack_messages('Task is awaiting review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Reviewer picks up task task = assign_task(self.workers[1].id, task.id) self.assertEquals(task.status, Task.Status.REVIEWING) # No notification should be sent self.assertEquals(len(self.mail.inbox), 0) _validate_slack_messages('Task is under review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Reviewer rejects task task = submit_task(task.id, {}, TaskAssignment.SnapshotType.REJECT, self.workers[1], 0) self.assertEquals(task.status, Task.Status.POST_REVIEW_PROCESSING) # Notification should be sent to original worker self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[0].user.email) self.assertEquals(notification['subject'], 'Your task has been returned') _validate_slack_messages('Task was returned by reviewer.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Entry-level worker resubmits task task = submit_task(task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[0], 0) self.assertEquals(task.status, Task.Status.REVIEWING) # Notification should be sent to reviewer self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[1].user.email) self.assertEquals(notification['subject'], 'A task is ready for re-review!') _validate_slack_messages('Task is under review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # First reviewer accepts task with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): task = submit_task(task.id, {}, TaskAssignment.SnapshotType.ACCEPT, self.workers[1], 0) self.assertEquals(task.status, Task.Status.PENDING_REVIEW) # Notification should be sent to first reviewer self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[1].user.email) self.assertEquals(notification['subject'], 'Your task is under review!') _validate_slack_messages('Task is awaiting review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Second reviewer picks up task task = assign_task(self.workers[3].id, task.id) self.assertEquals(task.status, Task.Status.REVIEWING) # No notification should be sent self.assertEquals(len(self.mail.inbox), 0) _validate_slack_messages('Task is under review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Second reviewer rejects task task = submit_task(task.id, {}, TaskAssignment.SnapshotType.REJECT, self.workers[3], 0) self.assertEquals(task.status, Task.Status.POST_REVIEW_PROCESSING) # Notification should be sent to first reviewer self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[1].user.email) self.assertEquals(notification['subject'], 'Your task has been returned') _validate_slack_messages('Task was returned by reviewer.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # First reviewer resubmits task task = submit_task(task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[1], 0) self.assertEquals(task.status, Task.Status.REVIEWING) # Notification should be sent to second reviewer self.assertEquals(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEquals(notification['recipient'], self.workers[3].user.email) self.assertEquals(notification['subject'], 'A task is ready for re-review!') _validate_slack_messages('Task is under review.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # Second reviewer accepts task; task is complete with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): task = submit_task(task.id, {}, TaskAssignment.SnapshotType.ACCEPT, self.workers[3], 0) self.assertEquals(task.status, Task.Status.COMPLETE) # Notification should be sent to all workers on task self.assertEquals(len(self.mail.inbox), 3) recipients = {mail['recipient'] for mail in self.mail.inbox} subjects = {mail['subject'] for mail in self.mail.inbox} self.assertEquals(recipients, {self.workers[uid].user.email for uid in (0, 1, 3)}) self.assertEquals(subjects, {'Task complete!'}) self.mail.clear() _validate_slack_messages('Task has been completed.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0) # End project end_project(task.project.id) task = Task.objects.get(id=task.id) self.assertEquals(task.status, Task.Status.ABORTED) # Notification should be sent to all workers on task self.assertEquals(len(self.mail.inbox), 3) recipients = {mail['recipient'] for mail in self.mail.inbox} subjects = {mail['subject'] for mail in self.mail.inbox} self.assertEquals(recipients, {self.workers[uid].user.email for uid in (0, 1, 3)}) self.assertEquals(subjects, {'A task you were working on has been ended'}) self.mail.clear() for task in project.tasks.all(): _validate_slack_messages('Task has been aborted.') self.assertEquals(len(internal_slack_messages), 0) self.assertEquals(len(experts_slack_messages), 0)
def test_preassign_workers(self): project = self.projects['assignment_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEquals(related_task.assignments.count(), 0) self.assertEquals(related_task.status, Task.Status.AWAITING_PROCESSING) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; verify we use the reviewer assignment policy mock_preassign_workers = MagicMock(return_value=initial_task) patch_path = 'orchestra.utils.task_lifecycle._preassign_workers' with patch(patch_path, new=mock_preassign_workers): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) mock_preassign_workers.assert_called_once_with( initial_task, AssignmentPolicyType.REVIEWER) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 4 initial_task = assign_task(self.workers[4].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[4]) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 4 is certified for related task and should have been assigned self.assertEquals(related_task.assignments.count(), 1) self.assertEquals(related_task.status, Task.Status.PROCESSING) self.assertTrue(related_task.is_worker_assigned(self.workers[4])) # Reset project project.tasks.all().delete()
def test_preassign_workers(self): project = self.projects['assignment_policy'] # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 0 not certified for related tasks, so should not have been # auto-assigned self.assertEquals(related_task.assignments.count(), 0) self.assertEquals(related_task.status, Task.Status.AWAITING_PROCESSING) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 0 initial_task = assign_task(self.workers[0].id, project.tasks.first().id) # Submit task; verify we use the reviewer assignment policy mock_preassign_workers = MagicMock(return_value=initial_task) patch_path = 'orchestra.utils.task_lifecycle._preassign_workers' with patch(patch_path, new=mock_preassign_workers): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) mock_preassign_workers.assert_called_once_with( initial_task, AssignmentPolicyType.REVIEWER) # Reset project project.tasks.all().delete() # Create first task in test project create_subsequent_tasks(project) self.assertEquals(project.tasks.count(), 1) # Assign initial task to worker 4 initial_task = assign_task(self.workers[4].id, project.tasks.first().id) # Submit task; next task should be created with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): initial_task = submit_task(initial_task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[4]) self.assertEquals(project.tasks.count(), 2) related_task = project.tasks.exclude(id=initial_task.id).first() # Worker 4 is certified for related task and should have been assigned self.assertEquals(related_task.assignments.count(), 1) self.assertEquals(related_task.status, Task.Status.PROCESSING) self.assertTrue( related_task.is_worker_assigned(self.workers[4]))
def setup_complete_task(test_case, times): task = TaskFactory(project=test_case.projects['empty_project'], status=Task.Status.AWAITING_PROCESSING, step=test_case.test_step, start_datetime=times['awaiting_pickup']) workers = {'entry': test_case.workers[0], 'reviewer': test_case.workers[1]} assign_task(workers['entry'].id, task.id) entry_assignment = task.assignments.get(worker=workers['entry']) # Modify assignment with correct datetime entry_assignment.start_datetime = times['entry_pickup'] entry_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PROCESSING) submit_task(task.id, {'test': 'entry_submit'}, TaskAssignment.SnapshotType.SUBMIT, workers['entry'], 0) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PENDING_REVIEW) # Modify snapshot with correct datetime entry_assignment.refresh_from_db() (entry_assignment.snapshots['snapshots'][0]['datetime'] ) = times['entry_submit'] entry_assignment.save() assign_task(workers['reviewer'].id, task.id) reviewer_assignment = task.assignments.get(worker=workers['reviewer']) # Modify assignment with correct datetime reviewer_assignment.start_datetime = times['reviewer_pickup'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) submit_task(task.id, {'test': 'reviewer_reject'}, TaskAssignment.SnapshotType.REJECT, workers['reviewer'], 0) # Modify snapshot with correct datetime reviewer_assignment.refresh_from_db() (reviewer_assignment.snapshots['snapshots'][0]['datetime'] ) = times['reviewer_reject'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.POST_REVIEW_PROCESSING) submit_task(task.id, {'test': 'entry_resubmit'}, TaskAssignment.SnapshotType.SUBMIT, workers['entry'], 0) # Modify snapshot with correct datetime entry_assignment.refresh_from_db() (entry_assignment.snapshots['snapshots'][1]['datetime'] ) = times['entry_resubmit'] entry_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): submit_task(task.id, {'test': 'reviewer_accept'}, TaskAssignment.SnapshotType.ACCEPT, workers['reviewer'], 0) # Modify snapshot with correct datetime reviewer_assignment.refresh_from_db() (reviewer_assignment.snapshots['snapshots'][1]['datetime'] ) = times['reviewer_accept'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.COMPLETE) test_case.assertEquals(task.assignments.count(), 2) for assignment in task.assignments.all(): test_case.assertEquals(assignment.status, TaskAssignment.Status.SUBMITTED) test_case.assertEquals(len(assignment.snapshots['snapshots']), 2) return task
def test_task_form_save(self): """ Test task form save for new, human and machine tasks """ # Workflow steps are hard-coded on `choices` for `Project` models # regardless of `settings.py`. Once we move workflows back into the # database, we should use the test workflows rather than the production # ones in `settings.py.` Until then, the hack below suffices. workflows = get_workflows() test_workflow_slug = 'website_design' workflow = workflows[test_workflow_slug] human_steps = {step_slug: step for step_slug, step in workflow.steps.items() if step.worker_type == Step.WorkerType.HUMAN} step_slug, step = human_steps.popitem() project = ProjectFactory(workflow_slug=test_workflow_slug) for certification_slug in step.required_certifications: certification = CertificationFactory(slug=certification_slug) for uname in (0, 1, 3, 6): WorkerCertificationFactory( certification=certification, worker=self.workers[uname], role=WorkerCertification.Role.ENTRY_LEVEL) for uname in (3, 6): WorkerCertificationFactory( certification=certification, worker=self.workers[uname], role=WorkerCertification.Role.REVIEWER) # Add new task to project form = TaskForm({'project': project.id, 'status': Task.Status.AWAITING_PROCESSING, 'step_slug': step_slug}) form.is_valid() self.assertTrue(form.is_valid()) task = form.save() self.assertFalse(task.assignments.exists()) # Add new task to project and assign to entry_level worker (0) form = TaskForm({'project': project.id, 'status': Task.Status.AWAITING_PROCESSING, 'step_slug': step_slug}) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[0].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[0], task)) self.assertEquals(assignment_history(task).count(), 1) self.assertTrue(task.assignments.exists()) self.assertEquals(task.status, Task.Status.PROCESSING) # Render task with preexisting entry_level assignment (0) and reassign # to another entry_level worker (1) form = TaskForm(model_to_dict(task), instance=task) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[0].id) form.is_valid() self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[1].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[1], task)) self.assertEquals(assignment_history(task).count(), 1) self.assertEquals(task.status, Task.Status.PROCESSING) # Submit task with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): task = submit_task(task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[1], 0) # Assign to reviewer (3) and reassign to another reviewer (6) task = assign_task(self.workers[3].id, task.id) self.assertTrue(task.status, Task.Status.REVIEWING) self.assertTrue(is_worker_assigned_to_task(self.workers[3], task)) task = Task.objects.get(id=task.id) form = TaskForm(model_to_dict(task), instance=task) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[3].id) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[6].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[6], task)) self.assertEquals(assignment_history(task).count(), 2) self.assertEquals(task.status, Task.Status.REVIEWING) # Attempt to reassign to non-certified worker (2) form = TaskForm(model_to_dict(task), instance=task) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[2].id with self.assertRaises(WorkerCertificationError): form.save()
def test_notify_status_change(self): project = self.projects['empty_project'] internal_name = settings.SLACK_INTERNAL_NOTIFICATION_CHANNEL.strip('#') internal_groups = [ group for group in self.slack.groups.list().body['groups'] if group['name'] == internal_name ] internal_group_id = internal_groups[0]['id'] internal_slack_messages = self.slack.get_messages(internal_group_id) experts_slack_messages = self.slack.get_messages( project.slack_group_id) def _validate_slack_messages(message_stub): """ Check that correct slack message was sent if API key present. """ self.assertIn(message_stub, internal_slack_messages.pop()) self.assertIn(message_stub, experts_slack_messages.pop()) task = TaskFactory(project=project, step=self.test_step, status=Task.Status.AWAITING_PROCESSING) # Entry-level worker picks up task self.assertEqual(task.status, Task.Status.AWAITING_PROCESSING) task = assign_task(self.workers[0].id, task.id) self.assertTrue(task.is_worker_assigned(self.workers[0])) # Notification should be sent to entry-level worker self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[0].user.email) self.assertEqual(notification['subject'], "You've been assigned to a new task!") _validate_slack_messages('Task has been picked up by a worker.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): # Entry-level worker submits task task = submit_task(task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) self.assertEqual(task.status, Task.Status.PENDING_REVIEW) # Notification should be sent to entry-level worker self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[0].user.email) self.assertEqual(notification['subject'], 'Your task is under review!') _validate_slack_messages('Task is awaiting review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Reviewer picks up task task = assign_task(self.workers[1].id, task.id) self.assertEqual(task.status, Task.Status.REVIEWING) # No notification should be sent self.assertEqual(len(self.mail.inbox), 0) _validate_slack_messages('Task is under review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Reviewer rejects task task = submit_task(task.id, {}, Iteration.Status.PROVIDED_REVIEW, self.workers[1]) self.assertEqual(task.status, Task.Status.POST_REVIEW_PROCESSING) # Notification should be sent to original worker self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[0].user.email) self.assertEqual(notification['subject'], 'Your task has been returned') _validate_slack_messages('Task was returned by reviewer.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Entry-level worker resubmits task task = submit_task(task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[0]) self.assertEqual(task.status, Task.Status.REVIEWING) # Notification should be sent to reviewer self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[1].user.email) self.assertEqual(notification['subject'], 'A task is ready for re-review!') _validate_slack_messages('Task is under review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # First reviewer accepts task with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): task = submit_task(task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[1]) self.assertEqual(task.status, Task.Status.PENDING_REVIEW) # Notification should be sent to first reviewer self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[1].user.email) self.assertEqual(notification['subject'], 'Your task is under review!') _validate_slack_messages('Task is awaiting review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Second reviewer picks up task task = assign_task(self.workers[3].id, task.id) self.assertEqual(task.status, Task.Status.REVIEWING) # No notification should be sent self.assertEqual(len(self.mail.inbox), 0) _validate_slack_messages('Task is under review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Second reviewer rejects task task = submit_task(task.id, {}, Iteration.Status.PROVIDED_REVIEW, self.workers[3]) self.assertEqual(task.status, Task.Status.POST_REVIEW_PROCESSING) # Notification should be sent to first reviewer self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[1].user.email) self.assertEqual(notification['subject'], 'Your task has been returned') _validate_slack_messages('Task was returned by reviewer.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # First reviewer resubmits task task = submit_task(task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[1]) self.assertEqual(task.status, Task.Status.REVIEWING) # Notification should be sent to second reviewer self.assertEqual(len(self.mail.inbox), 1) notification = self.mail.inbox.pop() self.assertEqual(notification['recipient'], self.workers[3].user.email) self.assertEqual(notification['subject'], 'A task is ready for re-review!') _validate_slack_messages('Task is under review.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # Second reviewer accepts task; task is complete with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): task = submit_task(task.id, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[3]) self.assertEqual(task.status, Task.Status.COMPLETE) # Notification should be sent to all workers on task self.assertEqual(len(self.mail.inbox), 3) recipients = {mail['recipient'] for mail in self.mail.inbox} subjects = {mail['subject'] for mail in self.mail.inbox} self.assertEqual(recipients, {self.workers[uid].user.email for uid in (0, 1, 3)}) self.assertEqual(subjects, {'Task complete!'}) self.mail.clear() _validate_slack_messages('Task has been completed.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0) # End project end_project(task.project.id) task = Task.objects.get(id=task.id) self.assertEqual(task.status, Task.Status.ABORTED) # Notification should be sent to all workers on task self.assertEqual(len(self.mail.inbox), 3) recipients = {mail['recipient'] for mail in self.mail.inbox} subjects = {mail['subject'] for mail in self.mail.inbox} self.assertEqual(recipients, {self.workers[uid].user.email for uid in (0, 1, 3)}) self.assertEqual(subjects, {'A task you were working on has been ended'}) self.mail.clear() for task in project.tasks.all(): _validate_slack_messages('Task has been aborted.') self.assertEqual(len(internal_slack_messages), 0) self.assertEqual(len(experts_slack_messages), 0)
def test_task_form_save(self): """ Test task form save for new, human and machine tasks """ workflow_version = self.workflow_versions['test_workflow'] human_step = self.workflow_steps[workflow_version.slug]['step1'] project = ProjectFactory(workflow_version=workflow_version) # Add new task to project form = TaskForm({'project': project.id, 'status': Task.Status.AWAITING_PROCESSING, 'step': human_step.id, 'start_datetime': timezone.now()}) form.is_valid() self.assertTrue(form.is_valid()) task = form.save() self.assertFalse(task.assignments.exists()) # Add new task to project and assign to entry_level worker (0) form = TaskForm({'project': project.id, 'status': Task.Status.AWAITING_PROCESSING, 'step': human_step.id, 'start_datetime': timezone.now()}) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[0].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[0], task)) self.assertEquals(assignment_history(task).count(), 1) self.assertTrue(task.assignments.exists()) self.assertEquals(task.status, Task.Status.PROCESSING) # Render task with preexisting entry_level assignment (0) and reassign # to another entry_level worker (4) form = TaskForm(model_to_dict(task), instance=task) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[0].id) form.is_valid() self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[4].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[4], task)) self.assertEquals(assignment_history(task).count(), 1) self.assertEquals(task.status, Task.Status.PROCESSING) # Submit task with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=True): task = submit_task(task.id, {}, TaskAssignment.SnapshotType.SUBMIT, self.workers[4], 0) # Assign to reviewer (1) and reassign to another reviewer (3) task = assign_task(self.workers[1].id, task.id) self.assertTrue(task.status, Task.Status.REVIEWING) self.assertTrue(is_worker_assigned_to_task(self.workers[1], task)) task = Task.objects.get(id=task.id) form = TaskForm(model_to_dict(task), instance=task) self.assertEquals(form.fields['currently_assigned_to'].initial, self.workers[1].id) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[3].id task = form.save() self.assertTrue(is_worker_assigned_to_task(self.workers[3], task)) self.assertEquals(assignment_history(task).count(), 2) self.assertEquals(task.status, Task.Status.REVIEWING) # Attempt to reassign to non-certified worker (2) form = TaskForm(model_to_dict(task), instance=task) self.assertTrue(form.is_valid()) form.cleaned_data['currently_assigned_to'] = self.workers[2].id with self.assertRaises(WorkerCertificationError): form.save()
def setup_complete_task(test_case): # Microseconds are truncated when manually saving models test_start = timezone.now().replace(microsecond=0) times = { 'awaiting_pickup': test_start, 'entry_pickup': test_start + timedelta(hours=1), 'entry_submit': test_start + timedelta(hours=2), 'reviewer_pickup': test_start + timedelta(hours=3), 'reviewer_reject': test_start + timedelta(hours=4), 'entry_resubmit': test_start + timedelta(hours=5), 'reviewer_accept': test_start + timedelta(hours=6), } task = TaskFactory( project=test_case.projects['empty_project'], status=Task.Status.AWAITING_PROCESSING, step=test_case.test_step, start_datetime=times['awaiting_pickup']) workers = { 'entry': test_case.workers[0], 'reviewer': test_case.workers[1] } assign_task(workers['entry'].id, task.id) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PROCESSING) submit_task( task.id, {'test': 'entry_submit'}, Iteration.Status.REQUESTED_REVIEW, workers['entry']) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PENDING_REVIEW) assign_task(workers['reviewer'].id, task.id) reviewer_assignment = task.assignments.get( worker=workers['reviewer']) # Modify assignment with correct datetime reviewer_assignment.start_datetime = times['reviewer_pickup'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) submit_task( task.id, {'test': 'reviewer_reject'}, Iteration.Status.PROVIDED_REVIEW, workers['reviewer']) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.POST_REVIEW_PROCESSING) submit_task( task.id, {'test': 'entry_resubmit'}, Iteration.Status.REQUESTED_REVIEW, workers['entry']) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): submit_task( task.id, {'test': 'reviewer_accept'}, Iteration.Status.REQUESTED_REVIEW, workers['reviewer']) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.COMPLETE) test_case.assertEquals(task.assignments.count(), 2) for assignment in task.assignments.all(): test_case.assertEquals( assignment.status, TaskAssignment.Status.SUBMITTED) test_case.assertEquals(assignment.iterations.count(), 2) # Modify assignments with correct datetime new_datetime_labels = ('entry_pickup', 'reviewer_pickup') for i, assignment in enumerate(assignment_history(task).all()): assignment.start_datetime = times[new_datetime_labels[i]] assignment.save() # Modify iterations with correct datetime new_datetime_labels = ( ('entry_pickup', 'entry_submit'), ('reviewer_pickup', 'reviewer_reject'), ('reviewer_reject', 'entry_resubmit'), ('entry_resubmit', 'reviewer_accept') ) new_datetimes = [ (times[start_label], times[end_label]) for start_label, end_label in new_datetime_labels] for i, iteration in enumerate(get_iteration_history(task)): iteration.start_datetime, iteration.end_datetime = new_datetimes[i] iteration.save() verify_iterations(task.id) return task
def setup_complete_task(test_case): # Microseconds are truncated when manually saving models test_start = timezone.now().replace(microsecond=0) times = { 'awaiting_pickup': test_start, 'entry_pickup': test_start + timedelta(hours=1), 'entry_submit': test_start + timedelta(hours=2), 'reviewer_pickup': test_start + timedelta(hours=3), 'reviewer_reject': test_start + timedelta(hours=4), 'entry_resubmit': test_start + timedelta(hours=5), 'reviewer_accept': test_start + timedelta(hours=6), } task = TaskFactory( project=test_case.projects['empty_project'], status=Task.Status.AWAITING_PROCESSING, step=test_case.test_step, start_datetime=times['awaiting_pickup']) workers = { 'entry': test_case.workers[0], 'reviewer': test_case.workers[1] } assign_task(workers['entry'].id, task.id) task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.PROCESSING) submit_task( task.id, {'test': 'entry_submit'}, Iteration.Status.REQUESTED_REVIEW, workers['entry']) task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.PENDING_REVIEW) assign_task(workers['reviewer'].id, task.id) reviewer_assignment = task.assignments.get( worker=workers['reviewer']) # Modify assignment with correct datetime reviewer_assignment.start_datetime = times['reviewer_pickup'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.REVIEWING) submit_task( task.id, {'test': 'reviewer_reject'}, Iteration.Status.PROVIDED_REVIEW, workers['reviewer']) task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.POST_REVIEW_PROCESSING) submit_task( task.id, {'test': 'entry_resubmit'}, Iteration.Status.REQUESTED_REVIEW, workers['entry']) task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.REVIEWING) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): submit_task( task.id, {'test': 'reviewer_accept'}, Iteration.Status.REQUESTED_REVIEW, workers['reviewer']) task.refresh_from_db() test_case.assertEqual(task.status, Task.Status.COMPLETE) test_case.assertEqual(task.assignments.count(), 2) for assignment in task.assignments.all(): test_case.assertEqual( assignment.status, TaskAssignment.Status.SUBMITTED) test_case.assertEqual(assignment.iterations.count(), 2) # Modify assignments with correct datetime new_datetime_labels = ('entry_pickup', 'reviewer_pickup') for i, assignment in enumerate(assignment_history(task).all()): assignment.start_datetime = times[new_datetime_labels[i]] assignment.save() # Modify iterations with correct datetime new_datetime_labels = ( ('entry_pickup', 'entry_submit'), ('reviewer_pickup', 'reviewer_reject'), ('reviewer_reject', 'entry_resubmit'), ('entry_resubmit', 'reviewer_accept') ) new_datetimes = [ (times[start_label], times[end_label]) for start_label, end_label in new_datetime_labels] for i, iteration in enumerate(get_iteration_history(task)): iteration.start_datetime, iteration.end_datetime = new_datetimes[i] iteration.save() verify_iterations(task.id) return task
def setup_complete_task(test_case, times): task = TaskFactory( project=test_case.projects['empty_project'], status=Task.Status.AWAITING_PROCESSING, step=test_case.test_step, start_datetime=times['awaiting_pickup']) workers = { 'entry': test_case.workers[0], 'reviewer': test_case.workers[1] } assign_task(workers['entry'].id, task.id) entry_assignment = task.assignments.get(worker=workers['entry']) # Modify assignment with correct datetime entry_assignment.start_datetime = times['entry_pickup'] entry_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PROCESSING) submit_task( task.id, {'test': 'entry_submit'}, TaskAssignment.SnapshotType.SUBMIT, workers['entry'], 0) task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.PENDING_REVIEW) # Modify snapshot with correct datetime entry_assignment.refresh_from_db() (entry_assignment.snapshots ['snapshots'][0]['datetime']) = times['entry_submit'] entry_assignment.save() assign_task(workers['reviewer'].id, task.id) reviewer_assignment = task.assignments.get( worker=workers['reviewer']) # Modify assignment with correct datetime reviewer_assignment.start_datetime = times['reviewer_pickup'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) submit_task( task.id, {'test': 'reviewer_reject'}, TaskAssignment.SnapshotType.REJECT, workers['reviewer'], 0) # Modify snapshot with correct datetime reviewer_assignment.refresh_from_db() (reviewer_assignment.snapshots ['snapshots'][0]['datetime']) = times['reviewer_reject'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.POST_REVIEW_PROCESSING) submit_task( task.id, {'test': 'entry_resubmit'}, TaskAssignment.SnapshotType.SUBMIT, workers['entry'], 0) # Modify snapshot with correct datetime entry_assignment.refresh_from_db() (entry_assignment.snapshots ['snapshots'][1]['datetime']) = times['entry_resubmit'] entry_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.REVIEWING) with patch('orchestra.utils.task_lifecycle._is_review_needed', return_value=False): submit_task( task.id, {'test': 'reviewer_accept'}, TaskAssignment.SnapshotType.ACCEPT, workers['reviewer'], 0) # Modify snapshot with correct datetime reviewer_assignment.refresh_from_db() (reviewer_assignment.snapshots ['snapshots'][1]['datetime']) = times['reviewer_accept'] reviewer_assignment.save() task.refresh_from_db() test_case.assertEquals(task.status, Task.Status.COMPLETE) test_case.assertEquals(task.assignments.count(), 2) for assignment in task.assignments.all(): test_case.assertEquals( assignment.status, TaskAssignment.Status.SUBMITTED) test_case.assertEquals(len(assignment.snapshots['snapshots']), 2) return task