diff --git a/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java index 8bd7f2fb21d..b8efe10f2df 100644 --- a/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java +++ b/buildSrc/src/main/java/org/springframework/boot/build/ConventionsPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 the original author or authors. + * Copyright 2012-2025 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. @@ -50,6 +50,7 @@ public class ConventionsPlugin implements Plugin { new KotlinConventions().apply(project); new WarConventions().apply(project); new EclipseConventions().apply(project); + new TestFixturesConventions().apply(project); RepositoryTransformersExtension.apply(project); } diff --git a/buildSrc/src/main/java/org/springframework/boot/build/TestFixturesConventions.java b/buildSrc/src/main/java/org/springframework/boot/build/TestFixturesConventions.java new file mode 100644 index 00000000000..06316d71f9d --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/boot/build/TestFixturesConventions.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2025 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.build; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.ConfigurationContainer; +import org.gradle.api.component.AdhocComponentWithVariants; +import org.gradle.api.plugins.JavaTestFixturesPlugin; + +/** + * Conventions that are applied in the presence of the {@link JavaTestFixturesPlugin}. + * When the plugin is applied: + * + * + * + * @author Andy Wilkinson + */ +class TestFixturesConventions { + + void apply(Project project) { + project.getPlugins().withType(JavaTestFixturesPlugin.class, (testFixtures) -> disablePublishing(project)); + } + + private void disablePublishing(Project project) { + ConfigurationContainer configurations = project.getConfigurations(); + AdhocComponentWithVariants javaComponent = (AdhocComponentWithVariants) project.getComponents() + .getByName("java"); + javaComponent.withVariantsFromConfiguration(configurations.getByName("testFixturesApiElements"), + (variant) -> variant.skip()); + javaComponent.withVariantsFromConfiguration(configurations.getByName("testFixturesRuntimeElements"), + (variant) -> variant.skip()); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index f82745e2615..9fe1552421d 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -137,6 +137,7 @@ dependencies { testImplementation(project(":spring-boot-project:spring-boot-test")) testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) + testImplementation(testFixtures(project(":spring-boot-project:spring-boot"))) testImplementation("io.micrometer:micrometer-observation-test") testImplementation("io.projectreactor:reactor-test") testImplementation("io.prometheus:prometheus-metrics-exposition-formats") diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/MockServletWebServerFactory.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/MockServletWebServerFactory.java deleted file mode 100644 index c750ca4b83a..00000000000 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/MockServletWebServerFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-2023 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.actuate.autoconfigure.web.servlet; - -import java.util.Arrays; - -import jakarta.servlet.ServletContext; - -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredFilter; -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredServlet; -import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; -import org.springframework.boot.web.servlet.server.ServletWebServerFactory; - -import static org.mockito.Mockito.spy; - -/** - * Mock {@link ServletWebServerFactory}. - * - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class MockServletWebServerFactory extends AbstractServletWebServerFactory { - - private MockServletWebServer webServer; - - @Override - public WebServer getWebServer(ServletContextInitializer... initializers) { - this.webServer = spy(new MockServletWebServer(mergeInitializers(initializers), getPort())); - return this.webServer; - } - - public MockServletWebServer getWebServer() { - return this.webServer; - } - - public ServletContext getServletContext() { - return (getWebServer() != null) ? getWebServer().getServletContext() : null; - } - - public RegisteredServlet getRegisteredServlet(int index) { - return (getWebServer() != null) ? getWebServer().getRegisteredServlet(index) : null; - } - - public RegisteredFilter getRegisteredFilter(int index) { - return (getWebServer() != null) ? getWebServer().getRegisteredFilters(index) : null; - } - - static class MockServletWebServer extends org.springframework.boot.testsupport.web.servlet.MockServletWebServer - implements WebServer { - - MockServletWebServer(ServletContextInitializer[] initializers, int port) { - super(Arrays.stream(initializers) - .map((initializer) -> (Initializer) initializer::onStartup) - .toArray(Initializer[]::new), port); - } - - @Override - public void start() { - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index 6d062d9ce6c..c2ead3819e1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -24,6 +24,7 @@ dependencies { dockerTestImplementation(project(":spring-boot-project:spring-boot-test")) dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker")) + dockerTestImplementation(testFixtures(project(":spring-boot-project:spring-boot"))) dockerTestImplementation("com.redis:testcontainers-redis") dockerTestImplementation("org.assertj:assertj-core") dockerTestImplementation("org.awaitility:awaitility") @@ -234,6 +235,7 @@ dependencies { testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) testImplementation(project(":spring-boot-project:spring-boot-test")) + testImplementation(testFixtures(project(":spring-boot-project:spring-boot"))) testImplementation("ch.qos.logback:logback-classic") testImplementation("commons-fileupload:commons-fileupload") testImplementation("com.github.h-thurow:simple-jndi") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java index 2c92ac5ee10..75c03bc0ba7 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -19,10 +19,10 @@ package org.springframework.boot.autoconfigure.condition; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; -import org.springframework.boot.autoconfigure.web.reactive.MockReactiveWebServerFactory; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; +import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java index 83ea467f2b5..1ad6959d8d4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2025 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. @@ -21,8 +21,8 @@ import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.web.reactive.MockReactiveWebServerFactory; import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; +import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext; import org.springframework.context.ConfigurableApplicationContext; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/AbstractSessionAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/AbstractSessionAutoConfigurationTests.java index a01c6b534b4..f6203e7076d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/AbstractSessionAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/session/AbstractSessionAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2025 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. @@ -19,11 +19,11 @@ package org.springframework.boot.autoconfigure.session; import java.util.Collections; import java.util.function.Consumer; -import org.springframework.boot.autoconfigure.web.reactive.MockReactiveWebServerFactory; import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; import org.springframework.boot.test.context.runner.ContextConsumer; import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; +import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/MockReactiveWebServerFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/MockReactiveWebServerFactory.java deleted file mode 100644 index 706fac198b2..00000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/MockReactiveWebServerFactory.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.autoconfigure.web.reactive; - -import java.util.Map; - -import org.springframework.boot.web.reactive.server.AbstractReactiveWebServerFactory; -import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; -import org.springframework.boot.web.server.WebServer; -import org.springframework.http.server.reactive.HttpHandler; - -import static org.mockito.Mockito.spy; - -/** - * Mock {@link ReactiveWebServerFactory}. - * - * @author Brian Clozel - */ -public class MockReactiveWebServerFactory extends AbstractReactiveWebServerFactory { - - private MockReactiveWebServer webServer; - - @Override - public WebServer getWebServer(HttpHandler httpHandler) { - this.webServer = spy(new MockReactiveWebServer(httpHandler, getPort())); - return this.webServer; - } - - public MockReactiveWebServer getWebServer() { - return this.webServer; - } - - static class MockReactiveWebServer implements WebServer { - - private final int port; - - private HttpHandler httpHandler; - - private Map httpHandlerMap; - - MockReactiveWebServer(HttpHandler httpHandler, int port) { - this.httpHandler = httpHandler; - this.port = port; - } - - MockReactiveWebServer(Map httpHandlerMap, int port) { - this.httpHandlerMap = httpHandlerMap; - this.port = port; - } - - HttpHandler getHttpHandler() { - return this.httpHandler; - } - - Map getHttpHandlerMap() { - return this.httpHandlerMap; - } - - @Override - public void start() { - - } - - @Override - public void stop() { - - } - - @Override - public int getPort() { - return this.port; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java index 044c1bfff9f..d10f6185a6e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -45,6 +45,7 @@ import org.springframework.boot.web.embedded.undertow.UndertowReactiveWebServerF import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext; import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory; +import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory; import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.ApplicationContextException; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java index 2d09358f02d..ac9ed313b72 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfigurationTests.java @@ -61,6 +61,7 @@ import org.springframework.boot.testsupport.classpath.resources.WithResource; import org.springframework.boot.web.codec.CodecCustomizer; import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; import org.springframework.boot.web.reactive.filter.OrderedHiddenHttpMethodFilter; +import org.springframework.boot.web.reactive.server.MockReactiveWebServerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/FilterOrderingIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/FilterOrderingIntegrationTests.java index 93d5f4f744d..e567ba36600 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/FilterOrderingIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/FilterOrderingIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -28,11 +28,12 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConf import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.session.SessionAutoConfiguration; import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredFilter; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; import org.springframework.boot.web.servlet.filter.OrderedRequestContextFilter; +import org.springframework.boot.web.servlet.server.MockServletWebServer.RegisteredFilter; +import org.springframework.boot.web.servlet.server.MockServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnection; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java index cde862aba14..4cf0d35ca6c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/HttpEncodingAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -33,6 +33,7 @@ import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostPro import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext; import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; import org.springframework.boot.web.servlet.filter.OrderedHiddenHttpMethodFilter; +import org.springframework.boot.web.servlet.server.MockServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAwareOrderComparator; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/MockServletWebServerFactory.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/MockServletWebServerFactory.java deleted file mode 100644 index 0726b960a37..00000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/MockServletWebServerFactory.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2012-2023 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.autoconfigure.web.servlet; - -import java.util.Arrays; - -import jakarta.servlet.ServletContext; - -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredFilter; -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredServlet; -import org.springframework.boot.web.server.WebServer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; -import org.springframework.boot.web.servlet.server.ServletWebServerFactory; - -import static org.mockito.Mockito.spy; - -/** - * Mock {@link ServletWebServerFactory}. - * - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class MockServletWebServerFactory extends AbstractServletWebServerFactory { - - private MockServletWebServer webServer; - - @Override - public WebServer getWebServer(ServletContextInitializer... initializers) { - this.webServer = spy(new MockServletWebServer(mergeInitializers(initializers), getPort())); - return this.webServer; - } - - public MockServletWebServer getWebServer() { - return this.webServer; - } - - public ServletContext getServletContext() { - return (getWebServer() != null) ? getWebServer().getServletContext() : null; - } - - public RegisteredServlet getRegisteredServlet(int index) { - return (getWebServer() != null) ? getWebServer().getRegisteredServlet(index) : null; - } - - public RegisteredFilter getRegisteredFilter(int index) { - return (getWebServer() != null) ? getWebServer().getRegisteredFilters(index) : null; - } - - static class MockServletWebServer extends org.springframework.boot.testsupport.web.servlet.MockServletWebServer - implements WebServer { - - MockServletWebServer(ServletContextInitializer[] initializers, int port) { - super(Arrays.stream(initializers) - .map((initializer) -> (Initializer) initializer::onStartup) - .toArray(Initializer[]::new), port); - } - - @Override - public void start() { - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java index 689b15bcaf0..9bad1433a18 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfigurationTests.java @@ -47,6 +47,7 @@ import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebSe import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier; +import org.springframework.boot.web.servlet.server.MockServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java index 52d920e34c3..5a3acfa3044 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfigurationTests.java @@ -64,6 +64,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.filter.OrderedFormContentFilter; +import org.springframework.boot.web.servlet.server.MockServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resources.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resources.java index 96e5011b3f2..491afac531b 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resources.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/classpath/resources/Resources.java @@ -18,21 +18,26 @@ package org.springframework.boot.testsupport.classpath.resources; import java.io.IOException; import java.io.UncheckedIOException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import org.springframework.util.Assert; import org.springframework.util.FileSystemUtils; +import org.springframework.util.function.ThrowingConsumer; /** * A collection of resources. @@ -50,27 +55,43 @@ class Resources { } Resources addPackage(Package root, String[] resourceNames) { + String packageName = root.getName(); Set unmatchedNames = new HashSet<>(Arrays.asList(resourceNames)); + withPathsForPackage(packageName, (packagePath) -> { + for (String resourceName : resourceNames) { + Path resource = packagePath.resolve(resourceName); + if (Files.exists(resource) && !Files.isDirectory(resource)) { + Path target = this.root.resolve(resourceName); + Path targetDirectory = target.getParent(); + if (!Files.isDirectory(targetDirectory)) { + Files.createDirectories(targetDirectory); + } + Files.copy(resource, target); + register(resourceName, target, true); + unmatchedNames.remove(resourceName); + } + } + }); + Assert.isTrue(unmatchedNames.isEmpty(), + "Package '" + packageName + "' did not contain resources: " + unmatchedNames); + return this; + } + + private void withPathsForPackage(String packageName, ThrowingConsumer consumer) { try { - Enumeration sources = getClass().getClassLoader().getResources(root.getName().replace(".", "/")); - for (URL source : Collections.list(sources)) { - Path sourceRoot = Paths.get(source.toURI()); - for (String resourceName : resourceNames) { - Path resource = sourceRoot.resolve(resourceName); - if (Files.isRegularFile(resource)) { - Path target = this.root.resolve(resourceName); - Path targetDirectory = target.getParent(); - if (!Files.isDirectory(targetDirectory)) { - Files.createDirectories(targetDirectory); - } - Files.copy(resource, target); - register(resourceName, target, true); - unmatchedNames.remove(resourceName); + List sources = Collections + .list(getClass().getClassLoader().getResources(packageName.replace(".", "/"))); + for (URL source : sources) { + URI sourceUri = source.toURI(); + try { + consumer.accept(Paths.get(sourceUri)); + } + catch (FileSystemNotFoundException ex) { + try (FileSystem fileSystem = FileSystems.newFileSystem(sourceUri, Collections.emptyMap())) { + consumer.accept(Paths.get(sourceUri)); } } } - Assert.isTrue(unmatchedNames.isEmpty(), - "Package '" + root.getName() + "' did not contain resources: " + unmatchedNames); } catch (IOException ex) { throw new UncheckedIOException(ex); @@ -78,7 +99,6 @@ class Resources { catch (URISyntaxException ex) { throw new RuntimeException(ex); } - return this; } Resources addResource(String name, String content, boolean additional) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServerTests.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServerTests.java deleted file mode 100644 index 7004abb4c2d..00000000000 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/test/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServerTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2012-2023 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.testsupport.web.servlet; - -import org.junit.jupiter.api.Test; - -import org.springframework.mock.web.MockSessionCookieConfig; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link MockServletWebServer}. - * - * @author Stephane Nicoll - */ -class MockServletWebServerTests { - - @Test - void servletContextIsConfigured() { - MockServletWebServer server = TestMockServletWebServer.create(); - assertThat(server.getServletContext()).isNotNull(); - } - - @Test - void servletContextHasSessionCookieConfigConfigured() { - MockServletWebServer server = TestMockServletWebServer.create(); - assertThat(server.getServletContext().getSessionCookieConfig()).isInstanceOf(MockSessionCookieConfig.class); - } - - private static final class TestMockServletWebServer extends MockServletWebServer { - - private TestMockServletWebServer(Initializer[] initializers, int port) { - super(initializers, port); - } - - static MockServletWebServer create(Initializer... initializers) { - return new TestMockServletWebServer(initializers, 8080); - } - - } - -} diff --git a/spring-boot-project/spring-boot/build.gradle b/spring-boot-project/spring-boot/build.gradle index 6d8fac07ede..773fa782a3e 100644 --- a/spring-boot-project/spring-boot/build.gradle +++ b/spring-boot-project/spring-boot/build.gradle @@ -1,6 +1,7 @@ plugins { id "dev.adamko.dokkatoo-html" id "java-library" + id "java-test-fixtures" id "org.jetbrains.kotlin.jvm" id "org.springframework.boot.configuration-properties" id "org.springframework.boot.deployed" @@ -99,6 +100,10 @@ dependencies { optional("org.yaml:snakeyaml") optional("org.jetbrains.kotlin:kotlin-reflect") optional("org.jetbrains.kotlin:kotlin-stdlib") + + testFixturesCompileOnly("jakarta.servlet:jakarta.servlet-api") + testFixturesCompileOnly("org.mockito:mockito-core") + testFixturesCompileOnly("org.springframework:spring-web") testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) testImplementation("org.springframework:spring-core-test") diff --git a/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServer.java b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServer.java new file mode 100644 index 00000000000..560a22f501f --- /dev/null +++ b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServer.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012-2025 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.web.reactive.server; + +import java.util.Map; + +import org.springframework.boot.web.server.WebServer; +import org.springframework.http.server.reactive.HttpHandler; + +/** + * A mock reactive {@link WebServer}. + * + * @author Brian Clozel + */ +public class MockReactiveWebServer implements WebServer { + + private final int port; + + private HttpHandler httpHandler; + + private Map httpHandlerMap; + + MockReactiveWebServer(HttpHandler httpHandler, int port) { + this.httpHandler = httpHandler; + this.port = port; + } + + MockReactiveWebServer(Map httpHandlerMap, int port) { + this.httpHandlerMap = httpHandlerMap; + this.port = port; + } + + public HttpHandler getHttpHandler() { + return this.httpHandler; + } + + public Map getHttpHandlerMap() { + return this.httpHandlerMap; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + @Override + public int getPort() { + return this.port; + } + +} diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java similarity index 59% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java rename to spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java index a2c672eb59f..1566c3383e7 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/reactive/server/MockReactiveWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ package org.springframework.boot.web.reactive.server; -import java.util.Map; - import org.springframework.boot.web.server.WebServer; import org.springframework.http.server.reactive.HttpHandler; @@ -42,47 +40,4 @@ public class MockReactiveWebServerFactory extends AbstractReactiveWebServerFacto return this.webServer; } - public static class MockReactiveWebServer implements WebServer { - - private final int port; - - private HttpHandler httpHandler; - - private Map httpHandlerMap; - - MockReactiveWebServer(HttpHandler httpHandler, int port) { - this.httpHandler = httpHandler; - this.port = port; - } - - MockReactiveWebServer(Map httpHandlerMap, int port) { - this.httpHandlerMap = httpHandlerMap; - this.port = port; - } - - public HttpHandler getHttpHandler() { - return this.httpHandler; - } - - public Map getHttpHandlerMap() { - return this.httpHandlerMap; - } - - @Override - public void start() { - - } - - @Override - public void stop() { - - } - - @Override - public int getPort() { - return this.port; - } - - } - } diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServer.java b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServer.java similarity index 86% rename from spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServer.java rename to spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServer.java index 9f5886ab852..6338acd3a1a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/web/servlet/MockServletWebServer.java +++ b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.testsupport.web.servlet; +package org.springframework.boot.web.servlet.server; import java.util.ArrayList; import java.util.Arrays; @@ -31,6 +31,9 @@ import jakarta.servlet.ServletException; import jakarta.servlet.ServletRegistration; import jakarta.servlet.SessionCookieConfig; +import org.springframework.boot.web.server.WebServer; +import org.springframework.boot.web.server.WebServerException; +import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.mock.web.MockSessionCookieConfig; import static org.mockito.ArgumentMatchers.any; @@ -40,14 +43,12 @@ import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; /** - * Base class for Mock {@code ServletWebServer} implementations. Reduces the amount of - * code that would otherwise be duplicated in {@code spring-boot}, - * {@code spring-boot-autoconfigure} and {@code spring-boot-actuator}. + * A mock servlet {@link WebServer}. * * @author Phillip Webb * @author Andy Wilkinson */ -public abstract class MockServletWebServer { +public class MockServletWebServer implements WebServer { private ServletContext servletContext; @@ -59,7 +60,13 @@ public abstract class MockServletWebServer { private final int port; - public MockServletWebServer(Initializer[] initializers, int port) { + MockServletWebServer(ServletContextInitializer[] initializers, int port) { + this(Arrays.stream(initializers) + .map((initializer) -> (Initializer) initializer::onStartup) + .toArray(Initializer[]::new), port); + } + + MockServletWebServer(Initializer[] initializers, int port) { this.initializers = initializers; this.port = port; initialize(); @@ -100,6 +107,11 @@ public abstract class MockServletWebServer { } } + @Override + public void start() throws WebServerException { + } + + @Override public void stop() { this.servletContext = null; this.registeredServlets.clear(); @@ -131,6 +143,7 @@ public abstract class MockServletWebServer { return this.registeredFilters; } + @Override public int getPort() { return this.port; } @@ -184,7 +197,7 @@ public abstract class MockServletWebServer { } /** - * Initializer (usually implement by adapting {@code Initializer}). + * Initializer (usually implement by adapting {@code ServletContextInitializer}). */ @FunctionalInterface protected interface Initializer { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java similarity index 72% rename from spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java rename to spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java index 502af7db905..59151d615e8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java +++ b/spring-boot-project/spring-boot/src/testFixtures/java/org/springframework/boot/web/servlet/server/MockServletWebServerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,12 @@ package org.springframework.boot.web.servlet.server; -import java.util.Arrays; - import jakarta.servlet.ServletContext; -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredFilter; -import org.springframework.boot.testsupport.web.servlet.MockServletWebServer.RegisteredServlet; import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.server.MockServletWebServer.RegisteredFilter; +import org.springframework.boot.web.servlet.server.MockServletWebServer.RegisteredServlet; import static org.mockito.Mockito.spy; @@ -59,19 +57,4 @@ public class MockServletWebServerFactory extends AbstractServletWebServerFactory return (getWebServer() != null) ? getWebServer().getRegisteredFilters(index) : null; } - public static class MockServletWebServer - extends org.springframework.boot.testsupport.web.servlet.MockServletWebServer implements WebServer { - - MockServletWebServer(ServletContextInitializer[] initializers, int port) { - super(Arrays.stream(initializers) - .map((initializer) -> (Initializer) initializer::onStartup) - .toArray(Initializer[]::new), port); - } - - @Override - public void start() { - } - - } - } diff --git a/src/checkstyle/checkstyle-suppressions.xml b/src/checkstyle/checkstyle-suppressions.xml index d44eac1e47e..b1d096a8711 100644 --- a/src/checkstyle/checkstyle-suppressions.xml +++ b/src/checkstyle/checkstyle-suppressions.xml @@ -22,7 +22,7 @@ - +