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;
 }

Reply via email to