diff --git a/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java b/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java index c6fd063d78..daaa7ad9d7 100644 --- a/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java +++ b/spring-web/src/main/java/org/springframework/web/client/support/RestClientAdapter.java @@ -31,24 +31,26 @@ import org.springframework.web.service.invoker.HttpRequestValues; import org.springframework.web.service.invoker.HttpServiceProxyFactory; /** - * {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} to use - * {@link RestClient} for request execution. + * {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} + * to use {@link RestClient} for request execution. * - *

- * Use static factory methods in this class to create an {@link HttpServiceProxyFactory} - * configured with a given {@link RestClient}. + *

Use static factory methods in this class to create an + * {@link HttpServiceProxyFactory} configured with the given {@link RestClient}. * * @author Olga Maciaszek-Sharma + * @author Rossen Stoyanchev * @since 6.1 */ public final class RestClientAdapter implements HttpExchangeAdapter { private final RestClient restClient; + private RestClientAdapter(RestClient restClient) { this.restClient = restClient; } + @Override public boolean supportsRequestAttributes() { return true; @@ -60,66 +62,66 @@ public final class RestClientAdapter implements HttpExchangeAdapter { } @Override - public HttpHeaders exchangeForHeaders(HttpRequestValues requestValues) { - return newRequest(requestValues).retrieve().toBodilessEntity().getHeaders(); + public HttpHeaders exchangeForHeaders(HttpRequestValues values) { + return newRequest(values).retrieve().toBodilessEntity().getHeaders(); } @Override - public T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return newRequest(requestValues).retrieve().body(bodyType); + public T exchangeForBody(HttpRequestValues values, ParameterizedTypeReference bodyType) { + return newRequest(values).retrieve().body(bodyType); } @Override - public ResponseEntity exchangeForBodilessEntity(HttpRequestValues requestValues) { - return newRequest(requestValues).retrieve().toBodilessEntity(); + public ResponseEntity exchangeForBodilessEntity(HttpRequestValues values) { + return newRequest(values).retrieve().toBodilessEntity(); } @Override - public ResponseEntity exchangeForEntity(HttpRequestValues requestValues, - ParameterizedTypeReference bodyType) { - return newRequest(requestValues).retrieve().toEntity(bodyType); + public ResponseEntity exchangeForEntity(HttpRequestValues values, ParameterizedTypeReference bodyType) { + return newRequest(values).retrieve().toEntity(bodyType); } - private RestClient.RequestBodySpec newRequest(HttpRequestValues requestValues) { + private RestClient.RequestBodySpec newRequest(HttpRequestValues values) { - HttpMethod httpMethod = requestValues.getHttpMethod(); + HttpMethod httpMethod = values.getHttpMethod(); Assert.notNull(httpMethod, "HttpMethod is required"); RestClient.RequestBodyUriSpec uriSpec = this.restClient.method(httpMethod); RestClient.RequestBodySpec bodySpec; - if (requestValues.getUri() != null) { - bodySpec = uriSpec.uri(requestValues.getUri()); + if (values.getUri() != null) { + bodySpec = uriSpec.uri(values.getUri()); } - else if (requestValues.getUriTemplate() != null) { - bodySpec = uriSpec.uri(requestValues.getUriTemplate(), requestValues.getUriVariables()); + else if (values.getUriTemplate() != null) { + bodySpec = uriSpec.uri(values.getUriTemplate(), values.getUriVariables()); } else { throw new IllegalStateException("Neither full URL nor URI template"); } - bodySpec.headers(headers -> headers.putAll(requestValues.getHeaders())); + bodySpec.headers(headers -> headers.putAll(values.getHeaders())); - if (!requestValues.getCookies().isEmpty()) { + if (!values.getCookies().isEmpty()) { List cookies = new ArrayList<>(); - requestValues.getCookies().forEach((name, values) -> values.forEach(value -> { + values.getCookies().forEach((name, cookieValues) -> cookieValues.forEach(value -> { HttpCookie cookie = new HttpCookie(name, value); cookies.add(cookie.toString()); })); bodySpec.header(HttpHeaders.COOKIE, String.join("; ", cookies)); } - bodySpec.attributes(attributes -> attributes.putAll(requestValues.getAttributes())); + bodySpec.attributes(attributes -> attributes.putAll(values.getAttributes())); - if (requestValues.getBodyValue() != null) { - bodySpec.body(requestValues.getBodyValue()); + if (values.getBodyValue() != null) { + bodySpec.body(values.getBodyValue()); } return bodySpec; } + /** - * Create a {@link RestClientAdapter} with the given {@link RestClient}. + * Create a {@link RestClientAdapter} for the given {@link RestClient}. */ public static RestClientAdapter create(RestClient restClient) { return new RestClientAdapter(restClient); diff --git a/spring-web/src/main/java/org/springframework/web/client/support/RestTemplateAdapter.java b/spring-web/src/main/java/org/springframework/web/client/support/RestTemplateAdapter.java index 214f3f339a..d5586aceb3 100644 --- a/spring-web/src/main/java/org/springframework/web/client/support/RestTemplateAdapter.java +++ b/spring-web/src/main/java/org/springframework/web/client/support/RestTemplateAdapter.java @@ -34,11 +34,11 @@ import org.springframework.web.service.invoker.HttpRequestValues; import org.springframework.web.service.invoker.HttpServiceProxyFactory; /** - * {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} to use - * {@link RestTemplate} for request execution. + * {@link HttpExchangeAdapter} that enables an {@link HttpServiceProxyFactory} + * to use {@link RestTemplate} for request execution. * *

Use static factory methods in this class to create an - * {@link HttpServiceProxyFactory} configured with a given {@link RestTemplate}. + * {@link HttpServiceProxyFactory} configured with the given {@link RestTemplate}. * * @author Olga Maciaszek-Sharma * @since 6.1 @@ -59,63 +59,61 @@ public final class RestTemplateAdapter implements HttpExchangeAdapter { } @Override - public void exchange(HttpRequestValues requestValues) { - this.restTemplate.exchange(newRequest(requestValues), Void.class); + public void exchange(HttpRequestValues values) { + this.restTemplate.exchange(newRequest(values), Void.class); } @Override - public HttpHeaders exchangeForHeaders(HttpRequestValues requestValues) { - return this.restTemplate.exchange(newRequest(requestValues), Void.class).getHeaders(); + public HttpHeaders exchangeForHeaders(HttpRequestValues values) { + return this.restTemplate.exchange(newRequest(values), Void.class).getHeaders(); } @Override - public T exchangeForBody(HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - return this.restTemplate.exchange(newRequest(requestValues), bodyType).getBody(); + public T exchangeForBody(HttpRequestValues values, ParameterizedTypeReference bodyType) { + return this.restTemplate.exchange(newRequest(values), bodyType).getBody(); } @Override - public ResponseEntity exchangeForBodilessEntity(HttpRequestValues requestValues) { - return this.restTemplate.exchange(newRequest(requestValues), Void.class); + public ResponseEntity exchangeForBodilessEntity(HttpRequestValues values) { + return this.restTemplate.exchange(newRequest(values), Void.class); } @Override - public ResponseEntity exchangeForEntity( - HttpRequestValues requestValues, ParameterizedTypeReference bodyType) { - - return this.restTemplate.exchange(newRequest(requestValues), bodyType); + public ResponseEntity exchangeForEntity(HttpRequestValues values, ParameterizedTypeReference bodyType) { + return this.restTemplate.exchange(newRequest(values), bodyType); } - private RequestEntity newRequest(HttpRequestValues requestValues) { + private RequestEntity newRequest(HttpRequestValues values) { URI uri; - if (requestValues.getUri() != null) { - uri = requestValues.getUri(); + if (values.getUri() != null) { + uri = values.getUri(); } - else if (requestValues.getUriTemplate() != null) { - String uriTemplate = requestValues.getUriTemplate(); - Map variables = requestValues.getUriVariables(); + else if (values.getUriTemplate() != null) { + String uriTemplate = values.getUriTemplate(); + Map variables = values.getUriVariables(); uri = this.restTemplate.getUriTemplateHandler().expand(uriTemplate, variables); } else { throw new IllegalStateException("Neither full URL nor URI template"); } - HttpMethod httpMethod = requestValues.getHttpMethod(); + HttpMethod httpMethod = values.getHttpMethod(); Assert.notNull(httpMethod, "HttpMethod is required"); RequestEntity.BodyBuilder builder = RequestEntity.method(httpMethod, uri); - builder.headers(requestValues.getHeaders()); + builder.headers(values.getHeaders()); - if (!requestValues.getCookies().isEmpty()) { + if (!values.getCookies().isEmpty()) { List cookies = new ArrayList<>(); - requestValues.getCookies().forEach((name, values) -> values.forEach(value -> { + values.getCookies().forEach((name, cookieValues) -> cookieValues.forEach(value -> { HttpCookie cookie = new HttpCookie(name, value); cookies.add(cookie.toString()); })); builder.header(HttpHeaders.COOKIE, String.join("; ", cookies)); } - if (requestValues.getBodyValue() != null) { - return builder.body(requestValues.getBodyValue()); + if (values.getBodyValue() != null) { + return builder.body(values.getBodyValue()); } return builder.build(); @@ -123,7 +121,7 @@ public final class RestTemplateAdapter implements HttpExchangeAdapter { /** - * Create a {@link RestTemplateAdapter} with the given {@link RestTemplate}. + * Create a {@link RestTemplateAdapter} for the given {@link RestTemplate}. */ public static RestTemplateAdapter create(RestTemplate restTemplate) { return new RestTemplateAdapter(restTemplate); diff --git a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java index e78a7e5f30..bf3e1eb873 100644 --- a/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java +++ b/spring-web/src/main/java/org/springframework/web/service/invoker/HttpServiceProxyFactory.java @@ -53,9 +53,9 @@ import org.springframework.web.service.annotation.HttpExchange; * * @author Rossen Stoyanchev * @since 6.0 - * @see org.springframework.web.client.support.RestTemplateAdapter - * @see org.springframework.web.reactive.function.client.support.WebClientAdapter * @see org.springframework.web.client.support.RestClientAdapter + * @see org.springframework.web.reactive.function.client.support.WebClientAdapter + * @see org.springframework.web.client.support.RestTemplateAdapter */ public final class HttpServiceProxyFactory { diff --git a/spring-web/src/test/java/org/springframework/web/client/support/RestClientAdapterTests.java b/spring-web/src/test/java/org/springframework/web/client/support/RestClientAdapterTests.java index b5cffaaa30..f04a12a04a 100644 --- a/spring-web/src/test/java/org/springframework/web/client/support/RestClientAdapterTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/support/RestClientAdapterTests.java @@ -16,17 +16,21 @@ package org.springframework.web.client.support; -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.net.URI; import java.util.Optional; +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.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.cglib.core.internal.Function; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -40,113 +44,127 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.client.RestClient; +import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.service.annotation.GetExchange; import org.springframework.web.service.annotation.PostExchange; import org.springframework.web.service.annotation.PutExchange; +import org.springframework.web.service.invoker.HttpExchangeAdapter; import org.springframework.web.service.invoker.HttpServiceProxyFactory; import org.springframework.web.testfixture.servlet.MockMultipartFile; +import org.springframework.web.util.DefaultUriBuilderFactory; import static org.assertj.core.api.Assertions.assertThat; /** - * Integration tests for {@link HttpServiceProxyFactory HTTP Service proxy} with - * {@link RestClientAdapter} connecting to {@link MockWebServer}. + * Integration tests for {@link HttpServiceProxyFactory} with {@link RestClient} + * and {@link RestTemplate} connecting to {@link MockWebServer}. * * @author Olga Maciaszek-Sharma + * @author Rossen Stoyanchev */ +@SuppressWarnings("JUnitMalformedDeclaration") class RestClientAdapterTests { - private MockWebServer server; - - private Service service; - - @BeforeEach - void setUp() { - this.server = new MockWebServer(); - prepareResponse(); - - RestClient restClient = RestClient.builder().baseUrl(this.server.url("/").toString()).build(); - RestClientAdapter adapter = RestClientAdapter.create(restClient); - this.service = HttpServiceProxyFactory.builderFor(adapter).build().createClient(Service.class); + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @ParameterizedTest + @MethodSource("arguments") + @interface ParameterizedAdapterTest { } - @SuppressWarnings("ConstantConditions") - @AfterEach - void shutDown() throws IOException { - if (this.server != null) { - this.server.shutdown(); - } + public static Stream arguments() { + return Stream.of( + args(url -> { + RestClient restClient = RestClient.builder().baseUrl(url).build(); + return RestClientAdapter.create(restClient); + }), + args(url -> { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(url)); + return RestTemplateAdapter.create(restTemplate); + })); } - @Test - void greeting() throws InterruptedException { - String response = this.service.getGreeting(); + @SuppressWarnings("resource") + private static Object[] args(Function adapterFactory) { + MockWebServer server = new MockWebServer(); - RecordedRequest request = this.server.takeRequest(); + MockResponse response = new MockResponse(); + response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!"); + server.enqueue(response); + + HttpExchangeAdapter adapter = adapterFactory.apply(server.url("/").toString()); + Service service = HttpServiceProxyFactory.builderFor(adapter).build().createClient(Service.class); + + return new Object[] { server, service }; + } + + + @ParameterizedAdapterTest + void greeting(MockWebServer server, Service service) throws Exception { + String response = service.getGreeting(); + + RecordedRequest request = server.takeRequest(); assertThat(response).isEqualTo("Hello Spring!"); assertThat(request.getMethod()).isEqualTo("GET"); assertThat(request.getPath()).isEqualTo("/greeting"); } - @Test - void greetingById() throws InterruptedException { - ResponseEntity response = this.service.getGreetingById("456"); + @ParameterizedAdapterTest + void greetingById(MockWebServer server, Service service) throws Exception { + ResponseEntity response = service.getGreetingById("456"); - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(response.getBody()).isEqualTo("Hello Spring!"); assertThat(request.getMethod()).isEqualTo("GET"); assertThat(request.getPath()).isEqualTo("/greeting/456"); } - @Test - void greetingWithDynamicUri() throws InterruptedException { - URI dynamicUri = this.server.url("/greeting/123").uri(); + @ParameterizedAdapterTest + void greetingWithDynamicUri(MockWebServer server, Service service) throws Exception { + URI dynamicUri = server.url("/greeting/123").uri(); + Optional response = service.getGreetingWithDynamicUri(dynamicUri, "456"); - Optional response = this.service.getGreetingWithDynamicUri(dynamicUri, "456"); - - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(response.orElse("empty")).isEqualTo("Hello Spring!"); assertThat(request.getMethod()).isEqualTo("GET"); assertThat(request.getRequestUrl().uri()).isEqualTo(dynamicUri); } - @Test - void postWithHeader() throws InterruptedException { + @ParameterizedAdapterTest + void postWithHeader(MockWebServer server, Service service) throws Exception { service.postWithHeader("testHeader", "testBody"); - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(request.getMethod()).isEqualTo("POST"); assertThat(request.getPath()).isEqualTo("/greeting"); assertThat(request.getHeaders().get("testHeaderName")).isEqualTo("testHeader"); assertThat(request.getBody().readUtf8()).isEqualTo("testBody"); } - @Test - void formData() throws Exception { + @ParameterizedAdapterTest + void formData(MockWebServer server, Service service) throws Exception { MultiValueMap map = new LinkedMultiValueMap<>(); map.add("param1", "value 1"); map.add("param2", "value 2"); service.postForm(map); - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getHeaders().get("Content-Type")) - .isEqualTo("application/x-www-form-urlencoded;charset=UTF-8"); + RecordedRequest request = server.takeRequest(); + assertThat(request.getHeaders().get("Content-Type")).isEqualTo("application/x-www-form-urlencoded;charset=UTF-8"); assertThat(request.getBody().readUtf8()).isEqualTo("param1=value+1¶m2=value+2"); } - @Test // gh-30342 - void multipart() throws InterruptedException { - String fileName = "testFileName"; - String originalFileName = "originalTestFileName"; - MultipartFile file = new MockMultipartFile(fileName, originalFileName, MediaType.APPLICATION_JSON_VALUE, - "test".getBytes()); + @ParameterizedAdapterTest // gh-30342 + void multipart(MockWebServer server, Service service) throws Exception { + MultipartFile file = new MockMultipartFile( + "testFileName", "originalTestFileName", MediaType.APPLICATION_JSON_VALUE, "test".getBytes()); service.postMultipart(file, "test2"); - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(request.getHeaders().get("Content-Type")).startsWith("multipart/form-data;boundary="); assertThat(request.getBody().readUtf8()).containsSubsequence( "Content-Disposition: form-data; name=\"file\"; filename=\"originalTestFileName\"", @@ -155,29 +173,24 @@ class RestClientAdapterTests { "Content-Length: 5", "test2"); } - @Test - void putWithCookies() throws InterruptedException { + @ParameterizedAdapterTest + void putWithCookies(MockWebServer server, Service service) throws Exception { service.putWithCookies("test1", "test2"); - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(request.getMethod()).isEqualTo("PUT"); assertThat(request.getHeader("Cookie")).isEqualTo("firstCookie=test1; secondCookie=test2"); } - @Test - void putWithSameNameCookies() throws InterruptedException { + @ParameterizedAdapterTest + void putWithSameNameCookies(MockWebServer server, Service service) throws Exception { service.putWithSameNameCookies("test1", "test2"); - RecordedRequest request = this.server.takeRequest(); + RecordedRequest request = server.takeRequest(); assertThat(request.getMethod()).isEqualTo("PUT"); assertThat(request.getHeader("Cookie")).isEqualTo("testCookie=test1; testCookie=test2"); } - private void prepareResponse() { - MockResponse response = new MockResponse(); - response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!"); - this.server.enqueue(response); - } private interface Service { @@ -203,8 +216,8 @@ class RestClientAdapterTests { void putWithCookies(@CookieValue String firstCookie, @CookieValue String secondCookie); @PutExchange - void putWithSameNameCookies(@CookieValue("testCookie") String firstCookie, - @CookieValue("testCookie") String secondCookie); + void putWithSameNameCookies( + @CookieValue("testCookie") String firstCookie, @CookieValue("testCookie") String secondCookie); } diff --git a/spring-web/src/test/java/org/springframework/web/client/support/RestTemplateAdapterTests.java b/spring-web/src/test/java/org/springframework/web/client/support/RestTemplateAdapterTests.java deleted file mode 100644 index 5b36b9e513..0000000000 --- a/spring-web/src/test/java/org/springframework/web/client/support/RestTemplateAdapterTests.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * 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.support; - -import java.io.IOException; -import java.net.URI; -import java.util.Optional; - -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.lang.Nullable; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.bind.annotation.CookieValue; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.service.annotation.GetExchange; -import org.springframework.web.service.annotation.PostExchange; -import org.springframework.web.service.annotation.PutExchange; -import org.springframework.web.service.invoker.HttpServiceProxyFactory; -import org.springframework.web.testfixture.servlet.MockMultipartFile; -import org.springframework.web.util.DefaultUriBuilderFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for {@link HttpServiceProxyFactory HTTP Service proxy} - * with {@link RestTemplateAdapter} connecting to {@link MockWebServer}. - * - * @author Olga Maciaszek-Sharma - */ -class RestTemplateAdapterTests { - - private MockWebServer server; - - private Service service; - - - @BeforeEach - void setUp() { - this.server = new MockWebServer(); - prepareResponse(); - - RestTemplate restTemplate = new RestTemplate(); - restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(this.server.url("/").toString())); - RestTemplateAdapter adapter = RestTemplateAdapter.create(restTemplate); - this.service = HttpServiceProxyFactory.builder().exchangeAdapter(adapter).build().createClient(Service.class); - } - - @SuppressWarnings("ConstantConditions") - @AfterEach - void shutDown() throws IOException { - if (this.server != null) { - this.server.shutdown(); - } - } - - - @Test - void greeting() throws InterruptedException { - String response = this.service.getGreeting(); - - RecordedRequest request = this.server.takeRequest(); - assertThat(response).isEqualTo("Hello Spring!"); - assertThat(request.getMethod()).isEqualTo("GET"); - assertThat(request.getPath()).isEqualTo("/greeting"); - } - - @Test - void greetingById() throws InterruptedException { - ResponseEntity response = this.service.getGreetingById("456"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).isEqualTo("Hello Spring!"); - assertThat(request.getMethod()).isEqualTo("GET"); - assertThat(request.getPath()).isEqualTo("/greeting/456"); - } - - @Test - void greetingWithDynamicUri() throws InterruptedException { - URI dynamicUri = this.server.url("/greeting/123").uri(); - - Optional response = this.service.getGreetingWithDynamicUri(dynamicUri, "456"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(response.orElse("empty")).isEqualTo("Hello Spring!"); - assertThat(request.getMethod()).isEqualTo("GET"); - assertThat(request.getRequestUrl().uri()).isEqualTo(dynamicUri); - } - - @Test - void postWithHeader() throws InterruptedException { - service.postWithHeader("testHeader", "testBody"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getMethod()).isEqualTo("POST"); - assertThat(request.getPath()).isEqualTo("/greeting"); - assertThat(request.getHeaders().get("testHeaderName")).isEqualTo("testHeader"); - assertThat(request.getBody().readUtf8()).isEqualTo("testBody"); - } - - @Test - void formData() throws Exception { - MultiValueMap map = new LinkedMultiValueMap<>(); - map.add("param1", "value 1"); - map.add("param2", "value 2"); - - service.postForm(map); - - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getHeaders().get("Content-Type")) - .isEqualTo("application/x-www-form-urlencoded;charset=UTF-8"); - assertThat(request.getBody().readUtf8()).isEqualTo("param1=value+1¶m2=value+2"); - } - - @Test // gh-30342 - void multipart() throws InterruptedException { - String fileName = "testFileName"; - String originalFileName = "originalTestFileName"; - MultipartFile file = new MockMultipartFile(fileName, originalFileName, MediaType.APPLICATION_JSON_VALUE, - "test".getBytes()); - - service.postMultipart(file, "test2"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getHeaders().get("Content-Type")).startsWith("multipart/form-data;boundary="); - assertThat(request.getBody().readUtf8()).containsSubsequence( - "Content-Disposition: form-data; name=\"file\"; filename=\"originalTestFileName\"", - "Content-Type: application/json", "Content-Length: 4", "test", - "Content-Disposition: form-data; name=\"anotherPart\"", "Content-Type: text/plain;charset=UTF-8", - "Content-Length: 5", "test2"); - } - - @Test - void putWithCookies() throws InterruptedException { - service.putWithCookies("test1", "test2"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getMethod()).isEqualTo("PUT"); - assertThat(request.getHeader("Cookie")).isEqualTo("firstCookie=test1; secondCookie=test2"); - } - - @Test - void putWithSameNameCookies() throws InterruptedException { - service.putWithSameNameCookies("test1", "test2"); - - RecordedRequest request = this.server.takeRequest(); - assertThat(request.getMethod()).isEqualTo("PUT"); - assertThat(request.getHeader("Cookie")).isEqualTo("testCookie=test1; testCookie=test2"); - } - - private void prepareResponse() { - MockResponse response = new MockResponse(); - response.setHeader("Content-Type", "text/plain").setBody("Hello Spring!"); - this.server.enqueue(response); - } - - - private interface Service { - - @GetExchange("/greeting") - String getGreeting(); - - @GetExchange("/greeting/{id}") - ResponseEntity getGreetingById(@PathVariable String id); - - @GetExchange("/greeting/{id}") - Optional getGreetingWithDynamicUri(@Nullable URI uri, @PathVariable String id); - - @PostExchange("/greeting") - void postWithHeader( - @RequestHeader("testHeaderName") String testHeader, @RequestBody String requestBody); - - @PostExchange(contentType = "application/x-www-form-urlencoded") - void postForm(@RequestParam MultiValueMap params); - - @PostExchange - void postMultipart(MultipartFile file, @RequestPart String anotherPart); - - @PutExchange - void putWithCookies( - @CookieValue String firstCookie, @CookieValue String secondCookie); - - @PutExchange - void putWithSameNameCookies( - @CookieValue("testCookie") String firstCookie, @CookieValue("testCookie") String secondCookie); - - } - -}