|
Akka/Scala example source code file (ActorSelectionSpec.scala)
The ActorSelectionSpec.scala Akka example source code/** * Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com> */ package akka.actor import language.postfixOps import akka.testkit._ import scala.concurrent.duration._ import scala.concurrent.Await import akka.pattern.ask object ActorSelectionSpec { final case class Create(child: String) trait Query final case class SelectString(path: String) extends Query final case class SelectPath(path: ActorPath) extends Query final case class GetSender(to: ActorRef) extends Query final case class Forward(path: String, msg: Any) extends Query val p = Props[Node] class Node extends Actor { def receive = { case Create(name) ⇒ sender() ! context.actorOf(p, name) case SelectString(path) ⇒ sender() ! context.actorSelection(path) case SelectPath(path) ⇒ sender() ! context.actorSelection(path) case GetSender(ref) ⇒ ref ! sender() case Forward(path, msg) ⇒ context.actorSelection(path).forward(msg) case msg ⇒ sender() ! msg } } } @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) class ActorSelectionSpec extends AkkaSpec("akka.loglevel=DEBUG") with DefaultTimeout { import ActorSelectionSpec._ val c1 = system.actorOf(p, "c1") val c2 = system.actorOf(p, "c2") val c21 = Await.result((c2 ? Create("c21")).mapTo[ActorRef], timeout.duration) val sysImpl = system.asInstanceOf[ActorSystemImpl] val user = sysImpl.guardian val syst = sysImpl.systemGuardian val root = sysImpl.lookupRoot def empty(path: String) = new EmptyLocalActorRef(sysImpl.provider, path match { case RelativeActorPath(elems) ⇒ sysImpl.lookupRoot.path / elems }, system.eventStream) val idProbe = TestProbe() def identify(selection: ActorSelection): Option[ActorRef] = { selection.tell(Identify(selection), idProbe.ref) val result = idProbe.expectMsgPF() { case ActorIdentity(`selection`, ref) ⇒ ref } val asked = Await.result((selection ? Identify(selection)).mapTo[ActorIdentity], timeout.duration) asked.ref should be(result) asked.correlationId should be(selection) implicit val ec = system.dispatcher val resolved = Await.result(selection.resolveOne(timeout.duration).mapTo[ActorRef] recover { case _ ⇒ null }, timeout.duration) Option(resolved) should be(result) result } def identify(path: String): Option[ActorRef] = identify(system.actorSelection(path)) def identify(path: ActorPath): Option[ActorRef] = identify(system.actorSelection(path)) def askNode(node: ActorRef, query: Query): Option[ActorRef] = { Await.result(node ? query, timeout.duration) match { case ref: ActorRef ⇒ Some(ref) case selection: ActorSelection ⇒ identify(selection) } } "An ActorSystem" must { "select actors by their path" in { identify(c1.path) should be(Some(c1)) identify(c2.path) should be(Some(c2)) identify(c21.path) should be(Some(c21)) identify(system / "c1") should be(Some(c1)) identify(system / "c2") should be(Some(c2)) identify(system / "c2" / "c21") should be(Some(c21)) identify(system child "c2" child "c21") should be(Some(c21)) // test Java API identify(system / Seq("c2", "c21")) should be(Some(c21)) import scala.collection.JavaConverters._ identify(system descendant Seq("c2", "c21").asJava) // test Java API } "select actors by their string path representation" in { identify(c1.path.toString) should be(Some(c1)) identify(c2.path.toString) should be(Some(c2)) identify(c21.path.toString) should be(Some(c21)) identify(c1.path.toStringWithoutAddress) should be(Some(c1)) identify(c2.path.toStringWithoutAddress) should be(Some(c2)) identify(c21.path.toStringWithoutAddress) should be(Some(c21)) } "take actor incarnation into account when comparing actor references" in { val name = "abcdefg" val a1 = system.actorOf(p, name) watch(a1) a1 ! PoisonPill expectMsgType[Terminated].actor should be(a1) // not equal because it's terminated identify(a1.path) should be(None) val a2 = system.actorOf(p, name) a2.path should be(a1.path) a2.path.toString should be(a1.path.toString) a2 should not be (a1) a2.toString should not be (a1.toString) watch(a2) a2 ! PoisonPill expectMsgType[Terminated].actor should be(a2) } "select actors by their root-anchored relative path" in { identify(c1.path.toStringWithoutAddress) should be(Some(c1)) identify(c2.path.toStringWithoutAddress) should be(Some(c2)) identify(c21.path.toStringWithoutAddress) should be(Some(c21)) } "select actors by their relative path" in { identify(c1.path.elements.mkString("/")) should be(Some(c1)) identify(c2.path.elements.mkString("/")) should be(Some(c2)) identify(c21.path.elements.mkString("/")) should be(Some(c21)) } "select system-generated actors" in { identify("/user") should be(Some(user)) identify("/system") should be(Some(syst)) identify(syst.path) should be(Some(syst)) identify(syst.path.toStringWithoutAddress) should be(Some(syst)) identify("/") should be(Some(root)) identify("") should be(Some(root)) identify(RootActorPath(root.path.address)) should be(Some(root)) identify("..") should be(Some(root)) identify(root.path) should be(Some(root)) identify(root.path.toStringWithoutAddress) should be(Some(root)) identify("user") should be(Some(user)) identify("system") should be(Some(syst)) identify("user/") should be(Some(user)) identify("system/") should be(Some(syst)) } "return ActorIdentity(None), respectively, for non-existing paths, and deadLetters" in { identify("a/b/c") should be(None) identify("a/b/c") should be(None) identify("akka://all-systems/Nobody") should be(None) identify("akka://all-systems/user") should be(None) identify(system / "hallo") should be(None) identify("foo://user") should be(None) identify("/deadLetters") should be(None) identify("deadLetters") should be(None) identify("deadLetters/") should be(None) } } "An ActorContext" must { val all = Seq(c1, c2, c21) "select actors by their path" in { def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) { askNode(looker, SelectPath(pathOf.path)) should be(Some(result)) } for { looker ← all target ← all } check(looker, target, target) } "select actors by their string path representation" in { def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) { askNode(looker, SelectString(pathOf.path.toStringWithoutAddress)) should be(Some(result)) // with trailing / askNode(looker, SelectString(pathOf.path.toStringWithoutAddress + "/")) should be(Some(result)) } for { looker ← all target ← all } check(looker, target, target) } "select actors by their root-anchored relative path" in { def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) { askNode(looker, SelectString(pathOf.path.toStringWithoutAddress)) should be(Some(result)) askNode(looker, SelectString(pathOf.path.elements.mkString("/", "/", "/"))) should be(Some(result)) } for { looker ← all target ← all } check(looker, target, target) } "select actors by their relative path" in { def check(looker: ActorRef, result: ActorRef, elems: String*) { askNode(looker, SelectString(elems mkString "/")) should be(Some(result)) askNode(looker, SelectString(elems mkString ("", "/", "/"))) should be(Some(result)) } check(c1, user, "..") for { looker ← Seq(c1, c2) target ← all } check(looker, target, Seq("..") ++ target.path.elements.drop(1): _*) check(c21, user, "..", "..") check(c21, root, "..", "..", "..") check(c21, root, "..", "..", "..", "..") } "find system-generated actors" in { def check(target: ActorRef) { for (looker ← all) { askNode(looker, SelectPath(target.path)) should be(Some(target)) askNode(looker, SelectString(target.path.toString)) should be(Some(target)) askNode(looker, SelectString(target.path.toString + "/")) should be(Some(target)) } if (target != root) askNode(c1, SelectString("../.." + target.path.elements.mkString("/", "/", "/"))) should be(Some(target)) } for (target ← Seq(root, syst, user)) check(target) } "return deadLetters or ActorIdentity(None), respectively, for non-existing paths" in { import scala.collection.JavaConverters._ def checkOne(looker: ActorRef, query: Query, result: Option[ActorRef]) { val lookup = askNode(looker, query) lookup should be(result) } def check(looker: ActorRef) { val lookname = looker.path.elements.mkString("", "/", "/") for ( (l, r) ← Seq( SelectString("a/b/c") -> None, SelectString("akka://all-systems/Nobody") -> None, SelectPath(system / "hallo") -> None, SelectPath(looker.path child "hallo") -> None, // test Java API SelectPath(looker.path descendant Seq("a", "b").asJava) -> None) // test Java API ) checkOne(looker, l, r) } for (looker ← all) check(looker) } } "An ActorSelection" must { "send messages directly" in { ActorSelection(c1, "") ! GetSender(testActor) expectMsg(system.deadLetters) lastSender should be(c1) } "send messages to string path" in { system.actorSelection("/user/c2/c21") ! GetSender(testActor) expectMsg(system.deadLetters) lastSender should be(c21) } "send messages to actor path" in { system.actorSelection(system / "c2" / "c21") ! GetSender(testActor) expectMsg(system.deadLetters) lastSender should be(c21) } "send messages with correct sender" in { implicit val sender = c1 ActorSelection(c21, "../../*") ! GetSender(testActor) val actors = Set() ++ receiveWhile(messages = 2) { case `c1` ⇒ lastSender } actors should be(Set(c1, c2)) expectNoMsg(1 second) } "drop messages which cannot be delivered" in { implicit val sender = c2 ActorSelection(c21, "../../*/c21") ! GetSender(testActor) val actors = receiveWhile(messages = 2) { case `c2` ⇒ lastSender } actors should be(Seq(c21)) expectNoMsg(1 second) } "resolve one actor with explicit timeout" in { val s = system.actorSelection(system / "c2") // Java and Scala API Await.result(s.resolveOne(1.second.dilated), timeout.duration) should be(c2) } "resolve one actor with implicit timeout" in { val s = system.actorSelection(system / "c2") // Scala API; implicit timeout from DefaultTimeout trait Await.result(s.resolveOne(), timeout.duration) should be(c2) } "resolve non-existing with Failure" in { intercept[ActorNotFound] { Await.result(system.actorSelection(system / "none").resolveOne(1.second.dilated), timeout.duration) } } "compare equally" in { ActorSelection(c21, "../*/hello") should be(ActorSelection(c21, "../*/hello")) ActorSelection(c21, "../*/hello").## should be(ActorSelection(c21, "../*/hello").##) ActorSelection(c2, "../*/hello") should not be ActorSelection(c21, "../*/hello") ActorSelection(c2, "../*/hello").## should not be ActorSelection(c21, "../*/hello").## ActorSelection(c21, "../*/hell") should not be ActorSelection(c21, "../*/hello") ActorSelection(c21, "../*/hell").## should not be ActorSelection(c21, "../*/hello").## } "print nicely" in { ActorSelection(c21, "../*/hello").toString should be( s"ActorSelection[Anchor(akka://ActorSelectionSpec/user/c2/c21#${c21.path.uid}), Path(/../*/hello)]") } "have a stringly serializable path" in { system.actorSelection(system / "c2").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2") system.actorSelection(system / "c2" / "c21").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/c21") ActorSelection(c2, "/").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2") ActorSelection(c2, "../*/hello").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/../*/hello") ActorSelection(c2, "/../*/hello").toSerializationFormat should be("akka://ActorSelectionSpec/user/c2/../*/hello") } "send ActorSelection targeted to missing actor to deadLetters" in { val p = TestProbe() system.eventStream.subscribe(p.ref, classOf[DeadLetter]) system.actorSelection("/user/missing").tell("boom", testActor) val d = p.expectMsgType[DeadLetter] d.message should be("boom") d.sender should be(testActor) d.recipient.path.toStringWithoutAddress should be("/user/missing") } "identify actors with wildcard selection correctly" in { val creator = TestProbe() implicit def self = creator.ref val top = system.actorOf(p, "a") val b1 = Await.result((top ? Create("b1")).mapTo[ActorRef], timeout.duration) val b2 = Await.result((top ? Create("b2")).mapTo[ActorRef], timeout.duration) val c = Await.result((b2 ? Create("c")).mapTo[ActorRef], timeout.duration) val d = Await.result((c ? Create("d")).mapTo[ActorRef], timeout.duration) val probe = TestProbe() system.actorSelection("/user/a/*").tell(Identify(1), probe.ref) probe.receiveN(2).map { case ActorIdentity(1, r) ⇒ r }.toSet should be(Set(Some(b1), Some(b2))) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/b1/*").tell(Identify(2), probe.ref) probe.expectMsg(ActorIdentity(2, None)) system.actorSelection("/user/a/*/c").tell(Identify(3), probe.ref) probe.expectMsg(ActorIdentity(3, Some(c))) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/b2/*/d").tell(Identify(4), probe.ref) probe.expectMsg(ActorIdentity(4, Some(d))) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/*/*/d").tell(Identify(5), probe.ref) probe.expectMsg(ActorIdentity(5, Some(d))) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/*/c/*").tell(Identify(6), probe.ref) probe.expectMsg(ActorIdentity(6, Some(d))) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/b2/*/d/e").tell(Identify(7), probe.ref) probe.expectMsg(ActorIdentity(7, None)) probe.expectNoMsg(200.millis) system.actorSelection("/user/a/*/c/d/e").tell(Identify(8), probe.ref) probe.expectNoMsg(500.millis) } "forward to selection" in { c2.tell(Forward("c21", "hello"), testActor) expectMsg("hello") lastSender should be(c21) } } } Other Akka source code examplesHere is a short list of links related to this Akka ActorSelectionSpec.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.