use std::time::Duration;
#[derive(Debug, Clone)]
pub struct RequestTimings {
pub(crate) dns: Option<Duration>,
pub(crate) tcp_connect: Option<Duration>,
pub(crate) tls_handshake: Option<Duration>,
pub(crate) transfer: Option<Duration>,
pub(crate) total: Duration,
}
impl RequestTimings {
pub fn dns(&self) -> Option<Duration> {
self.dns
}
pub fn tcp_connect(&self) -> Option<Duration> {
self.tcp_connect
}
pub fn tls_handshake(&self) -> Option<Duration> {
self.tls_handshake
}
pub fn transfer(&self) -> Option<Duration> {
self.transfer
}
pub fn total(&self) -> Duration {
self.total
}
}
#[derive(Debug, Clone, Default)]
pub(crate) struct TimingCollector {
pub(crate) dns: Option<Duration>,
pub(crate) tcp_connect: Option<Duration>,
pub(crate) tls_handshake: Option<Duration>,
}
impl TimingCollector {
pub(crate) fn into_timings(
self,
transfer: Option<Duration>,
total: Duration,
) -> RequestTimings {
RequestTimings {
dns: self.dns,
tcp_connect: self.tcp_connect,
tls_handshake: self.tls_handshake,
transfer,
total,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn full_timings() {
let t = RequestTimings {
dns: Some(Duration::from_millis(10)),
tcp_connect: Some(Duration::from_millis(20)),
tls_handshake: Some(Duration::from_millis(30)),
transfer: Some(Duration::from_millis(40)),
total: Duration::from_millis(100),
};
assert_eq!(t.dns(), Some(Duration::from_millis(10)));
assert_eq!(t.tcp_connect(), Some(Duration::from_millis(20)));
assert_eq!(t.tls_handshake(), Some(Duration::from_millis(30)));
assert_eq!(t.transfer(), Some(Duration::from_millis(40)));
assert_eq!(t.total(), Duration::from_millis(100));
}
#[test]
fn pool_hit_timings() {
let t = RequestTimings {
dns: None,
tcp_connect: None,
tls_handshake: None,
transfer: Some(Duration::from_millis(15)),
total: Duration::from_millis(15),
};
assert!(t.dns().is_none());
assert!(t.tcp_connect().is_none());
assert!(t.tls_handshake().is_none());
assert_eq!(t.transfer(), Some(Duration::from_millis(15)));
}
#[test]
fn http_no_tls_timings() {
let t = RequestTimings {
dns: Some(Duration::from_millis(5)),
tcp_connect: Some(Duration::from_millis(10)),
tls_handshake: None,
transfer: Some(Duration::from_millis(20)),
total: Duration::from_millis(35),
};
assert!(t.tls_handshake().is_none());
assert!(t.dns().is_some());
}
#[test]
fn debug_format() {
let t = RequestTimings {
dns: Some(Duration::from_millis(1)),
tcp_connect: None,
tls_handshake: None,
transfer: None,
total: Duration::from_millis(1),
};
let dbg = format!("{t:?}");
assert!(dbg.contains("RequestTimings"));
}
#[test]
fn collector_into_timings() {
let c = TimingCollector {
dns: Some(Duration::from_millis(5)),
tcp_connect: Some(Duration::from_millis(10)),
tls_handshake: Some(Duration::from_millis(15)),
};
let t = c.into_timings(Some(Duration::from_millis(20)), Duration::from_millis(50));
assert_eq!(t.dns(), Some(Duration::from_millis(5)));
assert_eq!(t.total(), Duration::from_millis(50));
}
#[test]
fn collector_default() {
let c = TimingCollector::default();
assert!(c.dns.is_none());
assert!(c.tcp_connect.is_none());
assert!(c.tls_handshake.is_none());
}
}