package com.equalexperts.logging.impl; import com.equalexperts.logging.LogMessage; import org.junit.Test; import java.time.Instant; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; import static java.util.Collections.emptyMap; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; public class LogicalLogRecordTest { static final StackTraceProcessor PROCESSOR_SHOULD_NOT_BE_CALLED = (t, out) -> fail("should not be called"); static final DiagnosticContext SAMPLE_DIAGNOSTIC_CONTEXT = new DiagnosticContext(Collections::emptyMap); @Test public void constructor_shouldThrowANullPointerException_givenANullTimestamp() throws Exception { try { new LogicalLogRecord<>(null, SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Foo, Optional.empty()); fail("expected an exception"); } catch (NullPointerException e) { assertThat(e.getMessage(), containsString("parameter timestamp")); } } @Test public void constructor_shouldThrowANullPointerException_givenANullDiagnosticContext() throws Exception { try { new LogicalLogRecord<>(Instant.now(), null, TestMessages.Foo, Optional.empty()); fail("expected an exception"); } catch (NullPointerException e) { assertThat(e.getMessage(), containsString("parameter diagnosticContext")); } } @Test public void constructor_shouldThrowANullPointerException_givenANullMessage() throws Exception { try { new LogicalLogRecord<TestMessages>(Instant.now(), SAMPLE_DIAGNOSTIC_CONTEXT, null, Optional.empty()); fail("expected an exception"); } catch (NullPointerException e) { assertThat(e.getMessage(), containsString("parameter message")); } } @Test public void constructor_shouldThrowANullPointerException_givenANullCause() throws Exception { try { new LogicalLogRecord<>(Instant.now(), SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Foo, null); fail("expected an exception"); } catch (NullPointerException e) { assertThat(e.getMessage(), containsString("parameter cause")); } } @Test public void constructor_shouldThrowANullPointerException_givenNullDetails() throws Exception { try { new LogicalLogRecord<>(Instant.now(), SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Foo, Optional.empty(), (Object[]) null); fail("expected an exception"); } catch (NullPointerException e) { assertThat(e.getMessage(), containsString("parameter details")); } } @Test public void format_shouldProduceAnAppropriatelyFormattedMessage() throws Exception { Instant instant = Instant.parse("2014-04-01T13:37:00.123Z"); LogicalLogRecord<TestMessages> record = new LogicalLogRecord<>(instant, SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Bar, Optional.empty(), 42); String result = record.format(PROCESSOR_SHOULD_NOT_BE_CALLED); assertEquals("2014-04-01T13:37:00.123Z,CODE-Bar,A Bar event occurred, with argument 42", result); } @Test public void format_shouldIncludeMilliseconds_whenTheTimestampIsAnEvenSecond() throws Exception { Instant instant = Instant.parse("2014-04-01T13:37:00.000Z"); LogicalLogRecord<TestMessages> record = new LogicalLogRecord<>(instant, SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Foo, Optional.empty()); String result = record.format(PROCESSOR_SHOULD_NOT_BE_CALLED); assertEquals("2014-04-01T13:37:00.000Z,CODE-Foo,An event of some kind occurred", result); } @Test public void format_shouldProduceAnAppropriatelyFormattedMessage_givenAThrowable() throws Exception { Instant instant = Instant.parse("2014-04-01T13:37:00.123Z"); Throwable expectedThrowable = new RuntimeException(); LogicalLogRecord<TestMessages> record = new LogicalLogRecord<>(instant, SAMPLE_DIAGNOSTIC_CONTEXT, TestMessages.Bar, Optional.of(expectedThrowable), 42); StackTraceProcessor processor = (t, out) -> { assertSame(expectedThrowable, t); out.append("#EXCEPTION_HERE#"); }; String result = record.format(processor); assertEquals("2014-04-01T13:37:00.123Z,CODE-Bar,A Bar event occurred, with argument 42 #EXCEPTION_HERE#", result); } @Test public void format_shouldIncludeTheDiagnosticContextInTheFormattedMessage() throws Exception { Instant instant = Instant.parse("2014-04-01T13:37:00.123Z"); Map<String, String> correlationIds = new HashMap<>(); correlationIds.put("user", "joeUser"); DiagnosticContext dc = spy(new DiagnosticContext(() -> correlationIds)); LogicalLogRecord<TestMessages> record = new LogicalLogRecord<>(instant, dc, TestMessages.Bar, Optional.empty(), 42); String result = record.format(PROCESSOR_SHOULD_NOT_BE_CALLED); assertEquals("2014-04-01T13:37:00.123Z,user=joeUser,CODE-Bar,A Bar event occurred, with argument 42", result); verify(dc).printContextInformation(any()); } private enum TestMessages implements LogMessage { Foo("CODE-Foo", "An event of some kind occurred"), Bar("CODE-Bar", "A Bar event occurred, with argument %d"); //region LogMessage implementation guts private final String messageCode; private final String messagePattern; TestMessages(String messageCode, String messagePattern) { this.messageCode = messageCode; this.messagePattern = messagePattern; } @Override public String getMessageCode() { return messageCode; } @Override public String getMessagePattern() { return messagePattern; } //endregion } }