//! Helpers shared between harness modules and tests. use std::future::Future; use std::net::{Ipv4Addr, SocketAddr, TcpListener}; use std::time::{Duration, Instant}; /// Pick a free TCP port by binding to `127.0.0.1:0` and immediately releasing. /// /// There is a small race: another process may grab the port between drop and /// the child re-binding, but for local single-user test runs it's negligible. pub fn free_port() -> u16 { let l = TcpListener::bind(SocketAddr::from((Ipv4Addr::LOCALHOST, 0))).expect("bind :0"); l.local_addr().expect("local_addr").port() } /// Poll `cond` every 50ms until it returns `true` or `timeout` elapses. /// Panics on timeout with `label`. pub async fn wait_for_async(label: &str, timeout: Duration, mut cond: F) where F: FnMut() -> Fut, Fut: Future, { let deadline = Instant::now() + timeout; while Instant::now() < deadline { if cond().await { return; } tokio::time::sleep(Duration::from_millis(50)).await; } panic!("timed out after {timeout:?} waiting for: {label}"); }