test(client): simplify staggered deadline regression
This commit is contained in:
1 file changed
+20
-76
@@ -1968,9 +1968,7 @@ impl ManagedClientTask {
|
|||||||
&& self.config.pacing == ManagedPacing::Staggered
|
&& self.config.pacing == ManagedPacing::Staggered
|
||||||
&& self.active_count() > 0
|
&& self.active_count() > 0
|
||||||
{
|
{
|
||||||
// A release gate delays a send opportunity; it cannot create one.
|
send_deadline = gated_send_deadline(send_deadline, self.send_gate);
|
||||||
send_deadline = send_deadline
|
|
||||||
.map(|deadline| self.send_gate.map_or(deadline, |gate| deadline.max(gate)));
|
|
||||||
}
|
}
|
||||||
non_send_deadline.into_iter().chain(send_deadline).min()
|
non_send_deadline.into_iter().chain(send_deadline).min()
|
||||||
}
|
}
|
||||||
@@ -2068,6 +2066,11 @@ impl ManagedClientTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A release gate delays a send opportunity; it cannot create one.
|
||||||
|
fn gated_send_deadline(cadence: Option<Instant>, gate: Option<Instant>) -> Option<Instant> {
|
||||||
|
cadence.map(|deadline| gate.map_or(deadline, |gate| deadline.max(gate)))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
enum SendResult {
|
enum SendResult {
|
||||||
NotAttempted,
|
NotAttempted,
|
||||||
@@ -2396,80 +2399,21 @@ fn close_timeout_failure() -> ManagedTargetFailure {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Public poll counts depend on reactor/timer timing. Inspect the selected
|
|
||||||
// deadline instead, after a real managed send exhausts a finite schedule.
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exhausted_staggered_schedule_waits_for_probe_timeout_not_release_gate() {
|
fn release_gate_only_delays_an_existing_send_deadline() {
|
||||||
tokio::runtime::Builder::new_current_thread()
|
let earlier = Instant::now();
|
||||||
.enable_all()
|
let later = earlier + Duration::from_secs(1);
|
||||||
.build()
|
for (cadence, gate, expected) in [
|
||||||
.unwrap()
|
(None, None, None),
|
||||||
.block_on(async {
|
(None, Some(earlier), None),
|
||||||
time::timeout(Duration::from_secs(5), async {
|
(None, Some(later), None),
|
||||||
let mut server = irtt_server::Server::bind(
|
(Some(earlier), None, Some(earlier)),
|
||||||
"127.0.0.1:0".parse().unwrap(),
|
(Some(later), Some(earlier), Some(later)),
|
||||||
irtt_server::ServerConfig::default(),
|
(Some(earlier), Some(earlier), Some(earlier)),
|
||||||
)
|
(Some(earlier), Some(later), Some(later)),
|
||||||
.await
|
] {
|
||||||
.unwrap();
|
assert_eq!(gated_send_deadline(cadence, gate), expected);
|
||||||
let addr = server.local_addr().unwrap();
|
}
|
||||||
let server_task = tokio::spawn(async move {
|
|
||||||
server.run(std::future::pending::<()>()).await.unwrap();
|
|
||||||
});
|
|
||||||
let (mut task, handle) = ManagedClient::task(
|
|
||||||
ManagedClientConfig {
|
|
||||||
client: ClientConfig {
|
|
||||||
duration: Some(Duration::from_secs(10)),
|
|
||||||
interval: Duration::from_secs(15),
|
|
||||||
probe_timeout: Duration::from_secs(60),
|
|
||||||
..ClientConfig::default()
|
|
||||||
},
|
|
||||||
pacing: ManagedPacing::Staggered,
|
|
||||||
..ManagedClientConfig::default()
|
|
||||||
},
|
|
||||||
vec![ManagedTargetConfig::new("finite", addr.to_string())],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let mut events = handle.subscribe().unwrap();
|
|
||||||
std::future::poll_fn(|cx| {
|
|
||||||
if let Poll::Ready(outcome) = Pin::new(&mut task).poll(cx) {
|
|
||||||
panic!("managed target ended before its final probe: {outcome:?}");
|
|
||||||
}
|
|
||||||
while let Ok(event) = events.try_recv() {
|
|
||||||
if matches!(
|
|
||||||
event,
|
|
||||||
ManagedEvent::Client {
|
|
||||||
event: ClientEvent::EchoSent { .. },
|
|
||||||
..
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
return Poll::Ready(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Poll::Pending
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let TargetState::Active { client } = &task.targets[0].state else {
|
|
||||||
panic!("the final probe must remain active while pending");
|
|
||||||
};
|
|
||||||
assert!(client.has_pending_probes());
|
|
||||||
assert!(task.targets[0].schedule.as_ref().unwrap().is_finished());
|
|
||||||
let timeout = client.next_probe_timeout_deadline().unwrap();
|
|
||||||
assert!(task.send_gate.unwrap() < timeout);
|
|
||||||
assert_eq!(task.next_deadline(), Some(timeout));
|
|
||||||
|
|
||||||
// An expired gate must not register an immediately-ready
|
|
||||||
// timer either; no sleep or fake clock is needed.
|
|
||||||
task.send_gate = Some(Instant::now() - Duration::from_secs(1));
|
|
||||||
assert_eq!(task.next_deadline(), Some(timeout));
|
|
||||||
let mut cx = Context::from_waker(std::task::Waker::noop());
|
|
||||||
assert!(!task.register_timer(&mut cx));
|
|
||||||
server_task.abort();
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect("managed target did not send its final probe");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll latency through public events cannot distinguish an O(n) discovery
|
// Poll latency through public events cannot distinguish an O(n) discovery
|
||||||
|
|||||||
Reference in new issue
Block a user