package org.geotoolkit.nio; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.UUID; import static org.apache.sis.test.Assert.assertTrue; /** * A test class to ensure recursive survey mechanism of {@link DirectoryWatcher} is working properly. * * @author Alexis Manin (Geomatys) */ public class RecursiveWatchTest extends DirectoryWatcherTest { @Before public void initWatcher() throws IOException { watcher = new DirectoryWatcher(true); watcher.addPathChangeListener(new MockListener(results)); watcher.register(rootDir); watcher.start(); } @After public void closeWatcher() throws IOException { watcher.stop(); watcher.close(); } /** * A simple test in which we'll try to create / delete files and directories recursively, and ensure events are * propagated. */ @Test(timeout=5000) public void testRecursivity() throws IOException, InterruptedException { Path childFile = rootDir.resolve("0.tmp"); assertFileCreated(childFile); assertFileDeleted(childFile); Path childDir = rootDir.resolve("0"); assertDirectoryCreated(childDir); // Test recursive creation Path previousDir = childDir; Path newFile; for (int i = 0 ; i < 10 ; i++) { newFile = previousDir.resolve(UUID.randomUUID().toString()+".tmp"); assertFileCreated(newFile); previousDir = previousDir.resolve(UUID.randomUUID().toString()); assertDirectoryCreated(previousDir); } //Test recursive removal assertDeleteFileTree(childDir); } /** * Add a root directory to the watcher component, and check events are well propagated. Then we'll unregister it, * and check events are no longer caught. * * @throws IOException */ @Test(timeout=5000) public void multipleRootTest() throws IOException, InterruptedException { final Path newRoot = Files.createTempDirectory("DirectoryWatcherTest2"); watcher.register(newRoot); Path childDir = newRoot.resolve("0"); assertDirectoryCreated(childDir); // Test recursivity Path subDir = childDir.resolve("0"); assertDirectoryCreated(subDir); // Test recursivity Path subFile = subDir.resolve("0.tmp"); assertFileCreated(subFile); assertFileDeleted(subFile); // Try to remove a root watcher.unregister(newRoot); Files.delete(subDir); Thread.sleep(500); assertTrue("We are on a removed root. sub-directory's changes should not be seen.", results.isEmpty()); Files.delete(childDir); Thread.sleep(500); assertTrue("We are on a removed root. sub-directory's changes should not be seen.", results.isEmpty()); Files.delete(newRoot); Thread.sleep(500); assertTrue("We are on a removed root. sub-directory's changes should not be seen.", results.isEmpty()); } /** * Add a filter on file names. We check : * - Changed files which don't match the filter should not be seen. * - Changed files matching filter should be seen. * - Remove filter makes all changed files visible. * @throws Exception */ @Test(timeout=10000) public void fileFilterTest() throws Exception { // Add a file filter watcher.setFileFilter(new DirectoryStream.Filter<Path>() { final PathMatcher matcher = FileSystems.getDefault().getPathMatcher("regex:(?i).*\\.tif"); @Override public boolean accept(Path entry) throws IOException { return matcher.matches(entry); } }); Path child = rootDir.resolve("file.tmp"); Files.createFile(child); Thread.sleep(500); assertTrue("File creation event should not be propagated cause of the file filter.", results.isEmpty()); Files.delete(child); Thread.sleep(500); assertTrue("File deletion event should not be propagated cause of the file filter.", results.isEmpty()); child = rootDir.resolve("testDir.tif"); assertDirectoryCreated(child); // Test recursive creation Path previousDir = child; Path matchingFile, ignoredFile; for (int i = 0 ; i < 5 ; i++) { // filter should not be applied on files, so we must see it. matchingFile = previousDir.resolve(""+i+".tif"); assertFileCreated(matchingFile); ignoredFile = previousDir.resolve(""+i+".tmp"); Files.createFile(ignoredFile); Thread.sleep(500); assertTrue("File deletion event should not be propagated cause of the file filter.", results.isEmpty()); // check that a directory matching filter is seen assertDirectoryCreated(previousDir.resolve("temp.tif")); // Check a directory which doesn't match filter. previousDir = previousDir.resolve(""+i); Files.createDirectory(previousDir); Thread.sleep(500); assertTrue("File deletion event should not be propagated cause of the file filter.", results.isEmpty()); } // Remove the file filter. All deleted file/folder should be seen by our listener. watcher.setFileFilter(null); assertDeleteFileTree(child); } /** * Delete a directory and all its content. For each deleted file / folder, we check event propagation. * * @param root The folder to delete. * @throws IOException If input path does not represent a directory, or if an unexpected error happened while removal. */ public void assertDeleteFileTree(final Path root) throws IOException { Files.walkFileTree(root, new SimpleFileVisitor<Path>() { @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { try { assertDirectoryDeleted(dir); } catch (InterruptedException e) { e.printStackTrace(); } return super.postVisitDirectory(dir, exc); } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { try { assertFileDeleted(file); } catch (InterruptedException e) { e.printStackTrace(); } return super.visitFile(file, attrs); } }); } }