diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index 953aa1094f..490416d4b9 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -314,8 +314,7 @@ public class TestContextAotGenerator { ClassName processAheadOfTime(MergedContextConfiguration mergedConfig, GenerationContext generationContext) throws TestContextAotException { - GenericApplicationContext gac = loadContextForAotProcessing(mergedConfig); - try { + try (GenericApplicationContext gac = loadContextForAotProcessing(mergedConfig)) { return this.aotGenerator.processAheadOfTime(gac, generationContext); } catch (Throwable ex) { @@ -333,7 +332,7 @@ public class TestContextAotGenerator { * context or if one of the prerequisites is not met * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) */ - private GenericApplicationContext loadContextForAotProcessing( + GenericApplicationContext loadContextForAotProcessing( MergedContextConfiguration mergedConfig) throws TestContextAotException { Class testClass = mergedConfig.getTestClass(); diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java index 2e9dd795cf..de275583b8 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-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,13 +16,23 @@ package org.springframework.test.context.aot; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.aot.generate.GeneratedFiles; +import org.springframework.aot.generate.InMemoryGeneratedFiles; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.SpringProperties; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.context.aot.TestContextAotGenerator.FAIL_ON_ERROR_PROPERTY_NAME; @@ -60,9 +70,55 @@ class TestContextAotGeneratorTests { assertThat(createGenerator().failOnError).isFalse(); } + @Test // gh-34841 + void contextIsClosedAfterAotProcessing() { + DemoTestContextAotGenerator generator = createGenerator(); + generator.processAheadOfTime(Stream.of(TestCase1.class, TestCase2.class)); - private static TestContextAotGenerator createGenerator() { - return new TestContextAotGenerator(null); + assertThat(generator.contexts) + .allSatisfy(context -> assertThat(context.isClosed()).as("context is closed").isTrue()); + } + + + private static DemoTestContextAotGenerator createGenerator() { + return new DemoTestContextAotGenerator(new InMemoryGeneratedFiles()); + } + + + private static class DemoTestContextAotGenerator extends TestContextAotGenerator { + + List contexts = new ArrayList<>(); + + DemoTestContextAotGenerator(GeneratedFiles generatedFiles) { + super(generatedFiles); + } + + @Override + GenericApplicationContext loadContextForAotProcessing( + MergedContextConfiguration mergedConfig) throws TestContextAotException { + + GenericApplicationContext context = super.loadContextForAotProcessing(mergedConfig); + this.contexts.add(context); + return context; + } + } + + @SpringJUnitConfig + private static class TestCase1 { + + @Configuration(proxyBeanMethods = false) + static class Config { + // no beans + } + } + + @SpringJUnitConfig + private static class TestCase2 { + + @Configuration(proxyBeanMethods = false) + static class Config { + // no beans + } } }