Merge pull request #16690 from kosii/16536-ask-with-actorselection-kosii

=act #16536 actor selection now completes ask
This commit is contained in:
Björn Antonsson 2015-03-04 21:07:20 +01:00
commit 064eea6180
2 changed files with 121 additions and 1 deletions

View file

@ -6,7 +6,7 @@ package akka.pattern
import language.postfixOps
import akka.actor._
import akka.testkit.AkkaSpec
import akka.testkit.{ TestProbe, AkkaSpec }
import akka.util.Timeout
import scala.concurrent.Await
import scala.concurrent.duration._
@ -111,6 +111,94 @@ class AskSpec extends AkkaSpec {
Await.result(identityFuture, 5 seconds) should be(echo)
}
"work when reply uses actor selection" in {
implicit val timeout = Timeout(0.5 seconds)
val deadListener = TestProbe()
system.eventStream.subscribe(deadListener.ref, classOf[DeadLetter])
val echo = system.actorOf(Props(new Actor { def receive = { case x context.actorSelection(sender().path) ! x } }), "select-echo2")
val f = echo ? "hi"
Await.result(f, 1 seconds) should be("hi")
deadListener.expectNoMsg(200 milliseconds)
}
"throw AskTimeoutException on using *" in {
implicit val timeout = Timeout(0.5 seconds)
val deadListener = TestProbe()
system.eventStream.subscribe(deadListener.ref, classOf[DeadLetter])
val echo = system.actorOf(Props(new Actor { def receive = { case x context.actorSelection("/temp/*") ! x } }), "select-echo3")
val f = echo ? "hi"
intercept[AskTimeoutException] {
Await.result(f, 1 seconds)
}
deadListener.expectMsgClass(200 milliseconds, classOf[DeadLetter])
}
"throw AskTimeoutException on using .." in {
implicit val timeout = Timeout(0.5 seconds)
val deadListener = TestProbe()
system.eventStream.subscribe(deadListener.ref, classOf[DeadLetter])
val echo = system.actorOf(Props(new Actor {
def receive = {
case x
val name = sender.path.name
val parent = sender.path.parent
context.actorSelection(parent / ".." / "temp" / name) ! x
}
}), "select-echo4")
val f = echo ? "hi"
intercept[AskTimeoutException] {
Await.result(f, 1 seconds) should be("hi")
}
deadListener.expectMsgClass(200 milliseconds, classOf[DeadLetter])
}
"send to DeadLetter when child does not exist" in {
implicit val timeout = Timeout(0.5 seconds)
val deadListener = TestProbe()
system.eventStream.subscribe(deadListener.ref, classOf[DeadLetter])
val echo = system.actorOf(Props(new Actor {
def receive = {
case x
val name = sender.path.name
val parent = sender.path.parent
context.actorSelection(parent / "missing") ! x
}
}), "select-echo5")
val f = echo ? "hi"
intercept[AskTimeoutException] {
Await.result(f, 1 seconds) should be("hi")
}
deadListener.expectMsgClass(200 milliseconds, classOf[DeadLetter])
}
"send DeadLetter when answering to grandchild" in {
implicit val timeout = Timeout(0.5 seconds)
val deadListener = TestProbe()
system.eventStream.subscribe(deadListener.ref, classOf[DeadLetter])
val echo = system.actorOf(Props(new Actor {
def receive = {
case x
val name = sender.path.name
val parent = sender.path.parent
context.actorSelection(sender().path / "missing") ! x
}
}), "select-echo6")
val f = echo ? "hi"
intercept[AskTimeoutException] {
Await.result(f, 1 seconds) should be(ActorSelectionMessage("hi", Vector(SelectChildName("missing")), false))
}
deadListener.expectMsgClass(200 milliseconds, classOf[DeadLetter])
}
}
}

View file

@ -599,6 +599,38 @@ private[akka] class VirtualPathContainer(
private val children = new ConcurrentHashMap[String, InternalActorRef]
/**
* In [[ActorSelectionMessage]]s only [[SelectChildName]] elements
* are supported, otherwise messages are sent to [[EmptyLocalActorRef]].
*/
override def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit = message match {
case sel @ ActorSelectionMessage(msg, elements, wildcardFanOut) {
require(elements.nonEmpty)
def emptyRef = new EmptyLocalActorRef(provider, path / sel.elements.map(_.toString),
provider.systemGuardian.underlying.system.eventStream)
elements.head match {
case SelectChildName(name)
getChild(name) match {
case null
if (!wildcardFanOut)
emptyRef.tell(msg, sender)
case child
if (elements.tail.isEmpty) {
child ! msg
} else if (!wildcardFanOut) {
emptyRef.tell(msg, sender)
}
}
case _
if (!wildcardFanOut)
emptyRef.tell(msg, sender)
}
}
case _ super.!(message)
}
def addChild(name: String, ref: InternalActorRef): Unit = {
children.put(name, ref) match {
case null // okay