From 755f2e708d16244ba274d1255c08f38a1b4d99d3 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 6 Nov 2026 13:31:08 -0800 Subject: [PATCH 1/7] chore(quest): claim quest/m1/mock-clock-tests/rs-relay.md Quest-Claim: 900e454fcb0275cb From 8a165d33305124acb08aca727b53c0336da8a992 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 6 Nov 2026 13:52:14 -0800 Subject: [PATCH 2/7] test(relay): auth and revalidate tests prove a session stayed open by its end reason Co-Authored-By: Claude Opus 5.5 --- rs/moq-relay/src/auth.rs | 8 +- rs/moq-relay/src/session.rs | 9 +- .../tests/integration/auth_lifetime.rs | 213 ++++++++++-------- .../tests/integration/session_revalidate.rs | 114 ++++++---- 4 files changed, 198 insertions(+), 146 deletions(-) diff --git a/rs/moq-relay/src/auth.rs b/rs/moq-relay/src/auth.rs index 720f3cbff8b..5e0bb770b67 100644 --- a/rs/moq-relay/src/auth.rs +++ b/rs/moq-relay/src/auth.rs @@ -1856,14 +1856,12 @@ mod tests { #[tokio::test] async fn dropping_the_last_auth_ends_admissions() { + use futures::FutureExt; + let (auth, mut admissions) = Auth::embedded("relay-1"); let clone = auth.clone(); drop(auth); - assert!( - kio::clock::timeout(std::time::Duration::ZERO, admissions.next()) - .await - .is_err() - ); + assert!(admissions.next().now_or_never().is_none(), "a clone still admits"); drop(clone); assert!(admissions.next().await.is_none()); } diff --git a/rs/moq-relay/src/session.rs b/rs/moq-relay/src/session.rs index f3f4878d4e0..e76ea793502 100644 --- a/rs/moq-relay/src/session.rs +++ b/rs/moq-relay/src/session.rs @@ -590,6 +590,8 @@ mod tests { #[tokio::test] async fn a_push_wakes_the_registration_once() { + use futures::FutureExt; + let registry = Registry::new(); let request = request("abc", "/room", "127.0.0.1:1"); let reg = registry.register(request); @@ -598,11 +600,6 @@ mod tests { kio::clock::timeout(Duration::from_secs(1), reg.nudged()) .await .expect("the registration woke"); - assert!( - kio::clock::timeout(std::time::Duration::from_millis(20), reg.nudged()) - .await - .is_err(), - "a single push wakes once" - ); + assert!(reg.nudged().now_or_never().is_none(), "a single push wakes once"); } } diff --git a/rs/moq-relay/tests/integration/auth_lifetime.rs b/rs/moq-relay/tests/integration/auth_lifetime.rs index 6feab4c60f3..c3e6153c04f 100644 --- a/rs/moq-relay/tests/integration/auth_lifetime.rs +++ b/rs/moq-relay/tests/integration/auth_lifetime.rs @@ -54,8 +54,8 @@ struct Script { seen: Arc>>, /// Answers each `end` only once a permit is added, when [`Self::hold_ends`] set it. end_gate: Arc>>>, - /// Notified as each `end` arrives. - end_arrived: Arc, + /// Bumped as each request arrives, so a test awaits one instead of sleeping. + arrived: Arc>, } impl Script { @@ -66,7 +66,7 @@ impl Script { revalidate_http: Arc::new(Mutex::new(None)), seen: Arc::new(Mutex::new(Vec::new())), end_gate: Arc::default(), - end_arrived: Arc::default(), + arrived: Arc::new(tokio::sync::watch::Sender::new(())), } } @@ -94,13 +94,37 @@ impl Script { .lock() .unwrap() .iter() - .filter(|r| matches!(r.event, Event::End { .. })) + .filter(|r| is_end(r)) .cloned() .collect() } + /// Wait until the requests seen so far satisfy `done`, and return them. + async fn until(&self, what: &str, done: impl Fn(&[Request]) -> bool) -> Vec { + let mut arrived = self.arrived.subscribe(); + let waited = kio::clock::timeout(TIMEOUT, async { + loop { + let seen = self.seen.lock().unwrap().clone(); + if done(&seen) { + return seen; + } + arrived.changed().await.expect("the script outlives its waiters"); + } + }) + .await; + waited.unwrap_or_else(|_| panic!("{what}: got {:?}", self.seen.lock().unwrap())) + } + + /// Wait for at least `n` `end`s, and return every one. + async fn ends_at_least(&self, n: usize, what: &str) -> Vec { + self.until(what, |seen| seen.iter().filter(|r| is_end(r)).count() >= n) + .await; + self.ends() + } + async fn handle(State(script): State