mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 15:40:18 +00:00
* fix(tests): eliminate env mutex poison cascade and fix test flakiness The shared ENV_MUTEX used by ~68 config tests would cascade a single test panic into failures across every module. Replace all .unwrap() / .expect() lock acquisitions with a poison-recovering lock_env() helper. Consolidate rogue module-local ENV_LOCK instances (workspace, orchestrator, bootstrap) onto the shared global mutex to prevent cross-module races. Also fixes: - gateway user_id fallback was hardcoded to "default" instead of owner_id - test_ironclaw_env_path used LazyLock which is order-dependent Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * test(helpers): add regression test for lock_env poison recovery Satisfies the regression-test-check CI gate by adding a test that intentionally poisons ENV_MUTEX and verifies lock_env() recovers. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix(ci): detect test changes inside #[cfg(test)] regions The regression test check relied on git diff -W to expand context to function boundaries, but git doesn't recognize Rust `mod tests {}` as a function boundary. Changes to imports, helpers, or lock calls inside test modules were invisible to the check. Add a line-level fallback: for each changed .rs file, find where #[cfg(test)] starts and check if any diff hunk targets a line at or after that boundary. This catches edits anywhere inside test modules regardless of git's language awareness. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: address PR review feedback - Clear ENV_MUTEX poison after regression test so it doesn't leave global state dirty for subsequent tests. - Fix CI regression-test-check to match #[cfg(test)] only when followed by `mod` (the test module pattern), avoiding false positives from standalone #[cfg(test)] items like statics or functions. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
95 lines
3.1 KiB
Rust
95 lines
3.1 KiB
Rust
use std::path::PathBuf;
|
|
use std::time::Duration;
|
|
|
|
use crate::config::helpers::{optional_env, parse_bool_env, parse_optional_env};
|
|
use crate::error::ConfigError;
|
|
|
|
/// Builder mode configuration.
|
|
#[derive(Debug, Clone)]
|
|
pub struct BuilderModeConfig {
|
|
/// Whether the software builder tool is enabled.
|
|
pub enabled: bool,
|
|
/// Directory for build artifacts (default: temp dir).
|
|
pub build_dir: Option<PathBuf>,
|
|
/// Maximum iterations for the build loop.
|
|
pub max_iterations: u32,
|
|
/// Build timeout in seconds.
|
|
pub timeout_secs: u64,
|
|
/// Whether to automatically register built WASM tools.
|
|
pub auto_register: bool,
|
|
}
|
|
|
|
impl Default for BuilderModeConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
enabled: true,
|
|
build_dir: None,
|
|
max_iterations: 20,
|
|
timeout_secs: 600,
|
|
auto_register: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BuilderModeConfig {
|
|
pub(crate) fn resolve(settings: &crate::settings::Settings) -> Result<Self, ConfigError> {
|
|
let bs = &settings.builder;
|
|
Ok(Self {
|
|
enabled: parse_bool_env("BUILDER_ENABLED", bs.enabled)?,
|
|
build_dir: optional_env("BUILDER_DIR")?
|
|
.map(PathBuf::from)
|
|
.or_else(|| bs.build_dir.clone()),
|
|
max_iterations: parse_optional_env("BUILDER_MAX_ITERATIONS", bs.max_iterations)?,
|
|
timeout_secs: parse_optional_env("BUILDER_TIMEOUT_SECS", bs.timeout_secs)?,
|
|
auto_register: parse_bool_env("BUILDER_AUTO_REGISTER", bs.auto_register)?,
|
|
})
|
|
}
|
|
|
|
/// Convert to BuilderConfig for the builder tool.
|
|
pub fn to_builder_config(&self) -> crate::tools::BuilderConfig {
|
|
crate::tools::BuilderConfig {
|
|
build_dir: self.build_dir.clone().unwrap_or_else(std::env::temp_dir),
|
|
max_iterations: self.max_iterations,
|
|
timeout: Duration::from_secs(self.timeout_secs),
|
|
cleanup_on_failure: true,
|
|
validate_wasm: true,
|
|
run_tests: true,
|
|
auto_register: self.auto_register,
|
|
wasm_output_dir: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::config::helpers::lock_env;
|
|
use crate::settings::Settings;
|
|
|
|
#[test]
|
|
fn resolve_falls_back_to_settings() {
|
|
let _guard = lock_env();
|
|
let mut settings = Settings::default();
|
|
settings.builder.max_iterations = 99;
|
|
settings.builder.auto_register = false;
|
|
|
|
let cfg = BuilderModeConfig::resolve(&settings).expect("resolve");
|
|
assert_eq!(cfg.max_iterations, 99);
|
|
assert!(!cfg.auto_register);
|
|
}
|
|
|
|
#[test]
|
|
fn env_overrides_settings() {
|
|
let _guard = lock_env();
|
|
let mut settings = Settings::default();
|
|
settings.builder.timeout_secs = 123;
|
|
|
|
// SAFETY: Under ENV_MUTEX, no concurrent env access.
|
|
unsafe { std::env::set_var("BUILDER_TIMEOUT_SECS", "3") };
|
|
let cfg = BuilderModeConfig::resolve(&settings).expect("resolve");
|
|
unsafe { std::env::remove_var("BUILDER_TIMEOUT_SECS") };
|
|
|
|
assert_eq!(cfg.timeout_secs, 3);
|
|
}
|
|
}
|