Vertx plus Kotlin coroutines вечно вешает

Я переписываю некоторый асинхронный код Java Vertx, используя Kotlin coroutines для обучения. Тем не менее, когда я пытаюсь протестировать простой HTTP-вызов, тест на основе coroutine вешает навсегда, и я действительно не понимаю, в чем проблема. Здесь воспроизводится:

@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) }) } } 

Каждый может понять проблему?

Мне кажется, что ваш код имеет несколько проблем:

  1. вы можете запустить тест до того, как HTTP-сервер будет развернут
  2. Я считаю, что, поскольку вы выполняете свой код внутри runBlocking вы блокируете цикл событий от завершения запроса.
  3. Наконец, я советую вам использовать метод HttpClienctResponse::bodyHandler вместо HttpClientResponse::handler поскольку обработчик может получать частичные данные.

Вот альтернативное решение, которое отлично работает:

 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") } } 
Intereting Posts
Преобразует ли файл Kotlin в java, добавив к нему java-код и вернувшись обратно в Kotlin так же, как добавление кода непосредственно в файл Kotlin? Как отклонить диалоговое окно предупреждения Android через setOnEditorActionListener? filterNotNull в списке Kotlin с общим типом Как создать экземпляр объекта с использованием значений параметров конструктора по умолчанию в Kotlin? Обработчик ссылки Clickable в TextView Не может быть предоставлен без @ Предоставляет-аннотированный метод Kotlin smart cast не работает для LinearLayout.LayoutParams Использовать метод / свойство расширения по всему миру Как установить ширину границы FloatingActionButton с Anko Если hashCode () возвращает уникальный идентификатор объекта Исключение UninferredParameterTypeConstructor во время сборки, когда общие параметры не указаны явно Параметр «Контроллер весны» не изменяется с параметром Как удалить размытие из корневого представления в android Mockito Mocks ведет себя как шпионы: Котлин можно ли добавить шаблон в getter / setter класса данных?