2011-05-19 21:34:21 +02:00
|
|
|
/**
|
2011-07-14 16:03:08 +02:00
|
|
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
2011-05-19 21:34:21 +02:00
|
|
|
*/
|
2011-04-16 22:20:04 +02:00
|
|
|
package akka.testkit
|
|
|
|
|
|
|
|
|
|
import org.scalatest.matchers.MustMatchers
|
2011-05-18 17:25:30 +02:00
|
|
|
import org.scalatest.{ BeforeAndAfterEach, WordSpec }
|
2011-04-16 22:20:04 +02:00
|
|
|
import akka.actor._
|
2011-10-27 12:23:01 +02:00
|
|
|
import akka.event.Logging.Warning
|
2011-06-04 12:42:06 -07:00
|
|
|
import akka.dispatch.{ Future, Promise }
|
2011-10-22 16:06:20 +02:00
|
|
|
import akka.util.duration._
|
2011-11-10 20:08:00 +01:00
|
|
|
import akka.actor.ActorSystem
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Test whether TestActorRef behaves as an ActorRef should, besides its own spec.
|
|
|
|
|
*
|
|
|
|
|
* @author Roland Kuhn
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
object TestActorRefSpec {
|
|
|
|
|
|
|
|
|
|
var counter = 4
|
|
|
|
|
val thread = Thread.currentThread
|
2011-05-18 17:25:30 +02:00
|
|
|
var otherthread: Thread = null
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
trait TActor extends Actor {
|
|
|
|
|
def receive = new Receive {
|
|
|
|
|
val recv = receiveT
|
2011-05-18 17:25:30 +02:00
|
|
|
def isDefinedAt(o: Any) = recv.isDefinedAt(o)
|
|
|
|
|
def apply(o: Any) {
|
2011-04-16 22:20:04 +02:00
|
|
|
if (Thread.currentThread ne thread)
|
|
|
|
|
otherthread = Thread.currentThread
|
|
|
|
|
recv(o)
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-05-18 17:25:30 +02:00
|
|
|
def receiveT: Receive
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ReplyActor extends TActor {
|
2011-10-22 16:06:20 +02:00
|
|
|
var replyTo: ActorRef = null
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
def receiveT = {
|
2011-05-18 17:25:30 +02:00
|
|
|
case "complexRequest" ⇒ {
|
2011-10-22 16:06:20 +02:00
|
|
|
replyTo = sender
|
2011-08-26 17:25:18 +02:00
|
|
|
val worker = TestActorRef(Props[WorkerActor])
|
2011-04-16 22:20:04 +02:00
|
|
|
worker ! "work"
|
|
|
|
|
}
|
2011-05-18 17:25:30 +02:00
|
|
|
case "complexRequest2" ⇒
|
2011-08-26 17:25:18 +02:00
|
|
|
val worker = TestActorRef(Props[WorkerActor])
|
2011-10-22 16:06:20 +02:00
|
|
|
worker ! sender
|
2011-05-18 17:25:30 +02:00
|
|
|
case "workDone" ⇒ replyTo ! "complexReply"
|
2011-10-22 16:06:20 +02:00
|
|
|
case "simpleRequest" ⇒ sender ! "simpleReply"
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class WorkerActor() extends TActor {
|
|
|
|
|
def receiveT = {
|
2011-10-22 16:06:20 +02:00
|
|
|
case "work" ⇒ sender ! "workDone"; self.stop()
|
|
|
|
|
case replyTo: Promise[Any] ⇒ replyTo.completeWithResult("complexReply")
|
|
|
|
|
case replyTo: ActorRef ⇒ replyTo ! "complexReply"
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SenderActor(replyActor: ActorRef) extends TActor {
|
|
|
|
|
|
|
|
|
|
def receiveT = {
|
2011-05-18 17:25:30 +02:00
|
|
|
case "complex" ⇒ replyActor ! "complexRequest"
|
|
|
|
|
case "complex2" ⇒ replyActor ! "complexRequest2"
|
|
|
|
|
case "simple" ⇒ replyActor ! "simpleRequest"
|
|
|
|
|
case "complexReply" ⇒ {
|
2011-04-16 22:20:04 +02:00
|
|
|
counter -= 1
|
|
|
|
|
}
|
2011-05-18 17:25:30 +02:00
|
|
|
case "simpleReply" ⇒ {
|
2011-04-16 22:20:04 +02:00
|
|
|
counter -= 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class Logger extends Actor {
|
|
|
|
|
var count = 0
|
2011-05-18 17:25:30 +02:00
|
|
|
var msg: String = _
|
2011-04-16 22:20:04 +02:00
|
|
|
def receive = {
|
2011-05-18 17:25:30 +02:00
|
|
|
case Warning(_, m: String) ⇒ count += 1; msg = m
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-21 17:01:22 +02:00
|
|
|
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
|
2011-10-10 11:12:34 +02:00
|
|
|
class TestActorRefSpec extends AkkaSpec with BeforeAndAfterEach {
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
import TestActorRefSpec._
|
|
|
|
|
|
|
|
|
|
override def beforeEach {
|
|
|
|
|
otherthread = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private def assertThread {
|
2011-05-18 17:25:30 +02:00
|
|
|
otherthread must (be(null) or equal(thread))
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"A TestActorRef must be an ActorRef, hence it" must {
|
|
|
|
|
|
|
|
|
|
"support nested Actor creation" when {
|
|
|
|
|
|
|
|
|
|
"used with TestActorRef" in {
|
2011-08-26 17:25:18 +02:00
|
|
|
val a = TestActorRef(Props(new Actor {
|
|
|
|
|
val nested = TestActorRef(Props(self ⇒ { case _ ⇒ }))
|
2011-10-22 16:06:20 +02:00
|
|
|
def receive = { case _ ⇒ sender ! nested }
|
2011-08-26 17:25:18 +02:00
|
|
|
}))
|
2011-04-16 22:20:04 +02:00
|
|
|
a must not be (null)
|
2011-06-13 15:29:35 +02:00
|
|
|
val nested = (a ? "any").as[ActorRef].get
|
2011-04-16 22:20:04 +02:00
|
|
|
nested must not be (null)
|
2011-05-18 17:25:30 +02:00
|
|
|
a must not be theSameInstanceAs(nested)
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"used with ActorRef" in {
|
2011-08-26 17:25:18 +02:00
|
|
|
val a = TestActorRef(Props(new Actor {
|
2011-10-18 17:56:23 +02:00
|
|
|
val nested = context.actorOf(Props(self ⇒ { case _ ⇒ }))
|
2011-10-22 16:06:20 +02:00
|
|
|
def receive = { case _ ⇒ sender ! nested }
|
2011-08-26 17:25:18 +02:00
|
|
|
}))
|
2011-04-16 22:20:04 +02:00
|
|
|
a must not be (null)
|
2011-06-13 15:29:35 +02:00
|
|
|
val nested = (a ? "any").as[ActorRef].get
|
2011-04-16 22:20:04 +02:00
|
|
|
nested must not be (null)
|
2011-05-18 17:25:30 +02:00
|
|
|
a must not be theSameInstanceAs(nested)
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-22 16:06:20 +02:00
|
|
|
"support reply via sender" in {
|
2011-08-26 17:25:18 +02:00
|
|
|
val serverRef = TestActorRef(Props[ReplyActor])
|
|
|
|
|
val clientRef = TestActorRef(Props(new SenderActor(serverRef)))
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
counter = 4
|
|
|
|
|
|
|
|
|
|
clientRef ! "complex"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
|
2011-05-18 17:25:30 +02:00
|
|
|
counter must be(0)
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
counter = 4
|
|
|
|
|
|
|
|
|
|
clientRef ! "complex2"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
clientRef ! "simple"
|
|
|
|
|
|
2011-05-18 17:25:30 +02:00
|
|
|
counter must be(0)
|
2011-04-16 22:20:04 +02:00
|
|
|
|
|
|
|
|
assertThread
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"stop when sent a poison pill" in {
|
2011-11-07 22:10:17 +01:00
|
|
|
EventFilter[ActorKilledException]() intercept {
|
2011-08-26 17:25:18 +02:00
|
|
|
val a = TestActorRef(Props[WorkerActor])
|
2011-11-16 16:46:16 +01:00
|
|
|
testActor startsWatching a
|
2011-10-22 16:06:20 +02:00
|
|
|
a.!(PoisonPill)(testActor)
|
|
|
|
|
expectMsgPF(5 seconds) {
|
|
|
|
|
case Terminated(`a`) ⇒ true
|
2011-07-29 15:22:11 -06:00
|
|
|
}
|
2011-11-23 19:03:56 +01:00
|
|
|
a.isTerminated must be(true)
|
2011-07-29 15:22:11 -06:00
|
|
|
assertThread
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"restart when Kill:ed" in {
|
2011-11-07 22:10:17 +01:00
|
|
|
EventFilter[ActorKilledException]() intercept {
|
2011-07-29 15:22:11 -06:00
|
|
|
counter = 2
|
|
|
|
|
|
2011-08-26 17:25:18 +02:00
|
|
|
val boss = TestActorRef(Props(new TActor {
|
2011-11-16 17:18:36 +01:00
|
|
|
val impl = system.asInstanceOf[ActorSystemImpl]
|
2011-11-17 16:09:18 +01:00
|
|
|
val ref = new TestActorRef(impl, impl.dispatcherFactory.prerequisites, Props(new TActor {
|
2011-07-29 15:22:11 -06:00
|
|
|
def receiveT = { case _ ⇒ }
|
|
|
|
|
override def preRestart(reason: Throwable, msg: Option[Any]) { counter -= 1 }
|
|
|
|
|
override def postRestart(reason: Throwable) { counter -= 1 }
|
2011-10-18 15:39:26 +02:00
|
|
|
}), self, "child")
|
2011-08-26 17:25:18 +02:00
|
|
|
|
2011-07-29 15:22:11 -06:00
|
|
|
def receiveT = { case "sendKill" ⇒ ref ! Kill }
|
2011-09-28 14:08:04 +02:00
|
|
|
}).withFaultHandler(OneForOneStrategy(List(classOf[ActorKilledException]), 5, 1000)))
|
2011-04-16 22:20:04 +02:00
|
|
|
|
2011-07-29 15:22:11 -06:00
|
|
|
boss ! "sendKill"
|
2011-04-16 22:20:04 +02:00
|
|
|
|
2011-07-29 15:22:11 -06:00
|
|
|
counter must be(0)
|
|
|
|
|
assertThread
|
|
|
|
|
}
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"support futures" in {
|
2011-09-08 11:02:17 +02:00
|
|
|
val a = TestActorRef[WorkerActor]
|
2011-11-09 14:56:05 +01:00
|
|
|
val f = a ? "work"
|
|
|
|
|
// CallingThreadDispatcher means that there is no delay
|
2011-05-18 17:25:30 +02:00
|
|
|
f must be('completed)
|
2011-11-09 14:56:05 +01:00
|
|
|
f.as[String] must equal(Some("workDone"))
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"A TestActorRef" must {
|
|
|
|
|
|
|
|
|
|
"allow access to internals" in {
|
|
|
|
|
val ref = TestActorRef(new TActor {
|
2011-05-18 17:25:30 +02:00
|
|
|
var s: String = _
|
2011-04-16 22:20:04 +02:00
|
|
|
def receiveT = {
|
2011-05-18 17:25:30 +02:00
|
|
|
case x: String ⇒ s = x
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
2011-09-08 11:02:17 +02:00
|
|
|
})
|
2011-04-16 22:20:04 +02:00
|
|
|
ref ! "hallo"
|
|
|
|
|
val actor = ref.underlyingActor
|
2011-05-18 17:25:30 +02:00
|
|
|
actor.s must equal("hallo")
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"set receiveTimeout to None" in {
|
|
|
|
|
val a = TestActorRef[WorkerActor]
|
2011-09-19 11:22:27 +02:00
|
|
|
a.underlyingActor.receiveTimeout must be(None)
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
"set CallingThreadDispatcher" in {
|
|
|
|
|
val a = TestActorRef[WorkerActor]
|
2011-09-19 11:22:27 +02:00
|
|
|
a.underlying.dispatcher.getClass must be(classOf[CallingThreadDispatcher])
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
2011-06-04 12:42:06 -07:00
|
|
|
"proxy apply for the underlying actor" in {
|
2011-09-08 11:02:17 +02:00
|
|
|
val ref = TestActorRef[WorkerActor]
|
2011-10-22 16:06:20 +02:00
|
|
|
ref("work")
|
2011-11-23 19:03:56 +01:00
|
|
|
ref.isTerminated must be(true)
|
2011-04-21 21:31:24 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
2011-04-21 21:31:24 +02:00
|
|
|
}
|