package net.kencochrane.raven.log4j2;

import net.kencochrane.raven.AbstractLoggerTest;
import net.kencochrane.raven.event.Event;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.Marker;
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.impl.Log4jLogEvent;
import org.apache.logging.log4j.message.FormattedMessage;
import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.SimpleMessage;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;

import java.util.List;
import java.util.UUID;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.verify;

public class SentryAppenderTest extends AbstractLoggerTest {
    private static final String LOGGER_NAME = SentryAppenderTest.class.getName();
    private SentryAppender sentryAppender;

    @Before
    public void setUp() throws Exception {
        sentryAppender = new SentryAppender(getMockRaven());
    }

    @Override
    public void logAnyLevel(String message) {
        logEvent(Level.INFO, null, null, message, null);
    }

    @Override
    public void logAnyLevel(String message, Throwable exception) {
        logEvent(Level.INFO, null, exception, message, null);
    }

    @Override
    public void logAnyLevel(String message, List<String> parameters) {
        logEvent(Level.INFO, null, null, message, parameters);
    }

    @Override
    public String getCurrentLoggerName() {
        return LOGGER_NAME;
    }

    @Override
    public String getUnformattedMessage() {
        return "Some content {} {} {}";
    }

    @Test
    @Override
    public void testLogLevelConversions() throws Exception {
        assertLevelConverted(Event.Level.DEBUG, Level.TRACE);
        assertLevelConverted(Event.Level.DEBUG, Level.DEBUG);
        assertLevelConverted(Event.Level.INFO, Level.INFO);
        assertLevelConverted(Event.Level.WARNING, Level.WARN);
        assertLevelConverted(Event.Level.ERROR, Level.ERROR);
        assertLevelConverted(Event.Level.FATAL, Level.FATAL);
    }

    private void assertLevelConverted(Event.Level expectedLevel, Level level) {
        logEvent(level, null, null, "", null);
        assertLogLevel(expectedLevel);
    }

    @Test
    public void testThreadNameAddedToExtra() {
        ArgumentCaptor<Event> eventCaptor = ArgumentCaptor.forClass(Event.class);

        logEvent(Level.INFO, null, null, "testMessage", null);

        verify(mockRaven).sendEvent(eventCaptor.capture());
        assertThat(eventCaptor.getValue().getExtra(),
                Matchers.<String, Object>hasEntry(SentryAppender.THREAD_NAME, Thread.currentThread().getName()));
    }

    @Test
    public void testMarkerAddedToTag() {
        ArgumentCaptor<Event> eventCaptor = ArgumentCaptor.forClass(Event.class);
        String markerName = UUID.randomUUID().toString();

        logEvent(Level.INFO, MarkerManager.getMarker(markerName), null, "testMessage", null);

        verify(mockRaven).sendEvent(eventCaptor.capture());
        assertThat(eventCaptor.getValue().getTags(),
                Matchers.<String, Object>hasEntry(SentryAppender.LOG4J_MARKER, markerName));
    }

    @Test
    public void testMdcAddedToExtra() {
        ArgumentCaptor<Event> eventCaptor = ArgumentCaptor.forClass(Event.class);
        String extraKey = UUID.randomUUID().toString();
        String extraValue = UUID.randomUUID().toString();

        ThreadContext.put(extraKey, extraValue);

        logEvent(Level.INFO, null, null, "testMessage", null);

        verify(mockRaven).sendEvent(eventCaptor.capture());
        assertThat(eventCaptor.getValue().getExtra(), Matchers.<String, Object>hasEntry(extraKey, extraValue));
    }

    private void logEvent(Level level, Marker marker, Throwable exception, String messageString,
                          List<String> messageParameters) {
        Message message;
        if (messageParameters != null)
            message = new FormattedMessage(messageString, messageParameters.toArray());
        else
            message = new SimpleMessage(messageString);

        LogEvent event = new Log4jLogEvent(LOGGER_NAME, marker, SentryAppenderTest.class.getName(), level,
                message, exception);
        sentryAppender.append(event);
    }
}

@@ -676,16 +676,45 @@
 aptor;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -805,16 +805,147 @@
 rtThat;%0A
+import static org.hamcrest.Matchers.contains;%0Aimport static org.hamcrest.Matchers.hasKey;%0Aimport static org.mockito.Mockito.reset;%0A
 import s
@@ -4022,32 +4022,1124 @@
 Value));%0A    %7D%0A%0A
+    @Test%0A    @SuppressWarnings(%22unchecked%22)%0A    public void testNdcAddedToExtra() %7B%0A        ArgumentCaptor%3CEvent%3E eventCaptor = ArgumentCaptor.forClass(Event.class);%0A        String extra = UUID.randomUUID().toString();%0A        String extra2 = UUID.randomUUID().toString();%0A%0A        ThreadContext.push(extra);%0A        logEvent(Level.INFO, null, null, %22testMessage%22, null);%0A%0A        verify(mockRaven).sendEvent(eventCaptor.capture());%0A        assertThat(eventCaptor.getValue().getExtra(), hasKey(SentryAppender.LOG4J_NDC));%0A        assertThat((Collection%3CString%3E) eventCaptor.getValue().getExtra().get(SentryAppender.LOG4J_NDC),%0A                contains(extra));%0A%0A        reset(mockRaven);%0A        ThreadContext.push(extra2);%0A        logEvent(Level.INFO, null, null, %22testMessage%22, null);%0A%0A        verify(mockRaven).sendEvent(eventCaptor.capture());%0A        assertThat(eventCaptor.getValue().getExtra(), hasKey(SentryAppender.LOG4J_NDC));%0A        assertThat((Collection%3CString%3E) eventCaptor.getValue().getExtra().get(SentryAppender.LOG4J_NDC),%0A                contains(extra, extra2));%0A    %7D%0A%0A
     private void

Add test to check that NDC details are available as extras