This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch Log4jEventRecorder
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit dba68fd3ce19719e711e3ab234a09bf4c5d3add0
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Mon May 8 22:37:58 2023 +0200

    Add JUnit 5 test-method-scoped `LoggerContext`s
---
 .../log4j/core/test/junit/Log4jEventRecorder.java  | 86 ++++++++++++++++++++++
 .../core/test/junit/Log4jEventRecorderAnchor.java  | 56 ++++++++++++++
 .../core/test/junit/Log4jEventRecorderEnabled.java | 32 ++++++++
 .../junit/Log4jEventRecorderParameterResolver.java | 34 +++++++++
 .../test/junit/Log4jEventRecorderTerminator.java   | 29 ++++++++
 .../core/test/junit/Log4jEventRecorderTest.java    | 44 +++++++++++
 6 files changed, 281 insertions(+)

diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorder.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorder.java
new file mode 100644
index 0000000000..a7c305b021
--- /dev/null
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorder.java
@@ -0,0 +1,86 @@
+/*
+ * 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.core.test.junit;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.impl.MutableLogEvent;
+import org.apache.logging.log4j.core.layout.PatternLayout;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public final class Log4jEventRecorder implements AutoCloseable {
+
+    private static final String LOGGER_CONTEXT_NAME_PREFIX = 
Log4jEventRecorder.class.getSimpleName() + "-LoggerContext-";
+
+    private static final AtomicInteger LOGGER_CONTEXT_COUNTER = new 
AtomicInteger(0);
+
+    private final InternalLog4jAppender appender;
+
+    private final LoggerContext loggerContext;
+
+    private static final class InternalLog4jAppender extends AbstractAppender {
+
+        private static final PatternLayout LAYOUT = 
PatternLayout.createDefaultLayout();
+
+        private final List<LogEvent> events;
+
+        private InternalLog4jAppender() {
+            super("ListAppender", null, LAYOUT, false, null);
+            this.events = Collections.synchronizedList(new ArrayList<>());
+            start();
+        }
+
+        @Override
+        public void append(final LogEvent event) {
+            final LogEvent copySafeEvent = event instanceof MutableLogEvent
+                    ? ((MutableLogEvent) event).createMemento()
+                    : event;
+            events.add(copySafeEvent);
+        }
+
+    }
+
+    Log4jEventRecorder() {
+        this.appender = new InternalLog4jAppender();
+        this.loggerContext = new LoggerContext(LOGGER_CONTEXT_NAME_PREFIX + 
LOGGER_CONTEXT_COUNTER.getAndIncrement());
+        final LoggerConfig rootConfig = 
loggerContext.getConfiguration().getRootLogger();
+        rootConfig.setLevel(Level.ALL);
+        rootConfig.getAppenders().values().forEach(appender -> 
rootConfig.removeAppender(appender.getName()));
+        rootConfig.addAppender(appender, Level.ALL, null);
+    }
+
+    public org.apache.logging.log4j.spi.LoggerContext getLoggerContext() {
+        return loggerContext;
+    }
+
+    public List<LogEvent> getEvents() {
+        return appender.events;
+    }
+
+    @Override
+    public void close() {
+        loggerContext.close();
+    }
+
+}
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderAnchor.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderAnchor.java
new file mode 100644
index 0000000000..b3dd0dc163
--- /dev/null
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderAnchor.java
@@ -0,0 +1,56 @@
+/*
+ * 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.core.test.junit;
+
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+final class Log4jEventRecorderAnchor {
+
+    private Log4jEventRecorderAnchor() {}
+
+    static Log4jEventRecorder recorder(
+            final ExtensionContext extensionContext,
+            final ParameterContext parameterContext) {
+        return recorderByParameterName(extensionContext).computeIfAbsent(
+                parameterContext.getParameter().getName(),
+                ignored -> new Log4jEventRecorder());
+    }
+
+    static Collection<Log4jEventRecorder> recorders(final ExtensionContext 
extensionContext) {
+        return recorderByParameterName(extensionContext).values();
+    }
+
+    private static Map<String, Log4jEventRecorder> 
recorderByParameterName(final ExtensionContext extensionContext) {
+        ExtensionContext.Namespace namespace = 
ExtensionContext.Namespace.create(
+                Log4jEventRecorder.class,
+                extensionContext.getRequiredTestClass(),
+                extensionContext.getRequiredTestMethod());
+        final ExtensionContext.Store store = 
extensionContext.getStore(namespace);
+        @SuppressWarnings("unchecked")
+        final Map<String, Log4jEventRecorder> recorderByParameterName = 
store.getOrComputeIfAbsent(
+                "recorderByParameterName",
+                ignored -> new LinkedHashMap<>(),
+                Map.class);
+        return recorderByParameterName;
+    }
+
+}
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderEnabled.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderEnabled.java
new file mode 100644
index 0000000000..41b5f8a3cb
--- /dev/null
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderEnabled.java
@@ -0,0 +1,32 @@
+/*
+ * 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.core.test.junit;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Enables JUnit support resolving test method parameters of type {@link 
Log4jEventRecorder}.
+ */
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@ExtendWith({Log4jEventRecorderTerminator.class, 
Log4jEventRecorderParameterResolver.class})
+public @interface Log4jEventRecorderEnabled {}
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderParameterResolver.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderParameterResolver.java
new file mode 100644
index 0000000000..c2221fcea1
--- /dev/null
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderParameterResolver.java
@@ -0,0 +1,34 @@
+/*
+ * 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.core.test.junit;
+
+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;
+
+public final class Log4jEventRecorderParameterResolver extends 
TypeBasedParameterResolver<Log4jEventRecorder> {
+
+    @Override
+    public Log4jEventRecorder resolveParameter(
+            final ParameterContext parameterContext,
+            final ExtensionContext extensionContext
+    ) throws ParameterResolutionException {
+        return Log4jEventRecorderAnchor.recorder(extensionContext, 
parameterContext);
+    }
+
+}
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTerminator.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTerminator.java
new file mode 100644
index 0000000000..157521d5ae
--- /dev/null
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTerminator.java
@@ -0,0 +1,29 @@
+/*
+ * 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.core.test.junit;
+
+import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+public final class Log4jEventRecorderTerminator implements 
AfterTestExecutionCallback {
+
+    @Override
+    public void afterTestExecution(final ExtensionContext extensionContext) {
+        
Log4jEventRecorderAnchor.recorders(extensionContext).forEach(Log4jEventRecorder::close);
+    }
+
+}
diff --git 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTest.java
 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTest.java
new file mode 100644
index 0000000000..b881c6ae14
--- /dev/null
+++ 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/test/junit/Log4jEventRecorderTest.java
@@ -0,0 +1,44 @@
+package org.apache.logging.log4j.core.test.junit;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Log4jEventRecorderEnabled
+class Log4jEventRecorderTest {
+
+    @Test
+    void should_succeed_when_run_even_in_parallel(final Log4jEventRecorder 
eventRecorder) {
+
+        // Log events
+        final int eventCount = 3;//1 + (int) (Math.random() * 1000D);
+        final Logger logger = 
eventRecorder.getLoggerContext().getLogger(Log4jEventRecorderTest.class);
+        for (int eventIndex = 0; eventIndex < eventCount; eventIndex++) {
+            logger.trace("test message {}", eventIndex);
+        }
+
+        // Verify logged levels
+        final List<LogEvent> events = eventRecorder.getEvents();
+        assertThat(events).allMatch(event -> 
Level.TRACE.equals(event.getLevel()));
+
+        // Verify logged messages
+        final List<String> expectedMessages = IntStream
+                .range(0, eventCount)
+                .mapToObj(eventIndex -> String.format("test message %d", 
eventIndex))
+                .collect(Collectors.toList());
+        final List<String> actualMessages = events
+                .stream()
+                .map(event -> event.getMessage().getFormattedMessage())
+                .collect(Collectors.toList());
+        assertThat(actualMessages).containsExactlyElementsOf(expectedMessages);
+
+    }
+
+}

Reply via email to