Files
qiming/qiming-mcp-proxy/voice-cli/src/tests/config_env_tests.rs
2026-06-01 13:03:20 +08:00

227 lines
7.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#[cfg(test)]
mod config_env_tests {
use crate::models::Config;
use std::collections::HashMap;
use std::env;
use std::sync::{Mutex, OnceLock};
use tempfile::TempDir;
// Safe environment variable testing using static state
static TEST_ENV_LOCK: OnceLock<Mutex<HashMap<String, Option<String>>>> = OnceLock::new();
fn get_test_env_lock() -> &'static Mutex<HashMap<String, Option<String>>> {
TEST_ENV_LOCK.get_or_init(|| Mutex::new(HashMap::new()))
}
// Safe helper to set environment variable for testing
fn safe_set_env_var(key: &str, value: &str) {
let lock = get_test_env_lock();
let mut env_state = lock.lock().unwrap();
// Store the original value if this is the first time setting this var
if !env_state.contains_key(key) {
env_state.insert(key.to_string(), env::var(key).ok());
}
// This is still technically unsafe, but we'll wrap it in unsafe block
// and document that tests should run serially to avoid race conditions
unsafe {
env::set_var(key, value);
}
}
// Safe helper to remove environment variable for testing
fn safe_remove_env_var(key: &str) {
let lock = get_test_env_lock();
let mut env_state = lock.lock().unwrap();
// Store the original value if this is the first time touching this var
if !env_state.contains_key(key) {
env_state.insert(key.to_string(), env::var(key).ok());
}
unsafe {
env::remove_var(key);
}
}
// Helper function to clear all voice-cli environment variables safely
fn clear_voice_cli_env_vars() {
let env_vars = [
"VOICE_CLI_HOST",
"VOICE_CLI_PORT",
"VOICE_CLI_LOG_LEVEL",
"VOICE_CLI_LOG_DIR",
"VOICE_CLI_LOG_MAX_FILES",
"VOICE_CLI_DEFAULT_MODEL",
"VOICE_CLI_MODELS_DIR",
"VOICE_CLI_AUTO_DOWNLOAD",
"VOICE_CLI_TRANSCRIPTION_WORKERS",
"VOICE_CLI_WORK_DIR",
"VOICE_CLI_PID_FILE",
"VOICE_CLI_MAX_FILE_SIZE",
"VOICE_CLI_CORS_ENABLED",
];
for var in &env_vars {
safe_remove_env_var(var);
}
// Add a small delay to ensure environment changes propagate
std::thread::sleep(std::time::Duration::from_millis(10));
}
// Cleanup function to restore original environment state
fn restore_original_env_vars() {
let lock = get_test_env_lock();
let env_state = lock.lock().unwrap();
for (key, original_value) in env_state.iter() {
match original_value {
Some(value) => unsafe {
env::set_var(key, value);
},
None => unsafe {
env::remove_var(key);
},
}
}
}
#[test]
#[ignore = "Modifies global environment variables, causes race conditions with parallel tests"]
fn test_http_port_environment_override() {
clear_voice_cli_env_vars();
// Set environment variable for HTTP port
safe_set_env_var("VOICE_CLI_PORT", "9090");
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let config = Config::load_with_env_overrides(&config_path).unwrap();
// Verify HTTP port was overridden
assert_eq!(config.server.port, 9090);
// Clean up
safe_remove_env_var("VOICE_CLI_PORT");
}
#[test]
#[ignore = "Modifies global environment variables, causes race conditions with parallel tests"]
fn test_invalid_port_environment_variable() {
clear_voice_cli_env_vars();
// Set invalid environment variable
safe_set_env_var("VOICE_CLI_PORT", "invalid_port");
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let result = Config::load_with_env_overrides(&config_path);
// Should fail with proper error message
assert!(result.is_err());
let error_msg = result.unwrap_err().to_string();
assert!(error_msg.contains("Invalid VOICE_CLI_PORT value 'invalid_port'"));
// Clean up
safe_remove_env_var("VOICE_CLI_PORT");
}
#[test]
#[ignore = "Modifies global environment variables, causes race conditions with parallel tests"]
fn test_log_level_environment_override() {
clear_voice_cli_env_vars();
// Set environment variable for log level
safe_set_env_var("VOICE_CLI_LOG_LEVEL", "DEBUG");
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let config = Config::load_with_env_overrides(&config_path).unwrap();
// Verify log level was overridden and normalized to lowercase
assert_eq!(config.logging.level, "debug");
// Clean up
safe_remove_env_var("VOICE_CLI_LOG_LEVEL");
}
#[test]
#[ignore = "Modifies global environment variables, causes race conditions with parallel tests"]
fn test_invalid_log_level_environment_variable() {
clear_voice_cli_env_vars();
// Set invalid environment variable
safe_set_env_var("VOICE_CLI_LOG_LEVEL", "invalid_level");
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let result = Config::load_with_env_overrides(&config_path);
// Should fail with proper error message
assert!(result.is_err());
let error_msg = result.unwrap_err().to_string();
assert!(error_msg.contains("Invalid VOICE_CLI_LOG_LEVEL"));
assert!(error_msg.contains("invalid_level"));
// Clean up
safe_remove_env_var("VOICE_CLI_LOG_LEVEL");
}
#[test]
#[ignore = "Modifies global environment variables, causes race conditions with parallel tests"]
fn test_comprehensive_validation() {
clear_voice_cli_env_vars();
// Set multiple environment variables
// 注意使用有效的模型名称large-v3 而不是 large
safe_set_env_var("VOICE_CLI_PORT", "8081");
safe_set_env_var("VOICE_CLI_LOG_LEVEL", "warn");
safe_set_env_var("VOICE_CLI_DEFAULT_MODEL", "large-v3");
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let config = Config::load_with_env_overrides(&config_path).unwrap();
// Verify all overrides were applied
assert_eq!(config.server.port, 8081);
assert_eq!(config.logging.level, "warn");
assert_eq!(config.whisper.default_model, "large-v3");
// Verify validation passes
assert!(config.validate().is_ok());
// Clean up
safe_remove_env_var("VOICE_CLI_PORT");
safe_remove_env_var("VOICE_CLI_LOG_LEVEL");
safe_remove_env_var("VOICE_CLI_DEFAULT_MODEL");
}
#[test]
fn test_empty_environment_variable_validation() {
clear_voice_cli_env_vars();
// Set empty environment variable
safe_set_env_var("VOICE_CLI_HOST", " "); // Use spaces instead of empty string
let temp_dir = TempDir::new().unwrap();
let config_path = temp_dir.path().join("config.yml");
let result = Config::load_with_env_overrides(&config_path);
// Should fail with proper error message
assert!(result.is_err());
let error_msg = result.unwrap_err().to_string();
assert!(error_msg.contains("VOICE_CLI_HOST environment variable cannot be empty"));
// Clean up
safe_remove_env_var("VOICE_CLI_HOST");
}
}