Skip to content

Commit 83df852

Browse files
testclaude
andcommitted
feat(tcp-connector): bound embassy loopback tests with a wall-clock watchdog
The loopback harness polls two non-terminating embassy-net stacks in the background, so a transport regression or a dropped crossover packet would leave `block_on` pending until the outer CI timeout instead of failing the test. Race the foreground/background `select` against a 20s wall-clock watchdog that re-arms its waker each poll (so the deadline is observed even when the stacks would otherwise park) and panics with a clear message. Addresses review feedback on #179. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 73f96c5 commit 83df852

1 file changed

Lines changed: 35 additions & 3 deletions

File tree

aimdb-tcp-connector/tests/embassy_loopback.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,19 @@ where
116116
Fut: Future<Output = ()>,
117117
F: FnOnce(Stack<'static>, Stack<'static>) -> Fut,
118118
{
119+
use core::future::poll_fn;
120+
use core::task::Poll;
121+
use std::time::{Duration, Instant};
122+
119123
use futures::future::{join4, select, Either};
120124
use futures::pin_mut;
121125

126+
// A stuck foreground (a transport regression or a dropped crossover packet)
127+
// would otherwise leave `block_on` pending forever, failing only at the outer
128+
// CI timeout. Bound every test with a wall-clock watchdog so `make check`
129+
// fails promptly and points at the hang instead.
130+
const WATCHDOG: Duration = Duration::from_secs(20);
131+
122132
let (server_stack, mut server_net, server_ch) = make_stack(SERVER_IP, 0x1111_2222);
123133
let (client_stack, mut client_net, client_ch) = make_stack(CLIENT_IP, 0x3333_4444);
124134

@@ -138,9 +148,31 @@ where
138148
futures::executor::block_on(async {
139149
pin_mut!(foreground);
140150
pin_mut!(background);
141-
match select(foreground, background).await {
142-
Either::Left(_) => {}
143-
Either::Right(_) => panic!("background stacks ended before the test"),
151+
let session = select(foreground, background);
152+
pin_mut!(session);
153+
154+
let deadline = Instant::now() + WATCHDOG;
155+
let watchdog = poll_fn(move |cx| {
156+
if Instant::now() >= deadline {
157+
Poll::Ready(())
158+
} else {
159+
// Re-arm each poll so the executor keeps spinning and observes the
160+
// deadline even if the stacks and foreground would otherwise park.
161+
cx.waker().wake_by_ref();
162+
Poll::Pending
163+
}
164+
});
165+
pin_mut!(watchdog);
166+
167+
match select(session, watchdog).await {
168+
Either::Left((Either::Left(_), _)) => {}
169+
Either::Left((Either::Right(_), _)) => {
170+
panic!("background stacks ended before the test")
171+
}
172+
Either::Right(_) => panic!(
173+
"watchdog: foreground stuck for {}s (transport regression or dropped packet)",
174+
WATCHDOG.as_secs()
175+
),
144176
}
145177
});
146178
}

0 commit comments

Comments
 (0)