test(gateway): observe qualification batch pacing
Verify Data Plane / gateway (push) Failing after 1m31s

This commit is contained in:
sechmachine
2026-08-09 16:16:04 +07:00
parent aa4f948fbc
commit a491c4f733
2 changed files with 44 additions and 18 deletions
+23 -1
View File
@@ -100,6 +100,15 @@ func TestQualificationApolloFixturePacesSourceShapedVideo(t *testing.T) {
fixture := &qualificationApolloFixture{video: sender, failures: make(chan error, 1)}
remote := *receiver.LocalAddr().(*net.UDPAddr)
fixture.videoRemote.Store(&remote)
var batchIndices []int
var batchStarts []time.Duration
var started time.Time
fixture.observeVideoBatch = func(index int, at time.Time) {
if len(batchIndices) < 3 {
batchIndices = append(batchIndices, index)
batchStarts = append(batchStarts, at.Sub(started))
}
}
drained := make(chan struct{})
go func() {
defer close(drained)
@@ -111,7 +120,7 @@ func TestQualificationApolloFixturePacesSourceShapedVideo(t *testing.T) {
}
}()
started := time.Now()
started = time.Now()
if err := fixture.sendVideo(context.Background(), packets); err != nil {
t.Fatal(err)
}
@@ -120,9 +129,22 @@ func TestQualificationApolloFixturePacesSourceShapedVideo(t *testing.T) {
}
elapsed := time.Since(started)
wantCarry := qualificationApolloVideoOffset(len(packets), packetsPerMillisecond)
if wantCarry != 10416666*time.Nanosecond {
t.Fatalf("1000-packet carry = %s, want 10.416666 ms", wantCarry)
}
if elapsed < wantCarry {
t.Fatalf("source fixture sent the next frame after %s, before Apollo pacing carry %s", elapsed, wantCarry)
}
wantIndices := []int{0, 63, 126}
wantStarts := []time.Duration{0, 656250 * time.Nanosecond, 1312500 * time.Nanosecond}
if len(batchIndices) != len(wantIndices) {
t.Fatalf("observed %d batch starts, want %d", len(batchIndices), len(wantIndices))
}
for index := range wantIndices {
if batchIndices[index] != wantIndices[index] || batchStarts[index] < wantStarts[index] {
t.Fatalf("batch starts = indices %v at %v; want indices %v no earlier than %v", batchIndices, batchStarts, wantIndices, wantStarts)
}
}
select {
case <-drained:
case <-time.After(time.Second):
+21 -17
View File
@@ -414,22 +414,23 @@ func (b *qualificationTracingBackend) session(sessionID string) *nativeApolloSes
}
type qualificationApolloFixture struct {
sessionID string
management *httptest.Server
stream net.Listener
control *net.UDPConn
audio *net.UDPConn
video *net.UDPConn
videoRemote atomic.Pointer[net.UDPAddr]
key atomic.Pointer[[]byte]
keyReady chan []byte
failures chan error
closed atomic.Bool
closeOnce sync.Once
sentPackets atomic.Uint64
work protocol.ProviderSessionWork
videoPaceMu sync.Mutex
videoNext time.Time
sessionID string
management *httptest.Server
stream net.Listener
control *net.UDPConn
audio *net.UDPConn
video *net.UDPConn
videoRemote atomic.Pointer[net.UDPAddr]
key atomic.Pointer[[]byte]
keyReady chan []byte
failures chan error
closed atomic.Bool
closeOnce sync.Once
sentPackets atomic.Uint64
work protocol.ProviderSessionWork
videoPaceMu sync.Mutex
videoNext time.Time
observeVideoBatch func(int, time.Time)
controlImpairmentMu sync.Mutex
controlRTT time.Duration
@@ -775,11 +776,14 @@ func (f *qualificationApolloFixture) sendVideo(ctx context.Context, packets [][]
}
framePackets := 0
for batchStart := 0; batchStart < len(packets); batchStart += batchSize {
batchEnd := min(batchStart+batchSize, len(packets))
due := frameStart.Add(qualificationApolloVideoOffset(framePackets, packetsPerMillisecond))
if err := qualificationWaitContext(ctx, due); err != nil {
return err
}
batchEnd := min(batchStart+batchSize, len(packets))
if f.observeVideoBatch != nil {
f.observeVideoBatch(framePackets, time.Now())
}
for _, packet := range packets[batchStart:batchEnd] {
if len(packet) != len(packets[0]) {
return ErrProviderMalformed