blob: f1fb99df8ab80a6d5b8393de33cf5a3555617648 [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.monitor;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.apache.commons.io.ThreadUtils;
import org.apache.commons.io.test.TestUtils;
import org.junit.jupiter.api.Test;
/**
* {@link FileAlterationMonitor} Test Case.
*/
public class FileAlterationMonitorTest extends AbstractMonitorTest {
/**
* Constructs a new test case.
*/
public FileAlterationMonitorTest() {
listener = new CollectionFileListener(false);
}
/**
* Check all the File Collections have the expected sizes.
*/
private void checkFile(final String label, final File file, final Collection<File> files) {
for (int i = 0; i < 20; i++) {
if (files.contains(file)) {
return; // found, test passes
}
TestUtils.sleepQuietly(pauseTime);
}
fail(label + " " + file + " not found");
}
/**
* Test add/remove observers.
*/
@Test
public void testAddRemoveObservers() {
FileAlterationObserver[] observers = null;
// Null Observers
FileAlterationMonitor monitor = new FileAlterationMonitor(123, observers);
assertEquals(123, monitor.getInterval(), "Interval");
assertFalse(monitor.getObservers().iterator().hasNext(), "Observers[1]");
// Null Observer
observers = new FileAlterationObserver[1]; // observer is null
monitor = new FileAlterationMonitor(456, observers);
assertFalse(monitor.getObservers().iterator().hasNext(), "Observers[2]");
// Null Observer
monitor.addObserver(null);
assertFalse(monitor.getObservers().iterator().hasNext(), "Observers[3]");
monitor.removeObserver(null);
// Add Observer
final FileAlterationObserver observer = new FileAlterationObserver("foo");
monitor.addObserver(observer);
final Iterator<FileAlterationObserver> it = monitor.getObservers().iterator();
assertTrue(it.hasNext(), "Observers[4]");
assertEquals(observer, it.next(), "Added");
assertFalse(it.hasNext(), "Observers[5]");
// Remove Observer
monitor.removeObserver(observer);
assertFalse(monitor.getObservers().iterator().hasNext(), "Observers[6]");
}
@Test
public void testCollectionConstructor() {
observer = new FileAlterationObserver("foo");
final Collection<FileAlterationObserver> observers = Arrays.asList(observer);
final FileAlterationMonitor monitor = new FileAlterationMonitor(0, observers);
final Iterator<FileAlterationObserver> iterator = monitor.getObservers().iterator();
assertEquals(observer, iterator.next());
}
@Test
public void testCollectionConstructorShouldDoNothingWithNullCollection() {
final Collection<FileAlterationObserver> observers = null;
final FileAlterationMonitor monitor = new FileAlterationMonitor(0, observers);
assertFalse(monitor.getObservers().iterator().hasNext());
}
@Test
public void testCollectionConstructorShouldDoNothingWithNullObservers() {
final Collection<FileAlterationObserver> observers = new ArrayList<>(5);
final FileAlterationMonitor monitor = new FileAlterationMonitor(0, observers);
assertFalse(monitor.getObservers().iterator().hasNext());
}
/**
* Test default constructor.
*/
@Test
public void testDefaultConstructor() {
final FileAlterationMonitor monitor = new FileAlterationMonitor();
assertEquals(10000, monitor.getInterval(), "Interval");
}
/**
* Test checkAndNotify() method
* @throws Exception
*/
@Test
public void testMonitor() throws Exception {
final long interval = 100;
listener.clear();
final FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
assertEquals(interval, monitor.getInterval(), "Interval");
monitor.start();
// try and start again
assertThrows(IllegalStateException.class, () -> monitor.start());
// Create a File
checkCollectionsEmpty("A");
File file1 = touch(new File(testDir, "file1.java"));
checkFile("Create", file1, listener.getCreatedFiles());
listener.clear();
// Update a file
checkCollectionsEmpty("B");
file1 = touch(file1);
checkFile("Update", file1, listener.getChangedFiles());
listener.clear();
// Delete a file
checkCollectionsEmpty("C");
file1.delete();
checkFile("Delete", file1, listener.getDeletedFiles());
listener.clear();
// Stop monitoring
monitor.stop();
// try and stop again
assertThrows(IllegalStateException.class, () -> monitor.stop());
}
/**
* Test case for IO-535
*
* Verify that {@link FileAlterationMonitor#stop()} stops the created thread
*/
@Test
public void testStopWhileWaitingForNextInterval() throws Exception {
final Collection<Thread> createdThreads = new ArrayList<>(1);
final ThreadFactory threadFactory = new ThreadFactory() {
private final ThreadFactory delegate = Executors.defaultThreadFactory();
@Override
public Thread newThread(final Runnable r) {
final Thread thread = delegate.newThread(r);
thread.setDaemon(true); //do not leak threads if the test fails
createdThreads.add(thread);
return thread;
}
};
final FileAlterationMonitor monitor = new FileAlterationMonitor(1_000);
monitor.setThreadFactory(threadFactory);
monitor.start();
assertFalse(createdThreads.isEmpty());
ThreadUtils.sleep(Duration.ofMillis(10)); // wait until the watcher thread enters Thread.sleep()
monitor.stop(100);
createdThreads.forEach(thread -> assertFalse(thread.isAlive(), "The FileAlterationMonitor did not stop the threads it created."));
}
/**
* Test using a thread factory.
* @throws Exception
*/
@Test
public void testThreadFactory() throws Exception {
final long interval = 100;
listener.clear();
final FileAlterationMonitor monitor = new FileAlterationMonitor(interval, observer);
monitor.setThreadFactory(Executors.defaultThreadFactory());
assertEquals(interval, monitor.getInterval(), "Interval");
monitor.start();
// Create a File
checkCollectionsEmpty("A");
final File file2 = touch(new File(testDir, "file2.java"));
checkFile("Create", file2, listener.getCreatedFiles());
listener.clear();
// Delete a file
checkCollectionsEmpty("B");
file2.delete();
checkFile("Delete", file2, listener.getDeletedFiles());
listener.clear();
// Stop monitoring
monitor.stop();
}
}