Squash integration of the reviewed Go core, frontend audit fixes, release tooling, and deployment hygiene. CI passed all Server/Client jobs.
150 lines
5.2 KiB
Go
150 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),
|
|
"maxSfuTokenLength": float64(MaxSfuTokenLength),
|
|
"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
|
|
}
|