fairjm
fairjm

Reputation: 1187

“Actor not found” on context.actorSelection where actorFor works

The code is:

 //      pilot = Await.result(context.actorSelection(s"../$pilotName").resolveOne, 5.seconds)
         pilot = context.actorFor("../" + pilotName)  

actorFor works fine in application and test.
It's really weird that the code commented works in application but fails with akka.actor.ActorNotFound(the actor it looked for existed and I think the timeout is enough) when running test.

The test is:

class PilotsSpec extends TestKit(ActorSystem("PilotsSpec",
  ConfigFactory.parseString(PilotsSpec.configStr)))
  with ImplicitSender with WordSpecLike with MustMatchers {
  import PilotsSpec._
  import plane.Plane._

  def nilActor: ActorRef = TestProbe().ref

  val pilotPath = s"/user/TestPilots/$pilotName"
  val copilotPath = s"/user/TestPilots/$copilotName"

  def pilotsReadyToGo(): ActorRef = {
    implicit val timeout = Timeout(5.seconds)

    val a = system.actorOf(Props(
      new IsolatedStopSupervisor with OneForOneStrategyFactory {
        def childrenStart() = {
          context.actorOf(Props[FakePilot], pilotName)
          context.actorOf(Props(new CoPilot(testActor, nilActor, nilActor)), copilotName)
        }
      }), "TestPilots")
    Await.result(a ? IsolatedLifeCycleSupervisor.WaitForStart, 5.seconds)
    system.actorFor(copilotPath) ! Pilots.ReadyToGo
    a
  }

  "CoPilot" should {
    "takecontrol when the Pilotdies" in {
      pilotsReadyToGo()
      // Kill the Pilot
      system.actorFor(pilotPath) ! PoisonPill
      // Sincethe test classis the "Plane" we can
      // expect to see this request
      expectMsg(GiveMeControl)
      // The girl who sent it had better be Mary
      lastSender must be (system.actorFor(copilotPath))
    }
  }

}

I don't know if I do something wrong with ActorSelection.
I try to use onComplete but it still doesn't work and throws ActorNotFound exception in test.

  val f = context.actorSelection("../" + pilotName).resolveOne
  f onComplete {
    case Success(v) => { pilot = v; context.watch(pilot); println("pilot get") }
    case Failure(e) => throw e
  }

Is there anyone who knows the reason why actorFor works but actorSelection fails(in test exactly)?

Then I add the code below to the test code:

system.actorSelection(pilotPath).resolveOne map {v => println("------pilot:"+v)}
system.actorSelection(copilotPath).resolveOne map {v => println("------copilot:"+v)}
Thread.sleep(1000)   

It works and prints these actorRef Then I try to replace ../+pilotName with constant string pilotPath but it fails again(no matter context.actorSelection or context.system.actorSelection)
Here is the exception(a fragment):

test-only cc.akka.avionics.PilotsSpec
[info] Compiling 1 Scala source to G:\scala_workspace\akka_test_u7\target\scala-2.10\test-classes...
[warn] there were 2 deprecation warning(s); re-run with -deprecation for details
[warn] one warning found
------copilot:Actor[akka://PilotsSpec/user/TestPilots/Mary#962346268]
------pilot:Actor[akka://PilotsSpec/user/TestPilots/Mark#-320295209]
ActorSelection[Anchor(akka://PilotsSpec/user/TestPilots/Mary#962346268), Path(/../Mark)]
[ERROR] [04/29/2014 15:13:16.080] [PilotsSpec-akka.actor.default-dispatcher-4] [akka.dispatch.Dispatcher] Actor not found for: ActorSelection[Ancho r(akka://PilotsSpec/user/TestPilots/Mary#962346268), Path(/../Mark)]
akka.actor.ActorNotFound: Actor not found for: ActorSelection[Anchor(akka://PilotsSpec/user/TestPilots/Mary#962346268), Path(/../Mark)]
at akka.actor.ActorSelection$$anonfun$resolveOne$1.apply(ActorSelection.scala:65)
at akka.actor.ActorSelection$$anonfun$resolveOne$1.apply(ActorSelection.scala:63)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.processBatch$1(BatchingExecutor.scala:67)
at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply$mcV$sp(BatchingExecutor.scala:82)
at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72)
at akka.dispatch.BatchingExecutor$Batch.run(BatchingExecutor.scala:58)
at akka.dispatch.ExecutionContexts$sameThreadExecutionContext$.unbatchedExecute(Future.scala:74)
at akka.dispatch.BatchingExecutor$class.execute(BatchingExecutor.scala:110)

Only actorFor works in test the other codes commented using actorSelection works in application but fails in test(so strange):

class CoPilot(plane: ActorRef,
  var controls: ActorRef,
  altimeter: ActorRef) extends Actor {
  implicit val timeout = Timeout(1.second)
  implicit val ct = context.dispatcher
  var pilot: ActorRef = context.system.deadLetters
  val pilotName: String = context.system.settings.config.getString("cc.akka.avionics.flightcrew.pilotName")
  val pilotId : Int = 200

  def receive = {
    case ReadyToGo =>
//      fails in test
//      pilot = Await.result(context.actorSelection(s"../$pilotName").resolveOne, 3.seconds)
//      println("get pilot:" + pilot.path + " dead:" + pilot.isTerminated)

//      actorFor works
//      pilot = context.actorFor("../" + pilotName) 
//      context.watch(pilot)
//      autopilot = Await.result(context.actorSelection("../AutoPilot").resolveOne, 100.millis)

//      fails in test
//      val f = context.actorSelection("../" + pilotName).resolveOne  
//      f onComplete {
//        case Success(v) => { pilot = v; context.watch(pilot); println("pilot get") }
//        case Failure(e) => throw e
//      }
        println("-----------"+pilotName)

        // fails in test
        context.actorSelection("../" + pilotName) ! Identify(pilotId) 

    case Terminated(_) =>
      plane ! GiveMeControl
    case Controls(controlSurfaces) =>
      controls = controlSurfaces

    case ActorIdentity(pilotId, Some(ref)) =>
      pilot = ref
      context.watch(pilot)
      println("find copilot:"+pilot)
    case ActorIdentity(pilotId, None) => 
      println("failed to find pilot")
  }
}

Upvotes: 3

Views: 1700

Answers (1)

Andrew Norman
Andrew Norman

Reputation: 911

actorFor creates new Actors whereas actorSelection finds actors that already exist.

I suspect the reason that your actorSelection isn't working and your actorFor does work is because the actor isn't currently in existence.

Upvotes: 0

Related Questions