Mercurial > hg > nginx-tests
comparison h2_priority.t @ 876:a6abbfed42c0
Tests: split HTTP/2 tests, HTTP2 package introduced.
author | Andrey Zelenkov <zelenkov@nginx.com> |
---|---|
date | Wed, 23 Mar 2016 17:23:08 +0300 |
parents | |
children | 4dc302d8e04f |
comparison
equal
deleted
inserted
replaced
875:c380b4b7e2e4 | 876:a6abbfed42c0 |
---|---|
1 #!/usr/bin/perl | |
2 | |
3 # (C) Sergey Kandaurov | |
4 # (C) Nginx, Inc. | |
5 | |
6 # Tests for HTTP/2 protocol with priority. | |
7 | |
8 ############################################################################### | |
9 | |
10 use warnings; | |
11 use strict; | |
12 | |
13 use Test::More; | |
14 | |
15 BEGIN { use FindBin; chdir($FindBin::Bin); } | |
16 | |
17 use lib 'lib'; | |
18 use Test::Nginx; | |
19 use Test::Nginx::HTTP2 qw/ :DEFAULT :frame /; | |
20 | |
21 ############################################################################### | |
22 | |
23 select STDERR; $| = 1; | |
24 select STDOUT; $| = 1; | |
25 | |
26 my $t = Test::Nginx->new()->has(qw/http http_v2/)->plan(20) | |
27 ->write_file_expand('nginx.conf', <<'EOF'); | |
28 | |
29 %%TEST_GLOBALS%% | |
30 | |
31 daemon off; | |
32 | |
33 events { | |
34 } | |
35 | |
36 http { | |
37 %%TEST_GLOBALS_HTTP%% | |
38 | |
39 server { | |
40 listen 127.0.0.1:8080 http2; | |
41 server_name localhost; | |
42 } | |
43 } | |
44 | |
45 EOF | |
46 | |
47 $t->run(); | |
48 | |
49 # file size is slightly beyond initial window size: 2**16 + 80 bytes | |
50 | |
51 $t->write_file('t1.html', | |
52 join('', map { sprintf "X%04dXXX", $_ } (1 .. 8202))); | |
53 | |
54 $t->write_file('t2.html', 'SEE-THIS'); | |
55 | |
56 ############################################################################### | |
57 | |
58 # stream muliplexing + PRIORITY frames | |
59 | |
60 my $sess = new_session(); | |
61 my $sid = new_stream($sess, { path => '/t1.html' }); | |
62 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
63 | |
64 my $sid2 = new_stream($sess, { path => '/t2.html' }); | |
65 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
66 | |
67 h2_priority($sess, 0, $sid); | |
68 h2_priority($sess, 255, $sid2); | |
69 | |
70 h2_window($sess, 2**17, $sid); | |
71 h2_window($sess, 2**17, $sid2); | |
72 h2_window($sess, 2**17); | |
73 | |
74 my $frames = h2_read($sess, all => [ | |
75 { sid => $sid, fin => 1 }, | |
76 { sid => $sid2, fin => 1 } | |
77 ]); | |
78 | |
79 my @data = grep { $_->{type} eq "DATA" } @$frames; | |
80 is(join(' ', map { $_->{sid} } @data), "$sid2 $sid", 'weight - PRIORITY 1'); | |
81 | |
82 # and vice versa | |
83 | |
84 $sess = new_session(); | |
85 $sid = new_stream($sess, { path => '/t1.html' }); | |
86 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
87 | |
88 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
89 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
90 | |
91 h2_priority($sess, 255, $sid); | |
92 h2_priority($sess, 0, $sid2); | |
93 | |
94 h2_window($sess, 2**17, $sid); | |
95 h2_window($sess, 2**17, $sid2); | |
96 h2_window($sess, 2**17); | |
97 | |
98 $frames = h2_read($sess, all => [ | |
99 { sid => $sid, fin => 1 }, | |
100 { sid => $sid2, fin => 1 } | |
101 ]); | |
102 | |
103 @data = grep { $_->{type} eq "DATA" } @$frames; | |
104 is(join(' ', map { $_->{sid} } @data), "$sid $sid2", 'weight - PRIORITY 2'); | |
105 | |
106 # stream muliplexing + HEADERS PRIORITY flag | |
107 | |
108 $sess = new_session(); | |
109 $sid = new_stream($sess, { path => '/t1.html', prio => 0 }); | |
110 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
111 | |
112 $sid2 = new_stream($sess, { path => '/t2.html', prio => 255 }); | |
113 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
114 | |
115 h2_window($sess, 2**17, $sid); | |
116 h2_window($sess, 2**17, $sid2); | |
117 h2_window($sess, 2**17); | |
118 | |
119 $frames = h2_read($sess, all => [ | |
120 { sid => $sid, fin => 1 }, | |
121 { sid => $sid2, fin => 1 } | |
122 ]); | |
123 | |
124 @data = grep { $_->{type} eq "DATA" } @$frames; | |
125 my $sids = join ' ', map { $_->{sid} } @data; | |
126 is($sids, "$sid2 $sid", 'weight - HEADERS PRIORITY 1'); | |
127 | |
128 # and vice versa | |
129 | |
130 $sess = new_session(); | |
131 $sid = new_stream($sess, { path => '/t1.html', prio => 255 }); | |
132 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
133 | |
134 $sid2 = new_stream($sess, { path => '/t2.html', prio => 0 }); | |
135 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
136 | |
137 h2_window($sess, 2**17, $sid); | |
138 h2_window($sess, 2**17, $sid2); | |
139 h2_window($sess, 2**17); | |
140 | |
141 $frames = h2_read($sess, all => [ | |
142 { sid => $sid, fin => 1 }, | |
143 { sid => $sid2, fin => 1 } | |
144 ]); | |
145 | |
146 @data = grep { $_->{type} eq "DATA" } @$frames; | |
147 $sids = join ' ', map { $_->{sid} } @data; | |
148 is($sids, "$sid $sid2", 'weight - HEADERS PRIORITY 2'); | |
149 | |
150 # 5.3.1. Stream Dependencies | |
151 | |
152 # PRIORITY frame | |
153 | |
154 $sess = new_session(); | |
155 | |
156 h2_priority($sess, 16, 3, 0); | |
157 h2_priority($sess, 16, 1, 3); | |
158 | |
159 $sid = new_stream($sess, { path => '/t1.html' }); | |
160 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
161 | |
162 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
163 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
164 | |
165 h2_window($sess, 2**17, $sid); | |
166 h2_window($sess, 2**17, $sid2); | |
167 h2_window($sess, 2**17); | |
168 | |
169 $frames = h2_read($sess, all => [ | |
170 { sid => $sid, fin => 1 }, | |
171 { sid => $sid2, fin => 1 }, | |
172 ]); | |
173 | |
174 @data = grep { $_->{type} eq "DATA" } @$frames; | |
175 $sids = join ' ', map { $_->{sid} } @data; | |
176 is($sids, "$sid2 $sid", 'dependency - PRIORITY 1'); | |
177 | |
178 # and vice versa | |
179 | |
180 $sess = new_session(); | |
181 | |
182 h2_priority($sess, 16, 1, 0); | |
183 h2_priority($sess, 16, 3, 1); | |
184 | |
185 $sid = new_stream($sess, { path => '/t1.html' }); | |
186 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
187 | |
188 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
189 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
190 | |
191 h2_window($sess, 2**17, $sid); | |
192 h2_window($sess, 2**17, $sid2); | |
193 h2_window($sess, 2**17); | |
194 | |
195 $frames = h2_read($sess, all => [ | |
196 { sid => $sid, fin => 1 }, | |
197 { sid => $sid2, fin => 1 }, | |
198 ]); | |
199 | |
200 @data = grep { $_->{type} eq "DATA" } @$frames; | |
201 $sids = join ' ', map { $_->{sid} } @data; | |
202 is($sids, "$sid $sid2", 'dependency - PRIORITY 2'); | |
203 | |
204 # PRIORITY - self dependency | |
205 | |
206 # 5.3.1. Stream Dependencies | |
207 # A stream cannot depend on itself. An endpoint MUST treat this as a | |
208 # stream error of type PROTOCOL_ERROR. | |
209 | |
210 $sess = new_session(); | |
211 $sid = new_stream($sess); | |
212 h2_read($sess, all => [{ sid => $sid, fin => 1 }]); | |
213 | |
214 h2_priority($sess, 0, $sid, $sid); | |
215 $frames = h2_read($sess, all => [{ type => 'RST_STREAM' }]); | |
216 | |
217 my ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; | |
218 is($frame->{sid}, $sid, 'dependency - PRIORITY self - RST_STREAM'); | |
219 is($frame->{code}, 1, 'dependency - PRIORITY self - PROTOCOL_ERROR'); | |
220 | |
221 # HEADERS PRIORITY flag, reprioritize prior PRIORITY frame records | |
222 | |
223 $sess = new_session(); | |
224 | |
225 h2_priority($sess, 16, 1, 0); | |
226 h2_priority($sess, 16, 3, 0); | |
227 | |
228 $sid = new_stream($sess, { path => '/t1.html', dep => 3 }); | |
229 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
230 | |
231 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
232 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
233 | |
234 h2_window($sess, 2**17, $sid); | |
235 h2_window($sess, 2**17, $sid2); | |
236 h2_window($sess, 2**17); | |
237 | |
238 $frames = h2_read($sess, all => [ | |
239 { sid => $sid, fin => 1 }, | |
240 { sid => $sid2, fin => 1 }, | |
241 ]); | |
242 | |
243 @data = grep { $_->{type} eq "DATA" } @$frames; | |
244 $sids = join ' ', map { $_->{sid} } @data; | |
245 is($sids, "$sid2 $sid", 'dependency - HEADERS PRIORITY 1'); | |
246 | |
247 # and vice versa | |
248 | |
249 $sess = new_session(); | |
250 | |
251 h2_priority($sess, 16, 1, 0); | |
252 h2_priority($sess, 16, 3, 0); | |
253 | |
254 $sid = new_stream($sess, { path => '/t1.html' }); | |
255 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
256 | |
257 $sid2 = new_stream($sess, { path => '/t2.html', dep => 1 }); | |
258 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
259 | |
260 h2_window($sess, 2**17, $sid); | |
261 h2_window($sess, 2**17, $sid2); | |
262 h2_window($sess, 2**17); | |
263 | |
264 $frames = h2_read($sess, all => [ | |
265 { sid => $sid, fin => 1 }, | |
266 { sid => $sid2, fin => 1 }, | |
267 ]); | |
268 | |
269 @data = grep { $_->{type} eq "DATA" } @$frames; | |
270 $sids = join ' ', map { $_->{sid} } @data; | |
271 is($sids, "$sid $sid2", 'dependency - HEADERS PRIORITY 2'); | |
272 | |
273 # HEADERS - self dependency | |
274 | |
275 $sess = new_session(); | |
276 $sid = new_stream($sess, { dep => 1 }); | |
277 $frames = h2_read($sess, all => [{ type => 'RST_STREAM' }]); | |
278 | |
279 ($frame) = grep { $_->{type} eq "RST_STREAM" } @$frames; | |
280 is($frame->{sid}, $sid, 'dependency - HEADERS self - RST_STREAM'); | |
281 is($frame->{code}, 1, 'dependency - HEADERS self - PROTOCOL_ERROR'); | |
282 | |
283 # PRIORITY frame, weighted dependencies | |
284 | |
285 $sess = new_session(); | |
286 | |
287 h2_priority($sess, 16, 5, 0); | |
288 h2_priority($sess, 255, 1, 5); | |
289 h2_priority($sess, 0, 3, 5); | |
290 | |
291 $sid = new_stream($sess, { path => '/t1.html' }); | |
292 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
293 | |
294 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
295 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
296 | |
297 my $sid3 = new_stream($sess, { path => '/t2.html' }); | |
298 h2_read($sess, all => [{ sid => $sid3, fin => 0x4 }]); | |
299 | |
300 h2_window($sess, 2**16, 1); | |
301 h2_window($sess, 2**16, 3); | |
302 h2_window($sess, 2**16, 5); | |
303 h2_window($sess, 2**16); | |
304 | |
305 $frames = h2_read($sess, all => [ | |
306 { sid => $sid, fin => 1 }, | |
307 { sid => $sid2, fin => 1 }, | |
308 { sid => $sid3, fin => 1 }, | |
309 ]); | |
310 | |
311 @data = grep { $_->{type} eq "DATA" } @$frames; | |
312 $sids = join ' ', map { $_->{sid} } @data; | |
313 is($sids, "$sid3 $sid $sid2", 'weighted dependency - PRIORITY 1'); | |
314 | |
315 # and vice versa | |
316 | |
317 $sess = new_session(); | |
318 | |
319 h2_priority($sess, 16, 5, 0); | |
320 h2_priority($sess, 0, 1, 5); | |
321 h2_priority($sess, 255, 3, 5); | |
322 | |
323 $sid = new_stream($sess, { path => '/t1.html' }); | |
324 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
325 | |
326 $sid2 = new_stream($sess, { path => '/t2.html' }); | |
327 h2_read($sess, all => [{ sid => $sid2, fin => 0x4 }]); | |
328 | |
329 $sid3 = new_stream($sess, { path => '/t2.html' }); | |
330 h2_read($sess, all => [{ sid => $sid3, fin => 0x4 }]); | |
331 | |
332 h2_window($sess, 2**16, 1); | |
333 h2_window($sess, 2**16, 3); | |
334 h2_window($sess, 2**16, 5); | |
335 h2_window($sess, 2**16); | |
336 | |
337 $frames = h2_read($sess, all => [ | |
338 { sid => $sid, fin => 1 }, | |
339 { sid => $sid2, fin => 1 }, | |
340 { sid => $sid3, fin => 1 }, | |
341 ]); | |
342 | |
343 @data = grep { $_->{type} eq "DATA" } @$frames; | |
344 $sids = join ' ', map { $_->{sid} } @data; | |
345 is($sids, "$sid3 $sid2 $sid", 'weighted dependency - PRIORITY 2'); | |
346 | |
347 # PRIORITY - reprioritization with circular dependency - after [3] removed | |
348 # initial dependency tree: | |
349 # 1 <- [3] <- 5 | |
350 | |
351 $sess = new_session(); | |
352 | |
353 h2_window($sess, 2**18); | |
354 | |
355 h2_priority($sess, 16, 1, 0); | |
356 h2_priority($sess, 16, 3, 1); | |
357 h2_priority($sess, 16, 5, 3); | |
358 | |
359 $sid = new_stream($sess, { path => '/t1.html' }); | |
360 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
361 | |
362 $sid2 = new_stream($sess, { path => '/t1.html' }); | |
363 h2_read($sess, all => [{ sid => $sid2, length => 2**16 - 1 }]); | |
364 | |
365 $sid3 = new_stream($sess, { path => '/t1.html' }); | |
366 h2_read($sess, all => [{ sid => $sid3, length => 2**16 - 1 }]); | |
367 | |
368 h2_window($sess, 2**16, $sid2); | |
369 | |
370 $frames = h2_read($sess, all => [{ sid => $sid2, fin => 1 }]); | |
371 $sids = join ' ', map { $_->{sid} } grep { $_->{type} eq "DATA" } @$frames; | |
372 is($sids, $sid2, 'removed dependency'); | |
373 | |
374 for (1 .. 40) { | |
375 h2_read($sess, all => [{ sid => new_stream($sess), fin => 1 }]); | |
376 } | |
377 | |
378 # make circular dependency | |
379 # 1 <- 5 -- current dependency tree before reprioritization | |
380 # 5 <- 1 | |
381 # 1 <- 5 | |
382 | |
383 h2_priority($sess, 16, 1, 5); | |
384 h2_priority($sess, 16, 5, 1); | |
385 | |
386 h2_window($sess, 2**16, $sid); | |
387 h2_window($sess, 2**16, $sid3); | |
388 | |
389 $frames = h2_read($sess, all => [ | |
390 { sid => $sid, fin => 1 }, | |
391 { sid => $sid3, fin => 1 }, | |
392 ]); | |
393 | |
394 ($frame) = grep { $_->{type} eq "DATA" && $_->{sid} == $sid } @$frames; | |
395 is($frame->{length}, 81, 'removed dependency - first stream'); | |
396 | |
397 ($frame) = grep { $_->{type} eq "DATA" && $_->{sid} == $sid3 } @$frames; | |
398 is($frame->{length}, 81, 'removed dependency - last stream'); | |
399 | |
400 # PRIORITY - reprioritization with circular dependency - exclusive [5] | |
401 # 1 <- [5] <- 3 | |
402 | |
403 $sess = new_session(); | |
404 | |
405 h2_window($sess, 2**18); | |
406 | |
407 h2_priority($sess, 16, 1, 0); | |
408 h2_priority($sess, 16, 3, 1); | |
409 h2_priority($sess, 16, 5, 1, excl => 1); | |
410 | |
411 $sid = new_stream($sess, { path => '/t1.html' }); | |
412 h2_read($sess, all => [{ sid => $sid, length => 2**16 - 1 }]); | |
413 | |
414 $sid2 = new_stream($sess, { path => '/t1.html' }); | |
415 h2_read($sess, all => [{ sid => $sid2, length => 2**16 - 1 }]); | |
416 | |
417 $sid3 = new_stream($sess, { path => '/t1.html' }); | |
418 h2_read($sess, all => [{ sid => $sid3, length => 2**16 - 1 }]); | |
419 | |
420 h2_window($sess, 2**16, $sid); | |
421 | |
422 $frames = h2_read($sess, all => [{ sid => $sid, fin => 1 }]); | |
423 $sids = join ' ', map { $_->{sid} } grep { $_->{type} eq "DATA" } @$frames; | |
424 is($sids, $sid, 'exclusive dependency - parent removed'); | |
425 | |
426 # make circular dependency | |
427 # 5 <- 3 -- current dependency tree before reprioritization | |
428 # 3 <- 5 | |
429 | |
430 h2_priority($sess, 16, 5, 3); | |
431 | |
432 h2_window($sess, 2**16, $sid2); | |
433 h2_window($sess, 2**16, $sid3); | |
434 | |
435 $frames = h2_read($sess, all => [ | |
436 { sid => $sid2, fin => 1 }, | |
437 { sid => $sid3, fin => 1 }, | |
438 ]); | |
439 | |
440 ($frame) = grep { $_->{type} eq "DATA" && $_->{sid} == $sid2 } @$frames; | |
441 is($frame->{length}, 81, 'exclusive dependency - first stream'); | |
442 | |
443 ($frame) = grep { $_->{type} eq "DATA" && $_->{sid} == $sid3 } @$frames; | |
444 is($frame->{length}, 81, 'exclusive dependency - last stream'); | |
445 | |
446 ############################################################################### |