diff --git a/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/extensions/spring/test/context/support/CloseApplicationContextAfterTestClassTestExecutionListener.java b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/extensions/spring/test/context/support/CloseApplicationContextAfterTestClassTestExecutionListener.java new file mode 100644 index 0000000..eca88db --- /dev/null +++ b/spring-data-geode-test/src/main/java/org/springframework/data/gemfire/tests/extensions/spring/test/context/support/CloseApplicationContextAfterTestClassTestExecutionListener.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019 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.data.gemfire.tests.extensions.spring.test.context.support; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import org.springframework.context.ApplicationContext; +import org.springframework.core.SpringProperties; +import org.springframework.lang.NonNull; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestContext; +import org.springframework.test.context.TestExecutionListener; + +/** + * Spring {@link TestContext} framework {@link org.springframework.test.context.TestExecutionListener} used to + * close the {@link org.springframework.context.ApplicationContext} after test class execution. + * + * This {@link TestExecutionListener} is configurable via {@link SpringProperties} + * or by declaring Java {@link System#getProperties() System properties}. + * + * @author John Blum + * @see org.springframework.context.ApplicationContext + * @see org.springframework.core.SpringProperties + * @see org.springframework.test.annotation.DirtiesContext + * @see org.springframework.test.context.TestContext + * @see org.springframework.test.context.TestExecutionListener + * @since 1.0.0 + */ +@SuppressWarnings("all") +public class CloseApplicationContextAfterTestClassTestExecutionListener implements TestExecutionListener { + + protected static final boolean DEFAULT_SPRING_TEST_CONTEXT_CLOSED = false; + + protected static final String SPRING_TEST_CONTEXT_CLOSE_PROPERTY = "spring.test.context.close"; + + protected static final DirtiesContext.HierarchyMode DEFAULT_HIERARCHY_MODE = + DirtiesContext.HierarchyMode.CURRENT_LEVEL; + + private final AtomicReference springTestContextCloseEnabled = new AtomicReference<>(); + + protected boolean isSpringTestContextCloseEnabled() { + return this.springTestContextCloseEnabled.updateAndGet(closeEnabled -> closeEnabled != null ? closeEnabled + : getSpringTestContextCloseEnabledResolvingFunction().apply(DEFAULT_SPRING_TEST_CONTEXT_CLOSED)); + } + + @SuppressWarnings("all") + protected Function getSpringTestContextCloseEnabledResolvingFunction() { + + return defaultCloseEnabled -> { + + String closeEnabledProperty = SpringProperties.getProperty(SPRING_TEST_CONTEXT_CLOSE_PROPERTY); + + boolean resolvedCloseEnabled = Boolean.parseBoolean(closeEnabledProperty) || defaultCloseEnabled; + + return resolvedCloseEnabled; + }; + } + + /** + * Closes the {@link ApplicationContext} associated with the given, required {@link TestContext} + * after the test class instance executes. + * + * This operation is implemented by marking the {@link ApplicationContext} as dirty. + * + * @param testContext Spring {@link TestContext} + * @throws Exception if the {@link ApplicationContext} close operation fails. + * @see org.springframework.test.context.TestContext#markApplicationContextDirty(DirtiesContext.HierarchyMode) + * @see #isSpringTestContextCloseEnabled() + */ + @Override + public void afterTestClass(@NonNull TestContext testContext) throws Exception { + + if (isSpringTestContextCloseEnabled()) { + TestExecutionListener.super.afterTestClass(testContext); + testContext.markApplicationContextDirty(DEFAULT_HIERARCHY_MODE); + } + } +} diff --git a/spring-data-geode-test/src/main/resources/META-INF/spring.factories b/spring-data-geode-test/src/main/resources/META-INF/spring.factories index c6d543a..a0018e1 100644 --- a/spring-data-geode-test/src/main/resources/META-INF/spring.factories +++ b/spring-data-geode-test/src/main/resources/META-INF/spring.factories @@ -1,4 +1,7 @@ # Spring Test for Apache Geode (STDG) framework configuration for the Spring TestContext Framework. -org.springframework.test.context.ContextCustomizerFactory=\ +org.springframework.test.context.ContextCustomizerFactory = \ org.springframework.data.gemfire.tests.extensions.spring.test.context.DependencyOfAnnotationContextCustomizerFactory + +org.springframework.test.context.TestExecutionListener = \ + org.springframework.data.gemfire.tests.extensions.spring.test.context.support.CloseApplicationContextAfterTestClassTestExecutionListener diff --git a/spring-data-geode-test/src/main/resources/spring.properties b/spring-data-geode-test/src/main/resources/spring.properties index 6ef528a..1e024a5 100644 --- a/spring-data-geode-test/src/main/resources/spring.properties +++ b/spring-data-geode-test/src/main/resources/spring.properties @@ -1,4 +1,4 @@ # Spring Test for Apache Geode (STDG) framework configuration for the Spring Framework. -spring.test.context.default.CacheAwareContextLoaderDelegate=\ +spring.test.context.default.CacheAwareContextLoaderDelegate = \ org.springframework.data.gemfire.tests.extensions.spring.test.context.cache.ConfigurableCacheAwareContextLoaderDelegate