/** * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.core.path_watch; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import junit.framework.TestCase; import name.pachler.nio.file.Paths; import name.pachler.nio.file.WatchEvent; import name.pachler.nio.file.WatchKey; import org.python.pydev.core.ListenerList; import com.aptana.shared_core.callbacks.ICallback; import com.aptana.shared_core.io.FileUtils; import com.aptana.shared_core.string.FastStringBuffer; import com.aptana.shared_core.structure.Tuple; /** * @author fabioz * */ public class PathWatchTest extends TestCase { private File baseDir; @Override protected void setUp() throws Exception { PathWatch.log = new FastStringBuffer(1000); baseDir = new File(FileUtils.getFileAbsolutePath(new File("pathwatchtest.temporary_dir"))); try { FileUtils.deleteDirectoryTree(baseDir); } catch (Exception e) { //ignore } } @Override protected void tearDown() throws Exception { System.out.println(PathWatch.log); PathWatch.log = null; FileUtils.deleteDirectoryTree(baseDir); } public void testEventsStackerRunnable() throws Exception { PathWatch.log.append("\n\n"); PathWatch.log.appendN('-', 50); PathWatch.log.append("testEventsStackerRunnable\n"); WatchKey key = new WatchKey() { public boolean reset() { return false; } public List<WatchEvent<?>> pollEvents() { return null; } public boolean isValid() { return true; } public void cancel() { } }; final List<Tuple<String, File>> changes = new ArrayList<Tuple<String, File>>(); ListenerList<IFilesystemChangesListener> list = new ListenerList<IFilesystemChangesListener>( IFilesystemChangesListener.class); list.add(new IFilesystemChangesListener() { public void removed(File file) { changes.add(new Tuple<String, File>("removed", file)); } public void added(File file) { changes.add(new Tuple<String, File>("added", file)); } }); EventsStackerRunnable stack = new EventsStackerRunnable(key, Paths.get(FileUtils.getFileAbsolutePath(baseDir)), list); stack.run(); assertEquals(0, changes.size()); stack.added(new File(baseDir, "f1.txt")); stack.removed(new File(baseDir, "f1.txt")); stack.run(); assertEquals(1, changes.size()); assertEquals("removed", changes.get(0).o1); changes.clear(); stack.added(new File(baseDir, "f1.txt")); stack.run(); assertEquals(1, changes.size()); assertEquals("added", changes.get(0).o1); changes.clear(); stack.added(new File(baseDir, "f1.txt")); stack.removed(new File(baseDir, "f1.txt")); stack.overflow(baseDir); stack.added(new File(baseDir, "f1.txt")); stack.removed(new File(baseDir, "f1.txt")); stack.run(); assertEquals(1, changes.size()); assertEquals("removed", changes.get(0).o1); changes.clear(); stack.run(); assertEquals(0, changes.size()); stack.overflow(baseDir); baseDir.mkdir(); stack.run(); assertEquals(2, changes.size()); assertEquals("removed", changes.get(0).o1); assertEquals("added", changes.get(1).o1); changes.clear(); } public void testPathWatch() throws Exception { PathWatch.log.append("\n\n"); PathWatch.log.appendN('-', 50); PathWatch.log.append("testPathWatch\n"); final PathWatch pathWatch = PathWatch.get(); baseDir.mkdir(); PathWatch.TIME_BEFORE_NOTIFY = 0; PathWatch.RECHECK_INVALID_PATHS_EACH = 0; final List<Tuple<String, File>> changes = new ArrayList<Tuple<String, File>>(); IFilesystemChangesListener listener = new IFilesystemChangesListener() { public void removed(File file) { changes.add(new Tuple<String, File>("removed", file)); } public void added(File file) { changes.add(new Tuple<String, File>("added", file)); } }; IFilesystemChangesListener listener2 = new IFilesystemChangesListener() { public void removed(File file) { changes.add(new Tuple<String, File>("removed", file)); } public void added(File file) { changes.add(new Tuple<String, File>("added", file)); } }; pathWatch.track(baseDir, listener); for (int i = 0; i < 5; i++) { FileUtils.writeStrToFile("FILE1", new File(baseDir, "f" + i + ".txt")); } waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { HashSet<Tuple<String, File>> set = new HashSet<Tuple<String, File>>(changes); if (set.size() == 5) { for (Tuple<String, File> tuple : set) { assertEquals("added", tuple.o1); } return null; } return changes.toString(); } }); changes.clear(); File[] files = baseDir.listFiles(); if (files != null) { for (int i = 0; i < files.length; ++i) { File f = files[i]; f.delete(); } } waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { if (changes.size() == 5) { for (Tuple<String, File> tuple : changes) { assertEquals("removed", tuple.o1); } return null; } return changes.toString(); } }); changes.clear(); assertTrue(baseDir.delete()); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { if (changes.size() == 1) { for (Tuple<String, File> tuple : changes) { assertEquals("removed", tuple.o1); assertEquals(baseDir, tuple.o2); } return null; } return changes.toString(); } }); changes.clear(); pathWatch.track(baseDir, listener2); baseDir.mkdir(); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { if (changes.size() == 2) { for (Tuple<String, File> tuple : changes) { assertEquals("added", tuple.o1); assertEquals(baseDir, tuple.o2); } return null; } return changes.toString(); } }); changes.clear(); PathWatch.log.append("testPathWatch: deleteBaseDir\n"); assertTrue(baseDir.delete()); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { if (changes.size() == 2) { for (Tuple<String, File> tuple : changes) { assertEquals("removed", tuple.o1); assertEquals(baseDir, tuple.o2); } return null; } return changes.toString(); } }); changes.clear(); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { Set<EventsStackerRunnable> invalidPaths = pathWatch.getInvalidPaths(); if (invalidPaths.size() == 1) { return null; } return invalidPaths.toString(); } }); pathWatch.stopTrack(baseDir, listener); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { Set<EventsStackerRunnable> invalidPaths = pathWatch.getInvalidPaths(); if (invalidPaths.size() == 1) { return null; } return invalidPaths.toString(); } }); pathWatch.stopTrack(baseDir, listener2); assertEquals(0, pathWatch.getInvalidPaths().size()); baseDir.mkdir(); try { synchronized (this) { wait(200); } } catch (Exception e) { e.printStackTrace(); } assertEquals(0, changes.size()); assertTrue(baseDir.delete()); changes.clear(); pathWatch.track(baseDir, listener); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { Set<EventsStackerRunnable> invalidPaths = pathWatch.getInvalidPaths(); if (invalidPaths.size() == 1) { return null; } return invalidPaths.toString(); } }); baseDir.mkdir(); waitUntilCondition(new ICallback<String, Object>() { public String call(Object arg) { if (changes.size() == 1) { for (Tuple<String, File> tuple : changes) { assertEquals("added", tuple.o1); assertEquals(baseDir, tuple.o2); } return null; } return changes.toString(); } }); assertEquals(0, pathWatch.getInvalidPaths().size()); changes.clear(); } private void waitUntilCondition(ICallback<String, Object> call) { long currentTimeMillis = System.currentTimeMillis(); String msg = null; while (System.currentTimeMillis() < currentTimeMillis + 2000) { //at most 2 seconds msg = call.call(null); if (msg == null) { return; } synchronized (this) { try { wait(25); } catch (Exception e) { e.printStackTrace(); } } } fail("Condition not satisfied in 2 seconds." + msg + "\nLog:" + PathWatch.log.toString()); } }