diff --git a/crates/engine/tests/panic_hunt.rs b/crates/engine/tests/panic_hunt.rs index 893ba5c23d..91f42be306 100644 --- a/crates/engine/tests/panic_hunt.rs +++ b/crates/engine/tests/panic_hunt.rs @@ -30,9 +30,14 @@ static PANICS: AtomicUsize = AtomicUsize::new(0); /// One run at a time, so a panic is charged to the run that caused it. static RUN: Mutex<()> = Mutex::new(()); -/// Run `f` on a worker thread. `None` if it timed out, else whether it finished without -/// panicking, contained or not (returning Ok or a graceful Err both count). -fn run_watched(f: impl FnOnce() + Send + 'static) -> Option { +/// Budget for the self-test below, which checks how panics are counted, not hangs. The panic hook +/// prints a backtrace under `RUST_BACKTRACE=1` (as in CI), and on a loaded Windows runner the +/// first symbol lookup alone can take 15–20 s. +const SELF_TEST_DEADLINE: Duration = Duration::from_secs(120); + +/// Run `f` on a worker thread. `None` if it took longer than `deadline`, else whether it +/// finished without panicking, contained or not (returning Ok or a graceful Err both count). +fn run_watched(deadline: Duration, f: impl FnOnce() + Send + 'static) -> Option { static HOOK: Once = Once::new(); HOOK.call_once(|| { let default = std::panic::take_hook(); @@ -48,13 +53,13 @@ fn run_watched(f: impl FnOnce() + Send + 'static) -> Option { let r = catch_unwind(AssertUnwindSafe(f)); let _ = tx.send(r.is_ok()); }); - rx.recv_timeout(DEADLINE).ok().map(|ok| ok && PANICS.load(Ordering::SeqCst) == before) + rx.recv_timeout(deadline).ok().map(|ok| ok && PANICS.load(Ordering::SeqCst) == before) } /// Run `id` with `p` on a fresh session; see [`run_watched`]. fn run_once(id: &str, p: &Value) -> Option { let (id, p) = (id.to_string(), p.clone()); - run_watched(move || { + run_watched(DEADLINE, move || { let mut s = fresh(); let _ = s.execute(&id, p); }) @@ -107,11 +112,11 @@ fn no_command_panics_or_hangs_on_adversarial_params() { /// #4982: a panic the code under test contains still fails the run; a graceful `Err` does not. #[test] fn contained_panics_count_and_graceful_errors_do_not() { - let contained = run_watched(|| { + let contained = run_watched(SELF_TEST_DEADLINE, || { let _ = catch_unwind(|| panic!("contained, as Session::execute does")); }); assert_eq!(contained, Some(false)); - let graceful = run_watched(|| { + let graceful = run_watched(SELF_TEST_DEADLINE, || { let mut s = fresh(); assert!(s.execute("layer.delete", json!({"layer": 999999})).is_err()); });