/** * Licensed 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 net.logstash.logback.encoder; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; import net.logstash.logback.Logback11Support; import net.logstash.logback.composite.CompositeJsonFormatter; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Context; import ch.qos.logback.core.encoder.Encoder; import ch.qos.logback.core.encoder.LayoutWrappingEncoder; import ch.qos.logback.core.status.StatusManager; import ch.qos.logback.core.status.WarnStatus; @SuppressWarnings("unchecked") @RunWith(PowerMockRunner.class) @PrepareForTest(Logback11Support.class) public class CompositeJsonEncoderTest { private CompositeJsonFormatter<ILoggingEvent> formatter = mock(CompositeJsonFormatter.class); @InjectMocks private CompositeJsonEncoder<ILoggingEvent> encoder = new CompositeJsonEncoder<ILoggingEvent>() { @Override protected CompositeJsonFormatter<ILoggingEvent> createFormatter() { return formatter; } }; @Mock private Context context; @Mock private StatusManager statusManager; @Mock private ILoggingEvent event; private ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); private BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); @Before public void setup() { when(formatter.getEncoding()).thenReturn("UTF-8"); when(context.getStatusManager()).thenReturn(statusManager); } @Test public void testNoPrefixNoSuffix_logback11() throws IOException { PowerMockito.mockStatic(Logback11Support.class); when(Logback11Support.isLogback11OrBefore()).thenReturn(true); encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); encoder.init(outputStream); encoder.doEncode(event); verify(formatter).writeEventToOutputStream(event, outputStream); Assert.assertEquals(System.getProperty("line.separator"), outputStream.toString("UTF-8")); encoder.stop(); Assert.assertFalse(encoder.isStarted()); verify(formatter).stop(); } @Test public void testNoPrefixNoSuffix_logback12OrLater() throws IOException { encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); byte[] encoded = encoder.encode(event); verify(formatter).writeEventToOutputStream(eq(event), any(OutputStream.class)); assertThat(encoded).containsExactly(System.getProperty("line.separator").getBytes("UTF-8")); encoder.stop(); Assert.assertFalse(encoder.isStarted()); verify(formatter).stop(); } @Test public void testPrefixAndSuffix_logback11() throws IOException { PowerMockito.mockStatic(Logback11Support.class); when(Logback11Support.isLogback11OrBefore()).thenReturn(true); LayoutWrappingEncoder<ILoggingEvent> prefix = mock(LayoutWrappingEncoder.class); Encoder<ILoggingEvent> suffix = mock(Encoder.class); encoder.setPrefix(prefix); encoder.setSuffix(suffix); encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); verify(prefix).setCharset(Charset.forName("UTF-8")); verify(prefix).start(); verify(suffix).start(); encoder.init(outputStream); PowerMockito.verifyStatic(); Logback11Support.init(prefix, outputStream); PowerMockito.verifyStatic(); Logback11Support.init(suffix, outputStream); encoder.doEncode(event); PowerMockito.verifyStatic(); Logback11Support.doEncode(prefix, event); PowerMockito.verifyStatic(); Logback11Support.doEncode(suffix, event); verify(formatter).writeEventToOutputStream(event, outputStream); Assert.assertEquals(System.getProperty("line.separator"), outputStream.toString("UTF-8")); encoder.close(); PowerMockito.verifyStatic(); Logback11Support.close(prefix); PowerMockito.verifyStatic(); Logback11Support.close(suffix); encoder.stop(); Assert.assertFalse(encoder.isStarted()); verify(formatter).stop(); verify(prefix).stop(); verify(suffix).stop(); } @Test public void testPrefixAndSuffix_logback12OrLater() throws IOException { LayoutWrappingEncoder<ILoggingEvent> prefix = mock(LayoutWrappingEncoder.class); Encoder<ILoggingEvent> suffix = mock(Encoder.class); when(prefix.encode(event)).thenReturn("prefix".getBytes("UTF-8")); when(suffix.encode(event)).thenReturn("suffix".getBytes("UTF-8")); encoder.setPrefix(prefix); encoder.setSuffix(suffix); encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); verify(prefix).setCharset(Charset.forName("UTF-8")); verify(prefix).start(); verify(suffix).start(); byte[] encoded = encoder.encode(event); verify(prefix).encode(event); verify(suffix).encode(event); verify(formatter).writeEventToOutputStream(eq(event), any(OutputStream.class)); assertThat(encoded).containsExactly(("prefixsuffix" + System.getProperty("line.separator")).getBytes("UTF-8")); encoder.stop(); Assert.assertFalse(encoder.isStarted()); verify(formatter).stop(); verify(prefix).stop(); verify(suffix).stop(); } @Test public void testNoImmediateFlush_logback11() throws IOException { PowerMockito.mockStatic(Logback11Support.class); when(Logback11Support.isLogback11OrBefore()).thenReturn(true); encoder.setImmediateFlush(false); encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); encoder.init(bufferedOutputStream); encoder.doEncode(event); verify(formatter).writeEventToOutputStream(event, bufferedOutputStream); Assert.assertEquals("", outputStream.toString("UTF-8")); bufferedOutputStream.flush(); Assert.assertEquals(System.getProperty("line.separator"), outputStream.toString("UTF-8")); encoder.stop(); Assert.assertFalse(encoder.isStarted()); verify(formatter).stop(); } @Test public void testLineEndings() throws IOException { Assert.assertEquals(System.getProperty("line.separator"), encoder.getLineSeparator()); encoder.setLineSeparator("UNIX"); Assert.assertEquals("\n", encoder.getLineSeparator()); encoder.setLineSeparator(null); Assert.assertEquals(null, encoder.getLineSeparator()); encoder.setLineSeparator("WINDOWS"); Assert.assertEquals("\r\n", encoder.getLineSeparator()); encoder.setLineSeparator("foo"); Assert.assertEquals("foo", encoder.getLineSeparator()); encoder.setLineSeparator("SYSTEM"); Assert.assertEquals(System.getProperty("line.separator"), encoder.getLineSeparator()); encoder.setLineSeparator(""); Assert.assertEquals(null, encoder.getLineSeparator()); } @Test public void testIOException_logback11() throws IOException { PowerMockito.mockStatic(Logback11Support.class); when(Logback11Support.isLogback11OrBefore()).thenReturn(true); encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); encoder.init(outputStream); IOException exception = new IOException(); doThrow(exception).when(formatter).writeEventToOutputStream(event, outputStream); encoder.doEncode(event); Assert.assertTrue(encoder.isStarted()); verify(statusManager).add(new WarnStatus("Error encountered while encoding log event. " + "OutputStream is now in an unknown state, but will continue to be used for future log events." + "Event: " + event, context, exception)); } @Test public void testIOException_logback12OrLater() throws IOException { encoder.start(); Assert.assertTrue(encoder.isStarted()); verify(formatter).setContext(context); verify(formatter).start(); IOException exception = new IOException(); doThrow(exception).when(formatter).writeEventToOutputStream(eq(event), any(OutputStream.class)); encoder.encode(event); Assert.assertTrue(encoder.isStarted()); verify(statusManager).add(new WarnStatus("Error encountered while encoding log event. " + "Event: " + event, context, exception)); } }