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.assertEqual(project.tasks.count(), 1) # Assign initial task to worker 0 task = project.tasks.first() counter = role_counter_required_for_new_task(task) self.assertEqual(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.assertEqual(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.assertEqual(counter, 2)
def test_staff_command(self, mock_slack, mock_mail): task = TaskFactory(status=Task.Status.AWAITING_PROCESSING) data = get_mock_slack_data(text='staff {}'.format(task.id), user_id=self.worker.slack_user_id) response = self.request_client.post(self.url, data) self.assertEqual( load_encoded_json(response.content)['attachments'][0]['text'], self.staffbot.staffing_success.format(task.id)) task = TaskFactory(status=Task.Status.PENDING_REVIEW) data = get_mock_slack_data(text='staff {}'.format(task.id), user_id=self.worker.slack_user_id) response = self.request_client.post(self.url, data) self.assertEqual( load_encoded_json(response.content)['attachments'][0]['text'], self.staffbot.staffing_success.format(task.id))
def test_assign_task(self): entry_task = TaskFactory(project=self.projects['base_test_project'], status=Task.Status.AWAITING_PROCESSING, step=self.test_step) # Assign entry-level task to entry-level worker entry_task = assign_task(self.workers[0].id, entry_task.id) self.assertTrue(is_worker_assigned_to_task(self.workers[0], entry_task)) self.assertEquals(entry_task.status, Task.Status.PROCESSING) self.assertEquals(entry_task.assignments.count(), 1) # Attempt to assign task which isn't awaiting a new assignment invalid = (Task.Status.PROCESSING, Task.Status.ABORTED, Task.Status.REVIEWING, Task.Status.COMPLETE, Task.Status.POST_REVIEW_PROCESSING) for status in invalid: invalid_status_task = Task.objects.create( project=self.projects['base_test_project'], status=status, step=self.test_step) with self.assertRaises(TaskAssignmentError): invalid_status_task = assign_task(self.workers[0].id, invalid_status_task.id) # Attempt to assign review task to worker already in review hierarchy review_task = Task.objects.create( project=self.projects['base_test_project'], status=Task.Status.PENDING_REVIEW, step=self.test_step) test_data = {'test_assign': True} TaskAssignmentFactory(worker=self.workers[1], task=review_task, status=TaskAssignment.Status.SUBMITTED, in_progress_task_data=test_data, snapshots=empty_snapshots()) with self.assertRaises(TaskAssignmentError): assign_task(self.workers[1].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Attempt to assign review task to worker not certified for task with self.assertRaises(WorkerCertificationError): assign_task(self.workers[2].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Assign review task to review worker self.assertEquals(review_task.assignments.count(), 1) review_task = assign_task(self.workers[3].id, review_task.id) self.assertEquals(review_task.assignments.count(), 2) self.assertEqual( current_assignment(review_task).worker, self.workers[3]) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) self.assertEquals(review_task.status, Task.Status.REVIEWING)
def _task_factory(status, path): description_no_kwargs = {'path': path} return TaskFactory( status=status, step=StepFactory( slug='stepslug', description='the step', detailed_description_function=description_no_kwargs), project__workflow_version__workflow__description=( 'the workflow'), project__short_description='the coolest project')
def test_restaff_command_errors(self): """ Test that the staffing logic errors are raised during staff command. """ bot = StaffBot() command = 'restaff 999999999999 unknown' data = get_mock_slack_data( text=command, user_id=self.worker.slack_user_id) response = bot.dispatch(data) self.assertEqual(response.get('text'), command) self.assertEqual(response['attachments'][0]['text'], bot.worker_does_not_exist.format('unknown')) worker = WorkerFactory(user__username='******') data['text'] = 'restaff 999999999999 username' response = bot.dispatch(data) self.assertEqual(response['attachments'][0]['text'], bot.task_does_not_exist_error.format('999999999999')) # making sure it works with slack username as well. worker.slack_username = '******' worker.save() data['text'] = 'restaff 999999999999 slackusername' response = bot.dispatch(data) self.assertEqual(response['attachments'][0]['text'], bot.task_does_not_exist_error.format('999999999999')) data['text'] = 'restaff' response = bot.dispatch(data) self.assertTrue(bot.default_error_text in response.get('text')) task = TaskFactory(status=Task.Status.COMPLETE) command = 'restaff {} {}'.format(task.id, worker.user.username) data['text'] = command response = bot.dispatch(data) self.assertEquals(response['attachments'][0]['text'], (bot.task_assignment_does_not_exist_error .format(worker.user.username, task.id)))
def test_worker_task_recent_todo_qas(self): todo_task_0 = TodoFactory(task=self.task_0) todo_task_1 = TodoFactory(task=self.task_1) # Zero TodoQAs self._verify_worker_task_recent_todo_qas( self.task_0, None, True) todo_qa_task_0 = TodoQAFactory(todo=todo_task_0, approved=False) # Most recent TodoQA is todo_qa_task_0 self._verify_worker_task_recent_todo_qas( self.task_0, todo_qa_task_0, True) self._verify_worker_task_recent_todo_qas( self.task_1, todo_qa_task_0, True) todo_qa_task_1 = TodoQAFactory(todo=todo_task_1, approved=False) # If available use the todo qa for the corresponding task. self._verify_worker_task_recent_todo_qas( self.task_0, todo_qa_task_0, True) self._verify_worker_task_recent_todo_qas( self.task_1, todo_qa_task_1, True) todo_qa_task_0.delete() # Most recent TodoQA is todo_qa_task_1 self._verify_worker_task_recent_todo_qas( self.task_0, todo_qa_task_1, True) self._verify_worker_task_recent_todo_qas( self.task_1, todo_qa_task_1, True) # Can't make requests for projects in which you're uninvolved. bad_task = TaskFactory() todo_bad_task = TodoFactory(task=bad_task) todo_qa_bad_task = TodoQAFactory(todo=todo_bad_task, approved=False) self._verify_worker_task_recent_todo_qas( bad_task, todo_qa_bad_task, False)
def test_staff_command_errors(self): """ Test that the staffing logic errors are raised during staff command. """ bot = StaffBot() data = get_mock_slack_data(text='staff 999999999999', user_id=self.worker.slack_user_id) response = bot.dispatch(data) self.assertEqual(response['attachments'][0]['text'], bot.task_does_not_exist_error.format('999999999999')) data['text'] = 'staff' response = bot.dispatch(data) self.assertTrue(bot.default_error_text in response.get('text')) task = TaskFactory(status=Task.Status.COMPLETE) data['text'] = 'staff {}'.format(task.id) response = bot.dispatch(data) self.assertEqual( response['attachments'][0]['text'], bot.task_assignment_error.format( task.id, 'Status incompatible with new assignment'))
def test_get_detailed_description(self): """ Verify that the detailed description text is valid """ # description functions are optional task = TaskFactory() self.assertEqual(task.get_detailed_description(), '') no_kwargs = { 'path': ('orchestra.tests.helpers.' 'fixtures.get_detailed_description') } task_no_kwargs = TaskFactory( step=StepFactory(slug='stepslug', detailed_description_function=no_kwargs)) self.assertEqual(task_no_kwargs.get_detailed_description(), 'No text given stepslug') with_kwargs = { 'path': ('orchestra.tests.helpers.' 'fixtures.get_detailed_description'), 'kwargs': { 'text': 'task 2 text', } } task_with_kwargs = TaskFactory( step=StepFactory(slug='stepslug', detailed_description_function=with_kwargs)) self.assertEqual(task_with_kwargs.get_detailed_description(), 'task 2 text stepslug') extra_kwargs = {'text': 'extra text'} self.assertEqual( task_with_kwargs.get_detailed_description( extra_kwargs=extra_kwargs), 'extra text stepslug' )
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_assign_task(self): entry_task = TaskFactory(project=self.projects['base_test_project'], status=Task.Status.AWAITING_PROCESSING, step=self.test_step) # No iterations should be present for task self.assertEqual( Iteration.objects.filter(assignment__task=entry_task).count(), 0) # Assign entry-level task to entry-level worker entry_task = assign_task(self.workers[0].id, entry_task.id) self.assertTrue(entry_task.is_worker_assigned(self.workers[0])) self.assertEqual(entry_task.status, Task.Status.PROCESSING) self.assertEqual(entry_task.assignments.count(), 1) entry_assignment = entry_task.assignments.first() # A single iteration was created for the assignment self.assertEqual(entry_assignment.iterations.count(), 1) self.assertEqual( Iteration.objects.filter(assignment__task=entry_task).count(), 1) self.assertEqual(entry_assignment.iterations.first().start_datetime, entry_assignment.start_datetime) # Attempt to assign task which isn't awaiting a new assignment invalid = (Task.Status.PROCESSING, Task.Status.ABORTED, Task.Status.REVIEWING, Task.Status.COMPLETE, Task.Status.POST_REVIEW_PROCESSING) for status in invalid: invalid_status_task = Task.objects.create( project=self.projects['base_test_project'], status=status, step=self.test_step) with self.assertRaises(TaskAssignmentError): invalid_status_task = assign_task(self.workers[0].id, invalid_status_task.id) # Attempt to assign review task to worker already in review hierarchy review_task = Task.objects.create( project=self.projects['base_test_project'], status=Task.Status.PENDING_REVIEW, step=self.test_step) test_data = {'test_assign': True} TaskAssignmentFactory(worker=self.workers[1], task=review_task, status=TaskAssignment.Status.SUBMITTED, in_progress_task_data=test_data) with self.assertRaises(TaskAssignmentError): assign_task(self.workers[1].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Attempt to assign review task to worker not certified for task with self.assertRaises(WorkerCertificationError): assign_task(self.workers[2].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Assign review task to review worker self.assertEquals(review_task.assignments.count(), 1) review_task = assign_task(self.workers[3].id, review_task.id) self.assertEquals(review_task.assignments.count(), 2) reviewer_assignment = current_assignment(review_task) self.assertEqual(reviewer_assignment.worker, self.workers[3]) self.assertEqual(reviewer_assignment.in_progress_task_data, test_data) self.assertEquals(reviewer_assignment.iterations.count(), 1) self.assertEqual(reviewer_assignment.iterations.first().start_datetime, reviewer_assignment.start_datetime) self.assertEquals(review_task.status, Task.Status.REVIEWING)
def test_assign_task(self): entry_task = TaskFactory( project=self.projects['base_test_project'], status=Task.Status.AWAITING_PROCESSING, step=self.test_step) # No iterations should be present for task self.assertEqual( Iteration.objects.filter(assignment__task=entry_task).count(), 0) # Assign entry-level task to entry-level worker entry_task = assign_task(self.workers[0].id, entry_task.id) self.assertTrue(entry_task.is_worker_assigned(self.workers[0])) self.assertEqual(entry_task.status, Task.Status.PROCESSING) self.assertEqual(entry_task.assignments.count(), 1) entry_assignment = entry_task.assignments.first() # A single iteration was created for the assignment self.assertEqual(entry_assignment.iterations.count(), 1) self.assertEqual( Iteration.objects.filter(assignment__task=entry_task).count(), 1) self.assertEqual( entry_assignment.iterations.first().start_datetime, entry_assignment.start_datetime) # Attempt to assign task which isn't awaiting a new assignment invalid = (Task.Status.PROCESSING, Task.Status.ABORTED, Task.Status.REVIEWING, Task.Status.COMPLETE, Task.Status.POST_REVIEW_PROCESSING) for status in invalid: invalid_status_task = Task.objects.create( project=self.projects['base_test_project'], status=status, step=self.test_step) with self.assertRaises(TaskAssignmentError): invalid_status_task = assign_task( self.workers[0].id, invalid_status_task.id) # Attempt to assign review task to worker already in review hierarchy review_task = Task.objects.create( project=self.projects['base_test_project'], status=Task.Status.PENDING_REVIEW, step=self.test_step) test_data = {'test_assign': True} TaskAssignmentFactory( worker=self.workers[1], task=review_task, status=TaskAssignment.Status.SUBMITTED, in_progress_task_data=test_data) with self.assertRaises(TaskAssignmentError): assign_task(self.workers[1].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Attempt to assign review task to worker not certified for task with self.assertRaises(WorkerCertificationError): assign_task(self.workers[2].id, review_task.id) self.assertEqual( current_assignment(review_task).in_progress_task_data, test_data) # Assign review task to review worker self.assertEquals(review_task.assignments.count(), 1) review_task = assign_task(self.workers[3].id, review_task.id) self.assertEquals(review_task.assignments.count(), 2) reviewer_assignment = current_assignment(review_task) self.assertEqual( reviewer_assignment.worker, self.workers[3]) self.assertEqual( reviewer_assignment.in_progress_task_data, test_data) self.assertEquals( reviewer_assignment.iterations.count(), 1) self.assertEqual( reviewer_assignment.iterations.first().start_datetime, reviewer_assignment.start_datetime) self.assertEquals( review_task.status, Task.Status.REVIEWING)
def test_todos_list_create_permissions(self): # Can't make requests for projects in which you're uninvolved. task = TaskFactory() self._verify_todos_list(task.project.id, [], False) self._verify_todo_creation(task, False)
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.assertEquals(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.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, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[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, {}, Iteration.Status.PROVIDED_REVIEW, self.workers[1]) 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, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[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, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[1]) 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, {}, Iteration.Status.PROVIDED_REVIEW, self.workers[3]) 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, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[1]) 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, {}, Iteration.Status.REQUESTED_REVIEW, self.workers[3]) 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)