Allow one-way delay samples to represent negative values caused by wall-clock skew between client and server. Update CLI output and statistics collection to correctly handle and report these signed durations.
158 lines
4.8 KiB
Rust
158 lines
4.8 KiB
Rust
use super::*;
|
|
|
|
#[test]
|
|
fn server_processing_greater_than_raw_does_not_underflow() {
|
|
let base = Instant::now();
|
|
let rtt = compute_rtt(
|
|
&ClientTimestamp {
|
|
mono: base,
|
|
wall: SystemTime::now(),
|
|
},
|
|
&ClientTimestamp {
|
|
mono: base + Duration::from_nanos(1),
|
|
wall: SystemTime::now(),
|
|
},
|
|
&TimestampFields {
|
|
recv_mono: Some(0),
|
|
send_mono: Some(1_000_000_000),
|
|
..Default::default()
|
|
},
|
|
);
|
|
assert_eq!(rtt.adjusted, Some(SignedDuration::from_nanos(-999_999_999)));
|
|
assert_eq!(rtt.effective, SignedDuration::from_nanos(-999_999_999));
|
|
}
|
|
|
|
#[test]
|
|
fn effective_rtt_uses_raw_when_adjusted_rtt_is_unavailable() {
|
|
let base = Instant::now();
|
|
let rtt = compute_rtt(
|
|
&ClientTimestamp {
|
|
mono: base,
|
|
wall: SystemTime::now(),
|
|
},
|
|
&ClientTimestamp {
|
|
mono: base + Duration::from_nanos(42),
|
|
wall: SystemTime::now(),
|
|
},
|
|
&TimestampFields::default(),
|
|
);
|
|
|
|
assert_eq!(rtt.adjusted, None);
|
|
assert_eq!(rtt.effective, SignedDuration::from_duration(rtt.raw));
|
|
}
|
|
|
|
#[test]
|
|
fn unix_epoch_ns_i64_rejects_out_of_range_wall_time() {
|
|
let i64_max_ns = u64::try_from(i64::MAX).unwrap();
|
|
let max = SystemTime::UNIX_EPOCH + Duration::from_nanos(i64_max_ns);
|
|
let overflow = max + Duration::from_nanos(1);
|
|
|
|
assert_eq!(unix_epoch_ns_i64(max), Some(i64::MAX));
|
|
assert_eq!(unix_epoch_ns_i64(overflow), None);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_omits_samples_when_client_wall_time_overflows_i64() {
|
|
let i64_max_ns = u64::try_from(i64::MAX).unwrap();
|
|
let overflow_wall =
|
|
SystemTime::UNIX_EPOCH + Duration::from_nanos(i64_max_ns) + Duration::from_nanos(1);
|
|
let sent_at = ClientTimestamp {
|
|
mono: Instant::now(),
|
|
wall: overflow_wall,
|
|
};
|
|
let received_at = ClientTimestamp {
|
|
mono: sent_at.mono + Duration::from_millis(40),
|
|
wall: overflow_wall + Duration::from_millis(40),
|
|
};
|
|
let ts = TimestampFields {
|
|
recv_wall: Some(i64::MAX),
|
|
send_wall: Some(i64::MAX),
|
|
..Default::default()
|
|
};
|
|
|
|
assert_eq!(compute_one_way(&sent_at, &received_at, &ts), None);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_returns_available_direction_samples() {
|
|
let sent_at = ClientTimestamp {
|
|
mono: Instant::now(),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10),
|
|
};
|
|
let received_at = ClientTimestamp {
|
|
mono: sent_at.mono + Duration::from_millis(40),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10) + Duration::from_millis(40),
|
|
};
|
|
let ts = TimestampFields {
|
|
recv_wall: Some(10_000_000_000 + 15_000_000),
|
|
send_wall: Some(10_000_000_000 + 25_000_000),
|
|
..Default::default()
|
|
};
|
|
|
|
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
|
assert_eq!(
|
|
sample.client_to_server,
|
|
Some(SignedDuration::from_nanos(15_000_000))
|
|
);
|
|
assert_eq!(
|
|
sample.server_to_client,
|
|
Some(SignedDuration::from_nanos(15_000_000))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_preserves_negative_client_to_server_delay() {
|
|
let sent_at = ClientTimestamp {
|
|
mono: Instant::now(),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10),
|
|
};
|
|
let received_at = ClientTimestamp {
|
|
mono: sent_at.mono + Duration::from_millis(40),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10) + Duration::from_millis(40),
|
|
};
|
|
let ts = TimestampFields {
|
|
recv_wall: Some(10_000_000_000 - 5_000_000),
|
|
send_wall: Some(10_000_000_000 + 25_000_000),
|
|
..Default::default()
|
|
};
|
|
|
|
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
|
|
|
assert_eq!(
|
|
sample.client_to_server,
|
|
Some(SignedDuration::from_nanos(-5_000_000))
|
|
);
|
|
assert_eq!(
|
|
sample.server_to_client,
|
|
Some(SignedDuration::from_nanos(15_000_000))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn compute_one_way_preserves_negative_server_to_client_delay() {
|
|
let sent_at = ClientTimestamp {
|
|
mono: Instant::now(),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10),
|
|
};
|
|
let received_at = ClientTimestamp {
|
|
mono: sent_at.mono + Duration::from_millis(40),
|
|
wall: SystemTime::UNIX_EPOCH + Duration::from_secs(10) + Duration::from_millis(40),
|
|
};
|
|
let ts = TimestampFields {
|
|
recv_wall: Some(10_000_000_000 + 15_000_000),
|
|
send_wall: Some(10_000_000_000 + 45_000_000),
|
|
..Default::default()
|
|
};
|
|
|
|
let sample = compute_one_way(&sent_at, &received_at, &ts).unwrap();
|
|
|
|
assert_eq!(
|
|
sample.client_to_server,
|
|
Some(SignedDuration::from_nanos(15_000_000))
|
|
);
|
|
assert_eq!(
|
|
sample.server_to_client,
|
|
Some(SignedDuration::from_nanos(-5_000_000))
|
|
);
|
|
}
|