test(panic_hunt): give the panic-counting self-test its own deadline (#8473)

contained_panics_count_and_graceful_errors_do_not used the 4 s hang
budget meant for fuzzed commands. With RUST_BACKTRACE=1 the panic hook
prints a backtrace, and on loaded Windows runners the first symbol
lookup took long enough (19.6 s) that run_watched returned None instead
of Some(false). The self-test now waits up to 120 s; the fuzz keeps 4 s.
This commit is contained in:
Zuujis
2026-10-23 17:40:32 -04:00
committed by GitHub
parent 03dd76022b
commit 4bda8d7388
+12 -7
View File
@@ -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<bool> {
/// 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<bool> {
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<bool> {
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<bool> {
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());
});