github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/internal/ackhandler/sent_packet_history_test.go (about)

     1  package ackhandler
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"github.com/metacubex/quic-go/internal/protocol"
     8  
     9  	. "github.com/onsi/ginkgo/v2"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  var _ = Describe("SentPacketHistory", func() {
    14  	var hist *sentPacketHistory
    15  
    16  	expectInHistory := func(expected []protocol.PacketNumber) {
    17  		pns := make([]protocol.PacketNumber, 0, len(expected))
    18  		for _, p := range hist.packets {
    19  			if p != nil && !p.skippedPacket {
    20  				pns = append(pns, p.PacketNumber)
    21  			}
    22  		}
    23  		if len(expected) == 0 {
    24  			Expect(pns).To(BeEmpty())
    25  			return
    26  		}
    27  		Expect(pns).To(Equal(expected))
    28  	}
    29  
    30  	expectSkippedInHistory := func(expected []protocol.PacketNumber) {
    31  		pns := make([]protocol.PacketNumber, 0, len(expected))
    32  		for _, p := range hist.packets {
    33  			if p != nil && p.skippedPacket {
    34  				pns = append(pns, p.PacketNumber)
    35  			}
    36  		}
    37  		if len(expected) == 0 {
    38  			Expect(pns).To(BeEmpty())
    39  			return
    40  		}
    41  		Expect(pns).To(Equal(expected))
    42  	}
    43  
    44  	BeforeEach(func() {
    45  		hist = newSentPacketHistory()
    46  	})
    47  
    48  	It("saves sent packets", func() {
    49  		hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
    50  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
    51  		hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
    52  		expectInHistory([]protocol.PacketNumber{0, 1, 2})
    53  		expectSkippedInHistory(nil)
    54  	})
    55  
    56  	It("saves non-ack-eliciting packets", func() {
    57  		now := time.Now()
    58  		hist.SentNonAckElicitingPacket(0)
    59  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1, SendTime: now})
    60  		hist.SentNonAckElicitingPacket(2)
    61  		hist.SentAckElicitingPacket(&packet{PacketNumber: 3, SendTime: now})
    62  		expectInHistory([]protocol.PacketNumber{1, 3})
    63  	})
    64  
    65  	It("saves sent packets, with skipped packet number", func() {
    66  		hist.SkippedPacket(0)
    67  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
    68  		hist.SkippedPacket(2)
    69  		hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
    70  		hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
    71  		expectInHistory([]protocol.PacketNumber{1, 3, 4})
    72  		expectSkippedInHistory([]protocol.PacketNumber{0, 2})
    73  	})
    74  
    75  	It("doesn't save non-ack-eliciting packets", func() {
    76  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
    77  		hist.SkippedPacket(2)
    78  		hist.SentNonAckElicitingPacket(3)
    79  		hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
    80  		expectInHistory([]protocol.PacketNumber{1, 4})
    81  	})
    82  
    83  	It("gets the length", func() {
    84  		hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
    85  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
    86  		hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
    87  		Expect(hist.Len()).To(Equal(3))
    88  	})
    89  
    90  	Context("getting the first outstanding packet", func() {
    91  		It("gets nil, if there are no packets", func() {
    92  			Expect(hist.FirstOutstanding()).To(BeNil())
    93  		})
    94  
    95  		It("gets the first outstanding packet", func() {
    96  			hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
    97  			hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
    98  			front := hist.FirstOutstanding()
    99  			Expect(front).ToNot(BeNil())
   100  			Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2)))
   101  			hist.Remove(2)
   102  			front = hist.FirstOutstanding()
   103  			Expect(front).ToNot(BeNil())
   104  			Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(3)))
   105  		})
   106  
   107  		It("doesn't regard path MTU packets as outstanding", func() {
   108  			hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
   109  			hist.SkippedPacket(3)
   110  			hist.SentAckElicitingPacket(&packet{PacketNumber: 4, IsPathMTUProbePacket: true})
   111  			front := hist.FirstOutstanding()
   112  			Expect(front).ToNot(BeNil())
   113  			Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2)))
   114  		})
   115  	})
   116  
   117  	It("removes packets", func() {
   118  		hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
   119  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   120  		hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
   121  		hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
   122  		Expect(hist.Remove(2)).To(Succeed())
   123  		expectInHistory([]protocol.PacketNumber{0, 1, 3})
   124  	})
   125  
   126  	It("also removes skipped packets before the removed packet", func() {
   127  		hist.SkippedPacket(0)
   128  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   129  		hist.SkippedPacket(2)
   130  		hist.SkippedPacket(3)
   131  		hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
   132  		expectSkippedInHistory([]protocol.PacketNumber{0, 2, 3})
   133  		Expect(hist.Remove(4)).To(Succeed())
   134  		expectSkippedInHistory([]protocol.PacketNumber{0})
   135  		expectInHistory([]protocol.PacketNumber{1})
   136  		Expect(hist.Remove(1)).To(Succeed())
   137  		expectInHistory(nil)
   138  		expectSkippedInHistory(nil)
   139  	})
   140  
   141  	It("panics on non-sequential packet number use", func() {
   142  		hist.SentAckElicitingPacket(&packet{PacketNumber: 100})
   143  		Expect(func() { hist.SentAckElicitingPacket(&packet{PacketNumber: 102}) }).To(Panic())
   144  	})
   145  
   146  	It("removes and adds packets", func() {
   147  		hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
   148  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   149  		hist.SkippedPacket(2)
   150  		hist.SkippedPacket(3)
   151  		hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
   152  		hist.SkippedPacket(5)
   153  		hist.SentAckElicitingPacket(&packet{PacketNumber: 6})
   154  		Expect(hist.Remove(0)).To(Succeed())
   155  		Expect(hist.Remove(1)).To(Succeed())
   156  		hist.SentAckElicitingPacket(&packet{PacketNumber: 7})
   157  		expectInHistory([]protocol.PacketNumber{4, 6, 7})
   158  	})
   159  
   160  	It("removes the last packet, then adds more", func() {
   161  		hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
   162  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   163  		Expect(hist.Remove(0)).To(Succeed())
   164  		Expect(hist.Remove(1)).To(Succeed())
   165  		expectInHistory([]protocol.PacketNumber{})
   166  		hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
   167  		expectInHistory([]protocol.PacketNumber{2})
   168  		Expect(hist.Remove(2)).To(Succeed())
   169  		expectInHistory(nil)
   170  	})
   171  
   172  	It("errors when trying to remove a non existing packet", func() {
   173  		hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   174  		Expect(hist.Remove(2)).To(MatchError("packet 2 not found in sent packet history"))
   175  	})
   176  
   177  	Context("iterating", func() {
   178  		BeforeEach(func() {
   179  			hist.SkippedPacket(0)
   180  			hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
   181  			hist.SkippedPacket(2)
   182  			hist.SkippedPacket(3)
   183  			hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
   184  			hist.SkippedPacket(5)
   185  			hist.SkippedPacket(6)
   186  			hist.SkippedPacket(7)
   187  			hist.SentAckElicitingPacket(&packet{PacketNumber: 8})
   188  		})
   189  
   190  		It("iterates over all packets", func() {
   191  			var iterations []protocol.PacketNumber
   192  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   193  				if p.skippedPacket {
   194  					return true, nil
   195  				}
   196  				iterations = append(iterations, p.PacketNumber)
   197  				return true, nil
   198  			})).To(Succeed())
   199  			Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4, 8}))
   200  		})
   201  
   202  		It("also iterates over skipped packets", func() {
   203  			var packets, skippedPackets, allPackets []protocol.PacketNumber
   204  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   205  				if p.skippedPacket {
   206  					skippedPackets = append(skippedPackets, p.PacketNumber)
   207  				} else {
   208  					packets = append(packets, p.PacketNumber)
   209  				}
   210  				allPackets = append(allPackets, p.PacketNumber)
   211  				return true, nil
   212  			})).To(Succeed())
   213  			Expect(packets).To(Equal([]protocol.PacketNumber{1, 4, 8}))
   214  			Expect(skippedPackets).To(Equal([]protocol.PacketNumber{0, 2, 3, 5, 6, 7}))
   215  			Expect(allPackets).To(Equal([]protocol.PacketNumber{0, 1, 2, 3, 4, 5, 6, 7, 8}))
   216  		})
   217  
   218  		It("stops iterating", func() {
   219  			var iterations []protocol.PacketNumber
   220  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   221  				if p.skippedPacket {
   222  					return true, nil
   223  				}
   224  				iterations = append(iterations, p.PacketNumber)
   225  				return p.PacketNumber != 4, nil
   226  			})).To(Succeed())
   227  			Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4}))
   228  		})
   229  
   230  		It("returns the error", func() {
   231  			testErr := errors.New("test error")
   232  			var iterations []protocol.PacketNumber
   233  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   234  				if p.skippedPacket {
   235  					return true, nil
   236  				}
   237  				iterations = append(iterations, p.PacketNumber)
   238  				if p.PacketNumber == 4 {
   239  					return false, testErr
   240  				}
   241  				return true, nil
   242  			})).To(MatchError(testErr))
   243  			Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4}))
   244  		})
   245  
   246  		It("doesn't iterate over deleted packets", func() {
   247  			hist.Remove(4)
   248  			var iterations []protocol.PacketNumber
   249  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   250  				if p.skippedPacket {
   251  					return true, nil
   252  				}
   253  				iterations = append(iterations, p.PacketNumber)
   254  				if p.PacketNumber == 4 {
   255  					Expect(hist.Remove(4)).To(Succeed())
   256  				}
   257  				return true, nil
   258  			})).To(Succeed())
   259  			Expect(iterations).To(Equal([]protocol.PacketNumber{1, 8}))
   260  		})
   261  
   262  		It("allows deletions", func() {
   263  			var iterations []protocol.PacketNumber
   264  			Expect(hist.Iterate(func(p *packet) (bool, error) {
   265  				if p.skippedPacket {
   266  					return true, nil
   267  				}
   268  				iterations = append(iterations, p.PacketNumber)
   269  				if p.PacketNumber == 4 {
   270  					Expect(hist.Remove(4)).To(Succeed())
   271  				}
   272  				return true, nil
   273  			})).To(Succeed())
   274  			expectInHistory([]protocol.PacketNumber{1, 8})
   275  			Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4, 8}))
   276  		})
   277  	})
   278  
   279  	Context("outstanding packets", func() {
   280  		It("says if it has outstanding packets", func() {
   281  			Expect(hist.HasOutstandingPackets()).To(BeFalse())
   282  			hist.SentAckElicitingPacket(&packet{EncryptionLevel: protocol.Encryption1RTT, PacketNumber: 0})
   283  			Expect(hist.HasOutstandingPackets()).To(BeTrue())
   284  		})
   285  
   286  		It("accounts for deleted packets", func() {
   287  			hist.SentAckElicitingPacket(&packet{
   288  				PacketNumber:    10,
   289  				EncryptionLevel: protocol.Encryption1RTT,
   290  			})
   291  			Expect(hist.HasOutstandingPackets()).To(BeTrue())
   292  			Expect(hist.Remove(10)).To(Succeed())
   293  			Expect(hist.HasOutstandingPackets()).To(BeFalse())
   294  		})
   295  
   296  		It("counts the number of packets", func() {
   297  			hist.SentAckElicitingPacket(&packet{
   298  				PacketNumber:    10,
   299  				EncryptionLevel: protocol.Encryption1RTT,
   300  			})
   301  			hist.SentAckElicitingPacket(&packet{
   302  				PacketNumber:    11,
   303  				EncryptionLevel: protocol.Encryption1RTT,
   304  			})
   305  			Expect(hist.Remove(11)).To(Succeed())
   306  			Expect(hist.HasOutstandingPackets()).To(BeTrue())
   307  			Expect(hist.Remove(10)).To(Succeed())
   308  			Expect(hist.HasOutstandingPackets()).To(BeFalse())
   309  		})
   310  	})
   311  })