github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/internal/ackhandler/packet_number_generator_test.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  
     7  	"github.com/daeuniverse/quic-go/internal/protocol"
     8  
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  var _ = Describe("Sequential Packet Number Generator", func() {
    14  	It("generates sequential packet numbers", func() {
    15  		const initialPN protocol.PacketNumber = 123
    16  		png := newSequentialPacketNumberGenerator(initialPN)
    17  
    18  		for i := initialPN; i < initialPN+1000; i++ {
    19  			Expect(png.Peek()).To(Equal(i))
    20  			Expect(png.Peek()).To(Equal(i))
    21  			skipNext, pn := png.Pop()
    22  			Expect(skipNext).To(BeFalse())
    23  			Expect(pn).To(Equal(i))
    24  		}
    25  	})
    26  })
    27  
    28  var _ = Describe("Skipping Packet Number Generator", func() {
    29  	const initialPN protocol.PacketNumber = 8
    30  	const initialPeriod protocol.PacketNumber = 25
    31  	const maxPeriod protocol.PacketNumber = 300
    32  
    33  	It("uses a maximum period that is sufficiently small such that using a 32-bit random number is ok", func() {
    34  		Expect(2 * protocol.SkipPacketMaxPeriod).To(BeNumerically("<", math.MaxInt32))
    35  	})
    36  
    37  	It("can be initialized to return any first packet number", func() {
    38  		png := newSkippingPacketNumberGenerator(12345, initialPeriod, maxPeriod)
    39  		_, pn := png.Pop()
    40  		Expect(pn).To(Equal(protocol.PacketNumber(12345)))
    41  	})
    42  
    43  	It("allows peeking", func() {
    44  		png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod).(*skippingPacketNumberGenerator)
    45  		Expect(png.Peek()).To(Equal(initialPN))
    46  		Expect(png.Peek()).To(Equal(initialPN))
    47  		skipped, pn := png.Pop()
    48  		Expect(pn).To(Equal(initialPN))
    49  		next := initialPN + 1
    50  		if skipped {
    51  			next++
    52  		}
    53  		Expect(png.Peek()).To(Equal(next))
    54  		Expect(png.Peek()).To(Equal(next))
    55  	})
    56  
    57  	It("skips a packet number", func() {
    58  		png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod)
    59  		var last protocol.PacketNumber
    60  		var skipped bool
    61  		for i := 0; i < int(maxPeriod); i++ {
    62  			didSkip, num := png.Pop()
    63  			if didSkip {
    64  				skipped = true
    65  				_, nextNum := png.Pop()
    66  				Expect(nextNum).To(Equal(num + 1))
    67  				break
    68  			}
    69  			if i != 0 {
    70  				Expect(num).To(Equal(last + 1))
    71  			}
    72  			last = num
    73  		}
    74  		Expect(skipped).To(BeTrue())
    75  	})
    76  
    77  	It("generates a new packet number to skip", func() {
    78  		const rep = 2500
    79  		periods := make([][]protocol.PacketNumber, rep)
    80  		expectedPeriods := []protocol.PacketNumber{25, 50, 100, 200, 300, 300, 300}
    81  
    82  		for i := 0; i < rep; i++ {
    83  			png := newSkippingPacketNumberGenerator(initialPN, initialPeriod, maxPeriod)
    84  			lastSkip := initialPN
    85  			for len(periods[i]) < len(expectedPeriods) {
    86  				skipNext, next := png.Pop()
    87  				if skipNext {
    88  					skipped := next + 1
    89  					Expect(skipped).To(BeNumerically(">", lastSkip+1))
    90  					periods[i] = append(periods[i], skipped-lastSkip-1)
    91  					lastSkip = skipped
    92  				}
    93  			}
    94  		}
    95  
    96  		for j := 0; j < len(expectedPeriods); j++ {
    97  			var average float64
    98  			for i := 0; i < rep; i++ {
    99  				average += float64(periods[i][j]) / float64(len(periods))
   100  			}
   101  			fmt.Fprintf(GinkgoWriter, "Period %d: %.2f (expected %d)\n", j, average, expectedPeriods[j])
   102  			tolerance := protocol.PacketNumber(5)
   103  			if t := expectedPeriods[j] / 10; t > tolerance {
   104  				tolerance = t
   105  			}
   106  			Expect(average).To(BeNumerically("~", expectedPeriods[j]+1 /* we never skip two packet numbers at the same time */, tolerance))
   107  		}
   108  	})
   109  })