Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ unimplemented = "deny"

[dev-dependencies]
tokio-test = "0.4"
parking_lot = "0.12"

# OS keystore (macOS Keychain for master key storage)
[target.'cfg(target_os = "macos")'.dependencies]
Expand Down
81 changes: 30 additions & 51 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6677,11 +6677,10 @@ pub fn run_onboarding() -> anyhow::Result<Option<PathBuf>> {
mod tests {
use super::*;
use std::result::Result as StdResult;
use std::sync::{Mutex, OnceLock};

fn env_test_lock() -> &'static Mutex<()> {
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
LOCK.get_or_init(|| Mutex::new(()))
fn env_test_lock() -> &'static parking_lot::Mutex<()> {
static LOCK: std::sync::OnceLock<parking_lot::Mutex<()>> = std::sync::OnceLock::new();
LOCK.get_or_init(|| parking_lot::Mutex::new(()))
}

struct EnvGuard {
Expand All @@ -6691,12 +6690,14 @@ mod tests {

impl EnvGuard {
fn new() -> Self {
const KEYS: [&str; 26] = [
// NOTE: Keep in sync with provider env vars that affect test behavior
const KEYS: [&str; 27] = [
"SPACEBOT_DIR",
"SPACEBOT_DEPLOYMENT",
"SPACEBOT_CRON_TIMEZONE",
"SPACEBOT_USER_TIMEZONE",
"ANTHROPIC_API_KEY",
"ANTHROPIC_BASE_URL",
"ANTHROPIC_OAUTH_TOKEN",
"OPENAI_API_KEY",
"OPENROUTER_API_KEY",
Expand Down Expand Up @@ -6859,7 +6860,7 @@ api_key = "sk-proj-xyz789"

#[test]
fn test_llm_provider_tables_parse_with_env_and_lowercase_keys() {
let _lock = env_test_lock().lock().unwrap_or_else(|e| e.into_inner());
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

let toml = r#"
Expand Down Expand Up @@ -6905,6 +6906,9 @@ api_key = "static-provider-key"

#[test]
fn test_legacy_llm_keys_auto_migrate_to_providers() {
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

let toml = r#"
[llm]
anthropic_key = "legacy-anthropic-key"
Expand Down Expand Up @@ -7035,19 +7039,15 @@ name = "My OpenRouter"

#[test]
fn test_needs_onboarding_without_config_or_env() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

assert!(Config::needs_onboarding());
}

#[test]
fn test_needs_onboarding_with_anthropic_env_key() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand All @@ -7059,9 +7059,7 @@ name = "My OpenRouter"

#[test]
fn test_needs_onboarding_false_with_oauth_credentials() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

// Create an OAuth credentials file in the EnvGuard's temp dir
Expand All @@ -7078,9 +7076,7 @@ name = "My OpenRouter"

#[test]
fn test_needs_onboarding_false_with_openai_oauth_credentials() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

let instance_dir = Config::default_instance_dir();
Expand All @@ -7098,9 +7094,7 @@ name = "My OpenRouter"

#[test]
fn test_load_from_env_populates_legacy_key_and_provider() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand All @@ -7122,9 +7116,7 @@ name = "My OpenRouter"

#[test]
fn test_hosted_deployment_forces_api_bind_from_toml() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand All @@ -7144,9 +7136,7 @@ bind = "127.0.0.1"

#[test]
fn test_hosted_deployment_forces_api_bind_from_env_defaults() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand Down Expand Up @@ -7262,9 +7252,7 @@ bind = "127.0.0.1"

#[test]
fn test_cron_timezone_resolution_precedence() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand Down Expand Up @@ -7321,9 +7309,7 @@ id = "main"

#[test]
fn test_cron_timezone_invalid_falls_back_to_system() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand All @@ -7343,9 +7329,7 @@ id = "main"

#[test]
fn test_cron_timezone_invalid_default_uses_env_fallback() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand All @@ -7368,9 +7352,7 @@ id = "main"

#[test]
fn test_user_timezone_resolution_precedence() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand Down Expand Up @@ -7417,9 +7399,7 @@ id = "main"

#[test]
fn test_user_timezone_falls_back_to_cron_timezone() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

let toml = r#"
Expand All @@ -7445,9 +7425,7 @@ id = "main"

#[test]
fn test_user_timezone_invalid_falls_back_to_cron_timezone() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

let toml = r#"
Expand All @@ -7470,9 +7448,7 @@ id = "main"

#[test]
fn test_user_timezone_invalid_config_uses_env_fallback() {
let _lock = env_test_lock()
.lock()
.expect("failed to lock env test mutex");
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

unsafe {
Expand Down Expand Up @@ -7760,6 +7736,9 @@ startup_delay_secs = 2
/// `LlmConfig` without wiring it up in `load_from_env` / `from_toml`, this test fails.
#[test]
fn all_shorthand_keys_register_providers_via_toml() {
let _lock = env_test_lock().lock();
let _env = EnvGuard::new();

// (toml_key, toml_value, provider_name, expected_base_url_substring)
let cases: &[(&str, &str, &str, &str)] = &[
("anthropic_key", "test-key", "anthropic", "anthropic.com"),
Expand Down Expand Up @@ -7824,7 +7803,7 @@ startup_delay_secs = 2

#[test]
fn all_shorthand_keys_register_providers_via_env() {
let _lock = env_test_lock().lock().unwrap();
let _lock = env_test_lock().lock();

// (env_var, env_value, provider_name, expected_base_url_substring)
let cases: &[(&str, &str, &str, &str)] = &[
Expand Down Expand Up @@ -8248,7 +8227,7 @@ startup_delay_secs = 2

#[test]
fn toml_round_trip_with_named_instances() {
let _guard = env_test_lock().lock().unwrap();
let _guard = env_test_lock().lock();
let guard = EnvGuard::new();

let toml_content = r#"
Expand Down Expand Up @@ -8289,7 +8268,7 @@ chat_id = "-100111"

#[test]
fn toml_backward_compat_no_adapter_field() {
let _guard = env_test_lock().lock().unwrap();
let _guard = env_test_lock().lock();
let guard = EnvGuard::new();

let toml_content = r#"
Expand Down