use std::fs; use std::path::Path; use std::sync::{Mutex, OnceLock}; use sgclaw::compat::config_adapter::{ build_zeroclaw_config, build_zeroclaw_config_from_settings, zeroclaw_workspace_dir, }; use sgclaw::config::DeepSeekSettings; use uuid::Uuid; fn env_lock() -> &'static Mutex<()> { static LOCK: OnceLock> = OnceLock::new(); LOCK.get_or_init(|| Mutex::new(())) } #[test] fn zeroclaw_config_adapter_maps_deepseek_env_to_zeroclaw_config() { let _guard = env_lock().lock().unwrap(); std::env::set_var("DEEPSEEK_API_KEY", "deepseek-test-key"); std::env::set_var("DEEPSEEK_BASE_URL", "https://api.deepseek.com"); std::env::set_var("DEEPSEEK_MODEL", "deepseek-chat"); let config = build_zeroclaw_config(Path::new("/tmp/sgclaw")).unwrap(); assert_eq!(config.default_provider.as_deref(), Some("deepseek")); assert_eq!(config.default_model.as_deref(), Some("deepseek-chat")); assert_eq!(config.api_key.as_deref(), Some("deepseek-test-key")); assert_eq!(config.api_url.as_deref(), Some("https://api.deepseek.com")); assert_eq!( config.workspace_dir, Path::new("/tmp/sgclaw/.sgclaw-zeroclaw-workspace") ); assert_eq!( config.config_path, Path::new("/tmp/sgclaw/.sgclaw-zeroclaw-workspace/config.toml") ); } #[test] fn zeroclaw_config_adapter_uses_deterministic_workspace_dir() { let settings = DeepSeekSettings { api_key: "key".to_string(), base_url: "https://proxy.example.com/v1".to_string(), model: "deepseek-reasoner".to_string(), }; let workspace_dir = zeroclaw_workspace_dir(Path::new("/var/lib/sgclaw")); let config = build_zeroclaw_config_from_settings(Path::new("/var/lib/sgclaw"), &settings); assert_eq!(workspace_dir, Path::new("/var/lib/sgclaw/.sgclaw-zeroclaw-workspace")); assert_eq!(config.workspace_dir, workspace_dir); assert_eq!(config.default_provider.as_deref(), Some("deepseek")); assert_eq!(config.default_model.as_deref(), Some("deepseek-reasoner")); assert_eq!(config.api_url.as_deref(), Some("https://proxy.example.com/v1")); } #[test] fn deepseek_settings_reload_from_browser_config_path_after_file_changes() { let root = std::env::temp_dir().join(format!("sgclaw-config-{}", Uuid::new_v4())); fs::create_dir_all(&root).unwrap(); let config_path = root.join("sgclaw_config.json"); fs::write( &config_path, r#"{ "apiKey": "sk-first", "baseUrl": "", "model": "" }"#, ) .unwrap(); let first = DeepSeekSettings::load(Some(config_path.as_path())) .unwrap() .expect("expected config file to produce settings"); assert_eq!(first.api_key, "sk-first"); assert_eq!(first.base_url, "https://api.deepseek.com"); assert_eq!(first.model, "deepseek-chat"); fs::write( &config_path, r#"{ "apiKey": "sk-second", "baseUrl": "https://proxy.example.com/v1", "model": "deepseek-reasoner" }"#, ) .unwrap(); let second = DeepSeekSettings::load(Some(config_path.as_path())) .unwrap() .expect("expected updated config file to produce settings"); assert_eq!(second.api_key, "sk-second"); assert_eq!(second.base_url, "https://proxy.example.com/v1"); assert_eq!(second.model, "deepseek-reasoner"); }