提交qiming-mcp-proxy

This commit is contained in:
Codex
2026-06-01 13:03:20 +08:00
parent 9e9486b7c2
commit afb3d9f4e6
394 changed files with 124494 additions and 0 deletions

View File

@@ -0,0 +1,226 @@
#[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");
}
}