diff --git a/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java index 4bbfa434f0..85bfe8e314 100644 --- a/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java +++ b/spring-boot-test/src/main/java/org/springframework/boot/test/web/client/TestRestTemplate.java @@ -217,7 +217,7 @@ public class TestRestTemplate { * @see RestTemplate#getForObject(java.net.URI, java.lang.Class) */ public T getForObject(URI url, Class responseType) throws RestClientException { - return this.restTemplate.getForObject(url, responseType); + return this.restTemplate.getForObject(url.toString(), responseType); } /** @@ -269,7 +269,7 @@ public class TestRestTemplate { */ public ResponseEntity getForEntity(URI url, Class responseType) throws RestClientException { - return this.restTemplate.getForEntity(url, responseType); + return this.restTemplate.getForEntity(url.toString(), responseType); } /** @@ -310,7 +310,7 @@ public class TestRestTemplate { * @see RestTemplate#headForHeaders(java.net.URI) */ public HttpHeaders headForHeaders(URI url) throws RestClientException { - return this.restTemplate.headForHeaders(url); + return this.restTemplate.headForHeaders(url.toString()); } /** @@ -374,7 +374,7 @@ public class TestRestTemplate { * @see RestTemplate#postForLocation(java.net.URI, java.lang.Object) */ public URI postForLocation(URI url, Object request) throws RestClientException { - return this.restTemplate.postForLocation(url, request); + return this.restTemplate.postForLocation(url.toString(), request); } /** @@ -442,7 +442,7 @@ public class TestRestTemplate { */ public T postForObject(URI url, Object request, Class responseType) throws RestClientException { - return this.restTemplate.postForObject(url, request, responseType); + return this.restTemplate.postForObject(url.toString(), request, responseType); } /** @@ -511,7 +511,7 @@ public class TestRestTemplate { */ public ResponseEntity postForEntity(URI url, Object request, Class responseType) throws RestClientException { - return this.restTemplate.postForEntity(url, request, responseType); + return this.restTemplate.postForEntity(url.toString(), request, responseType); } /** @@ -564,7 +564,7 @@ public class TestRestTemplate { * @see RestTemplate#put(java.net.URI, java.lang.Object) */ public void put(URI url, Object request) throws RestClientException { - this.restTemplate.put(url, request); + this.restTemplate.put(url.toString(), request); } /** @@ -630,7 +630,7 @@ public class TestRestTemplate { */ public T patchForObject(URI url, Object request, Class responseType) throws RestClientException { - return this.restTemplate.patchForObject(url, request, responseType); + return this.restTemplate.patchForObject(url.toString(), request, responseType); } @@ -668,7 +668,7 @@ public class TestRestTemplate { * @see RestTemplate#delete(java.net.URI) */ public void delete(URI url) throws RestClientException { - this.restTemplate.delete(url); + this.restTemplate.delete(url.toString()); } /** @@ -709,7 +709,7 @@ public class TestRestTemplate { * @see RestTemplate#optionsForAllow(java.net.URI) */ public Set optionsForAllow(URI url) throws RestClientException { - return this.restTemplate.optionsForAllow(url); + return this.restTemplate.optionsForAllow(url.toString()); } /** @@ -777,7 +777,8 @@ public class TestRestTemplate { public ResponseEntity exchange(URI url, HttpMethod method, HttpEntity requestEntity, Class responseType) throws RestClientException { - return this.restTemplate.exchange(url, method, requestEntity, responseType); + return this.restTemplate.exchange(url.toString(), method, requestEntity, + responseType); } /** @@ -859,7 +860,8 @@ public class TestRestTemplate { public ResponseEntity exchange(URI url, HttpMethod method, HttpEntity requestEntity, ParameterizedTypeReference responseType) throws RestClientException { - return this.restTemplate.exchange(url, method, requestEntity, responseType); + return this.restTemplate.exchange(url.toString(), method, requestEntity, + responseType); } /** @@ -879,7 +881,8 @@ public class TestRestTemplate { */ public ResponseEntity exchange(RequestEntity requestEntity, Class responseType) throws RestClientException { - return this.restTemplate.exchange(requestEntity, responseType); + return this.restTemplate.exchange( + createRequestEntityWithExpandedUri(requestEntity), responseType); } /** @@ -901,7 +904,8 @@ public class TestRestTemplate { */ public ResponseEntity exchange(RequestEntity requestEntity, ParameterizedTypeReference responseType) throws RestClientException { - return this.restTemplate.exchange(requestEntity, responseType); + return this.restTemplate.exchange( + createRequestEntityWithExpandedUri(requestEntity), responseType); } /** @@ -968,7 +972,8 @@ public class TestRestTemplate { */ public T execute(URI url, HttpMethod method, RequestCallback requestCallback, ResponseExtractor responseExtractor) throws RestClientException { - return this.restTemplate.execute(url, method, requestCallback, responseExtractor); + return this.restTemplate.execute(url.toString(), method, requestCallback, + responseExtractor); } /** @@ -1002,6 +1007,15 @@ public class TestRestTemplate { return testRestTemplate; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + private RequestEntity createRequestEntityWithExpandedUri( + RequestEntity requestEntity) { + URI expandedUri = this.restTemplate.getUriTemplateHandler() + .expand(requestEntity.getUrl().toString()); + return new RequestEntity(requestEntity.getBody(), requestEntity.getHeaders(), + requestEntity.getMethod(), expandedUri, requestEntity.getType()); + } + /** * Options used to customize the Apache Http Client if it is used. */ diff --git a/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java b/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java index 75f25d289d..345b78f1ae 100644 --- a/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java +++ b/spring-boot-test/src/test/java/org/springframework/boot/test/web/client/TestRestTemplateTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.test.web.client; +import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URI; @@ -27,21 +28,33 @@ import org.junit.Test; import org.springframework.boot.test.web.client.TestRestTemplate.CustomHttpComponentsClientHttpRequestFactory; import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption; import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.client.ClientHttpRequestFactory; import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.client.InterceptingClientHttpRequestFactory; import org.springframework.http.client.support.BasicAuthorizationInterceptor; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.MethodCallback; import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriTemplateHandler; +import org.springframework.web.util.UriTemplateHandler; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; /** * Tests for {@link TestRestTemplate}. @@ -49,6 +62,7 @@ import static org.mockito.Mockito.mock; * @author Dave Syer * @author Phillip Webb * @author Stephane Nicoll + * @author Andy Wilkinson */ public class TestRestTemplateTests { @@ -87,6 +101,8 @@ public class TestRestTemplateTests { @Test public void restOperationsAreAvailable() throws Exception { RestTemplate delegate = mock(RestTemplate.class); + given(delegate.getUriTemplateHandler()) + .willReturn(new DefaultUriTemplateHandler()); final TestRestTemplate restTemplate = new TestRestTemplate(delegate); ReflectionUtils.doWithMethods(RestOperations.class, new MethodCallback() { @@ -131,6 +147,10 @@ public class TestRestTemplateTests { if (Class.class.equals(type)) { return Object.class; } + if (RequestEntity.class.equals(type)) { + return new RequestEntity<>(HttpMethod.GET, + new URI("http://localhost")); + } return mock(type); } @@ -195,6 +215,231 @@ public class TestRestTemplateTests { .isSameAs(errorHandler); } + @Test + public void deleteHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.delete(relativeUri); + } + + }); + } + + @Test + public void exchangeWithRequestEntityAndClassHandlesRelativeUris() + throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.exchange( + new RequestEntity<>(HttpMethod.GET, relativeUri), String.class); + } + + }); + } + + @Test + public void exchangeWithRequestEntityAndParameterizedTypeReferenceHandlesRelativeUris() + throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.exchange( + new RequestEntity<>(HttpMethod.GET, relativeUri), + new ParameterizedTypeReference() { + }); + } + + }); + } + + @Test + public void exchangeHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.exchange(relativeUri, HttpMethod.GET, + new HttpEntity(new byte[0]), String.class); + } + + }); + } + + @Test + public void exchangeWithParameterizedTypeReferenceHandlesRelativeUris() + throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.exchange(relativeUri, HttpMethod.GET, + new HttpEntity(new byte[0]), + new ParameterizedTypeReference() { + }); + } + + }); + } + + @Test + public void executeHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.execute(relativeUri, HttpMethod.GET, null, null); + } + + }); + } + + @Test + public void getForEntityHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.getForEntity(relativeUri, String.class); + } + + }); + } + + @Test + public void getForObjectHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.getForObject(relativeUri, String.class); + } + + }); + } + + @Test + public void headForHeadersHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.headForHeaders(relativeUri); + } + + }); + } + + @Test + public void optionsForAllowHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.optionsForAllow(relativeUri); + } + + }); + } + + @Test + public void patchForObjectHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.patchForObject(relativeUri, "hello", String.class); + } + + }); + } + + @Test + public void postForEntityHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.postForEntity(relativeUri, "hello", String.class); + } + + }); + } + + @Test + public void postForLocationHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.postForLocation(relativeUri, "hello"); + } + + }); + } + + @Test + public void postForObjectHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.postForObject(relativeUri, "hello", String.class); + } + + }); + } + + @Test + public void putHandlesRelativeUris() throws IOException { + verifyRelativeUriHandling(new TestRestTemplateCallback() { + + @Override + public void doWithTestRestTemplate(TestRestTemplate testRestTemplate, + URI relativeUri) { + testRestTemplate.put(relativeUri, "hello"); + } + + }); + } + + private void verifyRelativeUriHandling(TestRestTemplateCallback callback) + throws IOException { + ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class); + MockClientHttpRequest request = new MockClientHttpRequest(); + request.setResponse(new MockClientHttpResponse(new byte[0], HttpStatus.OK)); + URI relativeUri = URI.create("a/b/c.txt"); + URI absoluteUri = URI.create("http://localhost:8080/" + relativeUri.toString()); + given(requestFactory.createRequest(eq(absoluteUri), any())).willReturn(request); + RestTemplate delegate = new RestTemplate(); + TestRestTemplate template = new TestRestTemplate(delegate); + delegate.setRequestFactory(requestFactory); + UriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class); + given(uriTemplateHandler.expand(relativeUri.toString(), new Object[0])) + .willReturn(absoluteUri); + template.setUriTemplateHandler(uriTemplateHandler); + callback.doWithTestRestTemplate(template, relativeUri); + verify(requestFactory).createRequest(eq(absoluteUri), any()); + } + private void assertBasicAuthorizationInterceptorCredentials( TestRestTemplate testRestTemplate, String username, String password) { @SuppressWarnings("unchecked") @@ -211,4 +456,10 @@ public class TestRestTemplateTests { } + private static interface TestRestTemplateCallback { + + void doWithTestRestTemplate(TestRestTemplate testRestTemplate, URI relativeUri); + + } + }