blob: 2cfe9ff6746eeca1e7a0aca7068bc1431e8d0ef5 [file] [log] [blame]
/*
* 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());
}
}
}