/* * 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.ambari.logfeeder.output.spool; import org.easymock.EasyMockRule; import org.easymock.LogicalOperator; import org.easymock.Mock; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Comparator; import static org.easymock.EasyMock.*; public class LogSpoolerTest { @Rule public TemporaryFolder testFolder = new TemporaryFolder(); @Rule public EasyMockRule mocks = new EasyMockRule(this); private String spoolDirectory; private static final String SOURCE_FILENAME_PREFIX = "hdfs-namenode.log"; @Mock private RolloverCondition rolloverCondition; @Mock private RolloverHandler rolloverHandler; @Before public void setup() { spoolDirectory = testFolder.getRoot().getAbsolutePath(); } @Test public void shouldSpoolEventToFile() { final PrintWriter spoolWriter = mock(PrintWriter.class); spoolWriter.println("log event"); final File mockFile = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext = new LogSpoolerContext(mockFile); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext, new LogSpoolerFileComparator(), LogicalOperator.EQUAL))). andReturn(false); replay(spoolWriter, rolloverCondition, mockFile); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { return spoolWriter; } @Override protected File initializeSpoolFile() { return mockFile; } }; logSpooler.add("log event"); verify(spoolWriter); } private File setupInputFileExpectations() { final File mockFile = mock(File.class); expect(mockFile.length()).andReturn(10240L); return mockFile; } @Test public void shouldIncrementSpooledEventsCount() { final PrintWriter spoolWriter = mock(PrintWriter.class); spoolWriter.println("log event"); final File mockFile = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext = new LogSpoolerContext(mockFile); logSpoolerContext.logEventSpooled(); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext, new LogSpoolerEventCountComparator(), LogicalOperator.EQUAL))). andReturn(false); replay(spoolWriter, rolloverCondition, mockFile); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { return spoolWriter; } @Override protected File initializeSpoolFile() { return mockFile; } }; logSpooler.add("log event"); verify(rolloverCondition); } @Test public void shouldCloseCurrentSpoolFileOnRollOver() { final PrintWriter spoolWriter = mock(PrintWriter.class); spoolWriter.println("log event"); spoolWriter.flush(); spoolWriter.close(); final File mockFile = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext = new LogSpoolerContext(mockFile); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext, new LogSpoolerFileComparator(), LogicalOperator.EQUAL))). andReturn(true); rolloverHandler.handleRollover(mockFile); replay(spoolWriter, rolloverCondition, rolloverHandler, mockFile); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { return spoolWriter; } @Override protected File initializeSpoolFile() { return mockFile; } }; logSpooler.add("log event"); verify(spoolWriter); } @Test public void shouldReinitializeFileOnRollover() { final PrintWriter spoolWriter1 = mock(PrintWriter.class); final PrintWriter spoolWriter2 = mock(PrintWriter.class); spoolWriter1.println("log event1"); spoolWriter2.println("log event2"); spoolWriter1.flush(); spoolWriter1.close(); final File mockFile1 = setupInputFileExpectations(); final File mockFile2 = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext1 = new LogSpoolerContext(mockFile1); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext1, new LogSpoolerFileComparator(), LogicalOperator.EQUAL)) ).andReturn(true); LogSpoolerContext logSpoolerContext2 = new LogSpoolerContext(mockFile2); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext2, new LogSpoolerFileComparator(), LogicalOperator.EQUAL)) ).andReturn(false); rolloverHandler.handleRollover(mockFile1); replay(spoolWriter1, spoolWriter2, rolloverCondition, rolloverHandler, mockFile1, mockFile2); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { private boolean wasRolledOver; @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { if (!wasRolledOver) { wasRolledOver = true; return spoolWriter1; } else { return spoolWriter2; } } @Override protected File initializeSpoolFile() { if (!wasRolledOver) { return mockFile1; } else { return mockFile2; } } }; logSpooler.add("log event1"); logSpooler.add("log event2"); verify(spoolWriter1, spoolWriter2, rolloverCondition); } @Test public void shouldCallRolloverHandlerOnRollover() { final PrintWriter spoolWriter = mock(PrintWriter.class); spoolWriter.println("log event"); spoolWriter.flush(); spoolWriter.close(); final File mockFile = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext = new LogSpoolerContext(mockFile); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext, new LogSpoolerFileComparator(), LogicalOperator.EQUAL)) ).andReturn(true); rolloverHandler.handleRollover(mockFile); replay(spoolWriter, rolloverCondition, rolloverHandler, mockFile); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { return spoolWriter; } @Override protected File initializeSpoolFile() { return mockFile; } }; logSpooler.add("log event"); verify(rolloverHandler); } // Rollover twice - the second rollover should work if the "rolloverInProgress" // flag is being reset correctly. Third file expectations being setup due // to auto-initialization. @Test public void shouldResetRolloverInProgressFlag() { final PrintWriter spoolWriter1 = mock(PrintWriter.class); final PrintWriter spoolWriter2 = mock(PrintWriter.class); final PrintWriter spoolWriter3 = mock(PrintWriter.class); spoolWriter1.println("log event1"); spoolWriter2.println("log event2"); spoolWriter1.flush(); spoolWriter1.close(); spoolWriter2.flush(); spoolWriter2.close(); final File mockFile1 = setupInputFileExpectations(); final File mockFile2 = setupInputFileExpectations(); final File mockFile3 = setupInputFileExpectations(); LogSpoolerContext logSpoolerContext1 = new LogSpoolerContext(mockFile1); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext1, new LogSpoolerFileComparator(), LogicalOperator.EQUAL)) ).andReturn(true); LogSpoolerContext logSpoolerContext2 = new LogSpoolerContext(mockFile2); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext2, new LogSpoolerFileComparator(), LogicalOperator.EQUAL)) ).andReturn(true); rolloverHandler.handleRollover(mockFile1); rolloverHandler.handleRollover(mockFile2); replay(spoolWriter1, spoolWriter2, rolloverCondition, rolloverHandler, mockFile1, mockFile2, mockFile3); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { private int currentFileNum; @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { PrintWriter spoolWriter = null; switch (currentFileNum) { case 0: spoolWriter = spoolWriter1; break; case 1: spoolWriter = spoolWriter2; break; case 2: spoolWriter = spoolWriter3; break; } currentFileNum++; return spoolWriter; } @Override protected File initializeSpoolFile() { switch (currentFileNum) { case 0: return mockFile1; case 1: return mockFile2; case 2: return mockFile3; default: return null; } } }; logSpooler.add("log event1"); logSpooler.add("log event2"); verify(spoolWriter1, spoolWriter2, rolloverCondition); } @Test public void shouldNotRolloverZeroLengthFiles() { final PrintWriter spoolWriter = mock(PrintWriter.class); spoolWriter.println("log event"); spoolWriter.flush(); spoolWriter.close(); final File mockFile = mock(File.class); expect(mockFile.length()).andReturn(0L); LogSpoolerContext logSpoolerContext = new LogSpoolerContext(mockFile); expect(rolloverCondition.shouldRollover( cmp(logSpoolerContext, new LogSpoolerFileComparator(), LogicalOperator.EQUAL))). andReturn(true); replay(spoolWriter, rolloverCondition, mockFile); LogSpooler logSpooler = new LogSpooler(spoolDirectory, SOURCE_FILENAME_PREFIX, rolloverCondition, rolloverHandler) { @Override protected PrintWriter initializeSpoolWriter(File spoolFile) throws IOException { return spoolWriter; } @Override protected File initializeSpoolFile() { return mockFile; } }; logSpooler.add("log event"); verify(mockFile); } class LogSpoolerFileComparator implements Comparator<LogSpoolerContext> { @Override public int compare(LogSpoolerContext o1, LogSpoolerContext o2) { return o1.getActiveSpoolFile()==o2.getActiveSpoolFile() ? 0 : -1; } } class LogSpoolerEventCountComparator implements Comparator<LogSpoolerContext> { @Override public int compare(LogSpoolerContext o1, LogSpoolerContext o2) { return (int)(o1.getNumEventsSpooled()-o2.getNumEventsSpooled()); } } }