HttpClientImpl implements HttpClient { <T> Callback createCallback(ResponseProcessor<? extends T> processor, CompletableFuture<T> resultFuture) { return new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { resultFuture.completeExceptionally(e); LOG.error("Failed HTTP request {} {}", call.request().method(), call.request().url(), e); } @Override public void onResponse(@NotNull Call call, @NotNull Response response) { try { LOG.debug("HTTP response {} - {} {}", response.code(), response.request().method(), response.request().url()); T result = processor.process(new ResponseImpl(response)); resultFuture.complete(result); } catch (Exception e) { resultFuture.completeExceptionally(e); LOG.error("Failed HTTP request {} {}", call.request().method(), call.request().url(), e); } finally { response.close(); } } }; } HttpClientImpl(OkHttpClient client, ObjectMapper mapper); @Override CompletableFuture<T> execute(Consumer<? super RequestBuilder> producer,
                                            ResponseProcessor<? extends T> processor);  }
@Test public void testResponseIsClosed() throws IOException { Object result = new Object(); Response response = createResponseMock(); CompletableFuture<Object> future = new CompletableFuture<>(); ResponseProcessor<Object> processor = createProcessorMock(); when(processor.process(any())).thenReturn(result); Callback callback = httpClient.createCallback(processor, future); callback.onResponse(createCallMock(), response); assertThat(future.join()).isEqualTo(result); verify(response).close(); }
@Test public void testResponseIsClosedEvenIfProcessorThrowsAnException() throws IOException { Response response = createResponseMock(); CompletableFuture<Object> future = new CompletableFuture<>(); IOException exception = new IOException("Boo"); ResponseProcessor<Object> processor = createProcessorMock(); when(processor.process(any())).thenThrow(exception); Callback callback = httpClient.createCallback(processor, future); callback.onResponse(createCallMock(), response); expectFailure(future, exception); verify(response).close(); }
@Test public void testResponseIsClosedEvenIfProcessorThrowsARuntimeException() throws IOException { Response response = createResponseMock(); CompletableFuture<Object> future = new CompletableFuture<>(); IllegalStateException exception = new IllegalStateException("Runtime boo"); ResponseProcessor<Object> processor = createProcessorMock(); when(processor.process(any())).thenThrow(exception); Callback callback = httpClient.createCallback(processor, future); callback.onResponse(createCallMock(), response); expectFailure(future, exception); verify(response).close(); }
@Test public void testCallbackErrorHandling() { CompletableFuture<Object> future = new CompletableFuture<>(); IOException exception = new IOException("Request failed miserably"); Callback callback = httpClient.createCallback(createProcessorMock(), future); callback.onFailure(createCallMock(), exception); expectFailure(future, exception); }