diff --git a/internal/services/datatransfer_test.go b/internal/services/datatransfer_test.go index eacd87b..2984b36 100644 --- a/internal/services/datatransfer_test.go +++ b/internal/services/datatransfer_test.go @@ -6,6 +6,7 @@ import ( "testing" "git.saqut.com/saqut/mwse/internal/testutil" + "git.saqut.com/saqut/mwse/internal/ws" ) // findReply scans the captured frames for a [payload, id] frame whose id slot is @@ -100,6 +101,50 @@ func TestTunnelLargePayloadIntact(t *testing.T) { } } +// TestWebRTCSignalingRelay is the #31 parity test. WebRTC signaling is not a +// distinct engine concept: the SDK tunnels offer/answer/ICE as opaque +// {type:":rtcpack:", payload:{...}} packs over pack/to. The engine must carry +// them through unchanged, in both directions, without inspecting the RTC payload. +func TestWebRTCSignalingRelay(t *testing.T) { + hub := newHub() + a, fa := connect(hub, "a") + b, fb := connect(hub, "b") + + signal := func(from *ws.Client, to string, rtc map[string]any) { + hub.Handle(from, msg("pack/to", "to", to, + "pack", map[string]any{"type": ":rtcpack:", "payload": rtc})) + } + + // A → B: SDP offer. + signal(a, "b", map[string]any{"type": "offer", "value": map[string]any{"sdp": "v=0...offer"}}) + offerPack := asMap(t, waitSignal(t, fb, "pack")["pack"]) + if offerPack["type"] != ":rtcpack:" { + t.Fatalf("offer relayed as %v, want :rtcpack:", offerPack["type"]) + } + if rtc := asMap(t, offerPack["payload"]); rtc["type"] != "offer" { + t.Fatalf("inner signaling type = %v, want offer", rtc["type"]) + } + + // B → A: SDP answer. + signal(b, "a", map[string]any{"type": "answer", "value": map[string]any{"sdp": "v=0...answer"}}) + answerPack := asMap(t, waitSignal(t, fa, "pack")["pack"]) + if rtc := asMap(t, answerPack["payload"]); rtc["type"] != "answer" { + t.Fatalf("inner signaling type = %v, want answer", rtc["type"]) + } + + // A → B: ICE candidate — payload carried verbatim. + cand := map[string]any{"candidate": "candidate:842163049 1 udp ...", "sdpMLineIndex": float64(0)} + signal(a, "b", map[string]any{"type": "icecandidate", "value": cand}) + waitFor(t, func() bool { + for _, raw := range fb.Writes() { + if strings.Contains(string(raw), "icecandidate") { + return true + } + } + return false + }) +} + // assertNoAddressLeak fails if a relayed payload exposes anything resembling the // sender's real network identity. func assertNoAddressLeak(t *testing.T, payload map[string]any) {