FSM: remove Ev extractor and move -> into companion object, see #1759
This commit is contained in:
parent
b4d9486e63
commit
983a6d3ace
6 changed files with 56 additions and 54 deletions
|
|
@ -7,7 +7,6 @@ package akka.actor
|
||||||
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
|
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
|
||||||
import akka.testkit._
|
import akka.testkit._
|
||||||
import TestEvent.Mute
|
import TestEvent.Mute
|
||||||
import FSM._
|
|
||||||
import akka.util.duration._
|
import akka.util.duration._
|
||||||
import akka.event._
|
import akka.event._
|
||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
|
|
@ -52,7 +51,7 @@ object FSMActorSpec {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Event("hello", _) ⇒ stay replying "world"
|
case Event("hello", _) ⇒ stay replying "world"
|
||||||
case Event("bye", _) ⇒ stop(Shutdown)
|
case Event("bye", _) ⇒ stop(FSM.Shutdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
when(Open) {
|
when(Open) {
|
||||||
|
|
@ -63,7 +62,7 @@ object FSMActorSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
whenUnhandled {
|
whenUnhandled {
|
||||||
case Ev(msg) ⇒ {
|
case Event(msg, _) ⇒ {
|
||||||
log.warning("unhandled event " + msg + " in state " + stateName + " with data " + stateData)
|
log.warning("unhandled event " + msg + " in state " + stateName + " with data " + stateData)
|
||||||
unhandledLatch.open
|
unhandledLatch.open
|
||||||
stay
|
stay
|
||||||
|
|
@ -82,7 +81,7 @@ object FSMActorSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
onTermination {
|
onTermination {
|
||||||
case StopEvent(Shutdown, Locked, _) ⇒
|
case StopEvent(FSM.Shutdown, Locked, _) ⇒
|
||||||
// stop is called from lockstate with shutdown as reason...
|
// stop is called from lockstate with shutdown as reason...
|
||||||
terminatedLatch.open
|
terminatedLatch.open
|
||||||
}
|
}
|
||||||
|
|
@ -110,6 +109,8 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
|
|
||||||
"unlock the lock" in {
|
"unlock the lock" in {
|
||||||
|
|
||||||
|
import FSM.{ Transition, CurrentState, SubscribeTransitionCallBack }
|
||||||
|
|
||||||
val latches = new Latches
|
val latches = new Latches
|
||||||
import latches._
|
import latches._
|
||||||
|
|
||||||
|
|
@ -163,7 +164,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
val fsm = TestActorRef(new Actor with FSM[Int, Null] {
|
val fsm = TestActorRef(new Actor with FSM[Int, Null] {
|
||||||
startWith(1, null)
|
startWith(1, null)
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev("go") ⇒ goto(2)
|
case Event("go", _) ⇒ goto(2)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
val name = fsm.path.toString
|
val name = fsm.path.toString
|
||||||
|
|
@ -182,7 +183,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
lazy val fsm = new Actor with FSM[Int, Null] {
|
lazy val fsm = new Actor with FSM[Int, Null] {
|
||||||
override def preStart = { started.countDown }
|
override def preStart = { started.countDown }
|
||||||
startWith(1, null)
|
startWith(1, null)
|
||||||
when(1) { NullFunction }
|
when(1) { FSM.NullFunction }
|
||||||
onTermination {
|
onTermination {
|
||||||
case x ⇒ testActor ! x
|
case x ⇒ testActor ! x
|
||||||
}
|
}
|
||||||
|
|
@ -190,7 +191,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
val ref = system.actorOf(Props(fsm))
|
val ref = system.actorOf(Props(fsm))
|
||||||
Await.ready(started, timeout.duration)
|
Await.ready(started, timeout.duration)
|
||||||
system.stop(ref)
|
system.stop(ref)
|
||||||
expectMsg(1 second, fsm.StopEvent(Shutdown, 1, null))
|
expectMsg(1 second, fsm.StopEvent(FSM.Shutdown, 1, null))
|
||||||
}
|
}
|
||||||
|
|
||||||
"log events and transitions if asked to do so" in {
|
"log events and transitions if asked to do so" in {
|
||||||
|
|
@ -204,12 +205,12 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] {
|
val fsm = TestActorRef(new Actor with LoggingFSM[Int, Null] {
|
||||||
startWith(1, null)
|
startWith(1, null)
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev("go") ⇒
|
case Event("go", _) ⇒
|
||||||
setTimer("t", Shutdown, 1.5 seconds, false)
|
setTimer("t", FSM.Shutdown, 1.5 seconds, false)
|
||||||
goto(2)
|
goto(2)
|
||||||
}
|
}
|
||||||
when(2) {
|
when(2) {
|
||||||
case Ev("stop") ⇒
|
case Event("stop", _) ⇒
|
||||||
cancelTimer("t")
|
cancelTimer("t")
|
||||||
stop
|
stop
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +231,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
expectMsgPF(1 second, hint = "processing Event(stop,null)") {
|
expectMsgPF(1 second, hint = "processing Event(stop,null)") {
|
||||||
case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(stop,null) from Actor[") ⇒ true
|
case Logging.Debug(`name`, `fsmClass`, s: String) if s.startsWith("processing Event(stop,null) from Actor[") ⇒ true
|
||||||
}
|
}
|
||||||
expectMsgAllOf(1 second, Logging.Debug(name, fsmClass, "canceling timer 't'"), Normal)
|
expectMsgAllOf(1 second, Logging.Debug(name, fsmClass, "canceling timer 't'"), FSM.Normal)
|
||||||
expectNoMsg(1 second)
|
expectNoMsg(1 second)
|
||||||
system.eventStream.unsubscribe(testActor)
|
system.eventStream.unsubscribe(testActor)
|
||||||
}
|
}
|
||||||
|
|
@ -251,6 +252,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
|
||||||
})
|
})
|
||||||
fsmref ! "log"
|
fsmref ! "log"
|
||||||
val fsm = fsmref.underlyingActor
|
val fsm = fsmref.underlyingActor
|
||||||
|
import FSM.LogEntry
|
||||||
expectMsg(1 second, IndexedSeq(LogEntry(1, 0, "log")))
|
expectMsg(1 second, IndexedSeq(LogEntry(1, 0, "log")))
|
||||||
fsmref ! "count"
|
fsmref ! "count"
|
||||||
fsmref ! "log"
|
fsmref ! "log"
|
||||||
|
|
|
||||||
|
|
@ -160,37 +160,37 @@ object FSMTimingSpec {
|
||||||
|
|
||||||
startWith(Initial, 0)
|
startWith(Initial, 0)
|
||||||
when(Initial) {
|
when(Initial) {
|
||||||
case Ev(TestSingleTimer) ⇒
|
case Event(TestSingleTimer, _) ⇒
|
||||||
setTimer("tester", Tick, 500 millis, false)
|
setTimer("tester", Tick, 500 millis, false)
|
||||||
goto(TestSingleTimer)
|
goto(TestSingleTimer)
|
||||||
case Ev(TestRepeatedTimer) ⇒
|
case Event(TestRepeatedTimer, _) ⇒
|
||||||
setTimer("tester", Tick, 100 millis, true)
|
setTimer("tester", Tick, 100 millis, true)
|
||||||
goto(TestRepeatedTimer) using 4
|
goto(TestRepeatedTimer) using 4
|
||||||
case Ev(TestStateTimeoutOverride) ⇒
|
case Event(TestStateTimeoutOverride, _) ⇒
|
||||||
goto(TestStateTimeout) forMax (Duration.Inf)
|
goto(TestStateTimeout) forMax (Duration.Inf)
|
||||||
case Ev(x: FSMTimingSpec.State) ⇒ goto(x)
|
case Event(x: FSMTimingSpec.State, _) ⇒ goto(x)
|
||||||
}
|
}
|
||||||
when(TestStateTimeout, stateTimeout = 500 millis) {
|
when(TestStateTimeout, stateTimeout = 500 millis) {
|
||||||
case Ev(StateTimeout) ⇒ goto(Initial)
|
case Event(StateTimeout, _) ⇒ goto(Initial)
|
||||||
case Ev(Cancel) ⇒ goto(Initial) replying (Cancel)
|
case Event(Cancel, _) ⇒ goto(Initial) replying (Cancel)
|
||||||
}
|
}
|
||||||
when(TestSingleTimer) {
|
when(TestSingleTimer) {
|
||||||
case Ev(Tick) ⇒
|
case Event(Tick, _) ⇒
|
||||||
tester ! Tick
|
tester ! Tick
|
||||||
goto(Initial)
|
goto(Initial)
|
||||||
}
|
}
|
||||||
when(TestCancelTimer) {
|
when(TestCancelTimer) {
|
||||||
case Ev(Tick) ⇒
|
case Event(Tick, _) ⇒
|
||||||
setTimer("hallo", Tock, 1 milli, false)
|
setTimer("hallo", Tock, 1 milli, false)
|
||||||
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
|
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
|
||||||
cancelTimer("hallo")
|
cancelTimer("hallo")
|
||||||
sender ! Tick
|
sender ! Tick
|
||||||
setTimer("hallo", Tock, 500 millis, false)
|
setTimer("hallo", Tock, 500 millis, false)
|
||||||
stay
|
stay
|
||||||
case Ev(Tock) ⇒
|
case Event(Tock, _) ⇒
|
||||||
tester ! Tock
|
tester ! Tock
|
||||||
stay
|
stay
|
||||||
case Ev(Cancel) ⇒
|
case Event(Cancel, _) ⇒
|
||||||
cancelTimer("hallo")
|
cancelTimer("hallo")
|
||||||
goto(Initial)
|
goto(Initial)
|
||||||
}
|
}
|
||||||
|
|
@ -206,29 +206,29 @@ object FSMTimingSpec {
|
||||||
}
|
}
|
||||||
when(TestCancelStateTimerInNamedTimerMessage) {
|
when(TestCancelStateTimerInNamedTimerMessage) {
|
||||||
// FSM is suspended after processing this message and resumed 500ms later
|
// FSM is suspended after processing this message and resumed 500ms later
|
||||||
case Ev(Tick) ⇒
|
case Event(Tick, _) ⇒
|
||||||
suspend(self)
|
suspend(self)
|
||||||
setTimer("named", Tock, 1 millis, false)
|
setTimer("named", Tock, 1 millis, false)
|
||||||
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
|
TestKit.awaitCond(context.asInstanceOf[ActorCell].mailbox.hasMessages, 1 second)
|
||||||
stay forMax (1 millis) replying Tick
|
stay forMax (1 millis) replying Tick
|
||||||
case Ev(Tock) ⇒
|
case Event(Tock, _) ⇒
|
||||||
goto(TestCancelStateTimerInNamedTimerMessage2)
|
goto(TestCancelStateTimerInNamedTimerMessage2)
|
||||||
}
|
}
|
||||||
when(TestCancelStateTimerInNamedTimerMessage2) {
|
when(TestCancelStateTimerInNamedTimerMessage2) {
|
||||||
case Ev(StateTimeout) ⇒
|
case Event(StateTimeout, _) ⇒
|
||||||
goto(Initial)
|
goto(Initial)
|
||||||
case Ev(Cancel) ⇒
|
case Event(Cancel, _) ⇒
|
||||||
goto(Initial) replying Cancel
|
goto(Initial) replying Cancel
|
||||||
}
|
}
|
||||||
when(TestUnhandled) {
|
when(TestUnhandled) {
|
||||||
case Ev(SetHandler) ⇒
|
case Event(SetHandler, _) ⇒
|
||||||
whenUnhandled {
|
whenUnhandled {
|
||||||
case Ev(Tick) ⇒
|
case Event(Tick, _) ⇒
|
||||||
tester ! Unhandled(Tick)
|
tester ! Unhandled(Tick)
|
||||||
stay
|
stay
|
||||||
}
|
}
|
||||||
stay
|
stay
|
||||||
case Ev(Cancel) ⇒
|
case Event(Cancel, _) ⇒
|
||||||
whenUnhandled(NullFunction)
|
whenUnhandled(NullFunction)
|
||||||
goto(Initial)
|
goto(Initial)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ package akka.actor
|
||||||
|
|
||||||
import akka.testkit._
|
import akka.testkit._
|
||||||
import akka.util.duration._
|
import akka.util.duration._
|
||||||
import FSM._
|
|
||||||
import akka.util.Duration
|
import akka.util.Duration
|
||||||
|
|
||||||
object FSMTransitionSpec {
|
object FSMTransitionSpec {
|
||||||
|
|
@ -17,13 +16,13 @@ object FSMTransitionSpec {
|
||||||
class MyFSM(target: ActorRef) extends Actor with FSM[Int, Unit] {
|
class MyFSM(target: ActorRef) extends Actor with FSM[Int, Unit] {
|
||||||
startWith(0, Unit)
|
startWith(0, Unit)
|
||||||
when(0) {
|
when(0) {
|
||||||
case Ev("tick") ⇒ goto(1)
|
case Event("tick", _) ⇒ goto(1)
|
||||||
}
|
}
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev("tick") ⇒ goto(0)
|
case Event("tick", _) ⇒ goto(0)
|
||||||
}
|
}
|
||||||
whenUnhandled {
|
whenUnhandled {
|
||||||
case Ev("reply") ⇒ stay replying "reply"
|
case Event("reply", _) ⇒ stay replying "reply"
|
||||||
}
|
}
|
||||||
initialize
|
initialize
|
||||||
override def preRestart(reason: Throwable, msg: Option[Any]) { target ! "restarted" }
|
override def preRestart(reason: Throwable, msg: Option[Any]) { target ! "restarted" }
|
||||||
|
|
@ -32,10 +31,10 @@ object FSMTransitionSpec {
|
||||||
class OtherFSM(target: ActorRef) extends Actor with FSM[Int, Int] {
|
class OtherFSM(target: ActorRef) extends Actor with FSM[Int, Int] {
|
||||||
startWith(0, 0)
|
startWith(0, 0)
|
||||||
when(0) {
|
when(0) {
|
||||||
case Ev("tick") ⇒ goto(1) using (1)
|
case Event("tick", _) ⇒ goto(1) using (1)
|
||||||
}
|
}
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev(_) ⇒ stay
|
case _ ⇒ stay
|
||||||
}
|
}
|
||||||
onTransition {
|
onTransition {
|
||||||
case 0 -> 1 ⇒ target ! ((stateData, nextStateData))
|
case 0 -> 1 ⇒ target ! ((stateData, nextStateData))
|
||||||
|
|
@ -56,6 +55,8 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender {
|
||||||
"A FSM transition notifier" must {
|
"A FSM transition notifier" must {
|
||||||
|
|
||||||
"notify listeners" in {
|
"notify listeners" in {
|
||||||
|
import FSM.{ SubscribeTransitionCallBack, CurrentState, Transition }
|
||||||
|
|
||||||
val fsm = system.actorOf(Props(new MyFSM(testActor)))
|
val fsm = system.actorOf(Props(new MyFSM(testActor)))
|
||||||
within(1 second) {
|
within(1 second) {
|
||||||
fsm ! SubscribeTransitionCallBack(testActor)
|
fsm ! SubscribeTransitionCallBack(testActor)
|
||||||
|
|
@ -77,8 +78,8 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
within(300 millis) {
|
within(300 millis) {
|
||||||
fsm ! SubscribeTransitionCallBack(forward)
|
fsm ! FSM.SubscribeTransitionCallBack(forward)
|
||||||
expectMsg(CurrentState(fsm, 0))
|
expectMsg(FSM.CurrentState(fsm, 0))
|
||||||
system.stop(forward)
|
system.stop(forward)
|
||||||
fsm ! "tick"
|
fsm ! "tick"
|
||||||
expectNoMsg
|
expectNoMsg
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,14 @@ object FSM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This extractor is just convenience for matching a (S, S) pair, including a
|
||||||
|
* reminder what the new state is.
|
||||||
|
*/
|
||||||
|
object -> {
|
||||||
|
def unapply[S](in: (S, S)) = Some(in)
|
||||||
|
}
|
||||||
|
|
||||||
case class LogEntry[S, D](stateName: S, stateData: D, event: Any)
|
case class LogEntry[S, D](stateName: S, stateData: D, event: Any)
|
||||||
|
|
||||||
case class State[S, D](stateName: S, stateData: D, timeout: Option[Duration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) {
|
case class State[S, D](stateName: S, stateData: D, timeout: Option[Duration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) {
|
||||||
|
|
@ -174,6 +182,10 @@ trait FSM[S, D] extends Listeners {
|
||||||
type Timeout = Option[Duration]
|
type Timeout = Option[Duration]
|
||||||
type TransitionHandler = PartialFunction[(S, S), Unit]
|
type TransitionHandler = PartialFunction[(S, S), Unit]
|
||||||
|
|
||||||
|
// “import” so that it is visible without an import
|
||||||
|
val -> = FSM.->
|
||||||
|
val StateTimeout = FSM.StateTimeout
|
||||||
|
|
||||||
val log = Logging(context.system, this)
|
val log = Logging(context.system, this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -284,14 +296,6 @@ trait FSM[S, D] extends Listeners {
|
||||||
*/
|
*/
|
||||||
protected final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout
|
protected final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout
|
||||||
|
|
||||||
/**
|
|
||||||
* This extractor is just convenience for matching a (S, S) pair, including a
|
|
||||||
* reminder what the new state is.
|
|
||||||
*/
|
|
||||||
object -> {
|
|
||||||
def unapply[S](in: (S, S)) = Some(in)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set handler which is called upon each state transition, i.e. not when
|
* Set handler which is called upon each state transition, i.e. not when
|
||||||
* staying in the same state. This may use the pair extractor defined in the
|
* staying in the same state. This may use the pair extractor defined in the
|
||||||
|
|
@ -533,9 +537,6 @@ trait FSM[S, D] extends Listeners {
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Event(event: Any, stateData: D)
|
case class Event(event: Any, stateData: D)
|
||||||
object Ev {
|
|
||||||
def unapply[D](e: Event): Option[Any] = Some(e.event)
|
|
||||||
}
|
|
||||||
|
|
||||||
case class StopEvent[S, D](reason: Reason, currentState: S, stateData: D)
|
case class StopEvent[S, D](reason: Reason, currentState: S, stateData: D)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,10 +89,10 @@ class TestkitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
||||||
val fsm = TestFSMRef(new Actor with FSM[Int, String] {
|
val fsm = TestFSMRef(new Actor with FSM[Int, String] {
|
||||||
startWith(1, "")
|
startWith(1, "")
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev("go") ⇒ goto(2) using "go"
|
case Event("go", _) ⇒ goto(2) using "go"
|
||||||
}
|
}
|
||||||
when(2) {
|
when(2) {
|
||||||
case Ev("back") ⇒ goto(1) using "back"
|
case Event("back", _) ⇒ goto(1) using "back"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,17 @@ import akka.util.duration._
|
||||||
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
||||||
class TestFSMRefSpec extends AkkaSpec {
|
class TestFSMRefSpec extends AkkaSpec {
|
||||||
|
|
||||||
import FSM._
|
|
||||||
|
|
||||||
"A TestFSMRef" must {
|
"A TestFSMRef" must {
|
||||||
|
|
||||||
"allow access to state data" in {
|
"allow access to state data" in {
|
||||||
val fsm = TestFSMRef(new Actor with FSM[Int, String] {
|
val fsm = TestFSMRef(new Actor with FSM[Int, String] {
|
||||||
startWith(1, "")
|
startWith(1, "")
|
||||||
when(1) {
|
when(1) {
|
||||||
case Ev("go") ⇒ goto(2) using "go"
|
case Event("go", _) ⇒ goto(2) using "go"
|
||||||
case Ev(StateTimeout) ⇒ goto(2) using "timeout"
|
case Event(StateTimeout, _) ⇒ goto(2) using "timeout"
|
||||||
}
|
}
|
||||||
when(2) {
|
when(2) {
|
||||||
case Ev("back") ⇒ goto(1) using "back"
|
case Event("back", _) ⇒ goto(1) using "back"
|
||||||
}
|
}
|
||||||
}, "test-fsm-ref-1")
|
}, "test-fsm-ref-1")
|
||||||
fsm.stateName must be(1)
|
fsm.stateName must be(1)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue