uquic/internal/ackhandler/sent_packet_history_test.go
2023-06-05 21:06:58 +03:00

311 lines
9.9 KiB
Go

package ackhandler
import (
"errors"
"time"
"github.com/quic-go/quic-go/internal/protocol"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("SentPacketHistory", func() {
var hist *sentPacketHistory
expectInHistory := func(expected []protocol.PacketNumber) {
pns := make([]protocol.PacketNumber, 0, len(expected))
for _, p := range hist.packets {
if p != nil && !p.skippedPacket {
pns = append(pns, p.PacketNumber)
}
}
if len(expected) == 0 {
Expect(pns).To(BeEmpty())
return
}
Expect(pns).To(Equal(expected))
}
expectSkippedInHistory := func(expected []protocol.PacketNumber) {
pns := make([]protocol.PacketNumber, 0, len(expected))
for _, p := range hist.packets {
if p != nil && p.skippedPacket {
pns = append(pns, p.PacketNumber)
}
}
if len(expected) == 0 {
Expect(pns).To(BeEmpty())
return
}
Expect(pns).To(Equal(expected))
}
BeforeEach(func() {
hist = newSentPacketHistory()
})
It("saves sent packets", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
expectInHistory([]protocol.PacketNumber{0, 1, 2})
expectSkippedInHistory(nil)
})
It("saves non-ack-eliciting packets", func() {
now := time.Now()
hist.SentNonAckElicitingPacket(0)
hist.SentAckElicitingPacket(&packet{PacketNumber: 1, SendTime: now})
hist.SentNonAckElicitingPacket(2)
hist.SentAckElicitingPacket(&packet{PacketNumber: 3, SendTime: now})
expectInHistory([]protocol.PacketNumber{1, 3})
})
It("saves sent packets, with skipped packet number", func() {
hist.SkippedPacket(0)
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SkippedPacket(2)
hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
expectInHistory([]protocol.PacketNumber{1, 3, 4})
expectSkippedInHistory([]protocol.PacketNumber{0, 2})
})
It("doesn't save non-ack-eliciting packets", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SkippedPacket(2)
hist.SentNonAckElicitingPacket(3)
hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
expectInHistory([]protocol.PacketNumber{1, 4})
})
It("gets the length", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
Expect(hist.Len()).To(Equal(3))
})
Context("getting the first outstanding packet", func() {
It("gets nil, if there are no packets", func() {
Expect(hist.FirstOutstanding()).To(BeNil())
})
It("gets the first outstanding packet", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
front := hist.FirstOutstanding()
Expect(front).ToNot(BeNil())
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2)))
hist.Remove(2)
front = hist.FirstOutstanding()
Expect(front).ToNot(BeNil())
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(3)))
})
It("doesn't regard path MTU packets as outstanding", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
hist.SkippedPacket(3)
hist.SentAckElicitingPacket(&packet{PacketNumber: 4, IsPathMTUProbePacket: true})
front := hist.FirstOutstanding()
Expect(front).ToNot(BeNil())
Expect(front.PacketNumber).To(Equal(protocol.PacketNumber(2)))
})
})
It("removes packets", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
hist.SentAckElicitingPacket(&packet{PacketNumber: 3})
Expect(hist.Remove(2)).To(Succeed())
expectInHistory([]protocol.PacketNumber{0, 1, 3})
})
It("also removes skipped packets before the removed packet", func() {
hist.SkippedPacket(0)
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SkippedPacket(2)
hist.SkippedPacket(3)
hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
expectSkippedInHistory([]protocol.PacketNumber{0, 2, 3})
Expect(hist.Remove(4)).To(Succeed())
expectSkippedInHistory([]protocol.PacketNumber{0})
expectInHistory([]protocol.PacketNumber{1})
Expect(hist.Remove(1)).To(Succeed())
expectInHistory(nil)
expectSkippedInHistory(nil)
})
It("panics on non-sequential packet number use", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 100})
Expect(func() { hist.SentAckElicitingPacket(&packet{PacketNumber: 102}) }).To(Panic())
})
It("removes and adds packets", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SkippedPacket(2)
hist.SkippedPacket(3)
hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
hist.SkippedPacket(5)
hist.SentAckElicitingPacket(&packet{PacketNumber: 6})
Expect(hist.Remove(0)).To(Succeed())
Expect(hist.Remove(1)).To(Succeed())
hist.SentAckElicitingPacket(&packet{PacketNumber: 7})
expectInHistory([]protocol.PacketNumber{4, 6, 7})
})
It("removes the last packet, then adds more", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 0})
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
Expect(hist.Remove(0)).To(Succeed())
Expect(hist.Remove(1)).To(Succeed())
expectInHistory([]protocol.PacketNumber{})
hist.SentAckElicitingPacket(&packet{PacketNumber: 2})
expectInHistory([]protocol.PacketNumber{2})
Expect(hist.Remove(2)).To(Succeed())
expectInHistory(nil)
})
It("errors when trying to remove a non existing packet", func() {
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
Expect(hist.Remove(2)).To(MatchError("packet 2 not found in sent packet history"))
})
Context("iterating", func() {
BeforeEach(func() {
hist.SkippedPacket(0)
hist.SentAckElicitingPacket(&packet{PacketNumber: 1})
hist.SkippedPacket(2)
hist.SkippedPacket(3)
hist.SentAckElicitingPacket(&packet{PacketNumber: 4})
hist.SkippedPacket(5)
hist.SkippedPacket(6)
hist.SkippedPacket(7)
hist.SentAckElicitingPacket(&packet{PacketNumber: 8})
})
It("iterates over all packets", func() {
var iterations []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
return true, nil
}
iterations = append(iterations, p.PacketNumber)
return true, nil
})).To(Succeed())
Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4, 8}))
})
It("also iterates over skipped packets", func() {
var packets, skippedPackets, allPackets []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
skippedPackets = append(skippedPackets, p.PacketNumber)
} else {
packets = append(packets, p.PacketNumber)
}
allPackets = append(allPackets, p.PacketNumber)
return true, nil
})).To(Succeed())
Expect(packets).To(Equal([]protocol.PacketNumber{1, 4, 8}))
Expect(skippedPackets).To(Equal([]protocol.PacketNumber{0, 2, 3, 5, 6, 7}))
Expect(allPackets).To(Equal([]protocol.PacketNumber{0, 1, 2, 3, 4, 5, 6, 7, 8}))
})
It("stops iterating", func() {
var iterations []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
return true, nil
}
iterations = append(iterations, p.PacketNumber)
return p.PacketNumber != 4, nil
})).To(Succeed())
Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4}))
})
It("returns the error", func() {
testErr := errors.New("test error")
var iterations []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
return true, nil
}
iterations = append(iterations, p.PacketNumber)
if p.PacketNumber == 4 {
return false, testErr
}
return true, nil
})).To(MatchError(testErr))
Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4}))
})
It("doesn't iterate over deleted packets", func() {
hist.Remove(4)
var iterations []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
return true, nil
}
iterations = append(iterations, p.PacketNumber)
if p.PacketNumber == 4 {
Expect(hist.Remove(4)).To(Succeed())
}
return true, nil
})).To(Succeed())
Expect(iterations).To(Equal([]protocol.PacketNumber{1, 8}))
})
It("allows deletions", func() {
var iterations []protocol.PacketNumber
Expect(hist.Iterate(func(p *packet) (bool, error) {
if p.skippedPacket {
return true, nil
}
iterations = append(iterations, p.PacketNumber)
if p.PacketNumber == 4 {
Expect(hist.Remove(4)).To(Succeed())
}
return true, nil
})).To(Succeed())
expectInHistory([]protocol.PacketNumber{1, 8})
Expect(iterations).To(Equal([]protocol.PacketNumber{1, 4, 8}))
})
})
Context("outstanding packets", func() {
It("says if it has outstanding packets", func() {
Expect(hist.HasOutstandingPackets()).To(BeFalse())
hist.SentAckElicitingPacket(&packet{EncryptionLevel: protocol.Encryption1RTT, PacketNumber: 0})
Expect(hist.HasOutstandingPackets()).To(BeTrue())
})
It("accounts for deleted packets", func() {
hist.SentAckElicitingPacket(&packet{
PacketNumber: 10,
EncryptionLevel: protocol.Encryption1RTT,
})
Expect(hist.HasOutstandingPackets()).To(BeTrue())
Expect(hist.Remove(10)).To(Succeed())
Expect(hist.HasOutstandingPackets()).To(BeFalse())
})
It("counts the number of packets", func() {
hist.SentAckElicitingPacket(&packet{
PacketNumber: 10,
EncryptionLevel: protocol.Encryption1RTT,
})
hist.SentAckElicitingPacket(&packet{
PacketNumber: 11,
EncryptionLevel: protocol.Encryption1RTT,
})
Expect(hist.Remove(11)).To(Succeed())
Expect(hist.HasOutstandingPackets()).To(BeTrue())
Expect(hist.Remove(10)).To(Succeed())
Expect(hist.HasOutstandingPackets()).To(BeFalse())
})
})
})