pekko/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala
Roland f46c6dc533 introducing: MainBus feat. LoggingBus
most tests passing, everything compiling, but docs not updated and nasty
thread-leak preventing me from running the whole test-suite (which is
the reason for this commit: I want to chase down that one first).

- the app.mainbus is classified by Class[_] (currently lookup, will
  possibly change to sub-class-aware) and accepts AnyRef messages
- LoggingBus handles akka.event-handlers from config specially:
  + start them as system services, supervised by SystemGuardian
  + keep their subscriptions in sync when logLevel_= is called
  + send them InitializeLogger(bus) message before subscribing them (so
    they can register for extras like Mute/UnMute)
- two-phased start-up: first phase with actor-less stdout logging, then
  subscription of config loggers, then remove stdout logger (logLevels
  configurable separately)
- MainBusReaper watches registered receivers and unsubscribes them upon
  death (started in phase 2)
- logger factory on Logging object, needs app/bus and log source;
  default instance in app.log
2011-10-27 12:36:22 +02:00

68 lines
3.2 KiB
Scala

/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.testkit
import akka.actor._
import akka.util.ReflectiveAccess
import com.eaio.uuid.UUID
import akka.actor.Props._
import akka.AkkaApplication
/**
* 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](_app: AkkaApplication, _props: Props, _supervisor: ActorRef, address: String)
extends LocalActorRef(_app, _props.withDispatcher(new CallingThreadDispatcher(_app)), _supervisor, address, false) {
/**
* 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.
*/
def apply(o: Any) { underlyingActorInstance.apply(o) }
/**
* 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 = underlyingActorInstance.asInstanceOf[T]
override def toString = "TestActor[" + address + ":" + uuid + "]"
override def equals(other: Any) = other.isInstanceOf[TestActorRef[_]] && other.asInstanceOf[TestActorRef[_]].uuid == uuid
}
object TestActorRef {
def apply[T <: Actor](factory: T)(implicit app: AkkaApplication): TestActorRef[T] = apply[T](Props(factory), Props.randomAddress)
def apply[T <: Actor](factory: T, address: String)(implicit app: AkkaApplication): TestActorRef[T] = apply[T](Props(factory), address)
def apply[T <: Actor](props: Props)(implicit app: AkkaApplication): TestActorRef[T] = apply[T](props, Props.randomAddress)
def apply[T <: Actor](props: Props, address: String)(implicit app: AkkaApplication): TestActorRef[T] = apply[T](props, app.guardian, address)
def apply[T <: Actor](props: Props, supervisor: ActorRef, address: String)(implicit app: AkkaApplication): TestActorRef[T] =
new TestActorRef(app, props, supervisor, address)
def apply[T <: Actor](implicit m: Manifest[T], app: AkkaApplication): TestActorRef[T] = apply[T](Props.randomAddress)
def apply[T <: Actor](address: String)(implicit m: Manifest[T], app: AkkaApplication): TestActorRef[T] = apply[T](Props({
import ReflectiveAccess.{ createInstance, noParams, noArgs }
createInstance[T](m.erasure, noParams, noArgs) match {
case Right(value) value
case Left(exception) throw new ActorInitializationException(null,
"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)'.", exception)
}
}), address)
}