From f5b6514befd9ce22eab88183c0c77e7f8b541829 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 18 Sep 2024 13:02:23 -0700 Subject: [PATCH] Allow additional context interfaces to be defined for testing Update `AssertableApplicationContext` and `ApplicationContextRunner` implementations to support additional `ApplicationContext` interfaces. Closes gh-42369 --- .../ApplicationContextAssertProvider.java | 38 +++++++++++++++++-- .../assertj/AssertableApplicationContext.java | 18 ++++++++- ...sertableReactiveWebApplicationContext.java | 20 +++++++++- .../AssertableWebApplicationContext.java | 18 ++++++++- .../AbstractApplicationContextRunner.java | 35 ++++++++++++++--- .../runner/ApplicationContextRunner.java | 20 ++++++++-- .../ReactiveWebApplicationContextRunner.java | 21 ++++++++-- .../runner/WebApplicationContextRunner.java | 20 ++++++++-- .../assertj/AdditionalContextInterface.java | 28 ++++++++++++++ .../AssertableApplicationContextTests.java | 13 ++++++- ...bleReactiveWebApplicationContextTests.java | 13 ++++++- .../AssertableWebApplicationContextTests.java | 13 ++++++- ...AbstractApplicationContextRunnerTests.java | 10 ++++- .../runner/AdditionalContextInterface.java | 28 ++++++++++++++ .../runner/ApplicationContextRunnerTests.java | 14 ++++++- ...ctiveWebApplicationContextRunnerTests.java | 14 ++++++- .../WebApplicationContextRunnerTests.java | 14 ++++++- .../extension/MyExtensionConfiguration.java | 2 +- 18 files changed, 310 insertions(+), 29 deletions(-) create mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AdditionalContextInterface.java create mode 100644 spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AdditionalContextInterface.java diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProvider.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProvider.java index f7fdf21223..8542c5aa67 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProvider.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/ApplicationContextAssertProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -18,12 +18,14 @@ package org.springframework.boot.test.context.assertj; import java.io.Closeable; import java.lang.reflect.Proxy; +import java.util.Arrays; import java.util.function.Supplier; import org.assertj.core.api.AssertProvider; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** * An {@link ApplicationContext} that additionally supports AssertJ style assertions. Can @@ -101,16 +103,46 @@ public interface ApplicationContextAssertProvider * {@link ApplicationContext} or throw an exception if the context fails to start. * @return a {@link ApplicationContextAssertProvider} instance */ - @SuppressWarnings("unchecked") static , C extends ApplicationContext> T get(Class type, Class contextType, Supplier contextSupplier) { + return get(type, contextType, contextSupplier, new Class[0]); + } + + /** + * Factory method to create a new {@link ApplicationContextAssertProvider} instance. + * @param the assert provider type + * @param the context type + * @param type the type of {@link ApplicationContextAssertProvider} required (must be + * an interface) + * @param contextType the type of {@link ApplicationContext} being managed (must be an + * interface) + * @param contextSupplier a supplier that will either return a fully configured + * {@link ApplicationContext} or throw an exception if the context fails to start. + * @param additionalContextInterfaces and additional context interfaces to add to the + * proxy + * @return a {@link ApplicationContextAssertProvider} instance + * @since 3.4.0 + */ + @SuppressWarnings("unchecked") + static , C extends ApplicationContext> T get(Class type, + Class contextType, Supplier contextSupplier, + Class... additionalContextInterfaces) { Assert.notNull(type, "Type must not be null"); Assert.isTrue(type.isInterface(), "Type must be an interface"); Assert.notNull(contextType, "ContextType must not be null"); Assert.isTrue(contextType.isInterface(), "ContextType must be an interface"); - Class[] interfaces = { type, contextType }; + Class[] interfaces = merge(new Class[] { type, contextType }, additionalContextInterfaces); return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), interfaces, new AssertProviderApplicationContextInvocationHandler(contextType, contextSupplier)); } + private static Class[] merge(Class[] classes, Class[] additional) { + if (ObjectUtils.isEmpty(additional)) { + return classes; + } + Class[] result = Arrays.copyOf(classes, classes.length + additional.length); + System.arraycopy(additional, 0, result, classes.length, additional.length); + return result; + } + } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableApplicationContext.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableApplicationContext.java index 9c2a4782f2..7cc7fa40b2 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableApplicationContext.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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. @@ -49,4 +49,20 @@ public interface AssertableApplicationContext ConfigurableApplicationContext.class, contextSupplier); } + /** + * Factory method to create a new {@link AssertableApplicationContext} instance. + * @param contextSupplier a supplier that will either return a fully configured + * {@link ConfigurableApplicationContext} or throw an exception if the context fails + * to start. + * @param additionalContextInterfaces and additional context interfaces to add to the + * proxy + * @return an {@link AssertableApplicationContext} instance + * @since 3.4.0 + */ + static AssertableApplicationContext get(Supplier contextSupplier, + Class... additionalContextInterfaces) { + return ApplicationContextAssertProvider.get(AssertableApplicationContext.class, + ConfigurableApplicationContext.class, contextSupplier, additionalContextInterfaces); + } + } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContext.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContext.java index 5af5a9fdd9..c18ec13eb6 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContext.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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. @@ -51,4 +51,22 @@ public interface AssertableReactiveWebApplicationContext ConfigurableReactiveWebApplicationContext.class, contextSupplier); } + /** + * Factory method to create a new {@link AssertableReactiveWebApplicationContext} + * instance. + * @param contextSupplier a supplier that will either return a fully configured + * {@link ConfigurableReactiveWebApplicationContext} or throw an exception if the + * context fails to start. + * @param additionalContextInterfaces and additional context interfaces to add to the + * proxy + * @return a {@link AssertableReactiveWebApplicationContext} instance + * @since 3.4.0 + */ + static AssertableReactiveWebApplicationContext get( + Supplier contextSupplier, + Class... additionalContextInterfaces) { + return ApplicationContextAssertProvider.get(AssertableReactiveWebApplicationContext.class, + ConfigurableReactiveWebApplicationContext.class, contextSupplier, additionalContextInterfaces); + } + } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContext.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContext.java index 96a7d03dd1..314b43503b 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContext.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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. @@ -49,4 +49,20 @@ public interface AssertableWebApplicationContext ConfigurableWebApplicationContext.class, contextSupplier); } + /** + * Factory method to create a new {@link AssertableWebApplicationContext} instance. + * @param contextSupplier a supplier that will either return a fully configured + * {@link ConfigurableWebApplicationContext} or throw an exception if the context + * fails to start. + * @param additionalContextInterfaces and additional context interfaces to add to the + * proxy + * @return a {@link AssertableWebApplicationContext} instance + * @since 3.4.0 + */ + static AssertableWebApplicationContext get(Supplier contextSupplier, + Class... additionalContextInterfaces) { + return ApplicationContextAssertProvider.get(AssertableWebApplicationContext.class, + ConfigurableWebApplicationContext.class, contextSupplier, additionalContextInterfaces); + } + } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java index 635222f8c7..6a7bd66727 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -106,6 +106,8 @@ import org.springframework.util.Assert; */ public abstract class AbstractApplicationContextRunner, C extends ConfigurableApplicationContext, A extends ApplicationContextAssertProvider> { + private static final Class[] NO_ADDITIONAL_CONTEXT_INTERFACES = {}; + private final RunnerConfiguration runnerConfiguration; private final Function, SELF> instanceFactory; @@ -115,13 +117,29 @@ public abstract class AbstractApplicationContextRunner contextFactory, Function, SELF> instanceFactory) { - Assert.notNull(contextFactory, "ContextFactory must not be null"); - Assert.notNull(contextFactory, "RunnerConfiguration must not be null"); - this.runnerConfiguration = new RunnerConfiguration<>(contextFactory); + this(instanceFactory, contextFactory, NO_ADDITIONAL_CONTEXT_INTERFACES); + } + + /** + * Create a new {@link AbstractApplicationContextRunner} instance. + * @param instanceFactory the factory used to create new instance of the runner + * @param contextFactory the factory used to create the actual context + * @param additionalContextInterfaces any additional application context interfaces to + * be added to the application context proxy + * @since 3.4.0 + */ + protected AbstractApplicationContextRunner(Function, SELF> instanceFactory, + Supplier contextFactory, Class... additionalContextInterfaces) { + Assert.notNull(instanceFactory, "'instanceFactory' must not be null"); + Assert.notNull(contextFactory, "'contextFactory' must not be null"); this.instanceFactory = instanceFactory; + this.runnerConfiguration = new RunnerConfiguration<>(contextFactory, additionalContextInterfaces); } /** @@ -386,7 +404,8 @@ public abstract class AbstractApplicationContextRunner assertType = (Class) resolvableType.resolveGeneric(1); Class contextType = (Class) resolvableType.resolveGeneric(2); - return ApplicationContextAssertProvider.get(assertType, contextType, () -> createAndLoadContext(refresh)); + return ApplicationContextAssertProvider.get(assertType, contextType, () -> createAndLoadContext(refresh), + this.runnerConfiguration.additionalContextInterfaces); } private C createAndLoadContext(boolean refresh) { @@ -472,6 +491,8 @@ public abstract class AbstractApplicationContextRunner contextFactory; + private final Class[] additionalContextInterfaces; + private boolean allowBeanDefinitionOverriding = false; private boolean allowCircularReferences = false; @@ -490,12 +511,14 @@ public abstract class AbstractApplicationContextRunner configurations = Collections.emptyList(); - private RunnerConfiguration(Supplier contextFactory) { + private RunnerConfiguration(Supplier contextFactory, Class[] additionalContextInterfaces) { this.contextFactory = contextFactory; + this.additionalContextInterfaces = additionalContextInterfaces; } private RunnerConfiguration(RunnerConfiguration source) { this.contextFactory = source.contextFactory; + this.additionalContextInterfaces = source.additionalContextInterfaces; this.allowBeanDefinitionOverriding = source.allowBeanDefinitionOverriding; this.allowCircularReferences = source.allowCircularReferences; this.initializers = source.initializers; diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java index 83de2a500d..b7d87ed42a 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -47,10 +47,24 @@ public class ApplicationContextRunner extends /** * Create a new {@link ApplicationContextRunner} instance using the specified * {@code contextFactory} as the underlying source. - * @param contextFactory a supplier that returns a new instance on each call + * @param contextFactory a supplier that returns a new instance on each call be added + * to the application context proxy */ public ApplicationContextRunner(Supplier contextFactory) { - super(contextFactory, ApplicationContextRunner::new); + super(ApplicationContextRunner::new, contextFactory); + } + + /** + * Create a new {@link ApplicationContextRunner} instance using the specified + * {@code contextFactory} as the underlying source. + * @param contextFactory a supplier that returns a new instance on each call + * @param additionalContextInterfaces any additional application context interfaces to + * be added to the application context proxy + * @since 3.4.0 + */ + public ApplicationContextRunner(Supplier contextFactory, + Class... additionalContextInterfaces) { + super(ApplicationContextRunner::new, contextFactory, additionalContextInterfaces); } private ApplicationContextRunner(RunnerConfiguration runnerConfiguration) { diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java index 77c99ecc5b..6274b01bf2 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -47,10 +47,25 @@ public final class ReactiveWebApplicationContextRunner extends /** * Create a new {@link ApplicationContextRunner} instance using the specified * {@code contextFactory} as the underlying source. - * @param contextFactory a supplier that returns a new instance on each call + * @param contextFactory a supplier that returns a new instance on each call be added + * to the application context proxy + * @since 3.4.0 */ public ReactiveWebApplicationContextRunner(Supplier contextFactory) { - super(contextFactory, ReactiveWebApplicationContextRunner::new); + super(ReactiveWebApplicationContextRunner::new, contextFactory); + } + + /** + * Create a new {@link ApplicationContextRunner} instance using the specified + * {@code contextFactory} as the underlying source. + * @param contextFactory a supplier that returns a new instance on each call + * @param additionalContextInterfaces any additional application context interfaces to + * be added to the application context proxy + * @since 3.4.0 + */ + public ReactiveWebApplicationContextRunner(Supplier contextFactory, + Class... additionalContextInterfaces) { + super(ReactiveWebApplicationContextRunner::new, contextFactory, additionalContextInterfaces); } private ReactiveWebApplicationContextRunner( diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java index fd186a747a..5528bdbb81 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2024 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. @@ -51,10 +51,24 @@ public final class WebApplicationContextRunner extends /** * Create a new {@link WebApplicationContextRunner} instance using the specified * {@code contextFactory} as the underlying source. - * @param contextFactory a supplier that returns a new instance on each call + * @param contextFactory a supplier that returns a new instance on each call be added + * to the application context proxy */ public WebApplicationContextRunner(Supplier contextFactory) { - super(contextFactory, WebApplicationContextRunner::new); + super(WebApplicationContextRunner::new, contextFactory); + } + + /** + * Create a new {@link WebApplicationContextRunner} instance using the specified + * {@code contextFactory} as the underlying source. + * @param contextFactory a supplier that returns a new instance on each call + * @param additionalContextInterfaces any additional application context interfaces to + * be added to the application context proxy + * @since 3.4.0 + */ + public WebApplicationContextRunner(Supplier contextFactory, + Class... additionalContextInterfaces) { + super(WebApplicationContextRunner::new, contextFactory, additionalContextInterfaces); } private WebApplicationContextRunner(RunnerConfiguration configuration) { diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AdditionalContextInterface.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AdditionalContextInterface.java new file mode 100644 index 0000000000..0144ffc616 --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AdditionalContextInterface.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2024 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.context.assertj; + +import org.springframework.context.ApplicationContext; + +/** + * Tests extra interface that can be applied to an {@link ApplicationContext} + * + * @author Phillip Webb + */ +interface AdditionalContextInterface { + +} diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java index 91189ce2a9..3ff56807dd 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -22,6 +22,7 @@ import org.springframework.context.ConfigurableApplicationContext; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.withSettings; /** * Tests for {@link AssertableApplicationContext}. @@ -38,4 +39,14 @@ class AssertableApplicationContextTests { assertThat(context).isInstanceOf(ConfigurableApplicationContext.class); } + @Test + void getWhenHasAdditionalInterfaceShouldReturnProxy() { + AssertableApplicationContext context = AssertableApplicationContext.get( + () -> mock(ConfigurableApplicationContext.class, + withSettings().extraInterfaces(AdditionalContextInterface.class)), + AdditionalContextInterface.class); + assertThat(context).isInstanceOf(ConfigurableApplicationContext.class) + .isInstanceOf(AdditionalContextInterface.class); + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java index b84b776bbd..0947f9b80e 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableReactiveWebApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -22,6 +22,7 @@ import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebAppl import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.withSettings; /** * Tests for {@link AssertableReactiveWebApplicationContext}. @@ -38,4 +39,14 @@ class AssertableReactiveWebApplicationContextTests { assertThat(context).isInstanceOf(ConfigurableReactiveWebApplicationContext.class); } + @Test + void getWhenHasAdditionalInterfaceShouldReturnProxy() { + AssertableReactiveWebApplicationContext context = AssertableReactiveWebApplicationContext.get( + () -> mock(ConfigurableReactiveWebApplicationContext.class, + withSettings().extraInterfaces(AdditionalContextInterface.class)), + AdditionalContextInterface.class); + assertThat(context).isInstanceOf(ConfigurableReactiveWebApplicationContext.class) + .isInstanceOf(AdditionalContextInterface.class); + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java index 53873f9c47..1a2268dbc0 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/assertj/AssertableWebApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -22,6 +22,7 @@ import org.springframework.web.context.ConfigurableWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.withSettings; /** * Tests for {@link AssertableWebApplicationContext}. @@ -38,4 +39,14 @@ class AssertableWebApplicationContextTests { assertThat(context).isInstanceOf(ConfigurableWebApplicationContext.class); } + @Test + void getWhenHasAdditionalInterfaceShouldReturnProxy() { + ConfigurableWebApplicationContext context = AssertableWebApplicationContext.get( + () -> mock(ConfigurableWebApplicationContext.class, + withSettings().extraInterfaces(AdditionalContextInterface.class)), + AdditionalContextInterface.class); + assertThat(context).isInstanceOf(ConfigurableWebApplicationContext.class) + .isInstanceOf(AdditionalContextInterface.class); + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java index cd309da536..d4a38ce5de 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -258,8 +258,16 @@ abstract class AbstractApplicationContextRunnerTests assertThat(context).isInstanceOf(AdditionalContextInterface.class)); + } + protected abstract T get(); + protected abstract T getWithAdditionalContextInterface(); + private static void throwCheckedException(String message) throws IOException { throw new IOException(message); } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AdditionalContextInterface.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AdditionalContextInterface.java new file mode 100644 index 0000000000..b66a01715b --- /dev/null +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AdditionalContextInterface.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2024 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.context.runner; + +import org.springframework.context.ApplicationContext; + +/** + * Tests extra interface that can be applied to an {@link ApplicationContext} + * + * @author Phillip Webb + */ +interface AdditionalContextInterface { + +} diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ApplicationContextRunnerTests.java index 462d58b9a5..86966fccb7 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ApplicationContextRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -18,6 +18,7 @@ package org.springframework.boot.test.context.runner; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * Tests for {@link ApplicationContextRunner}. @@ -33,4 +34,15 @@ class ApplicationContextRunnerTests extends return new ApplicationContextRunner(); } + @Override + protected ApplicationContextRunner getWithAdditionalContextInterface() { + return new ApplicationContextRunner(TestAnnotationConfigApplicationContext::new, + AdditionalContextInterface.class); + } + + static class TestAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext + implements AdditionalContextInterface { + + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunnerTests.java index 6d859b7d78..cf7a66f901 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * Copyright 2012-2024 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. @@ -17,6 +17,7 @@ package org.springframework.boot.test.context.runner; import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplicationContext; +import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; import org.springframework.boot.web.reactive.context.ConfigurableReactiveWebApplicationContext; /** @@ -33,4 +34,15 @@ class ReactiveWebApplicationContextRunnerTests extends return new ReactiveWebApplicationContextRunner(); } + @Override + protected ReactiveWebApplicationContextRunner getWithAdditionalContextInterface() { + return new ReactiveWebApplicationContextRunner(TestAnnotationConfigReactiveWebApplicationContext::new, + AdditionalContextInterface.class); + } + + static class TestAnnotationConfigReactiveWebApplicationContext extends AnnotationConfigReactiveWebApplicationContext + implements AdditionalContextInterface { + + } + } diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/WebApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/WebApplicationContextRunnerTests.java index edf448ff07..8d2ede8f98 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/WebApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/WebApplicationContextRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2024 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,6 +19,7 @@ package org.springframework.boot.test.context.runner; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebApplicationContext; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.ConfigurableWebApplicationContext; @@ -43,4 +44,15 @@ class WebApplicationContextRunnerTests extends return new WebApplicationContextRunner(); } + @Override + protected WebApplicationContextRunner getWithAdditionalContextInterface() { + return new WebApplicationContextRunner(TestAnnotationConfigServletWebApplicationContext::new, + AdditionalContextInterface.class); + } + + static class TestAnnotationConfigServletWebApplicationContext extends AnnotationConfigServletWebApplicationContext + implements AdditionalContextInterface { + + } + } diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionConfiguration.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionConfiguration.java index 8fe5193658..bec987b68e 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionConfiguration.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-actuator-extension/src/main/java/smoketest/actuator/extension/MyExtensionConfiguration.java @@ -50,7 +50,7 @@ public class MyExtensionConfiguration { List> filters = Collections .singletonList(new MyExtensionEndpointFilter(environment)); WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(applicationContext, parameterMapper, - endpointMediaTypes, null, invokerAdvisors, filters); + endpointMediaTypes, null, null, invokerAdvisors, filters); Collection endpoints = discoverer.getEndpoints(); return new MyExtensionWebMvcEndpointHandlerMapping(endpoints, endpointMediaTypes, corsConfiguration); }