mod tests { use super::*; fn backend(id: &str, port: u16) -> Backend { serde_json::from_value(serde_json::json!({ "id": id, "url": format!("http://127.0.0.1:{port}"), "protocol": "http1", "allow_private": true })) .unwrap() } #[test] fn protocol_observation_requires_a_real_http_response_version() { let backend = backend("protocol-observed", 18090); let client = client(&backend, AddressPolicy::new(&backend).unwrap(), false).unwrap(); assert_eq!(client.protocol_stats().last_version, None); let shared = client.clone(); // Exercise the response-version recorder independently of the network; // a live TLS ALPN acceptance test must still run on staging. shared.inner.observe_protocol(Version::HTTP_11); shared.inner.observe_protocol(Version::HTTP_2); let observed = client.protocol_stats(); assert_eq!(observed.last_version, Some("h2")); assert_eq!(observed.http1_responses, 1); assert_eq!(observed.http2_responses, 1); assert!(observed.observed_at_ms > 0); } #[test] fn generation_recycles_after_request_budget() { let backend = backend("rotation-test", 18081); let mut keepalive = crate::balance::Keepalive::default(); keepalive.pool_recycle_requests = 2; keepalive.pool_recycle_seconds = 0; let client = client_with_keepalive( &backend, AddressPolicy::new(&backend).unwrap(), false, &keepalive, ) .unwrap(); client.inner.client_for_request(); client.inner.client_for_request(); assert_eq!(client.rotation_stats().rotations, 0); client.inner.client_for_request(); let stats = client.rotation_stats(); assert_eq!(stats.rotations, 1); assert_eq!(stats.generation, 1); } #[test] fn generation_recycles_after_age_without_request() { let backend = backend("rotation-age-test", 18083); let mut keepalive = crate::balance::Keepalive::default(); keepalive.pool_recycle_requests = 0; keepalive.pool_recycle_seconds = 1; let client = client_with_keepalive( &backend, AddressPolicy::new(&backend).unwrap(), false, &keepalive, ) .unwrap(); client .inner .generation_started_ms .store(10, std::sync::atomic::Ordering::Relaxed); client.inner.maintain_rotation_at(2_010); let stats = client.rotation_stats(); assert_eq!(stats.rotations, 1); assert_eq!(stats.generation, 1); assert_eq!(stats.generation_requests, 0); } #[test] fn generation_recycling_can_be_disabled() { let backend = backend("rotation-off", 18082); let mut keepalive = crate::balance::Keepalive::default(); keepalive.pool_recycle_requests = 0; keepalive.pool_recycle_seconds = 0; let client = client_with_keepalive( &backend, AddressPolicy::new(&backend).unwrap(), false, &keepalive, ) .unwrap(); for _ in 0..10 { client.inner.client_for_request(); } assert_eq!(client.rotation_stats().rotations, 0); } }