feat(gateway): repair native Apollo provider path
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type syntheticPacerDelivery struct {
|
||||
at time.Time
|
||||
flow string
|
||||
bytes int64
|
||||
}
|
||||
|
||||
func TestFairPacerEightFlowSharesAndCapacitySteps(t *testing.T) {
|
||||
start := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
flows := []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}
|
||||
pacer := newFairPacer(8000)
|
||||
next := make(map[string]time.Time, len(flows))
|
||||
baseline := runSyntheticPacer(pacer, start, start.Add(60*time.Second), flows, next)
|
||||
assertSyntheticFairness(t, baseline, flows)
|
||||
assertSyntheticCap(t, baseline, 1_000_000)
|
||||
|
||||
pacer.setKbps(6000)
|
||||
quarter := runSyntheticPacer(pacer, start.Add(60*time.Second), start.Add(70*time.Second), flows, next)
|
||||
assertSyntheticFairness(t, quarter, flows)
|
||||
assertSyntheticCap(t, quarter, 750_000)
|
||||
|
||||
pacer.setKbps(4000)
|
||||
half := runSyntheticPacer(pacer, start.Add(70*time.Second), start.Add(80*time.Second), flows, next)
|
||||
assertSyntheticFairness(t, half, flows)
|
||||
assertSyntheticCap(t, half, 500_000)
|
||||
}
|
||||
|
||||
func runSyntheticPacer(pacer *fairPacer, start, end time.Time, flows []string, next map[string]time.Time) []syntheticPacerDelivery {
|
||||
const packetBytes = 1000
|
||||
for _, flow := range flows {
|
||||
if next[flow].IsZero() {
|
||||
next[flow] = pacer.reserveAt(start, flow, packetBytes)
|
||||
}
|
||||
}
|
||||
var deliveries []syntheticPacerDelivery
|
||||
for {
|
||||
flow := ""
|
||||
at := end.Add(time.Nanosecond)
|
||||
for _, candidate := range flows {
|
||||
if next[candidate].Before(at) {
|
||||
flow, at = candidate, next[candidate]
|
||||
}
|
||||
}
|
||||
if at.After(end) {
|
||||
return deliveries
|
||||
}
|
||||
deliveries = append(deliveries, syntheticPacerDelivery{at: at, flow: flow, bytes: packetBytes})
|
||||
next[flow] = pacer.reserveAt(at, flow, packetBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func assertSyntheticFairness(t *testing.T, deliveries []syntheticPacerDelivery, flows []string) {
|
||||
t.Helper()
|
||||
counts := make(map[string]int64, len(flows))
|
||||
for _, delivery := range deliveries {
|
||||
counts[delivery.flow] += delivery.bytes
|
||||
}
|
||||
total := int64(0)
|
||||
for _, flow := range flows {
|
||||
total += counts[flow]
|
||||
}
|
||||
target := total / int64(len(flows))
|
||||
for _, flow := range flows {
|
||||
delta := counts[flow] - target
|
||||
if delta < 0 {
|
||||
delta = -delta
|
||||
}
|
||||
if target == 0 || float64(delta)/float64(target) > 0.10 {
|
||||
t.Fatalf("flow %s share=%d target=%d", flow, counts[flow], target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertSyntheticCap(t *testing.T, deliveries []syntheticPacerDelivery, bytesPerSecond int64) {
|
||||
t.Helper()
|
||||
sort.Slice(deliveries, func(first, second int) bool { return deliveries[first].at.Before(deliveries[second].at) })
|
||||
for first, total, last := 0, int64(0), 0; first < len(deliveries); first++ {
|
||||
for last < len(deliveries) && deliveries[last].at.Sub(deliveries[first].at) <= 5*time.Second {
|
||||
total += deliveries[last].bytes
|
||||
last++
|
||||
}
|
||||
if total > bytesPerSecond*5*105/100 {
|
||||
t.Fatalf("five-second egress=%d exceeds cap=%d", total, bytesPerSecond*5)
|
||||
}
|
||||
total -= deliveries[first].bytes
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user