Skip to content

Commit 24df6c4

Browse files
Prithvi-Webclaude
andcommitted
fix(test): the paused-walk cancel test holds the walk before it can finish, instead of racing it
live::cancel_returns_within_200ms_on_five_thousand_entries (tm-walk tests/walk.rs, Phase 3) started a real walk of 5,050 entries, then paused it and cancelled 30 ms later. A pause only takes hold at a worker's next check, so a test thread descheduled between start() and pause() let the whole walk finish first: "the walk completed (5050 entries) before the cancel landed", seen once by T6b's agent under load (26 Sep 2026). The test raced the clock. Now the governor is paused before the walk starts, so each worker completes at most the one folder it holds and parks in throttle() — the 51 folders cannot finish. The walk is then paused, the governor released, and the test waits (counted, not timed) until a worker is parked in the walk's pause before cancelling; take() runs behind a hang guard, so a cancel that never reaches the paused walk fails instead of hanging. Proved on a scratch copy: the old test with 300 ms between start() and pause() goes red with the very message seen; the new test with the same delay stays green; the new test goes red ("take() did not return within 10s") when a cancel no longer wakes the walk's pause. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent d26c9e4 commit 24df6c4

1 file changed

Lines changed: 34 additions & 10 deletions

File tree

  • native/treemap-core/crates/tm-walk/tests

‎native/treemap-core/crates/tm-walk/tests/walk.rs‎

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,7 +1628,9 @@ mod live {
16281628
WalkOptions, probe, start,
16291629
};
16301630

1631-
use super::{REACT_WITHIN, TestResult, index_by_path, node, rel_paths, wait_done};
1631+
use super::{
1632+
REACT_WITHIN, SETTLE, TestResult, index_by_path, node, rel_paths, wait_done, wait_until,
1633+
};
16321634

16331635
const A_BYTES: usize = 1_234;
16341636
const B_BYTES: usize = 4_096;
@@ -2039,22 +2041,44 @@ mod live {
20392041
#[test]
20402042
fn cancel_returns_within_200ms_on_five_thousand_entries() -> TestResult {
20412043
let fx = five_thousand("cancel")?;
2042-
let handle = start(WalkOptions::new(&fx.root), governor()).map_err(|e| e.to_string())?;
2043-
// Hold the workers so the cancel has something to interrupt.
2044+
// Hold the workers so the cancel has something to interrupt — and so the
2045+
// walk cannot finish first, however late this thread runs: with the
2046+
// governor paused a worker completes at most the one folder it holds,
2047+
// then parks in `throttle()`, and 51 folders need more than the workers.
2048+
// (Pausing the walk after `start` raced it: a descheduled test thread let
2049+
// all 5,050 entries finish before the pause landed.)
2050+
let gov = governor();
2051+
gov.pause();
2052+
let handle =
2053+
start(WalkOptions::new(&fx.root), Arc::clone(&gov)).map_err(|e| e.to_string())?;
20442054
handle.pause();
2045-
thread::sleep(Duration::from_millis(30));
2055+
gov.resume();
2056+
// A worker let out of `throttle()` takes its next folder and parks in the
2057+
// walk's pause: counted, not timed.
2058+
if !wait_until(SETTLE, || handle.counts().paused_workers > 0) {
2059+
return Err("no worker parked in the walk's pause".to_owned());
2060+
}
20462061
let asked = Instant::now();
20472062
handle.cancel();
2048-
let result = handle.take();
2063+
let (tx, rx) = std::sync::mpsc::channel();
2064+
thread::spawn(move || {
2065+
let _ = tx.send(handle.take());
2066+
});
2067+
let outcome = rx.recv_timeout(SETTLE);
20492068
let took = asked.elapsed();
2050-
assert!(took <= REACT_WITHIN, "cancel took {took:?}");
2051-
match result {
2052-
Err(WalkError::Cancelled) => Ok(()),
2053-
Ok(out) => Err(format!(
2069+
match outcome {
2070+
Ok(Err(WalkError::Cancelled)) => {
2071+
assert!(took <= REACT_WITHIN, "cancel took {took:?}");
2072+
Ok(())
2073+
}
2074+
Ok(Ok(out)) => Err(format!(
20542075
"the walk completed ({} entries) before the cancel landed",
20552076
out.stats.entries
20562077
)),
2057-
Err(other) => Err(format!("expected Cancelled, got {other:?}")),
2078+
Ok(Err(other)) => Err(format!("expected Cancelled, got {other:?}")),
2079+
Err(_) => Err(format!(
2080+
"take() did not return within {SETTLE:?}: the cancel never reached the paused walk"
2081+
)),
20582082
}
20592083
}
20602084

0 commit comments

Comments
 (0)