/* * Copyright 2012-2017 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 * * http://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.boot.test.web.client; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URI; import java.util.List; import org.apache.http.client.config.RequestConfig; 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.env.MockEnvironment; 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.DefaultUriBuilderFactory; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; /** * Tests for {@link TestRestTemplate}. * * @author Dave Syer * @author Phillip Webb * @author Stephane Nicoll * @author Andy Wilkinson */ public class TestRestTemplateTests { @Test public void fromRestTemplateBuilder() { RestTemplateBuilder builder = mock(RestTemplateBuilder.class); RestTemplate delegate = new RestTemplate(); given(builder.build()).willReturn(delegate); assertThat(new TestRestTemplate(builder).getRestTemplate()).isEqualTo(delegate); } @Test public void simple() { // The Apache client is on the classpath so we get the fully-fledged factory assertThat(new TestRestTemplate().getRestTemplate().getRequestFactory()) .isInstanceOf(HttpComponentsClientHttpRequestFactory.class); } @Test public void authenticated() { assertThat(new TestRestTemplate("user", "password").getRestTemplate() .getRequestFactory()) .isInstanceOf(InterceptingClientHttpRequestFactory.class); } @Test public void options() throws Exception { TestRestTemplate template = new TestRestTemplate( HttpClientOption.ENABLE_REDIRECTS); CustomHttpComponentsClientHttpRequestFactory factory = (CustomHttpComponentsClientHttpRequestFactory) template .getRestTemplate().getRequestFactory(); RequestConfig config = factory.getRequestConfig(); assertThat(config.isRedirectsEnabled()).isTrue(); } @Test public void restOperationsAreAvailable() throws Exception { RestTemplate delegate = mock(RestTemplate.class); given(delegate.getUriTemplateHandler()) .willReturn(new DefaultUriBuilderFactory()); final TestRestTemplate restTemplate = new TestRestTemplate(delegate); ReflectionUtils.doWithMethods(RestOperations.class, new MethodCallback() { @Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { Method equivalent = ReflectionUtils.findMethod(TestRestTemplate.class, method.getName(), method.getParameterTypes()); assertThat(equivalent).as("Method %s not found", method).isNotNull(); assertThat(Modifier.isPublic(equivalent.getModifiers())) .as("Method %s should have been public", equivalent).isTrue(); try { equivalent.invoke(restTemplate, mockArguments(method.getParameterTypes())); } catch (Exception ex) { throw new IllegalStateException(ex); } } private Object[] mockArguments(Class<?>[] parameterTypes) throws Exception { Object[] arguments = new Object[parameterTypes.length]; for (int i = 0; i < parameterTypes.length; i++) { arguments[i] = mockArgument(parameterTypes[i]); } return arguments; } @SuppressWarnings("rawtypes") private Object mockArgument(Class<?> type) throws Exception { if (String.class.equals(type)) { return "String"; } if (Object[].class.equals(type)) { return new Object[0]; } if (URI.class.equals(type)) { return new URI("http://localhost"); } if (HttpMethod.class.equals(type)) { return HttpMethod.GET; } 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); } }, new ReflectionUtils.MethodFilter() { @Override public boolean matches(Method method) { return Modifier.isPublic(method.getModifiers()); } }); } @Test public void withBasicAuthAddsBasicAuthInterceptorWhenNotAlreadyPresent() { TestRestTemplate originalTemplate = new TestRestTemplate(); TestRestTemplate basicAuthTemplate = originalTemplate.withBasicAuth("user", "password"); assertThat(basicAuthTemplate.getRestTemplate().getMessageConverters()) .containsExactlyElementsOf( originalTemplate.getRestTemplate().getMessageConverters()); assertThat(basicAuthTemplate.getRestTemplate().getRequestFactory()) .isInstanceOf(InterceptingClientHttpRequestFactory.class); assertThat(ReflectionTestUtils.getField( basicAuthTemplate.getRestTemplate().getRequestFactory(), "requestFactory")) .isInstanceOf(CustomHttpComponentsClientHttpRequestFactory.class); assertThat(basicAuthTemplate.getRestTemplate().getUriTemplateHandler()) .isSameAs(originalTemplate.getRestTemplate().getUriTemplateHandler()); assertThat(basicAuthTemplate.getRestTemplate().getInterceptors()).hasSize(1); assertBasicAuthorizationInterceptorCredentials(basicAuthTemplate, "user", "password"); } @Test public void withBasicAuthReplacesBasicAuthInterceptorWhenAlreadyPresent() { TestRestTemplate original = new TestRestTemplate("foo", "bar") .withBasicAuth("replace", "replace"); TestRestTemplate basicAuth = original.withBasicAuth("user", "password"); assertThat(basicAuth.getRestTemplate().getMessageConverters()) .containsExactlyElementsOf( original.getRestTemplate().getMessageConverters()); assertThat(basicAuth.getRestTemplate().getRequestFactory()) .isInstanceOf(InterceptingClientHttpRequestFactory.class); assertThat(ReflectionTestUtils.getField( basicAuth.getRestTemplate().getRequestFactory(), "requestFactory")) .isInstanceOf(CustomHttpComponentsClientHttpRequestFactory.class); assertThat(basicAuth.getRestTemplate().getUriTemplateHandler()) .isSameAs(original.getRestTemplate().getUriTemplateHandler()); assertThat(basicAuth.getRestTemplate().getInterceptors()).hasSize(1); assertBasicAuthorizationInterceptorCredentials(basicAuth, "user", "password"); } @Test public void withBasicAuthDoesNotResetErrorHandler() throws Exception { TestRestTemplate originalTemplate = new TestRestTemplate("foo", "bar"); ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class); originalTemplate.getRestTemplate().setErrorHandler(errorHandler); TestRestTemplate basicAuthTemplate = originalTemplate.withBasicAuth("user", "password"); assertThat(basicAuthTemplate.getRestTemplate().getErrorHandler()) .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<String>(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<String>(HttpMethod.GET, relativeUri), new ParameterizedTypeReference<String>() { }); } }); } @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<String>() { }); } }); } @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 absoluteUri = URI .create("http://localhost:8080/a/b/c.txt?param=%7Bsomething%7D"); given(requestFactory.createRequest(eq(absoluteUri), (HttpMethod) any())) .willReturn(request); RestTemplate delegate = new RestTemplate(); TestRestTemplate template = new TestRestTemplate(delegate); delegate.setRequestFactory(requestFactory); LocalHostUriTemplateHandler uriTemplateHandler = new LocalHostUriTemplateHandler( new MockEnvironment()); template.setUriTemplateHandler(uriTemplateHandler); callback.doWithTestRestTemplate(template, URI.create("/a/b/c.txt?param=%7Bsomething%7D")); verify(requestFactory).createRequest(eq(absoluteUri), (HttpMethod) any()); } private void assertBasicAuthorizationInterceptorCredentials( TestRestTemplate testRestTemplate, String username, String password) { @SuppressWarnings("unchecked") List<ClientHttpRequestInterceptor> requestFactoryInterceptors = (List<ClientHttpRequestInterceptor>) ReflectionTestUtils .getField(testRestTemplate.getRestTemplate().getRequestFactory(), "interceptors"); assertThat(requestFactoryInterceptors).hasSize(1); ClientHttpRequestInterceptor interceptor = requestFactoryInterceptors.get(0); assertThat(interceptor).isInstanceOf(BasicAuthorizationInterceptor.class); assertThat(ReflectionTestUtils.getField(interceptor, "username")) .isEqualTo(username); assertThat(ReflectionTestUtils.getField(interceptor, "password")) .isEqualTo(password); } private interface TestRestTemplateCallback { void doWithTestRestTemplate(TestRestTemplate testRestTemplate, URI relativeUri); } }