2011-12-19 11:07:59 +01:00
|
|
|
/**
|
2016-02-23 12:58:39 +01:00
|
|
|
* Copyright (C) 2009-2016 Lightbend Inc. <http://www.lightbend.com>
|
2011-12-19 11:07:59 +01:00
|
|
|
*/
|
2012-05-22 11:37:09 +02:00
|
|
|
package docs.testkit
|
2011-12-15 15:03:05 +01:00
|
|
|
|
2012-06-28 15:33:49 +02:00
|
|
|
import language.postfixOps
|
2012-08-20 15:21:44 +02:00
|
|
|
import scala.util.Success
|
2013-06-20 00:04:57 +02:00
|
|
|
import akka.testkit._
|
2012-06-28 15:33:49 +02:00
|
|
|
|
2011-12-15 15:03:05 +01:00
|
|
|
//#imports-test-probe
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2012-07-06 17:04:04 +02:00
|
|
|
import scala.concurrent.Future
|
2014-07-02 12:55:48 +10:00
|
|
|
import akka.actor._
|
|
|
|
|
import akka.testkit.TestProbe
|
2011-12-15 15:03:05 +01:00
|
|
|
|
|
|
|
|
//#imports-test-probe
|
|
|
|
|
|
2012-07-22 15:33:18 +02:00
|
|
|
import scala.util.control.NonFatal
|
2012-06-04 10:03:41 +02:00
|
|
|
|
2011-12-15 15:03:05 +01:00
|
|
|
object TestkitDocSpec {
|
|
|
|
|
case object Say42
|
|
|
|
|
case object Unknown
|
|
|
|
|
|
|
|
|
|
class MyActor extends Actor {
|
|
|
|
|
def receive = {
|
2014-01-16 15:16:35 +01:00
|
|
|
case Say42 => sender() ! 42
|
|
|
|
|
case "some work" => sender() ! "some result"
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-20 00:04:57 +02:00
|
|
|
class TestFsmActor extends Actor with FSM[Int, String] {
|
|
|
|
|
startWith(1, "")
|
|
|
|
|
when(1) {
|
2013-12-03 16:34:26 +01:00
|
|
|
case Event("go", _) => goto(2) using "go"
|
2013-06-20 00:04:57 +02:00
|
|
|
}
|
|
|
|
|
when(2) {
|
2013-12-03 16:34:26 +01:00
|
|
|
case Event("back", _) => goto(1) using "back"
|
2013-06-20 00:04:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-15 15:03:05 +01:00
|
|
|
//#my-double-echo
|
|
|
|
|
class MyDoubleEcho extends Actor {
|
|
|
|
|
var dest1: ActorRef = _
|
|
|
|
|
var dest2: ActorRef = _
|
|
|
|
|
def receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case (d1: ActorRef, d2: ActorRef) =>
|
2011-12-15 15:03:05 +01:00
|
|
|
dest1 = d1
|
|
|
|
|
dest2 = d2
|
2013-12-03 16:34:26 +01:00
|
|
|
case x =>
|
2011-12-15 15:03:05 +01:00
|
|
|
dest1 ! x
|
|
|
|
|
dest2 ! x
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#my-double-echo
|
|
|
|
|
|
|
|
|
|
import akka.testkit.TestProbe
|
|
|
|
|
|
|
|
|
|
//#test-probe-forward-actors
|
|
|
|
|
class Source(target: ActorRef) extends Actor {
|
|
|
|
|
def receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case "start" => target ! "work"
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Destination extends Actor {
|
|
|
|
|
def receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case x => // Do something..
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//#test-probe-forward-actors
|
|
|
|
|
|
|
|
|
|
class LoggingActor extends Actor {
|
|
|
|
|
//#logging-receive
|
|
|
|
|
import akka.event.LoggingReceive
|
2012-01-26 13:24:48 +01:00
|
|
|
def receive = LoggingReceive {
|
2014-03-21 20:17:53 +01:00
|
|
|
case msg => // Do something ...
|
|
|
|
|
}
|
|
|
|
|
def otherState: Receive = LoggingReceive.withLabel("other") {
|
|
|
|
|
case msg => // Do something else ...
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
//#logging-receive
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class TestkitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
|
|
|
|
|
import TestkitDocSpec._
|
|
|
|
|
|
|
|
|
|
"demonstrate usage of TestActorRef" in {
|
|
|
|
|
//#test-actor-ref
|
|
|
|
|
import akka.testkit.TestActorRef
|
|
|
|
|
|
|
|
|
|
val actorRef = TestActorRef[MyActor]
|
|
|
|
|
val actor = actorRef.underlyingActor
|
|
|
|
|
//#test-actor-ref
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate usage of TestFSMRef" in {
|
|
|
|
|
//#test-fsm-ref
|
|
|
|
|
import akka.testkit.TestFSMRef
|
|
|
|
|
import akka.actor.FSM
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-15 15:03:05 +01:00
|
|
|
|
2013-06-20 00:04:57 +02:00
|
|
|
val fsm = TestFSMRef(new TestFsmActor)
|
|
|
|
|
|
|
|
|
|
val mustBeTypedProperly: TestActorRef[TestFsmActor] = fsm
|
2011-12-15 15:03:05 +01:00
|
|
|
|
|
|
|
|
assert(fsm.stateName == 1)
|
|
|
|
|
assert(fsm.stateData == "")
|
|
|
|
|
fsm ! "go" // being a TestActorRef, this runs also on the CallingThreadDispatcher
|
|
|
|
|
assert(fsm.stateName == 2)
|
|
|
|
|
assert(fsm.stateData == "go")
|
|
|
|
|
|
|
|
|
|
fsm.setState(stateName = 1)
|
|
|
|
|
assert(fsm.stateName == 1)
|
|
|
|
|
|
2012-12-06 17:28:49 +01:00
|
|
|
assert(fsm.isTimerActive("test") == false)
|
2011-12-15 15:03:05 +01:00
|
|
|
fsm.setTimer("test", 12, 10 millis, true)
|
2012-12-06 17:28:49 +01:00
|
|
|
assert(fsm.isTimerActive("test") == true)
|
2011-12-15 15:03:05 +01:00
|
|
|
fsm.cancelTimer("test")
|
2012-12-06 17:28:49 +01:00
|
|
|
assert(fsm.isTimerActive("test") == false)
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-fsm-ref
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate testing of behavior" in {
|
|
|
|
|
|
|
|
|
|
//#test-behavior
|
|
|
|
|
import akka.testkit.TestActorRef
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2012-06-29 16:06:26 +02:00
|
|
|
import scala.concurrent.Await
|
2012-01-18 10:18:51 +01:00
|
|
|
import akka.pattern.ask
|
2011-12-15 15:03:05 +01:00
|
|
|
|
|
|
|
|
val actorRef = TestActorRef(new MyActor)
|
|
|
|
|
// hypothetical message stimulating a '42' answer
|
2012-06-25 19:30:13 +02:00
|
|
|
val future = actorRef ? Say42
|
2012-09-19 17:32:54 +02:00
|
|
|
val Success(result: Int) = future.value.get
|
2013-12-17 14:25:56 +01:00
|
|
|
result should be(42)
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-behavior
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate unhandled message" in {
|
|
|
|
|
//#test-unhandled
|
|
|
|
|
import akka.testkit.TestActorRef
|
2011-12-20 11:19:06 +01:00
|
|
|
system.eventStream.subscribe(testActor, classOf[UnhandledMessage])
|
2011-12-15 15:03:05 +01:00
|
|
|
val ref = TestActorRef[MyActor]
|
2012-01-19 15:49:44 +01:00
|
|
|
ref.receive(Unknown)
|
2011-12-20 11:19:06 +01:00
|
|
|
expectMsg(1 second, UnhandledMessage(Unknown, system.deadLetters, ref))
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-unhandled
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate expecting exceptions" in {
|
|
|
|
|
//#test-expecting-exceptions
|
|
|
|
|
import akka.testkit.TestActorRef
|
|
|
|
|
|
|
|
|
|
val actorRef = TestActorRef(new Actor {
|
|
|
|
|
def receive = {
|
2013-12-03 16:34:26 +01:00
|
|
|
case "hello" => throw new IllegalArgumentException("boom")
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
})
|
2012-01-19 15:49:44 +01:00
|
|
|
intercept[IllegalArgumentException] { actorRef.receive("hello") }
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-expecting-exceptions
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate within" in {
|
|
|
|
|
type Worker = MyActor
|
|
|
|
|
//#test-within
|
|
|
|
|
import akka.actor.Props
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-15 15:03:05 +01:00
|
|
|
|
|
|
|
|
val worker = system.actorOf(Props[Worker])
|
|
|
|
|
within(200 millis) {
|
|
|
|
|
worker ! "some work"
|
|
|
|
|
expectMsg("some result")
|
|
|
|
|
expectNoMsg // will block for the rest of the 200ms
|
|
|
|
|
Thread.sleep(300) // will NOT make this block fail
|
|
|
|
|
}
|
|
|
|
|
//#test-within
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate dilated duration" in {
|
|
|
|
|
//#duration-dilation
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2011-12-15 15:03:05 +01:00
|
|
|
import akka.testkit._
|
|
|
|
|
10.milliseconds.dilated
|
|
|
|
|
//#duration-dilation
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate usage of probe" in {
|
|
|
|
|
//#test-probe
|
|
|
|
|
val probe1 = TestProbe()
|
|
|
|
|
val probe2 = TestProbe()
|
|
|
|
|
val actor = system.actorOf(Props[MyDoubleEcho])
|
2013-03-28 23:45:48 +01:00
|
|
|
actor ! ((probe1.ref, probe2.ref))
|
2011-12-15 15:03:05 +01:00
|
|
|
actor ! "hello"
|
2011-12-21 19:07:54 +01:00
|
|
|
probe1.expectMsg(500 millis, "hello")
|
|
|
|
|
probe2.expectMsg(500 millis, "hello")
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-probe
|
|
|
|
|
|
|
|
|
|
//#test-special-probe
|
2014-03-07 13:20:01 +01:00
|
|
|
final case class Update(id: Int, value: String)
|
2011-12-15 15:03:05 +01:00
|
|
|
|
|
|
|
|
val probe = new TestProbe(system) {
|
|
|
|
|
def expectUpdate(x: Int) = {
|
|
|
|
|
expectMsgPF() {
|
2013-12-03 16:34:26 +01:00
|
|
|
case Update(id, _) if id == x => true
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
2014-01-16 15:16:35 +01:00
|
|
|
sender() ! "ACK"
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//#test-special-probe
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 22:42:40 +01:00
|
|
|
"demonstrate usage of test probe with custom name" in {
|
|
|
|
|
//#test-probe-with-custom-name
|
|
|
|
|
val worker = TestProbe("worker")
|
|
|
|
|
val aggregator = TestProbe("aggregator")
|
|
|
|
|
|
|
|
|
|
worker.ref.path.name should startWith("worker")
|
|
|
|
|
aggregator.ref.path.name should startWith("aggregator")
|
|
|
|
|
//#test-probe-with-custom-name
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-23 23:38:22 +01:00
|
|
|
"demonstrate probe watch" in {
|
|
|
|
|
import akka.testkit.TestProbe
|
2013-04-14 22:56:41 +02:00
|
|
|
val target = system.actorOf(Props.empty)
|
2013-01-23 23:38:22 +01:00
|
|
|
//#test-probe-watch
|
|
|
|
|
val probe = TestProbe()
|
|
|
|
|
probe watch target
|
2013-03-26 18:17:50 +01:00
|
|
|
target ! PoisonPill
|
2013-04-09 14:48:17 +02:00
|
|
|
probe.expectTerminated(target)
|
2013-01-23 23:38:22 +01:00
|
|
|
//#test-probe-watch
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-15 15:03:05 +01:00
|
|
|
"demonstrate probe reply" in {
|
|
|
|
|
import akka.testkit.TestProbe
|
2012-09-21 14:50:06 +02:00
|
|
|
import scala.concurrent.duration._
|
2012-01-18 10:18:51 +01:00
|
|
|
import akka.pattern.ask
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-probe-reply
|
|
|
|
|
val probe = TestProbe()
|
2011-12-31 17:42:13 -08:00
|
|
|
val future = probe.ref ? "hello"
|
2011-12-15 15:03:05 +01:00
|
|
|
probe.expectMsg(0 millis, "hello") // TestActor runs on CallingThreadDispatcher
|
2012-06-04 11:29:56 +02:00
|
|
|
probe.reply("world")
|
2012-08-22 15:52:32 +02:00
|
|
|
assert(future.isCompleted && future.value == Some(Success("world")))
|
2011-12-15 15:03:05 +01:00
|
|
|
//#test-probe-reply
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"demonstrate probe forward" in {
|
|
|
|
|
import akka.testkit.TestProbe
|
|
|
|
|
import akka.actor.Props
|
|
|
|
|
//#test-probe-forward
|
|
|
|
|
val probe = TestProbe()
|
2013-04-14 22:56:41 +02:00
|
|
|
val source = system.actorOf(Props(classOf[Source], probe.ref))
|
2011-12-15 15:03:05 +01:00
|
|
|
val dest = system.actorOf(Props[Destination])
|
|
|
|
|
source ! "start"
|
|
|
|
|
probe.expectMsg("work")
|
|
|
|
|
probe.forward(dest)
|
|
|
|
|
//#test-probe-forward
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-11 16:24:12 +01:00
|
|
|
"demonstrate calling thread dispatcher" in {
|
2011-12-15 15:03:05 +01:00
|
|
|
//#calling-thread-dispatcher
|
|
|
|
|
import akka.testkit.CallingThreadDispatcher
|
2011-12-21 19:02:06 +01:00
|
|
|
val ref = system.actorOf(Props[MyActor].withDispatcher(CallingThreadDispatcher.Id))
|
2011-12-15 15:03:05 +01:00
|
|
|
//#calling-thread-dispatcher
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-23 21:31:12 +01:00
|
|
|
"demonstrate EventFilter" in {
|
|
|
|
|
//#event-filter
|
|
|
|
|
import akka.testkit.EventFilter
|
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
|
|
|
|
|
|
implicit val system = ActorSystem("testsystem", ConfigFactory.parseString("""
|
2013-02-01 08:02:53 +01:00
|
|
|
akka.loggers = ["akka.testkit.TestEventListener"]
|
2011-12-23 21:31:12 +01:00
|
|
|
"""))
|
|
|
|
|
try {
|
|
|
|
|
val actor = system.actorOf(Props.empty)
|
|
|
|
|
EventFilter[ActorKilledException](occurrences = 1) intercept {
|
|
|
|
|
actor ! Kill
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2011-12-23 21:31:12 +01:00
|
|
|
}
|
|
|
|
|
//#event-filter
|
|
|
|
|
}
|
2012-06-04 11:29:56 +02:00
|
|
|
|
2012-06-04 10:03:41 +02:00
|
|
|
"demonstrate TestKitBase" in {
|
|
|
|
|
//#test-kit-base
|
|
|
|
|
import akka.testkit.TestKitBase
|
2012-06-04 11:29:56 +02:00
|
|
|
|
2012-06-04 10:03:41 +02:00
|
|
|
class MyTest extends TestKitBase {
|
|
|
|
|
implicit lazy val system = ActorSystem()
|
2012-06-04 11:29:56 +02:00
|
|
|
|
2012-06-04 10:03:41 +02:00
|
|
|
//#put-your-test-code-here
|
|
|
|
|
val probe = TestProbe()
|
|
|
|
|
probe.send(testActor, "hello")
|
2014-08-25 15:49:28 +02:00
|
|
|
try expectMsg("hello") catch { case NonFatal(e) => system.terminate(); throw e }
|
2012-06-04 10:03:41 +02:00
|
|
|
//#put-your-test-code-here
|
2012-06-04 11:29:56 +02:00
|
|
|
|
2013-05-02 17:12:36 +02:00
|
|
|
shutdown(system)
|
2012-06-04 10:03:41 +02:00
|
|
|
}
|
|
|
|
|
//#test-kit-base
|
|
|
|
|
}
|
2011-12-23 21:31:12 +01:00
|
|
|
|
2012-06-29 14:42:11 +02:00
|
|
|
"demonstrate within() nesting" in {
|
|
|
|
|
intercept[AssertionError] {
|
|
|
|
|
//#test-within-probe
|
|
|
|
|
val probe = TestProbe()
|
|
|
|
|
within(1 second) {
|
|
|
|
|
probe.expectMsg("hello")
|
|
|
|
|
}
|
|
|
|
|
//#test-within-probe
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-12-15 15:03:05 +01:00
|
|
|
}
|