1
2
3
4
5
6
7 package quic
8
9 import (
10 "crypto/rand"
11 "reflect"
12 "testing"
13 )
14
15 func TestCryptoStreamReceive(t *testing.T) {
16 data := make([]byte, 1<<20)
17 rand.Read(data)
18 type frame struct {
19 start int64
20 end int64
21 want int
22 }
23 for _, test := range []struct {
24 name string
25 frames []frame
26 }{{
27 name: "linear",
28 frames: []frame{{
29 start: 0,
30 end: 1000,
31 want: 1000,
32 }, {
33 start: 1000,
34 end: 2000,
35 want: 2000,
36 }, {
37
38 start: 2000,
39 end: 1 << 20,
40 want: 1 << 20,
41 }},
42 }, {
43 name: "out of order",
44 frames: []frame{{
45 start: 1000,
46 end: 2000,
47 }, {
48 start: 2000,
49 end: 3000,
50 }, {
51 start: 0,
52 end: 1000,
53 want: 3000,
54 }},
55 }, {
56 name: "resent",
57 frames: []frame{{
58 start: 0,
59 end: 1000,
60 want: 1000,
61 }, {
62 start: 0,
63 end: 1000,
64 want: 1000,
65 }, {
66 start: 1000,
67 end: 2000,
68 want: 2000,
69 }, {
70 start: 0,
71 end: 1000,
72 want: 2000,
73 }, {
74 start: 1000,
75 end: 2000,
76 want: 2000,
77 }},
78 }, {
79 name: "overlapping",
80 frames: []frame{{
81 start: 0,
82 end: 1000,
83 want: 1000,
84 }, {
85 start: 3000,
86 end: 4000,
87 want: 1000,
88 }, {
89 start: 2000,
90 end: 3000,
91 want: 1000,
92 }, {
93 start: 1000,
94 end: 3000,
95 want: 4000,
96 }},
97 }, {
98 name: "resent consumed data",
99 frames: []frame{{
100 start: 0,
101 end: 1000,
102 want: 1000,
103 }, {
104 start: 1000,
105 end: 2000,
106 want: 2000,
107 }, {
108 start: 0,
109 end: 1000,
110 want: 2000,
111 }},
112 }} {
113 t.Run(test.name, func(t *testing.T) {
114 var s cryptoStream
115 var got []byte
116 for _, f := range test.frames {
117 t.Logf("receive [%v,%v)", f.start, f.end)
118 s.handleCrypto(
119 f.start,
120 data[f.start:f.end],
121 func(b []byte) error {
122 t.Logf("got new bytes [%v,%v)", len(got), len(got)+len(b))
123 got = append(got, b...)
124 return nil
125 },
126 )
127 if len(got) != f.want {
128 t.Fatalf("have bytes [0,%v), want [0,%v)", len(got), f.want)
129 }
130 for i := range got {
131 if got[i] != data[i] {
132 t.Fatalf("byte %v of received data = %v, want %v", i, got[i], data[i])
133 }
134 }
135 }
136 })
137 }
138 }
139
140 func TestCryptoStreamSends(t *testing.T) {
141 data := make([]byte, 1<<20)
142 rand.Read(data)
143 type (
144 sendOp i64range[int64]
145 ackOp i64range[int64]
146 lossOp i64range[int64]
147 )
148 for _, test := range []struct {
149 name string
150 size int64
151 ops []any
152 wantSend []i64range[int64]
153 wantPTOSend []i64range[int64]
154 }{{
155 name: "writes with data remaining",
156 size: 4000,
157 ops: []any{
158 sendOp{0, 1000},
159 sendOp{1000, 2000},
160 sendOp{2000, 3000},
161 },
162 wantSend: []i64range[int64]{
163 {3000, 4000},
164 },
165 wantPTOSend: []i64range[int64]{
166 {0, 4000},
167 },
168 }, {
169 name: "lost data is resent",
170 size: 4000,
171 ops: []any{
172 sendOp{0, 1000},
173 sendOp{1000, 2000},
174 sendOp{2000, 3000},
175 sendOp{3000, 4000},
176 lossOp{1000, 2000},
177 lossOp{3000, 4000},
178 },
179 wantSend: []i64range[int64]{
180 {1000, 2000},
181 {3000, 4000},
182 },
183 wantPTOSend: []i64range[int64]{
184 {0, 4000},
185 },
186 }, {
187 name: "acked data at start of range",
188 size: 4000,
189 ops: []any{
190 sendOp{0, 4000},
191 ackOp{0, 1000},
192 ackOp{1000, 2000},
193 ackOp{2000, 3000},
194 },
195 wantSend: nil,
196 wantPTOSend: []i64range[int64]{
197 {3000, 4000},
198 },
199 }, {
200 name: "acked data is not resent on pto",
201 size: 4000,
202 ops: []any{
203 sendOp{0, 4000},
204 ackOp{1000, 2000},
205 },
206 wantSend: nil,
207 wantPTOSend: []i64range[int64]{
208 {0, 1000},
209 },
210 }, {
211
212
213 name: "acked and then lost data is not resent",
214 size: 4000,
215 ops: []any{
216 sendOp{0, 4000},
217 sendOp{1000, 2000},
218 ackOp{1000, 2000},
219 lossOp{1000, 2000},
220 },
221 wantSend: nil,
222 wantPTOSend: []i64range[int64]{
223 {0, 1000},
224 },
225 }, {
226
227
228 name: "lost and then acked data is not resent",
229 size: 4000,
230 ops: []any{
231 sendOp{0, 4000},
232 sendOp{1000, 2000},
233 lossOp{1000, 2000},
234 ackOp{1000, 2000},
235 },
236 wantSend: nil,
237 wantPTOSend: []i64range[int64]{
238 {0, 1000},
239 },
240 }} {
241 t.Run(test.name, func(t *testing.T) {
242 var s cryptoStream
243 s.write(data[:test.size])
244 for _, op := range test.ops {
245 switch op := op.(type) {
246 case sendOp:
247 t.Logf("send [%v,%v)", op.start, op.end)
248 b := make([]byte, op.end-op.start)
249 s.sendData(op.start, b)
250 case ackOp:
251 t.Logf("ack [%v,%v)", op.start, op.end)
252 s.ackOrLoss(op.start, op.end, packetAcked)
253 case lossOp:
254 t.Logf("loss [%v,%v)", op.start, op.end)
255 s.ackOrLoss(op.start, op.end, packetLost)
256 default:
257 t.Fatalf("unhandled type %T", op)
258 }
259 }
260 var gotSend []i64range[int64]
261 s.dataToSend(true, func(off, size int64) (wrote int64) {
262 gotSend = append(gotSend, i64range[int64]{off, off + size})
263 return 0
264 })
265 if !reflect.DeepEqual(gotSend, test.wantPTOSend) {
266 t.Fatalf("got data to send on PTO: %v, want %v", gotSend, test.wantPTOSend)
267 }
268 gotSend = nil
269 s.dataToSend(false, func(off, size int64) (wrote int64) {
270 gotSend = append(gotSend, i64range[int64]{off, off + size})
271 b := make([]byte, size)
272 s.sendData(off, b)
273 return int64(len(b))
274 })
275 if !reflect.DeepEqual(gotSend, test.wantSend) {
276 t.Fatalf("got data to send: %v, want %v", gotSend, test.wantSend)
277 }
278 })
279 }
280 }
281
View as plain text