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