Browse Source

Replace `BaseUrl` with `LocalTestWebServer`

Replace `BaseUrl` and `BaseUrlProvider` provider code with a more
targeted `LocalTestWebServer` class.

The `LocalTestWebServer` can be used to obtain the url of the locally
running server, or provide `UriBuilderFactory` or `UriBuilder`
instances base on it.

This commit also updates the MockMVC HTML Unit auto-configuration to
directly use `localhost` as the base URL.

Closes gh-47680
pull/47721/head
Phillip Webb 2 months ago
parent
commit
41a399c5ae
  1. 80
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/client/BaseUrlUriBuilderFactory.java
  2. 96
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrl.java
  3. 40
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrlProvider.java
  4. 72
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrlProviders.java
  5. 66
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LazyUriBuilderFactory.java
  6. 240
      core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LocalTestWebServer.java
  7. 65
      core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/BaseUrlWebConnectionHtmlUnitDriver.java
  8. 24
      core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClient.java
  9. 67
      core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriver.java
  10. 68
      core/spring-boot-test/src/test/java/org/springframework/boot/test/http/client/BaseUrlUriBuilderFactoryTests.java
  11. 57
      core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/BaseUrlProvidersTests.java
  12. 104
      core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/BaseUrlTests.java
  13. 216
      core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/LocalTestWebServerTests.java
  14. 26
      core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClientTests.java
  15. 35
      core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriverTests.java
  16. 18
      module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfiguration.java
  17. 19
      module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfigurationTests.java
  18. 10
      module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientAutoConfiguration.java
  19. 22
      module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/TestRestTemplateAutoConfiguration.java
  20. 8
      module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/TestRestTemplateTests.java
  21. 25
      module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientAutoConfigurationTests.java
  22. 21
      module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextLocalTestWebServerProvider.java
  23. 21
      module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextLocalTestWebServerProvider.java
  24. 9
      module/spring-boot-web-server/src/main/resources/META-INF/spring.factories
  25. 9
      module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebClientAutoConfiguration.java
  26. 12
      module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebDriverAutoConfiguration.java
  27. 10
      module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/WebTestClientAutoConfiguration.java
  28. 28
      module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfigurationTests.java
  29. 8
      smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/AbstractSampleActuatorCustomSecurityTests.java
  30. 8
      smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/CorsSampleActuatorApplicationTests.java
  31. 8
      smoke-test/spring-boot-smoke-test-actuator-extension/src/test/java/smoketest/actuator/extension/SampleActuatorExtensionApplicationTests.java
  32. 8
      smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/CorsSampleActuatorApplicationTests.java

80
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/client/BaseUrlUriBuilderFactory.java

@ -1,80 +0,0 @@ @@ -1,80 +0,0 @@
/*
* Copyright 2012-present 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.http.client;
import java.net.URI;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.util.Assert;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
import org.springframework.web.util.UriComponentsBuilder;
/**
* {@link UriBuilderFactory} to support {@link BaseUrl}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
public final class BaseUrlUriBuilderFactory implements UriBuilderFactory {
private final BaseUrl baseUrl;
/**
* Create a new {@link BaseUrlUriBuilderFactory} instance.
* @param baseUrl the base URL to use
*/
BaseUrlUriBuilderFactory(BaseUrl baseUrl) {
Assert.notNull(baseUrl, "'baseUrl' must not be null");
this.baseUrl = baseUrl;
}
/**
* Get a {@link UriBuilderFactory} instance applying the given {@code baseUrl}.
* @param baseUrl the base URL to apply or {@code null}
* @return a factory for the given base URL
*/
public static UriBuilderFactory get(@Nullable BaseUrl baseUrl) {
return (baseUrl != null) ? new BaseUrlUriBuilderFactory(baseUrl) : new DefaultUriBuilderFactory();
}
@Override
public UriBuilder uriString(String uriTemplate) {
return this.baseUrl.getUriBuilderFactory().uriString(uriTemplate);
}
@Override
public UriBuilder builder() {
return UriComponentsBuilder.newInstance();
}
@Override
public URI expand(String uriTemplate, Map<String, ?> uriVariables) {
return this.baseUrl.getUriBuilderFactory().expand(uriTemplate, uriVariables);
}
@Override
public URI expand(String uriTemplate, @Nullable Object... uriVariables) {
return this.baseUrl.getUriBuilderFactory().expand(uriTemplate, uriVariables);
}
}

96
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrl.java

@ -1,96 +0,0 @@ @@ -1,96 +0,0 @@
/*
* Copyright 2012-present 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.http.server;
import java.util.function.Supplier;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilderFactory;
/**
* A base URL that can be used to connect to the running server.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
public final class BaseUrl {
/**
* {@link BaseUrl} that resolves to {@code http://localhost}.
*/
public static final BaseUrl LOCALHOST = BaseUrl.of("http://localhost");
private final boolean https;
private final Supplier<String> resolver;
private BaseUrl(boolean https, Supplier<String> resolver) {
this.https = https;
this.resolver = SingletonSupplier.of(resolver);
}
/**
* Return if the URL will ultimately resolve to an HTTPS address.
* @return if the URL is HTTPS
*/
public boolean isHttps() {
return this.https;
}
/**
* Get a {@link UriBuilderFactory} that applies the base URL.
* @return a {@link UriBuilderFactory}
*/
public UriBuilderFactory getUriBuilderFactory() {
return new DefaultUriBuilderFactory(this.resolver.get());
}
/**
* Return a new instance that applies the given {@code path}.
* @param path a path to append
* @return a new instance with the path added
*/
public BaseUrl withPath(String path) {
return new BaseUrl(this.https, () -> this.resolver.get() + path);
}
/**
* Factory method to create a new {@link BaseUrl}.
* @param url the URL to use
* @return a new {@link BaseUrl} instance
*/
public static BaseUrl of(String url) {
Assert.notNull(url, "'url' must not be null");
return of(StringUtils.startsWithIgnoreCase(url, "https"), () -> url);
}
/**
* Factory method to create a new {@link BaseUrl}.
* @param https whether the base URL is https
* @param resolver the resolver used to supply the actual URL
* @return a new {@link BaseUrl} instance
*/
public static BaseUrl of(boolean https, Supplier<String> resolver) {
Assert.notNull(resolver, "'resolver' must not be null");
return new BaseUrl(https, resolver);
}
}

40
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrlProvider.java

@ -1,40 +0,0 @@ @@ -1,40 +0,0 @@
/*
* Copyright 2012-present 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.http.server;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationContext;
/**
* Strategy used to provide the base URL that can be used to connect to the running
* server. Implementations can be registered in {@code spring.factories} and may accept an
* {@link ApplicationContext} constructor argument.
*
* @author Phillip Webb
* @since 4.0.0
*/
@FunctionalInterface
public interface BaseUrlProvider {
/**
* Return the base URL that can be used to connect to the running server.
* @return the base URL or {@code null}
*/
@Nullable BaseUrl getBaseUrl();
}

72
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/BaseUrlProviders.java

@ -1,72 +0,0 @@ @@ -1,72 +0,0 @@
/*
* Copyright 2012-present 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.http.server;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
/**
* A collection of {@link BaseUrlProvider} instances loaded from {@code spring.factories}.
*
* @author Phillip Webb
* @since 4.0.0
*/
public class BaseUrlProviders {
private List<BaseUrlProvider> providers;
public BaseUrlProviders(ApplicationContext applicationContext) {
Assert.notNull(applicationContext, "'applicationContext' must not be null");
this.providers = SpringFactoriesLoader.forDefaultResourceLocation(applicationContext.getClassLoader())
.load(BaseUrlProvider.class, ArgumentResolver.of(ApplicationContext.class, applicationContext));
}
BaseUrlProviders(List<BaseUrlProvider> providers) {
this.providers = providers;
}
/**
* Return the provided {@link BaseUrl} or {@code null}.
* @return the base URL or {@code null}
*/
public @Nullable BaseUrl getBaseUrl() {
return getBaseUrl(null);
}
/**
* Return the provided {@link BaseUrl} or the given fallback.
* @param fallback the fallback
* @return the base URL or the fallback
*/
@Contract("!null -> !null")
public @Nullable BaseUrl getBaseUrl(@Nullable BaseUrl fallback) {
return this.providers.stream()
.map(BaseUrlProvider::getBaseUrl)
.filter(Objects::nonNull)
.findFirst()
.orElse(fallback);
}
}

66
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LazyUriBuilderFactory.java

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/*
* Copyright 2012-present 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.http.server;
import java.net.URI;
import java.util.Map;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
/**
* Lazy {@link UriBuilderFactory} that only obtains the delegate on first call.
*
* @author Phillip Webb
*/
class LazyUriBuilderFactory implements UriBuilderFactory {
private final Supplier<UriBuilderFactory> suppler;
LazyUriBuilderFactory(Supplier<UriBuilderFactory> supplier) {
this.suppler = SingletonSupplier.of(supplier);
}
@Override
public URI expand(String uriTemplate, Map<String, ? extends @Nullable Object> uriVariables) {
return delegate().expand(uriTemplate, uriVariables);
}
@Override
public URI expand(String uriTemplate, @Nullable Object... uriVariables) {
return delegate().expand(uriTemplate, uriVariables);
}
@Override
public UriBuilder uriString(String uriTemplate) {
return delegate().uriString(uriTemplate);
}
@Override
public UriBuilder builder() {
return delegate().builder();
}
private UriBuilderFactory delegate() {
return this.suppler.get();
}
}

240
core/spring-boot-test/src/main/java/org/springframework/boot/test/http/server/LocalTestWebServer.java

@ -0,0 +1,240 @@ @@ -0,0 +1,240 @@
/*
* Copyright 2012-present 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.http.server;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Supplier;
import org.jspecify.annotations.Nullable;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
/**
* Provides details of a locally running test web server which may have been started on a
* dynamic port.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
public final class LocalTestWebServer {
private final Scheme scheme;
private final SingletonSupplier<Connection> connection;
private LocalTestWebServer(Scheme scheme, Supplier<Connection> connectionSupplier) {
Assert.notNull(scheme, "'scheme' must not be null");
Assert.notNull(connectionSupplier, "'connectionSupplier' must not be null");
this.scheme = scheme;
this.connection = SingletonSupplier.of(connectionSupplier);
}
/**
* Return if URI scheme used for the connection. This method can be safely called
* before the local test server is fully running.
* @return if the web server uses an HTTPS address
*/
public Scheme scheme() {
return this.scheme;
}
/**
* Return the URI of the running local test server. This method should only be called
* once the local test server is fully running.
* @return the URI of the server
*/
public String uri() {
return uri(null);
}
/**
* Return the URI of the running local test server taking into account the given
* {@code uri}. This method should only be called once the local test server is fully
* running.
* @param uri a URI template for the builder or {@code null}
* @return the URI of the server
*/
public String uri(@Nullable String uri) {
return uriBuilder(uri).toUriString();
}
/**
* Return a new {@link UriBuilder} with the base URI template initialized from the
* local server {@link #uri()}. This method should only be called once the local test
* server is fully running.
* @param uri a URI template for the builder or {@code null}
* @return a new {@link UriBuilder} instance
*/
public UriBuilder uriBuilder(@Nullable String uri) {
UriBuilderFactory factory = uriBuilderFactory();
return (uri != null) ? factory.uriString(uri) : factory.builder();
}
/**
* Return a new {@link UriBuilderFactory} with the base URI template initialized from
* the local server {@link #uri()}. Methods of the return UriBuilderFactory should
* only be called once the local test server is fully running.
* @return a new {@link UriBuilderFactory}
*/
public UriBuilderFactory uriBuilderFactory() {
return new LazyUriBuilderFactory(() -> new DefaultUriBuilderFactory(getConnection().uri(scheme())));
}
/**
* Return a new {@link LocalTestWebServer} instance that applies the given
* {@code path}.
* @param path a path to append
* @return a new instance with the path added
*/
public LocalTestWebServer withPath(String path) {
return of(this.scheme, () -> getConnection().withPath(path));
}
private Connection getConnection() {
Connection connection = this.connection.get();
Assert.state(connection != null, "No local test web server connection supplied");
return connection;
}
/**
* Factory method to create a new {@link LocalTestWebServer} instance.
* @param scheme the URL scheme
* @param port the port of the running server
* @return a new {@link LocalTestWebServer} instance
*/
public static LocalTestWebServer of(Scheme scheme, int port) {
return of(scheme, port, null);
}
/**
* Factory method to create a new {@link LocalTestWebServer} instance.
* @param scheme the URL scheme
* @param port the port of the running server
* @param contextPath the context path of the running server
* @return a new {@link LocalTestWebServer} instance
*/
public static LocalTestWebServer of(Scheme scheme, int port, @Nullable String contextPath) {
return of(scheme, () -> new Connection(port, (contextPath != null) ? contextPath : ""));
}
/**
* Factory method to create a new {@link LocalTestWebServer} instance.
* @param scheme the URL scheme
* @param connectionSupplier a supplier to provide the server connection
* @return a new {@link LocalTestWebServer} instance
*/
public static LocalTestWebServer of(Scheme scheme, Supplier<Connection> connectionSupplier) {
return new LocalTestWebServer(scheme, connectionSupplier);
}
/**
* Return a {@link LocalTestWebServer} instance provided from the
* {@link ApplicationContext}.
* @param applicationContext the application context
* @return the local test web server or {@code null}
*/
public static LocalTestWebServer getRequired(ApplicationContext applicationContext) {
LocalTestWebServer localTestWebServer = get(applicationContext);
Assert.state(localTestWebServer != null, "No local test web server available");
return localTestWebServer;
}
/**
* Return a {@link LocalTestWebServer} instance provided from the
* {@link ApplicationContext} or {@code null} of no local server is started or could
* be provided.
* @param applicationContext the application context
* @return the local test web server or {@code null}
*/
public static @Nullable LocalTestWebServer get(ApplicationContext applicationContext) {
Assert.notNull(applicationContext, "'applicationContext' must not be null");
SpringFactoriesLoader loader = SpringFactoriesLoader
.forDefaultResourceLocation(applicationContext.getClassLoader());
return loader.load(Provider.class, ArgumentResolver.of(ApplicationContext.class, applicationContext))
.stream()
.map(Provider::getLocalTestWebServer)
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
/**
* Details of a connection to the local test web server.
*
* @param port the port of the running server
* @param path the path of the running server
*/
public record Connection(int port, String path) {
String uri(Scheme scheme) {
StringBuilder uri = new StringBuilder(scheme.name().toLowerCase(Locale.getDefault()));
uri.append("://localhost:");
uri.append(port());
uri.append(path());
return uri.toString();
}
Connection withPath(String path) {
return new Connection(port(), path() + path);
}
}
/**
* Supported HTTP schemes.
*/
public enum Scheme {
/**
* HTTP scheme.
*/
HTTP,
/**
* HTTPS scheme.
*/
HTTPS
}
/**
* Strategy used to provide the running {@link LocalTestWebServer}. Implementations
* can be registered in {@code spring.factories} and may accept an
* {@link ApplicationContext} constructor argument.
*
*/
@FunctionalInterface
public interface Provider {
/**
* Return the provided {@link LocalTestWebServer} or {@code null}.
* @return the local test web server
*/
@Nullable LocalTestWebServer getLocalTestWebServer();
}
}

65
core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/BaseUrlWebConnectionHtmlUnitDriver.java

@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
/*
* Copyright 2012-present 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.htmlunit;
import org.htmlunit.BrowserVersion;
import org.jspecify.annotations.Nullable;
import org.openqa.selenium.Capabilities;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;
/**
* HTML Unit {@link WebConnectionHtmlUnitDriver} that will automatically prefix relative
* URLs with a {@link BaseUrlProvider provided} {@link BaseUrl}.
*
* @author Phillip Webb
* @since 4.0.0
*/
public class BaseUrlWebConnectionHtmlUnitDriver extends WebConnectionHtmlUnitDriver {
private @Nullable BaseUrl baseUrl;
public BaseUrlWebConnectionHtmlUnitDriver(@Nullable BaseUrl baseUrl) {
this.baseUrl = baseUrl;
}
public BaseUrlWebConnectionHtmlUnitDriver(@Nullable BaseUrl baseUrl, boolean enableJavascript) {
super(enableJavascript);
this.baseUrl = baseUrl;
}
public BaseUrlWebConnectionHtmlUnitDriver(@Nullable BaseUrl baseUrl, BrowserVersion browserVersion) {
super(browserVersion);
this.baseUrl = baseUrl;
}
public BaseUrlWebConnectionHtmlUnitDriver(@Nullable BaseUrl baseUrl, Capabilities capabilities) {
super(capabilities);
this.baseUrl = baseUrl;
}
@Override
public void get(String url) {
if (this.baseUrl != null) {
url = this.baseUrl.getUriBuilderFactory().uriString(url).toUriString();
}
super.get(url);
}
}

24
core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/BaseUrlWebClient.java → core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClient.java

@ -21,32 +21,30 @@ import java.io.IOException; @@ -21,32 +21,30 @@ import java.io.IOException;
import org.htmlunit.FailingHttpStatusCodeException;
import org.htmlunit.Page;
import org.htmlunit.WebClient;
import org.jspecify.annotations.Nullable;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.util.Assert;
import org.springframework.web.util.UriBuilderFactory;
/**
* HTML Unit {@link WebClient} that will automatically prefix relative URLs with a
* {@link BaseUrlProvider provided} {@link BaseUrl}.
* HTML Unit {@link WebClient} supported by a {@link UriBuilderFactory}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
public class BaseUrlWebClient extends WebClient {
public class UriBuilderFactoryWebClient extends WebClient {
private @Nullable BaseUrl baseUrl;
private UriBuilderFactory uriBuilderFactory;
public BaseUrlWebClient(@Nullable BaseUrl baseUrl) {
this.baseUrl = baseUrl;
public UriBuilderFactoryWebClient(UriBuilderFactory uriBuilderFactory) {
Assert.notNull(uriBuilderFactory, "'uriBuilderFactory' must not be null");
this.uriBuilderFactory = uriBuilderFactory;
}
@Override
public <P extends Page> P getPage(String url) throws IOException, FailingHttpStatusCodeException {
if (this.baseUrl != null) {
url = this.baseUrl.getUriBuilderFactory().uriString(url).toUriString();
}
return super.getPage(url);
return super.getPage(
(this.uriBuilderFactory != null) ? this.uriBuilderFactory.uriString(url).toUriString() : url);
}
}

67
core/spring-boot-test/src/main/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriver.java

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
/*
* Copyright 2012-present 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.htmlunit;
import org.htmlunit.BrowserVersion;
import org.openqa.selenium.Capabilities;
import org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;
import org.springframework.util.Assert;
import org.springframework.web.util.UriBuilderFactory;
/**
* HTML Unit {@link WebConnectionHtmlUnitDriver} supported by a {@link UriBuilderFactory}.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
public class UriBuilderFactoryWebConnectionHtmlUnitDriver extends WebConnectionHtmlUnitDriver {
private UriBuilderFactory uriBuilderFactory;
public UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory) {
Assert.notNull(uriBuilderFactory, "'uriBuilderFactory' must not be null");
this.uriBuilderFactory = uriBuilderFactory;
}
public UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory, boolean enableJavascript) {
super(enableJavascript);
Assert.notNull(uriBuilderFactory, "'uriBuilderFactory' must not be null");
this.uriBuilderFactory = uriBuilderFactory;
}
public UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory,
BrowserVersion browserVersion) {
super(browserVersion);
Assert.notNull(uriBuilderFactory, "'uriBuilderFactory' must not be null");
this.uriBuilderFactory = uriBuilderFactory;
}
public UriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory,
Capabilities capabilities) {
super(capabilities);
Assert.notNull(uriBuilderFactory, "'uriBuilderFactory' must not be null");
this.uriBuilderFactory = uriBuilderFactory;
}
@Override
public void get(String url) {
super.get((this.uriBuilderFactory != null) ? this.uriBuilderFactory.uriString(url).toUriString() : url);
}
}

68
core/spring-boot-test/src/test/java/org/springframework/boot/test/http/client/BaseUrlUriBuilderFactoryTests.java

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
/*
* Copyright 2012-present 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.http.client;
import java.net.URI;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.web.util.UriBuilderFactory;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link BaseUrlUriBuilderFactory}.
*
* @author Stephane Nicoll
*/
class BaseUrlUriBuilderFactoryTests {
@Test
void uriWithRootSlashAddsBaseUrl() {
UriBuilderFactory factory = BaseUrlUriBuilderFactory.get(BaseUrl.of("https://example.com"));
assertThat(factory.uriString("/").build()).isEqualTo(URI.create("https://example.com/"));
}
@Test
void uriWithEmptyAddsBaseUrl() {
UriBuilderFactory factory = BaseUrlUriBuilderFactory.get(BaseUrl.of("https://example.com"));
assertThat(factory.uriString("").build()).isEqualTo(URI.create("https://example.com"));
}
@Test
void uriWithMapVariablesAddsBaseUrl() {
UriBuilderFactory factory = BaseUrlUriBuilderFactory.get(BaseUrl.of("https://example.com"));
assertThat(factory.expand("/test/{name}", Map.of("name", "value")))
.isEqualTo(URI.create("https://example.com/test/value"));
}
@Test
void uriWithVariablesAddsBaseUrl() {
UriBuilderFactory factory = BaseUrlUriBuilderFactory.get(BaseUrl.of("https://example.com"));
assertThat(factory.expand("/test/{name}", "value")).isEqualTo(URI.create("https://example.com/test/value"));
}
@Test
void uriWithHostDoesNotExpandBaseUrl() {
UriBuilderFactory factory = BaseUrlUriBuilderFactory.get(BaseUrl.of("https://example.com"));
assertThat(factory.uriString("https://sub.example.com").build())
.isEqualTo(URI.create("https://sub.example.com"));
}
}

57
core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/BaseUrlProvidersTests.java

@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
/*
* Copyright 2012-present 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.http.server;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link BaseUrlProviders}.
*
* @author Phillip Webb
*/
class BaseUrlProvidersTests {
@Test
void getBaseUrlWhenNoProvidedBaseUrlReturnsNull() {
assertThat(new BaseUrlProviders(Collections.emptyList()).getBaseUrl()).isNull();
}
@Test
void getBaseUrlWithFallbackWhenNoProvidedBaseUrlReturnsFallback() {
BaseUrl fallback = BaseUrl.of("https://example.com");
assertThat(new BaseUrlProviders(Collections.emptyList()).getBaseUrl(fallback)).isSameAs(fallback);
}
@Test
void getBaseUrlReturnsFirstProvidedBaseUrl() {
BaseUrlProvider p1 = mock();
BaseUrlProvider p2 = mock();
BaseUrl baseUrl = BaseUrl.of("https://example.com");
given(p1.getBaseUrl()).willReturn(baseUrl);
assertThat(new BaseUrlProviders(List.of(p1, p2)).getBaseUrl()).isSameAs(baseUrl);
then(p2).shouldHaveNoInteractions();
}
}

104
core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/BaseUrlTests.java

@ -1,104 +0,0 @@ @@ -1,104 +0,0 @@
/*
* Copyright 2012-present 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.http.server;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link BaseUrl}.
*
* @author Phillip Webb
*/
class BaseUrlTests {
@Test
void resolveWithString() {
assertThat(resolve(BaseUrl.of("http://localhost"), "")).isEqualTo("http://localhost");
assertThat(resolve(BaseUrl.of("http://localhost"), "/path")).isEqualTo("http://localhost/path");
assertThat(resolve(BaseUrl.of("http://localhost/"), "/path")).isEqualTo("http://localhost/path");
}
@Test
void ofWhenHttp() {
BaseUrl baseUrl = BaseUrl.of("http://localhost:8080/context");
assertThat(baseUrl.isHttps()).isFalse();
assertThat(resolve(baseUrl, "")).isEqualTo("http://localhost:8080/context");
}
@Test
void ofWhenHttps() {
BaseUrl baseUrl = BaseUrl.of("https://localhost:8080/context");
assertThat(baseUrl.isHttps()).isTrue();
assertThat(resolve(baseUrl, "")).isEqualTo("https://localhost:8080/context");
}
@Test
void ofWhenUppercaseHttps() {
BaseUrl baseUrl = BaseUrl.of("HTTPS://localhost:8080/context");
assertThat(baseUrl.isHttps()).isTrue();
}
@Test
@SuppressWarnings("NullAway") // Test null check
void ofWhenUrlIssNull() {
assertThatIllegalArgumentException().isThrownBy(() -> BaseUrl.of(null)).withMessage("'url' must not be null");
}
@Test
void of() {
AtomicInteger atomicInteger = new AtomicInteger();
BaseUrl baseUrl = BaseUrl.of(true, () -> String.valueOf(atomicInteger.incrementAndGet()));
assertThat(atomicInteger.get()).isZero();
assertThat(baseUrl.isHttps()).isTrue();
assertThat(resolve(baseUrl, "")).isEqualTo("1");
assertThat(resolve(baseUrl, "")).isEqualTo("1");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void ofWhenResolverIsNull() {
assertThatIllegalArgumentException().isThrownBy(() -> BaseUrl.of(true, null))
.withMessage("'resolver' must not be null");
}
@Test
void withPath() {
BaseUrl baseUrl = BaseUrl.of("http://localhost");
assertThat(resolve(baseUrl.withPath("/context"), "")).isEqualTo("http://localhost/context");
assertThat(resolve(baseUrl.withPath("/context").withPath("/test"), "/path"))
.isEqualTo("http://localhost/context/test/path");
}
@Test
void withPathInvokesParentResolver() {
AtomicInteger atomicInteger = new AtomicInteger();
BaseUrl baseUrl = BaseUrl.of(true, () -> "https://example.com/" + atomicInteger.incrementAndGet());
assertThat(resolve(baseUrl.withPath("/context"), "")).isEqualTo("https://example.com/1/context");
assertThat(resolve(baseUrl.withPath("/context").withPath("/test"), "/path"))
.isEqualTo("https://example.com/1/context/test/path");
}
private String resolve(BaseUrl baseUrl, String path) {
return baseUrl.getUriBuilderFactory().uriString(path).toUriString();
}
}

216
core/spring-boot-test/src/test/java/org/springframework/boot/test/http/server/LocalTestWebServerTests.java

@ -0,0 +1,216 @@ @@ -0,0 +1,216 @@
/*
* Copyright 2012-present 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.http.server;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.http.server.LocalTestWebServer.Connection;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
/**
* Tests for {@link LocalTestWebServer}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
class LocalTestWebServerTests {
private final LocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTPS, 8080, "");
@Test
void schemeWhenHttpsSchemeReturnsHttpsScheme() {
assertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, "").scheme()).isEqualTo(Scheme.HTTPS);
}
@Test
void schemeWhenHttpSchemeReturnsHttpScheme() {
assertThat(LocalTestWebServer.of(Scheme.HTTP, 8080, "").scheme()).isEqualTo(Scheme.HTTP);
}
@Test
void uriBuilderWhenHasSlashUriUsesLocalServer() {
UriBuilder builder = this.server.uriBuilder("/");
assertThat(builder.toUriString()).isEqualTo("https://localhost:8080/");
}
@Test
void uriBuilderWhenHasEmptyUriUsesLocalServer() {
UriBuilder builder = this.server.uriBuilder("");
assertThat(builder.toUriString()).isEqualTo("https://localhost:8080");
}
@Test
void uriBuilderWhenHasNestedPathUsesLocalServer() {
UriBuilder builder = this.server.uriBuilder("/foo/bar");
assertThat(builder.toUriString()).isEqualTo("https://localhost:8080/foo/bar");
}
@Test
void uriBuilderWhenHasPathNoStartingWithSlashUsesLocalServer() {
UriBuilder builder = this.server.uriBuilder("foo/bar");
assertThat(builder.toUriString()).isEqualTo("https://localhost:8080/foo/bar");
}
@Test
void uriBuilderWhenHasFullUriDoesNotUseLocalServer() {
UriBuilder builder = this.server.uriBuilder("https://sub.example.com");
assertThat(builder.toUriString()).isEqualTo("https://sub.example.com");
}
@Test
void uriBuilderFactoryExpandWithMap() {
UriBuilderFactory factory = this.server.uriBuilderFactory();
assertThat(factory.expand("/test/{name}", Map.of("name", "value")))
.isEqualTo(URI.create("https://localhost:8080/test/value"));
}
@Test
void uriBuilderFactoryExpandsWithMap() {
UriBuilderFactory factory = this.server.uriBuilderFactory();
assertThat(factory.expand("/test/{name}", "value")).isEqualTo(URI.create("https://localhost:8080/test/value"));
}
@Test
void uriBuilderFactoryExpandsWithVariables() {
UriBuilderFactory factory = this.server.uriBuilderFactory();
assertThat(factory.uriString("https://example.com").build()).isEqualTo(URI.create("https://example.com"));
}
@Test
void uriWhenHttp() {
assertThat(LocalTestWebServer.of(Scheme.HTTP, 8080, "").uri()).isEqualTo("http://localhost:8080");
}
@Test
void uriWhenHttps() {
assertThat(LocalTestWebServer.of(Scheme.HTTPS, 4343, "").uri()).isEqualTo("https://localhost:4343");
}
@Test
void uriWhenHasPath() {
assertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, "/path").uri()).isEqualTo("https://localhost:8080/path");
}
@Test
void uriWithUri() {
assertThat(this.server.uri(null)).isEqualTo("https://localhost:8080");
assertThat(this.server.uri("")).isEqualTo("https://localhost:8080");
assertThat(this.server.uri("/")).isEqualTo("https://localhost:8080/");
assertThat(this.server.uri("/foo")).isEqualTo("https://localhost:8080/foo");
assertThat(this.server.uri("https://example.com/foo")).isEqualTo("https://example.com/foo");
}
@Test
void uriUsesSingletonConnection() {
AtomicInteger counter = new AtomicInteger();
LocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTPS,
() -> new Connection(8080, "/" + counter.incrementAndGet()));
assertThat(server.uri()).isEqualTo("https://localhost:8080/1");
assertThat(server.uri()).isEqualTo("https://localhost:8080/1");
}
@Test
void withPathCreatedNewInstance() {
assertThat(LocalTestWebServer.of(Scheme.HTTPS, 8080, "/path").withPath("/other").uri())
.isEqualTo("https://localhost:8080/path/other");
}
@Test
@SuppressWarnings("NullAway") // Test null check
void ofWhenConnectionSupplierIsNull() {
assertThatIllegalArgumentException().isThrownBy(() -> LocalTestWebServer.of(Scheme.HTTPS, null))
.withMessage("'connectionSupplier' must not be null");
}
@Test
@WithResource(name = "META-INF/spring.factories", content = """
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1,\
org.springframework.boot.test.http.server.LocalTestWebServerTests$Provider2,\
org.springframework.boot.test.http.server.LocalTestWebServerTests$Provider3
""")
void getReturnsFirstProvided() {
ApplicationContext applicationContext = new GenericApplicationContext();
LocalTestWebServer provided = LocalTestWebServer.get(applicationContext);
assertThat(provided).isNotNull();
assertThat(provided.uri()).isEqualTo("https://localhost:7070/p2");
}
@Test
@WithResource(name = "META-INF/spring.factories", content = """
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1
""")
void getWhenNoneReturnsNull() {
ApplicationContext applicationContext = new GenericApplicationContext();
LocalTestWebServer provided = LocalTestWebServer.get(applicationContext);
assertThat(provided).isNull();
}
@Test
@WithResource(name = "META-INF/spring.factories", content = """
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.test.http.server.LocalTestWebServerTests$Provider1
""")
void getRequiredWhenNoneProvidedThrowsException() {
ApplicationContext applicationContext = new GenericApplicationContext();
assertThatIllegalStateException().isThrownBy(() -> LocalTestWebServer.getRequired(applicationContext))
.withMessage("No local test web server available");
}
static class Provider1 implements LocalTestWebServer.Provider {
@Override
public @Nullable LocalTestWebServer getLocalTestWebServer() {
return null;
}
}
static class Provider2 implements LocalTestWebServer.Provider {
@Override
public @Nullable LocalTestWebServer getLocalTestWebServer() {
return LocalTestWebServer.of(Scheme.HTTPS, 7070, "/p2");
}
}
static class Provider3 implements LocalTestWebServer.Provider {
@Override
public @Nullable LocalTestWebServer getLocalTestWebServer() {
throw new IllegalStateException();
}
}
}

26
core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/BaseUrlWebClientTests.java → core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebClientTests.java

@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
package org.springframework.boot.test.web.htmlunit;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.htmlunit.StringWebResponse;
@ -26,10 +25,9 @@ import org.htmlunit.WebConnection; @@ -26,10 +25,9 @@ import org.htmlunit.WebConnection;
import org.htmlunit.WebResponse;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.web.util.DefaultUriBuilderFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.assertArg;
import static org.mockito.BDDMockito.given;
@ -37,33 +35,25 @@ import static org.mockito.BDDMockito.then; @@ -37,33 +35,25 @@ import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link BaseUrlWebClient}.
* Tests for {@link UriBuilderFactoryWebClient}.
*
* @author Phillip Webb
*/
@SuppressWarnings("resource")
class BaseUrlWebClientTests {
class UriBuilderFactoryWebClientTests {
@Test
void createWhenBaseUrlIsNull() throws Exception {
BaseUrlWebClient client = new BaseUrlWebClient(null);
WebConnection connection = mockConnection();
client.setWebConnection(connection);
assertThatExceptionOfType(MalformedURLException.class).isThrownBy(() -> client.getPage("/test"));
}
@Test
void getPageWhenUrlIsRelativeUsesBaseUrl() throws Exception {
WebClient client = new BaseUrlWebClient(BaseUrl.of("https://example.com:8080"));
void getPageWhenUriIsRelativeUsesBuilder() throws Exception {
WebClient client = new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory("https://localhost:8080"));
WebConnection connection = mockConnection();
client.setWebConnection(connection);
client.getPage("/test");
thenConnectionRequests(connection, new URL("https://example.com:8080/test"));
thenConnectionRequests(connection, new URL("https://localhost:8080/test"));
}
@Test
void getPageWhenUrlIsNotRelativeUsesUrl() throws Exception {
WebClient client = new BaseUrlWebClient(BaseUrl.of("https://example.com:8080"));
void getPageWhenUriIsNotRelativeUsesUri() throws Exception {
WebClient client = new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory("https://localhost"));
WebConnection connection = mockConnection();
client.setWebConnection(connection);
client.getPage("https://example.com:9000/test");

35
core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/BaseUrlWebConnectionHtmlUnitDriverTests.java → core/spring-boot-test/src/test/java/org/springframework/boot/test/web/htmlunit/UriBuilderFactoryWebConnectionHtmlUnitDriverTests.java

@ -16,7 +16,6 @@ @@ -16,7 +16,6 @@
package org.springframework.boot.test.web.htmlunit;
import java.net.MalformedURLException;
import java.net.URL;
import org.htmlunit.TopLevelWindow;
@ -25,14 +24,13 @@ import org.htmlunit.WebClientOptions; @@ -25,14 +24,13 @@ import org.htmlunit.WebClientOptions;
import org.htmlunit.WebConsole;
import org.htmlunit.WebRequest;
import org.htmlunit.WebWindow;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher;
import org.openqa.selenium.WebDriverException;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.test.web.servlet.htmlunit.webdriver.WebConnectionHtmlUnitDriver;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilderFactory;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.BDDMockito.given;
@ -40,15 +38,15 @@ import static org.mockito.BDDMockito.then; @@ -40,15 +38,15 @@ import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link BaseUrlWebConnectionHtmlUnitDriver}.
* Tests for {@link UriBuilderFactoryWebConnectionHtmlUnitDriver}.
*
* @author Phillip Webb
*/
class BaseUrlWebConnectionHtmlUnitDriverTests {
class UriBuilderFactoryWebConnectionHtmlUnitDriverTests {
private final WebClient webClient;
BaseUrlWebConnectionHtmlUnitDriverTests() {
UriBuilderFactoryWebConnectionHtmlUnitDriverTests() {
this.webClient = mock();
given(this.webClient.getOptions()).willReturn(new WebClientOptions());
given(this.webClient.getWebConsole()).willReturn(new WebConsole());
@ -57,35 +55,28 @@ class BaseUrlWebConnectionHtmlUnitDriverTests { @@ -57,35 +55,28 @@ class BaseUrlWebConnectionHtmlUnitDriverTests {
given(this.webClient.getCurrentWindow()).willReturn(currentWindow);
}
@Test
void createWhenBaseUrlIsNull() {
BaseUrlWebConnectionHtmlUnitDriver driver = new TestBaseUrlWebConnectionHtmlUnitDriver(null);
assertThatExceptionOfType(WebDriverException.class).isThrownBy(() -> driver.get("/test"))
.withCauseInstanceOf(MalformedURLException.class);
}
@Test
void getWhenUrlIsRelativeUsesBaseUrl() throws Exception {
BaseUrl baseUrl = BaseUrl.of("https://example.com");
BaseUrlWebConnectionHtmlUnitDriver driver = new TestBaseUrlWebConnectionHtmlUnitDriver(baseUrl);
WebConnectionHtmlUnitDriver driver = new TestUriBuilderFactoryWebConnectionHtmlUnitDriver(
new DefaultUriBuilderFactory("https://localhost:8080"));
driver.get("/test");
then(this.webClient).should()
.getPage(any(TopLevelWindow.class), requestToUrl(new URL("https://example.com/test")));
.getPage(any(TopLevelWindow.class), requestToUrl(new URL("https://localhost:8080/test")));
}
private WebRequest requestToUrl(URL url) {
return argThat(new WebRequestUrlArgumentMatcher(url));
}
public class TestBaseUrlWebConnectionHtmlUnitDriver extends BaseUrlWebConnectionHtmlUnitDriver {
class TestUriBuilderFactoryWebConnectionHtmlUnitDriver extends UriBuilderFactoryWebConnectionHtmlUnitDriver {
TestBaseUrlWebConnectionHtmlUnitDriver(@Nullable BaseUrl baseUrl) {
super(baseUrl);
TestUriBuilderFactoryWebConnectionHtmlUnitDriver(UriBuilderFactory uriBuilderFactory) {
super(uriBuilderFactory);
}
@Override
public WebClient getWebClient() {
return BaseUrlWebConnectionHtmlUnitDriverTests.this.webClient;
return UriBuilderFactoryWebConnectionHtmlUnitDriverTests.this.webClient;
}
}

18
module/spring-boot-graphql-test/src/main/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfiguration.java

@ -24,9 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -24,9 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.graphql.autoconfigure.GraphQlProperties;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.graphql.test.tester.HttpGraphQlTester;
@ -52,16 +50,14 @@ public final class HttpGraphQlTesterAutoConfiguration { @@ -52,16 +50,14 @@ public final class HttpGraphQlTesterAutoConfiguration {
HttpGraphQlTester webTestClientGraphQlTester(ApplicationContext applicationContext, WebTestClient webTestClient,
GraphQlProperties properties) {
String graphQlPath = properties.getHttp().getPath();
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl();
WebTestClient graphQlWebTestClient = configureGraphQlWebTestClient(webTestClient, baseUrl, graphQlPath);
return HttpGraphQlTester.create(graphQlWebTestClient);
LocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);
return HttpGraphQlTester.create(createWebTestClient(webTestClient.mutate(), localTestWebServer, graphQlPath));
}
private WebTestClient configureGraphQlWebTestClient(WebTestClient webTestClient, @Nullable BaseUrl baseUrl,
String graphQlPath) {
WebTestClient.Builder builder = webTestClient.mutate();
return (baseUrl != null)
? builder.uriBuilderFactory(BaseUrlUriBuilderFactory.get(baseUrl.withPath(graphQlPath))).build()
private WebTestClient createWebTestClient(WebTestClient.Builder builder,
@Nullable LocalTestWebServer localTestWebServer, String graphQlPath) {
return (localTestWebServer != null)
? builder.uriBuilderFactory(localTestWebServer.withPath(graphQlPath).uriBuilderFactory()).build()
: builder.baseUrl(graphQlPath).build();
}

19
module/spring-boot-graphql-test/src/test/java/org/springframework/boot/graphql/test/autoconfigure/tester/HttpGraphQlTesterAutoConfigurationTests.java

@ -24,8 +24,8 @@ import org.junit.jupiter.api.Test; @@ -24,8 +24,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.webtestclient.WebTestClientAutoConfiguration;
import org.springframework.graphql.test.tester.HttpGraphQlTester;
@ -66,8 +66,8 @@ class HttpGraphQlTesterAutoConfigurationTests { @@ -66,8 +66,8 @@ class HttpGraphQlTesterAutoConfigurationTests {
@Test
@WithResource(name = "META-INF/spring.factories",
content = """
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestBaseUrlProvider
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestLocalTestWebServerProvider
""")
void shouldContributeTesterBoundToHttpServer() {
this.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))
@ -85,8 +85,8 @@ class HttpGraphQlTesterAutoConfigurationTests { @@ -85,8 +85,8 @@ class HttpGraphQlTesterAutoConfigurationTests {
@Test
@WithResource(name = "META-INF/spring.factories",
content = """
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestBaseUrlProvider
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.graphql.test.autoconfigure.tester.HttpGraphQlTesterAutoConfigurationTests$TestLocalTestWebServerProvider
""")
void shouldContributeTesterBoundToHttpServerUsingCustomGraphQlHttpPath() {
this.contextRunner.withConfiguration(AutoConfigurations.of(WebTestClientAutoConfiguration.class))
@ -102,12 +102,11 @@ class HttpGraphQlTesterAutoConfigurationTests { @@ -102,12 +102,11 @@ class HttpGraphQlTesterAutoConfigurationTests {
});
}
@SuppressWarnings("unused")
static class TestBaseUrlProvider implements BaseUrlProvider {
static class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {
@Override
public @Nullable BaseUrl getBaseUrl() {
return BaseUrl.of("https://localhost:4242");
public @Nullable LocalTestWebServer getLocalTestWebServer() {
return LocalTestWebServer.of(Scheme.HTTPS, 4242);
}
}

10
module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientAutoConfiguration.java

@ -24,9 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -24,9 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.http.converter.autoconfigure.ClientHttpMessageConvertersCustomizer;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.servlet.MockMvc;
@ -62,9 +60,9 @@ public final class RestTestClientAutoConfiguration { @@ -62,9 +60,9 @@ public final class RestTestClientAutoConfiguration {
}
private RestTestClient.Builder<?> getBuilder(WebApplicationContext applicationContext) {
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl();
if (baseUrl != null) {
return RestTestClient.bindToServer().uriBuilderFactory(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);
if (localTestWebServer != null) {
return RestTestClient.bindToServer().uriBuilderFactory(localTestWebServer.uriBuilderFactory());
}
if (hasBean(applicationContext, MockMvc.class)) {
return RestTestClient.bindTo(applicationContext.getBean(MockMvc.class));

22
module/spring-boot-resttestclient/src/main/java/org/springframework/boot/resttestclient/autoconfigure/TestRestTemplateAutoConfiguration.java

@ -22,9 +22,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean @@ -22,9 +22,8 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.TestRestTemplate.HttpClientOption;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@ -37,20 +36,23 @@ import org.springframework.context.annotation.Bean; @@ -37,20 +36,23 @@ import org.springframework.context.annotation.Bean;
@AutoConfiguration
public final class TestRestTemplateAutoConfiguration {
private static final HttpClientOption[] DEFAULT_OPTIONS = {};
private static final HttpClientOption[] SSL_OPTIONS = { HttpClientOption.SSL };
@Bean(name = "org.springframework.boot.resttestclient.TestRestTemplate")
@ConditionalOnMissingBean
TestRestTemplate testRestTemplate(ObjectProvider<RestTemplateBuilder> builderProvider,
ApplicationContext applicationContext) {
RestTemplateBuilder builder = builderProvider.getIfAvailable(RestTemplateBuilder::new);
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl(BaseUrl.LOCALHOST);
LocalTestWebServer localTestWebServer = LocalTestWebServer.getRequired(applicationContext);
TestRestTemplate template = new TestRestTemplate(builder, null, null,
baseUrl.isHttps() ? SSL_OPTIONS : DEFAULT_OPTIONS);
template.setUriTemplateHandler(BaseUrlUriBuilderFactory.get(baseUrl));
httpClientOptions(localTestWebServer.scheme()));
template.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());
return template;
}
private HttpClientOption[] httpClientOptions(Scheme scheme) {
return switch (scheme) {
case HTTP -> new HttpClientOption[] {};
case HTTPS -> new HttpClientOption[] { HttpClientOption.SSL };
};
}
}

8
module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/TestRestTemplateTests.java

@ -38,8 +38,8 @@ import org.springframework.boot.http.client.HttpClientSettings; @@ -38,8 +38,8 @@ import org.springframework.boot.http.client.HttpClientSettings;
import org.springframework.boot.http.client.HttpRedirects;
import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.resttestclient.TestRestTemplate.HttpClientOption;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@ -343,7 +343,7 @@ class TestRestTemplateTests { @@ -343,7 +343,7 @@ class TestRestTemplateTests {
URI absoluteUri = URI.create("http://localhost:8080/a/b/c.txt");
given(requestFactory.createRequest(eq(absoluteUri), eq(HttpMethod.GET))).willReturn(request);
template.getRestTemplate().setRequestFactory(requestFactory);
template.setUriTemplateHandler(BaseUrlUriBuilderFactory.get(BaseUrl.of("http://localhost:8080")));
template.setUriTemplateHandler(LocalTestWebServer.of(Scheme.HTTP, 8080).uriBuilderFactory());
template.exchange(entity, String.class);
then(requestFactory).should().createRequest(eq(absoluteUri), eq(HttpMethod.GET));
}
@ -458,7 +458,7 @@ class TestRestTemplateTests { @@ -458,7 +458,7 @@ class TestRestTemplateTests {
given(requestFactory.createRequest(eq(absoluteUri), any(HttpMethod.class))).willReturn(request);
TestRestTemplate template = new TestRestTemplate();
template.getRestTemplate().setRequestFactory(requestFactory);
template.setUriTemplateHandler(BaseUrlUriBuilderFactory.get(BaseUrl.of("http://localhost:8080")));
template.setUriTemplateHandler(LocalTestWebServer.of(Scheme.HTTP, 8080).uriBuilderFactory());
callback.doWithTestRestTemplate(template, URI.create("/a/b/c.txt?param=%7Bsomething%7D"));
then(requestFactory).should().createRequest(eq(absoluteUri), any(HttpMethod.class));
}

25
module/spring-boot-resttestclient/src/test/java/org/springframework/boot/resttestclient/autoconfigure/RestTestClientAutoConfigurationTests.java

@ -16,20 +16,21 @@ @@ -16,20 +16,21 @@
package org.springframework.boot.resttestclient.autoconfigure;
import org.assertj.core.extractor.Extractors;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.web.servlet.client.RestTestClient;
import org.springframework.web.client.RestClient;
import org.springframework.web.util.UriBuilderFactory;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -71,18 +72,18 @@ class RestTestClientAutoConfigurationTests { @@ -71,18 +72,18 @@ class RestTestClientAutoConfigurationTests {
@Test
@WithResource(name = "META-INF/spring.factories",
content = """
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.resttestclient.autoconfigure.RestTestClientAutoConfigurationTests.TestBaseUrlProvider
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.resttestclient.autoconfigure.RestTestClientAutoConfigurationTests$TestLocalTestWebServerProvider
""")
void shouldDefineWebTestClientBoundToWebServer() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(RestTestClient.class);
assertThat(context).hasBean("restTestClient");
RestTestClient client = context.getBean(RestTestClient.class);
assertThat(client).extracting("restTestClientBuilder")
.extracting("restClientBuilder")
.extracting("uriBuilderFactory")
.isInstanceOf(BaseUrlUriBuilderFactory.class);
UriBuilderFactory uiBuilderFactory = (UriBuilderFactory) Extractors
.byName("restTestClientBuilder.restClientBuilder.uriBuilderFactory")
.apply(client);
assertThat(uiBuilderFactory.uriString("").toUriString()).isEqualTo("https://localhost:8182");
});
}
@ -96,11 +97,11 @@ class RestTestClientAutoConfigurationTests { @@ -96,11 +97,11 @@ class RestTestClientAutoConfigurationTests {
}
static class TestBaseUrlProvider implements BaseUrlProvider {
static class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {
@Override
public @Nullable BaseUrl getBaseUrl() {
return BaseUrl.of("https://localhost:8080");
public @Nullable LocalTestWebServer getLocalTestWebServer() {
return LocalTestWebServer.of(Scheme.HTTPS, 8182);
}
}

21
module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextBaseUrlProvider.java → module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/reactive/context/ReactiveWebServerApplicationContextLocalTestWebServerProvider.java

@ -19,21 +19,22 @@ package org.springframework.boot.web.server.reactive.context; @@ -19,21 +19,22 @@ package org.springframework.boot.web.server.reactive.context;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Connection;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
import org.springframework.context.ApplicationContext;
/**
* {@link BaseUrlProvider} for a {@link ReactiveWebServerApplicationContext}.
* {@link LocalTestWebServer} provider for a {@link ReactiveWebServerApplicationContext}.
*
* @author Phillip Webb
*/
class ReactiveWebServerApplicationContextBaseUrlProvider implements BaseUrlProvider {
class ReactiveWebServerApplicationContextLocalTestWebServerProvider implements LocalTestWebServer.Provider {
private final @Nullable ReactiveWebServerApplicationContext context;
ReactiveWebServerApplicationContextBaseUrlProvider(ApplicationContext context) {
ReactiveWebServerApplicationContextLocalTestWebServerProvider(ApplicationContext context) {
this.context = getWebServerApplicationContextIfPossible(context);
}
@ -48,16 +49,14 @@ class ReactiveWebServerApplicationContextBaseUrlProvider implements BaseUrlProvi @@ -48,16 +49,14 @@ class ReactiveWebServerApplicationContextBaseUrlProvider implements BaseUrlProvi
}
@Override
public @Nullable BaseUrl getBaseUrl() {
public @Nullable LocalTestWebServer getLocalTestWebServer() {
if (this.context == null) {
return null;
}
boolean sslEnabled = isSslEnabled(this.context);
return BaseUrl.of(sslEnabled, () -> {
String scheme = (sslEnabled) ? "https" : "http";
String port = this.context.getEnvironment().getProperty("local.server.port", "8080");
return LocalTestWebServer.of((isSslEnabled(this.context)) ? Scheme.HTTPS : Scheme.HTTP, () -> {
int port = this.context.getEnvironment().getProperty("local.server.port", Integer.class, 8080);
String path = this.context.getEnvironment().getProperty("spring.webflux.base-path", "");
return scheme + "://localhost:" + port + path;
return new Connection(port, path);
});
}

21
module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextBaseUrlProvider.java → module/spring-boot-web-server/src/main/java/org/springframework/boot/web/server/servlet/context/ServletWebServerApplicationContextLocalTestWebServerProvider.java

@ -19,21 +19,22 @@ package org.springframework.boot.web.server.servlet.context; @@ -19,21 +19,22 @@ package org.springframework.boot.web.server.servlet.context;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Connection;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.web.server.AbstractConfigurableWebServerFactory;
import org.springframework.context.ApplicationContext;
/**
* {@link BaseUrlProvider} for a {@link ServletWebServerApplicationContext}.
* {@link LocalTestWebServer} provider for a {@link ServletWebServerApplicationContext}.
*
* @author Phillip Webb
*/
class ServletWebServerApplicationContextBaseUrlProvider implements BaseUrlProvider {
class ServletWebServerApplicationContextLocalTestWebServerProvider implements LocalTestWebServer.Provider {
private final @Nullable ServletWebServerApplicationContext context;
ServletWebServerApplicationContextBaseUrlProvider(ApplicationContext context) {
ServletWebServerApplicationContextLocalTestWebServerProvider(ApplicationContext context) {
this.context = getWebServerApplicationContextIfPossible(context);
}
@ -48,16 +49,14 @@ class ServletWebServerApplicationContextBaseUrlProvider implements BaseUrlProvid @@ -48,16 +49,14 @@ class ServletWebServerApplicationContextBaseUrlProvider implements BaseUrlProvid
}
@Override
public @Nullable BaseUrl getBaseUrl() {
public @Nullable LocalTestWebServer getLocalTestWebServer() {
if (this.context == null) {
return null;
}
boolean sslEnabled = isSslEnabled(this.context);
return BaseUrl.of(sslEnabled, () -> {
String scheme = (sslEnabled) ? "https" : "http";
String port = this.context.getEnvironment().getProperty("local.server.port", "8080");
return LocalTestWebServer.of((isSslEnabled(this.context)) ? Scheme.HTTPS : Scheme.HTTP, () -> {
int port = this.context.getEnvironment().getProperty("local.server.port", Integer.class, 8080);
String path = this.context.getEnvironment().getProperty("server.servlet.context-path", "");
return scheme + "://localhost:" + port + path;
return new Connection(port, path);
});
}

9
module/spring-boot-web-server/src/main/resources/META-INF/spring.factories

@ -12,11 +12,12 @@ org.springframework.boot.diagnostics.FailureAnalyzer=\ @@ -12,11 +12,12 @@ org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.web.server.PortInUseFailureAnalyzer,\
org.springframework.boot.web.server.context.MissingWebServerFactoryBeanFailureAnalyzer
# HTTP Server Test Base URL Providers
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContextBaseUrlProvider,\
org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContextBaseUrlProvider
# HTTP Server LocalTestWebServer Providers
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.web.server.reactive.context.ReactiveWebServerApplicationContextLocalTestWebServerProvider,\
org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContextLocalTestWebServerProvider
# Spring Test Context Customizer Factories
org.springframework.test.context.ContextCustomizerFactory=\
org.springframework.boot.web.server.context.SpringBootTestRandomPortContextCustomizerFactory

9
module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebClientAutoConfiguration.java

@ -23,13 +23,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -23,13 +23,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.web.htmlunit.BaseUrlWebClient;
import org.springframework.boot.test.web.htmlunit.UriBuilderFactoryWebClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.MockMvcWebClientBuilder;
import org.springframework.web.util.DefaultUriBuilderFactory;
/**
* Auto-configuration for HtmlUnit {@link WebClient} MockMVC integration.
@ -46,8 +45,8 @@ public final class MockMvcWebClientAutoConfiguration { @@ -46,8 +45,8 @@ public final class MockMvcWebClientAutoConfiguration {
@ConditionalOnMissingBean({ WebClient.class, MockMvcWebClientBuilder.class })
@ConditionalOnBean(MockMvc.class)
MockMvcWebClientBuilder mockMvcWebClientBuilder(MockMvc mockMvc, ApplicationContext applicationContext) {
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl(BaseUrl.LOCALHOST);
return MockMvcWebClientBuilder.mockMvcSetup(mockMvc).withDelegate(new BaseUrlWebClient(baseUrl));
return MockMvcWebClientBuilder.mockMvcSetup(mockMvc)
.withDelegate(new UriBuilderFactoryWebClient(new DefaultUriBuilderFactory("http://localhost")));
}
@Bean

12
module/spring-boot-webmvc-test/src/main/java/org/springframework/boot/webmvc/test/autoconfigure/MockMvcWebDriverAutoConfiguration.java

@ -26,13 +26,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -26,13 +26,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.web.htmlunit.BaseUrlWebConnectionHtmlUnitDriver;
import org.springframework.boot.test.web.htmlunit.UriBuilderFactoryWebConnectionHtmlUnitDriver;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder;
import org.springframework.web.util.DefaultUriBuilderFactory;
/**
* Auto-configuration for Selenium {@link WebDriver} MockMVC integration.
@ -49,10 +48,9 @@ public final class MockMvcWebDriverAutoConfiguration { @@ -49,10 +48,9 @@ public final class MockMvcWebDriverAutoConfiguration {
@ConditionalOnMissingBean({ WebDriver.class, MockMvcHtmlUnitDriverBuilder.class })
@ConditionalOnBean(MockMvc.class)
MockMvcHtmlUnitDriverBuilder mockMvcHtmlUnitDriverBuilder(MockMvc mockMvc, ApplicationContext applicationContext) {
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl(BaseUrl.LOCALHOST);
MockMvcHtmlUnitDriverBuilder builder = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(mockMvc)
.withDelegate(new BaseUrlWebConnectionHtmlUnitDriver(baseUrl, BrowserVersion.CHROME));
return builder;
return MockMvcHtmlUnitDriverBuilder.mockMvcSetup(mockMvc)
.withDelegate(new UriBuilderFactoryWebConnectionHtmlUnitDriver(
new DefaultUriBuilderFactory("http://localhost"), BrowserVersion.CHROME));
}
@Bean

10
module/spring-boot-webtestclient/src/main/java/org/springframework/boot/webtestclient/WebTestClientAutoConfiguration.java

@ -26,9 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @@ -26,9 +26,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.http.codec.CodecCustomizer;
import org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.test.web.reactive.server.MockServerConfigurer;
@ -74,9 +72,9 @@ public final class WebTestClientAutoConfiguration { @@ -74,9 +72,9 @@ public final class WebTestClientAutoConfiguration {
private WebTestClient.Builder getBuilder(ApplicationContext applicationContext,
List<MockServerConfigurer> configurers) {
BaseUrl baseUrl = new BaseUrlProviders(applicationContext).getBaseUrl();
if (baseUrl != null) {
return WebTestClient.bindToServer().uriBuilderFactory(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.get(applicationContext);
if (localTestWebServer != null) {
return WebTestClient.bindToServer().uriBuilderFactory(localTestWebServer.uriBuilderFactory());
}
if (applicationContext.containsBean(WebHttpHandlerBuilder.WEB_HANDLER_BEAN_NAME)) {
MockServerSpec<?> spec = WebTestClient.bindToApplicationContext(applicationContext);

28
module/spring-boot-webtestclient/src/test/java/org/springframework/boot/webflux/test/autoconfigure/WebTestClientAutoConfigurationTests.java

@ -25,8 +25,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations; @@ -25,8 +25,8 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.http.codec.CodecCustomizer;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProvider;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.http.server.LocalTestWebServer.Scheme;
import org.springframework.boot.testsupport.classpath.resources.WithResource;
import org.springframework.boot.webtestclient.WebTestClientAutoConfiguration;
import org.springframework.boot.webtestclient.WebTestClientBuilderCustomizer;
@ -98,10 +98,11 @@ class WebTestClientAutoConfigurationTests { @@ -98,10 +98,11 @@ class WebTestClientAutoConfigurationTests {
}
@Test
@WithResource(name = "META-INF/spring.factories", content = """
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.webflux.test.autoconfigure.WebTestClientAutoConfigurationTests$TestBaseUrlProvider
""")
@WithResource(name = "META-INF/spring.factories",
content = """
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.webflux.test.autoconfigure.WebTestClientAutoConfigurationTests$TestLocalTestWebServerProvider
""")
void shouldDefineWebTestClientBoundToWebServer() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(WebTestClient.class);
@ -176,10 +177,11 @@ class WebTestClientAutoConfigurationTests { @@ -176,10 +177,11 @@ class WebTestClientAutoConfigurationTests {
}
@Test
@WithResource(name = "META-INF/spring.factories", content = """
org.springframework.boot.test.http.server.BaseUrlProvider=\
org.springframework.boot.webflux.test.autoconfigure.WebTestClientAutoConfigurationTests$TestBaseUrlProvider
""")
@WithResource(name = "META-INF/spring.factories",
content = """
org.springframework.boot.test.http.server.LocalTestWebServer$Provider=\
org.springframework.boot.webflux.test.autoconfigure.WebTestClientAutoConfigurationTests$TestLocalTestWebServerProvider
""")
void shouldWorkWithoutServletStack() {
ClassLoader parentClassLoader = Thread.currentThread().getContextClassLoader();
this.contextRunner.withClassLoader(new FilteredClassLoader(parentClassLoader, WebApplicationContext.class))
@ -223,11 +225,11 @@ class WebTestClientAutoConfigurationTests { @@ -223,11 +225,11 @@ class WebTestClientAutoConfigurationTests {
}
static class TestBaseUrlProvider implements BaseUrlProvider {
static class TestLocalTestWebServerProvider implements LocalTestWebServer.Provider {
@Override
public @Nullable BaseUrl getBaseUrl() {
return BaseUrl.of("https://localhost:8080");
public @Nullable LocalTestWebServer getLocalTestWebServer() {
return LocalTestWebServer.of(Scheme.HTTPS, 8080);
}
}

8
smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/AbstractSampleActuatorCustomSecurityTests.java

@ -21,9 +21,7 @@ import java.util.Map; @@ -21,9 +21,7 @@ import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -202,8 +200,8 @@ abstract class AbstractSampleActuatorCustomSecurityTests { @@ -202,8 +200,8 @@ abstract class AbstractSampleActuatorCustomSecurityTests {
}
private TestRestTemplate configure(TestRestTemplate restTemplate) {
BaseUrl baseUrl = new BaseUrlProviders(getApplicationContext()).getBaseUrl();
restTemplate.setUriTemplateHandler(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.getRequired(getApplicationContext());
restTemplate.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());
return restTemplate;
}

8
smoke-test/spring-boot-smoke-test-actuator-custom-security/src/test/java/smoketest/actuator/customsecurity/CorsSampleActuatorApplicationTests.java

@ -27,9 +27,7 @@ import org.springframework.boot.restclient.RestTemplateBuilder; @@ -27,9 +27,7 @@ import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
@ -56,8 +54,8 @@ class CorsSampleActuatorApplicationTests { @@ -56,8 +54,8 @@ class CorsSampleActuatorApplicationTests {
@BeforeEach
void setUp() {
RestTemplateBuilder builder = new RestTemplateBuilder();
BaseUrl baseUrl = new BaseUrlProviders(this.applicationContext).getBaseUrl();
builder = builder.uriTemplateHandler(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.getRequired(this.applicationContext);
builder = builder.uriTemplateHandler(localTestWebServer.uriBuilderFactory());
this.testRestTemplate = new TestRestTemplate(builder);
}

8
smoke-test/spring-boot-smoke-test-actuator-extension/src/test/java/smoketest/actuator/extension/SampleActuatorExtensionApplicationTests.java

@ -26,9 +26,7 @@ import org.springframework.boot.resttestclient.TestRestTemplate; @@ -26,9 +26,7 @@ import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@ -67,8 +65,8 @@ class SampleActuatorExtensionApplicationTests { @@ -67,8 +65,8 @@ class SampleActuatorExtensionApplicationTests {
void healthExtensionWithAuthHeader() {
TestRestTemplate restTemplate = new TestRestTemplate(
this.restTemplateBuilder.defaultHeader("Authorization", "Bearer secret"));
BaseUrl baseUrl = new BaseUrlProviders(this.applicationContext).getBaseUrl();
restTemplate.setUriTemplateHandler(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.getRequired(this.applicationContext);
restTemplate.setUriTemplateHandler(localTestWebServer.uriBuilderFactory());
ResponseEntity<Map> entity = restTemplate.getForEntity("/myextension/health", Map.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
}

8
smoke-test/spring-boot-smoke-test-actuator/src/test/java/smoketest/actuator/CorsSampleActuatorApplicationTests.java

@ -27,9 +27,7 @@ import org.springframework.boot.restclient.RestTemplateBuilder; @@ -27,9 +27,7 @@ import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.boot.resttestclient.TestRestTemplate;
import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.http.client.BaseUrlUriBuilderFactory;
import org.springframework.boot.test.http.server.BaseUrl;
import org.springframework.boot.test.http.server.BaseUrlProviders;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
@ -56,8 +54,8 @@ class CorsSampleActuatorApplicationTests { @@ -56,8 +54,8 @@ class CorsSampleActuatorApplicationTests {
@BeforeEach
void setUp() {
RestTemplateBuilder builder = new RestTemplateBuilder();
BaseUrl baseUrl = new BaseUrlProviders(this.applicationContext).getBaseUrl();
builder = builder.uriTemplateHandler(BaseUrlUriBuilderFactory.get(baseUrl));
LocalTestWebServer localTestWebServer = LocalTestWebServer.getRequired(this.applicationContext);
builder = builder.uriTemplateHandler(localTestWebServer.uriBuilderFactory());
this.testRestTemplate = new TestRestTemplate(builder);
}

Loading…
Cancel
Save