use serial_test::serial;
use std::time::Duration;
use terraphim_service::llm_proxy::{LlmProxyClient, ProxyConfig};
use terraphim_test_utils::TestEnv;
#[tokio::test]
#[serial]
async fn test_llm_proxy_auto_configuration() {
if std::env::var("RUN_LLM_PROXY_INTEGRATION_TESTS")
.map(|v| v != "1" && !v.eq_ignore_ascii_case("true"))
.unwrap_or(true)
{
eprintln!(
"Skipping: set RUN_LLM_PROXY_INTEGRATION_TESTS=1 to run llm proxy integration tests"
);
return;
}
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "test-token-123");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
assert!(
client
.configured_providers()
.contains(&"anthropic".to_string())
);
let config = client.get_config("anthropic").unwrap();
assert_eq!(config.provider, "anthropic");
assert_eq!(
config.base_url.as_ref().unwrap(),
"https://api.z.ai/api/anthropic"
);
assert_eq!(config.api_key.as_ref().unwrap(), "test-token-123");
let effective_url = client.get_effective_url("anthropic").unwrap();
assert_eq!(effective_url, "https://api.z.ai/api/anthropic");
assert!(client.is_using_proxy("anthropic"));
}
#[tokio::test]
#[serial]
async fn test_llm_proxy_fallback_mechanism() {
if std::env::var("RUN_LLM_PROXY_INTEGRATION_TESTS")
.map(|v| v != "1" && !v.eq_ignore_ascii_case("true"))
.unwrap_or(true)
{
eprintln!(
"Skipping: set RUN_LLM_PROXY_INTEGRATION_TESTS=1 to run llm proxy integration tests"
);
return;
}
let mut test_env = TestEnv::new();
test_env.remove("ANTHROPIC_BASE_URL");
test_env.remove("ANTHROPIC_AUTH_TOKEN");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let effective_url = client.get_effective_url("anthropic").unwrap();
assert_eq!(effective_url, "https://api.anthropic.com");
assert!(!client.is_using_proxy("anthropic"));
}
#[tokio::test]
#[serial]
async fn test_multiple_provider_configuration() {
if std::env::var("RUN_LLM_PROXY_INTEGRATION_TESTS")
.map(|v| v != "1" && !v.eq_ignore_ascii_case("true"))
.unwrap_or(true)
{
eprintln!(
"Skipping: set RUN_LLM_PROXY_INTEGRATION_TESTS=1 to run llm proxy integration tests"
);
return;
}
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "anthropic-token");
test_env.set("OPENROUTER_BASE_URL", "https://proxy.openrouter.ai/api/v1");
test_env.set("OPENROUTER_API_KEY", "openrouter-token");
test_env.set("OLLAMA_BASE_URL", "http://custom-ollama:11434");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let providers = client.configured_providers();
assert!(providers.contains(&"anthropic".to_string()));
assert!(providers.contains(&"openrouter".to_string()));
assert!(providers.contains(&"ollama".to_string()));
assert_eq!(
client.get_effective_url("anthropic").unwrap(),
"https://api.z.ai/api/anthropic"
);
assert_eq!(
client.get_effective_url("openrouter").unwrap(),
"https://proxy.openrouter.ai/api/v1"
);
assert_eq!(
client.get_effective_url("ollama").unwrap(),
"http://custom-ollama:11434"
);
}
#[tokio::test]
async fn test_custom_proxy_configuration() {
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let config = ProxyConfig::new(
"anthropic".to_string(),
"claude-3-sonnet-20240229".to_string(),
)
.with_base_url("https://custom-proxy.example.com/anthropic".to_string())
.with_api_key("custom-api-key".to_string())
.with_timeout(Duration::from_secs(60))
.with_fallback(true);
let mut client = client;
client.configure(config);
let stored_config = client.get_config("anthropic").unwrap();
assert_eq!(stored_config.model, "claude-3-sonnet-20240229");
assert_eq!(
stored_config.base_url.as_ref().unwrap(),
"https://custom-proxy.example.com/anthropic"
);
assert_eq!(stored_config.api_key.as_ref().unwrap(), "custom-api-key");
assert_eq!(stored_config.timeout, Duration::from_secs(60));
assert!(stored_config.enable_fallback);
}
#[tokio::test]
#[serial]
async fn test_connectivity_testing() {
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "test-token");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let result = client.test_connectivity("anthropic").await;
match result {
Ok(success) => {
println!("Connectivity test result: {}", success);
}
Err(e) => {
println!("Connectivity test error: {}", e);
}
}
let results = client.test_all_connectivity().await;
assert!(results.contains_key("anthropic"));
}
#[tokio::test]
#[serial]
async fn test_proxy_url_detection() {
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "test-token");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let config = client.get_config("anthropic").unwrap();
assert!(config.base_url.clone().unwrap().contains("z.ai"));
test_env.set(
"ANTHROPIC_BASE_URL",
"https://api.other-provider.com/anthropic",
);
let client2 = LlmProxyClient::new("anthropic".to_string()).unwrap();
let config2 = client2.get_config("anthropic").unwrap();
assert!(!config2.base_url.clone().unwrap().contains("z.ai"));
}
#[tokio::test]
#[serial]
async fn test_configuration_logging() {
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "test-token");
test_env.set("OPENROUTER_API_KEY", "openrouter-token");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
client.log_configuration();
assert_eq!(client.default_provider, "anthropic");
}
#[test]
fn test_proxy_config_builder() {
let config = ProxyConfig::new("test-provider".to_string(), "test-model".to_string())
.with_base_url("https://test-proxy.com".to_string())
.with_api_key("test-key".to_string())
.with_timeout(Duration::from_secs(45))
.with_fallback(false);
assert_eq!(config.provider, "test-provider");
assert_eq!(config.model, "test-model");
assert_eq!(config.base_url.unwrap(), "https://test-proxy.com");
assert_eq!(config.api_key.unwrap(), "test-key");
assert_eq!(config.timeout, Duration::from_secs(45));
assert!(!config.enable_fallback);
}
#[test]
#[serial]
fn test_environment_variable_precedence() {
if std::env::var("RUN_LLM_PROXY_INTEGRATION_TESTS")
.map(|v| v != "1" && !v.eq_ignore_ascii_case("true"))
.unwrap_or(true)
{
eprintln!(
"Skipping: set RUN_LLM_PROXY_INTEGRATION_TESTS=1 to run llm proxy integration tests"
);
return;
}
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "auth-token-value");
test_env.set("ANTHROPIC_API_KEY", "api-key-value");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let config = client.get_config("anthropic").unwrap();
assert_eq!(config.api_key.clone().unwrap(), "auth-token-value");
}
#[test]
fn test_error_handling() {
let client = LlmProxyClient::new("invalid-provider".to_string());
assert!(client.is_ok());
let client = client.unwrap();
assert!(client.get_config("non-existent").is_none());
assert!(client.get_effective_url("unsupported-provider").is_none());
assert!(!client.is_using_proxy("non-existent"));
}
#[tokio::test]
#[serial]
async fn test_concurrent_connectivity_tests() {
let mut test_env = TestEnv::new();
test_env.set("ANTHROPIC_BASE_URL", "https://api.z.ai/api/anthropic");
test_env.set("ANTHROPIC_AUTH_TOKEN", "test-token");
test_env.set("OPENROUTER_API_KEY", "test-token");
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let results = client.test_all_connectivity().await;
assert!(!results.is_empty());
for provider in client.configured_providers() {
assert!(results.contains_key(&provider));
}
}
#[tokio::test]
async fn test_timeout_configuration() {
let client = LlmProxyClient::new("anthropic".to_string()).unwrap();
let config = ProxyConfig::new(
"anthropic".to_string(),
"claude-3-sonnet-20240229".to_string(),
)
.with_base_url("https://httpbin.org/delay/10".to_string()) .with_timeout(Duration::from_millis(100))
.with_fallback(false);
let mut client = client;
client.configure(config);
let start = std::time::Instant::now();
let result = client.test_connectivity("anthropic").await;
let duration = start.elapsed();
assert!(duration < Duration::from_secs(5));
match result {
Ok(_) => println!("Unexpected success"),
Err(e) => println!("Expected timeout/error: {}", e),
}
}