50 lines
2.5 KiB
Rust
50 lines
2.5 KiB
Rust
//! Test-only helper shared by `mcp::status_hint_tests` and `runner::tests`.
|
|
//!
|
|
//! Both modules need `HYPERHIVE_HARNESS_DIR` set for the duration of a test
|
|
//! (`crate::paths::harness_dir` panics if it's unset — deliberately, see
|
|
//! its doc comment — and that's exactly cargo's sandboxed test env with no
|
|
//! meta-flake-injected value). The env var is one process-global, and both
|
|
//! modules land in the *same* test binary (same crate) with tests running
|
|
//! on parallel threads, so a single shared lock here is required — two
|
|
//! separate per-module mutexes serialise nothing against each other — that
|
|
//! caused a CI-only flake, since a container always has the var set so a
|
|
//! losing race still finds a valid restored value, while the nix sandbox
|
|
//! strips it, so a racing thread can delete the var out from under another
|
|
//! mid-test.
|
|
//!
|
|
//! ⚠️ **This asymmetry also breaks local reproduction**: a plain `cargo
|
|
//! test` inside an agent container can never fail this test, fixed or
|
|
//! broken — `HYPERHIVE_HARNESS_DIR` is always ambient-set there, so the
|
|
//! restore branch always takes `set_var`, never `remove_var`. To actually
|
|
//! exercise the sandbox shape (and prove a fix works, or reproduce the
|
|
//! original bug), unset the var first: `env -u HYPERHIVE_HARNESS_DIR
|
|
//! cargo test -p hive-bash-mcp`. Any *new* helper that reaches for the env
|
|
//! var in a test should route through `with_harness_dir` below rather than
|
|
//! rolling its own save/restore — a second lock reintroduces exactly this
|
|
//! bug.
|
|
use std::sync::Mutex;
|
|
|
|
static HARNESS_DIR_ENV_LOCK: Mutex<()> = Mutex::new(());
|
|
|
|
/// Run `f` with `HYPERHIVE_HARNESS_DIR` set to a dummy path, serialised
|
|
/// against every other caller of this helper in the process so parallel
|
|
/// test threads can't race the env var out from under each other.
|
|
/// Restores whatever value (or absence) was there before on the way out.
|
|
pub fn with_harness_dir<F: FnOnce()>(f: F) {
|
|
let _guard = HARNESS_DIR_ENV_LOCK
|
|
.lock()
|
|
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
|
let prev = std::env::var("HYPERHIVE_HARNESS_DIR").ok();
|
|
// SAFETY: serialised by HARNESS_DIR_ENV_LOCK above; restored below in
|
|
// the same scope before the guard drops.
|
|
unsafe {
|
|
std::env::set_var("HYPERHIVE_HARNESS_DIR", "/tmp/hive-bash-mcp-test-harness");
|
|
}
|
|
f();
|
|
unsafe {
|
|
match prev {
|
|
Some(v) => std::env::set_var("HYPERHIVE_HARNESS_DIR", v),
|
|
None => std::env::remove_var("HYPERHIVE_HARNESS_DIR"),
|
|
}
|
|
}
|
|
}
|