use std::ffi::OsString; use std::sync::{Mutex, OnceLock}; use api::{build_http_client_with, ProxyConfig}; fn env_lock() -> std::sync::MutexGuard<'static, ()> { static LOCK: OnceLock> = OnceLock::new(); LOCK.get_or_init(|| Mutex::new(())) .lock() .unwrap_or_else(std::sync::PoisonError::into_inner) } struct EnvVarGuard { key: &'static str, original: Option, } impl EnvVarGuard { fn set(key: &'static str, value: Option<&str>) -> Self { let original = std::env::var_os(key); match value { Some(value) => std::env::set_var(key, value), None => std::env::remove_var(key), } Self { key, original } } } impl Drop for EnvVarGuard { fn drop(&mut self) { match &self.original { Some(value) => std::env::set_var(self.key, value), None => std::env::remove_var(self.key), } } } #[test] fn proxy_config_from_env_reads_uppercase_proxy_vars() { // given let _lock = env_lock(); let _http = EnvVarGuard::set("HTTP_PROXY", Some("http://proxy.corp:3128")); let _https = EnvVarGuard::set("HTTPS_PROXY", Some("http://secure.corp:3129")); let _no = EnvVarGuard::set("NO_PROXY", Some("localhost,127.0.0.1")); let _http_lower = EnvVarGuard::set("http_proxy", None); let _https_lower = EnvVarGuard::set("https_proxy", None); let _no_lower = EnvVarGuard::set("no_proxy", None); // when let config = ProxyConfig::from_env(); // then assert_eq!(config.http_proxy.as_deref(), Some("http://proxy.corp:3128")); assert_eq!( config.https_proxy.as_deref(), Some("http://secure.corp:3129") ); assert_eq!(config.no_proxy.as_deref(), Some("localhost,127.0.0.1")); assert!(config.proxy_url.is_none()); assert!(!config.is_empty()); } #[test] fn proxy_config_from_env_reads_lowercase_proxy_vars() { // given let _lock = env_lock(); let _http = EnvVarGuard::set("HTTP_PROXY", None); let _https = EnvVarGuard::set("HTTPS_PROXY", None); let _no = EnvVarGuard::set("NO_PROXY", None); let _http_lower = EnvVarGuard::set("http_proxy", Some("http://lower.corp:3128")); let _https_lower = EnvVarGuard::set("https_proxy", Some("http://lower-secure.corp:3129")); let _no_lower = EnvVarGuard::set("no_proxy", Some(".internal")); // when let config = ProxyConfig::from_env(); // then assert_eq!(config.http_proxy.as_deref(), Some("http://lower.corp:3128")); assert_eq!( config.https_proxy.as_deref(), Some("http://lower-secure.corp:3129") ); assert_eq!(config.no_proxy.as_deref(), Some(".internal")); assert!(!config.is_empty()); } #[test] fn proxy_config_from_env_is_empty_when_no_vars_set() { // given let _lock = env_lock(); let _http = EnvVarGuard::set("HTTP_PROXY", None); let _https = EnvVarGuard::set("HTTPS_PROXY", None); let _no = EnvVarGuard::set("NO_PROXY", None); let _http_lower = EnvVarGuard::set("http_proxy", None); let _https_lower = EnvVarGuard::set("https_proxy", None); let _no_lower = EnvVarGuard::set("no_proxy", None); // when let config = ProxyConfig::from_env(); // then assert!(config.is_empty()); assert!(config.http_proxy.is_none()); assert!(config.https_proxy.is_none()); assert!(config.no_proxy.is_none()); } #[test] fn proxy_config_from_env_treats_empty_values_as_unset() { // given let _lock = env_lock(); let _http = EnvVarGuard::set("HTTP_PROXY", Some("")); let _https = EnvVarGuard::set("HTTPS_PROXY", Some("")); let _http_lower = EnvVarGuard::set("http_proxy", Some("")); let _https_lower = EnvVarGuard::set("https_proxy", Some("")); let _no = EnvVarGuard::set("NO_PROXY", Some("")); let _no_lower = EnvVarGuard::set("no_proxy", Some("")); // when let config = ProxyConfig::from_env(); // then assert!(config.is_empty()); } #[test] fn build_client_with_env_proxy_config_succeeds() { // given let _lock = env_lock(); let _http = EnvVarGuard::set("HTTP_PROXY", Some("http://proxy.corp:3128")); let _https = EnvVarGuard::set("HTTPS_PROXY", Some("http://secure.corp:3129")); let _no = EnvVarGuard::set("NO_PROXY", Some("localhost")); let _http_lower = EnvVarGuard::set("http_proxy", None); let _https_lower = EnvVarGuard::set("https_proxy", None); let _no_lower = EnvVarGuard::set("no_proxy", None); let config = ProxyConfig::from_env(); // when let result = build_http_client_with(&config); // then assert!(result.is_ok()); } #[test] fn build_client_with_proxy_url_config_succeeds() { // given let config = ProxyConfig::from_proxy_url("http://unified.corp:3128"); // when let result = build_http_client_with(&config); // then assert!(result.is_ok()); } #[test] fn proxy_config_from_env_prefers_uppercase_over_lowercase() { // given let _lock = env_lock(); let _http_upper = EnvVarGuard::set("HTTP_PROXY", Some("http://upper.corp:3128")); let _http_lower = EnvVarGuard::set("http_proxy", Some("http://lower.corp:3128")); let _https = EnvVarGuard::set("HTTPS_PROXY", None); let _https_lower = EnvVarGuard::set("https_proxy", None); let _no = EnvVarGuard::set("NO_PROXY", None); let _no_lower = EnvVarGuard::set("no_proxy", None); // when let config = ProxyConfig::from_env(); // then assert_eq!(config.http_proxy.as_deref(), Some("http://upper.corp:3128")); }