package org.apache.logging.log4j.nosql.appender; 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.message.Message; import org.easymock.Capture; import org.easymock.IAnswer; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.easymock.EasyMock.anyInt; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createStrictMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.getCurrentArguments; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class NoSqlDatabaseManagerTest { private NoSqlConnection<Map<String, Object>, DefaultNoSqlObject> connection; private NoSqlProvider<NoSqlConnection<Map<String, Object>, DefaultNoSqlObject>> provider; @Before @SuppressWarnings("unchecked") public void setUp() { this.provider = createStrictMock(NoSqlProvider.class); this.connection = createStrictMock(NoSqlConnection.class); } @After public void tearDown() { verify(this.provider, this.connection); } @Test public void testConnection() { replay(this.provider, this.connection); final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); assertNotNull("The manager should not be null.", manager); try { verify(this.provider, this.connection); reset(this.provider, this.connection); expect(this.provider.getConnection()).andReturn(this.connection); replay(this.provider, this.connection); manager.connectAndStart(); manager.commitAndClose(); } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } @Test public void testWriteInternalNotConnected01() { replay(this.provider, this.connection); final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); try { verify(this.provider, this.connection); reset(this.provider, this.connection); final LogEvent event = createStrictMock(LogEvent.class); replay(this.provider, this.connection, event); try { manager.writeInternal(event); fail("Expected AppenderLoggingException."); } catch (final AppenderLoggingException ignore) { /* */ } verify(event); } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } @Test public void testWriteInternalNotConnected02() { final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); try { replay(this.provider, this.connection); manager.startup(); verify(this.provider, this.connection); reset(this.provider, this.connection); expect(this.provider.getConnection()).andReturn(this.connection); replay(this.provider, this.connection); manager.connectAndStart(); verify(this.provider, this.connection); reset(this.provider, this.connection); final LogEvent event = createStrictMock(LogEvent.class); expect(this.connection.isClosed()).andReturn(true); replay(this.provider, this.connection, event); try { manager.writeInternal(event); fail("Expected AppenderLoggingException."); } catch (final AppenderLoggingException ignore) { /* */ } } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } @Test public void testWriteInternal01() { final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); try { replay(this.provider, this.connection); manager.startup(); verify(this.provider, this.connection); reset(this.provider, this.connection); expect(this.provider.getConnection()).andReturn(this.connection); replay(this.provider, this.connection); manager.connectAndStart(); verify(this.provider, this.connection); reset(this.provider, this.connection); final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>(); final LogEvent event = createStrictMock(LogEvent.class); final Message message = createStrictMock(Message.class); expect(this.connection.isClosed()).andReturn(false); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(event.getLevel()).andReturn(Level.WARN); expect(event.getLoggerName()).andReturn("com.foo.NoSQLDbTest.testWriteInternal01"); expect(event.getMessage()).andReturn(message).times(2); expect(message.getFormattedMessage()).andReturn("My formatted message 01."); expect(event.getSource()).andReturn(new StackTraceElement("com.foo.Bar", "testMethod01", "Bar.java", 15)); expect(event.getMarker()).andReturn(null); expect(event.getThreadName()).andReturn("MyThread-A"); expect(event.getTimeMillis()).andReturn(1234567890123L).times(2); expect(event.getThrown()).andReturn(null); expect(event.getContextMap()).andReturn(null); expect(event.getContextStack()).andReturn(null); this.connection.insertObject(capture(capture)); expectLastCall(); replay(this.provider, this.connection, event, message); manager.writeInternal(event); final NoSqlObject<Map<String, Object>> inserted = capture.getValue(); assertNotNull("The inserted value should not be null.", inserted); final Map<String, Object> object = inserted.unwrap(); assertNotNull("The unwrapped object should not be null.", object); assertEquals("The level is not correct.", Level.WARN, object.get("level")); assertEquals("The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal01", object.get("loggerName")); assertEquals("The message is not correct.", "My formatted message 01.", object.get("message")); assertEquals("The thread is not correct.", "MyThread-A", object.get("threadName")); assertEquals("The millis is not correct.", 1234567890123L, object.get("millis")); assertEquals("The date is not correct.", 1234567890123L, ((Date) object.get("date")).getTime()); assertTrue("The source should be a map.", object.get("source") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> source = (Map<String, Object>) object.get("source"); assertEquals("The class is not correct.", "com.foo.Bar", source.get("className")); assertEquals("The method is not correct.", "testMethod01", source.get("methodName")); assertEquals("The file name is not correct.", "Bar.java", source.get("fileName")); assertEquals("The line number is not correct.", 15, source.get("lineNumber")); assertNull("The marker should be null.", object.get("marker")); assertNull("The thrown should be null.", object.get("thrown")); assertNull("The context map should be null.", object.get("contextMap")); assertNull("The context stack should be null.", object.get("contextStack")); verify(this.provider, this.connection, event, message); } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } @Test public void testWriteInternal02() { final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); try { replay(this.provider, this.connection); manager.startup(); verify(this.provider, this.connection); reset(this.provider, this.connection); expect(this.provider.getConnection()).andReturn(this.connection); replay(this.provider, this.connection); manager.connectAndStart(); verify(this.provider, this.connection); reset(this.provider, this.connection); final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>(); final RuntimeException exception = new RuntimeException("This is something cool!"); final Map<String, String> context = new HashMap<String, String>(); context.put("hello", "world"); context.put("user", "pass"); final LogEvent event = createStrictMock(LogEvent.class); final Message message = createStrictMock(Message.class); ThreadContext.push("message1"); ThreadContext.push("stack2"); final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack(); ThreadContext.clearStack(); expect(this.connection.isClosed()).andReturn(false); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(this.connection.createList(anyInt())).andAnswer(new IAnswer<DefaultNoSqlObject[]>() { @Override public DefaultNoSqlObject[] answer() throws Throwable { return new DefaultNoSqlObject[(Integer) getCurrentArguments()[0]]; } }); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(event.getLevel()).andReturn(Level.DEBUG); expect(event.getLoggerName()).andReturn("com.foo.NoSQLDbTest.testWriteInternal02"); expect(event.getMessage()).andReturn(message).times(2); expect(message.getFormattedMessage()).andReturn("Another cool message 02."); expect(event.getSource()).andReturn(new StackTraceElement("com.bar.Foo", "anotherMethod03", "Foo.java", 9)); expect(event.getMarker()).andReturn(MarkerManager.getMarker("LoneMarker")); expect(event.getThreadName()).andReturn("AnotherThread-B"); expect(event.getTimeMillis()).andReturn(987654321564L).times(2); expect(event.getThrown()).andReturn(exception); expect(event.getContextMap()).andReturn(context); expect(event.getContextStack()).andReturn(stack); this.connection.insertObject(capture(capture)); expectLastCall(); replay(this.provider, this.connection, event, message); manager.writeInternal(event); final NoSqlObject<Map<String, Object>> inserted = capture.getValue(); assertNotNull("The inserted value should not be null.", inserted); final Map<String, Object> object = inserted.unwrap(); assertNotNull("The unwrapped object should not be null.", object); assertEquals("The level is not correct.", Level.DEBUG, object.get("level")); assertEquals("The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName")); assertEquals("The message is not correct.", "Another cool message 02.", object.get("message")); assertEquals("The thread is not correct.", "AnotherThread-B", object.get("threadName")); assertEquals("The millis is not correct.", 987654321564L, object.get("millis")); assertEquals("The date is not correct.", 987654321564L, ((Date) object.get("date")).getTime()); assertTrue("The source should be a map.", object.get("source") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> source = (Map<String, Object>) object.get("source"); assertEquals("The class is not correct.", "com.bar.Foo", source.get("className")); assertEquals("The method is not correct.", "anotherMethod03", source.get("methodName")); assertEquals("The file name is not correct.", "Foo.java", source.get("fileName")); assertEquals("The line number is not correct.", 9, source.get("lineNumber")); assertTrue("The marker should be a map.", object.get("marker") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> marker = (Map<String, Object>) object.get("marker"); assertEquals("The marker name is not correct.", "LoneMarker", marker.get("name")); assertNull("The marker parent should be null.", marker.get("parent")); assertTrue("The thrown should be a map.", object.get("thrown") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown"); assertEquals("The thrown type is not correct.", "java.lang.RuntimeException", thrown.get("type")); assertEquals("The thrown message is not correct.", "This is something cool!", thrown.get("message")); assertTrue("The thrown stack trace should be a list.", thrown.get("stackTrace") instanceof List); @SuppressWarnings("unchecked") final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace"); assertEquals("The thrown stack trace length is not correct.", exception.getStackTrace().length, stackTrace.size()); for (int i = 0; i < exception.getStackTrace().length; i++) { final StackTraceElement e1 = exception.getStackTrace()[i]; final Map<String, Object> e2 = stackTrace.get(i); assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className")); assertEquals("Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName")); assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName")); assertEquals("Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber")); } assertNull("The thrown should have no cause.", thrown.get("cause")); assertTrue("The context map should be a map.", object.get("contextMap") instanceof Map); assertEquals("The context map is not correct.", context, object.get("contextMap")); assertTrue("The context stack should be list.", object.get("contextStack") instanceof List); assertEquals("The context stack is not correct.", stack.asList(), object.get("contextStack")); verify(this.provider, this.connection, event, message); } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } @Test public void testWriteInternal03() { final NoSqlDatabaseManager<?> manager = NoSqlDatabaseManager.getNoSqlDatabaseManager("name", 0, this.provider); try { replay(this.provider, this.connection); manager.startup(); verify(this.provider, this.connection); reset(this.provider, this.connection); expect(this.provider.getConnection()).andReturn(this.connection); replay(this.provider, this.connection); manager.connectAndStart(); verify(this.provider, this.connection); reset(this.provider, this.connection); final Capture<NoSqlObject<Map<String, Object>>> capture = new Capture<NoSqlObject<Map<String, Object>>>(); 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<String, String>(); context.put("hello", "world"); context.put("user", "pass"); final LogEvent event = createStrictMock(LogEvent.class); final Message message = createStrictMock(Message.class); ThreadContext.push("message1"); ThreadContext.push("stack2"); final ThreadContext.ContextStack stack = ThreadContext.getImmutableStack(); ThreadContext.clearStack(); expect(this.connection.isClosed()).andReturn(false); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(this.connection.createList(anyInt())).andAnswer(new IAnswer<DefaultNoSqlObject[]>() { @Override public DefaultNoSqlObject[] answer() throws Throwable { return new DefaultNoSqlObject[(Integer) getCurrentArguments()[0]]; } }); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(this.connection.createList(anyInt())).andAnswer(new IAnswer<DefaultNoSqlObject[]>() { @Override public DefaultNoSqlObject[] answer() throws Throwable { return new DefaultNoSqlObject[(Integer) getCurrentArguments()[0]]; } }); expect(this.connection.createObject()).andAnswer(new IAnswer<DefaultNoSqlObject>() { @Override public DefaultNoSqlObject answer() throws Throwable { return new DefaultNoSqlObject(); } }).atLeastOnce(); expect(event.getLevel()).andReturn(Level.DEBUG); expect(event.getLoggerName()).andReturn("com.foo.NoSQLDbTest.testWriteInternal02"); expect(event.getMessage()).andReturn(message).times(2); expect(message.getFormattedMessage()).andReturn("Another cool message 02."); expect(event.getSource()).andReturn(new StackTraceElement("com.bar.Foo", "anotherMethod03", "Foo.java", 9)); expect(event.getMarker()).andReturn( MarkerManager.getMarker("AnotherMarker").addParents(MarkerManager.getMarker("Parent1").addParents(MarkerManager.getMarker("GrandParent1")), MarkerManager.getMarker("Parent2"))); expect(event.getThreadName()).andReturn("AnotherThread-B"); expect(event.getTimeMillis()).andReturn(987654321564L).times(2); expect(event.getThrown()).andReturn(exception2); expect(event.getContextMap()).andReturn(context); expect(event.getContextStack()).andReturn(stack); this.connection.insertObject(capture(capture)); expectLastCall(); replay(this.provider, this.connection, event, message); manager.writeInternal(event); final NoSqlObject<Map<String, Object>> inserted = capture.getValue(); assertNotNull("The inserted value should not be null.", inserted); final Map<String, Object> object = inserted.unwrap(); assertNotNull("The unwrapped object should not be null.", object); assertEquals("The level is not correct.", Level.DEBUG, object.get("level")); assertEquals("The logger is not correct.", "com.foo.NoSQLDbTest.testWriteInternal02", object.get("loggerName")); assertEquals("The message is not correct.", "Another cool message 02.", object.get("message")); assertEquals("The thread is not correct.", "AnotherThread-B", object.get("threadName")); assertEquals("The millis is not correct.", 987654321564L, object.get("millis")); assertEquals("The date is not correct.", 987654321564L, ((Date) object.get("date")).getTime()); assertTrue("The source should be a map.", object.get("source") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> source = (Map<String, Object>) object.get("source"); assertEquals("The class is not correct.", "com.bar.Foo", source.get("className")); assertEquals("The method is not correct.", "anotherMethod03", source.get("methodName")); assertEquals("The file name is not correct.", "Foo.java", source.get("fileName")); assertEquals("The line number is not correct.", 9, source.get("lineNumber")); assertTrue("The marker should be a map.", object.get("marker") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> marker = (Map<String, Object>) object.get("marker"); assertEquals("The marker name is not correct.", "AnotherMarker", marker.get("name")); assertTrue("The marker parents should be a list.", marker.get("parents") instanceof List); @SuppressWarnings("unchecked") final List<Object> markerParents = (List<Object>) marker.get("parents"); assertEquals("The marker parents should contain two parents", 2, markerParents.size()); assertTrue("The marker parents[0] should be a map.", markerParents.get(0) instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> parent1 = (Map<String, Object>) markerParents.get(0); assertEquals("The first marker parent name is not correct.", "Parent1", parent1.get("name")); assertTrue("The marker parents[1] should be a map.", markerParents.get(1) instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> parent2 = (Map<String, Object>) markerParents.get(1); assertEquals("The second marker parent name is not correct.", "Parent2", parent2.get("name")); assertNull("The second marker should have no parent.", parent2.get("parent")); assertTrue("The parent1 parents should be a list.", parent1.get("parents") instanceof List); @SuppressWarnings("unchecked") final List<Object> parent1Parents = (List<Object>) parent1.get("parents"); assertEquals("The parent1 parents should have only one parent", 1, parent1Parents.size()); assertTrue("The parent1Parents[0] should be a map.", parent1Parents.get(0) instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> parent1parent = (Map<String, Object>) parent1Parents.get(0); assertEquals("The first parent1 parent name is not correct.", "GrandParent1", parent1parent.get("name")); assertNull("The parent1parent marker should have no parent.", parent1parent.get("parent")); assertTrue("The thrown should be a map.", object.get("thrown") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> thrown = (Map<String, Object>) object.get("thrown"); assertEquals("The thrown type is not correct.", "java.sql.SQLException", thrown.get("type")); assertEquals("The thrown message is not correct.", "This is the result.", thrown.get("message")); assertTrue("The thrown stack trace should be a list.", thrown.get("stackTrace") instanceof List); @SuppressWarnings("unchecked") final List<Map<String, Object>> stackTrace = (List<Map<String, Object>>) thrown.get("stackTrace"); assertEquals("The thrown stack trace length is not correct.", exception2.getStackTrace().length, stackTrace.size()); for (int i = 0; i < exception2.getStackTrace().length; i++) { final StackTraceElement e1 = exception2.getStackTrace()[i]; final Map<String, Object> e2 = stackTrace.get(i); assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className")); assertEquals("Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName")); assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName")); assertEquals("Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber")); } assertTrue("The thrown cause should be a map.", thrown.get("cause") instanceof Map); @SuppressWarnings("unchecked") final Map<String, Object> cause = (Map<String, Object>) thrown.get("cause"); assertEquals("The cause type is not correct.", "java.io.IOException", cause.get("type")); assertEquals("The cause message is not correct.", "This is the cause.", cause.get("message")); assertTrue("The cause stack trace should be a list.", cause.get("stackTrace") instanceof List); @SuppressWarnings("unchecked") final List<Map<String, Object>> causeStackTrace = (List<Map<String, Object>>) cause.get("stackTrace"); assertEquals("The cause stack trace length is not correct.", exception1.getStackTrace().length, causeStackTrace.size()); for (int i = 0; i < exception1.getStackTrace().length; i++) { final StackTraceElement e1 = exception1.getStackTrace()[i]; final Map<String, Object> e2 = causeStackTrace.get(i); assertEquals("Element class name [" + i + "] is not correct.", e1.getClassName(), e2.get("className")); assertEquals("Element method name [" + i + "] is not correct.", e1.getMethodName(), e2.get("methodName")); assertEquals("Element file name [" + i + "] is not correct.", e1.getFileName(), e2.get("fileName")); assertEquals("Element line number [" + i + "] is not correct.", e1.getLineNumber(), e2.get("lineNumber")); } assertNull("The cause should have no cause.", cause.get("cause")); assertTrue("The context map should be a map.", object.get("contextMap") instanceof Map); assertEquals("The context map is not correct.", context, object.get("contextMap")); assertTrue("The context stack should be list.", object.get("contextStack") instanceof List); assertEquals("The context stack is not correct.", stack.asList(), object.get("contextStack")); verify(this.provider, this.connection, event, message); } finally { try { manager.release(); } catch (final Throwable ignore) { /* */ } } } }