Skip to content

Commit e7e2d3f

Browse files
committed
Improve error checks when we start a watch
1 parent e4e29a0 commit e7e2d3f

File tree

2 files changed

+39
-27
lines changed

2 files changed

+39
-27
lines changed

src/main/java/engineering/swat/watch/Watch.java

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@
2626
*/
2727
package engineering.swat.watch;
2828

29+
import java.io.FileNotFoundException;
2930
import java.io.IOException;
31+
import java.nio.file.FileSystemException;
3032
import java.nio.file.Files;
33+
import java.nio.file.InvalidPathException;
3134
import java.nio.file.LinkOption;
35+
import java.nio.file.NoSuchFileException;
36+
import java.nio.file.NotDirectoryException;
3237
import java.nio.file.Path;
3338
import java.util.concurrent.Executor;
3439
import java.util.function.BiConsumer;
@@ -76,28 +81,13 @@ private Watch(Path path, WatchScope scope) {
7681
* Watch a path for updates, optionally also get events for its children/descendants
7782
* @param path which absolute path to monitor, can be a file or a directory, but has to be absolute
7883
* @param scope for directories you can also choose to monitor it's direct children or all it's descendants
79-
* @throws IllegalArgumentException in case a path is not supported (in relation to the scope)
84+
* @throws IllegalArgumentException in case a path is not supported
8085
* @return watch builder that can be further configured and then started
8186
*/
8287
public static Watch build(Path path, WatchScope scope) {
8388
if (!path.isAbsolute()) {
8489
throw new IllegalArgumentException("We can only watch absolute paths");
8590
}
86-
switch (scope) {
87-
case PATH_AND_CHILDREN: // intended fallthrough
88-
case PATH_AND_ALL_DESCENDANTS:
89-
if (!Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) {
90-
throw new IllegalArgumentException("Only directories are supported for this scope: " + scope);
91-
}
92-
break;
93-
case PATH_ONLY:
94-
if (Files.isSymbolicLink(path)) {
95-
throw new IllegalArgumentException("Symlinks are not supported");
96-
}
97-
break;
98-
default:
99-
throw new IllegalArgumentException("Unsupported scope: " + scope);
100-
}
10191
return new Watch(path, scope);
10292
}
10393

@@ -192,16 +182,38 @@ public Watch onOverflow(Approximation whichFiles) {
192182
return this;
193183
}
194184

185+
private void validateOptions() throws IOException {
186+
if (this.eventHandler == EMPTY_HANDLER) {
187+
throw new IllegalStateException("There is no onEvent handler defined");
188+
}
189+
if (!Files.exists(path)) {
190+
throw new FileSystemException(path.toString(), null, "Cannot open a watch on a non-existing path");
191+
}
192+
switch (scope) {
193+
case PATH_AND_CHILDREN: // intended fallthrough
194+
case PATH_AND_ALL_DESCENDANTS:
195+
if (!Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) {
196+
throw new FileSystemException(path.toString(), null, "Only directories are supported for this scope: " + scope);
197+
}
198+
break;
199+
case PATH_ONLY:
200+
if (Files.isSymbolicLink(path)) {
201+
throw new FileSystemException(path.toString(), null, "Symlinks are not supported");
202+
}
203+
break;
204+
default:
205+
throw new IllegalArgumentException("Unsupported scope: " + scope);
206+
}
207+
}
208+
195209
/**
196210
* Start watch the path for events.
197211
* @return a subscription for the watch, when closed, new events will stop being registered to the worker pool.
198-
* @throws IOException in case the starting of the watcher caused an underlying IO exception
212+
* @throws IOException in case the starting of the watcher caused an underlying IO exception or we detect it is an invalid watch
199213
* @throws IllegalStateException the watchers is not configured correctly (for example, missing {@link #on(Consumer)}, or a watcher is started twice)
200214
*/
201215
public ActiveWatch start() throws IOException {
202-
if (this.eventHandler == EMPTY_HANDLER) {
203-
throw new IllegalStateException("There is no onEvent handler defined");
204-
}
216+
validateOptions();
205217
var executor = this.executor;
206218
if (executor == null) {
207219
executor = FALLBACK_EXECUTOR;

src/test/java/engineering/swat/watch/APIErrorsTests.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
3030

3131
import java.io.IOException;
32+
import java.nio.file.FileSystemException;
3233
import java.nio.file.Files;
3334

3435
import org.awaitility.Awaitility;
@@ -70,9 +71,11 @@ void noDuplicateEvents() {
7071

7172
@Test
7273
void onlyDirectoryWatchingOnDirectories() {
73-
assertThrowsExactly(IllegalArgumentException.class, () ->
74+
assertThrowsExactly(FileSystemException.class, () ->
7475
Watch
7576
.build(testDir.getTestFiles().get(0), WatchScope.PATH_AND_CHILDREN)
77+
.on(e -> {})
78+
.start()
7679
);
7780
}
7881

@@ -92,17 +95,14 @@ void noRelativePaths() {
9295
assertThrowsExactly(IllegalArgumentException.class, () ->
9396
Watch
9497
.build(relativePath, WatchScope.PATH_AND_CHILDREN)
95-
.start()
9698
);
9799
}
98100

99101
@Test
100102
void nonExistingDirectory() throws IOException {
101-
var nonExistingDir = testDir.getTestDirectory().resolve("testd1");
102-
Files.createDirectory(nonExistingDir);
103-
var w = Watch.build(nonExistingDir, WatchScope.PATH_AND_CHILDREN);
104-
Files.delete(nonExistingDir);
105-
assertThrowsExactly(IllegalStateException.class, w::start);
103+
var nonExistingDir = testDir.getTestDirectory().resolve("test-not-existing");
104+
var w = Watch.build(nonExistingDir, WatchScope.PATH_AND_CHILDREN).on(e -> {});
105+
assertThrowsExactly(FileSystemException.class, w::start);
106106
}
107107

108108

0 commit comments

Comments
 (0)