From 7eb5f35f2f9bb63037e69bfb8934277b2fe21d0f Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 29 Jul 2021 18:45:53 +0100 Subject: [PATCH] Make WebTestClient creation back off when no HTTP client available Fixes gh-27520 --- ...WebTestClientContextCustomizerFactory.java | 29 ++++++++--- ...omizerWithoutSupportedHttpClientTests.java | 51 +++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerWithoutSupportedHttpClientTests.java diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerFactory.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerFactory.java index 8582af1bb3..e41fab8608 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerFactory.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -29,21 +29,36 @@ import org.springframework.util.ClassUtils; * {@link ContextCustomizerFactory} for {@code WebTestClient}. * * @author Stephane Nicoll + * @author Andy Wilkinson */ class WebTestClientContextCustomizerFactory implements ContextCustomizerFactory { - private static final String WEB_TEST_CLIENT_CLASS = "org.springframework.web.reactive.function.client.WebClient"; + private static final boolean reactorClientPresent; + + private static final boolean jettyClientPresent; + + private static final boolean httpComponentsClientPresent; + + private static final boolean webClientPresent; + + static { + ClassLoader loader = WebTestClientContextCustomizerFactory.class.getClassLoader(); + reactorClientPresent = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", loader); + jettyClientPresent = ClassUtils.isPresent("org.eclipse.jetty.client.HttpClient", loader); + httpComponentsClientPresent = ClassUtils + .isPresent("org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient", loader) + && ClassUtils.isPresent("org.apache.hc.core5.reactive.ReactiveDataConsumer", loader); + webClientPresent = ClassUtils.isPresent("org.springframework.web.reactive.function.client.WebClient", loader); + } @Override public ContextCustomizer createContextCustomizer(Class testClass, List configAttributes) { SpringBootTest springBootTest = TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class); - return (springBootTest != null && isWebClientPresent()) ? new WebTestClientContextCustomizer() : null; - } - - private boolean isWebClientPresent() { - return ClassUtils.isPresent(WEB_TEST_CLIENT_CLASS, getClass().getClassLoader()); + return (springBootTest != null && webClientPresent + && (reactorClientPresent || jettyClientPresent || httpComponentsClientPresent)) + ? new WebTestClientContextCustomizer() : null; } } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerWithoutSupportedHttpClientTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerWithoutSupportedHttpClientTests.java new file mode 100644 index 0000000000..2a83f992ce --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/web/reactive/server/WebTestClientContextCustomizerWithoutSupportedHttpClientTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.web.reactive.server; + +import java.util.Collections; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.testsupport.classpath.ClassPathExclusions; +import org.springframework.test.context.ContextCustomizer; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebTestClientContextCustomizerFactory} when no supported HTTP client + * is on the classpath. + * + * @author Andy Wilkinson + */ +@ClassPathExclusions({ "reactor-netty*.jar", "jetty-client*.jar" }) +public class WebTestClientContextCustomizerWithoutSupportedHttpClientTests { + + @Test + void createContextCustomizerWhenNoSupportedHttpClientIsAvailableShouldReturnNull() { + WebTestClientContextCustomizerFactory contextCustomizerFactory = new WebTestClientContextCustomizerFactory(); + ContextCustomizer contextCustomizer = contextCustomizerFactory.createContextCustomizer(TestClass.class, + Collections.emptyList()); + assertThat(contextCustomizer).isNull(); + } + + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) + private static class TestClass { + + } + +}