test: retain durable negotiation and lifecycle review coverage
This commit is contained in:
4 files changed
+112
No files matched your search
@@ -87,6 +87,63 @@ fn dispatcher_reports_and_runs_the_enabled_applets() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The default presentation must reach a meaningful packet summary for a finite run.
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
#[test]
|
||||||
|
fn default_client_output_emits_a_packet_summary() {
|
||||||
|
use std::{io::Read, process::Stdio, thread};
|
||||||
|
let server = in_tree_server::InTreeServer::start(ServerConfig::default());
|
||||||
|
let mut client = ClientProcess(
|
||||||
|
Command::new(env!("CARGO_BIN_EXE_irtt-client"))
|
||||||
|
.env_clear()
|
||||||
|
.args([
|
||||||
|
"--duration",
|
||||||
|
"100ms",
|
||||||
|
"--interval",
|
||||||
|
"20ms",
|
||||||
|
&server.addr.to_string(),
|
||||||
|
])
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
let mut stdout = client.0.stdout.take().unwrap();
|
||||||
|
let stdout = thread::spawn(move || {
|
||||||
|
let mut text = String::new();
|
||||||
|
stdout.read_to_string(&mut text).unwrap();
|
||||||
|
text
|
||||||
|
});
|
||||||
|
let mut stderr = client.0.stderr.take().unwrap();
|
||||||
|
let stderr = thread::spawn(move || {
|
||||||
|
let mut text = String::new();
|
||||||
|
stderr.read_to_string(&mut text).unwrap();
|
||||||
|
text
|
||||||
|
});
|
||||||
|
let status = client.wait();
|
||||||
|
let stdout = stdout.join().unwrap();
|
||||||
|
let stderr = stderr.join().unwrap();
|
||||||
|
assert!(status.success(), "{stderr}");
|
||||||
|
assert!(stdout.contains("irtt-rs summary"), "{stdout}");
|
||||||
|
let packets = stdout
|
||||||
|
.lines()
|
||||||
|
.find(|line| line.starts_with("packets:"))
|
||||||
|
.expect("default output must include the packet summary");
|
||||||
|
for field in ["sent=", "received="] {
|
||||||
|
let count = packets
|
||||||
|
.split_whitespace()
|
||||||
|
.find_map(|word| word.strip_prefix(field))
|
||||||
|
.unwrap()
|
||||||
|
.parse::<u64>()
|
||||||
|
.unwrap();
|
||||||
|
assert!(
|
||||||
|
count > 0,
|
||||||
|
"summary must report {field} a positive count: {packets}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A real authenticated server detects broken client argument-to-config mapping.
|
// A real authenticated server detects broken client argument-to-config mapping.
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -1,5 +1,26 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
// Untrusted returned intervals must be rejected before managed scheduling,
|
||||||
|
// even when loose negotiation permits legitimate server restrictions.
|
||||||
|
#[test]
|
||||||
|
fn loose_open_rejects_nonpositive_returned_intervals() {
|
||||||
|
for interval_ns in [0, -1] {
|
||||||
|
let mut returned = default_params();
|
||||||
|
returned.interval_ns = interval_ns;
|
||||||
|
let server = open_success_server(returned);
|
||||||
|
let config = ClientConfig {
|
||||||
|
negotiation_policy: NegotiationPolicy::Loose,
|
||||||
|
..default_test_config(server.addr)
|
||||||
|
};
|
||||||
|
let mut client = Client::connect(config).unwrap();
|
||||||
|
assert!(
|
||||||
|
matches!(client.open(), Err(ClientError::NegotiationRejected { .. })),
|
||||||
|
"returned interval {interval_ns} must be rejected"
|
||||||
|
);
|
||||||
|
server.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn open_fails_when_already_open() {
|
fn open_fails_when_already_open() {
|
||||||
let params = default_params();
|
let params = default_params();
|
||||||
|
|||||||
@@ -162,9 +162,18 @@ async fn target_updates_preserve_identical_sessions_and_retire_removed_generatio
|
|||||||
handle.update_targets(vec![]).unwrap().await.unwrap();
|
handle.update_targets(vec![]).unwrap().await.unwrap();
|
||||||
loop {
|
loop {
|
||||||
if let ManagedEvent::TargetFinished { outcome } = events.recv().await.unwrap() {
|
if let ManagedEvent::TargetFinished { outcome } = events.recv().await.unwrap() {
|
||||||
|
let status = handle.status();
|
||||||
assert_eq!(outcome.target, first);
|
assert_eq!(outcome.target, first);
|
||||||
assert_eq!(outcome.end_reason, ManagedTargetEndReason::Removed);
|
assert_eq!(outcome.end_reason, ManagedTargetEndReason::Removed);
|
||||||
assert_eq!(outcome.cleanup_failure, None);
|
assert_eq!(outcome.cleanup_failure, None);
|
||||||
|
assert_eq!(status.total_target_outcomes, 1);
|
||||||
|
assert_eq!(status.successful_target_outcomes, 1);
|
||||||
|
assert_eq!(
|
||||||
|
status.recent_target_outcomes.as_ref(),
|
||||||
|
&[(*outcome).clone()]
|
||||||
|
);
|
||||||
|
assert!(status.targets.iter().all(|target| target.target != first
|
||||||
|
|| target.lifecycle == ManagedTargetLifecycle::Terminal));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,6 +200,28 @@ async fn target_updates_preserve_identical_sessions_and_retire_removed_generatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let stop = handle.stop();
|
let stop = handle.stop();
|
||||||
|
loop {
|
||||||
|
match events.recv().await.unwrap() {
|
||||||
|
ManagedEvent::TargetFinished { outcome } => {
|
||||||
|
let status = handle.status();
|
||||||
|
assert_eq!(outcome.target, second);
|
||||||
|
assert_eq!(status.total_target_outcomes, 2);
|
||||||
|
assert_eq!(
|
||||||
|
status.recent_target_outcomes.as_ref(),
|
||||||
|
&[(*outcome).clone()]
|
||||||
|
);
|
||||||
|
assert!(status.targets.iter().all(|target| target.target != second
|
||||||
|
|| target.lifecycle == ManagedTargetLifecycle::Terminal));
|
||||||
|
}
|
||||||
|
ManagedEvent::Completed { outcome } => {
|
||||||
|
let status = handle.status();
|
||||||
|
assert_eq!(status.lifecycle, ManagedLifecycle::Completed);
|
||||||
|
assert_eq!(status.final_outcome.as_ref(), Some(&outcome));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
let outcome = run.await.unwrap();
|
let outcome = run.await.unwrap();
|
||||||
stop.await;
|
stop.await;
|
||||||
assert_eq!(outcome.end_reason, ManagedEndReason::StopRequested);
|
assert_eq!(outcome.end_reason, ManagedEndReason::StopRequested);
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ fn authenticated_sessions_are_bounded_and_owned_by_the_opening_endpoint() {
|
|||||||
Some(key),
|
Some(key),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mut unkeyed = ServerCore::new(ServerConfig::default());
|
||||||
|
assert!(unkeyed.handle_datagram(peer, &open).unwrap().is_none());
|
||||||
|
assert_eq!(unkeyed.session_count(), 0);
|
||||||
let unauthenticated = encode_request(
|
let unauthenticated = encode_request(
|
||||||
RequestToEncode::Open {
|
RequestToEncode::Open {
|
||||||
params: ¶ms,
|
params: ¶ms,
|
||||||
|
|||||||
Reference in new issue
Block a user