/*
* 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.web.client;
import java.util.Collections;
import java.util.Set;
import org.apache.http.client.config.RequestConfig;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.support.BasicAuthorizationInterceptor;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriTemplateHandler;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
/**
* Tests for {@link RestTemplateBuilder}.
*
* @author Stephane Nicoll
* @author Phillip Webb
* @author Andy Wilkinson
*/
public class RestTemplateBuilderTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private RestTemplateBuilder builder = new RestTemplateBuilder();
@Mock
private HttpMessageConverter<Object> messageConverter;
@Mock
private ClientHttpRequestInterceptor interceptor;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void createWhenCustomizersAreNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Customizers must not be null");
RestTemplateCustomizer[] customizers = null;
new RestTemplateBuilder(customizers);
}
@Test
public void createWithCustomizersShouldApplyCustomizers() throws Exception {
RestTemplateCustomizer customizer = mock(RestTemplateCustomizer.class);
RestTemplate template = new RestTemplateBuilder(customizer).build();
verify(customizer).customize(template);
}
@Test
public void buildShouldDetectRequestFactory() throws Exception {
RestTemplate restTemplate = this.builder.build();
assertThat(restTemplate.getRequestFactory())
.isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
}
@Test
public void detectRequestFactoryWhenFalseShouldDisableDetection() throws Exception {
RestTemplate restTemplate = this.builder.detectRequestFactory(false).build();
assertThat(restTemplate.getRequestFactory())
.isInstanceOf(SimpleClientHttpRequestFactory.class);
}
@Test
public void rootUriShouldApply() throws Exception {
RestTemplate restTemplate = this.builder.rootUri("http://example.com").build();
MockRestServiceServer server = MockRestServiceServer.bindTo(restTemplate).build();
server.expect(requestTo("http://example.com/hello")).andRespond(withSuccess());
restTemplate.getForEntity("/hello", String.class);
server.verify();
}
@Test
public void rootUriShouldApplyAfterUriTemplateHandler() throws Exception {
UriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class);
RestTemplate template = this.builder.uriTemplateHandler(uriTemplateHandler)
.rootUri("http://example.com").build();
UriTemplateHandler handler = template.getUriTemplateHandler();
handler.expand("/hello");
assertThat(handler).isInstanceOf(RootUriTemplateHandler.class);
verify(uriTemplateHandler).expand("http://example.com/hello");
}
@Test
public void messageConvertersWhenConvertersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("MessageConverters must not be null");
this.builder.messageConverters((HttpMessageConverter<?>[]) null);
}
@Test
public void messageConvertersCollectionWhenConvertersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("MessageConverters must not be null");
this.builder.messageConverters((Set<HttpMessageConverter<?>>) null);
}
@Test
public void messageConvertersShouldApply() throws Exception {
RestTemplate template = this.builder.messageConverters(this.messageConverter)
.build();
assertThat(template.getMessageConverters()).containsOnly(this.messageConverter);
}
@Test
public void messageConvertersShouldReplaceExisting() throws Exception {
RestTemplate template = this.builder
.messageConverters(new ResourceHttpMessageConverter())
.messageConverters(Collections.singleton(this.messageConverter)).build();
assertThat(template.getMessageConverters()).containsOnly(this.messageConverter);
}
@Test
public void additionalMessageConvertersWhenConvertersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("MessageConverters must not be null");
this.builder.additionalMessageConverters((HttpMessageConverter<?>[]) null);
}
@Test
public void additionalMessageConvertersCollectionWhenConvertersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("MessageConverters must not be null");
this.builder.additionalMessageConverters((Set<HttpMessageConverter<?>>) null);
}
@Test
public void additionalMessageConvertersShouldAddToExisting() throws Exception {
HttpMessageConverter<?> resourceConverter = new ResourceHttpMessageConverter();
RestTemplate template = this.builder.messageConverters(resourceConverter)
.additionalMessageConverters(this.messageConverter).build();
assertThat(template.getMessageConverters()).containsOnly(resourceConverter,
this.messageConverter);
}
@Test
public void defaultMessageConvertersShouldSetDefaultList() throws Exception {
RestTemplate template = new RestTemplate(
Collections.<HttpMessageConverter<?>>singletonList(
new StringHttpMessageConverter()));
this.builder.defaultMessageConverters().configure(template);
assertThat(template.getMessageConverters())
.hasSameSizeAs(new RestTemplate().getMessageConverters());
}
@Test
public void defaultMessageConvertersShouldClearExisting() throws Exception {
RestTemplate template = new RestTemplate(
Collections.<HttpMessageConverter<?>>singletonList(
new StringHttpMessageConverter()));
this.builder.additionalMessageConverters(this.messageConverter)
.defaultMessageConverters().configure(template);
assertThat(template.getMessageConverters())
.hasSameSizeAs(new RestTemplate().getMessageConverters());
}
@Test
public void interceptorsWhenInterceptorsAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("interceptors must not be null");
this.builder.interceptors((ClientHttpRequestInterceptor[]) null);
}
@Test
public void interceptorsCollectionWhenInterceptorsAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("interceptors must not be null");
this.builder.interceptors((Set<ClientHttpRequestInterceptor>) null);
}
@Test
public void interceptorsShouldApply() throws Exception {
RestTemplate template = this.builder.interceptors(this.interceptor).build();
assertThat(template.getInterceptors()).containsOnly(this.interceptor);
}
@Test
public void interceptorsShouldReplaceExisting() throws Exception {
RestTemplate template = this.builder
.interceptors(mock(ClientHttpRequestInterceptor.class))
.interceptors(Collections.singleton(this.interceptor)).build();
assertThat(template.getInterceptors()).containsOnly(this.interceptor);
}
@Test
public void additionalInterceptorsWhenInterceptorsAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("interceptors must not be null");
this.builder.additionalInterceptors((ClientHttpRequestInterceptor[]) null);
}
@Test
public void additionalInterceptorsCollectionWhenInterceptorsAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("interceptors must not be null");
this.builder.additionalInterceptors((Set<ClientHttpRequestInterceptor>) null);
}
@Test
public void additionalInterceptorsShouldAddToExisting() throws Exception {
ClientHttpRequestInterceptor interceptor = mock(
ClientHttpRequestInterceptor.class);
RestTemplate template = this.builder.interceptors(interceptor)
.additionalInterceptors(this.interceptor).build();
assertThat(template.getInterceptors()).containsOnly(interceptor,
this.interceptor);
}
@Test
public void requestFactoryClassWhenFactoryIsNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RequestFactory must not be null");
this.builder.requestFactory((Class<ClientHttpRequestFactory>) null);
}
@Test
public void requestFactoryClassShouldApply() throws Exception {
RestTemplate template = this.builder
.requestFactory(SimpleClientHttpRequestFactory.class).build();
assertThat(template.getRequestFactory())
.isInstanceOf(SimpleClientHttpRequestFactory.class);
}
@Test
public void requestFactoryPackagePrivateClassShouldApply() throws Exception {
RestTemplate template = this.builder
.requestFactory(TestClientHttpRequestFactory.class).build();
assertThat(template.getRequestFactory())
.isInstanceOf(TestClientHttpRequestFactory.class);
}
@Test
public void requestFactoryWhenFactoryIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RequestFactory must not be null");
this.builder.requestFactory((ClientHttpRequestFactory) null);
}
@Test
public void requestFactoryShouldApply() throws Exception {
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
RestTemplate template = this.builder.requestFactory(requestFactory).build();
assertThat(template.getRequestFactory()).isSameAs(requestFactory);
}
@Test
public void uriTemplateHandlerWhenHandlerIsNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("UriTemplateHandler must not be null");
this.builder.uriTemplateHandler(null);
}
@Test
public void uriTemplateHandlerShouldApply() throws Exception {
UriTemplateHandler uriTemplateHandler = mock(UriTemplateHandler.class);
RestTemplate template = this.builder.uriTemplateHandler(uriTemplateHandler)
.build();
assertThat(template.getUriTemplateHandler()).isSameAs(uriTemplateHandler);
}
@Test
public void errorHandlerWhenHandlerIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("ErrorHandler must not be null");
this.builder.errorHandler(null);
}
@Test
public void errorHandlerShouldApply() throws Exception {
ResponseErrorHandler errorHandler = mock(ResponseErrorHandler.class);
RestTemplate template = this.builder.errorHandler(errorHandler).build();
assertThat(template.getErrorHandler()).isSameAs(errorHandler);
}
@Test
public void basicAuthorizationShouldApply() throws Exception {
RestTemplate template = this.builder.basicAuthorization("spring", "boot").build();
ClientHttpRequestInterceptor interceptor = template.getInterceptors().get(0);
assertThat(interceptor).isInstanceOf(BasicAuthorizationInterceptor.class);
assertThat(interceptor).extracting("username").containsExactly("spring");
assertThat(interceptor).extracting("password").containsExactly("boot");
}
@Test
public void customizersWhenCustomizersAreNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RestTemplateCustomizers must not be null");
this.builder.customizers((RestTemplateCustomizer[]) null);
}
@Test
public void customizersCollectionWhenCustomizersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RestTemplateCustomizers must not be null");
this.builder.customizers((Set<RestTemplateCustomizer>) null);
}
@Test
public void customizersShouldApply() throws Exception {
RestTemplateCustomizer customizer = mock(RestTemplateCustomizer.class);
RestTemplate template = this.builder.customizers(customizer).build();
verify(customizer).customize(template);
}
@Test
public void customizersShouldBeAppliedLast() throws Exception {
RestTemplate template = spy(new RestTemplate());
this.builder.additionalCustomizers(new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
verify(restTemplate).setRequestFactory((ClientHttpRequestFactory) any());
}
});
this.builder.configure(template);
}
@Test
public void customizersShouldReplaceExisting() throws Exception {
RestTemplateCustomizer customizer1 = mock(RestTemplateCustomizer.class);
RestTemplateCustomizer customizer2 = mock(RestTemplateCustomizer.class);
RestTemplate template = this.builder.customizers(customizer1)
.customizers(Collections.singleton(customizer2)).build();
verifyZeroInteractions(customizer1);
verify(customizer2).customize(template);
}
@Test
public void additionalCustomizersWhenCustomizersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RestTemplateCustomizers must not be null");
this.builder.additionalCustomizers((RestTemplateCustomizer[]) null);
}
@Test
public void additionalCustomizersCollectionWhenCustomizersAreNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("RestTemplateCustomizers must not be null");
this.builder.additionalCustomizers((Set<RestTemplateCustomizer>) null);
}
@Test
public void additionalCustomizersShouldAddToExisting() throws Exception {
RestTemplateCustomizer customizer1 = mock(RestTemplateCustomizer.class);
RestTemplateCustomizer customizer2 = mock(RestTemplateCustomizer.class);
RestTemplate template = this.builder.customizers(customizer1)
.additionalCustomizers(customizer2).build();
verify(customizer1).customize(template);
verify(customizer2).customize(template);
}
@Test
public void buildShouldReturnRestTemplate() throws Exception {
RestTemplate template = this.builder.build();
assertThat(template.getClass()).isEqualTo(RestTemplate.class);
}
@Test
public void buildClassShouldReturnClassInstance() throws Exception {
RestTemplateSubclass template = this.builder.build(RestTemplateSubclass.class);
assertThat(template.getClass()).isEqualTo(RestTemplateSubclass.class);
}
@Test
public void configureShouldApply() throws Exception {
RestTemplate template = new RestTemplate();
this.builder.configure(template);
assertThat(template.getRequestFactory())
.isInstanceOf(HttpComponentsClientHttpRequestFactory.class);
}
@Test
public void connectTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(HttpComponentsClientHttpRequestFactory.class)
.setConnectTimeout(1234).build().getRequestFactory();
assertThat(((RequestConfig) ReflectionTestUtils.getField(requestFactory,
"requestConfig")).getConnectTimeout()).isEqualTo(1234);
}
@Test
public void readTimeoutCanBeConfiguredOnHttpComponentsRequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(HttpComponentsClientHttpRequestFactory.class)
.setReadTimeout(1234).build().getRequestFactory();
assertThat(((RequestConfig) ReflectionTestUtils.getField(requestFactory,
"requestConfig")).getSocketTimeout()).isEqualTo(1234);
}
@Test
public void connectTimeoutCanBeConfiguredOnSimpleRequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(SimpleClientHttpRequestFactory.class)
.setConnectTimeout(1234).build().getRequestFactory();
assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout"))
.isEqualTo(1234);
}
@Test
public void readTimeoutCanBeConfiguredOnSimpleRequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(SimpleClientHttpRequestFactory.class).setReadTimeout(1234)
.build().getRequestFactory();
assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout"))
.isEqualTo(1234);
}
@Test
public void connectTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(OkHttp3ClientHttpRequestFactory.class)
.setConnectTimeout(1234).build().getRequestFactory();
assertThat(ReflectionTestUtils.getField(
ReflectionTestUtils.getField(requestFactory, "client"), "connectTimeout"))
.isEqualTo(1234);
}
@Test
public void readTimeoutCanBeConfiguredOnOkHttp3RequestFactory() {
ClientHttpRequestFactory requestFactory = this.builder
.requestFactory(OkHttp3ClientHttpRequestFactory.class)
.setReadTimeout(1234).build().getRequestFactory();
assertThat(ReflectionTestUtils.getField(
ReflectionTestUtils.getField(requestFactory, "client"), "readTimeout"))
.isEqualTo(1234);
}
@Test
public void connectTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
.setConnectTimeout(1234).build();
assertThat(ReflectionTestUtils.getField(requestFactory, "connectTimeout"))
.isEqualTo(1234);
}
@Test
public void readTimeoutCanBeConfiguredOnAWrappedRequestFactory() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
this.builder.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
.setReadTimeout(1234).build();
assertThat(ReflectionTestUtils.getField(requestFactory, "readTimeout"))
.isEqualTo(1234);
}
@Test
public void unwrappingDoesNotAffectRequestFactoryThatIsSetOnTheBuiltTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
RestTemplate template = this.builder
.requestFactory(new BufferingClientHttpRequestFactory(requestFactory))
.build();
assertThat(template.getRequestFactory())
.isInstanceOf(BufferingClientHttpRequestFactory.class);
}
public static class RestTemplateSubclass extends RestTemplate {
}
static class TestClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
}
}