Introduce RestClient

This commit introduces the RestClient, a synchronous HTTP client that
offers an API similar to WebClient, using the same infrastructure (i.e.
request factory, error handler, interceptors, etc) as RestTemplate.

Closes gh-29552
This commit is contained in:
Arjen Poutsma
2023-05-10 11:56:26 +02:00
parent 9eb1fbd5c3
commit 0820210c7c
7 changed files with 2711 additions and 1 deletions

View File

@@ -0,0 +1,758 @@
/*
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.client;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Stream;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.http.client.JettyClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.web.testfixture.xml.Pojo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.junit.jupiter.api.Named.named;
/**
* Integration tests for {@link RestClient}.
*
* @author Arjen Poutsma
*/
class RestClientIntegrationTests {
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@ParameterizedTest(name = "[{index}] {0}")
@MethodSource("clientHttpRequestFactories")
@interface ParameterizedWebClientTest {
}
static Stream<Named<ClientHttpRequestFactory>> clientHttpRequestFactories() {
return Stream.of(
named("JDK HttpURLConnection", new SimpleClientHttpRequestFactory()),
named("HttpComponents", new HttpComponentsClientHttpRequestFactory()),
named("OkHttp", new OkHttp3ClientHttpRequestFactory()),
named("Jetty", new JettyClientHttpRequestFactory()),
named("JDK HttpClient", new JdkClientHttpRequestFactory())
);
}
private MockWebServer server;
private RestClient restClient;
private void startServer(ClientHttpRequestFactory requestFactory) {
this.server = new MockWebServer();
this.restClient = RestClient
.builder()
.requestFactory(requestFactory)
.baseUrl(this.server.url("/").toString())
.build();
}
@AfterEach
void shutdown() throws IOException {
if (server != null) {
this.server.shutdown();
}
}
@ParameterizedWebClientTest
void retrieve(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response ->
response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!"));
String result = this.restClient.get()
.uri("/greeting")
.header("X-Test-Header", "testvalue")
.retrieve()
.body(String.class);
assertThat(result).isEqualTo("Hello Spring!");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getHeader("X-Test-Header")).isEqualTo("testvalue");
assertThat(request.getPath()).isEqualTo("/greeting");
});
}
@ParameterizedWebClientTest
void retrieveJson(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response
.setHeader("Content-Type", "application/json")
.setBody("{\"bar\":\"barbar\",\"foo\":\"foofoo\"}"));
Pojo result = this.restClient.get()
.uri("/pojo")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.body(Pojo.class);
assertThat(result.getFoo()).isEqualTo("foofoo");
assertThat(result.getBar()).isEqualTo("barbar");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/pojo");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonWithParameterizedTypeReference(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String content = "{\"containerValue\":{\"bar\":\"barbar\",\"foo\":\"foofoo\"}}";
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody(content));
ValueContainer<Pojo> result = this.restClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.body(new ParameterizedTypeReference<ValueContainer<Pojo>>() {});
assertThat(result.getContainerValue()).isNotNull();
Pojo pojo = result.getContainerValue();
assertThat(pojo.getFoo()).isEqualTo("foofoo");
assertThat(pojo.getBar()).isEqualTo("barbar");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/json");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonAsResponseEntity(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String content = "{\"bar\":\"barbar\",\"foo\":\"foofoo\"}";
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody(content));
ResponseEntity<String> result = this.restClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
assertThat(result.getHeaders().getContentLength()).isEqualTo(31);
assertThat(result.getBody()).isEqualTo(content);
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/json");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonAsBodilessEntity(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody("{\"bar\":\"barbar\",\"foo\":\"foofoo\"}"));
ResponseEntity<Void> result = this.restClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.toBodilessEntity();
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
assertThat(result.getHeaders().getContentLength()).isEqualTo(31);
assertThat(result.getBody()).isNull();
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/json");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonArray(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response
.setHeader("Content-Type", "application/json")
.setBody("[{\"bar\":\"bar1\",\"foo\":\"foo1\"},{\"bar\":\"bar2\",\"foo\":\"foo2\"}]"));
List<Pojo> result = this.restClient.get()
.uri("/pojos")
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.body(new ParameterizedTypeReference<>() {});
assertThat(result).hasSize(2);
assertThat(result.get(0).getFoo()).isEqualTo("foo1");
assertThat(result.get(0).getBar()).isEqualTo("bar1");
assertThat(result.get(1).getFoo()).isEqualTo("foo2");
assertThat(result.get(1).getBar()).isEqualTo("bar2");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/pojos");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonArrayAsResponseEntityList(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String content = "[{\"bar\":\"bar1\",\"foo\":\"foo1\"}, {\"bar\":\"bar2\",\"foo\":\"foo2\"}]";
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody(content));
ResponseEntity<List<Pojo>> result = this.restClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(new ParameterizedTypeReference<>() {});
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(result.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
assertThat(result.getHeaders().getContentLength()).isEqualTo(58);
assertThat(result.getBody()).hasSize(2);
assertThat(result.getBody().get(0).getFoo()).isEqualTo("foo1");
assertThat(result.getBody().get(0).getBar()).isEqualTo("bar1");
assertThat(result.getBody().get(1).getFoo()).isEqualTo("foo2");
assertThat(result.getBody().get(1).getBar()).isEqualTo("bar2");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/json");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieveJsonAsSerializedText(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String content = "{\"bar\":\"barbar\",\"foo\":\"foofoo\"}";
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody(content));
String result = this.restClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.body(String.class);
assertThat(result).isEqualTo(content);
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/json");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
@SuppressWarnings("rawtypes")
void retrieveJsonNull(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.setBody("null"));
Map result = this.restClient.get()
.uri("/null")
.retrieve()
.body(Map.class);
assertThat(result).isNull();
}
@ParameterizedWebClientTest
void retrieve404(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(404)
.setHeader("Content-Type", "text/plain"));
assertThatExceptionOfType(HttpClientErrorException.NotFound.class).isThrownBy(() ->
this.restClient.get().uri("/greeting")
.retrieve()
.body(String.class)
);
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void retrieve404WithBody(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(404)
.setHeader("Content-Type", "text/plain").setBody("Not Found"));
assertThatExceptionOfType(HttpClientErrorException.NotFound.class).isThrownBy(() ->
this.restClient.get()
.uri("/greeting")
.retrieve()
.body(String.class)
);
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void retrieve500(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String errorMessage = "Internal Server error";
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody(errorMessage));
String path = "/greeting";
try {
this.restClient.get()
.uri(path)
.retrieve()
.body(String.class);
}
catch (HttpServerErrorException ex) {
assertThat(ex.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assumeFalse(requestFactory instanceof JdkClientHttpRequestFactory, "JDK HttpClient does not expose status text");
assertThat(ex.getStatusText()).isEqualTo("Server Error");
assertThat(ex.getResponseHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN);
assertThat(ex.getResponseBodyAsString()).isEqualTo(errorMessage);
}
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo(path));
}
@ParameterizedWebClientTest
void retrieve500AsEntity(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody("Internal Server error"));
assertThatExceptionOfType(HttpServerErrorException.InternalServerError.class).isThrownBy(() ->
this.restClient.get()
.uri("/").accept(MediaType.APPLICATION_JSON)
.retrieve()
.toEntity(String.class)
);
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieve500AsBodilessEntity(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody("Internal Server error"));
assertThatExceptionOfType(HttpServerErrorException.InternalServerError.class).isThrownBy(() ->
this.restClient.get()
.uri("/").accept(MediaType.APPLICATION_JSON)
.retrieve()
.toBodilessEntity()
);
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void retrieve555UnknownStatus(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
int errorStatus = 555;
assertThat(HttpStatus.resolve(errorStatus)).isNull();
String errorMessage = "Something went wrong";
prepareResponse(response -> response.setResponseCode(errorStatus)
.setHeader("Content-Type", "text/plain").setBody(errorMessage));
try {
this.restClient.get()
.uri("/unknownPage")
.retrieve()
.body(String.class);
}
catch (HttpServerErrorException ex) {
assumeFalse(requestFactory instanceof JdkClientHttpRequestFactory, "JDK HttpClient does not expose status text");
assertThat(ex.getMessage()).isEqualTo("555 Server Error: \"Something went wrong\"");
assertThat(ex.getStatusText()).isEqualTo("Server Error");
assertThat(ex.getResponseHeaders().getContentType()).isEqualTo(MediaType.TEXT_PLAIN);
assertThat(ex.getResponseBodyAsString()).isEqualTo(errorMessage);
}
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/unknownPage"));
}
@ParameterizedWebClientTest
void postPojoAsJson(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setHeader("Content-Type", "application/json")
.setBody("{\"bar\":\"BARBAR\",\"foo\":\"FOOFOO\"}"));
Pojo result = this.restClient.post()
.uri("/pojo/capitalize")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.body(new Pojo("foofoo", "barbar"))
.retrieve()
.body(Pojo.class);
assertThat(result).isNotNull();
assertThat(result.getFoo()).isEqualTo("FOOFOO");
assertThat(result.getBar()).isEqualTo("BARBAR");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/pojo/capitalize");
assertThat(request.getBody().readUtf8()).isEqualTo("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}");
// assertThat(request.getHeader(HttpHeaders.CONTENT_LENGTH)).isEqualTo("31");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void statusHandler(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody("Internal Server error"));
assertThatExceptionOfType(MyException.class).isThrownBy(() ->
this.restClient.get()
.uri("/greeting")
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError, (request, response) -> {
throw new MyException("500 error!");
})
.body(String.class)
);
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void statusHandlerParameterizedTypeReference(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody("Internal Server error"));
assertThatExceptionOfType(MyException.class).isThrownBy(() ->
this.restClient.get()
.uri("/greeting")
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError, (request, response) -> {
throw new MyException("500 error!");
})
.body(new ParameterizedTypeReference<String>() {
})
);
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void statusHandlerSuppressedErrorSignal(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody("Internal Server error"));
String result = this.restClient.get()
.uri("/greeting")
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError, (request, response) -> {})
.body(String.class);
assertThat(result).isEqualTo("Internal Server error");
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void statusHandlerSuppressedErrorSignalWithEntity(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String content = "Internal Server error";
prepareResponse(response -> response.setResponseCode(500)
.setHeader("Content-Type", "text/plain").setBody(content));
ResponseEntity<String> result = this.restClient.get()
.uri("/").accept(MediaType.APPLICATION_JSON)
.retrieve()
.onStatus(HttpStatusCode::is5xxServerError, (request, response) -> {})
.toEntity(String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(result.getBody()).isEqualTo(content);
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getPath()).isEqualTo("/");
assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json");
});
}
@ParameterizedWebClientTest
void exchangeForPlainText(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setBody("Hello Spring!"));
String result = this.restClient.get()
.uri("/greeting")
.header("X-Test-Header", "testvalue")
.exchange((request, response) -> new String(RestClientUtils.getBody(response), StandardCharsets.UTF_8));
assertThat(result).isEqualTo("Hello Spring!");
expectRequestCount(1);
expectRequest(request -> {
assertThat(request.getHeader("X-Test-Header")).isEqualTo("testvalue");
assertThat(request.getPath()).isEqualTo("/greeting");
});
}
@ParameterizedWebClientTest
void exchangeFor404(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setResponseCode(404)
.setHeader("Content-Type", "text/plain").setBody("Not Found"));
String result = this.restClient.get()
.uri("/greeting")
.exchange((request, response) -> new String(RestClientUtils.getBody(response), StandardCharsets.UTF_8));
assertThat(result).isEqualTo("Not Found");
expectRequestCount(1);
expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting"));
}
@ParameterizedWebClientTest
void requestInitializer(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setHeader("Content-Type", "text/plain")
.setBody("Hello Spring!"));
RestClient initializedClient = this.restClient.mutate()
.requestInitializer(request -> request.getHeaders().add("foo", "bar"))
.build();
String result = initializedClient.get()
.uri("/greeting")
.retrieve()
.body(String.class);
assertThat(result).isEqualTo("Hello Spring!");
expectRequestCount(1);
expectRequest(request -> assertThat(request.getHeader("foo")).isEqualTo("bar"));
}
@ParameterizedWebClientTest
void requestInterceptor(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response.setHeader("Content-Type", "text/plain")
.setBody("Hello Spring!"));
RestClient interceptedClient = this.restClient.mutate()
.requestInterceptor((request, body, execution) -> {
request.getHeaders().add("foo", "bar");
return execution.execute(request, body);
})
.build();
String result = interceptedClient.get()
.uri("/greeting")
.retrieve()
.body(String.class);
assertThat(result).isEqualTo("Hello Spring!");
expectRequestCount(1);
expectRequest(request -> assertThat(request.getHeader("foo")).isEqualTo("bar"));
}
@ParameterizedWebClientTest
void filterForErrorHandling(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
ClientHttpRequestInterceptor interceptor = (request, body, execution) -> {
ClientHttpResponse response = execution.execute(request, body);
List<String> headerValues = response.getHeaders().get("Foo");
if (CollectionUtils.isEmpty(headerValues)) {
throw new MyException("Response does not contain Foo header");
}
else {
return response;
}
};
RestClient interceptedClient = this.restClient.mutate().requestInterceptor(interceptor).build();
// header not present
prepareResponse(response -> response
.setHeader("Content-Type", "text/plain").setBody("Hello Spring!"));
assertThatExceptionOfType(MyException.class).isThrownBy(() ->
interceptedClient.get()
.uri("/greeting")
.retrieve()
.body(String.class)
);
// header present
prepareResponse(response -> response.setHeader("Content-Type", "text/plain")
.setHeader("Foo", "Bar")
.setBody("Hello Spring!"));
String result = interceptedClient.get()
.uri("/greeting")
.retrieve().body(String.class);
assertThat(result).isEqualTo("Hello Spring!");
expectRequestCount(2);
}
@ParameterizedWebClientTest
void invalidDomain(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
String url = "http://example.invalid";
assertThatExceptionOfType(ResourceAccessException.class).isThrownBy(() ->
this.restClient.get().uri(url).retrieve().toBodilessEntity()
);
}
private void prepareResponse(Consumer<MockResponse> consumer) {
MockResponse response = new MockResponse();
consumer.accept(response);
this.server.enqueue(response);
}
private void expectRequest(Consumer<RecordedRequest> consumer) {
try {
consumer.accept(this.server.takeRequest());
}
catch (InterruptedException ex) {
throw new IllegalStateException(ex);
}
}
private void expectRequestCount(int count) {
assertThat(this.server.getRequestCount()).isEqualTo(count);
}
@SuppressWarnings("serial")
private static class MyException extends RuntimeException {
MyException(String message) {
super(message);
}
}
static class ValueContainer<T> {
private T containerValue;
public T getContainerValue() {
return containerValue;
}
public void setContainerValue(T containerValue) {
this.containerValue = containerValue;
}
}
}