Skip to content

Commit

Permalink
ZOOKEEPER-3219: Fix flaky FileChangeWatcherTest
Browse files Browse the repository at this point in the history
Made some changes to handle the random ENTRY_CREATE events that occasionally fire even though the watcher is created after the file is already written to disk. Should make the test more stable.

Author: Ilya Maykov <[email protected]>

Closes apache#739 from ivmaykov/ZOOKEEPER-3219
  • Loading branch information
ivmaykov authored and RokLenarcic committed Sep 3, 2022
1 parent ad33056 commit 189524e
Showing 1 changed file with 30 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class FileChangeWatcherTest extends ZKTestCase {
private static File tempDir;
Expand Down Expand Up @@ -70,6 +71,12 @@ public void testCallbackWorksOnFileChanges() throws IOException, InterruptedExce
tempDir.toPath(),
event -> {
LOG.info("Got an update: " + event.kind() + " " + event.context());
// Filter out the extra ENTRY_CREATE events that are
// sometimes seen at the start. Even though we create the watcher
// after the file exists, sometimes we still get a create event.
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
return;
}
synchronized (events) {
events.add(event);
events.notifyAll();
Expand Down Expand Up @@ -112,6 +119,12 @@ public void testCallbackWorksOnFileTouched() throws IOException, InterruptedExce
tempDir.toPath(),
event -> {
LOG.info("Got an update: " + event.kind() + " " + event.context());
// Filter out the extra ENTRY_CREATE events that are
// sometimes seen at the start. Even though we create the watcher
// after the file exists, sometimes we still get a create event.
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
return;
}
synchronized (events) {
events.add(event);
events.notifyAll();
Expand Down Expand Up @@ -184,6 +197,12 @@ public void testCallbackWorksOnFileDeleted() throws IOException, InterruptedExce
tempDir.toPath(),
event -> {
LOG.info("Got an update: " + event.kind() + " " + event.context());
// Filter out the extra ENTRY_CREATE events that are
// sometimes seen at the start. Even though we create the watcher
// after the file exists, sometimes we still get a create event.
if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
return;
}
synchronized (events) {
events.add(event);
events.notifyAll();
Expand Down Expand Up @@ -214,21 +233,18 @@ public void testCallbackWorksOnFileDeleted() throws IOException, InterruptedExce
public void testCallbackErrorDoesNotCrashWatcherThread() throws IOException, InterruptedException {
FileChangeWatcher watcher = null;
try {
final List<WatchEvent<?>> events = new ArrayList<>();
final AtomicInteger callCount = new AtomicInteger(0);
watcher = new FileChangeWatcher(
tempDir.toPath(),
event -> {
LOG.info("Got an update: " + event.kind() + " " + event.context());
int oldValue;
synchronized (callCount) {
if (callCount.getAndIncrement() == 0) {
callCount.notifyAll();
throw new RuntimeException("This error should not crash the watcher thread");
}
oldValue = callCount.getAndIncrement();
callCount.notifyAll();
}
synchronized (events) {
events.add(event);
events.notifyAll();
if (oldValue == 0) {
throw new RuntimeException("This error should not crash the watcher thread");
}
});
watcher.start();
Expand All @@ -243,16 +259,14 @@ public void testCallbackErrorDoesNotCrashWatcherThread() throws IOException, Int
}
LOG.info("Modifying file again");
FileUtils.writeStringToFile(tempFile, "Hello world again\n", StandardCharsets.UTF_8, true);
synchronized (events) {
if (events.isEmpty()) {
events.wait(3000L);
synchronized (callCount) {
if (callCount.get() == 1) {
callCount.wait(3000L);
}
assertEquals(2, callCount.get());
assertFalse(events.isEmpty());
WatchEvent<?> event = events.get(0);
assertEquals(StandardWatchEventKinds.ENTRY_MODIFY, event.kind());
assertEquals(tempFile.getName(), event.context().toString());
}
// The value of callCount can exceed 1 only if the callback thread
// survives the exception thrown by the first callback.
assertTrue(callCount.get() > 1);
} finally {
if (watcher != null) {
watcher.stop();
Expand Down

0 comments on commit 189524e

Please sign in to comment.