fix ci: gate harness_dir-dependent tests behind a dummy env var
This commit is contained in:
parent
7ba492b965
commit
22f8805a77
2 changed files with 98 additions and 27 deletions
|
|
@ -289,6 +289,36 @@ pub async fn serve_http(addr: std::net::SocketAddr) -> anyhow::Result<()> {
|
|||
mod status_hint_tests {
|
||||
use super::{BASH_IDLE_WAIT_HINT, format_task};
|
||||
use crate::protocol::{TaskFile, TaskStatus};
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// `format_task` unconditionally resolves `crate::paths::task_out`/
|
||||
/// `task_err` (to check captured-output length), which panics if
|
||||
/// `HYPERHIVE_HARNESS_DIR` is unset — exactly cargo's sandboxed test
|
||||
/// environment. Same helper shape as `runner::tests::with_harness_dir`
|
||||
/// (module-scope mutex to serialise against parallel test threads
|
||||
/// mutating the process-wide env var, save/restore on the way out);
|
||||
/// duplicated rather than shared because the two test modules live in
|
||||
/// separate files with no existing shared test-util module.
|
||||
static HARNESS_DIR_ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn task(status: TaskStatus) -> TaskFile {
|
||||
TaskFile {
|
||||
|
|
@ -307,16 +337,20 @@ mod status_hint_tests {
|
|||
|
||||
#[test]
|
||||
fn running_task_after_wait_appends_idle_hint() {
|
||||
let t = task(TaskStatus::Running);
|
||||
let mut out = format_task(&t);
|
||||
out.push_str(BASH_IDLE_WAIT_HINT);
|
||||
assert!(out.contains(BASH_IDLE_WAIT_HINT));
|
||||
with_harness_dir(|| {
|
||||
let t = task(TaskStatus::Running);
|
||||
let mut out = format_task(&t);
|
||||
out.push_str(BASH_IDLE_WAIT_HINT);
|
||||
assert!(out.contains(BASH_IDLE_WAIT_HINT));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn done_task_formats_without_hint() {
|
||||
let out = format_task(&task(TaskStatus::Done));
|
||||
assert!(!out.contains(BASH_IDLE_WAIT_HINT));
|
||||
assert!(out.contains("status=done"));
|
||||
with_harness_dir(|| {
|
||||
let out = format_task(&task(TaskStatus::Done));
|
||||
assert!(!out.contains(BASH_IDLE_WAIT_HINT));
|
||||
assert!(out.contains("status=done"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -797,6 +797,37 @@ fn done_summary(id: &str, summary: &str, output: Option<(bool, bool)>) -> String
|
|||
mod tests {
|
||||
use super::validate_task_name;
|
||||
use hive_types::Ident;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// `done_summary`'s stderr/stdout-pointer tests format real paths via
|
||||
/// `crate::paths::task_out`/`task_err`, which resolve through
|
||||
/// `hive_agent_sock::paths::harness_dir` — that panics if
|
||||
/// `HYPERHIVE_HARNESS_DIR` is unset (see its doc comment), which is
|
||||
/// exactly cargo's sandboxed test environment (no real container, no
|
||||
/// meta-flake-injected env). Set a dummy value for the duration of
|
||||
/// those tests, serialised on a module mutex so parallel test threads
|
||||
/// don't race the process-wide env var, and restore whatever was there
|
||||
/// before on the way out.
|
||||
static HARNESS_DIR_ENV_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_ident_names() {
|
||||
|
|
@ -881,35 +912,41 @@ mod tests {
|
|||
#[test]
|
||||
fn done_summary_stdout_only_is_unflagged() {
|
||||
use super::done_summary;
|
||||
let body = done_summary("t1", "exit=0", Some((true, false)));
|
||||
assert!(body.contains("output captured — read the full text with:"));
|
||||
assert!(body.contains("Read("));
|
||||
assert!(body.contains(".out"));
|
||||
assert!(!body.contains(".err"));
|
||||
assert!(!body.contains('\u{26a0}'), "no flag without stderr");
|
||||
with_harness_dir(|| {
|
||||
let body = done_summary("t1", "exit=0", Some((true, false)));
|
||||
assert!(body.contains("output captured — read the full text with:"));
|
||||
assert!(body.contains("Read("));
|
||||
assert!(body.contains(".out"));
|
||||
assert!(!body.contains(".err"));
|
||||
assert!(!body.contains('\u{26a0}'), "no flag without stderr");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn done_summary_stderr_present_is_flagged_regardless_of_summary_text() {
|
||||
use super::done_summary;
|
||||
// exit=0 in the summary — a swallowed mid-chain failure that
|
||||
// still exits clean. The flag must fire anyway, keyed on
|
||||
// has_stderr, not on the summary text.
|
||||
let body = done_summary("t1", "exit=0", Some((true, true)));
|
||||
assert!(
|
||||
body.contains("⚠️ stderr present"),
|
||||
"stderr present must flag even on a clean exit code"
|
||||
);
|
||||
let err_pos = body.find(".err").expect("err pointer present");
|
||||
let out_pos = body.find(".out").expect("out pointer present");
|
||||
assert!(err_pos < out_pos, ".err must be listed before .out");
|
||||
with_harness_dir(|| {
|
||||
// exit=0 in the summary — a swallowed mid-chain failure that
|
||||
// still exits clean. The flag must fire anyway, keyed on
|
||||
// has_stderr, not on the summary text.
|
||||
let body = done_summary("t1", "exit=0", Some((true, true)));
|
||||
assert!(
|
||||
body.contains("⚠️ stderr present"),
|
||||
"stderr present must flag even on a clean exit code"
|
||||
);
|
||||
let err_pos = body.find(".err").expect("err pointer present");
|
||||
let out_pos = body.find(".out").expect("out pointer present");
|
||||
assert!(err_pos < out_pos, ".err must be listed before .out");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn done_summary_stderr_only_omits_out_pointer() {
|
||||
use super::done_summary;
|
||||
let body = done_summary("t1", "exit=1", Some((false, true)));
|
||||
assert!(body.contains(".err"));
|
||||
assert!(!body.contains(".out"), "no stdout ⇒ no stdout pointer");
|
||||
with_harness_dir(|| {
|
||||
let body = done_summary("t1", "exit=1", Some((false, true)));
|
||||
assert!(body.contains(".err"));
|
||||
assert!(!body.contains(".out"), "no stdout ⇒ no stdout pointer");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue