Example #1
0
    def test_malformed_assignment_policy(self):
        project = self.projects['assignment_policy']
        workflow_version = project.workflow_version
        first_step = self.workflow_steps[workflow_version.slug]['step_0']

        # Create an invalid machine step with an assignment policy
        malformed_step = StepFactory(
            workflow_version=workflow_version,
            slug='machine_step',
            is_human=False,
            assignment_policy={
                'policy_function': {
                    'entry_level': {
                        'path': ('orchestra.assignment_policies.'
                                 'previously_completed_steps'),
                        'kwargs': {
                            'related_steps': ['step_0']
                        },
                    }
                }
            },
            creation_policy=get_default_creation_policy(),
        )
        malformed_step.creation_depends_on.add(first_step)

        # Create first task in project
        create_subsequent_tasks(project)
        self.assertEquals(project.tasks.count(), 1)

        # Assign initial task to worker 0 and mark as complete
        initial_task = assign_task(self.workers[4].id,
                                   project.tasks.first().id)
        initial_task.status = Task.Status.COMPLETE
        initial_task.save()

        # Cannot preassign machine task
        with self.assertRaises(AssignmentPolicyError):
            create_subsequent_tasks(project)

        # Reset project
        project.tasks.all().delete()

        # Machine should not be member of assignment policy
        first_step.assignment_policy = {
            'policy_function': {
                'entry_level': {
                    'path': ('orchestra.assignment_policies.'
                             'previously_completed_steps'),
                    'kwargs': {
                        'related_steps': ['machine_step']
                    },
                },
            }
        }
        first_step.save()
        with self.assertRaises(AssignmentPolicyError):
            create_subsequent_tasks(project)
Example #2
0
    def test_malformed_assignment_policy(self):
        project = self.projects['assignment_policy']
        workflow_version = project.workflow_version
        first_step = self.workflow_steps[workflow_version.slug]['step_0']

        # Create an invalid machine step with an assignment policy
        malformed_step = StepFactory(
            workflow_version=workflow_version,
            slug='machine_step',
            is_human=False,
            assignment_policy={
                'policy_function': {
                    'entry_level': {
                        'path': ('orchestra.assignment_policies.'
                                 'previously_completed_steps'),
                        'kwargs': {
                            'related_steps': ['step_0']
                        },
                    }
                }
            },
            creation_policy=get_default_creation_policy(),
        )
        malformed_step.creation_depends_on.add(first_step)

        # Create first task in project
        create_subsequent_tasks(project)
        self.assertEqual(project.tasks.count(), 1)

        # Assign initial task to worker 0 and mark as complete
        initial_task = assign_task(self.workers[4].id,
                                   project.tasks.first().id)
        initial_task.status = Task.Status.COMPLETE
        initial_task.save()

        # Cannot preassign machine task
        with self.assertRaises(AssignmentPolicyError):
            create_subsequent_tasks(project)

        # Reset project
        project.tasks.all().delete()

        # Machine should not be member of assignment policy
        first_step.assignment_policy = {
            'policy_function': {
                'entry_level': {
                    'path': ('orchestra.assignment_policies.'
                             'previously_completed_steps'),
                    'kwargs': {
                        'related_steps': ['machine_step']
                    },
                },
            }
        }
        first_step.save()
        with self.assertRaises(AssignmentPolicyError):
            create_subsequent_tasks(project)
Example #3
0
def _setup_workflows(test_case, workflows):
    # Create workflows
    test_case.workflows = {}
    test_case.certifications = {}
    test_case.workflow_versions = {}
    test_case.workflow_steps = {}
    for workflow_idx, workflow_details in enumerate(workflows):
        workflow = WorkflowFactory(
            slug=workflow_details['slug'],
            name=workflow_details['name'],
            code_directory='/test/dir/{}'.format(workflow_idx),
        )
        test_case.workflows[workflow_details['slug']] = workflow

        # Create certifications and dependencies
        # TODO(joshblum): workflow_step slugs may not be unique across
        # workflows! we shouldn't depend on this here
        for cert_details in workflow_details.get('certifications', []):
            certification = CertificationFactory(
                slug=cert_details['slug'],
                name=cert_details['name'],
                workflow=workflow,
            )
            test_case.certifications[cert_details['slug']] = certification

            for required_slug in cert_details['required_certifications']:
                certification.required_certifications.add(
                    test_case.certifications[required_slug])

        # Create workflow versions
        for version_details in workflow_details['versions']:
            version = WorkflowVersionFactory(
                workflow=workflow,
                slug=version_details['slug'],
                name=version_details['name'],
                description=version_details['description'],
                sanity_checks=version_details.get('sanity_checks', {})
            )
            test_case.workflow_versions[version_details['slug']] = version

            # Create workflow steps
            # TODO(joshblum): workflow_step slugs may not be unique across
            # workflows! we shouldn't depend on this here
            test_case.workflow_steps[version.slug] = {}
            workflow_steps = test_case.workflow_steps[version.slug]
            workflow_step_backrefs = []
            for step_details in version_details['steps']:
                is_human = step_details['is_human']
                step = StepFactory(
                    workflow_version=version,
                    slug=step_details['slug'],
                    name=step_details['name'],
                    is_human=is_human,
                    description=step_details.get('description', ''),

                    # TODO(dhaas): make default policies work
                    review_policy=step_details.get(
                        'review_policy',
                        get_default_review_policy(is_human)
                    ),
                    assignment_policy=step_details.get(
                        'assignment_policy',
                        get_default_assignment_policy(is_human)
                    ),
                    creation_policy=step_details.get(
                        'creation_policy',
                        get_default_creation_policy()),
                    user_interface=step_details.get('user_interface', {}),
                    execution_function=step_details.get('execution_function',
                                                        {}),
                )
                _set_step_relations(step, step_details,
                                    'todolist_templates_to_apply',
                                    TodoListTemplate)
                workflow_steps[step.slug] = step

                # Add required certifications
                for required_slug in step_details.get(
                        'required_certifications', []):
                    step.required_certifications.add(
                        test_case.certifications[required_slug])

                # Add step dependencies
                workflow_step_backrefs.extend(
                    _add_step_dependencies(
                        step_details, workflow_steps, 'creation_depends_on'))
                workflow_step_backrefs.extend(
                    _add_step_dependencies(
                        step_details, workflow_steps, 'submission_depends_on'))

            # Create backreferences we missed
            _create_backrefs(test_case.workflow_steps[version.slug],
                             workflow_step_backrefs)
Example #4
0
def load_workflow_version(version_data, workflow, force=False):
    # Create the version object
    version, version_created = WorkflowVersion.objects.update_or_create(
        slug=version_data['slug'],
        workflow=workflow,
        defaults={
            'name': version_data['name'],
            'description': version_data['description'],
            'sanity_checks': version_data.get('sanity_checks', {}),
        })

    if not version_created:
        if not force:
            # It is safe to error out after modifying the DB because
            # all of this code is wrapped in a transaction by load_workflow.
            raise WorkflowError('Version {} already exists'.format(
                version_data['slug']))

        # Check that the versions are safe to merge
        new_step_slugs = set(step['slug'] for step in version_data['steps'])
        old_step_slugs = set(
            Step.objects.filter(workflow_version=version).values_list(
                'slug', flat=True))
        if new_step_slugs != old_step_slugs:
            raise WorkflowError('Even with --force, cannot change the steps '
                                'of a workflow. Drop and recreate the '
                                'database to reset, or create a new version '
                                'for your workflow.')

    # Create or update the version steps.
    old_creation_dependencies = {}
    old_submission_dependencies = {}
    for step_data in version_data['steps']:
        is_human = step_data.get('is_human', True)
        step, step_created = Step.objects.update_or_create(
            slug=step_data['slug'],
            workflow_version=version,
            defaults={
                'name':
                step_data['name'],
                'description':
                step_data['description'],
                'is_human':
                is_human,
                'detailed_description_function':
                step_data.get('detailed_description_function', {}),
                'execution_function':
                step_data.get('execution_function', {}),
                'review_policy':
                step_data.get('review_policy',
                              get_default_review_policy(is_human)),
                'assignment_policy':
                step_data.get('assignment_policy',
                              get_default_assignment_policy(is_human)),
                'creation_policy':
                step_data.get('creation_policy',
                              get_default_creation_policy()),
                'user_interface':
                step_data.get('user_interface', {}),
            })
        if not step_created:
            old_creation_dependencies[step_data['slug']] = set(
                step.creation_depends_on.values_list('slug', flat=True))
            old_submission_dependencies[step_data['slug']] = set(
                step.submission_depends_on.values_list('slug', flat=True))

        # Don't prevent updates to these, because we want to allow
        # certifications to evolve over the lifetime of a workflow.
        _set_step_dependencies(step,
                               step_data,
                               'required_certifications',
                               Certification,
                               workflow=workflow)

    # Set up step dependencies once the steps objects are in the DB.
    for step_data in version_data['steps']:
        step_slug = step_data['slug']
        step = Step.objects.get(slug=step_slug, workflow_version=version)

        # Set step creation dependencies.
        _verify_dependencies_not_updated(
            step_data, 'creation_depends_on',
            old_creation_dependencies.get(step_slug))
        _set_step_dependencies(step,
                               step_data,
                               'creation_depends_on',
                               Step,
                               workflow_version=version)

        # Set step submission dependencies.
        _verify_dependencies_not_updated(
            step_data, 'submission_depends_on',
            old_submission_dependencies.get(step_slug))
        _set_step_dependencies(step,
                               step_data,
                               'submission_depends_on',
                               Step,
                               workflow_version=version)
Example #5
0
def load_workflow_version(version_data, workflow, force=False):
    # Create the version object
    version, version_created = WorkflowVersion.objects.update_or_create(
        slug=version_data['slug'],
        workflow=workflow,
        defaults={
            'name': version_data['name'],
            'description': version_data['description']
        }
    )

    if not version_created:
        if not force:
            # It is safe to error out after modifying the DB because
            # all of this code is wrapped in a transaction by load_workflow.
            raise WorkflowError('Version {} already exists'
                                .format(version_data['slug']))

        # Check that the versions are safe to merge
        new_step_slugs = set(step['slug'] for step in version_data['steps'])
        old_step_slugs = set(
            Step.objects
            .filter(workflow_version=version)
            .values_list('slug', flat=True)
        )
        if new_step_slugs != old_step_slugs:
            raise WorkflowError('Even with --force, cannot change the steps '
                                'of a workflow. Drop and recreate the '
                                'database to reset, or create a new version '
                                'for your workflow.')

    # Create or update the version steps.
    old_creation_dependencies = {}
    old_submission_dependencies = {}
    for step_data in version_data['steps']:
        is_human = step_data.get('is_human', True)
        step, step_created = Step.objects.update_or_create(
            slug=step_data['slug'],
            workflow_version=version,
            defaults={
                'name': step_data['name'],
                'description': step_data['description'],
                'is_human': is_human,
                'detailed_description_function': step_data.get(
                    'detailed_description_function', {}),
                'execution_function': step_data.get('execution_function', {}),
                'review_policy': step_data.get(
                    'review_policy',
                    get_default_review_policy(is_human)),
                'assignment_policy': step_data.get(
                    'assignment_policy',
                    get_default_assignment_policy(is_human)),
                'creation_policy': step_data.get(
                    'creation_policy',
                    get_default_creation_policy()),
                'user_interface': step_data.get('user_interface', {}),
            }
        )
        if not step_created:
            old_creation_dependencies[step_data['slug']] = set(
                step.creation_depends_on.values_list('slug', flat=True))
            old_submission_dependencies[step_data['slug']] = set(
                step.submission_depends_on.values_list('slug', flat=True))

        # Don't prevent updates to these, because we want to allow
        # certifications to evolve over the lifetime of a workflow.
        _set_step_dependencies(step, step_data, 'required_certifications',
                               Certification, workflow=workflow)

    # Set up step dependencies once the steps objects are in the DB.
    for step_data in version_data['steps']:
        step_slug = step_data['slug']
        step = Step.objects.get(
            slug=step_slug,
            workflow_version=version
        )

        # Set step creation dependencies.
        _verify_dependencies_not_updated(
            step_data,
            'creation_depends_on',
            old_creation_dependencies.get(step_slug)
        )
        _set_step_dependencies(step, step_data, 'creation_depends_on', Step,
                               workflow_version=version)

        # Set step submission dependencies.
        _verify_dependencies_not_updated(
            step_data,
            'submission_depends_on',
            old_submission_dependencies.get(step_slug)
        )
        _set_step_dependencies(step, step_data, 'submission_depends_on', Step,
                               workflow_version=version)
Example #6
0
def _setup_workflows(test_case, workflows):
    # Create workflows
    test_case.workflows = {}
    test_case.certifications = {}
    test_case.workflow_versions = {}
    test_case.workflow_steps = {}
    for workflow_idx, workflow_details in enumerate(workflows):
        workflow = WorkflowFactory(
            slug=workflow_details['slug'],
            name=workflow_details['name'],
            code_directory='/test/dir/{}'.format(workflow_idx),
        )
        test_case.workflows[workflow_details['slug']] = workflow

        # Create certifications and dependencies
        # TODO(joshblum): workflow_step slugs may not be unique across
        # workflows! we shouldn't depend on this here
        for cert_details in workflow_details.get('certifications', []):
            certification = CertificationFactory(
                slug=cert_details['slug'],
                name=cert_details['name'],
                workflow=workflow,
            )
            test_case.certifications[cert_details['slug']] = certification

            for required_slug in cert_details['required_certifications']:
                certification.required_certifications.add(
                    test_case.certifications[required_slug])

        # Create workflow versions
        for version_details in workflow_details['versions']:
            version = WorkflowVersionFactory(
                workflow=workflow,
                slug=version_details['slug'],
                name=version_details['name'],
                description=version_details['description'],
            )
            test_case.workflow_versions[version_details['slug']] = version

            # Create workflow steps
            # TODO(joshblum): workflow_step slugs may not be unique across
            # workflows! we shouldn't depend on this here
            test_case.workflow_steps[version.slug] = {}
            workflow_steps = test_case.workflow_steps[version.slug]
            workflow_step_backrefs = []
            for step_details in version_details['steps']:
                is_human = step_details['is_human']
                step = StepFactory(
                    workflow_version=version,
                    slug=step_details['slug'],
                    name=step_details['name'],
                    is_human=is_human,
                    description=step_details.get('description', ''),

                    # TODO(dhaas): make default policies work
                    review_policy=step_details.get(
                        'review_policy',
                        get_default_review_policy(is_human)
                    ),
                    assignment_policy=step_details.get(
                        'assignment_policy',
                        get_default_assignment_policy(is_human)
                    ),
                    creation_policy=step_details.get(
                        'creation_policy',
                        get_default_creation_policy()),
                    user_interface=step_details.get('user_interface', {}),
                    execution_function=step_details.get('execution_function',
                                                        {}),
                )
                workflow_steps[step.slug] = step

                # Add required certifications
                for required_slug in step_details.get(
                        'required_certifications', []):
                    step.required_certifications.add(
                        test_case.certifications[required_slug])

                # Add step dependencies
                workflow_step_backrefs.extend(
                    _add_step_dependencies(
                        step_details, workflow_steps, 'creation_depends_on'))
                workflow_step_backrefs.extend(
                    _add_step_dependencies(
                        step_details, workflow_steps, 'submission_depends_on'))

            # Create backreferences we missed
            _create_backrefs(test_case.workflow_steps[version.slug],
                             workflow_step_backrefs)