blob: f2298cb3e6ba666a23cdafcb1c7d293f3aaf2cc6 [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.commons.io.input;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.testtools.FileBasedTestCase;
/**
* Tests for {@link Tailer}.
*
* @version $Id$
*/
public class TailerTest extends FileBasedTestCase {
private Tailer tailer;
public TailerTest(String name) {
super(name);
}
@Override
protected void tearDown() throws Exception {
if (tailer != null) {
tailer.stop();
Thread.sleep(1000);
}
FileUtils.deleteDirectory(getTestDirectory());
}
public void testTailerEof() throws Exception {
// Create & start the Tailer
long delay = 50;
final File file = new File(getTestDirectory(), "tailer2-test.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener();
final Tailer tailer = new Tailer(file, listener, delay, false);
final Thread thread = new Thread(tailer);
thread.start();
// Write some lines to the file
FileWriter writer = null;
try {
writeString(file, "Line");
Thread.sleep(delay * 2);
List<String> lines = listener.getLines();
assertEquals("1 line count", 0, lines.size());
writeString(file, " one\n");
Thread.sleep(delay * 2);
lines = listener.getLines();
assertEquals("1 line count", 1, lines.size());
assertEquals("1 line 1", "Line one", lines.get(0));
listener.clear();
} finally {
tailer.stop();
Thread.sleep(delay * 2);
IOUtils.closeQuietly(writer);
}
}
public void testTailer() throws Exception {
// Create & start the Tailer
long delayMillis = 50;
final File file = new File(getTestDirectory(), "tailer1-test.txt");
createFile(file, 0);
final TestTailerListener listener = new TestTailerListener();
tailer = new Tailer(file, listener, delayMillis, false);
final Thread thread = new Thread(tailer);
thread.start();
// Write some lines to the file
write(file, "Line one", "Line two");
final long testDelayMillis = delayMillis * 10;
Thread.sleep(testDelayMillis);
List<String> lines = listener.getLines();
assertEquals("1 line count", 2, lines.size());
assertEquals("1 line 1", "Line one", lines.get(0));
assertEquals("1 line 2", "Line two", lines.get(1));
listener.clear();
// Write another line to the file
write(file, "Line three");
Thread.sleep(testDelayMillis);
lines = listener.getLines();
assertEquals("2 line count", 1, lines.size());
assertEquals("2 line 3", "Line three", lines.get(0));
listener.clear();
// Check file does actually have all the lines
lines = FileUtils.readLines(file);
assertEquals("3 line count", 3, lines.size());
assertEquals("3 line 1", "Line one", lines.get(0));
assertEquals("3 line 2", "Line two", lines.get(1));
assertEquals("3 line 3", "Line three", lines.get(2));
// Delete & re-create
file.delete();
boolean exists = file.exists();
String osname = System.getProperty("os.name");
boolean isWindows = osname.startsWith("Windows");
assertFalse("File should not exist (except on Windows)", exists && !isWindows);
createFile(file, 0);
Thread.sleep(testDelayMillis);
// Write another line
write(file, "Line four");
Thread.sleep(testDelayMillis);
lines = listener.getLines();
assertEquals("4 line count", 1, lines.size());
assertEquals("4 line 3", "Line four", lines.get(0));
listener.clear();
// Stop
tailer.stop();
tailer=null;
thread.interrupt();
Thread.sleep(testDelayMillis);
write(file, "Line five");
assertEquals("4 line count", 0, listener.getLines().size());
assertNull("Should not generate Exception", listener.exception);
assertEquals("Expected init to be called", 1 , listener.initialised);
assertEquals("fileNotFound should not be called", 0 , listener.notFound);
assertEquals("fileRotated should be be called", 1 , listener.rotated);
}
@Override
protected void createFile(File file, long size)
throws IOException {
super.createFile(file, size);
// try to make sure file is found
// (to stop continuum occasionally failing)
RandomAccessFile reader = null;
try {
while (reader == null) {
try {
reader = new RandomAccessFile(file.getPath(), "r");
} catch (FileNotFoundException e) {
}
try {
Thread.sleep(200L);
} catch (InterruptedException e) {
// ignore
}
}
} finally {
IOUtils.closeQuietly(reader);
}
}
/** Append some lines to a file */
private void write(File file, String... lines) throws Exception {
FileWriter writer = null;
try {
writer = new FileWriter(file, true);
for (String line : lines) {
writer.write(line + "\n");
}
} finally {
IOUtils.closeQuietly(writer);
}
}
/** Append a string to a file */
private void writeString(File file, String string) throws Exception {
FileWriter writer = null;
try {
writer = new FileWriter(file, true);
writer.write(string);
} finally {
IOUtils.closeQuietly(writer);
}
}
public void testStopWithNoFile() throws Exception {
final File file = new File(getTestDirectory(),"nosuchfile");
assertFalse("nosuchfile should not exist", file.exists());
final TestTailerListener listener = new TestTailerListener();
int delay = 100;
int idle = 50; // allow time for thread to work
tailer = Tailer.create(file, listener, delay, false);
Thread.sleep(idle);
tailer.stop();
tailer=null;
Thread.sleep(delay+idle);
assertNull("Should not generate Exception", listener.exception);
assertEquals("Expected init to be called", 1 , listener.initialised);
assertTrue("fileNotFound should be called", listener.notFound > 0);
assertEquals("fileRotated should be not be called", 0 , listener.rotated);
}
public void testStopWithNoFileUsingExecutor() throws Exception {
final File file = new File(getTestDirectory(),"nosuchfile");
assertFalse("nosuchfile should not exist", file.exists());
TestTailerListener listener = new TestTailerListener();
int delay = 100;
int idle = 50; // allow time for thread to work
tailer = new Tailer(file, listener, delay, false);
Executor exec = new ScheduledThreadPoolExecutor(1);
exec.execute(tailer);
Thread.sleep(idle);
tailer.stop();
tailer=null;
Thread.sleep(delay+idle);
assertNull("Should not generate Exception", listener.exception);
assertEquals("Expected init to be called", 1 , listener.initialised);
assertTrue("fileNotFound should be called", listener.notFound > 0);
assertEquals("fileRotated should be not be called", 0 , listener.rotated);
}
/**
* Test {@link TailerListener} implementation.
*/
private static class TestTailerListener implements TailerListener {
private final List<String> lines = new ArrayList<String>();
volatile Exception exception = null;
volatile int notFound = 0;
volatile int rotated = 0;
volatile int initialised = 0;
public void handle(String line) {
lines.add(line);
}
public List<String> getLines() {
return lines;
}
public void clear() {
lines.clear();
}
public void handle(Exception e) {
exception = e;
}
public void init(Tailer tailer) {
initialised++; // not atomic, but OK because only updated here.
}
public void fileNotFound() {
notFound++; // not atomic, but OK because only updated here.
}
public void fileRotated() {
rotated++; // not atomic, but OK because only updated here.
}
}
}