fi.jumi.core.ipc.dirs.DirectoryObserverTest.java Source code

Java tutorial

Introduction

Here is the source code for fi.jumi.core.ipc.dirs.DirectoryObserverTest.java

Source

// Copyright  2011-2014, Esko Luontola <www.orfjackal.net>
// This software is released under the Apache License 2.0.
// The license text is at http://www.apache.org/licenses/LICENSE-2.0

package fi.jumi.core.ipc.dirs;

import fi.jumi.core.Timeouts;
import fi.jumi.core.ipc.*;
import fi.jumi.core.util.TestingExecutor;
import org.apache.commons.io.FileUtils;
import org.hamcrest.Matcher;
import org.junit.*;
import org.junit.rules.*;

import java.io.IOException;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;

import static java.nio.file.StandardWatchEventKinds.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;

public class DirectoryObserverTest {

    @Rule
    public final TemporaryFolder tempDir = new TemporaryFolder();

    @Rule
    public final Timeout timeout = Timeouts.forUnitTest();

    @Rule
    public final TestingExecutor executor = new TestingExecutor();

    @Rule
    public final ExpectedException thrown = ExpectedException.none();

    private final BlockingQueue<Path> noticedFiles = new LinkedBlockingQueue<>();
    private Path directory;
    private DirectoryObserver observer;
    private Future<?> observerFuture;

    @Before
    public void setup() {
        directory = tempDir.getRoot().toPath();
        observer = new DirectoryObserver(directory, noticedFiles::add);
    }

    @Test
    public void notices_all_existing_files() throws Exception {
        tempDir.newFile("existing1");
        tempDir.newFile("existing2");

        startObserverAsynchronously();

        assertThat(takeAtLeast(2, noticedFiles), containsFiles("existing1", "existing2"));
    }

    @Test
    public void notices_new_files_as_they_are_created() throws Exception {
        startObserver();

        tempDir.newFile("created1");
        tempDir.newFile("created2");

        assertThat(takeAtLeast(2, noticedFiles), containsFiles("created1", "created2"));
    }

    @Test
    public void notices_new_files_even_when_the_notification_event_is_missed_due_to_an_overflow() throws Exception {
        FakeWatchService watchService = new FakeWatchService();
        observer = new DirectoryObserver(directory, noticedFiles::add) {
            @Override
            protected WatchService watchDirectory(Path directory, WatchEvent.Kind<?>... events) {
                return watchService;
            }
        };
        startObserver();
        tempDir.newFile("created1");
        tempDir.newFile("created2");

        watchService.publish(new FakeWatchKey().addEvent(ENTRY_CREATE, Paths.get("created1")).addEvent(OVERFLOW));

        assertThat(takeAtLeast(2, noticedFiles), containsFiles("created1", "created2"));
    }

    @Test
    public void stops_if_the_directory_becomes_inaccessible() throws Exception {
        startObserver();

        FileUtils.deleteDirectory(directory.toFile());

        observerFuture.get(); // should not timeout
    }

    @Test
    public void requires_the_directory_to_exist_before_observing_it() {
        Path noSuchDirectory = directory.resolve("no-such-directory");

        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Does not exist: " + noSuchDirectory);
        new DirectoryObserver(noSuchDirectory, noticedFiles::add);
    }

    @Test
    public void requires_the_path_to_be_a_directory() throws IOException {
        Path regularFile = tempDir.newFile("regular-file").toPath();

        thrown.expect(IllegalArgumentException.class);
        thrown.expectMessage("Not a directory: " + regularFile);
        new DirectoryObserver(regularFile, noticedFiles::add);
    }

    // helpers

    private void startObserver() throws Exception {
        tempDir.newFile("existing");
        startObserverAsynchronously();
        takeAtLeast(1, noticedFiles); // wait for observer to start, skip existing files
    }

    private void startObserverAsynchronously() {
        observerFuture = executor.submit(observer);
    }

    private static List<Path> takeAtLeast(int count, BlockingQueue<Path> src) throws InterruptedException {
        List<Path> taken = new ArrayList<>();
        for (int i = 0; i < count; i++) {
            taken.add(src.take());
        }
        Path p;
        while ((p = src.poll()) != null) {
            taken.add(p);
        }
        return taken;
    }

    private Matcher<Iterable<? extends Path>> containsFiles(String... filenames) {
        Path[] expected = new Path[filenames.length];
        for (int i = 0; i < filenames.length; i++) {
            expected[i] = directory.resolve(filenames[i]);
        }
        return containsInAnyOrder(expected);
    }
}