Embed STUN and SFU in the shared Go process, reuse native encoding pipelines with independent adaptation, and complete Client lifecycle, settings, diagnostics and packaging fixes. Retain standard Browser senders after measured encoded-reuse limitations.
149 lines
5.2 KiB
Go
149 lines
5.2 KiB
Go
package protocol
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// The fixture is the single owner of the cross-language wire samples;
|
|
// tests/protocol-fixture.test.ts replays the same file against the zod schemas.
|
|
const fixturePath = "../../../tests/fixtures/wire-samples.json"
|
|
|
|
type wireFixture struct {
|
|
Constants map[string]any `json:"constants"`
|
|
ClientMessages []struct {
|
|
Name string `json:"name"`
|
|
Schema string `json:"schema"`
|
|
JSON string `json:"json"`
|
|
Valid bool `json:"valid"`
|
|
} `json:"clientMessages"`
|
|
ServerMessages []struct {
|
|
Name string `json:"name"`
|
|
JSON string `json:"json"`
|
|
} `json:"serverMessages"`
|
|
}
|
|
|
|
func loadFixture(t *testing.T) wireFixture {
|
|
t.Helper()
|
|
raw, err := os.ReadFile(filepath.FromSlash(fixturePath))
|
|
if err != nil {
|
|
t.Fatalf("read fixture: %v", err)
|
|
}
|
|
var fixture wireFixture
|
|
if err := json.Unmarshal(raw, &fixture); err != nil {
|
|
t.Fatalf("parse fixture: %v", err)
|
|
}
|
|
return fixture
|
|
}
|
|
|
|
func TestFixtureConstants(t *testing.T) {
|
|
fixture := loadFixture(t)
|
|
expected := map[string]any{
|
|
"signalingProtocol": SignalingProtocol,
|
|
"maxViewersPerRoomLimit": float64(MaxViewersPerRoomLimit),
|
|
"maxParticipantsPerRoomLimit": float64(MaxParticipantsPerRoomLimit),
|
|
"maxSignalBytes": float64(MaxSignalBytes),
|
|
"roomCodeLength": float64(RoomCodeLength),
|
|
"maxMediaRouteRevision": float64(MaxMediaRouteRevision),
|
|
"maxIceServerUrls": float64(MaxIceServerURLs),
|
|
"maxNatPredictionAuxiliaryStunUrls": float64(MaxNatPredictionAuxiliaryStunURLs),
|
|
"maxViewerQualityEvidenceBytes": float64(MaxViewerQualityEvidenceBytes),
|
|
"viewerQualityEvidenceIntervalMs": float64(ViewerQualityEvidenceIntervalMs),
|
|
"viewerQualityEvidenceExpiryMs": float64(ViewerQualityEvidenceExpiryMs),
|
|
"persistentNativeEdgeDegradedWindows": float64(PersistentNativeEdgeDegradedWindows),
|
|
"maxDisplayNameCodePoints": float64(MaxDisplayNameCodePoints),
|
|
"defaultViewerDisplayName": DefaultViewerDisplayName,
|
|
"defaultHostDisplayNamePrefix": DefaultHostDisplayNamePrefix,
|
|
"minViewerPasswordLength": float64(MinViewerPasswordLength),
|
|
"maxViewerPasswordLength": float64(MaxViewerPasswordLength),
|
|
"defaultEndpointMediaCopyCapacity": float64(DefaultEndpointMediaCopyCapacity),
|
|
"maxEndpointMediaCopyCapacity": float64(MaxEndpointMediaCopyCapacity),
|
|
"signalCloseCodeServiceRestart": float64(SignalCloseServiceRestart),
|
|
"signalCloseCodeSessionReplaced": float64(SignalCloseSessionReplaced),
|
|
"signalCloseCodeClientReconnect": float64(SignalCloseClientReconnect),
|
|
"signalCloseCodeAuthenticationFailed": float64(SignalCloseAuthenticationFailed),
|
|
"signalCloseCodeViewerAccessRevoked": float64(SignalCloseViewerAccessRevoked),
|
|
"defaultQualitySettings": jsonValue(t, DefaultQualitySettings),
|
|
"defaultRoutePolicy": jsonValue(t, DefaultRoutePolicy),
|
|
}
|
|
if !reflect.DeepEqual(fixture.Constants, expected) {
|
|
t.Fatalf("constants mismatch\n got: %#v\nwant: %#v", fixture.Constants, expected)
|
|
}
|
|
}
|
|
|
|
func TestFixtureClientSamples(t *testing.T) {
|
|
fixture := loadFixture(t)
|
|
if len(fixture.ClientMessages) == 0 {
|
|
t.Fatal("fixture carries no client samples")
|
|
}
|
|
for _, sample := range fixture.ClientMessages {
|
|
t.Run(sample.Name, func(t *testing.T) {
|
|
var err error
|
|
switch sample.Schema {
|
|
case "client":
|
|
_, err = DecodeClientMessage([]byte(sample.JSON))
|
|
case "createRoomRequest":
|
|
_, err = DecodeCreateRoomRequest([]byte(sample.JSON))
|
|
case "replaceRoomRequest":
|
|
_, err = DecodeReplaceRoomRequest([]byte(sample.JSON))
|
|
case "roomAccessUpdateRequest":
|
|
_, err = DecodeRoomAccessUpdateRequest([]byte(sample.JSON))
|
|
default:
|
|
t.Fatalf("unknown fixture schema %q", sample.Schema)
|
|
}
|
|
if sample.Valid && err != nil {
|
|
t.Fatalf("expected the sample to decode, got %v", err)
|
|
}
|
|
if !sample.Valid && err == nil {
|
|
t.Fatal("expected the sample to be rejected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFixtureServerSamplesRoundTrip(t *testing.T) {
|
|
fixture := loadFixture(t)
|
|
if len(fixture.ServerMessages) == 0 {
|
|
t.Fatal("fixture carries no server samples")
|
|
}
|
|
for _, sample := range fixture.ServerMessages {
|
|
t.Run(sample.Name, func(t *testing.T) {
|
|
message, err := DecodeServerMessage([]byte(sample.JSON))
|
|
if err != nil {
|
|
t.Fatalf("decode: %v", err)
|
|
}
|
|
encoded, err := EncodeServerMessage(message)
|
|
if err != nil {
|
|
t.Fatalf("encode: %v", err)
|
|
}
|
|
var want, got any
|
|
if err := json.Unmarshal([]byte(sample.JSON), &want); err != nil {
|
|
t.Fatalf("parse sample: %v", err)
|
|
}
|
|
if err := json.Unmarshal(encoded, &got); err != nil {
|
|
t.Fatalf("parse re-encoded message: %v", err)
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("round trip changed the message\n got: %s\nwant: %s",
|
|
encoded, sample.JSON)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func jsonValue(t *testing.T, value any) any {
|
|
t.Helper()
|
|
encoded, err := json.Marshal(value)
|
|
if err != nil {
|
|
t.Fatalf("marshal: %v", err)
|
|
}
|
|
var decoded any
|
|
if err := json.Unmarshal(encoded, &decoded); err != nil {
|
|
t.Fatalf("unmarshal: %v", err)
|
|
}
|
|
return decoded
|
|
}
|