use emailks::config::{AppConfig, SmtpTls}; use emailks::error::ConfigError; use std::sync::Mutex; use std::time::Duration; /// Serialize tests that mutate process-wide environment variables. static TEST_MUTEX: Mutex<()> = Mutex::new(()); macro_rules! set_env { ($k:expr, $v:expr) => { unsafe { std::env::set_var($k, $v) } }; } macro_rules! rm_env { ($k:expr) => { unsafe { std::env::remove_var($k) } }; } fn clear_smtp_env() { for var in &[ "APP_SMTP_HOST", "APP_SMTP_PORT", "APP_SMTP_USERNAME", "APP_SMTP_PASSWORD", "APP_SMTP_FROM_EMAIL", "APP_SMTP_FROM_NAME", "APP_SMTP_REPLY_TO", "APP_SMTP_TLS", "APP_SMTP_TIMEOUT_SECS", "APP_SMTP_HELO_NAME", "APP_SMTP_ALLOW_REQUEST_FROM", "APP_SMTP_LISTEN_ADDR", "APP_SMTP_QUEUE_CAPACITY", ] { rm_env!(var); } } #[test] fn parse_smtp_config_full() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); set_env!("APP_SMTP_HOST", "smtp.test.com"); set_env!("APP_SMTP_PORT", "465"); set_env!("APP_SMTP_USERNAME", "user"); set_env!("APP_SMTP_PASSWORD", "pass"); set_env!("APP_SMTP_FROM_EMAIL", "from@test.com"); set_env!("APP_SMTP_FROM_NAME", "Test"); set_env!("APP_SMTP_REPLY_TO", "reply@test.com"); set_env!("APP_SMTP_TLS", "tls"); set_env!("APP_SMTP_TIMEOUT_SECS", "60"); set_env!("APP_SMTP_HELO_NAME", "helo.test.com"); let s = &AppConfig::from_env().unwrap().smtp; assert_eq!(s.host, "smtp.test.com"); assert_eq!(s.port, 465); assert_eq!(s.username.as_deref(), Some("user")); assert_eq!(s.password.as_deref(), Some("pass")); assert_eq!(s.from_email.as_deref(), Some("from@test.com")); assert_eq!(s.from_name.as_deref(), Some("Test")); assert_eq!(s.reply_to.as_deref(), Some("reply@test.com")); assert_eq!(s.tls, SmtpTls::Tls); assert_eq!(s.timeout, Duration::from_secs(60)); assert_eq!(s.helo_name.as_deref(), Some("helo.test.com")); assert!(!s.allow_request_from); } #[test] fn parse_smtp_config_minimal() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); set_env!("APP_SMTP_HOST", "smtp.test.com"); let s = &AppConfig::from_env().unwrap().smtp; assert_eq!(s.host, "smtp.test.com"); assert_eq!(s.port, 587); assert_eq!(s.tls, SmtpTls::StartTls); assert_eq!(s.timeout, Duration::from_secs(30)); assert!(s.username.is_none()); assert_eq!( AppConfig::from_env().unwrap().listen_addr.to_string(), "127.0.0.1:50051" ); } #[test] fn missing_host_is_error() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); let err = AppConfig::from_env().unwrap_err(); assert!(matches!(err, ConfigError::MissingEnv { name: "HOST" })); } #[test] fn tls_variants() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); set_env!("APP_SMTP_HOST", "h"); for (value, expected) in [ ("none", SmtpTls::None), ("false", SmtpTls::None), ("starttls", SmtpTls::StartTls), ("start_tls", SmtpTls::StartTls), ("tls", SmtpTls::Tls), ("ssl", SmtpTls::Tls), ] { set_env!("APP_SMTP_TLS", value); assert_eq!(AppConfig::from_env().unwrap().smtp.tls, expected); } } #[test] fn invalid_port_is_error() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); set_env!("APP_SMTP_HOST", "h"); set_env!("APP_SMTP_PORT", "0"); assert!(matches!( AppConfig::from_env().unwrap_err(), ConfigError::InvalidEnv { name: "PORT", .. } )); } #[test] fn queue_capacity_parsing() { let _guard = TEST_MUTEX.lock().unwrap_or_else(|e| e.into_inner()); clear_smtp_env(); set_env!("APP_SMTP_HOST", "h"); set_env!("APP_SMTP_QUEUE_CAPACITY", "100"); assert_eq!(AppConfig::from_env().unwrap().queue_capacity, Some(100)); rm_env!("APP_SMTP_QUEUE_CAPACITY"); assert_eq!(AppConfig::from_env().unwrap().queue_capacity, None); }