package bwtest import ( "context" "testing" "time" ) func TestUDPPacerUsesDeliveryFeedback(t *testing.T) { p := newUDPPacer(0) initial := p.rate now := p.started.Add(2 * time.Second) p.observe(10000, now) if p.rate >= initial { t.Fatal("automatic rate did not fall after severe loss") } lower := p.rate p.observe(10000+lower/8, now.Add(time.Second)) if p.rate <= lower { t.Fatal("automatic rate did not grow after successful delivery") } fixed := newUDPPacer(1234567) fixed.observe(0, fixed.started.Add(2*time.Second)) if fixed.rate != 1234567 { t.Fatal("receiver feedback changed explicit rate limit") } } func TestUDPPacerCancellation(t *testing.T) { p := newUDPPacer(1) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond) defer cancel() if p.wait(ctx, 1472) { t.Fatal("rate limiter ignored cancellation") } } func TestUDPTrackerStreamsReorderingDuplicates(t *testing.T) { var tracker udpTracker for _, v := range []struct { stream uint8 seq uint64 lost int64 }{{0, 1, 0}, {1, 1, 0}, {0, 3, 1}, {1, 2, 1}, {0, 2, 0}, {0, 4, 0}} { ok, lost := tracker.accept(v.stream, v.seq) if !ok || lost != v.lost { t.Fatalf("stream %d seq %d: accepted=%v lost=%d want=%d", v.stream, v.seq, ok, lost, v.lost) } } if ok, lost := tracker.accept(0, 3); ok || lost != 0 { t.Fatal("duplicate counted as data or loss") } } func TestBandwidthUDPDirectionsAndAutomaticPacing(t *testing.T) { s := testServer(t) for _, direction := range []string{"rx", "both", "tx"} { t.Run(direction, func(t *testing.T) { c := NewClient() t.Cleanup(c.Stop) if err := c.Run(context.Background(), SessionRequest{Target: "127.0.0.1", Port: s.config.Port, Protocol: "udp", Direction: direction, Streams: 4, PacketSize: 1472, Duration: 2}); err != nil { t.Fatal(err) } deadline := time.Now().Add(5 * time.Second) for c.GetStatus().Running && time.Now().Before(deadline) { time.Sleep(10 * time.Millisecond) } st := c.GetStatus() if st.Running || st.Error != "" || st.Summary == nil { t.Fatalf("UDP test failed: %+v", st) } if direction != "rx" && st.Summary.TotalTxBytes < 100000 { t.Fatalf("no confirmed TX: %+v", st.Summary) } if direction != "tx" && st.Summary.TotalRxBytes < 100000 { t.Fatalf("no reverse UDP: %+v", st.Summary) } if st.Summary.AvgLossPct != 0 { t.Fatalf("streams or reordered packets falsely counted as loss: %+v", st.Summary) } if st.Summary.AvgTxMbps > 20 || st.Summary.AvgRxMbps > 20 { t.Fatal("automatic UDP started with an unbounded flood") } if direction == "tx" && st.Summary.TotalRxBytes != 0 { t.Fatal("TX delivery reports mislabeled as downloaded data") } }) } }