github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/mtu_discoverer_test.go (about) 1 package quic 2 3 import ( 4 "math/rand" 5 "time" 6 7 "github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol" 8 "github.com/danielpfeifer02/quic-go-prio-packs/internal/utils" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("MTU Discoverer", func() { 15 const ( 16 rtt = 100 * time.Millisecond 17 startMTU protocol.ByteCount = 1000 18 maxMTU protocol.ByteCount = 2000 19 ) 20 21 var ( 22 d *mtuFinder 23 rttStats *utils.RTTStats 24 now time.Time 25 discoveredMTU protocol.ByteCount 26 ) 27 28 BeforeEach(func() { 29 rttStats = &utils.RTTStats{} 30 rttStats.SetInitialRTT(rtt) 31 Expect(rttStats.SmoothedRTT()).To(Equal(rtt)) 32 d = newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) { discoveredMTU = s }) 33 d.Start(maxMTU) 34 now = time.Now() 35 }) 36 37 It("only allows a probe 5 RTTs after the handshake completes", func() { 38 Expect(d.ShouldSendProbe(now)).To(BeFalse()) 39 Expect(d.ShouldSendProbe(now.Add(rtt * 9 / 2))).To(BeFalse()) 40 Expect(d.ShouldSendProbe(now.Add(rtt * 5))).To(BeTrue()) 41 }) 42 43 It("doesn't allow a probe if another probe is still in flight", func() { 44 ping, _ := d.GetPing() 45 Expect(d.ShouldSendProbe(now.Add(10 * rtt))).To(BeFalse()) 46 ping.Handler.OnLost(ping.Frame) 47 Expect(d.ShouldSendProbe(now.Add(10 * rtt))).To(BeTrue()) 48 }) 49 50 It("tries a lower size when a probe is lost", func() { 51 ping, size := d.GetPing() 52 Expect(size).To(Equal(protocol.ByteCount(1500))) 53 ping.Handler.OnLost(ping.Frame) 54 _, size = d.GetPing() 55 Expect(size).To(Equal(protocol.ByteCount(1250))) 56 }) 57 58 It("tries a higher size and calls the callback when a probe is acknowledged", func() { 59 ping, size := d.GetPing() 60 Expect(size).To(Equal(protocol.ByteCount(1500))) 61 ping.Handler.OnAcked(ping.Frame) 62 Expect(discoveredMTU).To(Equal(protocol.ByteCount(1500))) 63 _, size = d.GetPing() 64 Expect(size).To(Equal(protocol.ByteCount(1750))) 65 }) 66 67 It("stops discovery after getting close enough to the MTU", func() { 68 var sizes []protocol.ByteCount 69 t := now.Add(5 * rtt) 70 for d.ShouldSendProbe(t) { 71 ping, size := d.GetPing() 72 ping.Handler.OnAcked(ping.Frame) 73 sizes = append(sizes, size) 74 t = t.Add(5 * rtt) 75 } 76 Expect(sizes).To(Equal([]protocol.ByteCount{1500, 1750, 1875, 1937, 1968, 1984})) 77 Expect(d.ShouldSendProbe(t.Add(10 * rtt))).To(BeFalse()) 78 }) 79 80 It("doesn't do discovery before being started", func() { 81 d := newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) {}) 82 for i := 0; i < 5; i++ { 83 Expect(d.ShouldSendProbe(time.Now())).To(BeFalse()) 84 } 85 }) 86 87 It("finds the MTU", func() { 88 const rep = 3000 89 var maxDiff protocol.ByteCount 90 for i := 0; i < rep; i++ { 91 maxMTU := protocol.ByteCount(rand.Intn(int(3000-startMTU))) + startMTU + 1 92 currentMTU := startMTU 93 d := newMTUDiscoverer(rttStats, startMTU, func(s protocol.ByteCount) { currentMTU = s }) 94 d.Start(maxMTU) 95 now := time.Now() 96 realMTU := protocol.ByteCount(rand.Intn(int(maxMTU-startMTU))) + startMTU 97 t := now.Add(mtuProbeDelay * rtt) 98 var count int 99 for d.ShouldSendProbe(t) { 100 if count > 25 { 101 Fail("too many iterations") 102 } 103 count++ 104 105 ping, size := d.GetPing() 106 if size <= realMTU { 107 ping.Handler.OnAcked(ping.Frame) 108 } else { 109 ping.Handler.OnLost(ping.Frame) 110 } 111 t = t.Add(mtuProbeDelay * rtt) 112 } 113 diff := realMTU - currentMTU 114 Expect(diff).To(BeNumerically(">=", 0)) 115 maxDiff = max(maxDiff, diff) 116 } 117 Expect(maxDiff).To(BeEquivalentTo(maxMTUDiff)) 118 }) 119 })