import json

from django.test import override_settings

from orchestra.models import Step
from orchestra.models import Task
from orchestra.models import Project
from orchestra.models import TaskAssignment
from orchestra.tests.helpers import OrchestraTransactionTestCase
from orchestra.tests.helpers.fixtures import setup_models
from orchestra.tests.helpers.iterations import verify_iterations
from orchestra.utils.load_json import load_encoded_json
from orchestra.utils.task_lifecycle import assign_task
from orchestra.utils.task_lifecycle import create_subsequent_tasks


class DashboardTestCase(OrchestraTransactionTestCase):

    def setUp(self):
        super().setUp()
        setup_models(self)

    @override_settings(MACHINE_STEP_SCHEDULER={
        'path': ('orchestra.utils.machine_step_scheduler.'
                 'SynchronousMachineStepScheduler'),
    })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()

        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(),
                         0)
        create_subsequent_tasks(project)

        # Human Task was created
        self.assertEqual(Task.objects.filter(project=project).count(),
                         1)

        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)

        # user 0 submits a task
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        # Machine Task was created
        self.assertEqual(Task.objects.filter(project=project).count(),
                         2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = (
            TaskAssignment.objects
            .filter(task__step=machine_step,
                    task__project=project)[0])

        self.assertEqual(machine_task_assignment.status,
                         TaskAssignment.Status.SUBMITTED)

        self.assertEqual(machine_task_assignment.in_progress_task_data,
                         {'json': 'simple'})

        self.assertEqual(machine_task_assignment.task.status,
                         Task.Status.COMPLETE)

    def test_index(self):
        response = self.clients[0].get('/orchestra/app/')
        self.assertEqual(response.status_code, 200)

    def test_status(self):
        response = self.clients[0].get('/orchestra/status/')
        self.assertEqual(response.status_code, 200)

    def test_dashboard_tasks(self):
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)

        # set tags for this task
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(
            worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()

        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        # task assignment for invalid id should give bad request
        self._verify_bad_task_assignment_information(
            self.clients[0], {'task_id': -1},
            'Task matching query does not exist.')

        # task assignment for user3 not assigned to a task
        self._verify_bad_task_assignment_information(
            self.clients[2], {'task_id': task.id},
            'Worker is not associated with task')

        # task assignment is assigned to user 0
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Processing', False,
            False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks']
                           if task['state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks']
                       if task['state'] != non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)

    def test_reviewer_task_assignment(self):
        task = self.tasks['review_task']
        assign_task(
            self.workers[1].id, task.id)
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, {'test_key': 'test_value'}, self.workers[1])

    def test_save_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        # incorrect task id
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': -1,
                        'task_data': 'test'}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'No task for given id')

        # user does not have a permission to save
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': 'test'}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not associated with task')

        # save new info
        new_data = {'new_test_key': 'new_test_value'}
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': new_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Processing', False,
            False, new_data, self.workers[0])

    def test_save_reviewer_task_assignment(self):
        new_data = {'new_test_key': 'new_test_value'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)

        # entry level worker can't update the data
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': new_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to save')

        reviewer_data = {'reviewer_key': 'reviewer_value'}

        # reviewer can update the data
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': reviewer_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, reviewer_data, self.workers[1])

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        verify_iterations(task.id)

        # user is not assigned to a task
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task assignment with worker is in broken state.')

        # task does not exist
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'No task for given id')

        # user 0 can only submit a task not reject
        response = self._submit_assignment(
            self.clients[0], task.id, command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task not in rejectable state.')

        # user 0 can't call illegal commands
        response = self._submit_assignment(
            self.clients[0], task.id, command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Illegal command')
        data = {'submit_key1': 'submit_val1'}

        # user 0 can't submit a task if its submission prerequisites aren't
        # complete
        step = task.step
        step.submission_depends_on.set([
            Step.objects.create(
                workflow_version=step.workflow_version,
                slug='imaginary_test_step',
                is_human=True,
            )
        ])
        step.save()
        response = self._submit_assignment(
            self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()

        data = {'submit_key1': 'submit_val1'}
        # user 0 submits a task
        response = self._submit_assignment(
            self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Pending Review', False,
            True, data, self.workers[0])

        # Check that iteration has correct submitted state
        verify_iterations(task.id)

        # user cannot resubmit a task
        response = self._submit_assignment(
            self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to submit')

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)

        verify_iterations(task.id)

        rejected_data = {'rejected_key': 'rejected_val'}

        # user 0 can retrieve data, but should see a read-only interface
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Reviewing', False,
            True, {'test_key': 'test_value'}, self.workers[0])

        # user 1 should be able to review the post
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, {'test_key': 'test_value'}, self.workers[1])

        # user 1 rejects a task
        response = self._submit_assignment(
            self.clients[1], task.id, data=rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # user 0 should have the task back
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Post-review Processing', False,
            False, rejected_data, self.workers[0])

        # user 1 should no longer be able to modify the post
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Post-review Processing', True,
            True, rejected_data, self.workers[1])

        # user 0 submits an updated data
        response = self._submit_assignment(
            self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if the data is saved
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, data, self.workers[1])

        accepted_data = {'accepted_key': 'accepted_val'}
        # user 1 accepts a task
        response = self._submit_assignment(
            self.clients[1], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if the accepted_data is saved
        # and task is pending for a second review.
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Pending Review', True,
            True, accepted_data, self.workers[1])

        # make sure a task can't be submitted twice
        response = self._submit_assignment(
            self.clients[1], task.id, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to submit')

        # user 3 is picking up a task as a reviewer
        assign_task(self.workers[3].id, task.id)

        verify_iterations(task.id)

        rejected_data = {'rejected_key': 'rejected_val'}

        # user 3 rejects a task
        response = self._submit_assignment(
            self.clients[3], task.id, data=rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)

        verify_iterations(task.id)

        # check if the rejected_data is saved
        self._verify_good_task_assignment_information(
            self.clients[3], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Post-review Processing', True,
            True, rejected_data, self.workers[3])

        # check client dashboards
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

        self._check_client_dashboard_state(self.clients[1], 'returned')

        self._check_client_dashboard_state(self.clients[3],
                                           'pending_processing')

        response = self._submit_assignment(
            self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if client dashboards were updated
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

        self._check_client_dashboard_state(self.clients[1], 'pending_review')

        self._check_client_dashboard_state(self.clients[3], 'in_progress')

        # check if the accepted_data is saved
        response = self._submit_assignment(
            self.clients[3], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)

        verify_iterations(task.id)

        # check if task is complete
        self._verify_good_task_assignment_information(
            self.clients[3], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Complete', True,
            True, accepted_data, self.workers[3])

        # check that reviewer cannot reaccept task
        response = self._submit_assignment(
            self.clients[3], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task already completed')

    def _verify_bad_task_assignment_information(
            self, client, post_data, error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/',
            json.dumps(post_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         error_message)

    def _verify_good_task_assignment_information(
            self, client, post_data, project_description,
            assignment_status, task_status, is_reviewer,
            is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/',
            json.dumps(post_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {
            'project': {'details': project_description,
                        'id': task.project.id,
                        'project_data': {},
                        'status': dict(
                            Project.STATUS_CHOICES)[task.project.status],
                        'scratchpad_url': None},
            'status': assignment_status,
            'task': {'data': task_data, 'status': task_status},
            'task_id': task.id,
            'assignment_id': task.assignments.get(worker=worker).id,
            'workflow': {
                'slug': 'w1', 'name': 'Workflow One',
            },
            'workflow_version': {
                'slug': 'test_workflow', 'name': 'The workflow'},
            'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer,
            'is_read_only': is_read_only,
            'is_project_admin': False,
            'worker': {
                'username': worker.user.username,
                'first_name': worker.user.first_name,
                'last_name': worker.user.last_name,
            }
        }

        self.assertEqual(returned, expected)

649d1de649d4a24d90cef460ddaca97efa288a8c
<mask token>


class DashboardTestCase(OrchestraTransactionTestCase):
    <mask token>

    @override_settings(MACHINE_STEP_SCHEDULER={'path':
        'orchestra.utils.machine_step_scheduler.SynchronousMachineStepScheduler'
        })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()
        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(), 0)
        create_subsequent_tasks(project)
        self.assertEqual(Task.objects.filter(project=project).count(), 1)
        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(Task.objects.filter(project=project).count(), 2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = TaskAssignment.objects.filter(task__step=
            machine_step, task__project=project)[0]
        self.assertEqual(machine_task_assignment.status, TaskAssignment.
            Status.SUBMITTED)
        self.assertEqual(machine_task_assignment.in_progress_task_data, {
            'json': 'simple'})
        self.assertEqual(machine_task_assignment.task.status, Task.Status.
            COMPLETE)
    <mask token>
    <mask token>
    <mask token>

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()
        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        self._verify_bad_task_assignment_information(self.clients[0], {
            'task_id': -1}, 'Task matching query does not exist.')
        self._verify_bad_task_assignment_information(self.clients[2], {
            'task_id': task.id}, 'Worker is not associated with task')
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks'] if task[
            'state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks'] if task['state'] !=
            non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)
    <mask token>
    <mask token>
    <mask token>

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Task assignment with worker is in broken state.')
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self._submit_assignment(self.clients[0], task.id,
            command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task not in rejectable state.')
        response = self._submit_assignment(self.clients[0], task.id,
            command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Illegal command')
        data = {'submit_key1': 'submit_val1'}
        step = task.step
        step.submission_depends_on.set([Step.objects.create(
            workflow_version=step.workflow_version, slug=
            'imaginary_test_step', is_human=True)])
        step.save()
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()
        data = {'submit_key1': 'submit_val1'}
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', False, True, data, self.workers[0])
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Reviewing', False, True, {'test_key':
            'test_value'}, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])
        response = self._submit_assignment(self.clients[1], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Post-review Processing', False, False,
            rejected_data, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[1])
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, data, self.workers[1])
        accepted_data = {'accepted_key': 'accepted_val'}
        response = self._submit_assignment(self.clients[1], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', True, True, accepted_data, self.
            workers[1])
        response = self._submit_assignment(self.clients[1], task.id,
            command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )
        assign_task(self.workers[3].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        response = self._submit_assignment(self.clients[3], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[3])
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'returned')
        self._check_client_dashboard_state(self.clients[3],
            'pending_processing')
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'pending_review')
        self._check_client_dashboard_state(self.clients[3], 'in_progress')
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Complete', True, True, accepted_data, self.workers[3]
            )
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task already completed')

    def _verify_bad_task_assignment_information(self, client, post_data,
        error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], error_message)

    def _verify_good_task_assignment_information(self, client, post_data,
        project_description, assignment_status, task_status, is_reviewer,
        is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 200)
        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {'project': {'details': project_description, 'id': task.
            project.id, 'project_data': {}, 'status': dict(Project.
            STATUS_CHOICES)[task.project.status], 'scratchpad_url': None},
            'status': assignment_status, 'task': {'data': task_data,
            'status': task_status}, 'task_id': task.id, 'assignment_id':
            task.assignments.get(worker=worker).id, 'workflow': {'slug':
            'w1', 'name': 'Workflow One'}, 'workflow_version': {'slug':
            'test_workflow', 'name': 'The workflow'}, 'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer, 'is_read_only': is_read_only,
            'is_project_admin': False, 'worker': {'username': worker.user.
            username, 'first_name': worker.user.first_name, 'last_name':
            worker.user.last_name}}
        self.assertEqual(returned, expected)

<mask token>


class DashboardTestCase(OrchestraTransactionTestCase):
    <mask token>

    @override_settings(MACHINE_STEP_SCHEDULER={'path':
        'orchestra.utils.machine_step_scheduler.SynchronousMachineStepScheduler'
        })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()
        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(), 0)
        create_subsequent_tasks(project)
        self.assertEqual(Task.objects.filter(project=project).count(), 1)
        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(Task.objects.filter(project=project).count(), 2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = TaskAssignment.objects.filter(task__step=
            machine_step, task__project=project)[0]
        self.assertEqual(machine_task_assignment.status, TaskAssignment.
            Status.SUBMITTED)
        self.assertEqual(machine_task_assignment.in_progress_task_data, {
            'json': 'simple'})
        self.assertEqual(machine_task_assignment.task.status, Task.Status.
            COMPLETE)

    def test_index(self):
        response = self.clients[0].get('/orchestra/app/')
        self.assertEqual(response.status_code, 200)

    def test_status(self):
        response = self.clients[0].get('/orchestra/status/')
        self.assertEqual(response.status_code, 200)
    <mask token>

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()
        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        self._verify_bad_task_assignment_information(self.clients[0], {
            'task_id': -1}, 'Task matching query does not exist.')
        self._verify_bad_task_assignment_information(self.clients[2], {
            'task_id': task.id}, 'Worker is not associated with task')
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks'] if task[
            'state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks'] if task['state'] !=
            non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)
    <mask token>
    <mask token>
    <mask token>

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Task assignment with worker is in broken state.')
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self._submit_assignment(self.clients[0], task.id,
            command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task not in rejectable state.')
        response = self._submit_assignment(self.clients[0], task.id,
            command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Illegal command')
        data = {'submit_key1': 'submit_val1'}
        step = task.step
        step.submission_depends_on.set([Step.objects.create(
            workflow_version=step.workflow_version, slug=
            'imaginary_test_step', is_human=True)])
        step.save()
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()
        data = {'submit_key1': 'submit_val1'}
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', False, True, data, self.workers[0])
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Reviewing', False, True, {'test_key':
            'test_value'}, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])
        response = self._submit_assignment(self.clients[1], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Post-review Processing', False, False,
            rejected_data, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[1])
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, data, self.workers[1])
        accepted_data = {'accepted_key': 'accepted_val'}
        response = self._submit_assignment(self.clients[1], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', True, True, accepted_data, self.
            workers[1])
        response = self._submit_assignment(self.clients[1], task.id,
            command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )
        assign_task(self.workers[3].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        response = self._submit_assignment(self.clients[3], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[3])
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'returned')
        self._check_client_dashboard_state(self.clients[3],
            'pending_processing')
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'pending_review')
        self._check_client_dashboard_state(self.clients[3], 'in_progress')
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Complete', True, True, accepted_data, self.workers[3]
            )
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task already completed')

    def _verify_bad_task_assignment_information(self, client, post_data,
        error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], error_message)

    def _verify_good_task_assignment_information(self, client, post_data,
        project_description, assignment_status, task_status, is_reviewer,
        is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 200)
        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {'project': {'details': project_description, 'id': task.
            project.id, 'project_data': {}, 'status': dict(Project.
            STATUS_CHOICES)[task.project.status], 'scratchpad_url': None},
            'status': assignment_status, 'task': {'data': task_data,
            'status': task_status}, 'task_id': task.id, 'assignment_id':
            task.assignments.get(worker=worker).id, 'workflow': {'slug':
            'w1', 'name': 'Workflow One'}, 'workflow_version': {'slug':
            'test_workflow', 'name': 'The workflow'}, 'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer, 'is_read_only': is_read_only,
            'is_project_admin': False, 'worker': {'username': worker.user.
            username, 'first_name': worker.user.first_name, 'last_name':
            worker.user.last_name}}
        self.assertEqual(returned, expected)

<mask token>


class DashboardTestCase(OrchestraTransactionTestCase):
    <mask token>

    @override_settings(MACHINE_STEP_SCHEDULER={'path':
        'orchestra.utils.machine_step_scheduler.SynchronousMachineStepScheduler'
        })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()
        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(), 0)
        create_subsequent_tasks(project)
        self.assertEqual(Task.objects.filter(project=project).count(), 1)
        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(Task.objects.filter(project=project).count(), 2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = TaskAssignment.objects.filter(task__step=
            machine_step, task__project=project)[0]
        self.assertEqual(machine_task_assignment.status, TaskAssignment.
            Status.SUBMITTED)
        self.assertEqual(machine_task_assignment.in_progress_task_data, {
            'json': 'simple'})
        self.assertEqual(machine_task_assignment.task.status, Task.Status.
            COMPLETE)

    def test_index(self):
        response = self.clients[0].get('/orchestra/app/')
        self.assertEqual(response.status_code, 200)

    def test_status(self):
        response = self.clients[0].get('/orchestra/status/')
        self.assertEqual(response.status_code, 200)
    <mask token>

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()
        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        self._verify_bad_task_assignment_information(self.clients[0], {
            'task_id': -1}, 'Task matching query does not exist.')
        self._verify_bad_task_assignment_information(self.clients[2], {
            'task_id': task.id}, 'Worker is not associated with task')
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks'] if task[
            'state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks'] if task['state'] !=
            non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)

    def test_reviewer_task_assignment(self):
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])

    def test_save_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': -1, 'task_data': 'test'}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': 'test'}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Worker is not associated with task')
        new_data = {'new_test_key': 'new_test_value'}
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': new_data}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, new_data, self.workers[0]
            )
    <mask token>

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Task assignment with worker is in broken state.')
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self._submit_assignment(self.clients[0], task.id,
            command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task not in rejectable state.')
        response = self._submit_assignment(self.clients[0], task.id,
            command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Illegal command')
        data = {'submit_key1': 'submit_val1'}
        step = task.step
        step.submission_depends_on.set([Step.objects.create(
            workflow_version=step.workflow_version, slug=
            'imaginary_test_step', is_human=True)])
        step.save()
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()
        data = {'submit_key1': 'submit_val1'}
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', False, True, data, self.workers[0])
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Reviewing', False, True, {'test_key':
            'test_value'}, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])
        response = self._submit_assignment(self.clients[1], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Post-review Processing', False, False,
            rejected_data, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[1])
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, data, self.workers[1])
        accepted_data = {'accepted_key': 'accepted_val'}
        response = self._submit_assignment(self.clients[1], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', True, True, accepted_data, self.
            workers[1])
        response = self._submit_assignment(self.clients[1], task.id,
            command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )
        assign_task(self.workers[3].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        response = self._submit_assignment(self.clients[3], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[3])
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'returned')
        self._check_client_dashboard_state(self.clients[3],
            'pending_processing')
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'pending_review')
        self._check_client_dashboard_state(self.clients[3], 'in_progress')
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Complete', True, True, accepted_data, self.workers[3]
            )
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task already completed')

    def _verify_bad_task_assignment_information(self, client, post_data,
        error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], error_message)

    def _verify_good_task_assignment_information(self, client, post_data,
        project_description, assignment_status, task_status, is_reviewer,
        is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 200)
        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {'project': {'details': project_description, 'id': task.
            project.id, 'project_data': {}, 'status': dict(Project.
            STATUS_CHOICES)[task.project.status], 'scratchpad_url': None},
            'status': assignment_status, 'task': {'data': task_data,
            'status': task_status}, 'task_id': task.id, 'assignment_id':
            task.assignments.get(worker=worker).id, 'workflow': {'slug':
            'w1', 'name': 'Workflow One'}, 'workflow_version': {'slug':
            'test_workflow', 'name': 'The workflow'}, 'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer, 'is_read_only': is_read_only,
            'is_project_admin': False, 'worker': {'username': worker.user.
            username, 'first_name': worker.user.first_name, 'last_name':
            worker.user.last_name}}
        self.assertEqual(returned, expected)

<mask token>


class DashboardTestCase(OrchestraTransactionTestCase):
    <mask token>

    @override_settings(MACHINE_STEP_SCHEDULER={'path':
        'orchestra.utils.machine_step_scheduler.SynchronousMachineStepScheduler'
        })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()
        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(), 0)
        create_subsequent_tasks(project)
        self.assertEqual(Task.objects.filter(project=project).count(), 1)
        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(Task.objects.filter(project=project).count(), 2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = TaskAssignment.objects.filter(task__step=
            machine_step, task__project=project)[0]
        self.assertEqual(machine_task_assignment.status, TaskAssignment.
            Status.SUBMITTED)
        self.assertEqual(machine_task_assignment.in_progress_task_data, {
            'json': 'simple'})
        self.assertEqual(machine_task_assignment.task.status, Task.Status.
            COMPLETE)

    def test_index(self):
        response = self.clients[0].get('/orchestra/app/')
        self.assertEqual(response.status_code, 200)

    def test_status(self):
        response = self.clients[0].get('/orchestra/status/')
        self.assertEqual(response.status_code, 200)
    <mask token>

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()
        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        self._verify_bad_task_assignment_information(self.clients[0], {
            'task_id': -1}, 'Task matching query does not exist.')
        self._verify_bad_task_assignment_information(self.clients[2], {
            'task_id': task.id}, 'Worker is not associated with task')
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks'] if task[
            'state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks'] if task['state'] !=
            non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)

    def test_reviewer_task_assignment(self):
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])

    def test_save_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': -1, 'task_data': 'test'}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': 'test'}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Worker is not associated with task')
        new_data = {'new_test_key': 'new_test_value'}
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': new_data}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Processing', False, False, new_data, self.workers[0]
            )

    def test_save_reviewer_task_assignment(self):
        new_data = {'new_test_key': 'new_test_value'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': new_data}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to save')
        reviewer_data = {'reviewer_key': 'reviewer_value'}
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/', json.dumps({
            'task_id': task.id, 'task_data': reviewer_data}), content_type=
            'application/json')
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, reviewer_data, self.
            workers[1])

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Task assignment with worker is in broken state.')
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'No task for given id')
        response = self._submit_assignment(self.clients[0], task.id,
            command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task not in rejectable state.')
        response = self._submit_assignment(self.clients[0], task.id,
            command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Illegal command')
        data = {'submit_key1': 'submit_val1'}
        step = task.step
        step.submission_depends_on.set([Step.objects.create(
            workflow_version=step.workflow_version, slug=
            'imaginary_test_step', is_human=True)])
        step.save()
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
            'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()
        data = {'submit_key1': 'submit_val1'}
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', False, True, data, self.workers[0])
        verify_iterations(task.id)
        response = self._submit_assignment(self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Reviewing', False, True, {'test_key':
            'test_value'}, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, {'test_key':
            'test_value'}, self.workers[1])
        response = self._submit_assignment(self.clients[1], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[0], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Post-review Processing', False, False,
            rejected_data, self.workers[0])
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[1])
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Processing', 'Reviewing', True, False, data, self.workers[1])
        accepted_data = {'accepted_key': 'accepted_val'}
        response = self._submit_assignment(self.clients[1], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[1], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Pending Review', True, True, accepted_data, self.
            workers[1])
        response = self._submit_assignment(self.clients[1], task.id,
            command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Worker is not allowed to submit'
            )
        assign_task(self.workers[3].id, task.id)
        verify_iterations(task.id)
        rejected_data = {'rejected_key': 'rejected_val'}
        response = self._submit_assignment(self.clients[3], task.id, data=
            rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Post-review Processing', True, True,
            rejected_data, self.workers[3])
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'returned')
        self._check_client_dashboard_state(self.clients[3],
            'pending_processing')
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)
        verify_iterations(task.id)
        self._check_client_dashboard_state(self.clients[0], 'pending_review')
        self._check_client_dashboard_state(self.clients[1], 'pending_review')
        self._check_client_dashboard_state(self.clients[3], 'in_progress')
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)
        verify_iterations(task.id)
        self._verify_good_task_assignment_information(self.clients[3], {
            'task_id': task.id}, task.project.short_description,
            'Submitted', 'Complete', True, True, accepted_data, self.workers[3]
            )
        response = self._submit_assignment(self.clients[3], task.id, data=
            accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], 'Task already completed')

    def _verify_bad_task_assignment_information(self, client, post_data,
        error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'], error_message)

    def _verify_good_task_assignment_information(self, client, post_data,
        project_description, assignment_status, task_status, is_reviewer,
        is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/', json.
            dumps(post_data), content_type='application/json')
        self.assertEqual(response.status_code, 200)
        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {'project': {'details': project_description, 'id': task.
            project.id, 'project_data': {}, 'status': dict(Project.
            STATUS_CHOICES)[task.project.status], 'scratchpad_url': None},
            'status': assignment_status, 'task': {'data': task_data,
            'status': task_status}, 'task_id': task.id, 'assignment_id':
            task.assignments.get(worker=worker).id, 'workflow': {'slug':
            'w1', 'name': 'Workflow One'}, 'workflow_version': {'slug':
            'test_workflow', 'name': 'The workflow'}, 'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer, 'is_read_only': is_read_only,
            'is_project_admin': False, 'worker': {'username': worker.user.
            username, 'first_name': worker.user.first_name, 'last_name':
            worker.user.last_name}}
        self.assertEqual(returned, expected)

import json

from django.test import override_settings

from orchestra.models import Step
from orchestra.models import Task
from orchestra.models import Project
from orchestra.models import TaskAssignment
from orchestra.tests.helpers import OrchestraTransactionTestCase
from orchestra.tests.helpers.fixtures import setup_models
from orchestra.tests.helpers.iterations import verify_iterations
from orchestra.utils.load_json import load_encoded_json
from orchestra.utils.task_lifecycle import assign_task
from orchestra.utils.task_lifecycle import create_subsequent_tasks


class DashboardTestCase(OrchestraTransactionTestCase):

    def setUp(self):
        super().setUp()
        setup_models(self)

    @override_settings(MACHINE_STEP_SCHEDULER={
        'path': ('orchestra.utils.machine_step_scheduler.'
                 'SynchronousMachineStepScheduler'),
    })
    def test_task_creation(self):
        """
        Test human and machine task creation
        """
        Task.objects.filter(status=Task.Status.AWAITING_PROCESSING).delete()

        project = self.projects['test_human_and_machine']
        self.assertEqual(Task.objects.filter(project=project).count(),
                         0)
        create_subsequent_tasks(project)

        # Human Task was created
        self.assertEqual(Task.objects.filter(project=project).count(),
                         1)

        human_step = self.workflow_steps['test_workflow_2']['step4']
        task = Task.objects.get(step=human_step, project=project)
        data = {'submit_key1': 'submit_val1'}
        assign_task(self.workers[0].id, task.id)

        # user 0 submits a task
        response = self._submit_assignment(self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        # Machine Task was created
        self.assertEqual(Task.objects.filter(project=project).count(),
                         2)
        machine_step = self.workflow_steps['test_workflow_2']['simple_machine']
        machine_task_assignment = (
            TaskAssignment.objects
            .filter(task__step=machine_step,
                    task__project=project)[0])

        self.assertEqual(machine_task_assignment.status,
                         TaskAssignment.Status.SUBMITTED)

        self.assertEqual(machine_task_assignment.in_progress_task_data,
                         {'json': 'simple'})

        self.assertEqual(machine_task_assignment.task.status,
                         Task.Status.COMPLETE)

    def test_index(self):
        response = self.clients[0].get('/orchestra/app/')
        self.assertEqual(response.status_code, 200)

    def test_status(self):
        response = self.clients[0].get('/orchestra/status/')
        self.assertEqual(response.status_code, 200)

    def test_dashboard_tasks(self):
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

    def test_dashboard_tasks_tags(self):
        url = '/orchestra/api/interface/dashboard_tasks/'
        response = self.clients[0].get(url)
        returned = load_encoded_json(response.content)
        self.assertEqual(len(returned['tasks'][0]['tags']), 0)

        # set tags for this task
        bad_formatted_tags = {'tags': [{'foo': 'bar'}]}
        valid_tags = {'tags': [{'label': 'foo', 'status': 'default'}]}
        task = TaskAssignment.objects.filter(
            worker=self.workers[0])[0].task
        with self.assertRaises(AttributeError):
            task.tags = bad_formatted_tags
            task.tags.save()

        task.tags = valid_tags
        task.save()
        response2 = self.clients[0].get(url)
        returned2 = load_encoded_json(response2.content)
        tags = returned2['tasks'][0]['tags']
        self.assertEqual(len(tags), 1)
        self.assertEqual(tags[0]['label'], 'foo')
        self.assertEqual(tags[0]['status'], 'default')

    def test_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        # task assignment for invalid id should give bad request
        self._verify_bad_task_assignment_information(
            self.clients[0], {'task_id': -1},
            'Task matching query does not exist.')

        # task assignment for user3 not assigned to a task
        self._verify_bad_task_assignment_information(
            self.clients[2], {'task_id': task.id},
            'Worker is not associated with task')

        # task assignment is assigned to user 0
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Processing', False,
            False, {}, self.workers[0])

    def _check_client_dashboard_state(self, client, non_empty_status):
        response = client.get('/orchestra/api/interface/dashboard_tasks/')
        returned = load_encoded_json(response.content)
        non_empty_tasks = [task for task in returned['tasks']
                           if task['state'] == non_empty_status]
        empty_tasks = [task for task in returned['tasks']
                       if task['state'] != non_empty_status]
        self.assertGreater(len(non_empty_tasks), 0)
        self.assertEqual(len(empty_tasks), 0)

    def test_reviewer_task_assignment(self):
        task = self.tasks['review_task']
        assign_task(
            self.workers[1].id, task.id)
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, {'test_key': 'test_value'}, self.workers[1])

    def test_save_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        # incorrect task id
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': -1,
                        'task_data': 'test'}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'No task for given id')

        # user does not have a permission to save
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': 'test'}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not associated with task')

        # save new info
        new_data = {'new_test_key': 'new_test_value'}
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': new_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Processing', False,
            False, new_data, self.workers[0])

    def test_save_reviewer_task_assignment(self):
        new_data = {'new_test_key': 'new_test_value'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)

        # entry level worker can't update the data
        response = self.clients[0].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': new_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to save')

        reviewer_data = {'reviewer_key': 'reviewer_value'}

        # reviewer can update the data
        response = self.clients[1].post(
            '/orchestra/api/interface/save_task_assignment/',
            json.dumps({'task_id': task.id,
                        'task_data': reviewer_data}),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, reviewer_data, self.workers[1])

    def test_submit_entry_level_task_assignment(self):
        task = self.tasks['awaiting_processing']
        assign_task(self.workers[0].id, task.id)

        verify_iterations(task.id)

        # user is not assigned to a task
        response = self._submit_assignment(self.clients[1], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task assignment with worker is in broken state.')

        # task does not exist
        response = self._submit_assignment(self.clients[1], -1)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'No task for given id')

        # user 0 can only submit a task not reject
        response = self._submit_assignment(
            self.clients[0], task.id, command='reject')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task not in rejectable state.')

        # user 0 can't call illegal commands
        response = self._submit_assignment(
            self.clients[0], task.id, command='approve')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Illegal command')
        data = {'submit_key1': 'submit_val1'}

        # user 0 can't submit a task if its submission prerequisites aren't
        # complete
        step = task.step
        step.submission_depends_on.set([
            Step.objects.create(
                workflow_version=step.workflow_version,
                slug='imaginary_test_step',
                is_human=True,
            )
        ])
        step.save()
        response = self._submit_assignment(
            self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Submission prerequisites are not complete.')
        step.submission_depends_on.set([])
        step.save()

        data = {'submit_key1': 'submit_val1'}
        # user 0 submits a task
        response = self._submit_assignment(
            self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Pending Review', False,
            True, data, self.workers[0])

        # Check that iteration has correct submitted state
        verify_iterations(task.id)

        # user cannot resubmit a task
        response = self._submit_assignment(
            self.clients[0], task.id)
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to submit')

    def test_submit_reviewer_task_assignment(self):
        data = {'submit_key1': 'submit_val1'}
        task = self.tasks['review_task']
        assign_task(self.workers[1].id, task.id)

        verify_iterations(task.id)

        rejected_data = {'rejected_key': 'rejected_val'}

        # user 0 can retrieve data, but should see a read-only interface
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Reviewing', False,
            True, {'test_key': 'test_value'}, self.workers[0])

        # user 1 should be able to review the post
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, {'test_key': 'test_value'}, self.workers[1])

        # user 1 rejects a task
        response = self._submit_assignment(
            self.clients[1], task.id, data=rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # user 0 should have the task back
        self._verify_good_task_assignment_information(
            self.clients[0], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Post-review Processing', False,
            False, rejected_data, self.workers[0])

        # user 1 should no longer be able to modify the post
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Post-review Processing', True,
            True, rejected_data, self.workers[1])

        # user 0 submits an updated data
        response = self._submit_assignment(
            self.clients[0], task.id, data=data)
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if the data is saved
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Processing', 'Reviewing', True,
            False, data, self.workers[1])

        accepted_data = {'accepted_key': 'accepted_val'}
        # user 1 accepts a task
        response = self._submit_assignment(
            self.clients[1], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if the accepted_data is saved
        # and task is pending for a second review.
        self._verify_good_task_assignment_information(
            self.clients[1], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Pending Review', True,
            True, accepted_data, self.workers[1])

        # make sure a task can't be submitted twice
        response = self._submit_assignment(
            self.clients[1], task.id, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Worker is not allowed to submit')

        # user 3 is picking up a task as a reviewer
        assign_task(self.workers[3].id, task.id)

        verify_iterations(task.id)

        rejected_data = {'rejected_key': 'rejected_val'}

        # user 3 rejects a task
        response = self._submit_assignment(
            self.clients[3], task.id, data=rejected_data, command='reject')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)

        verify_iterations(task.id)

        # check if the rejected_data is saved
        self._verify_good_task_assignment_information(
            self.clients[3], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Post-review Processing', True,
            True, rejected_data, self.workers[3])

        # check client dashboards
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

        self._check_client_dashboard_state(self.clients[1], 'returned')

        self._check_client_dashboard_state(self.clients[3],
                                           'pending_processing')

        response = self._submit_assignment(
            self.clients[1], task.id)
        self.assertEqual(response.status_code, 200)

        verify_iterations(task.id)

        # check if client dashboards were updated
        self._check_client_dashboard_state(self.clients[0], 'pending_review')

        self._check_client_dashboard_state(self.clients[1], 'pending_review')

        self._check_client_dashboard_state(self.clients[3], 'in_progress')

        # check if the accepted_data is saved
        response = self._submit_assignment(
            self.clients[3], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 200)
        returned = load_encoded_json(response.content)

        verify_iterations(task.id)

        # check if task is complete
        self._verify_good_task_assignment_information(
            self.clients[3], {'task_id': task.id},
            task.project.short_description,
            'Submitted', 'Complete', True,
            True, accepted_data, self.workers[3])

        # check that reviewer cannot reaccept task
        response = self._submit_assignment(
            self.clients[3], task.id, data=accepted_data, command='accept')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         'Task already completed')

    def _verify_bad_task_assignment_information(
            self, client, post_data, error_message):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/',
            json.dumps(post_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 400)
        returned = load_encoded_json(response.content)
        self.assertEqual(returned['message'],
                         error_message)

    def _verify_good_task_assignment_information(
            self, client, post_data, project_description,
            assignment_status, task_status, is_reviewer,
            is_read_only, task_data, worker):
        response = client.post(
            '/orchestra/api/interface/task_assignment_information/',
            json.dumps(post_data),
            content_type='application/json')
        self.assertEqual(response.status_code, 200)

        task = Task.objects.get(id=post_data['task_id'])
        returned = load_encoded_json(response.content)
        expected = {
            'project': {'details': project_description,
                        'id': task.project.id,
                        'project_data': {},
                        'status': dict(
                            Project.STATUS_CHOICES)[task.project.status],
                        'scratchpad_url': None},
            'status': assignment_status,
            'task': {'data': task_data, 'status': task_status},
            'task_id': task.id,
            'assignment_id': task.assignments.get(worker=worker).id,
            'workflow': {
                'slug': 'w1', 'name': 'Workflow One',
            },
            'workflow_version': {
                'slug': 'test_workflow', 'name': 'The workflow'},
            'prerequisites': {},
            'step': {'slug': 'step1', 'name': 'The first step'},
            'is_reviewer': is_reviewer,
            'is_read_only': is_read_only,
            'is_project_admin': False,
            'worker': {
                'username': worker.user.username,
                'first_name': worker.user.first_name,
                'last_name': worker.user.last_name,
            }
        }

        self.assertEqual(returned, expected)
