|
Akka/Scala example source code file (FSMTimingSpec.scala)
The FSMTimingSpec.scala Akka example source code/** * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com> */ package akka.actor import language.postfixOps import akka.testkit._ import scala.concurrent.duration._ import akka.event.Logging @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) class FSMTimingSpec extends AkkaSpec with ImplicitSender { import FSMTimingSpec._ import FSM._ val fsm = system.actorOf(Props(new StateMachine(testActor))) fsm ! SubscribeTransitionCallBack(testActor) expectMsg(1 second, CurrentState(fsm, Initial)) ignoreMsg { case Transition(_, bs: FSMTimingSpec.State, _) if bs eq Initial ⇒ true // SI-5900 workaround } "A Finite State Machine" must { "receive StateTimeout" taggedAs TimingTest in { within(1 second) { within(500 millis, 1 second) { fsm ! TestStateTimeout expectMsg(Transition(fsm, TestStateTimeout, Initial)) } expectNoMsg } } "cancel a StateTimeout" taggedAs TimingTest in { within(1 second) { fsm ! TestStateTimeout fsm ! Cancel expectMsg(Cancel) expectMsg(Transition(fsm, TestStateTimeout, Initial)) expectNoMsg } } "allow StateTimeout override" taggedAs TimingTest in { // the timeout in state TestStateTimeout is 800 ms, then it will change to Initial within(400 millis) { fsm ! TestStateTimeoutOverride expectNoMsg } within(1 second) { fsm ! Cancel expectMsg(Cancel) expectMsg(Transition(fsm, TestStateTimeout, Initial)) } } "receive single-shot timer" taggedAs TimingTest in { within(2 seconds) { within(500 millis, 1 second) { fsm ! TestSingleTimer expectMsg(Tick) expectMsg(Transition(fsm, TestSingleTimer, Initial)) } expectNoMsg } } "resubmit single-shot timer" taggedAs TimingTest in { within(2.5 seconds) { within(500 millis, 1 second) { fsm ! TestSingleTimerResubmit expectMsg(Tick) } within(1 second) { expectMsg(Tock) expectMsg(Transition(fsm, TestSingleTimerResubmit, Initial)) } expectNoMsg } } "correctly cancel a named timer" taggedAs TimingTest in { fsm ! TestCancelTimer within(500 millis) { fsm ! Tick expectMsg(Tick) } within(300 millis, 1 second) { expectMsg(Tock) } fsm ! Cancel expectMsg(1 second, Transition(fsm, TestCancelTimer, Initial)) } "not get confused between named and state timers" taggedAs TimingTest in { fsm ! TestCancelStateTimerInNamedTimerMessage fsm ! Tick expectMsg(500 millis, Tick) Thread.sleep(200) // this is ugly: need to wait for StateTimeout to be queued resume(fsm) expectMsg(500 millis, Transition(fsm, TestCancelStateTimerInNamedTimerMessage, TestCancelStateTimerInNamedTimerMessage2)) fsm ! Cancel within(500 millis) { expectMsg(Cancel) // if this is not received, that means StateTimeout was not properly discarded expectMsg(Transition(fsm, TestCancelStateTimerInNamedTimerMessage2, Initial)) } } "receive and cancel a repeated timer" taggedAs TimingTest in { fsm ! TestRepeatedTimer val seq = receiveWhile(2 seconds) { case Tick ⇒ Tick } seq should have length 5 within(500 millis) { expectMsg(Transition(fsm, TestRepeatedTimer, Initial)) } } "notify unhandled messages" taggedAs TimingTest in { filterEvents(EventFilter.warning("unhandled event Tick in state TestUnhandled", source = fsm.path.toString, occurrences = 1), EventFilter.warning("unhandled event Unhandled(test) in state TestUnhandled", source = fsm.path.toString, occurrences = 1)) { fsm ! TestUnhandled within(1 second) { fsm ! Tick fsm ! SetHandler fsm ! Tick expectMsg(Unhandled(Tick)) fsm ! Unhandled("test") fsm ! Cancel expectMsg(Transition(fsm, TestUnhandled, Initial)) } } } } } object FSMTimingSpec { def suspend(actorRef: ActorRef): Unit = actorRef match { case l: ActorRefWithCell ⇒ l.suspend() case _ ⇒ } def resume(actorRef: ActorRef): Unit = actorRef match { case l: ActorRefWithCell ⇒ l.resume(causedByFailure = null) case _ ⇒ } trait State case object Initial extends State case object TestStateTimeout extends State case object TestStateTimeoutOverride extends State case object TestSingleTimer extends State case object TestSingleTimerResubmit extends State case object TestRepeatedTimer extends State case object TestUnhandled extends State case object TestCancelTimer extends State case object TestCancelStateTimerInNamedTimerMessage extends State case object TestCancelStateTimerInNamedTimerMessage2 extends State case object Tick case object Tock case object Cancel case object SetHandler final case class Unhandled(msg: AnyRef) class StateMachine(tester: ActorRef) extends Actor with FSM[State, Int] { import FSM._ // need implicit system for dilated import context.system startWith(Initial, 0) when(Initial) { case Event(TestSingleTimer, _) ⇒ setTimer("tester", Tick, 500.millis.dilated, false) goto(TestSingleTimer) case Event(TestRepeatedTimer, _) ⇒ setTimer("tester", Tick, 100.millis.dilated, true) goto(TestRepeatedTimer) using 4 case Event(TestStateTimeoutOverride, _) ⇒ goto(TestStateTimeout) forMax (Duration.Inf) case Event(x: FSMTimingSpec.State, _) ⇒ goto(x) } when(TestStateTimeout, stateTimeout = 800.millis.dilated) { case Event(StateTimeout, _) ⇒ goto(Initial) case Event(Cancel, _) ⇒ goto(Initial) replying (Cancel) } when(TestSingleTimer) { case Event(Tick, _) ⇒ tester ! Tick goto(Initial) } onTransition { case Initial -> TestSingleTimerResubmit ⇒ setTimer("blah", Tick, 500.millis.dilated) } when(TestSingleTimerResubmit) { case Event(Tick, _) ⇒ tester ! Tick setTimer("blah", Tock, 500.millis.dilated) stay() case Event(Tock, _) ⇒ tester ! Tock goto(Initial) } when(TestCancelTimer) { case Event(Tick, _) ⇒ setTimer("hallo", Tock, 1.milli.dilated) TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1.second.dilated) cancelTimer("hallo") sender() ! Tick setTimer("hallo", Tock, 500.millis.dilated) stay case Event(Tock, _) ⇒ tester ! Tock stay case Event(Cancel, _) ⇒ cancelTimer("hallo") goto(Initial) } when(TestRepeatedTimer) { case Event(Tick, remaining) ⇒ tester ! Tick if (remaining == 0) { cancelTimer("tester") goto(Initial) } else { stay using (remaining - 1) } } when(TestCancelStateTimerInNamedTimerMessage) { // FSM is suspended after processing this message and resumed 500ms later case Event(Tick, _) ⇒ suspend(self) setTimer("named", Tock, 1.millis.dilated) TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1.second.dilated) stay forMax (1.millis.dilated) replying Tick case Event(Tock, _) ⇒ goto(TestCancelStateTimerInNamedTimerMessage2) } when(TestCancelStateTimerInNamedTimerMessage2) { case Event(StateTimeout, _) ⇒ goto(Initial) case Event(Cancel, _) ⇒ goto(Initial) replying Cancel } when(TestUnhandled) { case Event(SetHandler, _) ⇒ whenUnhandled { case Event(Tick, _) ⇒ tester ! Unhandled(Tick) stay } stay case Event(Cancel, _) ⇒ whenUnhandled(NullFunction) goto(Initial) } } } Other Akka source code examplesHere is a short list of links related to this Akka FSMTimingSpec.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.