From a9263998a179e6e4a7ea54440c12c712ce353ad8 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Sun, 8 Oct 2017 16:09:10 -0700 Subject: [PATCH] Support custom WebTestClient timeouts Update @AutoConfigureWebTestClient to support a custom `timeout` option. See gh-10555 --- .../reactive/AutoConfigureWebTestClient.java | 10 ++++++ .../WebTestClientAutoConfiguration.java | 11 ++++++ .../WebTestClientAutoConfigurationTests.java | 35 ++++++++++++++++--- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/AutoConfigureWebTestClient.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/AutoConfigureWebTestClient.java index e92520419bc..f83789e3041 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/AutoConfigureWebTestClient.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/web/reactive/AutoConfigureWebTestClient.java @@ -22,8 +22,10 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.time.Duration; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.test.autoconfigure.properties.PropertyMapping; import org.springframework.test.web.reactive.server.WebTestClient; /** @@ -38,6 +40,14 @@ import org.springframework.test.web.reactive.server.WebTestClient; @Documented @Inherited @ImportAutoConfiguration +@PropertyMapping("spring.test.webtestclient") public @interface AutoConfigureWebTestClient { + /** + * The timeout duration for the client (in any format handled by + * {@link Duration#parse(CharSequence)}). + * @return the web client timeout + */ + String timeout() default ""; + } 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 51cc7b83b08..8997ebb4bdd 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 @@ -16,6 +16,7 @@ package org.springframework.boot.test.autoconfigure.web.reactive; +import java.time.Duration; import java.util.Collection; import java.util.function.Consumer; @@ -23,12 +24,14 @@ 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.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; @@ -49,10 +52,18 @@ public class WebTestClientAutoConfiguration { public WebTestClient webTestClient(ApplicationContext applicationContext) { WebTestClient.Builder builder = WebTestClient .bindToApplicationContext(applicationContext).configureClient(); + customizeWebTestClient(builder, applicationContext); customizeWebTestClientCodecs(builder, applicationContext); 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 diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java index 31a9b0f6c05..f9a25cff697 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/reactive/WebTestClientAutoConfigurationTests.java @@ -16,6 +16,10 @@ package org.springframework.boot.test.autoconfigure.web.reactive; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.Collections; + import org.junit.After; import org.junit.Test; @@ -24,7 +28,10 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.PropertySource; import org.springframework.http.codec.CodecConfigurer; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.server.WebHandler; @@ -58,12 +65,29 @@ public class WebTestClientAutoConfigurationTests { verify(codecCustomizer).customize(any(CodecConfigurer.class)); } + @Test + public void shouldCustomizeTimeout() throws Exception { + PropertySource propertySource = new MapPropertySource("test", Collections + .singletonMap("spring.test.webtestclient.timeout", (Object) "PT15M")); + load(propertySource, BaseConfiguration.class); + WebTestClient webTestClient = this.context.getBean(WebTestClient.class); + Object duration = ReflectionTestUtils.getField(webTestClient, "timeout"); + assertThat(duration).isEqualTo(Duration.of(15, ChronoUnit.MINUTES)); + } + private void load(Class... config) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(config); - ctx.register(WebTestClientAutoConfiguration.class); - ctx.refresh(); - this.context = ctx; + load(null, config); + } + + private void load(PropertySource propertySource, Class... config) { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + if (propertySource != null) { + context.getEnvironment().getPropertySources().addFirst(propertySource); + } + context.register(config); + context.register(WebTestClientAutoConfiguration.class); + context.refresh(); + this.context = context; } @Configuration @@ -73,6 +97,7 @@ public class WebTestClientAutoConfigurationTests { public WebHandler webHandler() { return mock(WebHandler.class); } + } @Configuration