django-statemachine / statemachine / tests.py

from django.db import models
from django.test import TestCase

from statemachine.models import StateMachineWithHistory
from statemachine.fields import FSM_StateField
from statemachine import fsm


class TestMachine(fsm.FSM):
    start = fsm.State(exits_to=['step1a', 'step1b', 'step1c'])
    step1a = fsm.State(exits_to=['step2', ])
    step1b = fsm.State(exits_to=['step2', ])
    step1c = fsm.State(exits_to=['step2', ])
    step2 = fsm.State(exits_to=['end', 'step3', ])
    step3 = fsm.State(exits_to=['end', ])
    end = fsm.State()


class TestStateMachine(StateMachineWithHistory):
    status = FSM_StateField(TestMachine)
    field1 = models.IntegerField()
    field2 = models.CharField(max_length=25)


class StateMachineTests(TestCase):
    def test_verify(self):
        """ Should raise a FSM_VerificationError """
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.status.states["random"] = (fsm.State("random", [
            "doesntexist", "alsodoesnexist"]))
        with self.assertRaises(fsm.FSM_VerificationError):
            testmachine.status.verify()

    def test_save_fail(self):
        """Should raise a StateMachineNotAllowed, messing with the
        state outside of the machine.

        """
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.save(None)
        with self.assertRaises(fsm.FSM_NotAllowed):
            testmachine.status.state = "Testing"
            testmachine.save(None)

    def test_full_transition(self):
        """ End to end smoke test of the transitions """
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.save(None)
        testmachine.status.change("step1a")
        testmachine.save(None)
        testmachine.status.change("step2")
        testmachine.save(None)
        #reload to check state is saved and reinstated
        self.assertEqual(testmachine.status.state.name, "step2")
        fsm_id = testmachine.id
        self.assertEqual(testmachine.status.state.name, "step2")
        testmachine = TestStateMachine.objects.get(pk=fsm_id)
        testmachine.status.change("step3")
        testmachine.save(None)
        testmachine.status.change("end")
        testmachine.save(None)

    def test_invalid_transition(self):
        """ Testing invalid transitions """
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.save(None)
        #check we are starting at "start"
        self.assertEqual(testmachine.status.state.name, "start")

        with self.assertRaises(fsm.FSM_TransitionNotAllowed):
            testmachine.status.change("step3")

        #check we are still at "start" after a failed transition
        self.assertEqual(testmachine.status.state.name, "start")

    def test_transition_history(self):
        """ Checking that history is being saved for each transition """
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        self.assertEqual(testmachine.status.state.name, "start")
        testmachine.status.change("step1a")
        testmachine.save(None)
        testmachine.status.change("step2")
        testmachine.save(None, "Some notes!")
        testmachine.status.change("end")
        testmachine.save(None)

        #reload so we get everything from the db
        fsm_id = testmachine.id
        testmachine = TestStateMachine.objects.get(pk=fsm_id)

        self.assertEqual(testmachine.state_history.count(), 3)
        self.assertEqual(testmachine.state_history.all()[1].notes,
                         "Some notes!")

    def test_entry_action(self):
        """ Tests an action set to run on entry to a state """
        def entry_func(entered, row):
            row.field1 = 500
        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.save(None)
        testmachine.status.states["step3"].entry_action = entry_func
        testmachine.status.change("step1a")
        testmachine.save(None)
        testmachine.status.change("step2")
        testmachine.save(None)
        testmachine.status.change("step3", testmachine)
        testmachine.save(None)
        self.assertEqual(testmachine.field1, 500)

    def test_exit_action(self):
        """ Tests an action set to run on entry to a state """
        def exit_func(entered, row):
            row.field1 = 10
            row.field2 = "Chickens"

        testmachine = TestStateMachine(field1=100, field2="LALALALALA")
        testmachine.save(None)
        testmachine.status.states["start"].exit_action = exit_func
        testmachine.status.change("step1a", testmachine)

        self.assertEqual(testmachine.field1, 10)
        self.assertEqual(testmachine.field2, "Chickens")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.