71 lines
2.5 KiB
Scala
71 lines
2.5 KiB
Scala
|
|
package akka.testkit
|
||
|
|
|
||
|
|
import akka.actor._
|
||
|
|
import akka.util.ReflectiveAccess
|
||
|
|
import akka.event.EventHandler
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 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
|
||
|
|
*/
|
||
|
|
class TestActorRef[T <: Actor](factory: () => T) extends LocalActorRef(factory, None) {
|
||
|
|
|
||
|
|
dispatcher = CallingThreadDispatcher.global
|
||
|
|
receiveTimeout = None
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 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.
|
||
|
|
*/
|
||
|
|
def underlyingActor : T = actor.asInstanceOf[T]
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Override to return the more specific static type.
|
||
|
|
*/
|
||
|
|
override def start() = {
|
||
|
|
super.start()
|
||
|
|
this
|
||
|
|
}
|
||
|
|
|
||
|
|
override def toString = "TestActor[" + id + ":" + uuid + "]"
|
||
|
|
|
||
|
|
override def equals(other : Any) =
|
||
|
|
other.isInstanceOf[TestActorRef[_]] &&
|
||
|
|
other.asInstanceOf[TestActorRef[_]].uuid == uuid
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Override to check whether the new supervisor is running on the CallingThreadDispatcher,
|
||
|
|
* as it should be. This can of course be tricked by linking before setting the dispatcher before starting the
|
||
|
|
* supervisor, but then you just asked for trouble.
|
||
|
|
*/
|
||
|
|
override def supervisor_=(a : Option[ActorRef]) {
|
||
|
|
for (ref <- a) {
|
||
|
|
if (!ref.dispatcher.isInstanceOf[CallingThreadDispatcher])
|
||
|
|
EventHandler.warning(this, "supervisor "+ref+" does not use CallingThreadDispatcher")
|
||
|
|
}
|
||
|
|
super.supervisor_=(a)
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
object TestActorRef {
|
||
|
|
|
||
|
|
def apply[T <: Actor](factory: => T) = new TestActorRef(() => factory)
|
||
|
|
|
||
|
|
def apply[T <: Actor : Manifest] : TestActorRef[T] = new TestActorRef[T] ({ () =>
|
||
|
|
import ReflectiveAccess.{ createInstance, noParams, noArgs }
|
||
|
|
createInstance[T](manifest[T].erasure, noParams, noArgs).getOrElse(
|
||
|
|
throw new ActorInitializationException(
|
||
|
|
"Could not instantiate Actor" +
|
||
|
|
"\nMake sure Actor is NOT defined inside a class/trait," +
|
||
|
|
"\nif so put it outside the class/trait, f.e. in a companion object," +
|
||
|
|
"\nOR try to change: 'actorOf[MyActor]' to 'actorOf(new MyActor)'."))
|
||
|
|
})
|
||
|
|
|
||
|
|
}
|