def test__shouldMigrationForIterationMustFinishInShortAmountOfTimeWithTooManyObject(self):
        out = StringIO()
        sys.stout = out
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        state3 = StateObjectFactory(label="state3")
        state4 = StateObjectFactory(label="state4")

        workflow = WorkflowFactory(initial_state=state1, content_type=ContentType.objects.get_for_model(BasicTestModel), field_name="my_field")
        transition_meta_1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state1,
        )

        transition_meta_2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state3,
        )

        transition_meta_3 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state4,
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_1,
            priority=0
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=0
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=1
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_3,
            priority=0
        )

        BasicTestModelObjectFactory.create_batch(250)

        call_command('migrate', 'river', '0006', stdout=out)

        before = datetime.now()
        call_command('migrate', 'river', '0007', stdout=out)
        after = datetime.now()
        assert_that(after - before, less_than(timedelta(minutes=5)))
Exemple #2
0
    def test_shouldAssesFinalStateProperlyWhenThereAreMultiple(self):
        state1 = StateObjectFactory(label="state1")
        state21 = StateObjectFactory(label="state21")
        state22 = StateObjectFactory(label="state22")
        state31 = StateObjectFactory(label="state31")
        state32 = StateObjectFactory(label="state32")

        workflow = WorkflowFactory(initial_state=state1, content_type=self.content_type, field_name="my_field")
        transition_meta1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state21,
        )
        transition_meta2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state22,
        )

        transition_meta3 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state31,
        )

        transition_meta4 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state32,
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta1,
            priority=0
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta2,
            priority=0
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta3,
            priority=0
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta4,
            priority=0
        )

        assert_that(BasicTestModel.river.my_field.final_states, has_length(4))
        assert_that(list(BasicTestModel.river.my_field.final_states), has_items(state21, state22, state31, state32))
Exemple #3
0
    def test_shouldNotAllowWorkflowToBeDeletedWhenThereIsATransitionApproval(
            self):
        content_type = ContentType.objects.get_for_model(BasicTestModel)

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        TransitionApprovalMetaFactory.create(workflow=workflow,
                                             transition_meta=transition_meta,
                                             priority=0)

        BasicTestModelObjectFactory(workflow=workflow)
        TransitionApproval.objects.filter(workflow=workflow).update(
            status=APPROVED)
        approvals = TransitionApproval.objects.filter(workflow=workflow)
        assert_that(approvals, has_length(1))

        assert_that(
            calling(workflow.delete),
            raises(
                ProtectedError,
                "Cannot delete some instances of model 'Workflow' because they are referenced through a protected foreign key"
            ))
Exemple #4
0
    def test_shouldNotDeletePendingTransitionWhenDeleted(self):
        content_type = ContentType.objects.get_for_model(BasicTestModel)

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        meta1 = TransitionApprovalMetaFactory.create(
            workflow=workflow, transition_meta=transition_meta, priority=0)

        BasicTestModelObjectFactory(workflow=workflow)
        TransitionApproval.objects.filter(workflow=workflow).update(
            status=PENDING)
        assert_that(TransitionApproval.objects.filter(workflow=workflow),
                    has_length(1))

        meta1.delete()

        assert_that(TransitionApproval.objects.filter(workflow=workflow),
                    has_length(0))
Exemple #5
0
    def test_shouldReturnNoApprovalWhenUserIsUnAuthorized(self):
        unauthorized_user = UserObjectFactory()

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=self.content_type,
                                   field_name="my_field")
        authorized_permission = PermissionObjectFactory()
        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0,
            permissions=[authorized_permission])

        BasicTestModelObjectFactory(workflow=workflow)

        available_approvals = BasicTestModel.river.my_field.get_available_approvals(
            as_user=unauthorized_user)
        assert_that(available_approvals, has_length(0))
Exemple #6
0
    def test__shouldReturnApprovalsOnTimeWhenTooManyWorkflowObject(self):
        authorized_permission = PermissionObjectFactory()
        authorized_user = UserObjectFactory(
            user_permissions=[authorized_permission])

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=self.content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0,
            permissions=[authorized_permission])

        self.objects = BasicTestModelObjectFactory.create_batch(
            250, workflow=workflow)
        before = datetime.now()
        BasicTestModel.river.my_field.get_on_approval_objects(
            as_user=authorized_user)
        after = datetime.now()
        assert_that(after - before, less_than(timedelta(milliseconds=200)))
        print("Time taken %s" % str(after - before))
Exemple #7
0
    def test_shouldReturnAnApprovalWhenUserIsAuthorizedWithAUserGroup(self):
        authorized_user_group = GroupObjectFactory()
        authorized_user = UserObjectFactory(groups=[authorized_user_group])

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=self.content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        approval_meta = TransitionApprovalMetaFactory.create(
            workflow=workflow, transition_meta=transition_meta, priority=0)
        approval_meta.groups.add(authorized_user_group)

        workflow_object = BasicTestModelObjectFactory(workflow=workflow)

        available_approvals = BasicTestModel.river.my_field.get_available_approvals(
            as_user=authorized_user)
        assert_that(available_approvals, has_length(1))
        assert_that(
            list(available_approvals),
            has_item(
                all_of(
                    has_property("workflow_object", workflow_object.model),
                    has_property("workflow", workflow),
                    has_property("transition",
                                 transition_meta.transitions.first()))))
Exemple #8
0
    def test_shouldInjectTheField(self):  # pylint: disable=no-self-use
        assert_that(BasicTestModel, has_property('river', is_(instance_of(RiverObject))))
        assert_that(BasicTestModel.river, has_property('my_field', is_(instance_of(ClassWorkflowObject))))

        content_type = ContentType.objects.get_for_model(BasicTestModel)

        state1 = StateObjectFactory.create(label="state1")
        state2 = StateObjectFactory.create(label="state2")

        workflow = WorkflowFactory(content_type=content_type, field_name="my_field", initial_state=state1)

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0
        )
        test_model = BasicTestModel.objects.create(workflow=workflow)
        assert_that(test_model, has_property('river', is_(instance_of(RiverObject))))
        assert_that(test_model.river, has_property('my_field', is_(instance_of(InstanceWorkflowObject))))
        assert_that(BasicTestModel.river.my_field, has_property('initial_state', is_(instance_of(State))))
        assert_that(BasicTestModel.river.my_field, has_property('final_states', is_(instance_of(QuerySet))))

        assert_that(test_model.river.my_field, has_property('approve', has_property("__call__")))
        assert_that(test_model.river.my_field, has_property('on_initial_state', is_(instance_of(bool))))
        assert_that(test_model.river.my_field, has_property('on_final_state', is_(instance_of(bool))))
Exemple #9
0
    def test_shouldNotDeleteApprovedTransitionWhenDeleted(self):
        content_type = ContentType.objects.get_for_model(BasicTestModel)

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        meta1 = TransitionApprovalMetaFactory.create(
            workflow=workflow, transition_meta=transition_meta, priority=0)

        BasicTestModelObjectFactory(workflow=workflow)
        TransitionApproval.objects.filter(workflow=workflow).update(
            status=APPROVED)
        approvals = TransitionApproval.objects.filter(workflow=workflow)
        assert_that(approvals, has_length(1))
        assert_that(approvals, has_item(has_property("meta", meta1)))

        meta1.delete()

        approvals = TransitionApproval.objects.filter(workflow=workflow)
        assert_that(approvals, has_length(1))
        assert_that(approvals, has_item(has_property("meta", none())))
Exemple #10
0
def transition(context, source_state_label, destination_state_label, workflow_identifier):
    from river.models import State
    from django.contrib.contenttypes.models import ContentType
    from river.models.factories import TransitionMetaFactory
    from river.tests.models import BasicTestModel
    from river.models.factories import WorkflowFactory

    source_state, _ = State.objects.get_or_create(label=source_state_label)
    workflow = getattr(context, "workflows", {}).get(workflow_identifier, None)
    if not workflow:
        content_type = ContentType.objects.get_for_model(BasicTestModel)
        workflow = WorkflowFactory(initial_state=source_state, content_type=content_type, field_name="my_field")
        if "workflows" not in context:
            context.workflows = {}
        context.workflows[workflow_identifier] = workflow

    destination_state, _ = State.objects.get_or_create(label=destination_state_label)
    transition = TransitionMetaFactory.create(
        workflow=workflow,
        source_state=source_state,
        destination_state=destination_state,
    )
    identifier = source_state_label + destination_state_label
    transitions = getattr(context, "transitions", {})
    transitions[identifier] = transition
    context.transitions = transitions
Exemple #11
0
    def test__shouldMigrateTransitionApprovalStatusToStringInDB(self):
        out = StringIO()
        sys.stout = out
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        workflow = WorkflowFactory(
            initial_state=state1,
            content_type=ContentType.objects.get_for_model(BasicTestModel),
            field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        TransitionApprovalMetaFactory.create(workflow=workflow,
                                             transition_meta=transition_meta,
                                             priority=0)
        workflow_object = BasicTestModelObjectFactory()

        with connection.cursor() as cur:
            result = cur.execute(
                "select status from river_transitionapproval where object_id=%s;"
                % workflow_object.model.pk).fetchall()
            assert_that(result[0][0], equal_to("pending"))

        call_command('migrate', 'river', '0004', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute(
                "PRAGMA table_info('river_transitionapproval');").fetchall()
            status_col_type = list(
                filter(lambda column: column[1] == 'status', schema))[0][2]
            assert_that(status_col_type, equal_to("integer"))

            result = cur.execute(
                "select status from river_transitionapproval where object_id=%s;"
                % workflow_object.model.pk).fetchall()
            assert_that(result[0][0], equal_to(0))

        call_command('migrate', 'river', '0005', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute(
                "PRAGMA table_info('river_transitionapproval');").fetchall()
            status_col_type = list(
                filter(lambda column: column[1] == 'status', schema))[0][2]
            assert_that(status_col_type, equal_to("varchar(100)"))

            result = cur.execute(
                "select status from river_transitionapproval where object_id=%s;"
                % workflow_object.model.pk).fetchall()
            assert_that(result[0][0], equal_to("pending"))
Exemple #12
0
def transition(context, source_state_label, destination_state_label, workflow_identifier):
    from river.models import State
    from river.models.factories import TransitionMetaFactory

    workflow = getattr(context, "workflows", {})[workflow_identifier]
    source_state = State.objects.get(label=source_state_label)
    destination_state = State.objects.get(label=destination_state_label)
    transition = TransitionMetaFactory.create(
        workflow=workflow,
        source_state=source_state,
        destination_state=destination_state,
    )
    identifier = source_state_label + destination_state_label
    transitions = getattr(context, "transitions", {})
    transitions[identifier] = transition
    context.transitions = transitions
Exemple #13
0
    def test_shouldAssesInitialStateProperly(self):
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1, content_type=self.content_type, field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0
        )

        assert_that(BasicTestModel.river.my_field.initial_state, equal_to(state1))
Exemple #14
0
    def test_shouldAssesFinalStateProperlyWhenThereIsOnlyOne(self):
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(initial_state=state1, content_type=self.content_type, field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )
        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0
        )
        assert_that(BasicTestModel.river.my_field.final_states, has_length(1))
        assert_that(list(BasicTestModel.river.my_field.final_states), has_item(state2))
Exemple #15
0
    def build(self):
        workflow = None
        states = {}
        transition_metas = []
        transitions_approval_metas = []
        workflow_objects = []
        for additional_raw_state in self.additional_raw_states:
            state, _ = State.objects.get_or_create(label=additional_raw_state.label)
            states[state.label] = state

        for raw_transition in self.raw_transitions:
            source_state, _ = State.objects.get_or_create(label=raw_transition.source_state.label)
            if not workflow:
                workflow = Workflow.objects.create(field_name=self.field_name, content_type=self.content_type, initial_state=source_state)
            destination_state, _ = State.objects.get_or_create(label=raw_transition.destination_state.label)

            states[source_state.label] = source_state
            states[destination_state.label] = destination_state

            transition_meta = TransitionMetaFactory.create(
                workflow=workflow,
                source_state=source_state,
                destination_state=destination_state,
            )
            transition_metas.append(transition_meta)

            if raw_transition.authorization_policies:
                for authorization_policy in raw_transition.authorization_policies:
                    transition_approval_meta = TransitionApprovalMetaFactory.create(
                        workflow=workflow,
                        transition_meta=transition_meta,
                        priority=authorization_policy.priority,
                        permissions=authorization_policy.permissions,
                    )
                    transition_approval_meta.groups.set(authorization_policy.groups)
                    transitions_approval_metas.append(transition_approval_meta)

        for i in range(self.objects_count):
            workflow_objects.append(self.object_factory())

        return Flow(workflow, states, transition_metas, transitions_approval_metas, workflow_objects)
Exemple #16
0
    def test_shouldInvokeCallbackThatIsRegisteredWithoutInstanceWhenAnApprovingHappens(
            self):
        authorized_permission = PermissionObjectFactory()
        authorized_user = UserObjectFactory(
            user_permissions=[authorized_permission])

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        content_type = ContentType.objects.get_for_model(BasicTestModel)
        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=content_type,
                                   field_name="my_field")

        transition_meta = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        meta1 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=0,
            permissions=[authorized_permission])

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta,
            priority=1,
            permissions=[authorized_permission])

        workflow_object = BasicTestModelObjectFactory(workflow=workflow)

        self.hook_pre_approve(workflow, meta1)

        assert_that(self.get_output(), none())

        assert_that(workflow_object.model.my_field, equal_to(state1))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(state1))

        output = self.get_output()
        assert_that(output, has_length(1))
        assert_that(output[0], has_key("hook"))
        assert_that(output[0]["hook"], has_entry("type", "on-approved"))
        assert_that(output[0]["hook"], has_entry("when", BEFORE))
        assert_that(
            output[0]["hook"],
            has_entry(
                "payload",
                all_of(
                    has_entry(equal_to("workflow_object"),
                              equal_to(workflow_object.model)),
                    has_entry(
                        equal_to("transition_approval"),
                        equal_to(
                            meta1.transition_approvals.filter(
                                priority=0).first())))))

        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(state2))

        output = self.get_output()
        assert_that(output, has_length(1))
        assert_that(output[0], has_key("hook"))
        assert_that(output[0]["hook"], has_entry("type", "on-approved"))
        assert_that(output[0]["hook"], has_entry("when", BEFORE))
        assert_that(
            output[0]["hook"],
            has_entry(
                "payload",
                all_of(
                    has_entry(equal_to("workflow_object"),
                              equal_to(workflow_object.model)),
                    has_entry(
                        equal_to("transition_approval"),
                        equal_to(
                            meta1.transition_approvals.filter(
                                priority=0).first())))))
Exemple #17
0
    def test_shouldInvokeCallbackForTheOnlyGivenApproval(self):
        authorized_permission = PermissionObjectFactory()
        authorized_user = UserObjectFactory(
            user_permissions=[authorized_permission])

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        state3 = StateObjectFactory(label="state3")

        content_type = ContentType.objects.get_for_model(BasicTestModel)
        workflow = WorkflowFactory(initial_state=state1,
                                   content_type=content_type,
                                   field_name="my_field")

        transition_meta_1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        transition_meta_2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state3,
        )

        transition_meta_3 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state3,
            destination_state=state1,
        )

        meta1 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_1,
            priority=0,
            permissions=[authorized_permission])

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=0,
            permissions=[authorized_permission])

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_3,
            priority=0,
            permissions=[authorized_permission])

        workflow_object = BasicTestModelObjectFactory(workflow=workflow)
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        workflow_object.model.river.my_field.approve(as_user=authorized_user)

        assert_that(TransitionApproval.objects.filter(meta=meta1),
                    has_length(2))
        first_approval = TransitionApproval.objects.filter(
            meta=meta1, transition__iteration=0).first()
        assert_that(first_approval, is_not(none()))

        self.hook_pre_approve(workflow,
                              meta1,
                              transition_approval=first_approval)

        output = self.get_output()
        assert_that(output, none())

        workflow_object.model.river.my_field.approve(as_user=authorized_user)

        output = self.get_output()
        assert_that(output, none())
Exemple #18
0
    def test__shouldMigrateObjectIdInHooksByCastingItToString(self):
        out = StringIO()
        sys.stout = out

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")

        workflow = WorkflowFactory(
            initial_state=state1,
            content_type=ContentType.objects.get_for_model(BasicTestModel),
            field_name="my_field")
        transition_1 = TransitionMetaFactory.create(workflow=workflow,
                                                    source_state=state1,
                                                    destination_state=state2)

        transition_approval_meta_1 = TransitionApprovalMetaFactory.create(
            workflow=workflow, transition_meta=transition_1, priority=0)

        workflow_object = BasicTestModelObjectFactory()

        callback_method = """
        from river.tests.hooking.base_hooking_test import callback_output
        def handle(context):
            print(context)
            key = '%s'
            callback_output[key] = callback_output.get(key,[]) + [context]
        """

        callback_function = Function.objects.create(name=uuid4(),
                                                    body=callback_method %
                                                    str(uuid4()))

        OnApprovedHook.objects.create(
            workflow=workflow,
            callback_function=callback_function,
            transition_approval_meta=transition_approval_meta_1,
            hook_type=BEFORE,
            workflow_object=workflow_object.model)

        OnCompleteHook.objects.create(workflow=workflow,
                                      callback_function=callback_function,
                                      hook_type=BEFORE,
                                      workflow_object=workflow_object.model)

        OnTransitHook.objects.create(workflow=workflow,
                                     callback_function=callback_function,
                                     transition_meta=transition_1,
                                     hook_type=BEFORE,
                                     workflow_object=workflow_object.model)

        call_command('migrate', 'river', '0013', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute(
                "PRAGMA table_info('river_onapprovedhook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("integer unsigned"))

            schema = cur.execute(
                "PRAGMA table_info('river_ontransithook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("integer unsigned"))

            schema = cur.execute(
                "PRAGMA table_info('river_oncompletehook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("integer unsigned"))

            result = cur.execute(
                "select object_id from river_onapprovedhook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(workflow_object.model.pk))

            result = cur.execute(
                "select object_id from river_ontransithook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(workflow_object.model.pk))

            result = cur.execute(
                "select object_id from river_oncompletehook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(workflow_object.model.pk))

        call_command('migrate', 'river', '0014', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute(
                "PRAGMA table_info('river_onapprovedhook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("varchar(200)"))

            schema = cur.execute(
                "PRAGMA table_info('river_ontransithook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("varchar(200)"))

            schema = cur.execute(
                "PRAGMA table_info('river_oncompletehook');").fetchall()
            column_type = next(
                iter([
                    column[2] for column in schema if column[1] == 'object_id'
                ]), None)
            assert_that(column_type, equal_to("varchar(200)"))

            result = cur.execute(
                "select object_id from river_onapprovedhook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(str(workflow_object.model.pk)))

            result = cur.execute(
                "select object_id from river_ontransithook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(str(workflow_object.model.pk)))

            result = cur.execute(
                "select object_id from river_oncompletehook where object_id='%s';"
                % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(1))
            assert_that(result[0][0], equal_to(str(workflow_object.model.pk)))
    def test__shouldAssessIterationsForExistingApprovals(self):
        out = StringIO()
        sys.stout = out
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        state3 = StateObjectFactory(label="state3")
        state4 = StateObjectFactory(label="state4")

        workflow = WorkflowFactory(initial_state=state1, content_type=ContentType.objects.get_for_model(BasicTestModel), field_name="my_field")
        transition_meta_1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        transition_meta_2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state3,
        )

        transition_meta_3 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state4,
        )

        meta_1 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_1,
            priority=0
        )
        meta_2 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=0
        )

        meta_3 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=1
        )

        meta_4 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_3,
            priority=0
        )

        workflow_object = BasicTestModelObjectFactory()

        with connection.cursor() as cur:
            result = cur.execute("""
                select 
                    river_transitionapproval.meta_id, 
                    iteration 
                from river_transitionapproval 
                inner join river_transition rt on river_transitionapproval.transition_id = rt.id  
                where river_transitionapproval.object_id=%s;
             """ % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.pk, 0))))
            assert_that(result, has_item(equal_to((meta_2.pk, 1))))
            assert_that(result, has_item(equal_to((meta_3.pk, 1))))
            assert_that(result, has_item(equal_to((meta_4.pk, 1))))

        call_command('migrate', 'river', '0006', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute("PRAGMA table_info('river_transitionapproval');").fetchall()
            columns = six.moves.map(lambda column: column[1], schema)
            assert_that(columns, is_not(has_item("iteration")))

        call_command('migrate', 'river', '0007', stdout=out)

        with connection.cursor() as cur:
            result = cur.execute("select meta_id, iteration from river_transitionapproval where object_id=%s;" % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.pk, 0))))
            assert_that(result, has_item(equal_to((meta_2.pk, 1))))
            assert_that(result, has_item(equal_to((meta_3.pk, 1))))
            assert_that(result, has_item(equal_to((meta_4.pk, 1))))
    def test__shouldAssessIterationsForExistingApprovalsWhenThereIsCycle(self):
        out = StringIO()
        sys.stout = out

        authorized_permission1 = PermissionObjectFactory()
        authorized_permission2 = PermissionObjectFactory()
        authorized_user = UserObjectFactory(user_permissions=[authorized_permission1, authorized_permission2])

        cycle_state_1 = StateObjectFactory(label="cycle_state_1")
        cycle_state_2 = StateObjectFactory(label="cycle_state_2")
        cycle_state_3 = StateObjectFactory(label="cycle_state_3")
        off_the_cycle_state = StateObjectFactory(label="off_the_cycle_state")

        workflow = WorkflowFactory(initial_state=cycle_state_1, content_type=ContentType.objects.get_for_model(BasicTestModel), field_name="my_field")

        transition_meta_1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=cycle_state_1,
            destination_state=cycle_state_2,
        )

        transition_meta_2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=cycle_state_2,
            destination_state=cycle_state_3,
        )

        transition_meta_3 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=cycle_state_3,
            destination_state=cycle_state_1,
        )

        transition_meta_4 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=cycle_state_3,
            destination_state=off_the_cycle_state,
        )

        meta_1 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_1,
            priority=0,
            permissions=[authorized_permission1]
        )

        meta_21 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=0,
            permissions=[authorized_permission1]
        )

        meta_22 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=1,
            permissions=[authorized_permission2]
        )

        meta_3 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_3,
            priority=0,
            permissions=[authorized_permission1]
        )

        final_meta = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_4,
            priority=0,
            permissions=[authorized_permission1]
        )

        workflow_object = BasicTestModelObjectFactory()

        assert_that(workflow_object.model.my_field, equal_to(cycle_state_1))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(cycle_state_2))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(cycle_state_2))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(cycle_state_3))

        approvals = TransitionApproval.objects.filter(workflow=workflow, workflow_object=workflow_object.model)
        assert_that(approvals, has_length(5))

        workflow_object.model.river.my_field.approve(as_user=authorized_user, next_state=cycle_state_1)
        assert_that(workflow_object.model.my_field, equal_to(cycle_state_1))

        with connection.cursor() as cur:
            result = cur.execute("""
                            select 
                                river_transitionapproval.meta_id, 
                                iteration 
                            from river_transitionapproval 
                            inner join river_transition rt on river_transitionapproval.transition_id = rt.id  
                            where river_transitionapproval.object_id=%s;
                         """ % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(10))
            assert_that(result, has_item(equal_to((meta_1.pk, 0))))
            assert_that(result, has_item(equal_to((meta_21.pk, 1))))
            assert_that(result, has_item(equal_to((meta_22.pk, 1))))
            assert_that(result, has_item(equal_to((meta_3.pk, 2))))
            assert_that(result, has_item(equal_to((final_meta.pk, 2))))
            assert_that(result, has_item(equal_to((meta_1.pk, 3))))
            assert_that(result, has_item(equal_to((meta_21.pk, 4))))
            assert_that(result, has_item(equal_to((meta_22.pk, 4))))
            assert_that(result, has_item(equal_to((meta_3.pk, 5))))
            assert_that(result, has_item(equal_to((final_meta.pk, 5))))

        call_command('migrate', 'river', '0006', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute("PRAGMA table_info('river_transitionapproval');").fetchall()
            columns = six.moves.map(lambda column: column[1], schema)
            assert_that(columns, is_not(has_item("iteration")))

        call_command('migrate', 'river', '0007', stdout=out)

        with connection.cursor() as cur:
            result = cur.execute("select meta_id, iteration from river_transitionapproval where object_id=%s;" % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(10))
            assert_that(result, has_item(equal_to((meta_1.pk, 0))))
            assert_that(result, has_item(equal_to((meta_21.pk, 1))))
            assert_that(result, has_item(equal_to((meta_22.pk, 1))))
            assert_that(result, has_item(equal_to((meta_3.pk, 2))))
            assert_that(result, has_item(equal_to((final_meta.pk, 2))))
            assert_that(result, has_item(equal_to((meta_1.pk, 3))))
            assert_that(result, has_item(equal_to((meta_21.pk, 4))))
            assert_that(result, has_item(equal_to((meta_22.pk, 4))))
            assert_that(result, has_item(equal_to((meta_3.pk, 5))))
            assert_that(result, has_item(equal_to((final_meta.pk, 5))))
    def test_shouldInvokeCallbackThatIsRegisteredWithoutInstanceWhenTransitionHappens(self):
        authorized_permission = PermissionObjectFactory()
        authorized_user = UserObjectFactory(user_permissions=[authorized_permission])

        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        state3 = StateObjectFactory(label="state3")

        content_type = ContentType.objects.get_for_model(BasicTestModel)
        workflow = WorkflowFactory(initial_state=state1, content_type=content_type, field_name="my_field")

        transition_meta_1 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state1,
            destination_state=state2,
        )

        transition_meta_2 = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=state2,
            destination_state=state3,
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_1,
            priority=0,
            permissions=[authorized_permission]
        )

        TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_meta_2,
            priority=0,
            permissions=[authorized_permission]
        )

        workflow_object = BasicTestModelObjectFactory()

        self.hook_post_transition(workflow, transition_meta_2)

        assert_that(self.get_output(), none())

        assert_that(workflow_object.model.my_field, equal_to(state1))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(state2))

        assert_that(self.get_output(), none())

        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(state3))

        last_approval = TransitionApproval.objects.get(object_id=workflow_object.model.pk, transition__source_state=state2, transition__destination_state=state3)
        output = self.get_output()
        assert_that(output, has_length(1))
        assert_that(output[0], has_key("hook"))
        assert_that(output[0]["hook"], has_entry("type", "on-transit"))
        assert_that(output[0]["hook"], has_entry("when", AFTER))
        assert_that(output[0]["hook"], has_entry(
            "payload",
            all_of(
                has_entry(equal_to("workflow_object"), equal_to(workflow_object.model)),
                has_entry(equal_to("transition_approval"), equal_to(last_approval))

            )
        ))
    def test__shouldAssessIterationsForExistingApprovalsWhenThereIsMoreAdvanceCycle(self):
        out = StringIO()
        sys.stout = out

        authorized_permission1 = PermissionObjectFactory()
        authorized_permission2 = PermissionObjectFactory()
        authorized_user = UserObjectFactory(user_permissions=[authorized_permission1, authorized_permission2])

        opn = StateObjectFactory(label="open")
        in_progress = StateObjectFactory(label="in_progress")
        resolved = StateObjectFactory(label="resolved")
        re_opened = StateObjectFactory(label="re_opened")
        closed = StateObjectFactory(label="closed")
        final = StateObjectFactory(label="final")

        workflow = WorkflowFactory(initial_state=opn, content_type=ContentType.objects.get_for_model(BasicTestModel), field_name="my_field")

        open_to_in_progress_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=opn,
            destination_state=in_progress,
        )

        in_progress_to_resolved_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=in_progress,
            destination_state=resolved
        )

        resolved_to_re_opened_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=resolved,
            destination_state=re_opened
        )

        re_opened_to_in_progress_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=re_opened,
            destination_state=in_progress
        )

        resolved_to_closed_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=resolved,
            destination_state=closed
        )

        closed_to_final_transition = TransitionMetaFactory.create(
            workflow=workflow,
            source_state=closed,
            destination_state=final
        )

        open_to_in_progress = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=open_to_in_progress_transition,
            priority=0,
            permissions=[authorized_permission1]
        )

        in_progress_to_resolved = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=in_progress_to_resolved_transition,
            priority=0,
            permissions=[authorized_permission1]
        )

        resolved_to_re_opened = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=resolved_to_re_opened_transition,
            priority=0,
            permissions=[authorized_permission2]
        )

        re_opened_to_in_progress = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=re_opened_to_in_progress_transition,
            priority=0,
            permissions=[authorized_permission1]
        )

        resolved_to_closed = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=resolved_to_closed_transition,
            priority=0,
            permissions=[authorized_permission1]
        )

        closed_to_final = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=closed_to_final_transition,
            priority=0,
            permissions=[authorized_permission1]
        )

        workflow_object = BasicTestModelObjectFactory()

        assert_that(workflow_object.model.my_field, equal_to(opn))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(in_progress))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(resolved))
        workflow_object.model.river.my_field.approve(as_user=authorized_user, next_state=re_opened)
        assert_that(workflow_object.model.my_field, equal_to(re_opened))
        workflow_object.model.river.my_field.approve(as_user=authorized_user)
        assert_that(workflow_object.model.my_field, equal_to(in_progress))

        with connection.cursor() as cur:
            result = cur.execute("""
                            select 
                                river_transitionapproval.meta_id, 
                                iteration 
                            from river_transitionapproval 
                            inner join river_transition rt on river_transitionapproval.transition_id = rt.id  
                            where river_transitionapproval.object_id=%s;
                         """ % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(11))
            assert_that(result, has_item(equal_to((open_to_in_progress.pk, 0))))
            assert_that(result, has_item(equal_to((in_progress_to_resolved.pk, 1))))
            assert_that(result, has_item(equal_to((resolved_to_closed.pk, 2))))
            assert_that(result, has_item(equal_to((resolved_to_re_opened.pk, 2))))
            assert_that(result, has_item(equal_to((re_opened_to_in_progress.pk, 3))))
            assert_that(result, has_item(equal_to((closed_to_final.pk, 3))))
            assert_that(result, has_item(equal_to((in_progress_to_resolved.pk, 4))))
            assert_that(result, has_item(equal_to((resolved_to_closed.pk, 5))))
            assert_that(result, has_item(equal_to((resolved_to_re_opened.pk, 5))))
            assert_that(result, has_item(equal_to((re_opened_to_in_progress.pk, 6))))
            assert_that(result, has_item(equal_to((closed_to_final.pk, 6))))

        call_command('migrate', 'river', '0006', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute("PRAGMA table_info('river_transitionapproval');").fetchall()
            columns = six.moves.map(lambda column: column[1], schema)
            assert_that(columns, is_not(has_item("iteration")))

        call_command('migrate', 'river', '0007', stdout=out)

        with connection.cursor() as cur:
            result = cur.execute("select meta_id, iteration from river_transitionapproval where object_id=%s;" % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(11))
            assert_that(result, has_item(equal_to((open_to_in_progress.pk, 0))))
            assert_that(result, has_item(equal_to((in_progress_to_resolved.pk, 1))))
            assert_that(result, has_item(equal_to((resolved_to_closed.pk, 2))))
            assert_that(result, has_item(equal_to((resolved_to_re_opened.pk, 2))))
            assert_that(result, has_item(equal_to((re_opened_to_in_progress.pk, 3))))
            assert_that(result, has_item(equal_to((closed_to_final.pk, 3))))
            assert_that(result, has_item(equal_to((in_progress_to_resolved.pk, 4))))
            assert_that(result, has_item(equal_to((resolved_to_closed.pk, 5))))
            assert_that(result, has_item(equal_to((resolved_to_re_opened.pk, 5))))
            assert_that(result, has_item(equal_to((re_opened_to_in_progress.pk, 6))))
            assert_that(result, has_item(equal_to((closed_to_final.pk, 6))))
    def test__shouldCreateTransitionsAndTransitionMetasOutOfApprovalMetaAndApprovals(self):
        out = StringIO()
        sys.stout = out
        state1 = StateObjectFactory(label="state1")
        state2 = StateObjectFactory(label="state2")
        state3 = StateObjectFactory(label="state3")
        state4 = StateObjectFactory(label="state4")

        workflow = WorkflowFactory(initial_state=state1, content_type=ContentType.objects.get_for_model(BasicTestModel), field_name="my_field")
        transition_1 = TransitionMetaFactory.create(workflow=workflow, source_state=state1, destination_state=state2)
        transition_2 = TransitionMetaFactory.create(workflow=workflow, source_state=state2, destination_state=state3)
        transition_3 = TransitionMetaFactory.create(workflow=workflow, source_state=state2, destination_state=state4)

        meta_1 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_1,
            priority=0
        )
        meta_2 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_2,
            priority=0
        )

        meta_3 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_2,
            priority=1
        )

        meta_4 = TransitionApprovalMetaFactory.create(
            workflow=workflow,
            transition_meta=transition_3,
            priority=0
        )

        workflow_object = BasicTestModelObjectFactory()

        with connection.cursor() as cur:
            result = cur.execute("select id, transition_meta_id from river_transitionapprovalmeta;").fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.pk, transition_1.pk))))
            assert_that(result, has_item(equal_to((meta_2.pk, transition_2.pk))))
            assert_that(result, has_item(equal_to((meta_3.pk, transition_2.pk))))
            assert_that(result, has_item(equal_to((meta_4.pk, transition_3.pk))))

            result = cur.execute("select id, transition_id from river_transitionapproval where object_id='%s';" % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.transition_approvals.first().pk, transition_1.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_2.transition_approvals.first().pk, transition_2.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_3.transition_approvals.first().pk, transition_2.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_4.transition_approvals.first().pk, transition_3.transitions.first().pk))))

        call_command('migrate', 'river', '0009', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute("PRAGMA table_info('river_transitionapprovalmeta');").fetchall()
            columns = [column[1] for column in schema]
            assert_that(columns, is_not(has_item("transition_meta_id")))
            assert_that(columns, has_item("source_state_id"))
            assert_that(columns, has_item("destination_state_id"))

            schema = cur.execute("PRAGMA table_info('river_transitionapproval');").fetchall()
            columns = [column[1] for column in schema]
            assert_that(columns, is_not(has_item("transition_id")))
            assert_that(columns, has_item("source_state_id"))
            assert_that(columns, has_item("destination_state_id"))

        call_command('migrate', 'river', '0010', stdout=out)

        with connection.cursor() as cur:
            schema = cur.execute("PRAGMA table_info('river_transitionapprovalmeta');").fetchall()
            columns = six.moves.map(lambda column: column[1], schema)
            assert_that(columns, has_item("transition_meta_id"))
            assert_that(columns, is_not(has_item("source_state_id")))
            assert_that(columns, is_not(has_item("destination_state_id")))

            schema = cur.execute("PRAGMA table_info('river_transitionapproval');").fetchall()
            columns = [column[1] for column in schema]
            assert_that(columns, has_item("transition_id"))
            assert_that(columns, is_not(has_item("source_state_id")))
            assert_that(columns, is_not(has_item("destination_state_id")))

        with connection.cursor() as cur:
            result = cur.execute("select id, transition_meta_id from river_transitionapprovalmeta;").fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.pk, transition_1.pk))))
            assert_that(result, has_item(equal_to((meta_2.pk, transition_2.pk))))
            assert_that(result, has_item(equal_to((meta_3.pk, transition_2.pk))))
            assert_that(result, has_item(equal_to((meta_4.pk, transition_3.pk))))

            result = cur.execute("select id, transition_id from river_transitionapproval where object_id='%s';" % workflow_object.model.pk).fetchall()
            assert_that(result, has_length(4))
            assert_that(result, has_item(equal_to((meta_1.transition_approvals.first().pk, transition_1.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_2.transition_approvals.first().pk, transition_2.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_3.transition_approvals.first().pk, transition_2.transitions.first().pk))))
            assert_that(result, has_item(equal_to((meta_4.transition_approvals.first().pk, transition_3.transitions.first().pk))))