Возможно ли, чтобы тестовое сообщение, отправленное на TestProbe, прибыло до `TestActor.SetAutoPilot (pilot)` - PullRequest
0 голосов
/ 26 октября 2018

Akka Testkit AutoPilot документация примеры показывают, что мы можем отправлять сообщения на TestProbe сразу после вызова setAutoPilot:

  probe.setAutoPilot(new TestActor.AutoPilot {
    def run(sender: ActorRef, msg: Any): TestActor.AutoPilot =
      msg match {
        case "stop" ⇒ TestActor.NoAutoPilot
        case x      ⇒ testActor.tell(x, sender); TestActor.KeepRunning
      }
  })
  //#autopilot
  probe.ref ! "hallo"

С другой стороны, setAutoPilot был реализован как отправка сообщения на testActor:

def setAutoPilot(pilot: TestActor.AutoPilot): Unit = testActor ! TestActor.SetAutoPilot(pilot)

Согласно Гарантии порядка получения сообщений Akka , testActor (probe.ref) не может получить "hallo" до TestActor.SetAutoPilot(pilot), поскольку оба отправляются из одного источника.

Однако, если мы использовали третьего актера (созданного с использованием system.actorOf(...)), чтобы отправить "hello" на probe.ref,

не было бы возможно, чтобы при некоторых обстоятельствах он был получен probe.ref до TestActor.SetAutoPilot(pilot), что в итоге было проигнорировано?

1 Ответ

0 голосов
/ 27 октября 2018

В теории - да, определенно - и это в основном ваш собственный ответ на вопрос. На практике это маловероятно, поскольку другое сообщение проходит более длинный путь, поэтому должно произойти что-то очень необычное, чтобы оно пришло раньше.

Поскольку теоретизирование вокруг этого не даст никакого действенного ответа, я написал тест для эмпирического наблюдения:

Build.sbt:

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor" % "2.5.17"
)

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-testkit" % "2.5.17",
  "org.scalactic" %% "scalactic" % "3.0.5",
  "org.scalatest" %% "scalatest" % "3.0.5",
  "org.scalacheck" %% "scalacheck" % "1.14.0"
) map (_ % "test")

Тест:

import scala.concurrent.duration.DurationInt

import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.pattern.ask
import akka.testkit.{TestActor, TestKit, TestProbe}
import akka.util.Timeout
import org.scalatest.{Matchers, PropSpecLike}
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.prop.PropertyChecks

class AutopilotTest extends TestKit(ActorSystem("test"))
  with PropSpecLike with PropertyChecks with ScalaFutures with Matchers {

  private implicit val askTimeout: Timeout = Timeout(100.millis)

  property("Test probe receives autopilot before any other message from same origin") {
    forAll(minSuccessful(1000)) { msg: String =>
      val probe = TestProbe()
      probe.setAutoPilot((sender: ActorRef, msg: Any) => msg match {
        case x => sender ! x; TestActor.KeepRunning
      })
      whenReady((probe.ref ? msg).mapTo[String]) {_ shouldBe msg}
    }
  }

  private class ProxyActor(target: ActorRef) extends Actor {
    override def receive: Receive = { case msg: Any => target forward msg }
  }
  private object ProxyActor { def props(target: ActorRef): Props = Props(new ProxyActor(target)) }

  property("Test probe receives autopilot before any other message from other origin") {
    // set minSuccessuful to as high as you want, but note that current version takes ~38 seconds on my laptop to run
    forAll(minSuccessful(1000)) { msg: String =>
      val probe = TestProbe()
      val proxy = system.actorOf(ProxyActor.props(probe.ref))
      val result = (proxy ? msg).mapTo[String]
      probe.setAutoPilot((sender: ActorRef, msg: Any) => msg match {
        case x => sender ! x; TestActor.KeepRunning
      })
      whenReady(result) {_ shouldBe msg}
    }
  }
}

Практически, я прошел весь путь до 10000 повторов для второго теста, и тесты всегда проходили - также я удостоверился, что он потерпит неудачу, если автопилот установлен после отправки сообщения на прокси, или если testProbe не отвечает .

Итак, я бы сказал, что потенциальная проблема, которую вы описываете, либо вообще не возникает, либо крайне маловероятна. Этот тест, конечно, очень упрощенный, поэтому в других условиях (например, блокировка, параллельное выполнение теста, CI и т. Д.) Наблюдения могут отличаться, но, по крайней мере, он предоставляет некоторые доказательства для наиболее распространенного / простого случая.

...