This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 11:15:58 +02:00
1 parent 87e571c170
commit fa7abc9e53
308 files changed
+49746 -50237

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
mod tests {
use super::*;
use http_body_util::BodyExt;
use tokio::sync::Semaphore;
async fn observation() -> (Arc<Exchange>, Arc<Semaphore>) {
let slots = Arc::new(Semaphore::new(1));
let permit = slots.clone().acquire_owned().await.unwrap();
let metrics = Arc::new(Metrics::default());
metrics.active.store(1, Ordering::Relaxed);
let exchange = Arc::new(Exchange {
vhost_metrics: None,
vhost: None,
route: Mutex::new(None),
cache_effective_enabled: Mutex::new(None),
transform_effective_enabled: Mutex::new(None),
backend: Mutex::new(None),
id: 1,
method: "POST".into(),
host: "localhost".into(),
path: "/echo".into(),
http_version: "1.1",
transport: "h1",
websocket_bootstrap: None,
websocket_phase: Mutex::new(None),
websocket_error: Mutex::new(None),
h3_reset_code: Mutex::new(None),
upstream_status: AtomicU16::new(0),
upstream_error: Mutex::new(None),
client_ip: Mutex::new(Some("127.0.0.1".into())),
user_agent: Some("RustProxy-Test/1.0".into()),
country: Mutex::new(Some("PL".into())),
started: Instant::now(),
status: AtomicU16::new(200),
cache_status: AtomicU16::new(0),
cache_reason: Mutex::new("not_proxy_response"),
failed: AtomicBool::new(false),
aborted: AtomicBool::new(false),
request_bytes: AtomicU64::new(0),
response_bytes: AtomicU64::new(0),
metrics,
logs: Arc::new(Logs::default()),
traffic: crate::traffic::Analytics::start(tokio_util::sync::CancellationToken::new()),
_permit: permit,
});
(exchange, slots)
}
#[tokio::test]
async fn permit_and_metrics_cover_both_bodies() {
let (exchange, slots) = observation().await;
let metrics = exchange.metrics.clone();
let logs = exchange.logs.clone();
let input = MeteredBody::new(
Body::from("in"),
exchange.clone(),
Direction::Request,
Duration::from_secs(1),
);
let output = MeteredBody::new(
Body::from("out"),
exchange.clone(),
Direction::Response,
Duration::from_secs(1),
);
drop(exchange);
assert_eq!(
input.collect().await.unwrap().to_bytes(),
Bytes::from_static(b"in")
);
assert_eq!(slots.available_permits(), 0);
assert_eq!(
output.collect().await.unwrap().to_bytes(),
Bytes::from_static(b"out")
);
assert_eq!(slots.available_permits(), 1);
assert_eq!(metrics.active.load(Ordering::Relaxed), 0);
assert_eq!(metrics.bytes_in.load(Ordering::Relaxed), 2);
assert_eq!(metrics.bytes_out.load(Ordering::Relaxed), 3);
assert_eq!(metrics.completed.load(Ordering::Relaxed), 1);
assert_eq!(logs.recent().len(), 1);
}
#[tokio::test]
async fn idle_body_fails_and_releases_capacity() {
let (exchange, slots) = observation().await;
let metrics = exchange.metrics.clone();
let pending = futures_util::stream::pending::<Result<Bytes, std::io::Error>>();
let output = MeteredBody::new(
Body::from_stream(pending),
exchange,
Direction::Response,
Duration::from_millis(10),
);
assert!(output.collect().await.is_err());
assert_eq!(slots.available_permits(), 1);
assert_eq!(metrics.errors.load(Ordering::Relaxed), 1);
}
}