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 ###############################################################################