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}