Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,20 @@ public void closePreventsFutureCallbacks() throws InterruptedException {
}

@Test
public void closeCancelsPendingTimer() throws InterruptedException {
public void closeCancelsPendingTimer() {
// Manually-driven executor for the same reason as resetCancelsPendingTimer: the pre-close
// sleep can overshoot the debounce window on a loaded runner, letting the timer fire before
// close() has a chance to cancel it.
AtomicInteger callCount = new AtomicInteger(0);
StateDebounceManager mgr = createManager(true, true, callCount::incrementAndGet);
ManualTaskExecutor manualExecutor = new ManualTaskExecutor();
StateDebounceManager mgr = new StateDebounceManager(
true, true, manualExecutor, TEST_DEBOUNCE_MS, callCount::incrementAndGet);

mgr.setNetworkAvailable(false);
Thread.sleep(TEST_DEBOUNCE_MS / 3);
mgr.close();
assertEquals("close should cancel the scheduled timer", 1, manualExecutor.cancelledCount());

Thread.sleep(TEST_DEBOUNCE_MS * 3);
manualExecutor.runPendingTasks();
assertEquals("pending timer should be cancelled on close", 0, callCount.get());
}

Expand Down Expand Up @@ -341,15 +346,23 @@ public void dedupAllowsGenuineChangeAfterSuppression() throws InterruptedExcepti
// ==== reset() (CONNMODE 3.5.6 — identify bypasses debounce) ====

@Test
public void resetCancelsPendingTimer() throws InterruptedException {
public void resetCancelsPendingTimer() {
// Uses a manually-driven executor instead of Thread.sleep so the test is deterministic:
// the short pre-reset sleep can overshoot the debounce window on a loaded runner, and once
// the timer has begun firing reset() cannot recall it -- reset() re-seeds the baseline
// under taskLock while fireIfChanged() reads it under workLock, an interleaving the
// implementation documents as harmless but which this assertion cannot tolerate.
AtomicInteger callCount = new AtomicInteger(0);
StateDebounceManager mgr = createManager(true, true, callCount::incrementAndGet);
ManualTaskExecutor manualExecutor = new ManualTaskExecutor();
StateDebounceManager mgr = new StateDebounceManager(
true, true, manualExecutor, TEST_DEBOUNCE_MS, callCount::incrementAndGet);

mgr.setNetworkAvailable(false);
Thread.sleep(TEST_DEBOUNCE_MS / 3);
mgr.reset(true, true);
assertEquals("reset should cancel the scheduled timer", 1, manualExecutor.cancelledCount());

Thread.sleep(TEST_DEBOUNCE_MS * 3);
// Draining the queue runs nothing, because the only scheduled task was cancelled.
manualExecutor.runPendingTasks();
assertEquals("reset should cancel the pending timer", 0, callCount.get());

mgr.close();
Expand Down
Loading