From 16c52bce8491b4ca88add697f518c44c0f4869c7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 9 Jan 2018 11:16:27 +0000 Subject: [PATCH] Introduce WebTestClientBuilderCustomizer callback Closes gh-11579 --- ...ingBootWebTestClientBuilderCustomizer.java | 81 +++++++++++++++++++ .../WebTestClientAutoConfiguration.java | 51 +++++------- .../WebTestClientBuilderCustomizer.java | 39 +++++++++ 3 files changed, 139 insertions(+), 32 deletions(-) create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/SpringBootWebTestClientBuilderCustomizer.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientBuilderCustomizer.java diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/SpringBootWebTestClientBuilderCustomizer.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/SpringBootWebTestClientBuilderCustomizer.java new file mode 100644 index 0000000000..1847ea1e6f --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/SpringBootWebTestClientBuilderCustomizer.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import java.time.Duration; +import java.util.Collection; +import java.util.function.Consumer; + +import org.springframework.boot.web.codec.CodecCustomizer; +import org.springframework.http.codec.ClientCodecConfigurer; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.test.web.reactive.server.WebTestClient.Builder; +import org.springframework.util.CollectionUtils; +import org.springframework.web.reactive.function.client.ExchangeStrategies; + +/** + * {@link WebTestClientBuilderCustomizer} for a typical Spring Boot application. Usually + * applied automatically via + * {@link AutoConfigureWebTestClient @AutoConfigureWebTestClient}, but may also be used + * directly. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class SpringBootWebTestClientBuilderCustomizer + implements WebTestClientBuilderCustomizer { + + private final Collection codecCustomizers; + + private Duration timeout; + + /** + * Create a new {@code SpringBootWebTestClientBuilderCustomizer} that will configure + * the builder's codecs using the given {@code codecCustomizers}. + * @param codecCustomizers the codec customizers + */ + public SpringBootWebTestClientBuilderCustomizer( + Collection codecCustomizers) { + this.codecCustomizers = codecCustomizers; + } + + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + + @Override + public void customize(Builder builder) { + if (this.timeout != null) { + builder.responseTimeout(this.timeout); + } + customizeWebTestClientCodecs(builder); + } + + private void customizeWebTestClientCodecs(WebTestClient.Builder builder) { + if (!CollectionUtils.isEmpty(this.codecCustomizers)) { + builder.exchangeStrategies(ExchangeStrategies.builder() + .codecs(applyCustomizers(this.codecCustomizers)).build()); + } + } + + private Consumer applyCustomizers( + Collection customizers) { + return (codecs) -> customizers + .forEach((customizer) -> customizer.customize(codecs)); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java index 8997ebb4bd..b5c1aa763f 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 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. @@ -16,68 +16,55 @@ package org.springframework.boot.test.autoconfigure.web.reactive; -import java.time.Duration; import java.util.Collection; -import java.util.function.Consumer; +import java.util.Collections; +import java.util.List; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration; -import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.codec.ClientCodecConfigurer; import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.test.web.reactive.server.WebTestClient.Builder; -import org.springframework.util.CollectionUtils; -import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; /** * Auto-configuration for {@link WebTestClient}. * * @author Stephane Nicoll + * @author Andy Wilkinson * @since 2.0.0 */ @Configuration @ConditionalOnClass({ WebClient.class, WebTestClient.class }) @AutoConfigureAfter(CodecsAutoConfiguration.class) +@EnableConfigurationProperties public class WebTestClientAutoConfiguration { @Bean @ConditionalOnMissingBean - public WebTestClient webTestClient(ApplicationContext applicationContext) { + public WebTestClient webTestClient(ApplicationContext applicationContext, + List customizers) { WebTestClient.Builder builder = WebTestClient .bindToApplicationContext(applicationContext).configureClient(); - customizeWebTestClient(builder, applicationContext); - customizeWebTestClientCodecs(builder, applicationContext); + for (WebTestClientBuilderCustomizer customizer : customizers) { + customizer.customize(builder); + } return builder.build(); } - private void customizeWebTestClient(Builder builder, - ApplicationContext applicationContext) { - Binder.get(applicationContext.getEnvironment()) - .bind("spring.test.webtestclient.timeout", Duration.class) - .ifBound(builder::responseTimeout); - } - - private void customizeWebTestClientCodecs(WebTestClient.Builder builder, - ApplicationContext applicationContext) { - Collection customizers = applicationContext - .getBeansOfType(CodecCustomizer.class).values(); - if (!CollectionUtils.isEmpty(customizers)) { - builder.exchangeStrategies(ExchangeStrategies.builder() - .codecs(applyCustomizers(customizers)).build()); - } - } - - private Consumer applyCustomizers( - Collection customizers) { - return (codecs) -> customizers - .forEach((customizer) -> customizer.customize(codecs)); + @Bean + @ConfigurationProperties(prefix = "spring.test.webtestclient") + public SpringBootWebTestClientBuilderCustomizer springBootWebTestClientBuilderCustomizer( + ObjectProvider> codecCustomizers) { + return new SpringBootWebTestClientBuilderCustomizer( + codecCustomizers.getIfAvailable(Collections::emptyList)); } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientBuilderCustomizer.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientBuilderCustomizer.java new file mode 100644 index 0000000000..d083d73268 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientBuilderCustomizer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2018 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.autoconfigure.web.reactive; + +import org.springframework.test.web.reactive.server.WebTestClient.Builder; + +/** + * A customizer for a {@link Builder}. Any {@code WebTestClientBuilderCustomizer} beans + * found in the application context will be {@link #customize called} to customize the + * auto-configured {@link Builder}. + * + * @author Andy Wilkinson + * @since 2.0.0 + * @see WebTestClientAutoConfiguration + */ +@FunctionalInterface +public interface WebTestClientBuilderCustomizer { + + /** + * Customize the given {@code builder}. + * @param builder the builder + */ + void customize(Builder builder); + +}