Модульное тестирование декоратора Armeria с помощью context.log(). WhenComplete()

У меня есть подкласс SimpleDecoratingHttpService который содержит что-то вроде этого:

          override fun serve(ctx: ServiceRequestContext, req: HttpRequest): HttpResponse {
        ctx.log().whenComplete().thenAccept {
            if (it.responseCause() == ...) {
                // do stuff
            }
        }
        return unwrap().serve(ctx, req)
    }

Я хочу проверить логику внутри whenComplete()Перезвоните. Однако при написании таких тестов:

      myDecorator.serve(context, request).aggregate().join()

будущее никогда не завершится. Что мне нужно сделать, чтобы убедиться, что log() будущее в конце концов завершается?

1 ответ

Решение

Эмуляция завершения

A дополняется сетевым уровнем Armeria, поэтому просто потребляя HttpRequest или же HttpResponse не завершит RequestLog. Для его завершения вам нужно вызвать методы в RequestLogBuilder:

      var myDecorator = new MySimpleDecoratingHttpService(...);

var ctx = ServiceRequestContext.of(
    HttpRequest.of(HttpMethod.GET, "/hello"));
var req = ctx.request();

var res = myDecorator.serve(ctx, ctx.req).aggregate().join();

// Fill the log.
ctx.logBuilder().endRequest();
assert ctx.log().isRequestComplete();

ctx.logBuilder().responseHeaders(ResponseHeaders.of(200));
ctx.logBuilder().endResponse();

assert ctx.log().isComplete();

Команда Armeria использует ту же технику для тестирования BraveService, так что вы можете также проверить это на BraveServiceTest.java:161.

Тестирование на реальном сервере

Если ваша установка слишком сложна для использования имитации, в качестве альтернативного подхода вы можете запустить настоящий сервер Armeria, чтобы Armeria заполнила журнал за вас. Вы можете легко запустить сервер, используя ServerRule (JUnit 4) или ServerExtension (JUnit 5):

      class MyJUnit5Test {
  static final var serviceContexts =
      new LinkedBlockingQueue<ServiceRequestContext>();

  @RegisterExtension
  static final var server = new ServerExtension() {
    @Override
    protected void configure(ServerBuilder sb) throws Exception {
      sb.service("/hello", (ctx, req) -> HttpResponse.of(200));
      sb.decorator(delegate -> new MySimpleDecoratingHttpService(delegate, ...));

      // Record the ServiceRequestContext of each request.
      sb.decorator((delegate, ctx, req) -> {
        serviceContexts.add(ctx);
        return delegate.serve(ctx, req);
      });
    }
  };

  @BeforeEach
  void clearServiceContexts() {
    serviceContexts.clear();
  }

  @Test
  void test() {
    // Send a real request.
    var client = WebClient.of(server.httpUri());
    var res = client.get("/hello").aggregate().join();

    // Get the ServiceRequestContext and its log.
    var ctx = serviceContexts.take();
    var log = sctx.log().whenComplete().join();

    // .. check `log` here ..
    assertEquals(200, log.responseHeaders().status().code());
  }
}
Другие вопросы по тегам