Cache of non working refactors - neighbourhoodie/logging-log4j2 GitHub Wiki

core-test

RollingAppenderNoUnconditionalDeleteTest

/*
 * 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.appender.rolling.RollingAppenderNoUnconditionalDeleteTest;
package org.apache.logging.log4j.core.appender.rolling;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.Arrays;

import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;
// import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;

import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.BeforeAll;
// import org.junit.jupiter.api.Rule;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.apache.logging.log4j.core.test.junit.ReconfigurationPolicy;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.provider.MethodSource;

// import org.junit.jupiter.api.runner.RunWith;
// import org.junit.jupiter.api.runners.Parameterized;

/**
 * reconfigure = ReconfigurationPolicy.AFTER_EACH
 */
@LoggerContextSource(timeout = 10)
public class RollingAppenderNoUnconditionalDeleteTest {

    private File directory;

    static Stream<Arguments> data() {
        return Stream.of(
            Arguments.of("log4j-rolling-with-custom-delete-unconditional1.xml", "target/rolling-unconditional-delete1/test"),
            Arguments.of("log4j-rolling-with-custom-delete-unconditional2.xml", "target/rolling-unconditional-delete2/test"),
            Arguments.of("log4j-rolling-with-custom-delete-unconditional3.xml", "target/rolling-unconditional-delete3/test")
        );
    }

    @ParameterizedTest(name = "{0} \u2192 {1}")
    @MethodSource("data")
    // @LoggerContextSource(timeout = 10)
    public void testAppender(String configFile, String dir, LoggerContext ctx) throws Exception {
        this.directory = new File(dir);
        // file shuld not be deleted
        //  main ERROR Missing Delete conditions: unconditional Delete not supported
        deleteDir();
        deleteDirParent();
        ctx = new LoggerContext(configFile);
        System.out.println("#### ctx.getName() ### " + ctx.getName());
        // LoggerContext loggerContext = new LoggerContext(configFile);
        System.out.println("######## directory #####" + directory);
        // Initialize LoggerContext
        // LoggerContext loggerContext = Configurator.initialize("TestContext", configFile);
        Logger logger = ctx.getLogger(RollingAppenderNoUnconditionalDeleteTest.class.getName());

        //  // Ensure directory is created before test
        if (!directory.exists() && !directory.mkdirs()) {
            System.out.println("#### failed ### " + directory.getAbsolutePath());
        }

        final int LINECOUNT = 18; // config has max="100"
        for (int i = 0; i < LINECOUNT; ++i) {
            // 30 chars per message: each message triggers a rollover
            logger.debug("This is a test message number " + i); // 30 chars:
             System.out.println("Logging message: " + i);
             // After logging, explicitly flush if necessary

        }
        Thread.sleep(100); // Allow time for rollover to complete
        // System.out.println("Directory path: " + directory.getAbsolutePath());

        System.out.println("#### directory exists ### " + directory.exists());
        System.out.println("#### directory length ###" + directory.listFiles().length);
        // System.out.println("#### this.directory ###" + this.directory);
        assertTrue(directory.exists(), "Dir " + directory + " should exist");
        assertTrue(directory.listFiles().length > 0, "Dir " + directory + " should contain files");

        int total = 0;
        for (final File file : directory.listFiles()) {
            final List<String> lines = Files.readAllLines(file.toPath(), Charset.defaultCharset());
            total += lines.size();
        }
        assertEquals(LINECOUNT - 1, total, "rolled over lines");
    }

    private void deleteDir() {
        deleteDir(directory);
    }

    private void deleteDirParent() {
        deleteDir(directory.getParentFile());
    }

    private void deleteDir(final File dir) {
        // System.out.println("#### deleteDir #########");
        // System.out.println("#### deleteDir exists ####" + dir.exists());
          if (dir.exists()) {
            for (File file : dir.listFiles()) {
                file.delete();
            }
            dir.delete();
        }
        // if (dir.exists()) {
        //     final File[] files = dir.listFiles();
        //     for (final File file : files) {
        //         file.delete();
        //     }
        //     dir.delete();
        // }
    }
}

RoutesScriptAppenderTest

/*
 * 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.appender.routing;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Stream;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.AppenderControl;
import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.core.test.junit.Named;
import org.apache.logging.log4j.core.util.Constants;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

@Tag("Scripts.Groovy") // technically only half of these tests require groovy
@LoggerContextSource
public class RoutesScriptAppenderTest {

    static Stream<Object[]> getParameters() {
        return Stream.of(
                new Object[] {"log4j-routing-routes-script-groovy.xml", false},
                new Object[] {"log4j-routing-routes-script-javascript.xml", false},
                new Object[] {"log4j-routing-script-staticvars-javascript.xml", true},
                new Object[] {"log4j-routing-script-staticvars-groovy.xml", true});
    }

    @BeforeAll
    public static void beforeAll() {
        System.setProperty(Constants.SCRIPT_LANGUAGES, "Groovy, JavaScript");
    }

    // @Rule
    // public final LoggerContextRule loggerContextRule;
    public LoggerContext loggerContext;

    private final boolean expectBindingEntries;

    public RoutesScriptAppenderTest(final boolean expectBindingEntries) {
        this.expectBindingEntries = expectBindingEntries;
    }

    @ParameterizedTest(name = "{0} {1}")
    @MethodSource("getParameters")
    void testRoutesScriptAppender(String configLocation, boolean expectBindingEntries) {
        this.loggerContext = new LoggerContext(configLocation);
        // LoggerContextRule loggerContextRule = new LoggerContextRule(configLocation);
        // Replace or refactor your assertions and test logic using loggerContextRule and expectBindingEntries
    }

    private void checkStaticVars() {
        final RoutingAppender routingAppender = getRoutingAppender();
        final ConcurrentMap<Object, Object> map = routingAppender.getScriptStaticVariables();
        if (expectBindingEntries) {
            assertEquals("TestValue2", map.get("TestKey"));
            assertEquals("HEXDUMP", map.get("MarkerName"));
        }
    }

    private ListAppender getListAppender() {
        final String key = "Service2";
        final RoutingAppender routingAppender = getRoutingAppender();
        assertTrue(routingAppender.isStarted());
        final Map<String, AppenderControl> appenders = routingAppender.getAppenders();
        final AppenderControl appenderControl = appenders.get(key);
        assertNotNull(appenderControl, "No appender control generated for '" + key + "'; appenders = " + appenders);
        return (ListAppender) appenderControl.getAppender();
    }

    private RoutingAppender getRoutingAppender(@Named("Routing") final RoutingAppender appender) {
        return appender;
    }

    private void logAndCheck(LoggerContext ctx) {
        final Marker marker = MarkerManager.getMarker("HEXDUMP");
        final Logger logger = ctx.getLogger(RoutesScriptAppenderTest.class);
        logger.error("Hello");
        final ListAppender listAppender = getListAppender();
        assertEquals(1, listAppender.getEvents().size(), "Incorrect number of events");
        logger.error("World");
        assertEquals(2, listAppender.getEvents().size(), "Incorrect number of events");
        logger.error(marker, "DEADBEEF");
        assertEquals(3, listAppender.getEvents().size(), "Incorrect number of events");
    }

    // @Test
    // public void testAppenderAbsence(LoggerContext ctx) {
    //     assertThrows(AssertionError.class, () -> ctx.getListAppender("List1"));
    // }

    // @Test
    // public void testListAppenderPresence() {
    //     // No appender until an event is routed, even thought we initialized the default route on startup.
    //     assertNull(
    //             "No appender control generated",
    //             getRoutingAppender().getAppenders().get("Service2"));
    // }

    // @Test
    // public void testNoPurgePolicy() {
    //     // No PurgePolicy in this test
    //     assertNull("Unexpected PurgePolicy", getRoutingAppender().getPurgePolicy());
    // }

    @Test
    public void testNoRewritePolicy() {
        // No RewritePolicy in this test
        assertNull("Unexpected RewritePolicy", getRoutingAppender().getRewritePolicy());
    }

    @Test
    public void testRoutingAppenderRoutes() {
        final RoutingAppender routingAppender = getRoutingAppender();
        assertEquals(expectBindingEntries, routingAppender.getDefaultRouteScript() != null);
        assertEquals(expectBindingEntries, routingAppender.getDefaultRoute() != null);
        final Routes routes = routingAppender.getRoutes();
        assertNotNull(routes);
        assertNotNull(routes.getPatternScript());
        final LogEvent logEvent =
                DefaultLogEventFactory.getInstance().createEvent("", null, "", Level.ERROR, null, null, null);
        assertEquals("Service2", routes.getPattern(logEvent, new ConcurrentHashMap<>()));
    }

    @Test
    public void testRoutingAppenderPresence() {
        getRoutingAppender();
    }

    @Test
    public void testRoutingPresence1() {
        logAndCheck();
        checkStaticVars();
    }

    @Test
    public void testRoutingPresence2() {
        logAndCheck();
        checkStaticVars();
    }
}

LogEventFactoryTest

/*
 * 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;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import java.lang.reflect.Field;
import java.util.List;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.impl.DefaultLogEventFactory;
import org.apache.logging.log4j.core.impl.LocationAwareLogEventFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.impl.LogEventFactory;
import org.apache.logging.log4j.core.test.appender.ListAppender;
import org.apache.logging.log4j.core.test.junit.LoggerContextSource;
import org.apache.logging.log4j.core.test.junit.Named;
import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.message.Message;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

/**
 *
 */
@LoggerContextSource("log4j2-config.xml")
public class LogEventFactoryTest {
    private ListAppender app;

    @AfterEach
    public void teardown(final LoggerContext context) throws IllegalAccessException {
        // Clear the LogEventFactory property and reset to default
        System.clearProperty(Constants.LOG4J_LOG_EVENT_FACTORY);
        resetLogEventFactory(new DefaultLogEventFactory());

        // Reload the context again to apply the reset configuration
        context.reconfigure();
    }

    // this would look so cool using lambdas
    private static void resetLogEventFactory(final LogEventFactory logEventFactory) throws IllegalAccessException {
        final Field field = FieldUtils.getField(LoggerConfig.class, "LOG_EVENT_FACTORY", true);
        FieldUtils.removeFinalModifier(field);
        FieldUtils.writeStaticField(field, logEventFactory, false);
    }

    @BeforeEach
    public void beforeEach(@Named("List") final ListAppender listAppender, final LoggerContext context)
            throws IllegalAccessException {
        this.app = listAppender.clear();

        // Set up the custom LogEventFactory
        System.setProperty(Constants.LOG4J_LOG_EVENT_FACTORY, TestLogEventFactory.class.getName());
        resetLogEventFactory(new TestLogEventFactory());

        // Reload the context to pick up the new configuration
        context.reconfigure();
    }

    @Test
    public void testEvent(final LoggerContext context) {
        final org.apache.logging.log4j.Logger logger = context.getLogger("org.apache.test.LogEventFactory");
        logger.error("error message");
        final List<LogEvent> events = app.getEvents();
        assertNotNull(events, "No events");
        assertEquals(1, events.size(), "Incorrect number of events. Expected 1, actual " + events.size());
        final LogEvent event = events.get(0);
        assertEquals("Test", event.getLoggerName(), "TestLogEventFactory wasn't used");
    }

    public static class TestLogEventFactory implements LogEventFactory, LocationAwareLogEventFactory {

        @Override
        public LogEvent createEvent(
                final String loggerName,
                final Marker marker,
                final String fqcn,
                final Level level,
                final Message data,
                final List<Property> properties,
                final Throwable t) {
            return new Log4jLogEvent("Test", marker, fqcn, level, data, properties, t);
        }

        @Override
        public LogEvent createEvent(
                final String loggerName,
                final Marker marker,
                final String fqcn,
                final StackTraceElement location,
                final Level level,
                final Message data,
                final List<Property> properties,
                final Throwable t) {
            return new Log4jLogEvent("Test", marker, fqcn, level, data, properties, t);
        }
    }
}

NoSqlDatabaseManagerTest

package org.apache.logging.log4j.core.appender.nosql;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AppenderLoggingException;
import org.apache.logging.log4j.core.impl.ContextDataFactory;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.test.junit.UsingThreadContextStack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
@UsingThreadContextStack
public class NoSqlDatabaseManagerTest {

    @Mock
    private NoSqlConnection<Map<String, Object>, DefaultNoSqlObject> connection;

    @Mock
    private NoSqlProvider<NoSqlConnection<Map<String, Object>, DefaultNoSqlObject>> provider;

    @Mock
    private Message message;

    @Captor
    private ArgumentCaptor<NoSqlObject<Map<String, Object>>> captor;

    @BeforeEach
    public void setUp() {
        given(provider.getConnection()).willReturn(connection);
        given(connection.createObject()).willAnswer(invocation -> new DefaultNoSqlObject());
        given(connection.createList(anyInt()))
                .willAnswer(invocation -> new DefaultNoSqlObject[invocation.<Integer>getArgument(0)]);
    }

    @Test
    public void testConnection() {
        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {

            assertNotNull(manager, "The manager should not be null.");

            manager.connectAndStart();
            then(provider).should().getConnection();
            manager.commitAndClose();
        }
    }

    @Test
    public void testWriteInternalNotConnected01() {
        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {
            assertThrows(AppenderLoggingException.class, () -> {
                // throw new AppenderLoggingException("stupid avocado");
                manager.writeInternal(mock(LogEvent.class), null);
            });
        }
    }

    @Test
    public void testWriteInternalNotConnected02() {
        given(connection.isClosed()).willReturn(true);

        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {

            manager.startup();
            manager.connectAndStart();
            then(provider).should().getConnection();

            assertThrows(AppenderLoggingException.class, () -> {
                // throw new AppenderLoggingException("möp");
                manager.writeInternal(mock(LogEvent.class), null);
            });
        }
    }

    @Test
    public void testWriteInternal01() {
        given(connection.isClosed()).willReturn(false);
        given(message.getFormattedMessage()).willReturn("My formatted message 01.");

        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {

            manager.startup();
            manager.connectAndStart();
            then(provider).should().getConnection();

            final LogEvent event = Log4jLogEvent.newBuilder()
                    .setLevel(Level.WARN)
                    .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal01")
                    .setMessage(message)
                    .setSource(new StackTraceElement("com.foo.Bar", "testMethod01", "Bar.java", 15))
                    .setThreadId(1L)
                    .setThreadName("MyThread-A")
                    .setThreadPriority(1)
                    .setTimeMillis(1234567890123L)
                    .build();

            manager.writeInternal(event, null);
            then(connection).should().insertObject(captor.capture());

            final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
            assertNotNull(inserted, "The inserted value should not be null.");
            final Map<String, Object> object = inserted.unwrap();
            assertNotNull(object, "The unwrapped object should not be null.");

            assertEquals(Level.WARN, object.get("level"), "The level is not correct.");
            assertEquals(
                    "com.foo.NoSQLDbTest.testWriteInternal01", object.get("loggerName"), "The logger is not correct.");
            assertEquals("My formatted message 01.", object.get("message"), "The message is not correct.");
            assertEquals("MyThread-A", object.get("threadName"), "The thread is not correct.");
            assertEquals(1234567890123L, object.get("millis"), "The millis is not correct.");
            assertEquals(1234567890123L, ((Date) object.get("date")).getTime(), "The date is not correct.");

            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> source = (Map<String, Object>) object.get("source");
            assertEquals("com.foo.Bar", source.get("className"), "The class is not correct.");
            assertEquals("testMethod01", source.get("methodName"), "The method is not correct.");
            assertEquals("Bar.java", source.get("fileName"), "The file name is not correct.");
            assertEquals(15, source.get("lineNumber"), "The line number is not correct.");

            assertNull(object.get("marker"), "The marker should be null.");

            assertNull(object.get("thrown"), "The thrown should be null.");

            assertTrue(((Map) object.get("contextMap")).isEmpty(), "The context map should be empty.");

            assertTrue(((Collection) object.get("contextStack")).isEmpty(), "The context stack should be null.");
        }
    }

    @Test
    public void testWriteInternal02() {
        given(connection.isClosed()).willReturn(false);
        given(message.getFormattedMessage()).willReturn("Another cool message 02.");

        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {
            manager.startup();

            manager.connectAndStart();
            then(provider).should().getConnection();

            final RuntimeException exception = new RuntimeException("This is something cool!");
            final Map<String, String> context = new HashMap<>();
            context.put("hello", "world");
            context.put("user", "pass");

            ThreadContext.push("message1");
            ThreadContext.push("stack2");
            final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack();
            ThreadContext.clearStack();

            final LogEvent event = Log4jLogEvent.newBuilder()
                    .setLevel(Level.DEBUG)
                    .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal02")
                    .setMessage(message)
                    .setSource(new StackTraceElement("com.bar.Foo", "anotherMethod03", "Foo.java", 9))
                    .setMarker(MarkerManager.getMarker("LoneMarker"))
                    .setThreadId(1L)
                    .setThreadName("AnotherThread-B")
                    .setThreadPriority(1)
                    .setTimeMillis(987654321564L)
                    .setThrown(exception)
                    .setContextData(ContextDataFactory.createContextData(context))
                    .setContextStack(stack)
                    .build();

            manager.writeInternal(event, null);
            then(connection).should().insertObject(captor.capture());

            final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
            assertNotNull(inserted, "The inserted value should not be null.");
            final Map<String, Object> object = inserted.unwrap();
            assertNotNull(object, "The unwrapped object should not be null.");

            assertEquals(Level.DEBUG, object.get("level"), "The level is not correct.");
            assertEquals(
                    "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"), "The logger is not correct.");
            assertEquals("Another cool message 02.", object.get("message"), "The message is not correct.");
            assertEquals("AnotherThread-B", object.get("threadName"), "The thread is not correct.");
            assertEquals(987654321564L, object.get("millis"), "The millis is not correct.");
            assertEquals(987654321564L, ((Date) object.get("date")).getTime(), "The date is not correct.");

            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> source = (Map<String, Object>) object.get("source");
            assertEquals("com.bar.Foo", source.get("className"), "The class is not correct.");
            assertEquals("anotherMethod03", source.get("methodName"), "The method is not correct.");
            assertEquals("Foo.java", source.get("fileName"), "The file name is not correct.");
            assertEquals(9, source.get("lineNumber"), "The line number is not correct.");

            assertTrue(object.get("marker") instanceof Map, "The marker should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> marker = (Map<String, Object>) object.get("marker");
            assertEquals("LoneMarker", marker.get("name"), "The marker name is not correct.");
            assertNull(marker.get("parent"), "The marker parent should be null.");

            assertTrue(object.get("thrown") instanceof Map, "The thrown should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown");
            assertEquals("java.lang.RuntimeException", thrown.get("type"), "The thrown type is not correct.");
            assertEquals("This is something cool!", thrown.get("message"), "The thrown message is not correct.");
            assertTrue(thrown.get("stackTrace") instanceof List, "The thrown stack trace should be a list.");
            @SuppressWarnings("unchecked")
            final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace");
            assertEquals(
                    exception.getStackTrace().length,
                    stackTrace.size(),
                    "The thrown stack trace length is not correct.");
            for (int i = 0; i < exception.getStackTrace().length; i++) {
                final StackTraceElement e1 = exception.getStackTrace()[i];
                final Map<String, Object> e2 = stackTrace.get(i);

                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                assertEquals(
                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                assertEquals(
                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
            }
            assertNull(thrown.get("cause"), "The thrown should have no cause.");

            assertTrue(object.get("contextMap") instanceof Map, "The context map should be a map.");
            assertEquals(context, object.get("contextMap"), "The context map is not correct.");

            assertTrue(object.get("contextStack") instanceof List, "The context stack should be list.");
            assertEquals(stack.asList(), object.get("contextStack"), "The context stack is not correct.");
        }
    }

    @Test
    public void testWriteInternal03() {
        given(connection.isClosed()).willReturn(false);
        given(message.getFormattedMessage()).willReturn("Another cool message 02.");

        try (final NoSqlDatabaseManager<?> manager =
                NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, provider, null, null)) {
            manager.startup();

            manager.connectAndStart();
            then(provider).should().getConnection();

            final IOException exception1 = new IOException("This is the cause.");
            final SQLException exception2 = new SQLException("This is the result.", exception1);
            final Map<String, String> context = new HashMap<>();
            context.put("hello", "world");
            context.put("user", "pass");

            ThreadContext.push("message1");
            ThreadContext.push("stack2");
            final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack();
            ThreadContext.clearStack();

            final LogEvent event = Log4jLogEvent.newBuilder()
                    .setLevel(Level.DEBUG)
                    .setLoggerName("com.foo.NoSQLDbTest.testWriteInternal02")
                    .setMessage(message)
                    .setSource(new StackTraceElement("com.bar.Foo", "anotherMethod03", "Foo.java", 9))
                    .setMarker(MarkerManager.getMarker("AnotherMarker")
                            .addParents(
                                    MarkerManager.getMarker("Parent1")
                                            .addParents(MarkerManager.getMarker("GrandParent1")),
                                    MarkerManager.getMarker("Parent2")))
                    .setThreadId(1L)
                    .setThreadName("AnotherThread-B")
                    .setThreadPriority(1)
                    .setTimeMillis(987654321564L)
                    .setThrown(exception2)
                    .setContextData(ContextDataFactory.createContextData(context))
                    .setContextStack(stack)
                    .build();

            manager.writeInternal(event, null);
            then(connection).should().insertObject(captor.capture());

            final NoSqlObject<Map<String, Object>> inserted = captor.getValue();
            assertNotNull(inserted, "The inserted value should not be null.");
            final Map<String, Object> object = inserted.unwrap();
            assertNotNull(object, "The unwrapped object should not be null.");

            assertEquals(Level.DEBUG, object.get("level"), "The level is not correct.");
            assertEquals(
                    "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName"), "The logger is not correct.");
            assertEquals("Another cool message 02.", object.get("message"), "The message is not correct.");
            assertEquals("AnotherThread-B", object.get("threadName"), "The thread is not correct.");
            assertEquals(987654321564L, object.get("millis"), "The millis is not correct.");
            assertEquals(987654321564L, ((Date) object.get("date")).getTime(), "The date is not correct.");

            assertTrue(object.get("source") instanceof Map, "The source should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> source = (Map<String, Object>) object.get("source");
            assertEquals("com.bar.Foo", source.get("className"), "The class is not correct.");
            assertEquals("anotherMethod03", source.get("methodName"), "The method is not correct.");
            assertEquals("Foo.java", source.get("fileName"), "The file name is not correct.");
            assertEquals(9, source.get("lineNumber"), "The line number is not correct.");

            assertTrue(object.get("marker") instanceof Map, "The marker should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> marker = (Map<String, Object>) object.get("marker");
            assertEquals("AnotherMarker", marker.get("name"), "The marker name is not correct.");

            assertTrue(marker.get("parents") instanceof List, "The marker parents should be a list.");
            @SuppressWarnings("unchecked")
            final List<Object> markerParents = (List<Object>) marker.get("parents");
            assertEquals(2, markerParents.size(), "The marker parents should contain two parents");

            assertTrue(markerParents.get(0) instanceof Map, "The marker parents[0] should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> parent1 = (Map<String, Object>) markerParents.get(0);
            assertEquals("Parent1", parent1.get("name"), "The first marker parent name is not correct.");

            assertTrue(markerParents.get(1) instanceof Map, "The marker parents[1] should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> parent2 = (Map<String, Object>) markerParents.get(1);
            assertEquals("Parent2", parent2.get("name"), "The second marker parent name is not correct.");
            assertNull(parent2.get("parent"), "The second marker should have no parent.");

            assertTrue(parent1.get("parents") instanceof List, "The parent1 parents should be a list.");
            @SuppressWarnings("unchecked")
            final List<Object> parent1Parents = (List<Object>) parent1.get("parents");
            assertEquals(1, parent1Parents.size(), "The parent1 parents should have only one parent");

            assertTrue(parent1Parents.get(0) instanceof Map, "The parent1Parents[0] should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> parent1parent = (Map<String, Object>) parent1Parents.get(0);
            assertEquals("GrandParent1", parent1parent.get("name"), "The first parent1 parent name is not correct.");
            assertNull(parent1parent.get("parent"), "The parent1parent marker should have no parent.");

            assertTrue(object.get("thrown") instanceof Map, "The thrown should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown");
            assertEquals("java.sql.SQLException", thrown.get("type"), "The thrown type is not correct.");
            assertEquals("This is the result.", thrown.get("message"), "The thrown message is not correct.");
            assertTrue(thrown.get("stackTrace") instanceof List, "The thrown stack trace should be a list.");
            @SuppressWarnings("unchecked")
            final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace");
            assertEquals(
                    exception2.getStackTrace().length,
                    stackTrace.size(),
                    "The thrown stack trace length is not correct.");
            for (int i = 0; i < exception2.getStackTrace().length; i++) {
                final StackTraceElement e1 = exception2.getStackTrace()[i];
                final Map<String, Object> e2 = stackTrace.get(i);

                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                assertEquals(
                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                assertEquals(
                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
            }
            assertTrue(thrown.get("cause") instanceof Map, "The thrown cause should be a map.");
            @SuppressWarnings("unchecked")
            final Map<String, Object> cause = (Map<String, Object>) thrown.get("cause");
            assertEquals("java.io.IOException", cause.get("type"), "The cause type is not correct.");
            assertEquals("This is the cause.", cause.get("message"), "The cause message is not correct.");
            assertTrue(cause.get("stackTrace") instanceof List, "The cause stack trace should be a list.");
            @SuppressWarnings("unchecked")
            final List<Map<String, Object>> causeStackTrace = (List<Map<String, Object>>) cause.get("stackTrace");
            assertEquals(
                    exception1.getStackTrace().length,
                    causeStackTrace.size(),
                    "The cause stack trace length is not correct.");
            for (int i = 0; i < exception1.getStackTrace().length; i++) {
                final StackTraceElement e1 = exception1.getStackTrace()[i];
                final Map<String, Object> e2 = causeStackTrace.get(i);

                assertEquals(e1.getClassName(), e2.get("className"), "Element class name [" + i + "] is not correct.");
                assertEquals(
                        e1.getMethodName(), e2.get("methodName"), "Element method name [" + i + "] is not correct.");
                assertEquals(e1.getFileName(), e2.get("fileName"), "Element file name [" + i + "] is not correct.");
                assertEquals(
                        e1.getLineNumber(), e2.get("lineNumber"), "Element line number [" + i + "] is not correct.");
            }
            assertNull(cause.get("cause"), "The cause should have no cause.");

            assertTrue(object.get("contextMap") instanceof Map, "The context map should be a map.");
            assertEquals(context, object.get("contextMap"), "The context map is not correct.");

            assertTrue(object.get("contextStack") instanceof List, "The context stack should be list.");
            assertEquals(stack.asList(), object.get("contextStack"), "The context stack is not correct.");
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️