Merge pull request #16690 from kosii/16536-ask-with-actorselection-kosii
=act #16536 actor selection now completes ask
This commit is contained in:
commit
064eea6180
2 changed files with 121 additions and 1 deletions
|
|
@ -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])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue