Files
olcrtc/internal/transport/videochannel/inbound_test.go
zarazaex69 4639e0b3b7 refactor: extract shared transport framing helpers into internal/transport/common
videochannel, seichannel and vp8channel each carried independent copies of
randomID(), fragmentPayload(), inboundMessage + upsertInbound +
assembleMessage + ackWaiters/ackMu. The reassembly logic was almost
byte-identical across videochannel and seichannel; vp8channel only needed
randomID. Three copies of the same idea.

Add internal/transport/common with:
- RandomID(): 8-char hex per-peer ID (Jitsi msid uniqueness requirement).
- FragmentPayload(): split bytes into max-size chunks.
- Reassembler: stores in-flight messages keyed by Seq, validates CRC, and
  reports Partial / Delivered / Duplicate / Ignore via a Result enum.
- AckRegistry: Register/Unregister/Resolve for ack waiters.

videochannel and seichannel now hold *common.AckRegistry and
*common.Reassembler instead of raw maps + mutexes. Their Send paths route
through acks.Register/Unregister; their handleInboundFrame is a 20-line
switch over reassembler.Push. vp8channel keeps its KCP framing but reuses
common.RandomID.

Tests that constructed raw streamTransport with inbound/delivered/ackWaiters
maps are updated to instantiate the new common types instead. Two now-
redundant low-level tests (upsertInbound out-of-range, assembleMessage)
collapse into the new TestInboundRejectsBadCRC.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 14:16:43 +03:00

77 lines
1.9 KiB
Go

package videochannel
import (
"bytes"
"hash/crc32"
"testing"
"github.com/openlibrecommunity/olcrtc/internal/transport/common"
)
func TestInboundAssemblyAndAck(t *testing.T) {
var got []byte
tr := &streamTransport{
onData: func(data []byte) { got = append([]byte(nil), data...) },
outboundAck: make(chan []byte, 4),
reassembler: common.NewReassembler(256),
}
payload := []byte("hello video")
crc := crc32.ChecksumIEEE(payload)
tr.handleInboundFrame(transportFrame{
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 1,
fragTotal: 2,
payload: []byte(" video"),
})
if len(got) != 0 {
t.Fatalf("onData called before message complete: %q", got)
}
tr.handleInboundFrame(transportFrame{
typ: frameTypeData,
seq: 1,
crc: crc,
totalLen: uint32(len(payload)), //nolint:gosec // G115: bounded conversion verified by surrounding logic
fragIdx: 0,
fragTotal: 2,
payload: []byte("hello"),
})
if !bytes.Equal(got, payload) {
t.Fatalf("assembled payload = %q, want %q", got, payload)
}
select {
case ack := <-tr.outboundAck:
frame, err := decodeTransportFrame(ack)
if err != nil || frame.typ != frameTypeAck || frame.seq != 1 || frame.crc != crc {
t.Fatalf("ack frame = %+v err=%v", frame, err)
}
default:
t.Fatal("handleInboundFrame() did not enqueue ack")
}
}
func TestInboundRejectsBadCRC(t *testing.T) {
tr := &streamTransport{
outboundAck: make(chan []byte, 2),
reassembler: common.NewReassembler(256),
}
called := false
tr.onData = func([]byte) { called = true }
tr.handleInboundFrame(transportFrame{
seq: 2,
crc: 123,
totalLen: 3,
fragIdx: 0,
fragTotal: 1,
payload: []byte("abc"),
})
if called {
t.Fatal("handleInboundFrame() delivered payload with bad crc")
}
}