fix(client): bound managed drain deadline bookkeeping
Rust CI / cargo fmt (push) Successful in 16s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 33s
Rust CI / cargo clippy (push) Successful in 35s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 22s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m13s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 6s
Supply chain / cargo-deny bans licenses sources (push) Successful in 5s
Supply chain / actionlint (push) Successful in 2s
Netem Interop / netem interop (push) Successful in 1m2s
Rust CI / cargo fmt (push) Successful in 16s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 33s
Rust CI / cargo clippy (push) Successful in 35s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 22s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Successful in 1m13s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 6s
Supply chain / cargo-deny bans licenses sources (push) Successful in 5s
Supply chain / actionlint (push) Successful in 2s
Netem Interop / netem interop (push) Successful in 1m2s
Reuse deadline-ordered linked storage in the separate timed-out retention map so each drain lookup reads its tail and late replies unlink directly. Preserve FIFO capacity eviction, original timeouts, classification, and the managed work budget; cover bounded inspection work and retention lifecycle transitions.
This commit is contained in:
2 files changed
+187
-35
No files matched your search
@@ -1245,6 +1245,86 @@ mod tests {
|
||||
events.into_iter().next().unwrap()
|
||||
}
|
||||
|
||||
// The latest retained deadline is internal to managed draining. Exercise
|
||||
// ordinary session transitions to check its classification/retention policy.
|
||||
#[cfg(feature = "tokio")]
|
||||
#[test]
|
||||
fn retained_deadline_tracks_timeouts_late_replies_eviction_and_close() {
|
||||
let mut machine = opened();
|
||||
assert_eq!(send(&mut machine).seq, 0);
|
||||
let first = machine.latest_probe_timeout_deadline().unwrap();
|
||||
assert_eq!(send(&mut machine).seq, 1);
|
||||
let second = machine.latest_probe_timeout_deadline().unwrap();
|
||||
let batch = machine.poll_timeouts_bounded_at(second, 1).unwrap();
|
||||
assert!(
|
||||
matches!(batch.events[0], ClientEvent::EchoLoss { seq: 0, timeout_at, .. } if timeout_at == first)
|
||||
);
|
||||
assert!(batch.more_due);
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), Some(second));
|
||||
let batch = machine.poll_timeouts_bounded_at(second, 1).unwrap();
|
||||
assert!(
|
||||
matches!(batch.events[0], ClientEvent::EchoLoss { seq: 1, timeout_at, .. } if timeout_at == second)
|
||||
);
|
||||
assert!(!batch.more_due);
|
||||
assert!(machine.pending_is_empty());
|
||||
assert_eq!(machine.next_probe_timeout_deadline(), None);
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), Some(second));
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 1),
|
||||
ClientEvent::LateReply {
|
||||
sent_at: Some(_),
|
||||
rtt: Some(_),
|
||||
..
|
||||
}
|
||||
));
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), Some(first));
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 1),
|
||||
ClientEvent::DuplicateReply { .. }
|
||||
));
|
||||
|
||||
for seq in 2..4 {
|
||||
assert_eq!(send(&mut machine).seq, seq);
|
||||
let deadline = machine.latest_probe_timeout_deadline().unwrap();
|
||||
machine.poll_timeouts_at(deadline).unwrap();
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), Some(deadline));
|
||||
}
|
||||
// Capacity eviction removes seq 0's measurement, not late classification.
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 0),
|
||||
ClientEvent::LateReply {
|
||||
sent_at: None,
|
||||
rtt: None,
|
||||
..
|
||||
}
|
||||
));
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 3),
|
||||
ClientEvent::LateReply {
|
||||
sent_at: Some(_),
|
||||
rtt: Some(_),
|
||||
..
|
||||
}
|
||||
));
|
||||
assert!(machine.latest_probe_timeout_deadline().is_some());
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 2),
|
||||
ClientEvent::LateReply {
|
||||
sent_at: Some(_),
|
||||
rtt: Some(_),
|
||||
..
|
||||
}
|
||||
));
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), None);
|
||||
|
||||
assert_eq!(send(&mut machine).seq, 4);
|
||||
let deadline = machine.next_probe_timeout_deadline().unwrap();
|
||||
machine.poll_timeouts_at(deadline).unwrap();
|
||||
let commit = machine.prepare_close().unwrap().commit;
|
||||
machine.commit_local_close(commit, ClientTimestamp::now());
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), None);
|
||||
}
|
||||
|
||||
// Advancing a real client through 2^32 submissions is unreasonable. Only
|
||||
// move the send/receive sequence epoch; construct completion/timeout history through
|
||||
// ordinary machine transitions and assert emitted behavior on reuse.
|
||||
@@ -1278,6 +1358,8 @@ mod tests {
|
||||
reply(&mut machine, 0),
|
||||
ClientEvent::EchoReply { seq: 0, .. }
|
||||
));
|
||||
#[cfg(feature = "tokio")]
|
||||
assert_eq!(machine.latest_probe_timeout_deadline(), None);
|
||||
assert!(matches!(
|
||||
reply(&mut machine, 0),
|
||||
ClientEvent::DuplicateReply { seq: 0, .. }
|
||||
|
||||
Reference in new issue
Block a user