2017-12-04 5 views
0

Ich habe eine einfache Route und einige Tests, die Erfolg einzeln, aber kollektiv scheitern mit Timeout. Irgendeine Idee warum?Warum wird dieser Akka-HTTP-Routentest nie erfolgreich abgeschlossen?

val route = (requestHandler: ActorRef @@ Web) => { 
    get { 
    pathPrefix("apps") { 
     pathEndOrSingleSlash { 
     completeWith(implicitly[ToEntityMarshaller[List[String]]]) { callback => 
      requestHandler ! GetAppsRequest(callback) 
     } 
     } ~ path("stats") { 
     completeWith(implicitly[ToEntityMarshaller[List[Stats]]]) { callback => 
      requestHandler ! GetStatsRequest(callback) 
     } 
     } 
    } ~ path("apps"/Segment/"stats") { app => 
     completeWith(implicitly[ToEntityMarshaller[Stats]]) { callback => 
     requestHandler ! GetStatsForOneRequest(app, callback) 
     } 
    } 
    } 
} 

und Prüfungen:

val testProbe = TestProbe() 
val testProbeActor = testProbe.ref 
    .taggedWith[Web] 

val timeout = 1.minute 

"Route" should "respond to get apps request" in { 
    implicit val routeTestTimout = RouteTestTimeout(timeout.dilated) 
    Get("/apps") ~> route(testProbeActor) ~> check { 

    testProbe.receiveOne(timeout) match { 
     case GetAppsRequest(callback) => { 
     callback(k8SProperties.apps) 
     } 
    } 
    entityAs[List[String]] should contain("test") 
    } 
    testProbe.expectNoMessage(timeout) 
} 

it should "respond to get stats request for all apps" in { 
    implicit val routeTestTimout = RouteTestTimeout(timeout.dilated) 
    val app = "test" 
    Get("/apps/stats") ~> route(testProbeActor) ~> check { 

    testProbe.receiveOne(timeout) match { 
     case GetStatsRequest(callback) => { 
     callback(List(Stats(app, ChronoUnit.SECONDS, Nil))) 
     } 
     case other => fail(s"Unexpected message $other.") 
    } 
    entityAs[List[Stats]].size shouldBe (1) 
    entityAs[List[Stats]].head.app shouldBe (app) 
    } 
    testProbe.expectNoMessage(timeout) 
} 

it should "respond to get stats request for one app" in { 
    implicit val routeTestTimout = RouteTestTimeout(timeout.dilated) 
    val app = "test" 
    Get(s"/apps/$app/stats") ~> route(testProbeActor) ~> check { 

    testProbe.receiveOne(timeout) match { 
     case GetStatsForOneRequest(app, callback) => { 
     callback(Stats(app, ChronoUnit.SECONDS, Nil)) 
     } 
     case other => fail(s"Unexpected message $other.") 
    } 
    entityAs[Stats].app shouldBe (app) 
    } 
    testProbe.expectNoMessage(timeout) 
} 

bearbeiten: https://github.com/akka/akka-http/issues/1615

Antwort

0

Arbeitscode, danke an mich.

"Routes" should "respond to get apps request" in { 
    testProbe.setAutoPilot((_: ActorRef, msg: Any) => { 
    msg match { 
     case GetAppsRequest(callback) => callback(List("test")); TestActor.KeepRunning 
     case _ => TestActor.NoAutoPilot 
    } 
    }) 

    Get("/apps") ~> handler ~> check { 
    entityAs[List[String]] should contain("test") 
    } 
} 

Putting TestProbe innen check für immer wahrscheinlich hängt, weil es eine Sackgasse schafft; test wartet darauf, dass der Callback aufgerufen wird, und Callback wird erst aufgerufen, wenn der Body ausgeführt wird.

Die Verwendung des Autopiloten richtet eine "Erwartung" ein, die später erfüllt werden kann, um den Deadlock zu vermeiden.

2

Das Problem ist, dass Sie eine einzelne TestProbe in allen drei Tests Eröffnet verwenden. Diese TestProbe ist ein einzelner Akteur und empfängt daher Nachrichten von allen drei Tests. Wenn Sie Ihre Testsonden-Erstellung und -Konfiguration einfach in die Testkörper verschieben, sollte es wie erwartet funktionieren. speziell diese zwei Zeilen:

val testProbe = TestProbe() 
val testProbeActor = testProbe.ref 
    .taggedWith[Web] 
+0

Dieser Gedanke kam mir in den Sinn. Ich hatte das schon probiert und es machte keinen Unterschied. Außerdem verwende ich 'TestProbe' in ähnlicher Weise in anderen Tests mit' Actor', bisher keine Probleme. Zu guter Letzt, was denkst du ist das Problem, wenn die "TestProbe" mehrere Nachrichten empfängt? –

+0

Wenn Sie eine TestProbe verwenden, tun Sie (a) etwas und (b) überprüfen, wie die TestProbe reagiert (empfängt eine Nachricht oder nicht, usw.). Wenn Sie denselben TestProbe in verschiedenen Tests verwenden, können Sie beim Überprüfen einer Reaktion nicht feststellen, ob diese Reaktion auf etwas zurückzuführen ist, das Sie im aktuellen Test oder in einem anderen Test durchgeführt haben. Sie können das Problem mindern, indem Sie sicherstellen, dass alle Ihre Tests nacheinander und nicht gleichzeitig ausgeführt werden. Angesichts der Risiken rätselhafter Ergebnisse empfehle ich, die TestProbe innerhalb jedes Tests zu erstellen, es sei denn, es gibt einen wirklich zwingenden Grund, einen Test testweise zu teilen. – jmcnulty

+0

Nicht wirklich. Die Tests verwenden unterschiedliche Anforderungsantworten. Wenn mehrere Tests die gleiche Anfrage-Antwort verwenden, könnte das, was Sie sagen, ein Problem sein. Es hängt vom Anwendungsfall ab, es ist keine Regel. Ich sehe keinen Nutzen darin, den Code überall zu kopieren oder ein Fixture zu verwenden. –

Verwandte Themen