Finite State Machines (FSM)

with Akka Actors

writing and unit testing 'em

"lightning talk" by Prasanna Kumar
Glassbeam

What is FSM?

"When a program is in a state S and an event E occurs then do an action A and change to another state S1"

If the above sounds too theoritical to understand ....

Imagine a traffic signal

hope you could understand !!!

Why do we need FSM?

  • Model and Execute Constraints
  • Simulations
  • Automata based programming

"FSM" from Akka Perspective

  • State
  • Data
  • Messages to the actor is analogous to Events
  • Actor abstraction itself

  sealed trait FSMSignal
  
  case class SignalColorData
  
  class SignalChangeFSMActor extends Actor 
    with FSM[FSMSignal, SignalColorData] {
    ..... 
  }

				  

Let's model FSM



  // state - 
  sealed trait FSMSignal
  case object RedSignal extends FSMSignal
  case object YellowSignal extends FSMSignal
  case object GreenSignal extends FSMSignal

  // data  
  case class SignalColorData

  // event
  case object ChangeSignal
  case object RetainSignal

				  
				  

Actor Code


class SignalChangeFSMActor extends Actor with FSM[FSMSignal, SignalColorData] {

  // initial state of FSM
  startWith(RedSignal, SignalColorData())

  when(RedSignal) {
    case Event(ChangeSignal, _) => goto(YellowSignal)
    case Event(RetainSignal, _) => stay
  }

  when(YellowSignal) {
    case Event(ChangeSignal, _) => goto(GreenSignal)
    case Event(RetainSignal, _) => stay
  }
				  
				  

Contd ...


  when(GreenSignal) {
    case Event(ChangeSignal, _) => goto(RedSignal)
    case Event(RetainSignal, _) => stay
  }

  onTransition {
    case RedSignal -> YellowSignal => 
	println("Changing from red to yellow signal - get ready to go")
    case YellowSignal -> GreenSignal =>
	println("Changing from yellow to green signal - wroooom")
    case GreenSignal -> RedSignal =>
	println("Changing from green to red signal - stop !!! :(")
  }

  initialize
}

				
				

Unit testing FSM actors with


class FSMActorTest(as: ActorSystem) extends TestKit(as)
  with ImplicitSender
  with WordSpecLike
  with Matchers
  with BeforeAndAfterAll {
  // all our test cases
}
          
          

Contd


  val fsmRef = TestFSMRef(new SignalChangeFSMActor)
  "Our signal emulating FSMActor" must {
    "be red at initial stage " in {
      assert(fsmRef.stateName == RedSignal)
      assert(fsmRef.stateData == SignalColorData())
    }
    "change to yellow after AlternateColour event occured " in {
      fsmRef ! ChangeSignal // send an event to FSM
      assert(fsmRef.stateName == YellowSignal)
      assert(fsmRef.stateData == SignalColorData())
    }
    "change to green after AlternateColour event occured" in {
      fsmRef ! ChangeSignal
      assert(fsmRef.stateName == GreenSignal)
      assert(fsmRef.stateData == SignalColorData())
    }
    "retain should not change the fsm state" in {
      fsmRef ! RetainSignal
      assert(fsmRef.stateName == GreenSignal)
      assert(fsmRef.stateData == SignalColorData())
    }
  }
  
        

Over to Demo !!

Session takeaway

  • Code :- https://github.com/prassee/FSMExperiment

Thanks :)