This is an automated email from the ASF dual-hosted git repository. mattsicker pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 1fb8aaee0704cafbe074f9b5c180b4a87e2ae096 Author: Matt Sicker <[email protected]> AuthorDate: Mon Sep 7 14:13:20 2020 -0500 Support shutdown timeout in JUnit 5 extension This ports over the previous functionality to specify a custom shutdown timeout when stopping a LoggerContext in unit tests. Signed-off-by: Matt Sicker <[email protected]> --- .../logging/log4j/junit/LoggerContextResolver.java | 95 +++++++++++++++------- .../logging/log4j/junit/LoggerContextRule.java | 3 + .../logging/log4j/junit/LoggerContextSource.java | 11 +++ 3 files changed, 80 insertions(+), 29 deletions(-) diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextResolver.java b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextResolver.java index fb0f367..3a92d3b 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextResolver.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextResolver.java @@ -18,6 +18,7 @@ package org.apache.logging.log4j.junit; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.LoggerContextAccessor; import org.apache.logging.log4j.core.config.Configurator; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.AfterEachCallback; @@ -29,6 +30,7 @@ import org.junit.jupiter.api.extension.ParameterResolutionException; import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; class LoggerContextResolver extends TypeBasedParameterResolver<LoggerContext> implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback { @@ -37,59 +39,64 @@ class LoggerContextResolver extends TypeBasedParameterResolver<LoggerContext> im final Class<?> testClass = context.getRequiredTestClass(); final LoggerContextSource testSource = testClass.getAnnotation(LoggerContextSource.class); if (testSource != null) { - final LoggerContext loggerContext = - Configurator.initialize(context.getDisplayName(), testClass.getClassLoader(), testSource.value()); - getTestClassStore(context).put(LoggerContext.class, loggerContext); + final LoggerContextConfig config = new LoggerContextConfig(testSource, context); + getTestClassStore(context).put(LoggerContext.class, config); } } @Override public void afterAll(ExtensionContext context) throws Exception { - final LoggerContext loggerContext = getTestClassStore(context).get(LoggerContext.class, LoggerContext.class); - if (loggerContext != null) { - loggerContext.close(); + final LoggerContextConfig config = + getTestClassStore(context).get(LoggerContext.class, LoggerContextConfig.class); + if (config != null) { + config.close(); } } @Override public void beforeEach(ExtensionContext context) throws Exception { final Class<?> testClass = context.getRequiredTestClass(); - final LoggerContextSource testSource = testClass.getAnnotation(LoggerContextSource.class); - if (testSource != null && testSource.reconfigure() == ReconfigurationPolicy.BEFORE_EACH) { - final LoggerContext loggerContext = getTestClassStore(context).get(LoggerContext.class, LoggerContext.class); - if (loggerContext == null) { + if (testClass.isAnnotationPresent(LoggerContextSource.class)) { + final LoggerContextConfig config = getTestClassStore(context).get(LoggerContext.class, LoggerContextConfig.class); + if (config == null) { throw new IllegalStateException( - "Specified test class reconfiguration policy of BEFORE_EACH, but no LoggerContext found for test class " + + "Specified @LoggerContextSource but no LoggerContext found for test class " + testClass.getCanonicalName()); } - loggerContext.reconfigure(); + if (config.reconfigurationPolicy == ReconfigurationPolicy.BEFORE_EACH) { + config.reconfigure(); + } } final LoggerContextSource source = context.getRequiredTestMethod().getAnnotation(LoggerContextSource.class); if (source != null) { - final LoggerContext loggerContext = Configurator - .initialize(context.getDisplayName(), testClass.getClassLoader(), source.value()); - getTestInstanceStore(context).put(LoggerContext.class, loggerContext); + final LoggerContextConfig config = new LoggerContextConfig(source, context); + if (config.reconfigurationPolicy == ReconfigurationPolicy.BEFORE_EACH) { + config.reconfigure(); + } + getTestInstanceStore(context).put(LoggerContext.class, config); } } @Override public void afterEach(ExtensionContext context) throws Exception { // method-annotated variant - final LoggerContext testInstanceContext = getTestInstanceStore(context).get(LoggerContext.class, LoggerContext.class); - if (testInstanceContext != null) { - testInstanceContext.close(); + final LoggerContextConfig testInstanceConfig = + getTestInstanceStore(context).get(LoggerContext.class, LoggerContextConfig.class); + if (testInstanceConfig != null) { + testInstanceConfig.close(); } // reloadable variant final Class<?> testClass = context.getRequiredTestClass(); - final LoggerContextSource source = testClass.getAnnotation(LoggerContextSource.class); - if (source != null && source.reconfigure() == ReconfigurationPolicy.AFTER_EACH) { - final LoggerContext loggerContext = getTestClassStore(context).get(LoggerContext.class, LoggerContext.class); - if (loggerContext == null) { + if (testClass.isAnnotationPresent(LoggerContextSource.class)) { + final LoggerContextConfig config = getTestClassStore(context).get(LoggerContext.class, LoggerContextConfig.class); + if (config == null) { throw new IllegalStateException( - "Specified test class reconfiguration policy of AFTER_EACH, but no LoggerContext found for test class " + + "Specified @LoggerContextSource but no LoggerContext found for test class " + testClass.getCanonicalName()); } - loggerContext.reconfigure(); + if (config.reconfigurationPolicy == ReconfigurationPolicy.AFTER_EACH) { + config.reconfigure(); + } } } @@ -109,12 +116,42 @@ class LoggerContextResolver extends TypeBasedParameterResolver<LoggerContext> im static LoggerContext getParameterLoggerContext(ParameterContext parameterContext, ExtensionContext extensionContext) { if (parameterContext.getDeclaringExecutable() instanceof Method) { - final LoggerContext loggerContext = - getTestInstanceStore(extensionContext).get(LoggerContext.class, LoggerContext.class); - return loggerContext != null ? loggerContext : - getTestClassStore(extensionContext).get(LoggerContext.class, LoggerContext.class); + final LoggerContextAccessor accessor = + getTestInstanceStore(extensionContext).get(LoggerContext.class, LoggerContextAccessor.class); + return accessor != null ? accessor.getLoggerContext() : + getTestClassStore(extensionContext).get(LoggerContext.class, LoggerContextAccessor.class).getLoggerContext(); + } + return getTestClassStore(extensionContext).get(LoggerContext.class, LoggerContextAccessor.class).getLoggerContext(); + } + + private static class LoggerContextConfig implements AutoCloseable, LoggerContextAccessor { + private final LoggerContext context; + private final ReconfigurationPolicy reconfigurationPolicy; + private final long shutdownTimeout; + private final TimeUnit unit; + + private LoggerContextConfig(final LoggerContextSource source, final ExtensionContext extensionContext) { + final String displayName = extensionContext.getDisplayName(); + final ClassLoader classLoader = extensionContext.getRequiredTestClass().getClassLoader(); + context = Configurator.initialize(displayName, classLoader, source.value()); + reconfigurationPolicy = source.reconfigure(); + shutdownTimeout = source.timeout(); + unit = source.unit(); + } + + @Override + public LoggerContext getLoggerContext() { + return context; + } + + public void reconfigure() { + context.reconfigure(); + } + + @Override + public void close() { + context.stop(shutdownTimeout, unit); } - return getTestClassStore(extensionContext).get(LoggerContext.class, LoggerContext.class); } } diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextRule.java b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextRule.java index 2215350..73a994a 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextRule.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextRule.java @@ -42,6 +42,9 @@ import static org.junit.Assert.*; * property {@code EBUG} is set (e.g., through the command line option {@code -DEBUG}), then the StatusLogger will be * set to the debug level. This allows for more debug messages as the StatusLogger will be in the error level until a * configuration file has been read and parsed into a tree of Nodes. + * + * @see LoggerContextSource + * @see Named */ public class LoggerContextRule implements TestRule, LoggerContextAccessor { diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextSource.java b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextSource.java index a6cedfb..e0cba27 100644 --- a/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextSource.java +++ b/log4j-core/src/test/java/org/apache/logging/log4j/junit/LoggerContextSource.java @@ -29,6 +29,7 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.util.concurrent.TimeUnit; /** * Specifies a configuration file to use for unit tests. This configuration file will be loaded once and used for all tests @@ -65,4 +66,14 @@ public @interface LoggerContextSource { * Specifies when to {@linkplain LoggerContext#reconfigure() reconfigure} the logging system. */ ReconfigurationPolicy reconfigure() default ReconfigurationPolicy.NEVER; + + /** + * Specifies the shutdown timeout limit. Defaults to 0 to mean no limit. + */ + long timeout() default 0L; + + /** + * Specifies the time unit {@link #timeout()} is measured in. + */ + TimeUnit unit() default TimeUnit.SECONDS; }
