Files
RustProxy/src/runtime/tests.rs
T
2026-10-17 20:34:13 +02:00

162 lines
8.2 KiB
Rust

#[cfg(test)]
mod cache_revision_tests {
use super::*;
#[test]
fn operational_saves_keep_cache_identity_but_cache_affecting_saves_rotate_it() {
let base = config::demo_config("127.0.0.1:9000".parse().unwrap());
let identity = cache_revision(&base);
let mut file_transport = base.clone();
file_transport.web_services.push(crate::web_server::Service {
id: "static-test".into(), name: "Static Test".into(),
document_root: "/var/www/static-test".into(),
..Default::default()
});
let mut zero_copy = file_transport.clone();
zero_copy.web_services[0].sendfile = crate::web_server::SendfileMode::Auto;
assert_eq!(cache_revision(&file_transport), cache_revision(&zero_copy));
assert!(matches!(cache_invalidation(&file_transport, &zero_copy), CacheInvalidation::None));
let mut logging = base.clone();
logging.logging.file.path = "/tmp/rustproxy-test-access.jsonl".into();
assert_eq!(cache_revision(&logging), identity);
assert!(matches!(
cache_invalidation(&base, &logging),
CacheInvalidation::None
));
let mut metrics = base.clone();
metrics.prometheus.include_system = !metrics.prometheus.include_system;
assert_eq!(cache_revision(&metrics), identity);
let mut response = base.clone();
response.server_header.value = "edge-test".into();
response.diagnostic_headers.request_id = !response.diagnostic_headers.request_id;
response.compression.gzip = !response.compression.gzip;
assert_eq!(cache_revision(&response), identity);
let mut docker = base.clone();
docker.docker_agents.agents.push(crate::docker::Agent {
id: "node1".into(),
name: "Node 1".into(),
..Default::default()
});
assert_eq!(cache_revision(&docker), identity);
let mut preset = base.clone();
preset.cache.memory_preset = Some(crate::cache::MemoryPreset::Recommended);
preset.cache.cold_preset = Some(crate::cache::ColdPreset::Recommended);
preset.transform.preset = Some(crate::transform::Preset::Uber);
preset.transform.memory_budget_bytes = 1024 * 1024 * 1024;
preset.transform.max_inflight = 128;
assert_eq!(cache_revision(&preset), identity);
assert!(matches!(
cache_invalidation(&base, &preset),
CacheInvalidation::None
));
let mut transform_policy = base.clone();
transform_policy.transform.json = !transform_policy.transform.json;
assert_ne!(cache_revision(&transform_policy), identity);
let mut transform_body_limit = base.clone();
transform_body_limit.transform.max_body_bytes += 1024;
assert_ne!(cache_revision(&transform_body_limit), identity);
let mut wire_only = base.clone();
wire_only.cache.bypass_query = !wire_only.cache.bypass_query;
wire_only.cache.bypass_prefixes.push("/private".into());
wire_only.cache.expose_status = !wire_only.cache.expose_status;
wire_only.cache.expose_hits = !wire_only.cache.expose_hits;
wire_only.cache.expose_cache_status = !wire_only.cache.expose_cache_status;
wire_only.cache.expose_resident_age = !wire_only.cache.expose_resident_age;
wire_only.cache.expose_only_hits = !wire_only.cache.expose_only_hits;
wire_only.cache.via_header = Some("RustProxy edge".into());
wire_only.cache.http_invalidation_allowed_cidrs = vec!["192.0.2.42".into()];
assert_eq!(cache_revision(&wire_only), identity);
assert!(matches!(
cache_invalidation(&base, &wire_only),
CacheInvalidation::None
));
for label in ["http2", "http3"] {
let mut protocol_only = base.clone();
if label == "http2" {
protocol_only.vhosts[0].http2_enabled = !base.vhosts[0].http2_enabled;
} else {
protocol_only.vhosts[0].http3_enabled = !base.vhosts[0].http3_enabled;
}
// The effective configuration really changes, but the cache key
// does not. This must hold for both toggling directions.
assert_ne!(
(protocol_only.vhosts[0].http2_enabled, protocol_only.vhosts[0].http3_enabled),
(base.vhosts[0].http2_enabled, base.vhosts[0].http3_enabled),
"{label} toggle did not change a transport switch"
);
assert_eq!(cache_revision(&protocol_only), identity, "{label} rotated cache");
assert!(matches!(cache_invalidation(&base, &protocol_only), CacheInvalidation::None));
assert!(matches!(cache_invalidation(&protocol_only, &base), CacheInvalidation::None));
}
let mut both_protocols = base.clone();
both_protocols.vhosts[0].http2_enabled = !base.vhosts[0].http2_enabled;
both_protocols.vhosts[0].http3_enabled = !base.vhosts[0].http3_enabled;
assert_eq!(cache_revision(&both_protocols), identity);
assert!(matches!(cache_invalidation(&base, &both_protocols), CacheInvalidation::None));
let mut vhost_diagnostics = base.clone();
vhost_diagnostics.vhosts[0].cache.expose_only_hits = Some(true);
assert_eq!(cache_revision(&vhost_diagnostics), identity);
assert!(matches!(cache_invalidation(&base, &vhost_diagnostics), CacheInvalidation::None));
let mut cache = base.clone();
cache.cache.max_entries += 1;
let cache_identity = cache_revision(&cache);
assert_ne!(cache_identity, identity);
assert!(matches!(
cache_invalidation(&base, &cache),
CacheInvalidation::All(value) if value == cache_identity
));
let mut operational = base.clone();
operational.vhosts[0].load_balancing.keepalive.enabled = false;
operational.vhosts[0].load_balancing.keepalive.idle_timeout_seconds = 90;
operational.vhosts[0].load_balancing.keepalive.max_idle_per_host = 32;
operational.vhosts[0].load_balancing.keepalive.tcp_keepalive_seconds = 90;
operational.vhosts[0].load_balancing.keepalive.pool_recycle_requests = 1_000;
operational.vhosts[0].load_balancing.keepalive.pool_recycle_seconds = 1_800;
operational.vhosts[0].load_balancing.keepalive.http1_max_buffer_bytes = 65_536;
operational.vhosts[0].backends[0].weight += 1;
operational.vhosts[0].backends[0].max_concurrent_requests = 16;
operational.vhosts[0].backends[0].queue_timeout_ms = 100;
operational.vhosts[0].timing_headers = true;
operational.vhosts[0].acl_profile_id = Some("test-only-acl".into());
operational.vhosts[0].user_agent_blocking = Default::default();
operational.vhosts[0].proxy_timeouts.read_timeout_seconds = Some(180);
assert_eq!(cache_revision(&operational), identity);
assert_eq!(vhost_cache_revision(&operational.vhosts[0]), vhost_cache_revision(&base.vhosts[0]));
assert!(matches!(cache_invalidation(&base, &operational), CacheInvalidation::None));
assert!(matches!(cache_invalidation(&operational, &base), CacheInvalidation::None));
let mut vhost = base.clone();
vhost.vhosts[0].backends[0].url = "http://127.0.0.1:9001".into();
assert_eq!(cache_revision(&vhost), identity);
let affected_id = base.vhosts[0].id.clone();
assert!(matches!(cache_invalidation(&base, &vhost), CacheInvalidation::Scopes(ids) if ids == vec![affected_id]));
// A content change must not invalidate another independent vhost.
let mut multiple = base.clone();
let mut another = multiple.vhosts[0].clone();
another.id = "other-scope".into();
another.frontend.hosts = vec!["other.example.test".into()];
multiple.vhosts.push(another);
let mut changed_one = multiple.clone();
changed_one.vhosts[0].backends[0].url = "http://127.0.0.1:9002".into();
assert!(matches!(cache_invalidation(&multiple, &changed_one), CacheInvalidation::Scopes(ids)
if ids == vec![base.vhosts[0].id.clone()]));
let mut changed_global = multiple.clone();
changed_global.transform.max_body_bytes += 1;
assert!(matches!(cache_invalidation(&multiple, &changed_global), CacheInvalidation::All(_)));
}
}