package gateway import ( "compress/gzip" "io" "os" "path/filepath" "reflect" "strings" "testing" "time" ) func TestQualificationCatalogMatchesSection7(t *testing.T) { media := qualificationMediaProfiles() if len(media) != 3 { t.Fatalf("media profile count = %d, want 3", len(media)) } wantMedia := []qualificationMediaProfile{ {Name: "1080p60-h264", Codec: "h264", BitrateKbps: 20000, Duration: 10 * time.Minute, Warmup: time.Second, PacketBytes: 1179}, {Name: "1440p120-hevc", Codec: "hevc", BitrateKbps: 50000, Duration: 10 * time.Minute, Warmup: time.Second, PacketBytes: 1179}, {Name: "4k60-hevc", Codec: "hevc", BitrateKbps: 80000, Duration: 10 * time.Minute, Warmup: time.Second, PacketBytes: 1179}, } if !reflect.DeepEqual(media, wantMedia) { t.Fatalf("media profiles = %#v, want %#v", media, wantMedia) } impairments := qualificationImpairmentProfiles() wantImpairments := []qualificationImpairmentProfile{ {Name: "baseline", RTT: 20 * time.Millisecond}, {Name: "latency", RTT: 150 * time.Millisecond}, {Name: "jitter", RTT: 50 * time.Millisecond, Jitter: 30 * time.Millisecond}, {Name: "loss", RTT: 50 * time.Millisecond, Jitter: 10 * time.Millisecond, LossPercent: 5}, {Name: "reorder", RTT: 100 * time.Millisecond, Jitter: 10 * time.Millisecond, LossPercent: 1, Reorder: true}, {Name: "constrained", RTT: 50 * time.Millisecond, Jitter: 10 * time.Millisecond, LossPercent: 2, Reorder: true, CapacitySteps: []int{25, 50}}, } if !reflect.DeepEqual(impairments, wantImpairments) { t.Fatalf("impairment profiles = %#v, want %#v", impairments, wantImpairments) } } func TestQualificationProtocolVersionIsExplicitAndImmutable(t *testing.T) { const version = "v1.0.0-phase3c-gateway-rc.6" t.Setenv("VERSEVDI_QUALIFICATION_PROTOCOL_VERSION", version) got, err := qualificationProtocolVersion() if err != nil || got != version { t.Fatalf("qualificationProtocolVersion() = %q, want %q", got, version) } for _, invalid := range []string{"", "unknown", "v1", " v1.0.0", "v1.0.0+mutable"} { t.Setenv("VERSEVDI_QUALIFICATION_PROTOCOL_VERSION", invalid) if _, err := qualificationProtocolVersion(); err == nil { t.Fatalf("qualificationProtocolVersion() accepted %q", invalid) } } } func TestQualificationRecordsLinkedToolVersions(t *testing.T) { versions, err := qualificationToolVersions() if err != nil || versions["qualification"] != qualificationToolVersion || versions["go"] == "" || versions["quic-go"] == "" { t.Fatalf("qualification tool versions = %#v, %v", versions, err) } } func TestQualificationOutputAndStatisticsFailClosed(t *testing.T) { if err := validateQualificationOutputDir("relative/evidence"); err == nil { t.Fatal("relative evidence directory was accepted") } if err := validateQualificationOutputDir(filepath.Join(t.TempDir(), "evidence")); err != nil { t.Fatalf("absolute evidence directory rejected: %v", err) } summary, err := summarizeQualificationSamples([]time.Duration{ time.Millisecond, 2 * time.Millisecond, 3 * time.Millisecond, 4 * time.Millisecond, 5 * time.Millisecond, }) if err != nil { t.Fatal(err) } if summary.Count != 5 || summary.Min != time.Millisecond || summary.Median != 3*time.Millisecond || summary.P90 != 5*time.Millisecond || summary.P95 != 5*time.Millisecond || summary.P99 != 5*time.Millisecond || summary.Max != 5*time.Millisecond || summary.Mean != 3*time.Millisecond || summary.Histogram["le_5ms"] != 5 { t.Fatalf("summary = %#v", summary) } if err := enforceQualificationProcessingGate(summary); err != nil { t.Fatalf("5 ms p95 rejected: %v", err) } summary.P95++ if err := enforceQualificationProcessingGate(summary); err == nil { t.Fatal("p95 above 5 ms was accepted") } } func TestQualificationShortProcessingWritesRawArtifact(t *testing.T) { profile := qualificationMediaProfile{ Name: "smoke", Codec: "h264", BitrateKbps: 20000, Duration: time.Second, Warmup: time.Millisecond, PacketBytes: 1000, } rawPath := filepath.Join(t.TempDir(), "processing.csv.gz") summary, err := runQualificationProcessing(t, profile, rawPath) if err != nil { t.Fatal(err) } if summary.Count < 1 || summary.RawSamplesSHA256 == "" || summary.RawSamplesBytes < 1 || summary.ResourceSamples < 2 || summary.RawResourcesSHA256 == "" || summary.RawResourcesBytes < 1 { t.Fatalf("processing summary = %#v", summary) } file, err := os.Open(rawPath) if err != nil { t.Fatal(err) } defer file.Close() reader, err := gzip.NewReader(file) if err != nil { t.Fatal(err) } raw, err := io.ReadAll(reader) if err != nil { t.Fatal(err) } if err := reader.Close(); err != nil { t.Fatal(err) } if !strings.HasPrefix(string(raw), "elapsed_ns,processing_ns\n") || strings.Count(string(raw), "\n") != int(summary.Count)+1 { t.Fatalf("raw sample rows do not match summary count: %q", raw) } } func TestQualificationProcessingPreservesPayload(t *testing.T) { profile := qualificationMediaProfiles()[0] payload := qualificationPayload(profile) trace, elapsed, err := newQualificationPath(t, profile.BitrateKbps).traverse(t, payload) if err != nil { t.Fatal(err) } if !trace.PayloadPreserved || !trace.ApolloRecovered || !trace.VerseQUIC { t.Fatalf("production path trace = %#v", trace) } if elapsed <= 0 { t.Fatalf("processing duration = %s", elapsed) } } func TestQualificationImpairmentIsDeterministicAndBounded(t *testing.T) { profile := qualificationImpairmentProfiles()[3] first, err := runQualificationImpairment(t, profile, qualificationMediaProfiles()[0], 1000, filepath.Join(t.TempDir(), "first.csv.gz")) if err != nil { t.Fatal(err) } second, err := runQualificationImpairment(t, profile, qualificationMediaProfiles()[0], 1000, filepath.Join(t.TempDir(), "second.csv.gz")) if err != nil { t.Fatal(err) } if first.Dropped != second.Dropped || first.InjectedReordered != second.InjectedReordered { t.Fatalf("deterministic impairment selection differs:\n%#v\n%#v", first, second) } if first.Sent != 1000 || first.Delivered+first.Dropped != first.Sent || first.ObservedLossPercent < 3.5 || first.ObservedLossPercent > 6.5 || first.MaxQueuePackets > qualificationImpairmentQueuePackets || first.RawSamplesSHA256 == "" { t.Fatalf("impairment observation = %#v", first) } if _, err := runQualificationImpairment(t, profile, qualificationMediaProfiles()[0], qualificationImpairmentMaxPackets+1, filepath.Join(t.TempDir(), "invalid.csv.gz")); err == nil { t.Fatal("unbounded impairment packet count was accepted") } unknown := profile unknown.Name = "private-simulator" if _, err := runQualificationImpairment(t, unknown, qualificationMediaProfiles()[0], 1, filepath.Join(t.TempDir(), "unknown.csv.gz")); err == nil { t.Fatal("unregistered impairment profile was accepted") } } func TestQualificationSixImpairmentProfilesTraverseProductionPath(t *testing.T) { profiles := qualificationImpairmentProfiles() if len(profiles) != 6 { t.Fatalf("impairment profile count = %d, want exactly 6", len(profiles)) } for _, profile := range profiles { observation, err := runQualificationImpairment(t, profile, qualificationMediaProfiles()[0], 40, filepath.Join(t.TempDir(), profile.Name+".csv.gz")) if err != nil { t.Fatalf("%s: %v", profile.Name, err) } if observation.Profile != profile.Name || observation.Delivered+observation.Dropped != 40 || observation.RawSamplesSHA256 == "" || observation.MaxQueuePackets > qualificationImpairmentQueuePackets { t.Fatalf("%s observation = %#v", profile.Name, observation) } } } func TestQualificationUsesPublicQUICAndProductionPacer(t *testing.T) { qualificationTraverseProfiles(t, qualificationMediaProfiles()) evidence, err := qualificationPacerEvidence(filepath.Join(t.TempDir(), "fairness.csv.gz")) if err != nil { t.Fatal(err) } if len(evidence.PerFlowBytes) != 8 || len(evidence.CapacitySteps) != 2 || len(evidence.Series) != 80 || evidence.RawSamplesSHA256 == "" || evidence.JainIndex < 0.99 { t.Fatalf("pacer evidence = %#v", evidence) } } func TestQualificationSmokeTraversesNativeApolloRecoveryQueuePacerAndQUIC(t *testing.T) { trace := qualificationProductionPathSmoke(t, qualificationMediaProfiles()[0]) if !trace.ApolloRecovered || !trace.ProductionQueue || !trace.ProductionPacer || !trace.VerseQUIC || !trace.PayloadPreserved { t.Fatalf("qualification production-path trace = %#v", trace) } }