Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ folded into Dropped sources.
- [Identity and recovery guide](/quest/m1/identity-guide.md) - explain pinned catalogs, lazy jobs, takeover, restart and version compatibility
- [Finalize moq-lite-07](/quest/m1/lite07-finalize.md) - when the maintainer cuts it, lite-07 negotiates as `moq-lite-07` and the next release ships it
- [Dropped sources](/quest/m1/dropped-sources.md) - track consumers see the producer's real error on every end path, never `Dropped`; a dead route ends Unroutable, and the TS follower lingers on announcements instead of matching errors
- [Release warm FETCH](/quest/m1/release-warm-fetch.md) - on the 0.17 line, a FETCH of a group a subscription delivered in part gets every frame instead of stalling on a parked open group
- [Malformed moq-lite input](/quest/m1/lite-malformed-close.md) - a lite peer that breaks a control-stream rule, including SETUP's client-only parameters, gets PROTOCOL_VIOLATION, and a Report-level publisher answers PROBE targets, in Rust and js/net
- [Client settings parity](/quest/m1/obs-client-config.md) - moq-ffi offers moq-c's client knobs, and the OBS Advanced settings get back the ones the C++ migration dropped
- [Session report parity](/quest/m1/obs-session-report.md) - a session reports its negotiated draft and reconnect failures, so the OBS dock shows them again
Expand Down
47 changes: 0 additions & 47 deletions quest/m1/release-warm-fetch.md

This file was deleted.

98 changes: 98 additions & 0 deletions rs/moq-net/tests/idle_cancel_refetch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! A relay whose last reader leaves mid-group cancels the idle upstream subscription. A later
//! fetch of that group still gets every frame (#5348, a release-line regression).

mod support;

use std::time::Duration;

use moq_net::{Hop, Version};
use support::harness::{MockConnectOptions, connect_mock};

const TIMEOUT: Duration = Duration::from_secs(5);

fn produce_origin(hop: u64) -> moq_net::origin::Producer {
let (producer, driver) = moq_net::origin::Producer::new(moq_net::origin::Config::new(Hop::new(hop).unwrap()));
support::harness::spawn(driver);
producer
}

#[moq_net_sim::test]
async fn a_group_cut_by_an_idle_cancel_is_refetched_whole() {
let publisher = produce_origin(1);
let broadcast = publisher.create_broadcast("bcast").unwrap();
let track = broadcast
.create_track("audio", moq_net::track::Info::default().with_timescale(None))
.unwrap();
broadcast.announce(Default::default()).unwrap();

let mut g0 = track.create_group(moq_net::group::Info { sequence: 0 }).unwrap();
g0.write_frame(None, &b"0a"[..]).unwrap();
g0.finish().unwrap();
let mut g1 = track.create_group(moq_net::group::Info { sequence: 1 }).unwrap();
g1.write_frame(None, &b"1a"[..]).unwrap();

let client = produce_origin(2);
let mut options = MockConnectOptions::new("moq-lite-06".parse::<Version>().unwrap());
options.server_publish = Some(publisher.consume());
options.client_subscribe = Some(client.clone());
let _pair = connect_mock(options).await;

let consumer = client.consume();
moq_net_sim::timeout(TIMEOUT, consumer.routed("bcast"))
.await
.unwrap()
.unwrap();
let remote = moq_net_sim::timeout(TIMEOUT, consumer.request_broadcast("bcast", None))
.await
.unwrap()
.unwrap();

{
let mut subscriber = moq_net_sim::timeout(TIMEOUT, remote.track("audio").unwrap().subscribe(None))
.await
.unwrap()
.unwrap();
let mut group = moq_net_sim::timeout(TIMEOUT, subscriber.recv_group())
.await
.unwrap()
.unwrap()
.unwrap();
assert_eq!(group.sequence, 1);
let frame = moq_net_sim::timeout(TIMEOUT, group.read_frame())
.await
.unwrap()
.unwrap()
.unwrap();
assert_eq!(&frame.payload[..], b"1a");
}

// The relay cancels the idle upstream subscription.
moq_net_sim::timeout(TIMEOUT, track.demand().unused())
.await
.unwrap()
.unwrap();

g1.write_frame(None, &b"1b"[..]).unwrap();
g1.finish().unwrap();
let mut g2 = track.create_group(moq_net::group::Info { sequence: 2 }).unwrap();
g2.write_frame(None, &b"2a"[..]).unwrap();

let track = remote.track("audio").unwrap();
let _feed = track.subscribe(None);
let mut group = moq_net_sim::timeout(TIMEOUT, track.fetch_group(1, None))
.await
.unwrap()
.unwrap();
let mut frames = Vec::new();
loop {
match moq_net_sim::timeout(TIMEOUT, group.read_frame())
.await
.expect("group 1 hangs")
{
Ok(Some(frame)) => frames.push(frame.payload),
Ok(None) => break,
Err(err) => panic!("group 1 failed: {err}"),
}
}
assert_eq!(frames, vec![&b"1a"[..], &b"1b"[..]]);
}
Loading