test: trim redundant coverage
This commit was merged in pull request #58.
This commit is contained in:
1 parent
186c6eba97
commit
f0f9277469
7 files changed
+59
-462
No files matched your search
@@ -206,42 +206,6 @@ fn single_target_ten_millisecond_cadence_uses_managed_deadlines() {
|
||||
.any(|line| line.starts_with("session_closed,")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn finite_single_target_peer_close_exits_successfully() {
|
||||
let server = start_peer_close_server(test_params(
|
||||
Some(Duration::from_millis(40)),
|
||||
Duration::from_millis(10),
|
||||
));
|
||||
let mut command = Command::new(env!("CARGO_BIN_EXE_irtt-cli"));
|
||||
command.args([
|
||||
"--duration",
|
||||
"40ms",
|
||||
"--interval",
|
||||
"10ms",
|
||||
"--format",
|
||||
"csv",
|
||||
"--columns",
|
||||
"seq",
|
||||
"--header",
|
||||
"never",
|
||||
&server.addr.to_string(),
|
||||
]);
|
||||
|
||||
let output = run_with_timeout(command, Duration::from_secs(3));
|
||||
server.join();
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"status={:?}\nstderr={}",
|
||||
output.status.code(),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
let stdout = String::from_utf8(output.stdout).unwrap();
|
||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||
assert!(!stdout.trim().is_empty(), "{stdout}");
|
||||
assert!(!stderr.contains("peer closure"), "{stderr}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn continuous_single_target_peer_close_exits_nonzero() {
|
||||
let server = start_peer_close_server(test_params(None, Duration::from_millis(10)));
|
||||
|
||||
@@ -802,7 +802,7 @@ fn terminal_targets_count_toward_retained_generation_limit() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pruning_preserves_target_cursor_progress() {
|
||||
fn pruning_leaves_no_stale_target_work() {
|
||||
let (mut task, _) = ManagedClient::task(
|
||||
config(ManagedPacing::Staggered),
|
||||
vec![
|
||||
@@ -812,29 +812,39 @@ fn pruning_preserves_target_cursor_progress() {
|
||||
],
|
||||
)
|
||||
.unwrap();
|
||||
task.cursor = 5;
|
||||
task.timeout_cursor = 5;
|
||||
task.send_cursor = 5;
|
||||
task.cursor = 2;
|
||||
task.timeout_cursor = 2;
|
||||
task.send_cursor = 2;
|
||||
task.scan_remaining = 3;
|
||||
task.burst_remaining = 3;
|
||||
task.stagger_remaining = 3;
|
||||
task.targets.truncate(2);
|
||||
task.rebase_target_cursors();
|
||||
assert_eq!(task.cursor, 1);
|
||||
assert_eq!(task.timeout_cursor, 1);
|
||||
assert_eq!(task.send_cursor, 1);
|
||||
assert_eq!(task.scan_remaining, 2);
|
||||
assert_eq!(task.burst_remaining, 2);
|
||||
assert_eq!(task.stagger_remaining, 2);
|
||||
|
||||
task.targets.clear();
|
||||
task.rebase_target_cursors();
|
||||
assert_eq!(task.cursor, 0);
|
||||
assert_eq!(task.timeout_cursor, 0);
|
||||
assert_eq!(task.send_cursor, 0);
|
||||
task.targets[2].desired = false;
|
||||
task.targets[2].state = TargetState::Terminal;
|
||||
task.prune_undesired_terminal();
|
||||
|
||||
// Timeout discovery indexes `targets` with `timeout_cursor` directly, so a
|
||||
// prune must leave it safe to use; the target and send passes modulo their
|
||||
// own cursors. Pending per-pass work must not outlive the targets it was
|
||||
// scheduled for either.
|
||||
assert_eq!(task.targets.len(), 2);
|
||||
assert!(task.timeout_cursor < task.targets.len());
|
||||
assert!(task.scan_remaining <= task.targets.len());
|
||||
assert!(task.burst_remaining <= task.targets.len());
|
||||
assert!(task.stagger_remaining <= task.targets.len());
|
||||
assert!(!task.poll_timeout_pass(Instant::now()));
|
||||
|
||||
for target in &mut task.targets {
|
||||
target.desired = false;
|
||||
target.state = TargetState::Terminal;
|
||||
}
|
||||
task.prune_undesired_terminal();
|
||||
|
||||
assert!(task.targets.is_empty());
|
||||
assert_eq!(task.scan_remaining, 0);
|
||||
assert_eq!(task.burst_remaining, 0);
|
||||
assert_eq!(task.stagger_remaining, 0);
|
||||
assert!(!task.poll_timeout_pass(Instant::now()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1761,91 +1771,6 @@ fn timeout_discovery_inspects_at_most_one_budget_of_targets() {
|
||||
assert!(!task.poll_timeout_pass(Instant::now()));
|
||||
|
||||
assert_eq!(task.timeout_inspections, TIMEOUT_WORK_BUDGET);
|
||||
assert_eq!(task.timeout_cursor, TIMEOUT_WORK_BUDGET);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idle_timeout_discovery_inspects_one_target_once() {
|
||||
let (mut task, _) = ManagedClient::task(
|
||||
config(ManagedPacing::Burst),
|
||||
vec![ManagedTargetConfig::new("idle", "127.0.0.1:9")],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
task.timeout_inspections = 0;
|
||||
assert!(!task.poll_timeout_pass(Instant::now()));
|
||||
|
||||
assert_eq!(task.timeout_inspections, 1);
|
||||
assert_eq!(task.timeout_cursor, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn idle_timeout_discovery_sweeps_small_target_set_once() {
|
||||
let target_count = 8;
|
||||
let mut managed = config(ManagedPacing::Burst);
|
||||
managed.max_live_target_generations = target_count;
|
||||
let targets = (0..target_count)
|
||||
.map(|index| ManagedTargetConfig::new(format!("idle-{index}"), "127.0.0.1:9"))
|
||||
.collect();
|
||||
let (mut task, _) = ManagedClient::task(managed, targets).unwrap();
|
||||
|
||||
task.timeout_inspections = 0;
|
||||
assert!(!task.poll_timeout_pass(Instant::now()));
|
||||
|
||||
assert_eq!(task.timeout_inspections, target_count);
|
||||
assert_eq!(task.timeout_cursor, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sparse_timeout_backlog_progresses_within_one_poll() {
|
||||
let server = start_server(ServerBehavior::Echo, None);
|
||||
let target_count = TIMEOUT_WORK_BUDGET + 1;
|
||||
let late_index = target_count - 1;
|
||||
let mut managed = config(ManagedPacing::Burst);
|
||||
managed.completion = ManagedCompletionPolicy::ExplicitStop;
|
||||
managed.client.duration = None;
|
||||
managed.max_live_target_generations = target_count;
|
||||
let targets = (0..target_count)
|
||||
.map(|index| {
|
||||
if index == late_index {
|
||||
target("late", server.addr)
|
||||
} else {
|
||||
ManagedTargetConfig::new(format!("target-{index}"), "127.0.0.1:9")
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let (mut task, _) = ManagedClient::task(managed, targets).unwrap();
|
||||
for target in &mut task.targets[..late_index] {
|
||||
target.state = TargetState::Terminal;
|
||||
}
|
||||
let observations = Arc::new(Mutex::new(Vec::new()));
|
||||
task.event_observations = Some(Arc::clone(&observations));
|
||||
let runtime = runtime();
|
||||
open_target_for_timeout_test(&runtime, &mut task, late_index);
|
||||
let now = Instant::now();
|
||||
for seq in 0..u32::try_from(TIMEOUT_WORK_BUDGET + 64).unwrap() {
|
||||
replace_pending_for_timeout_test(
|
||||
&mut task,
|
||||
late_index,
|
||||
timeout_probe(
|
||||
seq,
|
||||
now - Duration::from_secs(2),
|
||||
now - Duration::from_secs(1),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
assert!(!task.poll_timeout_pass(now));
|
||||
assert!(task.poll_timeout_pass(now));
|
||||
|
||||
assert_eq!(
|
||||
timeout_losses_for(&observations, "late"),
|
||||
TIMEOUT_WORK_BUDGET
|
||||
);
|
||||
assert_eq!(task.timeout_backlog.len(), 1);
|
||||
close_timeout_test_target(&runtime, &mut task, late_index);
|
||||
drop(task);
|
||||
server.finish();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1889,7 +1814,6 @@ fn sparse_timeout_backlog_persists_across_polls() {
|
||||
TIMEOUT_WORK_BUDGET
|
||||
);
|
||||
assert_eq!(task.timeout_backlog.len(), 1);
|
||||
assert_eq!(task.timeout_cursor, TIMEOUT_WORK_BUDGET);
|
||||
|
||||
assert!(task.poll_timeout_pass(now));
|
||||
assert_eq!(
|
||||
@@ -1897,75 +1821,11 @@ fn sparse_timeout_backlog_persists_across_polls() {
|
||||
2 * TIMEOUT_WORK_BUDGET
|
||||
);
|
||||
assert_eq!(task.timeout_backlog.len(), 1);
|
||||
assert_eq!(task.timeout_cursor, 2 * TIMEOUT_WORK_BUDGET);
|
||||
close_timeout_test_target(&runtime, &mut task, 0);
|
||||
drop(task);
|
||||
server.finish();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_backlog_round_robins_known_sparse_targets() {
|
||||
let first = start_server(ServerBehavior::Echo, None);
|
||||
let second = start_server(ServerBehavior::Echo, None);
|
||||
let target_count = TIMEOUT_WORK_BUDGET + 2;
|
||||
let mut managed = config(ManagedPacing::Burst);
|
||||
managed.completion = ManagedCompletionPolicy::ExplicitStop;
|
||||
managed.client.duration = None;
|
||||
managed.max_live_target_generations = target_count;
|
||||
let targets = vec![target("first", first.addr), target("second", second.addr)]
|
||||
.into_iter()
|
||||
.chain(
|
||||
(2..target_count)
|
||||
.map(|index| ManagedTargetConfig::new(format!("target-{index}"), "127.0.0.1:9")),
|
||||
)
|
||||
.collect();
|
||||
let (mut task, _) = ManagedClient::task(managed, targets).unwrap();
|
||||
for target in &mut task.targets[2..] {
|
||||
target.state = TargetState::Terminal;
|
||||
}
|
||||
let observations = Arc::new(Mutex::new(Vec::new()));
|
||||
task.event_observations = Some(Arc::clone(&observations));
|
||||
let runtime = runtime();
|
||||
open_target_for_timeout_test(&runtime, &mut task, 0);
|
||||
open_target_for_timeout_test(&runtime, &mut task, 1);
|
||||
let now = Instant::now();
|
||||
for index in 0..2 {
|
||||
for seq in 0..u32::try_from(TIMEOUT_WORK_BUDGET + 1).unwrap() {
|
||||
replace_pending_for_timeout_test(
|
||||
&mut task,
|
||||
index,
|
||||
timeout_probe(
|
||||
seq,
|
||||
now - Duration::from_secs(2),
|
||||
now - Duration::from_secs(1),
|
||||
),
|
||||
);
|
||||
}
|
||||
task.timeout_backlog.push_back(TimeoutBacklogEntry {
|
||||
index,
|
||||
generation: task.targets[index].instance.generation,
|
||||
});
|
||||
}
|
||||
task.timeout_cursor = 2;
|
||||
|
||||
assert!(task.poll_timeout_pass(now));
|
||||
|
||||
assert_eq!(
|
||||
timeout_losses_for(&observations, "first"),
|
||||
TIMEOUT_WORK_BUDGET / 2
|
||||
);
|
||||
assert_eq!(
|
||||
timeout_losses_for(&observations, "second"),
|
||||
TIMEOUT_WORK_BUDGET / 2
|
||||
);
|
||||
assert_eq!(task.timeout_backlog.len(), 2);
|
||||
close_timeout_test_target(&runtime, &mut task, 0);
|
||||
close_timeout_test_target(&runtime, &mut task, 1);
|
||||
drop(task);
|
||||
first.finish();
|
||||
second.finish();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timeout_backlog_does_not_starve_discovery() {
|
||||
let first = start_server(ServerBehavior::Echo, None);
|
||||
@@ -2021,11 +1881,9 @@ fn timeout_backlog_does_not_starve_discovery() {
|
||||
|
||||
assert!(task.poll_timeout_pass(now));
|
||||
assert_eq!(timeout_losses_for(&observations, "late"), 0);
|
||||
assert_eq!(task.timeout_cursor, TIMEOUT_WORK_BUDGET + 1);
|
||||
|
||||
assert!(task.poll_timeout_pass(now));
|
||||
assert_eq!(timeout_losses_for(&observations, "late"), 1);
|
||||
assert_eq!(task.timeout_cursor, 0);
|
||||
assert_eq!(task.timeout_backlog.len(), 1);
|
||||
close_timeout_test_target(&runtime, &mut task, 0);
|
||||
close_timeout_test_target(&runtime, &mut task, late_index);
|
||||
@@ -2166,7 +2024,6 @@ fn timeout_discovery_reaches_later_target_after_budget_slice() {
|
||||
task.timeout_inspections = 0;
|
||||
assert!(!task.poll_timeout_pass(now));
|
||||
assert_eq!(task.timeout_inspections, TIMEOUT_WORK_BUDGET);
|
||||
assert_eq!(task.timeout_cursor, late_index);
|
||||
assert_eq!(timeout_losses_for(&observations, "late"), 0);
|
||||
|
||||
task.timeout_inspections = 0;
|
||||
|
||||
@@ -1060,7 +1060,6 @@ impl SessionMachine {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::client::{schedule::ProbeSchedule, validate_datagram_length};
|
||||
|
||||
fn open_machine(max_pending_probes: usize, probe_timeout: Duration) -> SessionMachine {
|
||||
let config = ClientConfig {
|
||||
@@ -1584,25 +1583,22 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_prepared_probe_changes_nothing() {
|
||||
let machine = open_machine(4, Duration::from_secs(1));
|
||||
let prepared = machine.prepare_probe().unwrap().unwrap();
|
||||
assert_eq!(prepared.seq, 0);
|
||||
drop(prepared);
|
||||
|
||||
let session = active(&machine);
|
||||
assert_eq!(session.next_wire_seq, 0);
|
||||
assert_eq!(session.packets_sent, 0);
|
||||
assert_eq!(session.pending.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_uncommitted_preflight_changes_no_logical_state() {
|
||||
fn uncommitted_probe_preparation_changes_no_authoritative_state() {
|
||||
let mut machine = open_machine(4, Duration::from_secs(1));
|
||||
let prepared = machine.prepare_probe().unwrap().unwrap();
|
||||
assert_eq!(prepared.seq, 0);
|
||||
|
||||
let _first_preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
let _second_preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
// Repeating preflight, and finalizing a commit that is never applied,
|
||||
// must both leave the session exactly as it was.
|
||||
{
|
||||
let _discarded_preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
}
|
||||
{
|
||||
let preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
let _discarded_commit = machine
|
||||
.finalize_probe_commit(preflight, timestamp(Instant::now()))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let session = active(&machine);
|
||||
assert_eq!(session.next_wire_seq, 0);
|
||||
@@ -1636,66 +1632,6 @@ mod tests {
|
||||
assert_eq!(session.pending.capacity(), capacity);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simulated_send_error_leaves_machine_and_schedule_unchanged() {
|
||||
let mut machine = open_machine(4, Duration::from_secs(1));
|
||||
let start = Instant::now();
|
||||
let mut schedule = ProbeSchedule::new(start, &active(&machine).negotiated).unwrap();
|
||||
assert!(schedule.permit_probe_at(start));
|
||||
let prepared = machine.prepare_probe().unwrap().unwrap();
|
||||
let sent_at = timestamp(start);
|
||||
let machine_preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
let schedule_commit = schedule
|
||||
.preflight_caller_commit(machine_preflight.next_packets_sent)
|
||||
.unwrap();
|
||||
let machine_commit = machine
|
||||
.finalize_probe_commit(machine_preflight, sent_at)
|
||||
.unwrap();
|
||||
|
||||
let _uncommitted_machine = machine_commit;
|
||||
let _uncommitted_schedule = schedule_commit;
|
||||
|
||||
let session = active(&machine);
|
||||
assert_eq!(session.next_wire_seq, 0);
|
||||
assert_eq!(session.packets_sent, 0);
|
||||
assert_eq!(session.pending.len(), 0);
|
||||
assert_eq!(schedule.next_send_deadline(), Some(start));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_success_commits_before_reporting_transport_invariant() {
|
||||
let mut machine = open_machine(4, Duration::from_secs(1));
|
||||
let start = Instant::now();
|
||||
let mut schedule = ProbeSchedule::new(start, &active(&machine).negotiated).unwrap();
|
||||
assert!(schedule.permit_probe_at(start));
|
||||
let prepared = machine.prepare_probe().unwrap().unwrap();
|
||||
let machine_preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
let machine_commit = machine
|
||||
.finalize_probe_commit(machine_preflight, timestamp(start))
|
||||
.unwrap();
|
||||
let schedule_commit = schedule.preflight_managed_commit(start, start).unwrap();
|
||||
let expected = prepared.bytes.len();
|
||||
let actual = expected - 1;
|
||||
|
||||
machine.commit_probe_sent(machine_commit, actual);
|
||||
schedule.commit(schedule_commit);
|
||||
let result = validate_datagram_length(expected, actual);
|
||||
|
||||
assert!(matches!(
|
||||
result,
|
||||
Err(ClientError::DatagramLengthMismatch { expected, actual })
|
||||
if actual + 1 == expected
|
||||
));
|
||||
let session = active(&machine);
|
||||
assert_eq!(session.next_wire_seq, 1);
|
||||
assert_eq!(session.packets_sent, 1);
|
||||
assert_eq!(session.pending.len(), 1);
|
||||
assert_eq!(
|
||||
schedule.next_send_deadline(),
|
||||
Some(start + machine.config.interval)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repeated_would_block_style_preflight_commits_once() {
|
||||
let mut machine = open_machine(4, Duration::from_secs(1));
|
||||
@@ -1737,26 +1673,6 @@ mod tests {
|
||||
assert_eq!(sent.bytes, prepared.bytes.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dropping_preflight_or_finalized_commit_changes_no_authoritative_state() {
|
||||
let mut machine = open_machine(4, Duration::from_secs(1));
|
||||
let prepared = machine.prepare_probe().unwrap().unwrap();
|
||||
{
|
||||
let _preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
}
|
||||
{
|
||||
let preflight = machine.preflight_probe_commit(&prepared).unwrap();
|
||||
let _commit = machine
|
||||
.finalize_probe_commit(preflight, timestamp(Instant::now()))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let session = active(&machine);
|
||||
assert_eq!(session.next_wire_seq, 0);
|
||||
assert_eq!(session.packets_sent, 0);
|
||||
assert_eq!(session.pending.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_uses_reserved_capacity_and_prevalidated_counter() {
|
||||
let mut machine = open_machine(2, Duration::from_secs(1));
|
||||
|
||||
@@ -39,37 +39,6 @@ fn assert_reply_bytes(event: &ClientEvent, expected: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Config/client validation ───
|
||||
|
||||
#[test]
|
||||
fn length_zero_baseline() {
|
||||
let params = params_with_length(0);
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
let header = echo_header_len(false, ¶ms);
|
||||
assert_eq!(expected, header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length_one_accepted() {
|
||||
let params = params_with_length(1);
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
assert!(expected >= 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length_1472_accepted() {
|
||||
let params = params_with_length(1472);
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
assert_eq!(expected, 1472);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length_4096_accepted() {
|
||||
let params = params_with_length(4096);
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
assert_eq!(expected, 4096);
|
||||
}
|
||||
|
||||
// ─── Echo request size: FakeServer observes exact packet size ───
|
||||
|
||||
#[test]
|
||||
@@ -98,21 +67,13 @@ fn echo_request_size_matches_echo_packet_len_above_header() {
|
||||
|
||||
// ─── Echo reply handling ───
|
||||
|
||||
#[test]
|
||||
fn echo_reply_decoded_for_large_length() {
|
||||
let params = params_with_length(4096);
|
||||
let run = run_one_probe(params.clone(), TimestampFields::default());
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
assert_reply(&run.reply);
|
||||
assert_reply_bytes(&run.reply, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn echo_reply_bytes_consistent_with_echo_packet_len_for_various_lengths() {
|
||||
for length in [0, 1472, 4096] {
|
||||
let params = params_with_length(length);
|
||||
let run = run_one_probe(params.clone(), TimestampFields::default());
|
||||
let expected = test_echo_packet_len(false, ¶ms);
|
||||
assert_reply(&run.reply);
|
||||
assert_reply_bytes(&run.reply, expected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,16 +369,3 @@ fn assert_one_way_presence(
|
||||
assert_eq!(sample.client_to_server.is_some(), client_to_server);
|
||||
assert_eq!(sample.server_to_client.is_some(), server_to_client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dscp_configured_open_close_smoke() {
|
||||
let mut params = default_params();
|
||||
params.dscp = 46;
|
||||
let server = start_open_server(params.clone(), None);
|
||||
let mut client = Client::connect(config_for_params(server.addr, ¶ms)).unwrap();
|
||||
|
||||
let outcome = client.open().unwrap();
|
||||
assert!(matches!(outcome, irtt_client::OpenOutcome::Started { .. }));
|
||||
client.close().unwrap();
|
||||
server.join();
|
||||
}
|
||||
@@ -22,27 +22,6 @@ fn backend_basic_open_echo_close() {
|
||||
client.close().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backend_ttl_smoke() {
|
||||
let params = default_params();
|
||||
let peer = BackendPeer::start_open_echo(params.clone(), None);
|
||||
let mut config = config_for_params(peer.addr(), ¶ms);
|
||||
config.socket_config.ttl = Some(64);
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
|
||||
let outcome = client.open().unwrap();
|
||||
assert!(matches!(outcome, irtt_client::OpenOutcome::Started { .. }));
|
||||
|
||||
let sent = client.send_probe().unwrap();
|
||||
assert_eq!(sent.len(), 1);
|
||||
|
||||
let events = client.recv_once().unwrap();
|
||||
assert_eq!(events.len(), 1);
|
||||
assert!(matches!(events[0], ClientEvent::EchoReply { .. }));
|
||||
|
||||
client.close().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn backend_received_stats_smoke() {
|
||||
for mode in [
|
||||
|
||||
@@ -185,81 +185,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_completes_adjacent_pair() {
|
||||
let mut tracker = IpdvTracker::new(None);
|
||||
assert!(tracker.insert(ipdv_sample(0, 10)).is_empty());
|
||||
|
||||
let pairs = tracker.insert(ipdv_sample(1, 14));
|
||||
|
||||
assert_eq!(
|
||||
pairs,
|
||||
vec![CompletedIpdvPair {
|
||||
previous_seq: 0,
|
||||
current_seq: 1,
|
||||
rtt_ipdv_ns: 4,
|
||||
send_ipdv_ns: None,
|
||||
receive_ipdv_ns: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_gap_fill_completes_both_adjacent_pairs() {
|
||||
let mut tracker = IpdvTracker::new(None);
|
||||
assert!(tracker.insert(ipdv_sample(0, 10)).is_empty());
|
||||
assert!(tracker.insert(ipdv_sample(2, 20)).is_empty());
|
||||
|
||||
let pairs = tracker.insert(ipdv_sample(1, 13));
|
||||
|
||||
assert_eq!(
|
||||
pairs,
|
||||
vec![
|
||||
CompletedIpdvPair {
|
||||
previous_seq: 0,
|
||||
current_seq: 1,
|
||||
rtt_ipdv_ns: 3,
|
||||
send_ipdv_ns: None,
|
||||
receive_ipdv_ns: None,
|
||||
},
|
||||
CompletedIpdvPair {
|
||||
previous_seq: 1,
|
||||
current_seq: 2,
|
||||
rtt_ipdv_ns: 7,
|
||||
send_ipdv_ns: None,
|
||||
receive_ipdv_ns: None,
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_completes_wrapped_adjacent_pair() {
|
||||
let mut tracker = IpdvTracker::new(None);
|
||||
assert!(tracker.insert(ipdv_sample(u32::MAX, 10)).is_empty());
|
||||
|
||||
let pairs = tracker.insert(ipdv_sample(0, 14));
|
||||
|
||||
assert_eq!(
|
||||
pairs,
|
||||
vec![CompletedIpdvPair {
|
||||
previous_seq: u32::MAX,
|
||||
current_seq: 0,
|
||||
rtt_ipdv_ns: 4,
|
||||
send_ipdv_ns: None,
|
||||
receive_ipdv_ns: None,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_wrap_gap_does_not_complete_pair() {
|
||||
let mut tracker = IpdvTracker::new(None);
|
||||
assert!(tracker.insert(ipdv_sample(u32::MAX - 1, 10)).is_empty());
|
||||
|
||||
assert!(tracker.insert(ipdv_sample(0, 14)).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_late_wrapped_previous_completes_pair() {
|
||||
let mut tracker = IpdvTracker::new(None);
|
||||
@@ -289,17 +214,25 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ipdv_tracker_bounded_mode_evicts_old_sequence_state() {
|
||||
let mut tracker = IpdvTracker::new(Some(2));
|
||||
assert!(tracker.insert(ipdv_sample(0, 10)).is_empty());
|
||||
assert_eq!(tracker.insert(ipdv_sample(1, 14)).len(), 1);
|
||||
fn ipdv_tracker_bounded_mode_limits_sequence_state() {
|
||||
let limit = 4;
|
||||
let mut tracker = IpdvTracker::new(Some(limit));
|
||||
|
||||
let pairs = tracker.insert(ipdv_sample(2, 20));
|
||||
// Far more inserts than the limit, so eviction runs repeatedly. Every
|
||||
// per-sequence collection must stay bounded by the limit rather than
|
||||
// growing with the number of samples seen, and eviction must not stop
|
||||
// adjacent sequences from still completing a pair.
|
||||
for seq in 0..512_u32 {
|
||||
let pairs = tracker.insert(ipdv_sample(seq, i128::from(seq)));
|
||||
|
||||
assert_eq!(pairs.len(), 1);
|
||||
assert!(!tracker.samples.contains_key(&0));
|
||||
assert!(!tracker.completed_pairs.contains(&0));
|
||||
assert!(!tracker.completed_pairs.contains(&1));
|
||||
assert!(tracker.completed_pairs.contains(&2));
|
||||
assert_eq!(pairs.len(), usize::from(seq > 0), "seq {seq}");
|
||||
assert!(tracker.samples.len() <= limit, "seq {seq}");
|
||||
assert_eq!(
|
||||
tracker.sample_order.len(),
|
||||
tracker.samples.len(),
|
||||
"seq {seq}"
|
||||
);
|
||||
assert!(tracker.completed_pairs.len() <= limit, "seq {seq}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user