Test & fix for FileWatcher

- Test for modification listening
- Fix for Path resolution when calling a WatchedFile
This commit is contained in:
Rsl1122 2018-12-24 22:43:46 +02:00
parent 88f8653cb8
commit 3bdb85312c
3 changed files with 89 additions and 15 deletions

View File

@ -42,22 +42,25 @@ public class FileWatcher extends Thread {
private Path watchedPath;
private Set<WatchedFile> watchedFiles;
public FileWatcher(File folder, ErrorHandler errorHandler) {
this(folder, errorHandler, new HashSet<>());
public FileWatcher(
File folder,
ErrorHandler errorHandler
) {
this(folder.toPath(), errorHandler);
}
public FileWatcher(
File folder,
ErrorHandler errorHandler,
Set<WatchedFile> watchedFiles
Path watchedPath,
ErrorHandler errorHandler
) {
this.errorHandler = errorHandler;
this.running = false;
this.watchedFiles = watchedFiles;
this.watchedFiles = new HashSet<>();
Verify.isTrue(folder.isDirectory(), () -> new IllegalArgumentException("Given File " + folder.getAbsolutePath() + " was not a folder."));
watchedPath = folder.toPath();
Verify.isTrue(watchedPath.toFile().isDirectory(), () -> new IllegalArgumentException("Given File " + watchedPath.toString() + " was not a folder."));
this.watchedPath = watchedPath;
}
public void addToWatchlist(WatchedFile watchedFile) {
@ -73,6 +76,7 @@ public class FileWatcher extends Thread {
runLoop(watcher);
} catch (IOException e) {
errorHandler.log(L.ERROR, this.getClass(), e);
interrupt();
} catch (InterruptedException e) {
interrupt();
}
@ -107,7 +111,7 @@ public class FileWatcher extends Thread {
} else {
@SuppressWarnings("unchecked")
Path modifiedFile = ((WatchEvent<Path>) event).context();
actOnModification(modifiedFile);
actOnModification(watchedPath.resolve(modifiedFile));
}
}
@ -122,4 +126,8 @@ public class FileWatcher extends Thread {
running = false;
super.interrupt();
}
public boolean isRunning() {
return running;
}
}

View File

@ -23,22 +23,26 @@ import java.nio.file.Path;
import java.util.Objects;
/**
* File with a consumer that is called if the file is modified.
* File or Path with a function that is called if the file is modified.
*
* @author Rsl1122
*/
public class WatchedFile {
private final File file;
private final Path watchedPath;
private final VoidFunction onChange;
public WatchedFile(File file, VoidFunction onChange) {
this.file = file;
this(file.toPath(), onChange);
}
public WatchedFile(Path path, VoidFunction onChange) {
this.watchedPath = path;
this.onChange = onChange;
}
public void modified(Path modifiedPath) {
if (modifiedPath != null && file.toPath().equals(modifiedPath)) {
if (watchedPath.equals(modifiedPath)) {
onChange.apply();
}
}
@ -48,11 +52,11 @@ public class WatchedFile {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WatchedFile that = (WatchedFile) o;
return Objects.equals(file, that.file);
return Objects.equals(watchedPath, that.watchedPath);
}
@Override
public int hashCode() {
return Objects.hash(file);
return Objects.hash(watchedPath);
}
}

View File

@ -0,0 +1,62 @@
package com.djrapitops.plan.utilities.file;
import com.jayway.awaitility.Awaitility;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.junitpioneer.jupiter.TempDirectory;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(JUnitPlatform.class)
@ExtendWith(TempDirectory.class)
class FileWatcherTest {
private Path temporaryDir;
@BeforeEach
void setUpTemporaryDir(@TempDirectory.TempDir Path dir) {
temporaryDir = dir;
}
@Test
void fileWatcherCallsWatchedFile() throws IOException {
FileWatcher underTest = new FileWatcher(temporaryDir, null);
File modified = temporaryDir.resolve("modifiedFile").toFile();
AtomicBoolean methodWasCalled = new AtomicBoolean(false);
WatchedFile watchedFile = new WatchedFile(modified, () -> methodWasCalled.set(true));
underTest.addToWatchlist(watchedFile);
try {
underTest.start();
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.until(underTest::isRunning);
// Modification should trigger a watch event here.
createAndModifyFile(modified);
Awaitility.await()
.atMost(1, TimeUnit.SECONDS)
.until(methodWasCalled::get);
} finally {
underTest.interrupt();
}
}
private void createAndModifyFile(File modified) throws IOException {
modified.createNewFile();
Files.write(modified.toPath(), Collections.singletonList("DataToWrite"), StandardCharsets.UTF_8);
Files.write(modified.toPath(), Collections.singletonList("OverWrite"), StandardCharsets.UTF_8);
}
}