/*
* 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);
}
}