diff options
Diffstat (limited to 'jimfs/src/test/java/com/google/common/jimfs/PollingWatchServiceTest.java')
-rw-r--r-- | jimfs/src/test/java/com/google/common/jimfs/PollingWatchServiceTest.java | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/jimfs/src/test/java/com/google/common/jimfs/PollingWatchServiceTest.java b/jimfs/src/test/java/com/google/common/jimfs/PollingWatchServiceTest.java new file mode 100644 index 0000000..86f9832 --- /dev/null +++ b/jimfs/src/test/java/com/google/common/jimfs/PollingWatchServiceTest.java @@ -0,0 +1,247 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed 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 com.google.common.jimfs; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.Assert.fail; + +import com.google.common.collect.ImmutableList; +import com.google.common.jimfs.AbstractWatchService.Event; +import com.google.common.jimfs.AbstractWatchService.Key; +import com.google.common.util.concurrent.Runnables; +import com.google.common.util.concurrent.Uninterruptibles; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link PollingWatchService}. + * + * @author Colin Decker + */ +@RunWith(JUnit4.class) +public class PollingWatchServiceTest { + + private JimfsFileSystem fs; + private PollingWatchService watcher; + + @Before + public void setUp() { + fs = (JimfsFileSystem) Jimfs.newFileSystem(Configuration.unix()); + watcher = + new PollingWatchService( + fs.getDefaultView(), + fs.getPathService(), + new FileSystemState(Runnables.doNothing()), + 4, + MILLISECONDS); + } + + @After + public void tearDown() throws IOException { + watcher.close(); + fs.close(); + watcher = null; + fs = null; + } + + @Test + public void testNewWatcher() { + assertThat(watcher.isOpen()).isTrue(); + assertThat(watcher.isPolling()).isFalse(); + } + + @Test + public void testRegister() throws IOException { + Key key = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE)); + assertThat(key.isValid()).isTrue(); + + assertThat(watcher.isPolling()).isTrue(); + } + + @Test + public void testRegister_fileDoesNotExist() throws IOException { + try { + watcher.register(fs.getPath("/a/b/c"), ImmutableList.of(ENTRY_CREATE)); + fail(); + } catch (NoSuchFileException expected) { + } + } + + @Test + public void testRegister_fileIsNotDirectory() throws IOException { + Path path = fs.getPath("/a.txt"); + Files.createFile(path); + try { + watcher.register(path, ImmutableList.of(ENTRY_CREATE)); + fail(); + } catch (NotDirectoryException expected) { + } + } + + @Test + public void testCancellingLastKeyStopsPolling() throws IOException { + Key key = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE)); + key.cancel(); + assertThat(key.isValid()).isFalse(); + + assertThat(watcher.isPolling()).isFalse(); + + Key key2 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE)); + Key key3 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_DELETE)); + + assertThat(watcher.isPolling()).isTrue(); + + key2.cancel(); + + assertThat(watcher.isPolling()).isTrue(); + + key3.cancel(); + + assertThat(watcher.isPolling()).isFalse(); + } + + @Test + public void testCloseCancelsAllKeysAndStopsPolling() throws IOException { + Key key1 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_CREATE)); + Key key2 = watcher.register(createDirectory(), ImmutableList.of(ENTRY_DELETE)); + + assertThat(key1.isValid()).isTrue(); + assertThat(key2.isValid()).isTrue(); + assertThat(watcher.isPolling()).isTrue(); + + watcher.close(); + + assertThat(key1.isValid()).isFalse(); + assertThat(key2.isValid()).isFalse(); + assertThat(watcher.isPolling()).isFalse(); + } + + @Test(timeout = 2000) + public void testWatchForOneEventType() throws IOException, InterruptedException { + JimfsPath path = createDirectory(); + watcher.register(path, ImmutableList.of(ENTRY_CREATE)); + + Files.createFile(path.resolve("foo")); + + assertWatcherHasEvents(new Event<>(ENTRY_CREATE, 1, fs.getPath("foo"))); + + Files.createFile(path.resolve("bar")); + Files.createFile(path.resolve("baz")); + + assertWatcherHasEvents( + new Event<>(ENTRY_CREATE, 1, fs.getPath("bar")), + new Event<>(ENTRY_CREATE, 1, fs.getPath("baz"))); + } + + @Test(timeout = 2000) + public void testWatchForMultipleEventTypes() throws IOException, InterruptedException { + JimfsPath path = createDirectory(); + watcher.register(path, ImmutableList.of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY)); + + Files.createDirectory(path.resolve("foo")); + Files.createFile(path.resolve("bar")); + + assertWatcherHasEvents( + new Event<>(ENTRY_CREATE, 1, fs.getPath("bar")), + new Event<>(ENTRY_CREATE, 1, fs.getPath("foo"))); + + Files.createFile(path.resolve("baz")); + Files.delete(path.resolve("bar")); + Files.createFile(path.resolve("foo/bar")); + + assertWatcherHasEvents( + new Event<>(ENTRY_CREATE, 1, fs.getPath("baz")), + new Event<>(ENTRY_DELETE, 1, fs.getPath("bar")), + new Event<>(ENTRY_MODIFY, 1, fs.getPath("foo"))); + + Files.delete(path.resolve("foo/bar")); + ensureTimeToPoll(); // watcher polls, seeing modification, then polls again, seeing delete + Files.delete(path.resolve("foo")); + + assertWatcherHasEvents( + new Event<>(ENTRY_MODIFY, 1, fs.getPath("foo")), + new Event<>(ENTRY_DELETE, 1, fs.getPath("foo"))); + + Files.createDirectories(path.resolve("foo/bar")); + + // polling here may either see just the creation of foo, or may first see the creation of foo + // and then the creation of foo/bar (modification of foo) since those don't happen atomically + assertWatcherHasEvents( + ImmutableList.<WatchEvent<?>>of(new Event<>(ENTRY_CREATE, 1, fs.getPath("foo"))), + // or + ImmutableList.<WatchEvent<?>>of( + new Event<>(ENTRY_CREATE, 1, fs.getPath("foo")), + new Event<>(ENTRY_MODIFY, 1, fs.getPath("foo")))); + + Files.delete(path.resolve("foo/bar")); + Files.delete(path.resolve("foo")); + + // polling here may either just see the deletion of foo, or may first see the deletion of bar + // (modification of foo) and then the deletion of foo + assertWatcherHasEvents( + ImmutableList.<WatchEvent<?>>of(new Event<>(ENTRY_DELETE, 1, fs.getPath("foo"))), + // or + ImmutableList.<WatchEvent<?>>of( + new Event<>(ENTRY_MODIFY, 1, fs.getPath("foo")), + new Event<>(ENTRY_DELETE, 1, fs.getPath("foo")))); + } + + private void assertWatcherHasEvents(WatchEvent<?>... events) throws InterruptedException { + assertWatcherHasEvents(Arrays.asList(events), ImmutableList.<WatchEvent<?>>of()); + } + + private void assertWatcherHasEvents(List<WatchEvent<?>> expected, List<WatchEvent<?>> alternate) + throws InterruptedException { + ensureTimeToPoll(); // otherwise we could read 1 event but not all the events we're expecting + WatchKey key = watcher.take(); + List<WatchEvent<?>> keyEvents = key.pollEvents(); + + if (keyEvents.size() == expected.size() || alternate.isEmpty()) { + assertThat(keyEvents).containsExactlyElementsIn(expected); + } else { + assertThat(keyEvents).containsExactlyElementsIn(alternate); + } + key.reset(); + } + + private static void ensureTimeToPoll() { + Uninterruptibles.sleepUninterruptibly(40, MILLISECONDS); + } + + private JimfsPath createDirectory() throws IOException { + JimfsPath path = fs.getPath("/" + UUID.randomUUID().toString()); + Files.createDirectory(path); + return path; + } +} |