diff --git a/crates/irtt-cli/src/lib.rs b/crates/irtt-cli/src/lib.rs index 01b2ac1..962c46b 100644 --- a/crates/irtt-cli/src/lib.rs +++ b/crates/irtt-cli/src/lib.rs @@ -1217,17 +1217,6 @@ mod tests { 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] fn machine_echo_reply_metadata_dscp_46_ecn_2_prints_values() { let line = format_event( @@ -1252,18 +1241,6 @@ mod tests { 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] fn machine_late_reply_metadata_observed_values_prints_values() { let line = format_event( @@ -1276,20 +1253,6 @@ mod tests { 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] fn simple_prints_readable_reply_line() { let line = format_event(&reply_event(), OutputMode::Simple).unwrap(); diff --git a/crates/irtt-client/tests/hmac.rs b/crates/irtt-client/tests/hmac.rs index 749f6d2..fbd099e 100644 --- a/crates/irtt-client/tests/hmac.rs +++ b/crates/irtt-client/tests/hmac.rs @@ -122,47 +122,27 @@ fn hmac_close_success_sends_authenticated_close_and_closes_session() { } #[test] -fn missing_client_key_against_hmac_required_server_times_out() { - let key = b"compat-secret".to_vec(); - let server = start_hmac_required_open_drop_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 = None; +fn hmac_required_server_rejects_missing_or_wrong_client_key() { + for (hmac_key, expected_hmac_flag) in [(None, false), (Some(b"wrong-secret".to_vec()), true)] { + 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 = hmac_key; - let mut client = Client::connect(config).unwrap(); - assert!(matches!(client.open(), Err(ClientError::OpenTimeout))); + 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: false, - bad_hmac: true - }] - )); - 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(); + let observations = server.observations(1); + assert!(matches!( + observations.as_slice(), + [ServerObservation::RejectedHmac { + hmac, + bad_hmac: true + }] if *hmac == expected_hmac_flag + )); + server.join(); + } } #[test] @@ -311,25 +291,15 @@ fn backend_hmac_correct_key_succeeds() { } #[test] -fn backend_hmac_wrong_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 = Some(b"wrong-secret".to_vec()); +fn backend_hmac_required_rejects_missing_or_wrong_client_key() { + for hmac_key in [None, Some(b"wrong-secret".to_vec())] { + 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 = hmac_key; - let mut client = Client::connect(config).unwrap(); - 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))); + let mut client = Client::connect(config).unwrap(); + assert!(matches!(client.open(), Err(ClientError::OpenTimeout))); + } } diff --git a/crates/irtt-client/tests/server_fill.rs b/crates/irtt-client/tests/server_fill.rs index c314155..96dbb86 100644 --- a/crates/irtt-client/tests/server_fill.rs +++ b/crates/irtt-client/tests/server_fill.rs @@ -1,6 +1,6 @@ mod support; -use irtt_client::{Client, ClientConfig, ClientError, ClientEvent, NegotiationPolicy}; +use irtt_client::{Client, ClientConfig, ClientError, NegotiationPolicy}; use irtt_proto::{Params, TimestampFields}; use support::{ @@ -32,63 +32,34 @@ fn echo_observation(run: &OneProbeRun) -> (usize, bool, u64, u32) { // ─── Config mapping ─── #[test] -fn server_fill_none_produces_no_fill_in_open_params() { - let params = default_params(); - let run = run_one_probe(params, TimestampFields::default()); - assert!(open_observation_params(&run).server_fill.is_none()); +fn server_fill_none_short_and_max_map_into_open_params() { + for fill in [None, Some("abc"), Some("0123456789abcdef0123456789abcdef")] { + let mut params = default_params(); + 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] -fn server_fill_short_value_maps_into_open_params() { - let mut params = default_params(); - params.server_fill = server_fill("abc"); - 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("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 { .. }) - )); +fn server_fill_empty_and_oversized_values_are_rejected_at_config_boundary() { + for fill in ["", "0123456789abcdef0123456789abcdefx"] { + let config = ClientConfig { + server_fill: Some(fill.to_owned()), + ..ClientConfig::default() + }; + assert!(matches!( + Client::connect(config), + Err(ClientError::InvalidConfig { .. }) + )); + } } // ─── Open negotiation ─── @@ -102,53 +73,26 @@ fn server_fill_negotiated_params_reflect_accepted_value() { } #[test] -fn server_fill_strict_rejects_removed_fill() { - let mut requested = default_params(); - requested.server_fill = server_fill("rand"); +fn server_fill_strict_rejects_removed_changed_or_unexpected_fill() { + for (requested_fill, returned_fill) in [ + (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(); - returned.server_fill = None; + let mut returned = requested.clone(); + returned.server_fill = returned_fill.and_then(server_fill); - 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_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(); + 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] @@ -176,14 +120,6 @@ fn server_fill_loose_allows_server_to_remove_fill() { // ─── 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 // client-observable reply payload layout. The client sends server_fill in // the open request and expects the server to use it for reply payload diff --git a/crates/irtt-client/tests/support/real_irtt.rs b/crates/irtt-client/tests/support/real_irtt.rs index dca4d08..646bbd0 100644 --- a/crates/irtt-client/tests/support/real_irtt.rs +++ b/crates/irtt-client/tests/support/real_irtt.rs @@ -275,61 +275,3 @@ macro_rules! 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")); - } -}