1package quic
2
3import (
4	"github.com/lucas-clemente/quic-go/internal/protocol"
5	"github.com/lucas-clemente/quic-go/internal/wire"
6
7	. "github.com/onsi/ginkgo"
8	. "github.com/onsi/gomega"
9)
10
11var _ = Describe("Retransmission queue", func() {
12	const version = protocol.VersionTLS
13
14	var q *retransmissionQueue
15
16	BeforeEach(func() {
17		q = newRetransmissionQueue(version)
18	})
19
20	Context("Initial data", func() {
21		It("doesn't dequeue anything when it's empty", func() {
22			Expect(q.HasInitialData()).To(BeFalse())
23			Expect(q.GetInitialFrame(protocol.MaxByteCount)).To(BeNil())
24		})
25
26		It("queues and retrieves a control frame", func() {
27			f := &wire.MaxDataFrame{MaximumData: 0x42}
28			q.AddInitial(f)
29			Expect(q.HasInitialData()).To(BeTrue())
30			Expect(q.GetInitialFrame(f.Length(version) - 1)).To(BeNil())
31			Expect(q.GetInitialFrame(f.Length(version))).To(Equal(f))
32			Expect(q.HasInitialData()).To(BeFalse())
33		})
34
35		It("queues and retrieves a CRYPTO frame", func() {
36			f := &wire.CryptoFrame{Data: []byte("foobar")}
37			q.AddInitial(f)
38			Expect(q.HasInitialData()).To(BeTrue())
39			Expect(q.GetInitialFrame(f.Length(version))).To(Equal(f))
40			Expect(q.HasInitialData()).To(BeFalse())
41		})
42
43		It("returns split CRYPTO frames", func() {
44			f := &wire.CryptoFrame{
45				Offset: 100,
46				Data:   []byte("foobar"),
47			}
48			q.AddInitial(f)
49			Expect(q.HasInitialData()).To(BeTrue())
50			f1 := q.GetInitialFrame(f.Length(version) - 3)
51			Expect(f1).ToNot(BeNil())
52			Expect(f1).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
53			Expect(f1.(*wire.CryptoFrame).Data).To(Equal([]byte("foo")))
54			Expect(f1.(*wire.CryptoFrame).Offset).To(Equal(protocol.ByteCount(100)))
55			Expect(q.HasInitialData()).To(BeTrue())
56			f2 := q.GetInitialFrame(protocol.MaxByteCount)
57			Expect(f2).ToNot(BeNil())
58			Expect(f2).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
59			Expect(f2.(*wire.CryptoFrame).Data).To(Equal([]byte("bar")))
60			Expect(f2.(*wire.CryptoFrame).Offset).To(Equal(protocol.ByteCount(103)))
61			Expect(q.HasInitialData()).To(BeFalse())
62		})
63
64		It("returns other frames when a CRYPTO frame wouldn't fit", func() {
65			f := &wire.CryptoFrame{Data: []byte("foobar")}
66			q.AddInitial(f)
67			q.AddInitial(&wire.PingFrame{})
68			f1 := q.GetInitialFrame(2) // too small for a CRYPTO frame
69			Expect(f1).ToNot(BeNil())
70			Expect(f1).To(BeAssignableToTypeOf(&wire.PingFrame{}))
71			Expect(q.HasInitialData()).To(BeTrue())
72			f2 := q.GetInitialFrame(protocol.MaxByteCount)
73			Expect(f2).To(Equal(f))
74		})
75
76		It("retrieves both a CRYPTO frame and a control frame", func() {
77			cf := &wire.MaxDataFrame{MaximumData: 0x42}
78			f := &wire.CryptoFrame{Data: []byte("foobar")}
79			q.AddInitial(f)
80			q.AddInitial(cf)
81			Expect(q.HasInitialData()).To(BeTrue())
82			Expect(q.GetInitialFrame(protocol.MaxByteCount)).To(Equal(f))
83			Expect(q.GetInitialFrame(protocol.MaxByteCount)).To(Equal(cf))
84			Expect(q.HasInitialData()).To(BeFalse())
85		})
86
87		It("drops all Initial frames", func() {
88			q.AddInitial(&wire.CryptoFrame{Data: []byte("foobar")})
89			q.AddInitial(&wire.MaxDataFrame{MaximumData: 0x42})
90			q.DropPackets(protocol.EncryptionInitial)
91			Expect(q.HasInitialData()).To(BeFalse())
92			Expect(q.GetInitialFrame(protocol.MaxByteCount)).To(BeNil())
93		})
94	})
95
96	Context("Handshake data", func() {
97		It("doesn't dequeue anything when it's empty", func() {
98			Expect(q.HasHandshakeData()).To(BeFalse())
99			Expect(q.GetHandshakeFrame(protocol.MaxByteCount)).To(BeNil())
100		})
101
102		It("queues and retrieves a control frame", func() {
103			f := &wire.MaxDataFrame{MaximumData: 0x42}
104			q.AddHandshake(f)
105			Expect(q.HasHandshakeData()).To(BeTrue())
106			Expect(q.GetHandshakeFrame(f.Length(version) - 1)).To(BeNil())
107			Expect(q.GetHandshakeFrame(f.Length(version))).To(Equal(f))
108			Expect(q.HasHandshakeData()).To(BeFalse())
109		})
110
111		It("queues and retrieves a CRYPTO frame", func() {
112			f := &wire.CryptoFrame{Data: []byte("foobar")}
113			q.AddHandshake(f)
114			Expect(q.HasHandshakeData()).To(BeTrue())
115			Expect(q.GetHandshakeFrame(f.Length(version))).To(Equal(f))
116			Expect(q.HasHandshakeData()).To(BeFalse())
117		})
118
119		It("returns split CRYPTO frames", func() {
120			f := &wire.CryptoFrame{
121				Offset: 100,
122				Data:   []byte("foobar"),
123			}
124			q.AddHandshake(f)
125			Expect(q.HasHandshakeData()).To(BeTrue())
126			f1 := q.GetHandshakeFrame(f.Length(version) - 3)
127			Expect(f1).ToNot(BeNil())
128			Expect(f1).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
129			Expect(f1.(*wire.CryptoFrame).Data).To(Equal([]byte("foo")))
130			Expect(f1.(*wire.CryptoFrame).Offset).To(Equal(protocol.ByteCount(100)))
131			Expect(q.HasHandshakeData()).To(BeTrue())
132			f2 := q.GetHandshakeFrame(protocol.MaxByteCount)
133			Expect(f2).ToNot(BeNil())
134			Expect(f2).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
135			Expect(f2.(*wire.CryptoFrame).Data).To(Equal([]byte("bar")))
136			Expect(f2.(*wire.CryptoFrame).Offset).To(Equal(protocol.ByteCount(103)))
137			Expect(q.HasHandshakeData()).To(BeFalse())
138		})
139
140		It("returns other frames when a CRYPTO frame wouldn't fit", func() {
141			f := &wire.CryptoFrame{Data: []byte("foobar")}
142			q.AddHandshake(f)
143			q.AddHandshake(&wire.PingFrame{})
144			f1 := q.GetHandshakeFrame(2) // too small for a CRYPTO frame
145			Expect(f1).ToNot(BeNil())
146			Expect(f1).To(BeAssignableToTypeOf(&wire.PingFrame{}))
147			Expect(q.HasHandshakeData()).To(BeTrue())
148			f2 := q.GetHandshakeFrame(protocol.MaxByteCount)
149			Expect(f2).To(Equal(f))
150		})
151
152		It("retrieves both a CRYPTO frame and a control frame", func() {
153			cf := &wire.MaxDataFrame{MaximumData: 0x42}
154			f := &wire.CryptoFrame{Data: []byte("foobar")}
155			q.AddHandshake(f)
156			q.AddHandshake(cf)
157			Expect(q.HasHandshakeData()).To(BeTrue())
158			Expect(q.GetHandshakeFrame(protocol.MaxByteCount)).To(Equal(f))
159			Expect(q.GetHandshakeFrame(protocol.MaxByteCount)).To(Equal(cf))
160			Expect(q.HasHandshakeData()).To(BeFalse())
161		})
162
163		It("drops all Handshake frames", func() {
164			q.AddHandshake(&wire.CryptoFrame{Data: []byte("foobar")})
165			q.AddHandshake(&wire.MaxDataFrame{MaximumData: 0x42})
166			q.DropPackets(protocol.EncryptionHandshake)
167			Expect(q.HasHandshakeData()).To(BeFalse())
168			Expect(q.GetHandshakeFrame(protocol.MaxByteCount)).To(BeNil())
169		})
170	})
171
172	Context("Application data", func() {
173		It("doesn't dequeue anything when it's empty", func() {
174			Expect(q.GetAppDataFrame(protocol.MaxByteCount)).To(BeNil())
175		})
176
177		It("queues and retrieves a control frame", func() {
178			f := &wire.MaxDataFrame{MaximumData: 0x42}
179			Expect(q.HasAppData()).To(BeFalse())
180			q.AddAppData(f)
181			Expect(q.HasAppData()).To(BeTrue())
182			Expect(q.GetAppDataFrame(f.Length(version) - 1)).To(BeNil())
183			Expect(q.GetAppDataFrame(f.Length(version))).To(Equal(f))
184			Expect(q.HasAppData()).To(BeFalse())
185		})
186	})
187})
188