github.com/MerlinKodo/quic-go@v0.39.2/internal/congestion/pacer_test.go (about) 1 package congestion 2 3 import ( 4 "math/rand" 5 "time" 6 7 "github.com/MerlinKodo/quic-go/internal/protocol" 8 9 . "github.com/onsi/ginkgo/v2" 10 . "github.com/onsi/gomega" 11 ) 12 13 var _ = Describe("Pacer", func() { 14 var p *pacer 15 16 const packetsPerSecond = 50 17 var bandwidth uint64 // in bytes/s 18 19 BeforeEach(func() { 20 bandwidth = uint64(packetsPerSecond * initialMaxDatagramSize) // 50 full-size packets per second 21 // The pacer will multiply the bandwidth with 1.25 to achieve a slightly higher pacing speed. 22 // For the tests, cancel out this factor, so we can do the math using the exact bandwidth. 23 p = newPacer(func() Bandwidth { return Bandwidth(bandwidth) * BytesPerSecond * 4 / 5 }) 24 }) 25 26 It("allows a burst at the beginning", func() { 27 t := time.Now() 28 Expect(p.TimeUntilSend()).To(BeZero()) 29 Expect(p.Budget(t)).To(BeEquivalentTo(maxBurstSizePackets * initialMaxDatagramSize)) 30 }) 31 32 It("allows a big burst for high pacing rates", func() { 33 t := time.Now() 34 bandwidth = uint64(10000 * packetsPerSecond * initialMaxDatagramSize) 35 Expect(p.TimeUntilSend()).To(BeZero()) 36 Expect(p.Budget(t)).To(BeNumerically(">", maxBurstSizePackets*initialMaxDatagramSize)) 37 }) 38 39 It("reduces the budget when sending packets", func() { 40 t := time.Now() 41 budget := p.Budget(t) 42 for budget > 0 { 43 Expect(p.TimeUntilSend()).To(BeZero()) 44 Expect(p.Budget(t)).To(Equal(budget)) 45 p.SentPacket(t, initialMaxDatagramSize) 46 budget -= initialMaxDatagramSize 47 } 48 Expect(p.Budget(t)).To(BeZero()) 49 Expect(p.TimeUntilSend()).ToNot(BeZero()) 50 }) 51 52 sendBurst := func(t time.Time) { 53 for p.Budget(t) > 0 { 54 p.SentPacket(t, initialMaxDatagramSize) 55 } 56 } 57 58 It("paces packets after a burst", func() { 59 t := time.Now() 60 sendBurst(t) 61 // send 100 exactly paced packets 62 for i := 0; i < 100; i++ { 63 t2 := p.TimeUntilSend() 64 Expect(t2.Sub(t)).To(BeNumerically("~", time.Second/packetsPerSecond, time.Nanosecond)) 65 Expect(p.Budget(t2)).To(BeEquivalentTo(initialMaxDatagramSize)) 66 p.SentPacket(t2, initialMaxDatagramSize) 67 t = t2 68 } 69 }) 70 71 It("accounts for non-full-size packets", func() { 72 t := time.Now() 73 sendBurst(t) 74 t2 := p.TimeUntilSend() 75 Expect(t2.Sub(t)).To(BeNumerically("~", time.Second/packetsPerSecond, time.Nanosecond)) 76 // send a half-full packet 77 Expect(p.Budget(t2)).To(BeEquivalentTo(initialMaxDatagramSize)) 78 size := initialMaxDatagramSize / 2 79 p.SentPacket(t2, size) 80 Expect(p.Budget(t2)).To(Equal(initialMaxDatagramSize - size)) 81 Expect(p.TimeUntilSend()).To(BeTemporally("~", t2.Add(time.Second/packetsPerSecond/2), time.Nanosecond)) 82 }) 83 84 It("accumulates budget, if no packets are sent", func() { 85 t := time.Now() 86 sendBurst(t) 87 t2 := p.TimeUntilSend() 88 Expect(t2).To(BeTemporally(">", t)) 89 // wait for 5 times the duration 90 Expect(p.Budget(t.Add(5 * t2.Sub(t)))).To(BeEquivalentTo(5 * initialMaxDatagramSize)) 91 }) 92 93 It("accumulates budget, if no packets are sent, for larger packet sizes", func() { 94 t := time.Now() 95 sendBurst(t) 96 const packetSize = initialMaxDatagramSize + 200 97 p.SetMaxDatagramSize(packetSize) 98 t2 := p.TimeUntilSend() 99 Expect(t2).To(BeTemporally(">", t)) 100 // wait for 5 times the duration 101 Expect(p.Budget(t.Add(5 * t2.Sub(t)))).To(BeEquivalentTo(5 * packetSize)) 102 }) 103 104 It("never allows bursts larger than the maximum burst size", func() { 105 t := time.Now() 106 sendBurst(t) 107 Expect(p.Budget(t.Add(time.Hour))).To(BeEquivalentTo(maxBurstSizePackets * initialMaxDatagramSize)) 108 }) 109 110 It("never allows bursts larger than the maximum burst size, for larger packets", func() { 111 t := time.Now() 112 const packetSize = initialMaxDatagramSize + 200 113 p.SetMaxDatagramSize(packetSize) 114 sendBurst(t) 115 Expect(p.Budget(t.Add(time.Hour))).To(BeEquivalentTo(maxBurstSizePackets * packetSize)) 116 }) 117 118 It("changes the bandwidth", func() { 119 t := time.Now() 120 sendBurst(t) 121 bandwidth = uint64(5 * initialMaxDatagramSize) // reduce the bandwidth to 5 packet per second 122 Expect(p.TimeUntilSend()).To(Equal(t.Add(time.Second / 5))) 123 }) 124 125 It("doesn't pace faster than the minimum pacing duration", func() { 126 t := time.Now() 127 sendBurst(t) 128 bandwidth = uint64(1e6 * initialMaxDatagramSize) 129 Expect(p.TimeUntilSend()).To(Equal(t.Add(protocol.MinPacingDelay))) 130 Expect(p.Budget(t.Add(protocol.MinPacingDelay))).To(Equal(protocol.ByteCount(protocol.MinPacingDelay) * initialMaxDatagramSize * 1e6 / 1e9)) 131 }) 132 133 It("protects against overflows", func() { 134 p = newPacer(func() Bandwidth { return infBandwidth }) 135 t := time.Now() 136 p.SentPacket(t, initialMaxDatagramSize) 137 for i := 0; i < 1e5; i++ { 138 Expect(p.Budget(t.Add(time.Duration(rand.Int63())))).To(BeNumerically(">=", 0)) 139 } 140 }) 141 })