Подтверждение прекращения действия дочернего актера
У меня есть следующая иерархия актеров parent -> child -> worker, где область действия дочернего элемента ограничена до запроса - когда запрос завершен, дочерний субъект должен быть прекращен. Это я хотел проверить как часть теста. Я создал StepParent как для целей тестирования, так как я хочу проверить ответ на данный запрос, который пересылается в msg to testprobe.
class StepParent(child: Props, name: String, probe: ActorRef) extends Actor with ActorLogging {
context.watch(context.actorOf(props = child, name = name))
override def receive: Actor.Receive = {
case msg: PersistImages => context.children.foreach(child => child.tell(msg, sender))
case msg =>
log.debug(s"Msg forwarded to probe $msg")
probe.tell(msg, sender)
}
}
Мой тест выглядит следующим образом:
class ImagesControllerActorTest extends TestKit(ActorSystem("testsystem"))
with WordSpecLike with MustMatchers with StopSystemAfterAll {
val id = "456"
"ControllerActor" must {
"distribute a work to dedicated dedicated workers and combine back results and then terminate" in {
val p = TestProbe()
val ica = system.actorOf(Props(classOf[StepParent], createActorWithMockedWorkers(id, p.ref), "ControllerActor", p.ref), "parent")
p.send(ica, PersistImages(Set(new URL("http://success"), new URL("http://fail"))))
p.expectMsgPF(2 seconds)(validMsgPersistImageActor)
p.expectMsgPF(2 seconds)(validMsgPersistImageActor)
p.expectMsg(2 seconds, ImagesProcessed(id, Set(new URI("file:/"))))
p.expectMsg(4 seconds, Terminated)
}
}
Мой тест не пройден из-за последней проверки ожидаемого сообщения:
assertion failed: timeout (4 seconds) during expectMsg while waiting for Terminated
java.lang.AssertionError: assertion failed: timeout (4 seconds) during expectMsg while waiting for Terminated
at scala.Predef$.assert(Predef.scala:179)
at akka.testkit.TestKitBase$class.expectMsg_internal(TestKit.scala:338)
...
В соответствии с подробным журналом Прекращено сообщение также пересылается (согласно последней строке)
2015-01-11 17:41:10,386 [WARN ] [testsystem-akka.actor.default-dispatcher-5] akka.tcp://testsystem@127.0.0.1:2555/user/parent/ControllerActor - id: 456 image url: http://fail FAILED
2015-01-11 17:41:10,386 [INFO ] [testsystem-akka.actor.default-dispatcher-5] akka.tcp://testsystem@127.0.0.1:2555/user/parent/ControllerActor - id: 456 Processing completed with 1 downloded and 1 failed
2015-01-11 17:41:10,387 [DEBUG] [testsystem-akka.actor.default-dispatcher-4] akka.tcp://testsystem@127.0.0.1:2555/user/parent - Msg forwarded to probe ImagesProcessed(456,Set(file:/))
2015-01-11 17:41:10,392 [DEBUG] [testsystem-akka.actor.default-dispatcher-2] akka://testsystem/user/parent/ControllerActor/$b - stopped
2015-01-11 17:41:10,394 [DEBUG] [testsystem-akka.actor.default-dispatcher-5] akka://testsystem/user/parent/ControllerActor - stopping
2015-01-11 17:41:10,396 [INFO ] [testsystem-akka.actor.default-dispatcher-4] akka://testsystem/user/parent/ControllerActor/$b - Message [akka.dispatch.sysmsg.Terminate] from Actor[akka://testsystem/user/parent/ImagesControllerActor/$b#-426862126] to Actor[akka://testsystem/user/parent/ControllerActor/$b#-426862126] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
2015-01-11 17:41:10,396 [INFO ] [testsystem-akka.actor.default-dispatcher-2] akka://testsystem/user/parent/ControllerActor/$a - Message [akka.dispatch.sysmsg.Terminate] from Actor[akka://testsystem/user/parent/ControllerActor/$a#1067345522] to Actor[akka://testsystem/user/parent/ControllerActor/$a#1067345522] was not delivered. [2] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
2015-01-11 17:41:10,398 [DEBUG] [testsystem-akka.actor.default-dispatcher-2] akka://testsystem/user/parent/ControllerActor - stopped
2015-01-11 17:41:10,399 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka://testsystem/user/parent/ControllerActor/$a - stopped
2015-01-11 17:41:10,399 [DEBUG] [testsystem-akka.actor.default-dispatcher-5] akka://testsystem/user/parent - received AutoReceiveMessage Envelope(Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-770422232]),Actor[akka://testsystem/user/parent/ControllerActor#-770422232])
**2015-01-11 17:41:10,400 [DEBUG] [testsystem-akka.actor.default-dispatcher-5] akka.tcp://testsystem@127.0.0.1:2555/user/parent - Msg forwarded to probe Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-770422232])**
...
Я не очень понимаю, почему последняя проверка ожидаемого сообщения не работает здесь, так как сообщение пересылается как обычно. Есть ли специальная обработка для автоматически полученных сообщений?
Может ли кто-нибудь принести сюда какой-нибудь сарай?
Спасибо
ОБНОВЛЕНИЕ: Попытался решить это как предложено - удалите конверт конверт следующим образом:
class StepParent(child: Props, name: String, probe: ActorRef) extends Actor with ActorLogging {
context.watch(context.actorOf(props = child, name = name))
override def receive: Actor.Receive = {
case msg: PersistImages => context.children.foreach(child => child.tell(msg, sender))
case mssg: Envelope =>
log.debug(s"Envelope msg forwarded to probe $mssg")
probe.tell(mssg.message, sender)
case msg =>
log.debug(s"Msg forwarded to probe $msg")
probe.tell(msg, sender)
}
}
2015-01-11 23:52:16,352 [DEBUG] [testsystem-akka.actor.default-dispatcher-4] akka://testsystem/user/parent/ControllerActor - stopping
2015-01-11 23:52:16,354 [DEBUG] [testsystem-akka.actor.default-dispatcher-4] akka://testsystem/user/parent/ControllerActor - stopped
2015-01-11 23:52:16,358 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka.tcp://testsystem@127.0.0.1:2555/user/parent - Msg forwarded to probe ImagesProcessed(456,Set(file:/))
2015-01-11 23:52:16,358 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka://testsystem/user/parent - received AutoReceiveMessage Envelope(Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-1965336139]),Actor[akka://testsystem/user/parent/ControllerActor#-1965336139])
2015-01-11 23:52:16,360 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka.tcp://testsystem@127.0.0.1:2555/user/parent - Msg forwarded to probe Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-1965336139])
2015-01-11 23:52:16,365 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka://testsystem/system/testActor2 - received AutoReceiveMessage Envelope(Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-1965336139]),Actor[akka://testsystem/user/parent/ControllerActor#-1965336139])
Это все еще терпит неудачу и кажется, что здесь происходит что-то подозрительное:
2015-01-11 23:52:16,360 [DEBUG] [testsystem-akka.actor.default-dispatcher-16] akka.tcp://testsystem@127.0.0.1:2555/user/parent - Msg forwarded to probe Terminated(Actor[akka://testsystem/user/parent/ImagesControllerActor#-1965336139])
Это неверное сообщение от StepParent, но оно каким-то образом извлекается.
3 ответа
К сожалению, ни одно из предложенных решений не сработало, хотя я также был убежден, что они могут работать, и из журнала автоматического приема Прерванное сообщение было передано единственным способом, с помощью которого я получил эту вещь - это своего рода "уродливое" решение, переведенное Прерванное сообщение чему-то другому:
class StepParent(child: Props, name: String, probe: ActorRef) extends Actor with ActorLogging {
context.watch(context.actorOf(props = child, name = name))
override def receive: Actor.Receive = {
case msg: PersistImages => context.children.foreach(child => child.tell(msg, sender))
case msg: Terminated =>
log.debug("Parent: Terminated recieved")
probe.tell("controller terminated",sender)
case msg =>
log.debug(s"Msg forwarded to probe $msg")
probe.tell(msg, sender)
}
}
И логика утверждения прекрасно работает как:
p.expectMsg(4 seconds,"controller terminated")
Не уверен, что происходило, так как кажется, что сообщение Termination msg нельзя просто переслать, даже если оно явно получено.
StepParent
на самом деле получает Envelope
из Terminated
сообщение.
Вы можете увидеть это из журнала:
2015-01-11 17:41:10,399 [DEBUG] [testsystem-akka.actor.default-dispatcher-5] akka://testsystem/user/parent - received AutoReceiveMessage Envelope(Terminated(Actor[akka://testsystem/user/parent/ControllerActor#-770422232]),Actor[akka://testsystem/user/parent/ControllerActor#-770422232])
Тем не менее, Envelope
сообщение будет напечатано в ваших журналах, как если бы оно было Terminated
пока это не так.
Сообщение является Envelope
для того, чтобы содержать метаданные отправителя из автоматически отправленного сообщения, даже если в этом случае Terminated
сообщение уже содержит информацию об отправителе.
Таким образом, для прохождения теста вы можете сделать что-то вроде:
override def receive: Actor.Receive = {
case msg: PersistImages => context.children.foreach(child => child.tell(msg, sender))
case msg: Envelope =>
log.debug(s"Envelope msg forwarded to probe $msg")
probe.tell(msg.message, sender)
case msg =>
log.debug(s"Msg forwarded to probe $msg")
probe.tell(msg, sender)
}
Ваше утверждение о расторжении неверно. Как это в настоящее время закодировано:
p.expectMsg(4 seconds, Terminated)
Вы в основном говорите, что вы ожидаете сообщение, которое является Terminated
введите сам, а не экземпляр Terminated
кейс-класс. Вы должны изменить утверждение на:
p.expectMsg(4 seconds, Terminated(refToBeTerminated))
или еще лучше:
p.expectTerminated(refToBeTerminated, 4 seconds)
где refToBeTerminated
это ActorRef
что вы ожидаете прекращения. Я не уверен, что это ваша единственная проблема, но это проблема наверняка.
РЕДАКТИРОВАТЬ
Конечно, если все, что вас волнует, это то, что у вас есть какие-либо Terminate
тогда у вас есть несколько вариантов, чтобы проверить это. Вы можете попробовать:
p.expectMsgType[Terminated](4 seconds)
или же:
p.expectMsgClass(4 seconds, classOf[Terminated])
или даже:
p.expectMsgPF(4 seconds){case t:Terminated => }