Example #1
0
    def _test_reverted_task(self, task, iteration, num_iterations,
                            task_status, latest_data, expected_audit,
                            revert_before=False):
        response = self._revert_task(
            task, iteration, revert_before=revert_before, commit=False)
        self.assertEqual(response.status_code, 200)
        task.refresh_from_db()
        fake_audit = load_encoded_json(response.content)
        self.assertEqual(fake_audit, expected_audit)

        self.assertEqual(task.status, Task.Status.COMPLETE)
        self.assertEqual(task.assignments.count(), 2)
        for assignment in task.assignments.all():
            self.assertEqual(assignment.iterations.count(), 2)

        response = self._revert_task(
            task, iteration, revert_before=revert_before, commit=True)
        self.assertEqual(response.status_code, 200)
        task.refresh_from_db()
        audit = load_encoded_json(response.content)
        self.assertEqual(audit, fake_audit)
        task.refresh_from_db()
        self.assertEqual(task.status, task_status)
        self.assertEqual(
            get_iteration_history(task).count(), num_iterations)

        verify_iterations(task.id)

        if num_iterations:
            self.assertEqual(
                current_assignment(task).in_progress_task_data,
                latest_data)

        verify_iterations(task.id)
Example #2
0
def verify_iterations(task_id):
    task = Task.objects.get(id=task_id)
    iterations = list(get_iteration_history(task).all())
    if iterations:
        _verify_iteration_topology(iterations)
        _verify_iteration_data(iterations)
        _verify_iteration_datetimes(iterations)
Example #3
0
def verify_iterations(task_id):
    task = Task.objects.get(id=task_id)
    iterations = list(get_iteration_history(task).all())
    if iterations:
        _verify_iteration_topology(iterations)
        _verify_iteration_data(iterations)
        _verify_iteration_datetimes(iterations)
    def _test_reverted_task(self, task, iteration, num_iterations,
                            task_status, latest_data, expected_audit,
                            revert_before=False):
        response = self._revert_task(
            task, iteration, revert_before=revert_before, commit=False)
        self.assertEquals(response.status_code, 200)
        task.refresh_from_db()
        fake_audit = load_encoded_json(response.content)
        self.assertEqual(fake_audit, expected_audit)

        self.assertEquals(task.status, Task.Status.COMPLETE)
        self.assertEquals(task.assignments.count(), 2)
        for assignment in task.assignments.all():
            self.assertEquals(assignment.iterations.count(), 2)

        response = self._revert_task(
            task, iteration, revert_before=revert_before, commit=True)
        self.assertEqual(response.status_code, 200)
        task.refresh_from_db()
        audit = load_encoded_json(response.content)
        self.assertEqual(audit, fake_audit)
        task.refresh_from_db()
        self.assertEqual(task.status, task_status)
        self.assertEqual(
            get_iteration_history(task).count(), num_iterations)

        verify_iterations(task.id)

        if num_iterations:
            self.assertEquals(
                current_assignment(task).in_progress_task_data,
                latest_data)

        verify_iterations(task.id)
Example #5
0
 def _expected_audit(self,
                     complete_task,
                     reverted_status=None,
                     assignment_changes=None,
                     iteration_changes=None):
     assignments = assignment_history(complete_task)
     iterations = get_iteration_history(complete_task)
     audit = {
         'task':
         TaskSerializer(complete_task).data,
         'assignments': [{
             'assignment':
             (TaskAssignmentSerializer(assignments.first()).data),
             'change':
             0,
             'iterations': [{
                 'change':
                 0,
                 'iteration':
                 (IterationSerializer(iterations.all()[0]).data)
             }, {
                 'change':
                 0,
                 'iteration':
                 (IterationSerializer(iterations.all()[2]).data)
             }]
         }, {
             'assignment':
             (TaskAssignmentSerializer(assignments.last()).data),
             'change':
             0,
             'iterations': [{
                 'change':
                 0,
                 'iteration':
                 (IterationSerializer(iterations.all()[1]).data)
             }, {
                 'change':
                 0,
                 'iteration':
                 (IterationSerializer(iterations.all()[3]).data)
             }]
         }],
     }
     if reverted_status is not None:
         audit['reverted_status'] = reverted_status
     if assignment_changes is not None:
         for i, assignment_change in enumerate(assignment_changes):
             audit['assignments'][i]['change'] = assignment_change
     if iteration_changes is not None:
         for i, changes_per_assignment in enumerate(iteration_changes):
             for j, iteration_change in enumerate(changes_per_assignment):
                 audit['assignments'][i]['iterations'][j][
                     'change'] = iteration_change
     return audit
 def _expected_audit(self, complete_task, reverted_status=None,
                     assignment_changes=None, iteration_changes=None):
     assignments = assignment_history(complete_task)
     iterations = get_iteration_history(complete_task)
     audit = {
         'task': TaskSerializer(complete_task).data,
         'assignments': [
             {
                 'assignment': (
                     TaskAssignmentSerializer(assignments.first()).data),
                 'change': 0,
                 'iterations': [
                     {
                         'change': 0,
                         'iteration': (
                             IterationSerializer(iterations.all()[0]).data)
                     },
                     {
                         'change': 0,
                         'iteration': (
                             IterationSerializer(iterations.all()[2]).data)
                     }
                 ]
             },
             {
                 'assignment': (
                     TaskAssignmentSerializer(assignments.last()).data),
                 'change': 0,
                 'iterations': [
                     {
                         'change': 0,
                         'iteration': (
                             IterationSerializer(iterations.all()[1]).data)
                     },
                     {
                         'change': 0,
                         'iteration': (
                             IterationSerializer(iterations.all()[3]).data)
                     }
                 ]
             }
         ],
     }
     if reverted_status is not None:
         audit['reverted_status'] = reverted_status
     if assignment_changes is not None:
         for i, assignment_change in enumerate(assignment_changes):
             audit['assignments'][i]['change'] = assignment_change
     if iteration_changes is not None:
         for i, changes_per_assignment in enumerate(iteration_changes):
             for j, iteration_change in enumerate(changes_per_assignment):
                 audit['assignments'][i][
                     'iterations'][j]['change'] = iteration_change
     return audit
Example #7
0
def _reverted_task_status(task_audit, revert_before):
    """
    Reverts the status of an otherwise-reverted task.

    Args:
        task (dict):
            Audit containing task data to be changed upon revert.

    Returns:
        status (orchestra.models.Task.Status):
            The status of the task if it were reverted.
    """
    task = Task.objects.get(id=task_audit['task']['id'])

    flattened_iterations = [
        iteration_audit
        for assignment_audit in task_audit['assignments']
        for iteration_audit in assignment_audit['iterations']]
    changed_items = _parse_changed_items(flattened_iterations, 'iteration')

    latest_iterations = (
        get_iteration_history(task, reverse=True)
        .exclude(id__in=changed_items[RevertChange.DELETED.value]))

    num_iterations = latest_iterations.count()
    if num_iterations == 0:
        return Task.Status.AWAITING_PROCESSING
    elif revert_before:
        # Reverting before the first iteration in an assignment means the task
        # is pending review, since at least one iteration exists
        return Task.Status.PENDING_REVIEW
    else:
        # Revert to a processing iteration state
        if num_iterations == 1:
            return Task.Status.PROCESSING
        else:
            previous_status = latest_iterations[1].status
            if previous_status == Iteration.Status.REQUESTED_REVIEW:
                return Task.Status.REVIEWING
            else:
                return Task.Status.POST_REVIEW_PROCESSING
Example #8
0
def _reverted_task_status(task_audit, revert_before):
    """
    Reverts the status of an otherwise-reverted task.

    Args:
        task (dict):
            Audit containing task data to be changed upon revert.

    Returns:
        status (orchestra.models.Task.Status):
            The status of the task if it were reverted.
    """
    task = Task.objects.get(id=task_audit['task']['id'])

    flattened_iterations = [
        iteration_audit for assignment_audit in task_audit['assignments']
        for iteration_audit in assignment_audit['iterations']
    ]
    changed_items = _parse_changed_items(flattened_iterations, 'iteration')

    latest_iterations = (get_iteration_history(task, reverse=True).exclude(
        id__in=changed_items[RevertChange.DELETED.value]))

    num_iterations = latest_iterations.count()
    if num_iterations == 0:
        return Task.Status.AWAITING_PROCESSING
    elif revert_before:
        # Reverting before the first iteration in an assignment means the task
        # is pending review, since at least one iteration exists
        return Task.Status.PENDING_REVIEW
    else:
        # Revert to a processing iteration state
        if num_iterations == 1:
            return Task.Status.PROCESSING
        else:
            previous_status = latest_iterations[1].status
            if previous_status == Iteration.Status.REQUESTED_REVIEW:
                return Task.Status.REVIEWING
            else:
                return Task.Status.POST_REVIEW_PROCESSING
Example #9
0
    def test_revert_processing(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.PROCESSING

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(RevertChange.REVERTED.value,
                                RevertChange.DELETED.value),
            iteration_changes=((RevertChange.REVERTED.value,
                                RevertChange.DELETED.value),
                               (RevertChange.DELETED.value,
                                RevertChange.DELETED.value)))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[0],
            num_iterations=1,
            task_status=reverted_status,
            latest_data={'test': 'entry_resubmit'},
            expected_audit=expected_audit)

        task.delete()
Example #10
0
    def test_revert_first_review(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.REVIEWING

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(RevertChange.REVERTED.value,
                                RevertChange.REVERTED.value),
            iteration_changes=((RevertChange.UNCHANGED.value,
                                RevertChange.DELETED.value),
                               (RevertChange.REVERTED.value,
                                RevertChange.DELETED.value)))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[1],
            num_iterations=2,
            task_status=reverted_status,
            latest_data={'test': 'reviewer_accept'},
            expected_audit=expected_audit)

        task.delete()
    def test_revert_processing(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.PROCESSING

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(
                RevertChange.REVERTED.value, RevertChange.DELETED.value),
            iteration_changes=(
                (RevertChange.REVERTED.value, RevertChange.DELETED.value),
                (RevertChange.DELETED.value, RevertChange.DELETED.value)
            ))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[0],
            num_iterations=1,
            task_status=reverted_status,
            latest_data={'test': 'entry_resubmit'},
            expected_audit=expected_audit)

        task.delete()
    def test_revert_first_review(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.REVIEWING

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(
                RevertChange.REVERTED.value, RevertChange.REVERTED.value),
            iteration_changes=(
                (RevertChange.UNCHANGED.value, RevertChange.DELETED.value),
                (RevertChange.REVERTED.value, RevertChange.DELETED.value)
            ))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[1],
            num_iterations=2,
            task_status=reverted_status,
            latest_data={'test': 'reviewer_accept'},
            expected_audit=expected_audit)

        task.delete()
Example #13
0
    def test_revert_pending_review(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.PENDING_REVIEW

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(RevertChange.REVERTED.value,
                                RevertChange.DELETED.value),
            iteration_changes=((RevertChange.UNCHANGED.value,
                                RevertChange.DELETED.value),
                               (RevertChange.DELETED.value,
                                RevertChange.DELETED.value)))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[1],
            num_iterations=1,
            task_status=reverted_status,
            latest_data={'test': 'entry_resubmit'},
            expected_audit=expected_audit,
            revert_before=True)

        task.delete()
    def test_revert_pending_review(self):
        task = setup_complete_task(self)
        reverted_status = Task.Status.PENDING_REVIEW

        expected_audit = self._expected_audit(
            task,
            reverted_status=reverted_status,
            assignment_changes=(
                RevertChange.REVERTED.value, RevertChange.DELETED.value),
            iteration_changes=(
                (RevertChange.UNCHANGED.value, RevertChange.DELETED.value),
                (RevertChange.DELETED.value, RevertChange.DELETED.value)
            ))

        self._test_reverted_task(
            task,
            iteration=get_iteration_history(task).all()[1],
            num_iterations=1,
            task_status=reverted_status,
            latest_data={'test': 'entry_resubmit'},
            expected_audit=expected_audit,
            revert_before=True)

        task.delete()
Example #15
0
def _setup_tasks(test_case, tasks):
    # Create and assign tasks
    test_case.tasks = {}
    test_case.test_step = test_case.workflow_steps[
        test_case.test_version_slug][test_case.test_step_slug]
    for task_slug, details in tasks.items():
        task_pickup_time = BASE_DATETIME + timedelta(hours=1)
        task = TaskFactory(
            project=test_case.projects[details['project_name']],
            step=test_case.test_step,
            status=details['status'],
            start_datetime=task_pickup_time,
        )
        test_case.tasks[task_slug] = task
        for i, (user_id,
                task_data,
                assignment_status) in enumerate(details['assignments']):
            assignment = TaskAssignmentFactory(
                worker=test_case.workers[user_id],
                task=task,
                status=assignment_status,
                assignment_counter=i,
                in_progress_task_data=task_data,
                start_datetime=_new_assignment_start_datetime(task))

            # Each assignment must have at least one corresponding iteration
            Iteration.objects.create(
                assignment=assignment,
                start_datetime=assignment.start_datetime,
                end_datetime=assignment.start_datetime + ITERATION_DURATION,
                submitted_data=assignment.in_progress_task_data,
                status=Iteration.Status.REQUESTED_REVIEW)

            # Create time entry for each task.
            TimeEntryFactory(date='2016-04-04',
                             time_worked=timedelta(minutes=30),
                             assignment=assignment,
                             worker=test_case.workers[user_id],
                             description=(
                                 'test description {}'.format(assignment.id)))

        cur_assignment = current_assignment(task)
        assignments = assignment_history(task).all()
        if cur_assignment and (
                cur_assignment.status == TaskAssignment.Status.PROCESSING):
            # If there's a currently processing assignment, we'll need to
            # adjust the task's iteration sequence
            processing_counter = cur_assignment.assignment_counter
            if processing_counter != len(assignments) - 1:
                # If processing assignment is not the last in the hierarchy, we
                # need to reconstruct an iteration sequence: REQUESTED_REVIEW
                # up to the highest assignment counter, then PROVIDED_REVIEW
                # back down to the current assignment
                last_iteration = assignments.last().iterations.first()
                last_iteration.status = Iteration.Status.PROVIDED_REVIEW
                last_iteration.save()

                adjust_assignments = list(assignments)[processing_counter:-1]
                for assignment in reversed(adjust_assignments):
                    last_iteration = get_iteration_history(task).last()
                    Iteration.objects.create(
                        assignment=assignment,
                        start_datetime=last_iteration.end_datetime,
                        end_datetime=(
                            last_iteration.end_datetime + ITERATION_DURATION),
                        submitted_data=assignment.in_progress_task_data,
                        status=Iteration.Status.PROVIDED_REVIEW)

            # If there is a currently processing assignment, the task's last
            # iteration should still be processing
            last_iteration = get_iteration_history(task).last()
            last_iteration.end_datetime = None
            last_iteration.submitted_data = {}
            last_iteration.status = Iteration.Status.PROCESSING
            last_iteration.save()

        verify_iterations(task.id)
Example #16
0
def _setup_tasks(test_case, tasks):
    # Create and assign tasks
    test_case.tasks = {}
    test_case.test_step = test_case.workflow_steps[
        test_case.test_version_slug][test_case.test_step_slug]
    for task_slug, details in tasks.items():
        task_pickup_time = BASE_DATETIME + timedelta(hours=1)
        task = TaskFactory(
            project=test_case.projects[details['project_name']],
            step=test_case.test_step,
            status=details['status'],
            start_datetime=task_pickup_time,
        )
        test_case.tasks[task_slug] = task
        for i, (user_id,
                task_data,
                assignment_status) in enumerate(details['assignments']):
            assignment = TaskAssignmentFactory(
                worker=test_case.workers[user_id],
                task=task,
                status=assignment_status,
                assignment_counter=i,
                in_progress_task_data=task_data,
                start_datetime=_new_assignment_start_datetime(task))

            # Each assignment must have at least one corresponding iteration
            Iteration.objects.create(
                assignment=assignment,
                start_datetime=assignment.start_datetime,
                end_datetime=assignment.start_datetime + ITERATION_DURATION,
                submitted_data=assignment.in_progress_task_data,
                status=Iteration.Status.REQUESTED_REVIEW)

            # Create time entry for each task.
            TimeEntryFactory(date='2016-04-04',
                             time_worked=timedelta(minutes=30),
                             assignment=assignment,
                             worker=test_case.workers[user_id],
                             description=(
                                 'test description {}'.format(assignment.id)))

        cur_assignment = current_assignment(task)
        assignments = assignment_history(task).all()
        if cur_assignment and (
                cur_assignment.status == TaskAssignment.Status.PROCESSING):
            # If there's a currently processing assignment, we'll need to
            # adjust the task's iteration sequence
            processing_counter = cur_assignment.assignment_counter
            if processing_counter != len(assignments) - 1:
                # If processing assignment is not the last in the hierarchy, we
                # need to reconstruct an iteration sequence: REQUESTED_REVIEW
                # up to the highest assignment counter, then PROVIDED_REVIEW
                # back down to the current assignment
                last_iteration = assignments.last().iterations.first()
                last_iteration.status = Iteration.Status.PROVIDED_REVIEW
                last_iteration.save()

                adjust_assignments = list(assignments)[processing_counter:-1]
                for assignment in reversed(adjust_assignments):
                    last_iteration = get_iteration_history(task).last()
                    Iteration.objects.create(
                        assignment=assignment,
                        start_datetime=last_iteration.end_datetime,
                        end_datetime=(
                            last_iteration.end_datetime + ITERATION_DURATION),
                        submitted_data=assignment.in_progress_task_data,
                        status=Iteration.Status.PROVIDED_REVIEW)

            # If there is a currently processing assignment, the task's last
            # iteration should still be processing
            last_iteration = get_iteration_history(task).last()
            last_iteration.end_datetime = None
            last_iteration.submitted_data = {}
            last_iteration.status = Iteration.Status.PROCESSING
            last_iteration.save()

        verify_iterations(task.id)
Example #17
0
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
Example #18
0
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