diff --git a/litellm-rust/Cargo.lock b/litellm-rust/Cargo.lock index c868d3e4b8a..6b44d381dc7 100644 --- a/litellm-rust/Cargo.lock +++ b/litellm-rust/Cargo.lock @@ -2329,7 +2329,7 @@ dependencies = [ "hmac 0.13.0", "http 1.4.2", "jiff", - "reqwest 0.13.5", + "reqwest", "rustc_version", "rustls 0.23.42", "rustls-pki-types", @@ -2387,7 +2387,7 @@ dependencies = [ "pin-project", "prost", "prost-types", - "reqwest 0.13.5", + "reqwest", "rustc_version", "serde", "serde_json", @@ -2883,7 +2883,6 @@ dependencies = [ "tokio", "tokio-rustls 0.26.4", "tower-service", - "webpki-roots", ] [[package]] @@ -3376,7 +3375,7 @@ dependencies = [ "litellm-auth-types", "litellm-http", "moka", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -3460,7 +3459,7 @@ dependencies = [ "litellm-cache-response", "litellm-cache-testing", "litellm-http", - "reqwest 0.12.28", + "reqwest", "rstest", "serde_json", "tokio", @@ -3495,7 +3494,7 @@ dependencies = [ "litellm-cache-testing", "litellm-http", "percent-encoding", - "reqwest 0.12.28", + "reqwest", "rstest", "serde_json", "tokio", @@ -3522,7 +3521,7 @@ dependencies = [ "litellm-cache-testing", "litellm-http", "qdrant-client", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -3598,7 +3597,7 @@ dependencies = [ "litellm-cache", "litellm-cache-testing", "litellm-http", - "reqwest 0.12.28", + "reqwest", "rstest", "serde_json", "tokio", @@ -3945,9 +3944,7 @@ dependencies = [ "hyper-util", "litellm-core-utils", "rcgen", - "reqwest 0.12.28", - "reqwest 0.13.5", - "rmcp", + "reqwest", "rstest", "rustls 0.23.42", "rustls-native-certs", @@ -3980,7 +3977,7 @@ dependencies = [ "litellm-llms", "litellm-secrets", "litellm-tracing", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4039,7 +4036,7 @@ dependencies = [ "litellm-router-types", "litellm-secrets", "litellm-tracing", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4100,7 +4097,7 @@ dependencies = [ "litellm-llms-types", "litellm-secrets", "litellm-tracing", - "reqwest 0.12.28", + "reqwest", "rstest", "serde_json", "tokio", @@ -4163,7 +4160,7 @@ dependencies = [ "litellm-python-compat", "litellm-router-types", "litellm-secrets", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4245,7 +4242,7 @@ dependencies = [ "pyo3", "pyo3-async-runtimes", "redis", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4316,7 +4313,7 @@ dependencies = [ "litellm-secrets-hashicorp", "litellm-secrets-types", "moka", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4358,7 +4355,7 @@ dependencies = [ "litellm-http", "litellm-secrets-types", "percent-encoding", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4381,7 +4378,7 @@ dependencies = [ "moka", "percent-encoding", "rcgen", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4408,7 +4405,7 @@ dependencies = [ "litellm-secrets-types", "moka", "percent-encoding", - "reqwest 0.12.28", + "reqwest", "rstest", "serde", "serde_json", @@ -4496,7 +4493,7 @@ version = "0.1.0" dependencies = [ "flate2", "futures-util", - "reqwest 0.12.28", + "reqwest", "rstest", "semver", "serde", @@ -5869,49 +5866,6 @@ version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" -[[package]] -name = "reqwest" -version = "0.12.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "h2 0.4.15", - "http 1.4.2", - "http-body 1.1.0", - "http-body-util", - "hyper 1.10.1", - "hyper-rustls 0.27.9", - "hyper-util", - "js-sys", - "log", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls 0.23.42", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls 0.26.4", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.4.2", - "web-sys", - "webpki-roots", -] - [[package]] name = "reqwest" version = "0.13.5" @@ -5933,6 +5887,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "percent-encoding", "pin-project-lite", "quinn", @@ -5952,7 +5907,7 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams 0.5.0", + "wasm-streams", "web-sys", ] @@ -5999,7 +5954,7 @@ dependencies = [ "pin-project-lite", "process-wrap", "rand 0.10.2", - "reqwest 0.13.5", + "reqwest", "schemars 1.2.2", "serde", "serde_json", @@ -6122,7 +6077,7 @@ dependencies = [ "async-trait", "bytes", "http 1.4.2", - "reqwest 0.13.5", + "reqwest", "rustify_derive", "serde", "serde_json", @@ -7154,7 +7109,7 @@ dependencies = [ "memchr", "parse-display", "pin-project-lite", - "reqwest 0.13.5", + "reqwest", "serde", "serde_json", "serde_with", @@ -7793,7 +7748,7 @@ dependencies = [ "futures", "pin-project", "rand 0.10.2", - "reqwest 0.13.5", + "reqwest", "serde", "serde_json", "time", @@ -8007,7 +7962,7 @@ dependencies = [ "async-trait", "derive_builder", "http 1.4.2", - "reqwest 0.13.5", + "reqwest", "rustify", "rustify_derive", "serde", @@ -8154,19 +8109,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wasm-streams" version = "0.5.0" diff --git a/litellm-rust/Cargo.toml b/litellm-rust/Cargo.toml index 9e5e0a96b73..43ff3820bfa 100644 --- a/litellm-rust/Cargo.toml +++ b/litellm-rust/Cargo.toml @@ -87,7 +87,7 @@ pyo3-async-runtimes = { version = "0.29.0", features = ["tokio-runtime"] } rand = "0.8" macro_rules_attribute = "0.2.3" schemars = "1" -reqwest = { version = "0.12", default-features = false, features = ["json", "multipart", "rustls-tls", "http2", "stream"] } +reqwest = { version = "0.13", default-features = false, features = ["json", "multipart", "rustls", "http2", "stream", "query"] } qdrant-client = { version = "1.19.0", default-features = false } uuid = { version = "1", features = ["v4"] } rstest = "0.26.1" diff --git a/litellm-rust/clippy.toml b/litellm-rust/clippy.toml index 18663cfdffb..075e24a7849 100644 --- a/litellm-rust/clippy.toml +++ b/litellm-rust/clippy.toml @@ -10,8 +10,11 @@ disallowed-methods = [ { path = "reqwest::Client::new", reason = "take litellm_http::Client from HttpClientPool" }, { path = "reqwest::Client::builder", reason = "HttpClientConfig owns client construction" }, { path = "reqwest::ClientBuilder::danger_accept_invalid_certs", reason = "set HttpClientConfig::verify instead" }, + { path = "reqwest::ClientBuilder::tls_danger_accept_invalid_certs", reason = "set HttpClientConfig::verify instead" }, + { path = "reqwest::ClientBuilder::tls_danger_accept_invalid_hostnames", reason = "set HttpClientConfig::verify instead" }, { path = "reqwest::ClientBuilder::identity", reason = "set HttpClientConfig::client_certificate instead" }, { path = "reqwest::ClientBuilder::use_preconfigured_tls", reason = "HttpClientConfig owns the TLS configuration" }, + { path = "reqwest::ClientBuilder::tls_backend_preconfigured", reason = "HttpClientConfig owns the TLS configuration" }, { path = "sqlx::query", reason = "use sqlx::query! or query_file! so the SQL is checked against the migrated schema" }, { path = "sqlx::query_as", reason = "use sqlx::query_as! or query_file_as! so the SQL is checked against the migrated schema" }, { path = "sqlx::query_scalar", reason = "use sqlx::query_scalar! so the SQL is checked against the migrated schema" }, diff --git a/litellm-rust/crates/auth-aws/src/aws.rs b/litellm-rust/crates/auth-aws/src/aws.rs index 8fdbba21711..eaa033d631f 100644 --- a/litellm-rust/crates/auth-aws/src/aws.rs +++ b/litellm-rust/crates/auth-aws/src/aws.rs @@ -1080,7 +1080,7 @@ mod tests { &no_env, ) .await?; - let client = litellm_http::Client::plain_for_test(); + let client = litellm_http::Client::for_test(); let mut failures = Vec::new(); for region in ["us-west-2", "us-east-1"] { diff --git a/litellm-rust/crates/cache-azure-blob/tests/transport.rs b/litellm-rust/crates/cache-azure-blob/tests/transport.rs index c8b14cd8543..e600b15af0f 100644 --- a/litellm-rust/crates/cache-azure-blob/tests/transport.rs +++ b/litellm-rust/crates/cache-azure-blob/tests/transport.rs @@ -31,7 +31,7 @@ async fn connect(server: &MockServer) -> AzureBlobCache> { None, ClientOptions { transport: Some(Transport::new(Arc::new(ReqwestTransport( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), )))), ..ClientOptions::default() }, diff --git a/litellm-rust/crates/cache-gcs/tests/cache.rs b/litellm-rust/crates/cache-gcs/tests/cache.rs index 096b691ea16..3e92c3fca19 100644 --- a/litellm-rust/crates/cache-gcs/tests/cache.rs +++ b/litellm-rust/crates/cache-gcs/tests/cache.rs @@ -97,7 +97,7 @@ async fn cache_exposes_its_configuration(#[future(awt)] server: MockServer) { path_service_account: Some("/secrets/sa.json".into()), ..support::config(&server, Some("folder")) }, - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), litellm_cache::JsonCodec::::new(), ); assert_eq!(cache.bucket_name(), "bucket"); diff --git a/litellm-rust/crates/cache-gcs/tests/support/mod.rs b/litellm-rust/crates/cache-gcs/tests/support/mod.rs index beb9aa39d9c..99fb0270a74 100644 --- a/litellm-rust/crates/cache-gcs/tests/support/mod.rs +++ b/litellm-rust/crates/cache-gcs/tests/support/mod.rs @@ -29,7 +29,7 @@ pub fn cache_with_token( ) -> JsonGcsCache { GcsCache::with_token_source( config(server, gcs_path), - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), JsonCodec::new(), token, ) diff --git a/litellm-rust/crates/cache-qdrant-semantic/tests/embedder.rs b/litellm-rust/crates/cache-qdrant-semantic/tests/embedder.rs index 24e6e5eba3e..71fc986616e 100644 --- a/litellm-rust/crates/cache-qdrant-semantic/tests/embedder.rs +++ b/litellm-rust/crates/cache-qdrant-semantic/tests/embedder.rs @@ -108,7 +108,7 @@ fn config(base: String, timeout: Option) -> OpenAiEmbedderConfig { async fn posts_embeddings_request_and_parses_vector() { let server = TestHttpServer::response("200 OK", r#"{"data":[{"embedding":[0.1,0.2]}]}"#).await; let embedder = OpenAiEmbedder::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), config( format!("{}/", server.base_url()), Some(Duration::from_secs(1)), @@ -161,7 +161,7 @@ async fn status_timeout_and_body_errors_are_unavailable( let server = TestHttpServer::response_after(status, body, Duration::from_millis(delay_ms)).await; let embedder = OpenAiEmbedder::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), config(server.base_url(), timeout), ); assert_eq!(embedder.async_embed("hello", None).await, expected); @@ -170,7 +170,7 @@ async fn status_timeout_and_body_errors_are_unavailable( #[rstest] fn sync_embedding_is_unsupported() { let embedder = OpenAiEmbedder::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), config("http://127.0.0.1:9".to_owned(), None), ); assert_eq!( diff --git a/litellm-rust/crates/cache-response/tests/response.rs b/litellm-rust/crates/cache-response/tests/response.rs index 655fcb8a46a..86ddf4a72cd 100644 --- a/litellm-rust/crates/cache-response/tests/response.rs +++ b/litellm-rust/crates/cache-response/tests/response.rs @@ -768,7 +768,7 @@ async fn gcs() -> (wiremock::MockServer, Gcs) { path_service_account: None, endpoint: server.uri(), }, - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), litellm_cache_response::ResponseCacheCodec, Arc::new(litellm_cache_gcs::StaticTokenSource("token".into())), ))); diff --git a/litellm-rust/crates/cache-s3/tests/support/mod.rs b/litellm-rust/crates/cache-s3/tests/support/mod.rs index b628c1df431..7378dde21bf 100644 --- a/litellm-rust/crates/cache-s3/tests/support/mod.rs +++ b/litellm-rust/crates/cache-s3/tests/support/mod.rs @@ -34,7 +34,7 @@ pub fn config(endpoint: &str) -> S3CacheConfig { pub fn cache_with(config: S3CacheConfig, runtime: Handle) -> JsonS3Cache { S3Cache::new( config, - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), JsonCodec::new(), runtime, ) diff --git a/litellm-rust/crates/gateway-mcp/Cargo.toml b/litellm-rust/crates/gateway-mcp/Cargo.toml index 07706dcb6a4..1db5257448f 100644 --- a/litellm-rust/crates/gateway-mcp/Cargo.toml +++ b/litellm-rust/crates/gateway-mcp/Cargo.toml @@ -19,7 +19,7 @@ url.workspace = true moka.workspace = true sha2.workspace = true tower = { version = "0.5", features = ["util"] } -rmcp = { version = "=3.4.1", default-features = false, features = ["server", "client", "elicitation", "transport-streamable-http-server", "transport-streamable-http-client", "transport-child-process"] } +rmcp = { version = "=3.4.1", default-features = false, features = ["server", "client", "elicitation", "transport-streamable-http-server", "transport-streamable-http-client-reqwest", "transport-child-process"] } serde.workspace = true serde_json.workspace = true thiserror.workspace = true diff --git a/litellm-rust/crates/gateway/Cargo.toml b/litellm-rust/crates/gateway/Cargo.toml index 387bcd43231..c212816794f 100644 --- a/litellm-rust/crates/gateway/Cargo.toml +++ b/litellm-rust/crates/gateway/Cargo.toml @@ -19,7 +19,7 @@ litellm-gateway-auth.workspace = true litellm-gateway-ui.workspace = true litellm-auth-types.workspace = true litellm-config.workspace = true -litellm-http = { workspace = true, features = ["mcp"] } +litellm-http.workspace = true litellm-llms.workspace = true litellm-secrets.workspace = true litellm-tracing.workspace = true diff --git a/litellm-rust/crates/gateway/src/lib.rs b/litellm-rust/crates/gateway/src/lib.rs index 0b3aba81181..0c693738408 100644 --- a/litellm-rust/crates/gateway/src/lib.rs +++ b/litellm-rust/crates/gateway/src/lib.rs @@ -101,11 +101,11 @@ pub async fn build_mcp( Auth::from_config(config, secrets.clone()) .validate() .await?; - let client = pool.mcp_client(http)?; + let client = pool.client(http, ClientVariant::NoRedirect)?; Ok(Some( litellm_gateway_mcp::ConfiguredGateway::connect( &config.mcp_servers, - client, + (*client).clone(), secrets.as_ref(), shutdown, ) diff --git a/litellm-rust/crates/http/Cargo.toml b/litellm-rust/crates/http/Cargo.toml index 7d64467f2f7..3b46825ad9d 100644 --- a/litellm-rust/crates/http/Cargo.toml +++ b/litellm-rust/crates/http/Cargo.toml @@ -7,11 +7,8 @@ repository.workspace = true [features] test-support = [] -mcp = ["dep:rmcp", "dep:reqwest-mcp"] [dependencies] -rmcp = { version = "=3.4.1", default-features = false, features = ["client", "transport-streamable-http-client-reqwest"], optional = true } -reqwest-mcp = { package = "reqwest", version = "0.13.2", default-features = false, features = ["rustls-no-provider", "json", "stream", "http2"], optional = true } http.workspace = true litellm-core-utils.workspace = true hyper-util.workspace = true diff --git a/litellm-rust/crates/http/src/client.rs b/litellm-rust/crates/http/src/client.rs index 1f7017d083b..90a47ca9a74 100644 --- a/litellm-rust/crates/http/src/client.rs +++ b/litellm-rust/crates/http/src/client.rs @@ -1,5 +1,6 @@ use std::ops::Deref; +/// Only `HttpClientPool` builds one, so every client carries the resolved TLS, proxy and timeout settings. #[derive(Clone, Debug)] pub struct Client(reqwest::Client); @@ -9,17 +10,7 @@ impl Client { } #[cfg(any(test, feature = "test-support"))] - pub fn for_test(client: reqwest::Client) -> Self { - Self(client) - } - - #[cfg(any(test, feature = "test-support"))] - pub fn plain_for_test() -> Self { - Self(reqwest::Client::new()) - } - - #[cfg(any(test, feature = "test-support"))] - pub fn no_redirect_for_test() -> Self { + pub fn for_test() -> Self { Self( reqwest::Client::builder() .redirect(reqwest::redirect::Policy::none()) @@ -27,6 +18,11 @@ impl Client { .expect("a client without TLS or proxy settings builds"), ) } + + #[cfg(any(test, feature = "test-support"))] + pub fn wrap_for_test(client: reqwest::Client) -> Self { + Self(client) + } } impl Deref for Client { diff --git a/litellm-rust/crates/http/src/config.rs b/litellm-rust/crates/http/src/config.rs index 2f36784bc70..6a2d80e3f85 100644 --- a/litellm-rust/crates/http/src/config.rs +++ b/litellm-rust/crates/http/src/config.rs @@ -98,7 +98,7 @@ impl TryFrom<&HttpClientConfig> for reqwest::ClientBuilder { fn try_from(config: &HttpClientConfig) -> Result { let base = reqwest::Client::builder() - .use_preconfigured_tls(rustls::ClientConfig::try_from(config)?) + .tls_backend_preconfigured(rustls::ClientConfig::try_from(config)?) .connect_timeout(config.connect_timeout) .pool_idle_timeout(config.pool_idle_timeout); let with_keepalive = match config.tcp_keepalive { diff --git a/litellm-rust/crates/http/src/lib.rs b/litellm-rust/crates/http/src/lib.rs index d53da607d39..ef72420af9b 100644 --- a/litellm-rust/crates/http/src/lib.rs +++ b/litellm-rust/crates/http/src/lib.rs @@ -7,8 +7,6 @@ mod client; mod config; mod error; -#[cfg(feature = "mcp")] -mod mcp; pub mod media; pub mod outbound; mod pool; diff --git a/litellm-rust/crates/http/src/mcp.rs b/litellm-rust/crates/http/src/mcp.rs deleted file mode 100644 index 2b101fb9c98..00000000000 --- a/litellm-rust/crates/http/src/mcp.rs +++ /dev/null @@ -1,76 +0,0 @@ -use std::{ - collections::HashMap, - net::{IpAddr, Ipv4Addr}, - sync::{Mutex, PoisonError}, - time::{Duration, Instant}, -}; - -use crate::{Error, HttpClientConfig}; - -struct Entry { - client: reqwest_mcp::Client, - built_at: Instant, -} - -#[derive(Default)] -pub(super) struct Pool(Mutex>); - -impl Pool { - pub fn client( - &self, - config: &HttpClientConfig, - ttl: Duration, - ) -> Result { - let mut clients = self.0.lock().unwrap_or_else(PoisonError::into_inner); - if let Some(entry) = clients.get(config) - && entry.built_at.elapsed() < ttl - { - return Ok(entry.client.clone()); - } - let client = build(config)?; - clients.insert( - config.clone(), - Entry { - client: client.clone(), - built_at: Instant::now(), - }, - ); - Ok(client) - } -} - -fn build(config: &HttpClientConfig) -> Result { - let base = reqwest_mcp::Client::builder() - .tls_backend_preconfigured(rustls::ClientConfig::try_from(config)?) - .connect_timeout(config.connect_timeout) - .pool_idle_timeout(config.pool_idle_timeout) - .redirect(reqwest_mcp::redirect::Policy::none()); - let keepalive = match config.tcp_keepalive { - Some(value) => base - .tcp_keepalive(value.idle) - .tcp_keepalive_interval(value.interval) - .tcp_keepalive_retries(value.retries), - None => base, - }; - let address = if config.force_ipv4 { - keepalive.local_address(IpAddr::V4(Ipv4Addr::UNSPECIFIED)) - } else { - keepalive - }; - let protocol = if config.http2 { - address - } else { - address.http1_only() - }; - let agent = match &config.user_agent { - Some(value) => protocol.user_agent(value), - None => protocol, - }; - config - .proxies - .mcp_proxies() - .into_iter() - .fold(agent.no_proxy(), reqwest_mcp::ClientBuilder::proxy) - .build() - .map_err(|error| Error::Client(error.without_url().to_string())) -} diff --git a/litellm-rust/crates/http/src/media.rs b/litellm-rust/crates/http/src/media.rs index 22a881831cf..960a1d4044a 100644 --- a/litellm-rust/crates/http/src/media.rs +++ b/litellm-rust/crates/http/src/media.rs @@ -522,7 +522,7 @@ mod tests { b"HTTP/1.1 200 OK\r\nContent-Type: application/pdf; charset=binary\r\nContent-Length: 3\r\nConnection: close\r\n\r\nabc", ) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let media = MediaFetcher::for_test(client) .fetch(url, policy(3, 0)) .await @@ -538,7 +538,7 @@ mod tests { b"HTTP/1.1 200 OK\r\nContent-Type: application/pdf\r\nContent-Length: 3\r\nConnection: close\r\n\r\nabc", ) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let error = MediaFetcher::for_test(client) .fetch(url, policy(2, 0)) .await @@ -553,7 +553,7 @@ mod tests { b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\nConnection: close\r\n\r\n2\r\nab\r\n2\r\ncd\r\n0\r\n\r\n", ) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let error = MediaFetcher::for_test(client) .fetch(url, policy(3, 0)) .await diff --git a/litellm-rust/crates/http/src/pool.rs b/litellm-rust/crates/http/src/pool.rs index 78932f9e29f..dfcc9270fe9 100644 --- a/litellm-rust/crates/http/src/pool.rs +++ b/litellm-rust/crates/http/src/pool.rs @@ -29,8 +29,6 @@ pub struct HttpClientPool { media_resolver: Arc, ttl: Duration, clients: Mutex, - #[cfg(feature = "mcp")] - mcp: crate::mcp::Pool, } impl HttpClientPool { @@ -43,19 +41,9 @@ impl HttpClientPool { media_resolver, ttl, clients: Mutex::default(), - #[cfg(feature = "mcp")] - mcp: crate::mcp::Pool::default(), } } - #[cfg(feature = "mcp")] - pub fn mcp_client( - &self, - config: &HttpClientConfig, - ) -> Result { - self.mcp.client(config, self.ttl) - } - pub fn client( &self, config: &HttpClientConfig, @@ -108,7 +96,7 @@ impl HttpClientPool { } ClientVariant::Media => builder .redirect(reqwest::redirect::Policy::none()) - .dns_resolver2(Arc::clone(&self.media_resolver)), + .dns_resolver(Arc::clone(&self.media_resolver)), } } } @@ -390,56 +378,4 @@ mod tests { .is_err() ); } - #[cfg(feature = "mcp")] - #[rstest::rstest] - #[tokio::test] - async fn mcp_clients_reuse_connections_and_apply_proxy_headers_without_redirects() { - let (address, connections, requests) = serve("HTTP/1.1 302 Found").await; - let pool = pool(); - let config = HttpClientConfig { - proxies: proxied_through(&format!("http://{address}")), - ..config("mcp-pool-test") - }; - for _ in 0..2 { - let response = pool - .mcp - .client(&config, pool.ttl) - .unwrap() - .get("http://upstream.invalid/mcp") - .timeout(Duration::from_secs(2)) - .send() - .await - .unwrap(); - assert_eq!(response.status(), 302); - response.bytes().await.unwrap(); - } - assert_eq!(connections.load(Ordering::SeqCst), 1); - let requests = requests.lock().unwrap(); - assert_eq!(requests.len(), 2); - assert!( - requests - .iter() - .all(|request| request.starts_with("GET http://upstream.invalid/mcp HTTP/1.1")) - ); - assert!( - requests - .iter() - .all(|request| request.contains("user-agent: mcp-pool-test")) - ); - } - - #[cfg(feature = "mcp")] - #[rstest::rstest] - #[tokio::test] - async fn mcp_client_uses_host_tls_configuration() { - let directory = tempfile::tempdir().unwrap(); - let config = HttpClientConfig { - verify: Verify::CaBundle(directory.path().join("missing.pem")), - ..config("mcp-test") - }; - assert!(matches!( - pool().mcp_client(&config), - Err(Error::Read { .. }) - )); - } } diff --git a/litellm-rust/crates/http/src/proxy.rs b/litellm-rust/crates/http/src/proxy.rs index e7e54ed6ae2..eb960d8200d 100644 --- a/litellm-rust/crates/http/src/proxy.rs +++ b/litellm-rust/crates/http/src/proxy.rs @@ -63,19 +63,6 @@ impl EnvironmentProxies { .map(|proxy| proxy.no_proxy(no_proxy.clone())) .collect() } - #[cfg(feature = "mcp")] - pub(crate) fn mcp_proxies(&self) -> Vec { - let no_proxy = reqwest_mcp::NoProxy::from_string(&self.no); - [ - reqwest_mcp::Proxy::http(self.http.as_str()), - reqwest_mcp::Proxy::https(self.https.as_str()), - reqwest_mcp::Proxy::all(self.all.as_str()), - ] - .into_iter() - .filter_map(Result::ok) - .map(|proxy| proxy.no_proxy(no_proxy.clone())) - .collect() - } } #[cfg(test)] diff --git a/litellm-rust/crates/inference-chat/src/handler.rs b/litellm-rust/crates/inference-chat/src/handler.rs index 595e851c6fd..c52ff19ac08 100644 --- a/litellm-rust/crates/inference-chat/src/handler.rs +++ b/litellm-rust/crates/inference-chat/src/handler.rs @@ -283,7 +283,7 @@ mod tests { let (provider, config, request) = prepared(&upstream.uri()); execute( - &Client::plain_for_test(), + &Client::for_test(), &AuthServices::default(), config, provider, @@ -328,7 +328,7 @@ mod tests { let (provider, config, request) = prepared(&upstream.uri()); let error = execute( - &Client::plain_for_test(), + &Client::for_test(), &AuthServices::default(), config, provider, diff --git a/litellm-rust/crates/inference-chat/tests/caching.rs b/litellm-rust/crates/inference-chat/tests/caching.rs index 70da8bc3255..4b3e32f04bc 100644 --- a/litellm-rust/crates/inference-chat/tests/caching.rs +++ b/litellm-rust/crates/inference-chat/tests/caching.rs @@ -239,7 +239,7 @@ async fn chat_cache_identity_follows_resolved_configuration_and_request_callback .store(usize::from(call >= 2), Ordering::SeqCst); let cache = ScopedCache::new(cache.clone(), CacheScope::Shared); ChatCompletionsRoute::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), Arc::new(Default::default()), secrets.clone(), ) diff --git a/litellm-rust/crates/inference-messages/src/handler.rs b/litellm-rust/crates/inference-messages/src/handler.rs index 55c80d9bddf..8b6154ecbee 100644 --- a/litellm-rust/crates/inference-messages/src/handler.rs +++ b/litellm-rust/crates/inference-messages/src/handler.rs @@ -888,7 +888,7 @@ mod tests { .respond_with(ResponseTemplate::new(200).set_body_raw(body, "text/event-stream")) .mount(&upstream) .await; - let response = litellm_http::Client::plain_for_test() + let response = litellm_http::Client::for_test() .get(upstream.uri()) .send() .await diff --git a/litellm-rust/crates/inference-ocr/src/handler.rs b/litellm-rust/crates/inference-ocr/src/handler.rs index e9cfc9a8989..426d4297f28 100644 --- a/litellm-rust/crates/inference-ocr/src/handler.rs +++ b/litellm-rust/crates/inference-ocr/src/handler.rs @@ -121,11 +121,7 @@ mod tests { }; fn client() -> OcrClient { - OcrClient::for_test( - litellm_http::Client::plain_for_test(), - litellm_http::Client::no_redirect_for_test(), - ) - .with_secrets(litellm_inference_testing::no_secrets()) + OcrClient::for_test().with_secrets(litellm_inference_testing::no_secrets()) } fn request(model: &str, base: &str, document: Value, options: Value) -> LiteLLMOcrRequest { diff --git a/litellm-rust/crates/llms/src/base_llm/ocr/document.rs b/litellm-rust/crates/llms/src/base_llm/ocr/document.rs index b32ea4bf73a..57976240e1b 100644 --- a/litellm-rust/crates/llms/src/base_llm/ocr/document.rs +++ b/litellm-rust/crates/llms/src/base_llm/ocr/document.rs @@ -190,16 +190,14 @@ mod tests { clippy::disallowed_types, reason = "the pool has no default-header setting to stand in for provider credentials" )] - let provider_http = litellm_http::Client::for_test( + let provider_http = litellm_http::Client::wrap_for_test( reqwest::Client::builder() .default_headers(provider_headers) .build() .unwrap(), ); - let client = crate::base_llm::ocr::handler::OcrClient::for_test( - provider_http, - litellm_http::Client::no_redirect_for_test(), - ); + let client = + crate::base_llm::ocr::handler::OcrClient::for_test().with_provider_http(provider_http); let converted = inline_remote_document( client.document_fetcher(), OcrDocument::ImageUrl { diff --git a/litellm-rust/crates/llms/src/base_llm/ocr/handler.rs b/litellm-rust/crates/llms/src/base_llm/ocr/handler.rs index 2cf955ff0c6..21ad4ea8025 100644 --- a/litellm-rust/crates/llms/src/base_llm/ocr/handler.rs +++ b/litellm-rust/crates/llms/src/base_llm/ocr/handler.rs @@ -86,21 +86,27 @@ impl OcrClient { } #[cfg(any(test, feature = "test-support"))] - pub fn for_test(provider_http: Client, no_redirect_http: Client) -> Self { + pub fn for_test() -> Self { Self { secrets: Arc::new( - litellm_secrets::source::EnvironmentSecrets::python_compatible( - provider_http.clone(), - ), + litellm_secrets::source::EnvironmentSecrets::python_compatible(Client::for_test()), ), - provider_http, - polling_http: no_redirect_http.clone(), - document_fetcher: MediaFetcher::for_test(no_redirect_http), + provider_http: Client::for_test(), + polling_http: Client::for_test(), + document_fetcher: MediaFetcher::for_test(Client::for_test()), auth: Arc::new(AuthServices::default()), settings: OcrSettings::default(), } } + #[cfg(any(test, feature = "test-support"))] + pub fn with_provider_http(self, provider_http: Client) -> Self { + Self { + provider_http, + ..self + } + } + #[cfg(any(test, feature = "test-support"))] pub fn with_settings(self, settings: OcrSettings) -> Self { Self { settings, ..self } @@ -322,7 +328,7 @@ mod tests { let _connection = listener.accept().await.unwrap(); tokio::time::sleep(Duration::from_secs(1)).await; }); - let error = litellm_http::Client::plain_for_test() + let error = litellm_http::Client::for_test() .get(format!("http://{address}")) .timeout(Duration::from_millis(10)) .send() @@ -347,7 +353,7 @@ mod tests { socket.write_all(response.as_bytes()).await.unwrap(); std::future::pending::<()>().await; }); - let response = litellm_http::Client::plain_for_test() + let response = litellm_http::Client::for_test() .get(format!("http://{address}")) .send() .await diff --git a/litellm-rust/crates/llms/src/reducto/ocr/transformation.rs b/litellm-rust/crates/llms/src/reducto/ocr/transformation.rs index 1979b442936..9b991b75e5b 100644 --- a/litellm-rust/crates/llms/src/reducto/ocr/transformation.rs +++ b/litellm-rust/crates/llms/src/reducto/ocr/transformation.rs @@ -566,10 +566,7 @@ mod tests { let params = ReductoParseV3Config .map_ocr_params(&overrides, "parse-v3") .unwrap(); - let client = OcrClient::for_test( - litellm_http::Client::plain_for_test(), - litellm_http::Client::no_redirect_for_test(), - ); + let client = OcrClient::for_test(); let connection = OcrConnection::default(); let document = serde_json::from_value( json!({"type":"document_url","document_url":"reducto://ready.pdf"}), diff --git a/litellm-rust/crates/python-bridge/src/secrets/callback.rs b/litellm-rust/crates/python-bridge/src/secrets/callback.rs index 71a06bfdc39..669c10e602a 100644 --- a/litellm-rust/crates/python-bridge/src/secrets/callback.rs +++ b/litellm-rust/crates/python-bridge/src/secrets/callback.rs @@ -192,7 +192,7 @@ handler.get_secret_from_manager = get_secret_from_manager KeyManagementSettings::default(), )), Arc::new(move |_: &str| fallback.map(str::to_owned)), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ) .with_failure_policy(FailurePolicy::EnvironmentFallback); (resolver, locals, handler) diff --git a/litellm-rust/crates/python-bridge/src/secrets/resolved.rs b/litellm-rust/crates/python-bridge/src/secrets/resolved.rs index 5a606ab1039..deb07175e7a 100644 --- a/litellm-rust/crates/python-bridge/src/secrets/resolved.rs +++ b/litellm-rust/crates/python-bridge/src/secrets/resolved.rs @@ -84,7 +84,7 @@ mod tests { } async fn resolve(state: Arc, name: &'static str) -> Option { - ResolvedSecrets::from_state(state, litellm_http::Client::plain_for_test()) + ResolvedSecrets::from_state(state, litellm_http::Client::for_test()) .resolve(&[name]) .await .unwrap() @@ -182,7 +182,7 @@ mod tests { .await; let source = ResolvedSecrets::from_state( state(&server, KeyManagementSettings::default()), - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), ); let snapshot = source.resolve(&[declared]).await.unwrap(); assert_eq!(snapshot.get(undeclared), None); @@ -248,7 +248,7 @@ mod tests { async fn oidc_failures_are_not_converted_to_missing_secrets() { let result = ResolvedSecrets::from_state( Arc::new(SecretManagerState::default()), - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), ) .resolve(&["oidc/"]) .await; diff --git a/litellm-rust/crates/secrets-azure/tests/key_vault.rs b/litellm-rust/crates/secrets-azure/tests/key_vault.rs index fcbc46092e1..05f62d25dce 100644 --- a/litellm-rust/crates/secrets-azure/tests/key_vault.rs +++ b/litellm-rust/crates/secrets-azure/tests/key_vault.rs @@ -11,7 +11,7 @@ use wiremock::{ fn manager(server: &MockServer) -> AzureKeyVault { AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), Arc::new(|name: &str| (name == "AZURE_AD_TOKEN").then(|| "fake".to_owned())), ) @@ -131,7 +131,7 @@ fn new_validates_vault_environment( #[case] missing_environment: bool, ) { let result = AzureKeyVault::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), Arc::new(move |name: &str| { (name == "AZURE_KEY_VAULT_URI") .then(|| uri.map(str::to_owned)) @@ -158,7 +158,7 @@ fn new_validates_vault_environment( #[case::local("http://localhost:8080", "https://localhost/.default")] fn derives_scope_from_vault_host(#[case] uri: &str, #[case] expected: &str) { let manager = AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), uri.parse().unwrap(), Arc::new(|_: &str| None), ) @@ -187,7 +187,7 @@ async fn missing_credentials_do_not_request_vault() { fn manager_without_credentials(server: &MockServer) -> AzureKeyVault { AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), Arc::new(|name: &str| { (name == "AZURE_CREDENTIAL").then(|| "ClientSecretCredential".to_owned()) diff --git a/litellm-rust/crates/secrets-azure/tests/live.rs b/litellm-rust/crates/secrets-azure/tests/live.rs index 429cd3013f7..d7713dc798d 100644 --- a/litellm-rust/crates/secrets-azure/tests/live.rs +++ b/litellm-rust/crates/secrets-azure/tests/live.rs @@ -10,7 +10,7 @@ use rstest::rstest; #[ignore] async fn reads_a_real_secret() { let environment = Arc::new(ProcessEnvironment); - let manager = AzureKeyVault::new(litellm_http::Client::plain_for_test(), environment).unwrap(); + let manager = AzureKeyVault::new(litellm_http::Client::for_test(), environment).unwrap(); let name = std::env::var("AZURE_KEY_VAULT_LIVE_SECRET_NAME").unwrap(); let secret = manager.get_secret(&name).await.unwrap().unwrap(); assert!(matches!(&secret, Secret::String(_))); diff --git a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/configuration.rs b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/configuration.rs index 1bea77e49ae..a3c20a0db3d 100644 --- a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/configuration.rs +++ b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/configuration.rs @@ -77,7 +77,7 @@ async fn authentication_encodes_login(#[case] username: &str, #[case] expected_p .mount(&server) .await; let manager = CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "acct".into(), username.into(), @@ -433,7 +433,7 @@ async fn trailing_slash_endpoint_preserves_base_path() { .await; let endpoint = format!("{}/prefix/", server.uri()).parse().unwrap(); let manager = CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), endpoint, "acct".into(), "admin".into(), diff --git a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/support.rs b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/support.rs index 6fa15ecba9b..d7bc71b6503 100644 --- a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/support.rs +++ b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/support.rs @@ -62,7 +62,7 @@ pub(super) fn from_environment( pub(super) fn manager(server: &MockServer, ttl: Duration) -> CyberArkSecretManager { CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "acct".into(), "admin".into(), diff --git a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/writes.rs b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/writes.rs index 764a591bc71..3db8b6355e1 100644 --- a/litellm-rust/crates/secrets-cyberark/tests/secret_manager/writes.rs +++ b/litellm-rust/crates/secrets-cyberark/tests/secret_manager/writes.rs @@ -233,7 +233,7 @@ async fn writes_match_python_parity_fixture(parity_fixture: ParityFixture) { .mount(&server) .await; let manager = CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), parity_fixture.account, parity_fixture.username, @@ -297,7 +297,7 @@ async fn live_conjur_round_trip() { .as_nanos() ); let manager = CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), endpoint.clone(), account.clone(), username.clone(), @@ -312,7 +312,7 @@ async fn live_conjur_round_trip() { .await .unwrap(); let verifier = CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), endpoint.clone(), account.clone(), username.clone(), diff --git a/litellm-rust/crates/secrets-google/tests/secret_manager.rs b/litellm-rust/crates/secrets-google/tests/secret_manager.rs index e9bee7633f5..f2cb5ff3603 100644 --- a/litellm-rust/crates/secrets-google/tests/secret_manager.rs +++ b/litellm-rust/crates/secrets-google/tests/secret_manager.rs @@ -11,7 +11,7 @@ use wiremock::{ fn manager(server: &MockServer, always_read: bool, ttl: Duration) -> GoogleSecretManager { GoogleSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "project".into(), Arc::new(|name: &str| (name == "VERTEX_AI_API_KEY").then(|| "token".into())), @@ -215,7 +215,7 @@ async fn always_read_and_expired_cache_fetch_again( fn google_manager_requires_host_license_and_project_configuration() { assert!(matches!( GoogleSecretManager::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), Arc::new(|_: &str| None), false ), @@ -223,7 +223,7 @@ fn google_manager_requires_host_license_and_project_configuration() { )); assert!(matches!( GoogleSecretManager::new( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), Arc::new(|_: &str| None), true ), @@ -244,7 +244,7 @@ fn google_manager_rejects_invalid_refresh_intervals(#[case] variable: &'static s }); assert!(matches!( - GoogleSecretManager::new(litellm_http::Client::plain_for_test(), environment, true), + GoogleSecretManager::new(litellm_http::Client::for_test(), environment, true), Err(Error::RefreshInterval) )); } diff --git a/litellm-rust/crates/secrets/tests/aws.rs b/litellm-rust/crates/secrets/tests/aws.rs index 910b1855b77..f28f404c3ff 100644 --- a/litellm-rust/crates/secrets/tests/aws.rs +++ b/litellm-rust/crates/secrets/tests/aws.rs @@ -53,7 +53,7 @@ async fn read_results_follow_the_selected_failure_policy( }, )), Arc::new(move |_: &str| environment.map(str::to_owned)), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ) .with_failure_policy(policy); let result = resolver @@ -97,7 +97,7 @@ async fn primary_secret_values_other_than_strings_resolve_to_none( let resolver = SecretResolver::new_python_compatible( Arc::new(state(&server, settings)), Arc::new(|_: &str| Some("fallback".into())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); let text = value.as_str(); assert_eq!( @@ -157,7 +157,7 @@ async fn gating_prediction_matches_actual_lookup( let resolver = SecretResolver::new_python_compatible( Arc::new(state), Arc::new(|_: &str| Some("environment".into())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver diff --git a/litellm-rust/crates/secrets/tests/azure.rs b/litellm-rust/crates/secrets/tests/azure.rs index 60f165add54..6e81017b0f6 100644 --- a/litellm-rust/crates/secrets/tests/azure.rs +++ b/litellm-rust/crates/secrets/tests/azure.rs @@ -22,7 +22,7 @@ async fn azure_handler_reads_missing_and_failed_secrets() { .await; let manager = SecretManager::AzureKeyVault( AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), std::sync::Arc::new(|name: &str| (name == "AZURE_AD_TOKEN").then(|| "fake".to_owned())), ) @@ -81,7 +81,7 @@ async fn successful_azure_responses_do_not_fall_back_when_the_value_is_empty_or_ .mount(&server) .await; let manager = AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), Arc::new(|name: &str| (name == "AZURE_AD_TOKEN").then(|| "token".into())), ) @@ -92,7 +92,7 @@ async fn successful_azure_responses_do_not_fall_back_when_the_value_is_empty_or_ Default::default(), )), Arc::new(|_: &str| Some("environment".into())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver diff --git a/litellm-rust/crates/secrets/tests/common_read_contract.rs b/litellm-rust/crates/secrets/tests/common_read_contract.rs index 2e8fbf46008..e6928038799 100644 --- a/litellm-rust/crates/secrets/tests/common_read_contract.rs +++ b/litellm-rust/crates/secrets/tests/common_read_contract.rs @@ -59,7 +59,7 @@ fn manager(provider: Provider, server: &MockServer) -> SecretManager { ), Provider::Azure => SecretManager::AzureKeyVault( AzureKeyVault::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), environment, ) @@ -67,7 +67,7 @@ fn manager(provider: Provider, server: &MockServer) -> SecretManager { ), Provider::Google => SecretManager::GoogleSecretManager( GoogleSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "project".into(), environment, @@ -84,7 +84,7 @@ fn manager(provider: Provider, server: &MockServer) -> SecretManager { .unwrap(), ), Provider::Cyberark => SecretManager::Cyberark(CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "acct".into(), "admin".into(), @@ -240,7 +240,7 @@ async fn python_read_failures_preserve_provider_fallback_rules( KeyManagementSettings::default(), )), Arc::new(move |_: &str| environment_value.map(str::to_owned)), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); let expected = if matches!(provider, Provider::Aws) { None diff --git a/litellm-rust/crates/secrets/tests/cyberark.rs b/litellm-rust/crates/secrets/tests/cyberark.rs index b94bd9dc0ad..0a6c394937e 100644 --- a/litellm-rust/crates/secrets/tests/cyberark.rs +++ b/litellm-rust/crates/secrets/tests/cyberark.rs @@ -24,7 +24,7 @@ async fn cyberark_handler_reads_values_and_surfaces_errors() { .mount(&server) .await; let manager = SecretManager::Cyberark(CyberArkSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "acct".into(), "admin".into(), diff --git a/litellm-rust/crates/secrets/tests/google.rs b/litellm-rust/crates/secrets/tests/google.rs index 0b45a90c10b..fa1db9916e8 100644 --- a/litellm-rust/crates/secrets/tests/google.rs +++ b/litellm-rust/crates/secrets/tests/google.rs @@ -25,7 +25,7 @@ async fn google_resolver_distinguishes_absence_from_failure(#[case] status: u16) _ => None, }); let manager = GoogleSecretManager::with_client( - litellm_http::Client::plain_for_test(), + litellm_http::Client::for_test(), server.uri().parse().unwrap(), "project".into(), environment.clone(), @@ -40,7 +40,7 @@ async fn google_resolver_distinguishes_absence_from_failure(#[case] status: u16) let resolver = SecretResolver::new_python_compatible( Arc::new(state), environment, - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ) .with_failure_policy(FailurePolicy::Propagate); let result = resolver.get_secret_str("KEY", None).await; diff --git a/litellm-rust/crates/secrets/tests/hashicorp.rs b/litellm-rust/crates/secrets/tests/hashicorp.rs index e10e903c25a..bfb289cdb97 100644 --- a/litellm-rust/crates/secrets/tests/hashicorp.rs +++ b/litellm-rust/crates/secrets/tests/hashicorp.rs @@ -56,7 +56,7 @@ async fn hashicorp_handler_resolves_found_missing_and_failed_values() { }, )), Arc::new(|_: &str| None), - litellm_secrets::OidcResolver::new(litellm_http::Client::plain_for_test()), + litellm_secrets::OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( found_resolver @@ -131,7 +131,7 @@ async fn hashicorp_handler_resolves_found_missing_and_failed_values() { let failed_resolver = SecretResolver::new_python_compatible( Arc::new(failed_state), Arc::new(|_: &str| None), - litellm_secrets::OidcResolver::new(litellm_http::Client::plain_for_test()), + litellm_secrets::OidcResolver::new(litellm_http::Client::for_test()), ) .with_failure_policy(FailurePolicy::Propagate); assert!(matches!( diff --git a/litellm-rust/crates/secrets/tests/oidc.rs b/litellm-rust/crates/secrets/tests/oidc.rs index 6f72bd9d645..867a662cbbb 100644 --- a/litellm-rust/crates/secrets/tests/oidc.rs +++ b/litellm-rust/crates/secrets/tests/oidc.rs @@ -30,7 +30,7 @@ async fn environment_sources_resolve_expected_value( ("CIRCLE_OIDC_TOKEN_V2", "circle-v2"), ]); assert_eq!( - OidcResolver::new(litellm_http::Client::plain_for_test()) + OidcResolver::new(litellm_http::Client::for_test()) .resolve(reference, env.as_ref()) .await .unwrap() @@ -43,7 +43,7 @@ async fn environment_sources_resolve_expected_value( #[tokio::test] async fn environment_sources_bypass_boolean_conversion_and_defaults() { let env = environment(&[("TOKEN", "true")]); - let oidc = OidcResolver::new(litellm_http::Client::plain_for_test()); + let oidc = OidcResolver::new(litellm_http::Client::for_test()); let resolver = SecretResolver::new(Arc::new(SecretManagerState::default()), env, oidc); assert_eq!( resolver @@ -94,7 +94,7 @@ async fn github_requests_are_authenticated_cached_and_revalidate_environment() { ), ("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "request-token"), ]); - let oidc = OidcResolver::new(litellm_http::Client::plain_for_test()); + let oidc = OidcResolver::new(litellm_http::Client::for_test()); for _ in 0..2 { assert_eq!( oidc.resolve("oidc/github/https://service/oidc/path", env.as_ref()) @@ -131,7 +131,7 @@ async fn file_allowlist_resolves_symlinks_while_environment_paths_remain_explici ("PATH_TOKEN", private.to_str().unwrap()), ("AZURE_FEDERATED_TOKEN_FILE", token.to_str().unwrap()), ]); - let oidc = OidcResolver::new(litellm_http::Client::plain_for_test()); + let oidc = OidcResolver::new(litellm_http::Client::for_test()); assert_eq!( oidc.resolve(&format!("oidc/file/{}", token.display()), env.as_ref()) .await @@ -213,7 +213,7 @@ async fn google_expiry_caps_cache_and_preserves_audience( .expect(calls) .mount(&server) .await; - let oidc = OidcResolver::new(litellm_http::Client::plain_for_test()) + let oidc = OidcResolver::new(litellm_http::Client::for_test()) .with_google_identity_endpoint(server.uri().parse().unwrap()) .with_clock(now); for _ in 0..2 { @@ -235,7 +235,7 @@ async fn google_expiry_caps_cache_and_preserves_audience( #[tokio::test] async fn google_oidc_requires_its_build_feature() { assert!(matches!( - OidcResolver::new(litellm_http::Client::plain_for_test()) + OidcResolver::new(litellm_http::Client::for_test()) .resolve("oidc/google/audience", environment(&[]).as_ref()) .await, Err(Error::UnsupportedOidc) @@ -246,7 +246,7 @@ async fn google_oidc_requires_its_build_feature() { #[tokio::test] async fn azure_oidc_without_a_token_file_requires_its_build_feature() { assert!(matches!( - OidcResolver::new(litellm_http::Client::plain_for_test()) + OidcResolver::new(litellm_http::Client::for_test()) .resolve("oidc/azure/scope", environment(&[]).as_ref()) .await, Err(Error::UnsupportedOidc) @@ -262,7 +262,7 @@ async fn invalid_references_fail_before_environment_lookup( #[case] reference: &str, #[case] unsupported: bool, ) { - let error = OidcResolver::new(litellm_http::Client::plain_for_test()) + let error = OidcResolver::new(litellm_http::Client::for_test()) .resolve(reference, &|_: &str| { panic!("invalid reference reached environment lookup") }) @@ -284,7 +284,7 @@ async fn unreadable_expiry_keeps_python_cache_fallback(#[case] token: &str) { .expect(1) .mount(&server) .await; - let resolver = OidcResolver::new(litellm_http::Client::plain_for_test()) + let resolver = OidcResolver::new(litellm_http::Client::for_test()) .with_google_identity_endpoint(server.uri().parse().unwrap()); for _ in 0..2 { assert_eq!( @@ -336,7 +336,7 @@ async fn azure_oidc_acquires_the_requested_scope_and_preserves_failures(#[case] }) } } - let oidc = OidcResolver::new(litellm_http::Client::plain_for_test()) + let oidc = OidcResolver::new(litellm_http::Client::for_test()) .with_azure_token_provider(Arc::new(Provider(failed))); let resolver = SecretResolver::new_python_compatible( Arc::new(SecretManagerState::default()), @@ -364,7 +364,7 @@ async fn azure_oidc_acquires_the_requested_scope_and_preserves_failures(#[case] #[tokio::test] async fn missing_oidc_environment_is_an_error(#[case] reference: &str) { assert!(matches!( - OidcResolver::new(litellm_http::Client::plain_for_test()) + OidcResolver::new(litellm_http::Client::for_test()) .resolve(reference, environment(&[]).as_ref()) .await, Err(Error::MissingEnvironment) @@ -383,7 +383,7 @@ async fn google_oidc_failures_are_not_cached_or_hidden_by_defaults() { let resolver = SecretResolver::new_python_compatible( Arc::new(SecretManagerState::default()), environment(&[]), - OidcResolver::new(litellm_http::Client::plain_for_test()) + OidcResolver::new(litellm_http::Client::for_test()) .with_google_identity_endpoint(server.uri().parse().unwrap()), ); for _ in 0..2 { @@ -424,7 +424,7 @@ async fn google_tokens_expire_at_the_python_cache_deadline( .expect(2) .mount(&server) .await; - let resolver = OidcResolver::new(litellm_http::Client::plain_for_test()) + let resolver = OidcResolver::new(litellm_http::Client::for_test()) .with_google_identity_endpoint(server.uri().parse().unwrap()) .with_clock(|| UNIX_EPOCH + Duration::from_secs(1000)); assert_eq!( @@ -477,7 +477,7 @@ async fn google_cache_uses_payload_expiry_without_requiring_a_jwt_header() { .expect(2) .mount(&server) .await; - let resolver = OidcResolver::new(litellm_http::Client::plain_for_test()) + let resolver = OidcResolver::new(litellm_http::Client::for_test()) .with_google_identity_endpoint(server.uri().parse().unwrap()) .with_clock(|| UNIX_EPOCH + Duration::from_secs(1000)); for _ in 0..2 { diff --git a/litellm-rust/crates/secrets/tests/resolution.rs b/litellm-rust/crates/secrets/tests/resolution.rs index 37557c36fb5..0858089b94f 100644 --- a/litellm-rust/crates/secrets/tests/resolution.rs +++ b/litellm-rust/crates/secrets/tests/resolution.rs @@ -12,7 +12,7 @@ fn resolver(value: Option<&str>) -> SecretResolver { SecretResolver::new_python_compatible( Arc::new(SecretManagerState::default()), Arc::new(move |_: &str| value.clone()), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ) } @@ -35,7 +35,7 @@ async fn native_reads_preserve_strings_and_report_conversion_errors(#[case] mana let resolver = SecretResolver::new( Arc::new(state), Arc::new(move |_: &str| Some(raw.to_owned())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver @@ -75,7 +75,7 @@ async fn native_defaults_apply_to_absence_but_never_hide_provider_failures() { KeyManagementSettings::default(), )), Arc::new(|_: &str| None), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); let result = resolver .get_secret_str("key", Some(SecretValue::new("default"))) @@ -189,7 +189,7 @@ fn managed(reply: Result, ()>, environment: Option<&'static str>) KeyManagementSettings::default(), )), Arc::new(move |_: &str| environment.map(str::to_owned)), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ) .with_failure_policy(FailurePolicy::EnvironmentFallback) } @@ -281,7 +281,7 @@ async fn prefix_is_removed_once_and_resolved_from_environment() { let resolver = SecretResolver::new_python_compatible( Arc::new(state), Arc::new(|name: &str| (name == "os.environ/KEY").then(|| "value".into())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver @@ -340,7 +340,7 @@ async fn excluded_hosted_keys_keep_the_python_manager_conversion_path( }, )), Arc::new(move |_: &str| Some(raw.to_owned())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver.get_secret("KEY", None).await.unwrap(), @@ -373,7 +373,7 @@ async fn azure_callback_absence_preserves_none_but_errors_fall_back( KeyManagementSettings::default(), )), Arc::new(|_: &str| Some("environment".into())), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); assert_eq!( resolver diff --git a/litellm-rust/crates/secrets/tests/source.rs b/litellm-rust/crates/secrets/tests/source.rs index 17210940a67..41f0ecea518 100644 --- a/litellm-rust/crates/secrets/tests/source.rs +++ b/litellm-rust/crates/secrets/tests/source.rs @@ -15,7 +15,7 @@ mod tests { #[case] expected: Option<&str>, ) { unsafe { std::env::set_var(name, value) }; - let secret = EnvironmentSecrets::python_compatible(litellm_http::Client::plain_for_test()) + let secret = EnvironmentSecrets::python_compatible(litellm_http::Client::for_test()) .resolve(&[name]) .await .unwrap() @@ -42,7 +42,7 @@ async fn dynamic_names_use_the_same_resolver_and_snapshots_never_do_fresh_lookup reads.fetch_add(1, Ordering::SeqCst); (name != "missing").then(|| name.to_owned()) }), - OidcResolver::new(litellm_http::Client::plain_for_test()), + OidcResolver::new(litellm_http::Client::for_test()), ); let snapshot = source.resolve(&["declared", "missing"]).await.unwrap(); let name = format!("runtime-{}", "key"); diff --git a/litellm-rust/crates/spend-clickhouse/tests/storage.rs b/litellm-rust/crates/spend-clickhouse/tests/storage.rs index 2b3eb75c658..81b6527f9e1 100644 --- a/litellm-rust/crates/spend-clickhouse/tests/storage.rs +++ b/litellm-rust/crates/spend-clickhouse/tests/storage.rs @@ -77,7 +77,7 @@ async fn database() -> Database { 7, ) .unwrap(), - client: Client::no_redirect_for_test(), + client: Client::for_test(), } } diff --git a/litellm-rust/crates/spend-clickhouse/tests/transport.rs b/litellm-rust/crates/spend-clickhouse/tests/transport.rs index ffc3423f65e..49a4b365135 100644 --- a/litellm-rust/crates/spend-clickhouse/tests/transport.rs +++ b/litellm-rust/crates/spend-clickhouse/tests/transport.rs @@ -29,7 +29,7 @@ async fn spend_insert_controls_target_and_retry_settings() { .mount(&server) .await; let config = Config::new("spend_test".into(), &format!("{}?query=DROP&async_insert=0&wait_for_async_insert=0&input_format_skip_unknown_fields=1&database=wrong&readonly=1", server.uri()), 7).unwrap(); - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let row = BTreeMap::from([ ("request_id".into(), json!("request")), ("start_time".into(), json!(1234)), @@ -77,7 +77,7 @@ async fn spend_insert_preserves_storage_failure(#[case] status: u16) { .await; let config = Config::new("spend_test".into(), &server.uri(), 7).unwrap(); let error = insert_rows( - &Client::no_redirect_for_test(), + &Client::for_test(), config.storage().writer(), "spend_test", vec![BTreeMap::from([("request_id".into(), json!("request"))])], @@ -95,7 +95,7 @@ async fn empty_spend_insert_does_not_contact_storage() { let server = MockServer::start().await; let config = Config::new("spend_test".into(), &server.uri(), 7).unwrap(); insert_rows( - &Client::no_redirect_for_test(), + &Client::for_test(), config.storage().writer(), "spend_test", vec![], @@ -116,7 +116,7 @@ async fn failed_schema_setup_is_reported() { .await; let config = Config::new("spend_test".into(), &server.uri(), 7).unwrap(); assert!(matches!( - ensure_schema(&Client::no_redirect_for_test(), &config).await, + ensure_schema(&Client::for_test(), &config).await, Err(Error::Storage( litellm_storage_clickhouse::Error::SchemaFailed(403) )) diff --git a/litellm-rust/crates/storage-clickhouse/tests/migrations.rs b/litellm-rust/crates/storage-clickhouse/tests/migrations.rs index 29a85a8c4ec..49f481df632 100644 --- a/litellm-rust/crates/storage-clickhouse/tests/migrations.rs +++ b/litellm-rust/crates/storage-clickhouse/tests/migrations.rs @@ -48,7 +48,7 @@ async fn database() -> TestResult { Ok(ClickHouseDatabase { _container: container, url, - client: Client::no_redirect_for_test(), + client: Client::for_test(), }) } @@ -244,7 +244,7 @@ async fn failed_migration_is_not_recorded_and_retains_storage_error( #[rstest] fn invalid_database_identifier_is_rejected() { - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::writer("http://127.0.0.1:1").expect("valid URL"); assert!(matches!( ClickHouseMigrate::new( @@ -327,7 +327,7 @@ async fn duplicate_ledger_rows_are_tolerated( #[rstest] #[tokio::test] async fn revert_reports_forward_only_error() { - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::writer("http://127.0.0.1:1").expect("valid URL"); let migration = migration( 1, @@ -369,7 +369,7 @@ async fn applied_int64_versions_accept_numeric_and_quoted_json( ) .mount(&mock_server) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::writer(&mock_server.uri()).expect("valid URL"); let migrator = migrator(vec![]); let mut adapter = ClickHouseMigrate::new( @@ -406,7 +406,7 @@ async fn schema_requests_override_unsafe_connection_settings( mock_server.uri() ); execute_statement( - &Client::no_redirect_for_test(), + &Client::for_test(), &Connection::writer(&url).expect("valid URL"), "CREATE DATABASE IF NOT EXISTS trace_test", REQUEST_TIMEOUT, @@ -445,7 +445,7 @@ async fn oversized_ledger_response_is_rejected_before_migrations( ) .mount(&mock_server) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::writer(&mock_server.uri()).expect("valid URL"); let migrator = migrator(vec![]); let mut adapter = ClickHouseMigrate::new( diff --git a/litellm-rust/crates/storage-clickhouse/tests/transport.rs b/litellm-rust/crates/storage-clickhouse/tests/transport.rs index f70fe52e1de..2560c2985f0 100644 --- a/litellm-rust/crates/storage-clickhouse/tests/transport.rs +++ b/litellm-rust/crates/storage-clickhouse/tests/transport.rs @@ -13,7 +13,7 @@ async fn insert_rejects_invalid_identifiers( #[case] table: &str, #[case] invalid_database: bool, ) { - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::writer("http://localhost:8123").expect("valid URL"); let result = insert_encoded_rows(&client, &connection, database, table, "token", "{}").await; @@ -24,7 +24,7 @@ async fn insert_rejects_invalid_identifiers( #[rstest] #[tokio::test] async fn read_rejects_empty_sql() { - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::reader("http://localhost:8123", "litellm").expect("valid URL"); assert!(matches!( @@ -87,7 +87,7 @@ async fn typed_fetch_encodes_parameters_and_validates_rows( .expect(2) .mount(&server) .await; - let client = Client::no_redirect_for_test(); + let client = Client::for_test(); let connection = Connection::parse(&server.uri()).unwrap(); let params = QueryParams { signed: i64::MIN, @@ -131,7 +131,7 @@ async fn server_result_limits_allow_smaller_pages_without_retrying_other_failure .await; let connection = Connection::parse(&server.uri()).unwrap(); let error = execute_read( - &Client::no_redirect_for_test(), + &Client::for_test(), &connection, "SELECT 1", &BTreeMap::new(), @@ -174,7 +174,7 @@ async fn insert_timeout_environment_child() { .mount(&server) .await; let result = insert_encoded_rows( - &Client::no_redirect_for_test(), + &Client::for_test(), &Connection::parse(&server.uri()).unwrap(), "traces", "otel_traces",