diff --git a/src/config/embeddings.rs b/src/config/embeddings.rs index 39f28f06..4528aded 100644 --- a/src/config/embeddings.rs +++ b/src/config/embeddings.rs @@ -102,16 +102,12 @@ impl EmbeddingsConfig { #[cfg(test)] mod tests { use super::*; + use crate::config::helpers::ENV_MUTEX; use crate::settings::{EmbeddingsSettings, Settings}; - use std::sync::Mutex; - - /// Serializes env-mutating tests to prevent parallel races. - static ENV_MUTEX: Mutex<()> = Mutex::new(()); /// Clear all embedding-related env vars. fn clear_embedding_env() { - // SAFETY: Only called under ENV_MUTEX in tests. No other threads - // observe these vars while the lock is held. + // SAFETY: Only called under ENV_MUTEX in tests. unsafe { std::env::remove_var("EMBEDDING_ENABLED"); std::env::remove_var("EMBEDDING_PROVIDER"); diff --git a/src/config/helpers.rs b/src/config/helpers.rs index b463bb50..e9e966df 100644 --- a/src/config/helpers.rs +++ b/src/config/helpers.rs @@ -2,6 +2,15 @@ use crate::error::ConfigError; use super::INJECTED_VARS; +/// Crate-wide mutex for tests that mutate process environment variables. +/// +/// The process environment is global state shared across all threads. +/// Per-module mutexes do NOT prevent races between modules running in +/// parallel. Every `unsafe { set_var / remove_var }` call in tests +/// MUST hold this single lock. +#[cfg(test)] +pub(crate) static ENV_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(()); + pub(crate) fn optional_env(key: &str) -> Result, ConfigError> { // Check real env vars first (always win over injected secrets) match std::env::var(key) { diff --git a/src/config/llm.rs b/src/config/llm.rs index a7564011..947b6da1 100644 --- a/src/config/llm.rs +++ b/src/config/llm.rs @@ -383,11 +383,8 @@ fn default_session_path() -> PathBuf { #[cfg(test)] mod tests { use super::*; + use crate::config::helpers::ENV_MUTEX; use crate::settings::Settings; - use std::sync::Mutex; - - /// Serializes env-mutating tests to prevent parallel races. - static ENV_MUTEX: Mutex<()> = Mutex::new(()); /// Clear all openai-compatible-related env vars. fn clear_openai_compatible_env() {