use std::fs;
use opi_coding_agent::config::{OpiConfig, load_config_file};
fn write_temp_config(dir: &std::path::Path, contents: &str) -> std::path::PathBuf {
let path = dir.join("config.toml");
fs::write(&path, contents).unwrap();
path
}
#[test]
fn no_proxy_config_returns_none() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
"#,
);
let config = load_config_file(&path).unwrap();
assert!(
config.providers.anthropic.proxy.is_none(),
"no proxy config should be None"
);
}
#[test]
fn empty_config_has_no_proxy() {
let config = OpiConfig::default();
assert!(config.providers.anthropic.proxy.is_none());
assert!(config.providers.openai.proxy.is_none());
assert!(config.providers.openrouter.proxy.is_none());
assert!(config.providers.gemini.proxy.is_none());
}
#[test]
fn parse_anthropic_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.anthropic.proxy]
url = "http://proxy.example.com:8080"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.anthropic
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
assert!(proxy.no_proxy.is_none());
}
#[test]
fn parse_anthropic_proxy_with_no_proxy() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.anthropic.proxy]
url = "http://proxy.example.com:8080"
no_proxy = "localhost,*.internal"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.anthropic
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
assert_eq!(proxy.no_proxy.as_deref(), Some("localhost,*.internal"));
}
#[test]
fn parse_openai_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.openai]
api_key_env = "OPENAI_API_KEY"
[providers.openai.proxy]
url = "http://proxy.example.com:8080"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.openai
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
}
#[test]
fn parse_gemini_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.gemini]
api_key_env = "GEMINI_API_KEY"
[providers.gemini.proxy]
url = "http://proxy.example.com:8080"
no_proxy = "localhost"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.gemini
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
assert_eq!(proxy.no_proxy.as_deref(), Some("localhost"));
}
#[test]
fn parse_openrouter_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.openrouter]
api_key_env = "OPENROUTER_API_KEY"
[providers.openrouter.proxy]
url = "http://proxy.example.com:8080"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.openrouter
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
}
#[test]
fn parse_mistral_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.mistral]
api_key_env = "MISTRAL_API_KEY"
[providers.mistral.proxy]
url = "http://proxy.example.com:8080"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.mistral
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
}
#[test]
fn parse_openai_responses_proxy_url() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.openai_responses]
api_key_env = "OPENAI_API_KEY"
[providers.openai_responses.proxy]
url = "http://proxy.example.com:8080"
"#,
);
let config = load_config_file(&path).unwrap();
let proxy = config
.providers
.openai_responses
.proxy
.as_ref()
.expect("proxy should be set");
assert_eq!(proxy.url, "http://proxy.example.com:8080");
}
#[test]
fn different_proxy_per_provider() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.anthropic.proxy]
url = "http://anthropic-proxy:8080"
[providers.openai]
api_key_env = "OPENAI_API_KEY"
[providers.openai.proxy]
url = "http://openai-proxy:9090"
no_proxy = "localhost"
"#,
);
let config = load_config_file(&path).unwrap();
let ap = config
.providers
.anthropic
.proxy
.as_ref()
.expect("anthropic proxy");
assert_eq!(ap.url, "http://anthropic-proxy:8080");
assert!(ap.no_proxy.is_none());
let op = config
.providers
.openai
.proxy
.as_ref()
.expect("openai proxy");
assert_eq!(op.url, "http://openai-proxy:9090");
assert_eq!(op.no_proxy.as_deref(), Some("localhost"));
assert!(config.providers.gemini.proxy.is_none());
}
#[test]
fn empty_proxy_section_ignored() {
let dir = tempfile::tempdir().unwrap();
let path = write_temp_config(
dir.path(),
r#"
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.anthropic.proxy]
no_proxy = "localhost"
"#,
);
let config = load_config_file(&path).unwrap();
assert!(
config.providers.anthropic.proxy.is_none(),
"proxy section without url should be ignored"
);
}
#[test]
fn build_http_client_with_explicit_proxy() {
use opi_coding_agent::config::{ProviderProxyConfig, build_http_client};
let proxy = ProviderProxyConfig {
url: "http://proxy.example.com:8080".into(),
no_proxy: Some("localhost".into()),
};
let client = build_http_client(Some(&proxy)).expect("valid proxy should succeed");
let config = client.proxy_config();
assert_eq!(
config.url.as_deref(),
Some("http://proxy.example.com:8080"),
"proxy URL should be set"
);
assert_eq!(
config.no_proxy.as_deref(),
Some("localhost"),
"no_proxy should be set"
);
}
#[test]
fn build_http_client_with_no_proxy_falls_back_to_env() {
use opi_coding_agent::config::build_http_client;
let client = build_http_client(None).expect("no-proxy should succeed");
let _ = client.proxy_config();
}
#[test]
fn build_http_client_with_proxy_and_no_proxy_list() {
use opi_coding_agent::config::{ProviderProxyConfig, build_http_client};
let proxy = ProviderProxyConfig {
url: "http://corporate-proxy.internal:3128".into(),
no_proxy: Some("localhost,*.internal,10.0.0.0/8".into()),
};
let client = build_http_client(Some(&proxy)).expect("valid proxy should succeed");
let config = client.proxy_config();
assert!(config.url.is_some());
assert_eq!(
config.no_proxy.as_deref(),
Some("localhost,*.internal,10.0.0.0/8")
);
}
#[test]
fn build_http_client_with_proxy_no_no_proxy() {
use opi_coding_agent::config::{ProviderProxyConfig, build_http_client};
let proxy = ProviderProxyConfig {
url: "http://proxy.example.com:9999".into(),
no_proxy: None,
};
let client = build_http_client(Some(&proxy)).expect("valid proxy should succeed");
let config = client.proxy_config();
assert_eq!(config.url.as_deref(), Some("http://proxy.example.com:9999"));
assert!(config.no_proxy.is_none());
}
#[test]
fn build_http_client_rejects_invalid_proxy_url() {
use opi_coding_agent::config::{ProviderProxyConfig, build_http_client};
let proxy = ProviderProxyConfig {
url: "not a proxy url".into(),
no_proxy: None,
};
let result = build_http_client(Some(&proxy));
assert!(result.is_err(), "invalid proxy URL should return Err");
}
#[test]
fn build_http_client_without_proxy_succeeds() {
use opi_coding_agent::config::build_http_client;
let client = build_http_client(None).expect("no proxy should succeed");
assert!(client.proxy_config().url.is_none());
}