2017-08-03 2 views
1

Ich schreibe einige Java Vertex asynch Code mit Kotlin Korotinen zu Lernzwecken. Wenn ich jedoch versuche, einen einfachen HTTP-Aufruf zu testen, hängt der Coroutine-basierte Test für immer und ich verstehe wirklich nicht, wo das Problem liegt. Hier ein Reproduzierer:Vertex Plus Kotlin Koroutinen hängt für immer

@RunWith(VertxUnitRunner::class) 
class HelloWorldTest { 

    private val vertx: Vertx = Vertx.vertx() 

    @Before 
    fun setUp(context: TestContext) { 
     // HelloWorldVerticle is a simple http server that replies "Hello, World!" to whatever call 
     vertx.deployVerticle(HelloWorldVerticle::class.java!!.getName(), context.asyncAssertSuccess()) 
    } 

    // ORIGINAL ASYNC TEST HERE. IT WORKS AS EXPECTED 
    @Test 
    fun testAsync(context: TestContext) { 
     val atc = context.async() 
     vertx.createHttpClient().getNow(8080, "localhost", "/") { response -> 
      response.handler { body -> 
       context.assertTrue(body.toString().equals("Hello, World!")) 
       atc.complete() 
      } 
     } 
    } 

    // First attempt, it hangs forever, the response is never called 
    @Test 
    fun testSync1(context: TestContext) = runBlocking<Unit> { 
     val atc = context.async() 
     val body = await<HttpClientResponse> { 
      vertx.createHttpClient().getNow(8080, "localhost", "/", { response -> response.handler {it}}) 
     } 
     context.assertTrue(body.toString().equals("Hello, World!")) 
     atc.complete() 
    } 

    // Second attempt, it hangs forever, the response is never called 
    @Test 
    fun testSync2(context: TestContext) = runBlocking<Unit> { 
     val atc = context.async() 
     val response = await<HttpClientResponse> { 
       vertx.createHttpClient().getNow(8080, "localhost", "/", it) 
     } 
     response.handler { body -> 
      context.assertTrue(body.toString().equals("Hello, World!")) 
      atc.complete() 
     } 
    } 

    suspend fun <T> await(callback: (Handler<T>) -> Unit) = 
      suspendCoroutine<T> { cont -> 
       callback(Handler { result: T -> 
        cont.resume(result) 
       }) 
      } 
} 

Ist jeder in der Lage, das Problem herauszufinden?

Antwort

1

Es scheint mir, dass der Code mehrere Probleme:

  1. Sie den Test ausgeführt wird, bevor der http-Server
  2. eingesetzt wurde ich glaube, dass Sie innerhalb runBlocking Ihren Code ausführen, da Sie die Sperrung sind Ereignisschleife vom Ausfüllen der Anfrage.
  3. Schließlich rate ich Ihnen, die HttpClienctResponse::bodyHandler Methode anstelle von HttpClientResponse::handler zu verwenden, da der Handler Teildaten erhalten kann. Hier

ist eine alternative Lösung, die gut funktioniert:

import io.vertx.core.AbstractVerticle 
import io.vertx.core.Future 
import io.vertx.core.Handler 
import io.vertx.core.Vertx 
import io.vertx.core.buffer.Buffer 
import io.vertx.core.http.HttpClientResponse 
import kotlin.coroutines.experimental.Continuation 
import kotlin.coroutines.experimental.EmptyCoroutineContext 
import kotlin.coroutines.experimental.startCoroutine 
import kotlin.coroutines.experimental.suspendCoroutine 

inline suspend fun <T> await(crossinline callback: (Handler<T>) -> Unit) = 
     suspendCoroutine<T> { cont -> 
      callback(Handler { result: T -> 
       cont.resume(result) 
      }) 
     } 

fun <T : Any> async(code: suspend() -> T) = Future.future<T>().apply { 
    code.startCoroutine(object : Continuation<T> { 
     override val context = EmptyCoroutineContext 
     override fun resume(value: T) = complete() 
     override fun resumeWithException(exception: Throwable) = fail(exception) 
    }) 
} 

fun main(args: Array<String>) { 
    async { 
     val vertx: Vertx = Vertx.vertx() 

     //0. take the current context 
     val ctx = vertx.getOrCreateContext() 

     //1. deploy the http server 
     await<Unit> { cont -> 
      vertx.deployVerticle(object : AbstractVerticle() { 
       override fun start() { 
        vertx.createHttpServer() 
          .requestHandler { it.response().end("Hello World") } 
          .listen(7777) { ctx.runOnContext { cont.handle(Unit) } } 
        //note that it is important tp complete the handler in the correct context 
       } 
      }) 
     } 

     //2. send request 
     val response: HttpClientResponse = await { vertx.createHttpClient().getNow(7777, "localhost", "/", it) } 

     //3. await response 
     val body = await<Buffer> { response.bodyHandler(it) } 
     println("received $body") 
    } 
} 
+0

ich Ihre Antwort akzeptiert, weil das Problem in der Tat war in der Ereignisschleife zu blockieren; Ihr Punkt 1 ist jedoch falsch, in der Tat stellt context.asyncAssertSuccess() in der Methode setUp() sicher, dass die Tests nur ausgeführt werden, wenn der Server bereit ist. –

Verwandte Themen