test: consolidate and prune implementation-coupled tests

This commit is contained in:
Nils Andreas Svee committed 2026-05-17 00:28:05 +07:00
1 parent a7288cc612
commit ddd420cc21
4 files changed
+73 -262

No files matched your search

-37
View File
@@ -1217,17 +1217,6 @@ mod tests {
assert_machine_packet_meta(&line, "0", "0", "0", "none"); assert_machine_packet_meta(&line, "0", "0", "0", "none");
} }
#[test]
fn machine_echo_reply_metadata_dscp_46_ecn_0_prints_values() {
let line = format_event(
&reply_event_with_meta(packet_meta(184, 46, 0)),
OutputMode::Machine,
)
.unwrap();
assert_machine_packet_meta(&line, "184", "46", "0", "none");
}
#[test] #[test]
fn machine_echo_reply_metadata_dscp_46_ecn_2_prints_values() { fn machine_echo_reply_metadata_dscp_46_ecn_2_prints_values() {
let line = format_event( let line = format_event(
@@ -1252,18 +1241,6 @@ mod tests {
assert_machine_packet_meta(&line, "none", "none", "none", "1000000234"); assert_machine_packet_meta(&line, "none", "none", "none", "1000000234");
} }
#[test]
fn machine_late_reply_metadata_unavailable_prints_none() {
let line = format_event(
&late_event_with_meta(PacketMeta::default()),
OutputMode::Machine,
)
.unwrap();
assert!(line.starts_with("event=late "));
assert_machine_packet_meta(&line, "none", "none", "none", "none");
}
#[test] #[test]
fn machine_late_reply_metadata_observed_values_prints_values() { fn machine_late_reply_metadata_observed_values_prints_values() {
let line = format_event( let line = format_event(
@@ -1276,20 +1253,6 @@ mod tests {
assert_machine_packet_meta(&line, "186", "46", "2", "none"); assert_machine_packet_meta(&line, "186", "46", "2", "none");
} }
#[test]
fn machine_late_reply_metadata_kernel_rx_timestamp_prints_ns() {
let line = format_event(
&late_event_with_meta(packet_meta_with_timestamp(Some(
UNIX_EPOCH + Duration::new(2, 345),
))),
OutputMode::Machine,
)
.unwrap();
assert!(line.starts_with("event=late "));
assert_machine_packet_meta(&line, "none", "none", "none", "2000000345");
}
#[test] #[test]
fn simple_prints_readable_reply_line() { fn simple_prints_readable_reply_line() {
let line = format_event(&reply_event(), OutputMode::Simple).unwrap(); let line = format_event(&reply_event(), OutputMode::Simple).unwrap();
+29 -59
View File
@@ -122,47 +122,27 @@ fn hmac_close_success_sends_authenticated_close_and_closes_session() {
} }
#[test] #[test]
fn missing_client_key_against_hmac_required_server_times_out() { fn hmac_required_server_rejects_missing_or_wrong_client_key() {
let key = b"compat-secret".to_vec(); for (hmac_key, expected_hmac_flag) in [(None, false), (Some(b"wrong-secret".to_vec()), true)] {
let server = start_hmac_required_open_drop_server(key, Duration::from_millis(250)); let server_key = b"compat-secret".to_vec();
let mut config = config_for_params(server.addr, &default_params()); let server = start_hmac_required_open_drop_server(server_key, Duration::from_millis(250));
config.open_timeouts = vec![Duration::from_millis(200)]; let mut config = config_for_params(server.addr, &default_params());
config.hmac_key = None; config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = hmac_key;
let mut client = Client::connect(config).unwrap(); let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout))); assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
let observations = server.observations(1); let observations = server.observations(1);
assert!(matches!( assert!(matches!(
observations.as_slice(), observations.as_slice(),
[ServerObservation::RejectedHmac { [ServerObservation::RejectedHmac {
hmac: false, hmac,
bad_hmac: true bad_hmac: true
}] }] if *hmac == expected_hmac_flag
)); ));
server.join(); server.join();
} }
#[test]
fn wrong_client_key_against_hmac_required_server_times_out() {
let server_key = b"compat-secret".to_vec();
let server = start_hmac_required_open_drop_server(server_key, Duration::from_millis(250));
let mut config = config_for_params(server.addr, &default_params());
config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = Some(b"wrong-secret".to_vec());
let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
let observations = server.observations(1);
assert!(matches!(
observations.as_slice(),
[ServerObservation::RejectedHmac {
hmac: true,
bad_hmac: true
}]
));
server.join();
} }
#[test] #[test]
@@ -311,25 +291,15 @@ fn backend_hmac_correct_key_succeeds() {
} }
#[test] #[test]
fn backend_hmac_wrong_key_fails() { fn backend_hmac_required_rejects_missing_or_wrong_client_key() {
let server_key = b"compat-secret".to_vec(); for hmac_key in [None, Some(b"wrong-secret".to_vec())] {
let peer = BackendPeer::start_hmac_required(server_key); let server_key = b"compat-secret".to_vec();
let mut config = config_for_params(peer.addr(), &default_params()); let peer = BackendPeer::start_hmac_required(server_key);
config.open_timeouts = vec![Duration::from_millis(200)]; let mut config = config_for_params(peer.addr(), &default_params());
config.hmac_key = Some(b"wrong-secret".to_vec()); config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = hmac_key;
let mut client = Client::connect(config).unwrap(); let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout))); assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
} }
#[test]
fn backend_hmac_missing_key_fails() {
let server_key = b"compat-secret".to_vec();
let peer = BackendPeer::start_hmac_required(server_key);
let mut config = config_for_params(peer.addr(), &default_params());
config.open_timeouts = vec![Duration::from_millis(200)];
config.hmac_key = None;
let mut client = Client::connect(config).unwrap();
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
} }
+44 -108
View File
@@ -1,6 +1,6 @@
mod support; mod support;
use irtt_client::{Client, ClientConfig, ClientError, ClientEvent, NegotiationPolicy}; use irtt_client::{Client, ClientConfig, ClientError, NegotiationPolicy};
use irtt_proto::{Params, TimestampFields}; use irtt_proto::{Params, TimestampFields};
use support::{ use support::{
@@ -32,63 +32,34 @@ fn echo_observation(run: &OneProbeRun) -> (usize, bool, u64, u32) {
// ─── Config mapping ─── // ─── Config mapping ───
#[test] #[test]
fn server_fill_none_produces_no_fill_in_open_params() { fn server_fill_none_short_and_max_map_into_open_params() {
let params = default_params(); for fill in [None, Some("abc"), Some("0123456789abcdef0123456789abcdef")] {
let run = run_one_probe(params, TimestampFields::default()); let mut params = default_params();
assert!(open_observation_params(&run).server_fill.is_none()); params.server_fill = fill.and_then(server_fill);
let run = run_one_probe(params, TimestampFields::default());
assert_eq!(
open_observation_params(&run)
.server_fill
.as_ref()
.map(|f| f.value.as_str()),
fill
);
}
} }
#[test] #[test]
fn server_fill_short_value_maps_into_open_params() { fn server_fill_empty_and_oversized_values_are_rejected_at_config_boundary() {
let mut params = default_params(); for fill in ["", "0123456789abcdef0123456789abcdefx"] {
params.server_fill = server_fill("abc"); let config = ClientConfig {
let run = run_one_probe(params, TimestampFields::default()); server_fill: Some(fill.to_owned()),
assert_eq!( ..ClientConfig::default()
open_observation_params(&run) };
.server_fill assert!(matches!(
.as_ref() Client::connect(config),
.map(|f| f.value.as_str()), Err(ClientError::InvalidConfig { .. })
Some("abc") ));
); }
}
#[test]
fn server_fill_32_byte_value_maps_into_open_params() {
let mut params = default_params();
let fill = "0123456789abcdef0123456789abcdef";
params.server_fill = server_fill(fill);
let run = run_one_probe(params, TimestampFields::default());
assert_eq!(
open_observation_params(&run)
.server_fill
.as_ref()
.map(|f| f.value.as_str()),
Some(fill)
);
}
#[test]
fn server_fill_over_32_bytes_rejected_at_config_boundary() {
let config = ClientConfig {
server_fill: Some("0123456789abcdef0123456789abcdefx".to_owned()),
..ClientConfig::default()
};
assert!(matches!(
Client::connect(config),
Err(ClientError::InvalidConfig { .. })
));
}
#[test]
fn server_fill_empty_rejected_at_config_boundary() {
let config = ClientConfig {
server_fill: Some("".to_owned()),
..ClientConfig::default()
};
assert!(matches!(
Client::connect(config),
Err(ClientError::InvalidConfig { .. })
));
} }
// ─── Open negotiation ─── // ─── Open negotiation ───
@@ -102,53 +73,26 @@ fn server_fill_negotiated_params_reflect_accepted_value() {
} }
#[test] #[test]
fn server_fill_strict_rejects_removed_fill() { fn server_fill_strict_rejects_removed_changed_or_unexpected_fill() {
let mut requested = default_params(); for (requested_fill, returned_fill) in [
requested.server_fill = server_fill("rand"); (Some("rand"), None),
(Some("abc"), Some("xyz")),
(None, Some("unexpected")),
] {
let mut requested = default_params();
requested.server_fill = requested_fill.and_then(server_fill);
let mut returned = requested.clone(); let mut returned = requested.clone();
returned.server_fill = None; returned.server_fill = returned_fill.and_then(server_fill);
let server = start_open_server(returned, None); let server = start_open_server(returned, None);
let mut client = Client::connect(config_for_params(server.addr, &requested)).unwrap(); let mut client = Client::connect(config_for_params(server.addr, &requested)).unwrap();
assert!(matches!( assert!(matches!(
client.open(), client.open(),
Err(ClientError::NegotiationRejected { .. }) Err(ClientError::NegotiationRejected { .. })
)); ));
server.join(); server.join();
} }
#[test]
fn server_fill_strict_rejects_different_fill_value() {
let mut requested = default_params();
requested.server_fill = server_fill("abc");
let mut returned = requested.clone();
returned.server_fill = server_fill("xyz");
let server = start_open_server(returned, None);
let mut client = Client::connect(config_for_params(server.addr, &requested)).unwrap();
assert!(matches!(
client.open(),
Err(ClientError::NegotiationRejected { .. })
));
server.join();
}
#[test]
fn server_fill_strict_rejects_unexpected_fill_from_server() {
let requested = default_params();
let mut returned = requested.clone();
returned.server_fill = server_fill("unexpected");
let server = start_open_server(returned, None);
let mut client = Client::connect(config_for_params(server.addr, &requested)).unwrap();
assert!(matches!(
client.open(),
Err(ClientError::NegotiationRejected { .. })
));
server.join();
} }
#[test] #[test]
@@ -176,14 +120,6 @@ fn server_fill_loose_allows_server_to_remove_fill() {
// ─── Echo behavior ─── // ─── Echo behavior ───
#[test]
fn server_fill_echo_reply_decoded_with_fill_configured() {
let mut params = default_params();
params.server_fill = server_fill("rand");
let run = run_one_probe(params, TimestampFields::default());
assert!(matches!(run.reply, ClientEvent::EchoReply { .. }));
}
// server_fill is a negotiation/config parameter only; it does not affect // server_fill is a negotiation/config parameter only; it does not affect
// client-observable reply payload layout. The client sends server_fill in // client-observable reply payload layout. The client sends server_fill in
// the open request and expects the server to use it for reply payload // the open request and expects the server to use it for reply payload
@@ -275,61 +275,3 @@ macro_rules! debug_eprintln {
} }
use debug_eprintln; use debug_eprintln;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn startup_failure_details_include_bind_command_status_and_output() {
let status = Command::new("sh")
.arg("-c")
.arg("exit 7")
.status()
.expect("shell exits");
let failure = StartupFailure {
bind: "127.0.0.1:12345".to_owned(),
command: "\"irtt\" \"server\"".to_owned(),
output: "stderr: listen udp4 127.0.0.1:12345: bind: address already in use".to_owned(),
exit_status: Some(status),
error: Some("readiness timed out or server exited before ready".to_owned()),
};
let details = failure.details();
assert!(details.contains("bind: 127.0.0.1:12345"));
assert!(details.contains("command: \"irtt\" \"server\""));
assert!(details.contains("exit status:"));
assert!(details.contains("address already in use"));
}
#[test]
fn startup_failure_summary_includes_attempt_count_and_each_bind() {
let failures = vec![
StartupFailure {
bind: "127.0.0.1:11111".to_owned(),
command: "\"irtt\" \"server\" -b 127.0.0.1:11111".to_owned(),
output: "stdout: first".to_owned(),
exit_status: None,
error: Some("readiness timed out or server exited before ready".to_owned()),
},
StartupFailure {
bind: "127.0.0.1:22222".to_owned(),
command: "\"irtt\" \"server\" -b 127.0.0.1:22222".to_owned(),
output: "stderr: second".to_owned(),
exit_status: None,
error: Some("readiness timed out or server exited before ready".to_owned()),
},
];
let message = format_startup_failures("irtt", &failures);
assert!(message.contains("after 2 attempt(s)"));
assert!(message.contains("attempt 1/2"));
assert!(message.contains("attempt 2/2"));
assert!(message.contains("127.0.0.1:11111"));
assert!(message.contains("127.0.0.1:22222"));
assert!(message.contains("stdout: first"));
assert!(message.contains("stderr: second"));
}
}