Search code examples
javajunitmicronaut

Micronaut: Unable to test Redirect response with junit


I am trying to test a redirect scenario where Controller is returning HttpResponse.seeOther(URI.create(redirectUri));. The issue is my test case is following the redirect instead of returning HttpResponse<String> or something equivalent. How to test this in Micronaut?

Controller

  @Post("/some/endpoint")
  public HttpResponse<?> capture(@Body Map<String, String> body)
      throws Exception {
    // do something
    String uri = getRedirectUri();
    return HttpResponse.seeOther(URI.create(redirectUri));
  }

Test

  @Test
  public void testCapture() {
    String expectedUri = getRedirectUri();
    //following doesn't work
    String redirectUrl = client.toBlocking().retrieve(HttpRequest.POST("/some/endpoint",  body), String.class);
    assertEquals(expectedUri, redirectUrl);

    //following also doesn't work
    HttpResponse<String> response = client.toBlocking().retrieve(HttpRequest.POST("/some/controller", someBody), HttpResponse.class);
    assertEquals(HttpStatus.SEE_OTHER, response.status());
  }

Error

16:59:32.321 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - HTTP Client Response Received for Request: POST http://localhost:65164/some/endpoint
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - Status Code: 303 See Other
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - Location: http://localhost:8080/target/location.html
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - Date: Wed, 13 Nov 2019 23:59:32 GMT
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - connection: close
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - Response Body
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - ----
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - 
16:59:32.322 [nioEventLoopGroup-1-3] TRACE i.m.http.client.DefaultHttpClient - ----


io.micronaut.http.client.exceptions.HttpClientException: Connect Error: Connection refused: localhost/127.0.0.1:8080

    at io.micronaut.http.client.DefaultHttpClient.lambda$null$24(DefaultHttpClient.java:1035)
    at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:504)
    at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:483)
    at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
    at io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:121)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:327)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:343)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:632)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:897)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
Caused by: io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:8080
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method)
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717)
    at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:327)
    at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:340)
    ... 7 more
Caused by: java.net.ConnectException: Connection refused
    ... 11 more

Solution

  • Implemented a work around by using client.exchange() method which returns a publisher. A io.reactivex.subscribers.TestSubscriber can be used to subscribe and test for assertions.

    HttpClient.exchange() method signature-

    <I, O> Publisher<HttpResponse<O>> exchange(HttpRequest<I> request, Class<O> bodyType) {...}
    

    Working test case with TestSubscriber-

    @Test
    public void testCapture() {
      //Instead of using client.toBlocking().retrieve(...)
      /*
      String redirectUrl = client.toBlocking()
          .retrieve(HttpRequest.POST("/some/endpoint",  body), String.class);
      */
    
      // Use client.exchange(...)
      Publisher<HttpResponse<Object>> exchange =
        client.exchange(HttpRequest.POST("/payment/1234567890/capture", body)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED), Object.class);
    
      TestSubscriber<HttpResponse<?>> testSubscriber = new TestSubscriber<HttpResponse<?>>() {
        @Override
        public void onNext(HttpResponse<?> httpResponse) {
          assertNotNull(httpResponse);
          assertEquals(HttpStatus.SEE_OTHER, httpResponse.status());
          assertEquals(getRedirectUri(), httpResponse.header("location"));
        }
      };
    
      exchange.subscribe(testSubscriber);
    
      // await to allow for response
      testSubscriber.awaitTerminalEvent(2, TimeUnit.SECONDS);
    
      // assert for errors, completion, terminated etc.
      testSubscriber.assertNoErrors();
      testSubscriber.assertComplete();
      testSubscriber.assertTerminated();
    }