2011-04-27 15:00:41 +02:00
|
|
|
/**
|
2011-07-14 16:03:08 +02:00
|
|
|
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
|
2011-04-27 15:00:41 +02:00
|
|
|
*/
|
|
|
|
|
|
2011-04-16 22:20:04 +02:00
|
|
|
package akka.testkit
|
|
|
|
|
|
|
|
|
|
import akka.actor._
|
|
|
|
|
import akka.util.ReflectiveAccess
|
2011-04-27 15:00:41 +02:00
|
|
|
import com.eaio.uuid.UUID
|
2011-08-26 17:25:18 +02:00
|
|
|
import akka.actor.Props._
|
2011-11-10 20:08:00 +01:00
|
|
|
import akka.actor.ActorSystem
|
2011-11-13 20:38:14 +01:00
|
|
|
import java.util.concurrent.atomic.AtomicLong
|
2011-11-14 16:03:26 +01:00
|
|
|
import akka.dispatch.Mailbox
|
|
|
|
|
import akka.event.EventStream
|
2011-04-27 15:00:41 +02:00
|
|
|
|
2011-04-16 22:20:04 +02:00
|
|
|
/**
|
|
|
|
|
* This special ActorRef is exclusively for use during unit testing in a single-threaded environment. Therefore, it
|
|
|
|
|
* overrides the dispatcher to CallingThreadDispatcher and sets the receiveTimeout to None. Otherwise,
|
|
|
|
|
* it acts just like a normal ActorRef. You may retrieve a reference to the underlying actor to test internal logic.
|
|
|
|
|
*
|
|
|
|
|
* @author Roland Kuhn
|
|
|
|
|
* @since 1.1
|
|
|
|
|
*/
|
2011-11-14 16:03:26 +01:00
|
|
|
class TestActorRef[T <: Actor](
|
2011-11-16 17:18:36 +01:00
|
|
|
_app: ActorSystemImpl,
|
2011-11-14 16:03:26 +01:00
|
|
|
_deadLetterMailbox: Mailbox,
|
|
|
|
|
_eventStream: EventStream,
|
|
|
|
|
_scheduler: Scheduler,
|
|
|
|
|
_props: Props,
|
|
|
|
|
_supervisor: ActorRef,
|
|
|
|
|
name: String)
|
|
|
|
|
extends LocalActorRef(_app, _props.withDispatcher(new CallingThreadDispatcher(_deadLetterMailbox, _eventStream, _scheduler)), _supervisor, _supervisor.path / name, false) {
|
2011-04-21 21:31:24 +02:00
|
|
|
/**
|
|
|
|
|
* Directly inject messages into actor receive behavior. Any exceptions
|
|
|
|
|
* thrown will be available to you, while still being able to use
|
|
|
|
|
* become/unbecome and their message counterparts.
|
|
|
|
|
*/
|
2011-09-15 08:12:07 +02:00
|
|
|
def apply(o: Any) { underlyingActorInstance.apply(o) }
|
2011-04-21 21:31:24 +02:00
|
|
|
|
2011-04-16 22:20:04 +02:00
|
|
|
/**
|
|
|
|
|
* Retrieve reference to the underlying actor, where the static type matches the factory used inside the
|
|
|
|
|
* constructor. Beware that this reference is discarded by the ActorRef upon restarting the actor (should this
|
|
|
|
|
* reference be linked to a supervisor). The old Actor may of course still be used in post-mortem assertions.
|
|
|
|
|
*/
|
2011-09-15 08:12:07 +02:00
|
|
|
def underlyingActor: T = underlyingActorInstance.asInstanceOf[T]
|
2011-04-16 22:20:04 +02:00
|
|
|
|
2011-11-08 11:56:46 +01:00
|
|
|
override def toString = "TestActor[" + address + "]"
|
2011-04-16 22:20:04 +02:00
|
|
|
|
2011-11-08 11:56:46 +01:00
|
|
|
override def equals(other: Any) = other.isInstanceOf[TestActorRef[_]] && other.asInstanceOf[TestActorRef[_]].address == address
|
2011-04-16 22:20:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
object TestActorRef {
|
|
|
|
|
|
2011-11-13 20:38:14 +01:00
|
|
|
private val number = new AtomicLong
|
|
|
|
|
private[testkit] def randomName: String = {
|
|
|
|
|
val l = number.getAndIncrement()
|
|
|
|
|
"$" + akka.util.Helpers.base64(l)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def apply[T <: Actor](factory: ⇒ T)(implicit app: ActorSystem): TestActorRef[T] = apply[T](Props(factory), randomName)
|
2011-04-27 15:00:41 +02:00
|
|
|
|
2011-11-10 20:08:00 +01:00
|
|
|
def apply[T <: Actor](factory: ⇒ T, name: String)(implicit app: ActorSystem): TestActorRef[T] = apply[T](Props(factory), name)
|
2011-04-27 15:00:41 +02:00
|
|
|
|
2011-11-13 20:38:14 +01:00
|
|
|
def apply[T <: Actor](props: Props)(implicit app: ActorSystem): TestActorRef[T] = apply[T](props, randomName)
|
2011-04-27 15:00:41 +02:00
|
|
|
|
2011-11-16 17:18:36 +01:00
|
|
|
def apply[T <: Actor](props: Props, name: String)(implicit app: ActorSystem): TestActorRef[T] =
|
|
|
|
|
apply[T](props, app.asInstanceOf[ActorSystemImpl].guardian, name)
|
2011-10-18 15:39:26 +02:00
|
|
|
|
2011-11-13 20:38:14 +01:00
|
|
|
def apply[T <: Actor](props: Props, supervisor: ActorRef, name: String)(implicit app: ActorSystem): TestActorRef[T] = {
|
2011-11-16 17:18:36 +01:00
|
|
|
val impl = app.asInstanceOf[ActorSystemImpl]
|
|
|
|
|
new TestActorRef(impl, impl.deadLetterMailbox, app.eventStream, app.scheduler, props, supervisor, name)
|
2011-11-08 11:56:46 +01:00
|
|
|
}
|
2011-08-26 17:25:18 +02:00
|
|
|
|
2011-11-13 20:38:14 +01:00
|
|
|
def apply[T <: Actor](implicit m: Manifest[T], app: ActorSystem): TestActorRef[T] = apply[T](randomName)
|
2011-04-16 22:20:04 +02:00
|
|
|
|
2011-11-10 20:08:00 +01:00
|
|
|
def apply[T <: Actor](name: String)(implicit m: Manifest[T], app: ActorSystem): TestActorRef[T] = apply[T](Props({
|
2011-04-16 22:20:04 +02:00
|
|
|
import ReflectiveAccess.{ createInstance, noParams, noArgs }
|
2011-10-06 21:19:46 +02:00
|
|
|
createInstance[T](m.erasure, noParams, noArgs) match {
|
2011-07-19 19:28:46 +02:00
|
|
|
case Right(value) ⇒ value
|
2011-10-20 23:37:54 +02:00
|
|
|
case Left(exception) ⇒ throw new ActorInitializationException(null,
|
2011-04-16 22:20:04 +02:00
|
|
|
"Could not instantiate Actor" +
|
2011-05-18 17:25:30 +02:00
|
|
|
"\nMake sure Actor is NOT defined inside a class/trait," +
|
|
|
|
|
"\nif so put it outside the class/trait, f.e. in a companion object," +
|
2011-07-19 19:28:46 +02:00
|
|
|
"\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'.", exception)
|
2011-04-29 17:15:00 +02:00
|
|
|
}
|
2011-11-08 14:30:33 +01:00
|
|
|
}), name)
|
2011-04-21 21:31:24 +02:00
|
|
|
}
|