From 44b0d7c0388f20ca756ba155577fef597500e1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=80=A7=E9=A9=8A?= Date: Sun, 13 Sep 2026 16:54:48 +0800 Subject: [PATCH] test: serialize CONFIRM/HANDOFF env mutations across crates Avoid parallel cargo test flakes when multiple tests set process env. --- crates/grokboy-core/src/browser.rs | 1 + crates/grokboy-core/src/confirm.rs | 3 +++ crates/grokboy-core/src/lib.rs | 14 ++++++++++++++ crates/grokboy-core/src/tools.rs | 2 ++ 4 files changed, 20 insertions(+) diff --git a/crates/grokboy-core/src/browser.rs b/crates/grokboy-core/src/browser.rs index dcb8812..5574b0d 100644 --- a/crates/grokboy-core/src/browser.rs +++ b/crates/grokboy-core/src/browser.rs @@ -743,6 +743,7 @@ mod tests { #[test] fn handoff_auto_resume_and_abort() { + let _env_lock = crate::test_env::lock(); // SAFETY: tests run serially for this env in practice; restore after. let prev = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); unsafe { std::env::set_var("GROKBOY_HANDOFF_AUTO", "1") }; diff --git a/crates/grokboy-core/src/confirm.rs b/crates/grokboy-core/src/confirm.rs index 8d8127d..fc14713 100644 --- a/crates/grokboy-core/src/confirm.rs +++ b/crates/grokboy-core/src/confirm.rs @@ -267,6 +267,7 @@ mod tests { #[test] fn confirm_auto_approve_via_confirm_env() { + let _env_lock = crate::test_env::lock(); let prev_c = std::env::var("GROKBOY_CONFIRM_AUTO").ok(); let prev_h = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); unsafe { @@ -288,6 +289,7 @@ mod tests { #[test] fn confirm_auto_falls_back_to_handoff_env() { + let _env_lock = crate::test_env::lock(); let prev_c = std::env::var("GROKBOY_CONFIRM_AUTO").ok(); let prev_h = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); unsafe { @@ -308,6 +310,7 @@ mod tests { #[test] fn execute_approve_and_deny_offline() { + let _env_lock = crate::test_env::lock(); let prev_c = std::env::var("GROKBOY_CONFIRM_AUTO").ok(); let prev_h = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); unsafe { diff --git a/crates/grokboy-core/src/lib.rs b/crates/grokboy-core/src/lib.rs index aa4ed12..f543363 100644 --- a/crates/grokboy-core/src/lib.rs +++ b/crates/grokboy-core/src/lib.rs @@ -19,3 +19,17 @@ pub use config::Config; pub use model::{ChatMessage, FunctionCall, Role, ToolCall, chat_completion, stream_chat}; pub use session::{Session, load_or_create, load_session, save_session, sessions_dir}; pub use tools::{ToolContext, execute_tool, is_completion_tool, tool_definitions}; + +/// Serialize tests that mutate process env (CONFIRM_AUTO / HANDOFF_AUTO). +#[cfg(test)] +pub(crate) mod test_env { + use std::sync::{Mutex, MutexGuard, OnceLock}; + + pub(crate) fn lock() -> MutexGuard<'static, ()> { + static M: OnceLock> = OnceLock::new(); + M.get_or_init(|| Mutex::new(())) + .lock() + .unwrap_or_else(|e| e.into_inner()) + } +} + diff --git a/crates/grokboy-core/src/tools.rs b/crates/grokboy-core/src/tools.rs index f5d38e0..4602c76 100644 --- a/crates/grokboy-core/src/tools.rs +++ b/crates/grokboy-core/src/tools.rs @@ -522,6 +522,7 @@ mod tests { #[tokio::test] async fn browser_handoff_auto_resume_protocol() { + let _env_lock = crate::test_env::lock(); // Offline: with GROKBOY_HANDOFF_AUTO=1, missing Chromium still fail-closes // OR (if Chromium present) resumes and returns snapshot/error JSON — never hangs. let prev = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); @@ -553,6 +554,7 @@ mod tests { #[tokio::test] async fn request_user_confirm_auto_approve_and_deny() { + let _env_lock = crate::test_env::lock(); let prev_c = std::env::var("GROKBOY_CONFIRM_AUTO").ok(); let prev_h = std::env::var("GROKBOY_HANDOFF_AUTO").ok(); unsafe {