github.com/tumi8/quic-go@v0.37.4-tum/mtu_discoverer_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"math/rand"
     5  	"time"
     6  
     7  	"github.com/tumi8/quic-go/noninternal/protocol"
     8  	"github.com/tumi8/quic-go/noninternal/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  			max := 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(max)
    95  			now := time.Now()
    96  			realMTU := protocol.ByteCount(rand.Intn(int(max-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 = utils.Max(maxDiff, diff)
   116  		}
   117  		Expect(maxDiff).To(BeEquivalentTo(maxMTUDiff))
   118  	})
   119  })