001/*
002 * Copyright 2012-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.test.autoconfigure.web.client;
018
019import java.io.IOException;
020import java.lang.reflect.Constructor;
021import java.util.Map;
022
023import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
024import org.springframework.boot.test.web.client.MockServerRestTemplateCustomizer;
025import org.springframework.context.annotation.Bean;
026import org.springframework.context.annotation.Configuration;
027import org.springframework.http.client.ClientHttpRequest;
028import org.springframework.http.client.ClientHttpResponse;
029import org.springframework.test.web.client.ExpectedCount;
030import org.springframework.test.web.client.MockRestServiceServer;
031import org.springframework.test.web.client.RequestExpectationManager;
032import org.springframework.test.web.client.RequestMatcher;
033import org.springframework.test.web.client.ResponseActions;
034import org.springframework.util.Assert;
035import org.springframework.web.client.RestTemplate;
036
037/**
038 * Auto-configuration for {@link MockRestServiceServer} support.
039 *
040 * @author Phillip Webb
041 * @since 1.4.0
042 * @see AutoConfigureMockRestServiceServer
043 */
044@Configuration
045@ConditionalOnProperty(prefix = "spring.test.webclient.mockrestserviceserver", name = "enabled")
046public class MockRestServiceServerAutoConfiguration {
047
048        @Bean
049        public MockServerRestTemplateCustomizer mockServerRestTemplateCustomizer() {
050                return new MockServerRestTemplateCustomizer();
051        }
052
053        @Bean
054        public MockRestServiceServer mockRestServiceServer(
055                        MockServerRestTemplateCustomizer customizer) {
056                try {
057                        return createDeferredMockRestServiceServer(customizer);
058                }
059                catch (Exception ex) {
060                        throw new IllegalStateException(ex);
061                }
062        }
063
064        private MockRestServiceServer createDeferredMockRestServiceServer(
065                        MockServerRestTemplateCustomizer customizer) throws Exception {
066                Constructor<MockRestServiceServer> constructor = MockRestServiceServer.class
067                                .getDeclaredConstructor(RequestExpectationManager.class);
068                constructor.setAccessible(true);
069                return constructor.newInstance(new DeferredRequestExpectationManager(customizer));
070        }
071
072        /**
073         * {@link RequestExpectationManager} with the injected {@link MockRestServiceServer}
074         * so that the bean can be created before the
075         * {@link MockServerRestTemplateCustomizer#customize(RestTemplate)
076         * MockServerRestTemplateCustomizer} has been called.
077         */
078        private static class DeferredRequestExpectationManager
079                        implements RequestExpectationManager {
080
081                private MockServerRestTemplateCustomizer customizer;
082
083                DeferredRequestExpectationManager(MockServerRestTemplateCustomizer customizer) {
084                        this.customizer = customizer;
085                }
086
087                @Override
088                public ResponseActions expectRequest(ExpectedCount count,
089                                RequestMatcher requestMatcher) {
090                        return getDelegate().expectRequest(count, requestMatcher);
091                }
092
093                @Override
094                public ClientHttpResponse validateRequest(ClientHttpRequest request)
095                                throws IOException {
096                        return getDelegate().validateRequest(request);
097                }
098
099                @Override
100                public void verify() {
101                        getDelegate().verify();
102                }
103
104                @Override
105                public void reset() {
106                        Map<RestTemplate, RequestExpectationManager> expectationManagers = this.customizer
107                                        .getExpectationManagers();
108                        if (expectationManagers.size() == 1) {
109                                getDelegate().reset();
110                        }
111                }
112
113                private RequestExpectationManager getDelegate() {
114                        Map<RestTemplate, RequestExpectationManager> expectationManagers = this.customizer
115                                        .getExpectationManagers();
116                        Assert.state(!expectationManagers.isEmpty(),
117                                        "Unable to use auto-configured MockRestServiceServer since "
118                                                        + "MockServerRestTemplateCustomizer has not been bound to "
119                                                        + "a RestTemplate");
120                        Assert.state(expectationManagers.size() == 1,
121                                        "Unable to use auto-configured MockRestServiceServer since "
122                                                        + "MockServerRestTemplateCustomizer has been bound to "
123                                                        + "more than one RestTemplate");
124                        return expectationManagers.values().iterator().next();
125                }
126
127        }
128
129}