This is an automated email from the ASF dual-hosted git repository. pkarwasz pushed a commit to branch parallel-tests in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 3a249203ba88962b53837dd64968e5e3ae739536 Author: Piotr P. Karwasz <[email protected]> AuthorDate: Fri Jun 24 21:12:01 2022 +0200 Add `StatusMessages` and `TestProperties` extension Add a JUnit 5 extension, which: * capture per-test status logger messages and print them to the console only if the test fails, * set properties that apply only to the current thread. --- log4j-api-test/pom.xml | 1 + ...herSessionListener.java => StatusMessages.java} | 27 ++-- ...herSessionListener.java => TestProperties.java} | 27 ++-- .../log4j/test/junit/ExtensionContextAnchor.java | 8 +- .../test/junit/Log4j2LauncherSessionListener.java | 33 ++++- .../logging/log4j/test/junit/SetTestProperty.java | 59 +++++++++ .../log4j/test/junit/StatusLoggerExtension.java | 134 ++++++++++++++++++++ .../log4j/test/junit/TestPropertyResolver.java | 75 +++++++++++ .../log4j/test/junit/TestPropertySource.java | 141 +++++++++++++++++++++ ...SessionListener.java => UsingStatusLogger.java} | 33 +++-- ...ssionListener.java => UsingTestProperties.java} | 36 ++++-- .../org.junit.jupiter.api.extension.Extension | 4 +- 12 files changed, 522 insertions(+), 56 deletions(-) diff --git a/log4j-api-test/pom.xml b/log4j-api-test/pom.xml index 698af4e3bc..de7d3667a6 100644 --- a/log4j-api-test/pom.xml +++ b/log4j-api-test/pom.xml @@ -147,6 +147,7 @@ <!-- Enables the `ExtensionContextAnchor` on each test --> <junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled> <junit.jupiter.testclass.order.default>org.junit.jupiter.api.ClassOrderer$Random</junit.jupiter.testclass.order.default> + <log4j2.junit.disableConsoleStatusListener>true</log4j2.junit.disableConsoleStatusListener> </systemPropertyVariables> </configuration> </plugin> diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/StatusMessages.java similarity index 58% copy from log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java copy to log4j-api-test/src/main/java/org/apache/logging/log4j/test/StatusMessages.java index 51abd82afe..e59a10ce8e 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/StatusMessages.java @@ -14,22 +14,23 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.test.junit; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.junit.platform.launcher.LauncherSession; -import org.junit.platform.launcher.LauncherSessionListener; +package org.apache.logging.log4j.test; -/** - * Global Log4j2 test setup. - */ -public class Log4j2LauncherSessionListener implements LauncherSessionListener { +import java.util.stream.Stream; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.status.StatusData; + +public interface StatusMessages { - @Override - public void launcherSessionOpened(LauncherSession session) { - // Prevents `PropertiesUtil` from initializing (and caching the results) - // in the middle of a test. - PropertiesUtil.getProperties(); + Stream<StatusData> getMessages(); + + default Stream<StatusData> findStatusMessages(Level level) { + return getMessages().filter(data -> level.isLessSpecificThan(data.getLevel())); } + default Stream<StatusData> findStatusMessages(Level level, String regex) { + return findStatusMessages(level).filter(data -> data.getMessage().getFormattedMessage().matches(regex)); + } } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestProperties.java similarity index 59% copy from log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java copy to log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestProperties.java index 51abd82afe..0c66fc8b94 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/TestProperties.java @@ -14,22 +14,27 @@ * See the license for the specific language governing permissions and * limitations under the license. */ -package org.apache.logging.log4j.test.junit; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.junit.platform.launcher.LauncherSession; -import org.junit.platform.launcher.LauncherSessionListener; +package org.apache.logging.log4j.test; /** - * Global Log4j2 test setup. + * A container for per-test properties. */ -public class Log4j2LauncherSessionListener implements LauncherSessionListener { +public interface TestProperties { - @Override - public void launcherSessionOpened(LauncherSession session) { - // Prevents `PropertiesUtil` from initializing (and caching the results) - // in the middle of a test. - PropertiesUtil.getProperties(); + String getProperty(final String key); + + boolean containsProperty(final String key); + + void setProperty(final String key, final String value); + + default void setProperty(final String key, final boolean value) { + setProperty(key, value ? "true" : "false"); + } + + default void setProperty(final String key, final int value) { + setProperty(key, Integer.toString(value)); } + void clearProperty(final String key); } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ExtensionContextAnchor.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ExtensionContextAnchor.java index 0b4cc50d60..25c3117171 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ExtensionContextAnchor.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/ExtensionContextAnchor.java @@ -32,7 +32,7 @@ public class ExtensionContextAnchor public static Namespace LOG4J2_NAMESPACE = Namespace.create("org.apache.logging.log4j.junit"); private static final ThreadLocal<ExtensionContext> EXTENSION_CONTEXT = new InheritableThreadLocal<>(); - private static void bind(ExtensionContext context) { + static void bind(ExtensionContext context) { EXTENSION_CONTEXT.set(context); } @@ -48,19 +48,19 @@ public class ExtensionContextAnchor return context != null ? context : EXTENSION_CONTEXT.get(); } - static <T> T getAttribute(Object key, Class<T> clazz, ExtensionContext context) { + public static <T> T getAttribute(Object key, Class<T> clazz, ExtensionContext context) { final ExtensionContext actualContext = getContext(context); assertNotNull(actualContext, "missing ExtensionContext"); return actualContext.getStore(LOG4J2_NAMESPACE).get(key, clazz); } - static void setAttribute(Object key, Object value, ExtensionContext context) { + public static void setAttribute(Object key, Object value, ExtensionContext context) { final ExtensionContext actualContext = getContext(context); assertNotNull(actualContext, "missing ExtensionContext"); actualContext.getStore(LOG4J2_NAMESPACE).put(key, value); } - static void removeAttribute(Object key, ExtensionContext context) { + public static void removeAttribute(Object key, ExtensionContext context) { final ExtensionContext actualContext = getContext(context); if (actualContext != null) { actualContext.getStore(LOG4J2_NAMESPACE).remove(key); diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java index 51abd82afe..c88aa37d73 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java @@ -16,6 +16,11 @@ */ package org.apache.logging.log4j.test.junit; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.status.StatusConsoleListener; +import org.apache.logging.log4j.status.StatusData; +import org.apache.logging.log4j.status.StatusListener; +import org.apache.logging.log4j.status.StatusLogger; import org.apache.logging.log4j.util.PropertiesUtil; import org.junit.platform.launcher.LauncherSession; import org.junit.platform.launcher.LauncherSessionListener; @@ -25,11 +30,37 @@ import org.junit.platform.launcher.LauncherSessionListener; */ public class Log4j2LauncherSessionListener implements LauncherSessionListener { + private static final String DISABLE_CONSOLE_STATUS_LISTENER = "log4j2.junit.disableConsoleStatusListener"; + @Override public void launcherSessionOpened(LauncherSession session) { // Prevents `PropertiesUtil` from initializing (and caching the results) // in the middle of a test. - PropertiesUtil.getProperties(); + final PropertiesUtil properties = PropertiesUtil.getProperties(); + if (properties.getBooleanProperty(DISABLE_CONSOLE_STATUS_LISTENER)) { + replaceStatusConsoleListener(); + } + } + + private static void replaceStatusConsoleListener() { + final StatusLogger logger = StatusLogger.getLogger(); + for (final StatusListener listener : logger.getListeners()) { + if (listener instanceof StatusConsoleListener) { + logger.removeListener(listener); + } + } + logger.registerListener(new NoOpStatusConsoleListener()); + } + + private static class NoOpStatusConsoleListener extends StatusConsoleListener { + + public NoOpStatusConsoleListener() { + super(Level.OFF); + } + + public void log(final StatusData data) { + // NOP + } } } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SetTestProperty.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SetTestProperty.java new file mode 100644 index 0000000000..d277125255 --- /dev/null +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/SetTestProperty.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.logging.log4j.test.junit; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Registers a Log4j2 system property with the {@link TestPropertySource}. The + * property will also be available in configuration files using the + * {@code ${test:...} lookup. + * + */ +@Retention(RUNTIME) +@Target({ TYPE, METHOD }) +@Inherited +@Documented +@ExtendWith(ExtensionContextAnchor.class) +@ExtendWith(TestPropertyResolver.class) +@Repeatable(SetTestProperty.SetTestProperties.class) +public @interface SetTestProperty { + + String key(); + + String value(); + + @Retention(RUNTIME) + @Target({ TYPE, METHOD }) + @Documented + @Inherited + public @interface SetTestProperties { + + SetTestProperty[] value(); + } +} diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java new file mode 100644 index 0000000000..e2cfdacfa8 --- /dev/null +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/StatusLoggerExtension.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.logging.log4j.test.junit; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.status.StatusConsoleListener; +import org.apache.logging.log4j.status.StatusData; +import org.apache.logging.log4j.status.StatusListener; +import org.apache.logging.log4j.status.StatusLogger; +import org.apache.logging.log4j.test.StatusMessages; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Store.CloseableResource; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; +import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; + +public class StatusLoggerExtension extends TypeBasedParameterResolver<StatusMessages> + implements BeforeEachCallback, TestExecutionExceptionHandler { + + private static final StatusLogger LOGGER = StatusLogger.getLogger(); + private static final StatusConsoleListener CONSOLE_LISTENER = new StatusConsoleListener(Level.ALL); + private static final Object KEY = StatusMessages.class; + + public StatusLoggerExtension() { + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + ExtensionContextAnchor.bind(context); + final StatusMessagesHolder holder = new StatusMessagesHolder(context); + ExtensionContextAnchor.setAttribute(KEY, holder, context); + } + + @Override + public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { + printStatusMessages(context); + throw throwable; + } + + public void printStatusMessages(ExtensionContext context) { + final StatusMessages statusListener = getStatusMessages(context); + statusListener.getMessages().forEach(CONSOLE_LISTENER::log); + } + + @Override + public StatusMessages resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return getStatusMessages(extensionContext); + } + + private static StatusMessages getStatusMessages(ExtensionContext extensionContext) { + final StatusMessagesHolder holder = ExtensionContextAnchor.getAttribute(KEY, StatusMessagesHolder.class, + extensionContext); + return holder.get(); + } + + private static class StatusMessagesHolder implements CloseableResource, Supplier<StatusMessages> { + + private final JUnitStatusMessages statusListener; + + public StatusMessagesHolder(ExtensionContext context) { + this.statusListener = new JUnitStatusMessages(context); + LOGGER.registerListener(statusListener); + } + + @Override + public StatusMessages get() { + return statusListener; + } + + @Override + public void close() throws Throwable { + LOGGER.removeListener(statusListener); + } + + } + + private static class JUnitStatusMessages implements StatusMessages, StatusListener { + + private final ExtensionContext context; + private final List<StatusData> statusData = Collections.synchronizedList(new ArrayList<StatusData>()); + + public JUnitStatusMessages(ExtensionContext context) { + this.context = context; + } + + @Override + public void log(StatusData data) { + if (context.equals(ExtensionContextAnchor.getContext())) { + statusData.add(data); + } + } + + @Override + public Level getStatusLevel() { + return Level.DEBUG; + } + + @Override + public void close() throws IOException { + // NOP + } + + @Override + public Stream<StatusData> getMessages() { + return statusData.stream(); + } + + } +} diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertyResolver.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertyResolver.java new file mode 100644 index 0000000000..7c7e9177af --- /dev/null +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertyResolver.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.logging.log4j.test.junit; + +import java.lang.reflect.Modifier; + +import org.apache.logging.log4j.test.TestProperties; +import org.apache.logging.log4j.util.ReflectionUtil; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; +import org.junit.platform.commons.util.AnnotationUtils; + +public class TestPropertyResolver extends TypeBasedParameterResolver<TestProperties> + implements BeforeAllCallback, BeforeEachCallback { + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + final TestProperties props = TestPropertySource.createProperties(context); + final SetTestProperty[] setProperties = context.getRequiredTestMethod() + .getAnnotationsByType(SetTestProperty.class); + if (setProperties.length > 0) { + for (final SetTestProperty setProperty : setProperties) { + props.setProperty(setProperty.key(), setProperty.value()); + } + } + final Class<?> testClass = context.getRequiredTestClass(); + Object testInstance = context.getRequiredTestInstance(); + AnnotationUtils + .findAnnotatedFields(testClass, UsingTestProperties.class, + field -> !Modifier.isStatic(field.getModifiers())) + .forEach(field -> ReflectionUtil.setFieldValue(field, testInstance, props)); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + final TestProperties props = TestPropertySource.createProperties(context); + final SetTestProperty[] setProperties = context.getRequiredTestClass() + .getAnnotationsByType(SetTestProperty.class); + if (setProperties.length > 0) { + for (final SetTestProperty setProperty : setProperties) { + props.setProperty(setProperty.key(), setProperty.value()); + } + } + final Class<?> testClass = context.getRequiredTestClass(); + AnnotationUtils + .findAnnotatedFields(testClass, UsingTestProperties.class, + field -> Modifier.isStatic(field.getModifiers())) + .forEach(field -> ReflectionUtil.setStaticFieldValue(field, props)); + } + + @Override + public TestProperties resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return TestPropertySource.createProperties(extensionContext); + } +} diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertySource.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertySource.java new file mode 100644 index 0000000000..92547a463f --- /dev/null +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/TestPropertySource.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 + * + * http://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.apache.logging.log4j.test.junit; + +import org.apache.logging.log4j.test.TestProperties; +import org.apache.logging.log4j.util.PropertySource; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ExtensionContext.Namespace; +import org.junit.jupiter.api.extension.ExtensionContext.Store; + +public class TestPropertySource implements PropertySource { + + private static final String PREFIX = "log4j2."; + private static final Namespace NAMESPACE = ExtensionContextAnchor.LOG4J2_NAMESPACE.append("properties"); + private static final TestProperties EMPTY_PROPERTIES = new EmptyTestProperties(); + + @Override + public int getPriority() { + // Highest priority + return Integer.MIN_VALUE; + } + + public static TestProperties createProperties(ExtensionContext context) { + TestProperties props = getProperties(context); + // Make sure that the properties do not come from the parent ExtensionContext + if (props instanceof JUnitTestProperties && context.equals(((JUnitTestProperties) props).getContext())) { + return props; + } + props = new JUnitTestProperties(context); + ExtensionContextAnchor.setAttribute(TestProperties.class, props, context); + return props; + } + + private static TestProperties getProperties() { + return getProperties(null); + } + + private static TestProperties getProperties(ExtensionContext context) { + final ExtensionContext actualContext = context != null ? context : ExtensionContextAnchor.getContext(); + if (actualContext != null) { + TestProperties props = ExtensionContextAnchor.getAttribute(TestProperties.class, TestProperties.class, + actualContext); + if (props != null) { + return props; + } + } + return EMPTY_PROPERTIES; + } + + @Override + public CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) { + final CharSequence camelCase = Util.joinAsCamelCase(tokens); + // Do not use Strings to prevent recursive initialization + return camelCase.length() > 0 ? PREFIX + camelCase.toString() : null; + } + + @Override + public String getProperty(String key) { + return getProperties().getProperty(key); + } + + @Override + public boolean containsProperty(String key) { + return getProperties().containsProperty(key); + } + + private static class JUnitTestProperties implements TestProperties { + + private final ExtensionContext context; + private final Store store; + + public JUnitTestProperties(ExtensionContext context) { + this.context = context; + this.store = context.getStore(NAMESPACE); + } + + public ExtensionContext getContext() { + return context; + } + + @Override + public String getProperty(String key) { + return store.get(key, String.class); + } + + @Override + public boolean containsProperty(String key) { + return getProperty(key) != null; + } + + @Override + public void setProperty(String key, String value) { + store.put(key, value); + } + + @Override + public void clearProperty(String key) { + store.remove(key, String.class); + } + + } + + private static class EmptyTestProperties implements TestProperties { + + @Override + public String getProperty(String key) { + return null; + } + + @Override + public boolean containsProperty(String key) { + return false; + } + + @Override + public void setProperty(String key, String value) { + throw new UnsupportedOperationException(); + } + + @Override + public void clearProperty(String key) { + throw new UnsupportedOperationException(); + } + + } +} diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingStatusLogger.java similarity index 53% copy from log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java copy to log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingStatusLogger.java index 51abd82afe..875973415d 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingStatusLogger.java @@ -14,22 +14,29 @@ * See the license for the specific language governing permissions and * limitations under the license. */ + package org.apache.logging.log4j.test.junit; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.junit.platform.launcher.LauncherSession; -import org.junit.platform.launcher.LauncherSessionListener; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.junit.jupiter.api.extension.ExtendWith; /** - * Global Log4j2 test setup. + * Marks a test class as using {@link org.apache.logging.log4j.ThreadContext} APIs. This will automatically clear and restore + * both the thread context map and stack for each test invocation. + * + * @since 2.14.0 */ -public class Log4j2LauncherSessionListener implements LauncherSessionListener { - - @Override - public void launcherSessionOpened(LauncherSession session) { - // Prevents `PropertiesUtil` from initializing (and caching the results) - // in the middle of a test. - PropertiesUtil.getProperties(); - } - +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Documented +@Inherited +@ExtendWith(ExtensionContextAnchor.class) +@ExtendWith(StatusLoggerExtension.class) +public @interface UsingStatusLogger { } diff --git a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingTestProperties.java similarity index 50% copy from log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java copy to log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingTestProperties.java index 51abd82afe..eb9ab84267 100644 --- a/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/Log4j2LauncherSessionListener.java +++ b/log4j-api-test/src/main/java/org/apache/logging/log4j/test/junit/UsingTestProperties.java @@ -14,22 +14,32 @@ * See the license for the specific language governing permissions and * limitations under the license. */ + package org.apache.logging.log4j.test.junit; -import org.apache.logging.log4j.util.PropertiesUtil; -import org.junit.platform.launcher.LauncherSession; -import org.junit.platform.launcher.LauncherSessionListener; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; -/** - * Global Log4j2 test setup. - */ -public class Log4j2LauncherSessionListener implements LauncherSessionListener { +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; - @Override - public void launcherSessionOpened(LauncherSession session) { - // Prevents `PropertiesUtil` from initializing (and caching the results) - // in the middle of a test. - PropertiesUtil.getProperties(); - } +import org.apache.logging.log4j.test.TestProperties; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junitpioneer.jupiter.ReadsSystemProperty; +/** + * A field or method parameter of type {@link TestProperties} will be injected with a per-test source of Log4j2's + * system properties. + */ +@Retention(RUNTIME) +@Target({ FIELD, METHOD }) +@Inherited +@Documented +@ExtendWith(ExtensionContextAnchor.class) +@ExtendWith(TestPropertyResolver.class) +@ReadsSystemProperty +public @interface UsingTestProperties { } diff --git a/log4j-api-test/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension b/log4j-api-test/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension index ca7ce84edd..a28e0eea70 100644 --- a/log4j-api-test/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension +++ b/log4j-api-test/src/main/resources/META-INF/services/org.junit.jupiter.api.extension.Extension @@ -12,4 +12,6 @@ # 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. -org.apache.logging.log4j.test.junit.ExtensionContextAnchor \ No newline at end of file + +org.apache.logging.log4j.test.junit.ExtensionContextAnchor +org.apache.logging.log4j.test.junit.StatusLoggerExtension \ No newline at end of file
