Skip to content

Commit 1a82543

Browse files
committed
test(sync): demultiplex sync frames by type in interop tests
The sync channel is full-duplex, so Origin can interleave server-initiated frames (e.g. a DeltaPush echoing another peer's write, or a keepalive) ahead of the response a test is waiting for. Loop and match on msg_type instead of assuming the next frame on the socket is always the expected reply.
1 parent 07d659a commit 1a82543

3 files changed

Lines changed: 52 additions & 30 deletions

File tree

nodedb-lite/tests/sync_interop_delta_ack.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,26 @@ async fn push_and_recv(
3535
.await
3636
.expect("send DeltaPush");
3737

38-
let resp = tokio::time::timeout(Duration::from_secs(10), ws.next())
39-
.await
40-
.expect("timeout waiting for delta response")
41-
.expect("stream closed before response")
42-
.expect("WebSocket read error");
43-
44-
SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode response frame")
38+
// The sync channel is full-duplex: Origin may interleave its own
39+
// server-initiated frames (e.g. a `DeltaPush` echoing another peer's
40+
// write, or a keepalive `Ping`) ahead of the ack for the frame we just
41+
// sent. A real client demultiplexes by frame type rather than assuming
42+
// the next frame is its response, so skip anything that is not a
43+
// terminal ack for our push.
44+
loop {
45+
let resp = tokio::time::timeout(Duration::from_secs(10), ws.next())
46+
.await
47+
.expect("timeout waiting for delta response")
48+
.expect("stream closed before response")
49+
.expect("WebSocket read error");
50+
51+
let frame =
52+
SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode response frame");
53+
match frame.msg_type {
54+
SyncMessageType::DeltaAck | SyncMessageType::DeltaReject => return frame,
55+
_ => continue,
56+
}
57+
}
4558
}
4659

4760
// ── tests ─────────────────────────────────────────────────────────────────────

nodedb-lite/tests/sync_interop_live.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -436,14 +436,22 @@ async fn live_shape_snapshot_with_wal_lsn() {
436436
.await
437437
.expect("send");
438438

439-
let resp = tokio::time::timeout(Duration::from_secs(5), ws.next())
440-
.await
441-
.expect("timeout")
442-
.expect("closed")
443-
.expect("error");
439+
// Full-duplex channel: Origin may interleave a server-initiated frame
440+
// (e.g. a `DeltaPush` for a concurrent write) ahead of the `ShapeSnapshot`
441+
// answering our subscribe. Demultiplex by frame type rather than assuming
442+
// the next frame is the snapshot.
443+
let frame = loop {
444+
let resp = tokio::time::timeout(Duration::from_secs(5), ws.next())
445+
.await
446+
.expect("timeout")
447+
.expect("closed")
448+
.expect("error");
444449

445-
let frame = SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode");
446-
assert_eq!(frame.msg_type, SyncMessageType::ShapeSnapshot);
450+
let frame = SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode");
451+
if frame.msg_type == SyncMessageType::ShapeSnapshot {
452+
break frame;
453+
}
454+
};
447455

448456
let snapshot: ShapeSnapshotMsg = frame.decode_body().expect("decode");
449457
assert_eq!(snapshot.shape_id, "lsn-live-shape");

nodedb-lite/tests/sync_interop_resync.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -47,23 +47,24 @@ async fn subscribe_shape(
4747
.await
4848
.expect("send ShapeSubscribe");
4949

50-
let resp = tokio::time::timeout(Duration::from_secs(10), ws.next())
51-
.await
52-
.expect("timeout waiting for ShapeSnapshot")
53-
.expect("stream closed before snapshot")
54-
.expect("WebSocket read error");
55-
56-
let frame = SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode frame");
57-
assert_eq!(
58-
frame.msg_type,
59-
SyncMessageType::ShapeSnapshot,
60-
"expected ShapeSnapshot, got {:?}",
61-
frame.msg_type
62-
);
50+
// The channel is full-duplex: Origin may interleave a server-initiated
51+
// frame (e.g. a `DeltaPush` for a concurrent write, or a keepalive) ahead
52+
// of the `ShapeSnapshot` that answers our subscribe. Demultiplex by frame
53+
// type rather than assuming the next frame is the snapshot.
54+
loop {
55+
let resp = tokio::time::timeout(Duration::from_secs(10), ws.next())
56+
.await
57+
.expect("timeout waiting for ShapeSnapshot")
58+
.expect("stream closed before snapshot")
59+
.expect("WebSocket read error");
6360

64-
frame
65-
.decode_body::<ShapeSnapshotMsg>()
66-
.expect("decode ShapeSnapshotMsg")
61+
let frame = SyncFrame::from_bytes(resp.into_data().as_ref()).expect("decode frame");
62+
if frame.msg_type == SyncMessageType::ShapeSnapshot {
63+
return frame
64+
.decode_body::<ShapeSnapshotMsg>()
65+
.expect("decode ShapeSnapshotMsg");
66+
}
67+
}
6768
}
6869

6970
// ── tests ─────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)