Akka FSM Testkit doesn't catch *starting state* correctly

63 Views Asked by At

I am using Akka FSM to simulate a moving elevator (you are going: not again! :-)) and trying to test the FSM using regular Testkit features, but there seems to be a gap either in my understanding or the published behaviour of FSM (or both).

Here's the relevant portion of the code:

class LiftCarriageWithMovingState (val movingStateSimulator: ActorRef) extends Actor
  with LoggingFSM[LiftState,LiftData]
  with ActorLogging
{
  val mxTimeToWaitStopping = 250 milliseconds
  private var pendingPassengerRequests: Vector[NextStop] = Vector.empty
  private var currentFloorID = 0 // Always start at Ground Floor

  val timeToReachNextFloor = 1000 millis  // up  or down, same time taken

  private val dontCare: StateFunction = {
    // ..
  }

  private val powerYourselfOff: StateFunction = {
    case Event(InstructedToPowerOff,_) =>
      stay
  }

  private val powerYourselfOn: StateFunction = {
    case Event(InstructedToPowerOn,_)  =>
      goto (PoweredOn)
  }

  private val beReady: StateFunction = {
    case Event(BeReady,_)          =>
      settleDownAtGroundFloor
      goto (Ready)
  }

  // .. other StateFunctions here

  startWith(PoweredOff,InitialData)

  when (PoweredOff) (powerYourselfOn orElse
                     dontCare)

  when (PoweredOn)  (powerYourselfOff orElse
                     beReady orElse
                     dontCare
  // ...

One expects that the FSM will respond with the CurrentState message, just after it is created and startWith function is called, but that doesn't happen. This test (partial code again) fails:

"A LiftCarriage" must {
    "be ready, when it settles down after being PoweredOn" in {

      val testCarriageFSM = TestFSMRef(new LiftCarriageWithMovingState(movingStateSimulator))

      expectMsgPF() {
        case CurrentState(_,PoweredOff) => true // Line 46, see the stacktrace below
      }

thus:

 A LiftCarriage
[info] - must be ready, when it settles down after being PoweredOn *** FAILED ***
[info]   java.lang.AssertionError: assertion failed: timeout (3 seconds) during expectMsg:
[info]   at scala.Predef$.assert(Predef.scala:170)
[info]   at akka.testkit.TestKitBase$class.expectMsgPF(TestKit.scala:356)
[info]   at akka.testkit.TestKit.expectMsgPF(TestKit.scala:718)
[info]   at withExplicitMovingState.LiftCarriageMovingStoppingCorrectlyTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(LiftCarriageMovingStoppingCorrectlyTest.scala:46)
[info]   at withExplicitMovingState.LiftCarriageMovingStoppingCorrectlyTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(LiftCarriageMovingStoppingCorrectlyTest.scala:42)
[info]   at withExplicitMovingState.LiftCarriageMovingStoppingCorrectlyTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(LiftCarriageMovingStoppingCorrectlyTest.scala:42)

Is there a gap in my understanding? Please educate me, if so.

I also see that exactly the same question - asked in more summarised form here - has gone unanswered. Isn't this seen to be a gap in the semantics of Akka FSM and Testkit, worth addressing? :-P

0

There are 0 best solutions below