Mercurial > hg > nginx-tests
comparison spdy.t @ 425:cc7da696a330
Tests: reduced execution time of SPDY tests.
Notably, added hints when to stop reading data.
Read function changed to blocking mode.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Fri, 04 Jul 2014 12:37:13 +0400 |
parents | 5c25acbc870a |
children | 7cb6af00afdd |
comparison
equal
deleted
inserted
replaced
424:e402c5ed57eb | 425:cc7da696a330 |
---|---|
111 | 111 |
112 # PING | 112 # PING |
113 | 113 |
114 my $sess = new_session(); | 114 my $sess = new_session(); |
115 spdy_ping($sess, 0x12345678); | 115 spdy_ping($sess, 0x12345678); |
116 my $frames = spdy_read($sess); | 116 my $frames = spdy_read($sess, all => [{ type => 'PING' }]); |
117 | 117 |
118 my ($frame) = grep { $_->{type} eq "PING" } @$frames; | 118 my ($frame) = grep { $_->{type} eq "PING" } @$frames; |
119 ok($frame, 'PING frame'); | 119 ok($frame, 'PING frame'); |
120 is($frame->{value}, 0x12345678, 'PING payload'); | 120 is($frame->{value}, 0x12345678, 'PING payload'); |
121 | 121 |
264 | 264 |
265 # WINDOW_UPDATE (client side) | 265 # WINDOW_UPDATE (client side) |
266 | 266 |
267 $sess = new_session(); | 267 $sess = new_session(); |
268 $sid1 = spdy_stream($sess, { path => '/t1.html' }); | 268 $sid1 = spdy_stream($sess, { path => '/t1.html' }); |
269 $frames = spdy_read($sess, all => [{ sid => $sid1, fin => 0 }]); | 269 $frames = spdy_read($sess, all => [{ sid => $sid1, length => 2**16 }]); |
270 | 270 |
271 @data = grep { $_->{type} eq "DATA" } @$frames; | 271 @data = grep { $_->{type} eq "DATA" } @$frames; |
272 my $sum = eval join '+', map { $_->{length} } @data; | 272 my $sum = eval join '+', map { $_->{length} } @data; |
273 is($sum, 2**16, 'iws - stream blocked on initial window size'); | 273 is($sum, 2**16, 'iws - stream blocked on initial window size'); |
274 | 274 |
275 spdy_ping($sess, 0xf00ff00f); | 275 spdy_ping($sess, 0xf00ff00f); |
276 $frames = spdy_read($sess); | 276 $frames = spdy_read($sess, all => [{ type => 'PING' }]); |
277 | 277 |
278 ($frame) = grep { $_->{type} eq "PING" } @$frames; | 278 ($frame) = grep { $_->{type} eq "PING" } @$frames; |
279 ok($frame, 'iws - PING not blocked'); | 279 ok($frame, 'iws - PING not blocked'); |
280 | 280 |
281 spdy_window($sess, 2**16, $sid1); | 281 spdy_window($sess, 2**16, $sid1); |
304 | 304 |
305 # probe for negative available space in a flow control window | 305 # probe for negative available space in a flow control window |
306 | 306 |
307 $sess = new_session(); | 307 $sess = new_session(); |
308 $sid1 = spdy_stream($sess, { path => '/t1.html' }); | 308 $sid1 = spdy_stream($sess, { path => '/t1.html' }); |
309 spdy_read($sess, all => [{ sid => $sid1, fin => 0 }]); | 309 spdy_read($sess, all => [{ sid => $sid1, length => 2**16 }]); |
310 | 310 |
311 spdy_window($sess, 1); | 311 spdy_window($sess, 1); |
312 spdy_settings($sess, 7 => 42); | 312 spdy_settings($sess, 7 => 42); |
313 spdy_window($sess, 1024, $sid1); | 313 spdy_window($sess, 1024, $sid1); |
314 | 314 |
318 spdy_window($sess, 2**16 - 42 - 1024, $sid1); | 318 spdy_window($sess, 2**16 - 42 - 1024, $sid1); |
319 $frames = spdy_read($sess); | 319 $frames = spdy_read($sess); |
320 is(@$frames, 0, 'zero window - no data'); | 320 is(@$frames, 0, 'zero window - no data'); |
321 | 321 |
322 spdy_window($sess, 1, $sid1); | 322 spdy_window($sess, 1, $sid1); |
323 $frames = spdy_read($sess, all => [{ sid => $sid1, fin => 0 }]); | 323 $frames = spdy_read($sess, all => [{ sid => $sid1, length => 1 }]); |
324 is(@$frames, 1, 'positive window - data'); | 324 is(@$frames, 1, 'positive window - data'); |
325 is(@$frames[0]->{length}, 1, 'positive window - data length'); | 325 is(@$frames[0]->{length}, 1, 'positive window - data length'); |
326 | 326 |
327 # stream multiplexing | 327 # stream multiplexing |
328 | 328 |
329 $sess = new_session(); | 329 $sess = new_session(); |
330 $sid1 = spdy_stream($sess, { path => '/t1.html' }); | 330 $sid1 = spdy_stream($sess, { path => '/t1.html' }); |
331 $frames = spdy_read($sess, all => [{ sid => $sid1, fin => 0 }]); | 331 $frames = spdy_read($sess, all => [{ sid => $sid1, length => 2**16 }]); |
332 | 332 |
333 @data = grep { $_->{type} eq "DATA" } @$frames; | 333 @data = grep { $_->{type} eq "DATA" } @$frames; |
334 $sum = eval join '+', map { $_->{length} } @data; | 334 $sum = eval join '+', map { $_->{length} } @data; |
335 is($sum, 2**16, 'multiple - stream1 data'); | 335 is($sum, 2**16, 'multiple - stream1 data'); |
336 | 336 |
381 # stream muliplexing + priority | 381 # stream muliplexing + priority |
382 | 382 |
383 $sess = new_session(); | 383 $sess = new_session(); |
384 $sid1 = spdy_stream($sess, { path => '/t1.html', prio => 7 }); | 384 $sid1 = spdy_stream($sess, { path => '/t1.html', prio => 7 }); |
385 $sid2 = spdy_stream($sess, { path => '/t2.html', prio => 0 }); | 385 $sid2 = spdy_stream($sess, { path => '/t2.html', prio => 0 }); |
386 spdy_read($sess); | 386 spdy_read($sess, all => [ |
387 { sid => $sid1, length => 2**16 }, | |
388 { sid => $sid2, fin => 0 } | |
389 ]); | |
387 | 390 |
388 spdy_window($sess, 2**17, $sid1); | 391 spdy_window($sess, 2**17, $sid1); |
389 spdy_window($sess, 2**17, $sid2); | 392 spdy_window($sess, 2**17, $sid2); |
390 spdy_window($sess, 2**17); | 393 spdy_window($sess, 2**17); |
391 | 394 |
400 # and vice versa | 403 # and vice versa |
401 | 404 |
402 $sess = new_session(); | 405 $sess = new_session(); |
403 $sid1 = spdy_stream($sess, { path => '/t1.html', prio => 0 }); | 406 $sid1 = spdy_stream($sess, { path => '/t1.html', prio => 0 }); |
404 $sid2 = spdy_stream($sess, { path => '/t2.html', prio => 7 }); | 407 $sid2 = spdy_stream($sess, { path => '/t2.html', prio => 7 }); |
405 spdy_read($sess); | 408 spdy_read($sess, all => [ |
409 { sid => $sid1, length => 2**16 }, | |
410 { sid => $sid2, fin => 0 } | |
411 ]); | |
406 | 412 |
407 spdy_window($sess, 2**17, $sid1); | 413 spdy_window($sess, 2**17, $sid1); |
408 spdy_window($sess, 2**17, $sid2); | 414 spdy_window($sess, 2**17, $sid2); |
409 spdy_window($sess, 2**17); | 415 spdy_window($sess, 2**17); |
410 | 416 |
568 raw_write($sess->{socket}, $buf); | 574 raw_write($sess->{socket}, $buf); |
569 } | 575 } |
570 | 576 |
571 sub spdy_read { | 577 sub spdy_read { |
572 my ($sess, %extra) = @_; | 578 my ($sess, %extra) = @_; |
573 my ($skip, $length, $buf, @got); | 579 my ($length, @got); |
574 my $tries = 0; | 580 my $s = $sess->{socket}; |
575 my $maxtried = 3; | 581 my $buf = ''; |
576 | 582 |
583 eval { | |
584 local $SIG{ALRM} = sub { die "timeout\n" }; | |
585 local $SIG{PIPE} = sub { die "sigpipe\n" }; | |
577 again: | 586 again: |
578 do { | 587 alarm(1); |
579 $buf = raw_read($sess->{socket}); | 588 |
580 } until (defined $buf || $tries++ >= $maxtried); | 589 $buf = raw_read($s, $buf, 8); |
581 | 590 |
582 $buf = '' if !defined $buf; | 591 my $type = unpack("B", $buf); |
583 | 592 $length = 8 + hex unpack("x5 H6", $buf); |
584 for ($skip = 0; $skip < length $buf; $skip += $length + 8) { | 593 $buf = raw_read($s, $buf, $length); |
585 my $type = unpack("\@$skip B", $buf); | 594 |
586 $length = hex unpack("\@$skip x5 H6", $buf); | |
587 if ($type == 0) { | 595 if ($type == 0) { |
588 push @got, dframe($skip, $buf); | 596 push @got, dframe($buf); |
589 test_fin($got[-1], $extra{all}); | 597 |
590 next; | 598 } else { |
599 my $ctype = unpack("x2 n", $buf); | |
600 push @got, $cframe{$ctype}($sess, $buf); | |
591 } | 601 } |
592 | 602 $buf = substr($buf, $length); |
593 my $ctype = unpack("\@$skip x2 n", $buf); | 603 |
594 push @got, $cframe{$ctype}($sess, $skip, $buf); | 604 goto again if test_fin($got[-1], $extra{all}); |
595 test_fin($got[-1], $extra{all}); | 605 alarm(0); |
596 } | 606 }; |
597 goto again if %extra && @{$extra{all}} && $tries < $maxtried; | 607 alarm(0); |
598 return \@got; | 608 return \@got; |
599 } | 609 } |
600 | 610 |
601 sub test_fin { | 611 sub test_fin { |
602 my ($frame, $all) = @_; | 612 my ($frame, $all) = @_; |
603 | 613 my @test = @{$all}; |
604 @{$all} = grep { | 614 |
605 !($_->{sid} == $frame->{sid} && $_->{fin} == $frame->{fin}) | 615 # wait for the specified DATA length |
606 } @{$all} if defined $frame->{fin}; | 616 |
617 for (@test) { | |
618 if ($_->{length} && $frame->{type} eq 'DATA') { | |
619 # check also for StreamID if needed | |
620 | |
621 if (!$_->{sid} || $_->{sid} == $frame->{sid}) { | |
622 $_->{length} -= $frame->{length}; | |
623 } | |
624 } | |
625 } | |
626 @test = grep { !(defined $_->{length} && $_->{length} == 0) } @test; | |
627 | |
628 # wait for the fin flag | |
629 | |
630 @test = grep { !(defined $_->{fin} | |
631 && $_->{sid} == $frame->{sid} && $_->{fin} == $frame->{fin}) | |
632 } @test if defined $frame->{fin}; | |
633 | |
634 # wait for the specified frame | |
635 | |
636 @test = grep { !($_->{type} && $_->{type} eq $frame->{type}) } @test; | |
637 | |
638 @{$all} = @test; | |
607 } | 639 } |
608 | 640 |
609 sub dframe { | 641 sub dframe { |
610 my ($skip, $buf) = @_; | 642 my ($buf) = @_; |
611 my %frame; | 643 my %frame; |
644 my $skip = 0; | |
612 | 645 |
613 my $stream = unpack "\@$skip B32", $buf; $skip += 4; | 646 my $stream = unpack "\@$skip B32", $buf; $skip += 4; |
614 substr($stream, 0, 1) = 0; | 647 substr($stream, 0, 1) = 0; |
615 $stream = unpack("N", pack("B32", $stream)); | 648 $stream = unpack("N", pack("B32", $stream)); |
616 $frame{sid} = $stream; | 649 $frame{sid} = $stream; |
687 raw_write($ctx->{socket}, $buf); | 720 raw_write($ctx->{socket}, $buf); |
688 return $ctx->{last_stream}; | 721 return $ctx->{last_stream}; |
689 } | 722 } |
690 | 723 |
691 sub syn_reply { | 724 sub syn_reply { |
692 my ($ctx, $skip, $buf) = @_; | 725 my ($ctx, $buf) = @_; |
693 my ($i, $status); | 726 my ($i, $status); |
694 my %payload; | 727 my %payload; |
695 | 728 my $skip = 4; |
696 $skip += 4; | 729 |
697 my $flags = unpack "\@$skip B8", $buf; $skip += 1; | 730 my $flags = unpack "\@$skip B8", $buf; $skip += 1; |
698 $payload{fin} = substr($flags, 7, 1); | 731 $payload{fin} = substr($flags, 7, 1); |
699 | 732 |
700 my $length = hex unpack "\@$skip H6", $buf; $skip += 3; | 733 my $length = hex unpack "\@$skip H6", $buf; $skip += 3; |
701 $payload{length} = $length; | 734 $payload{length} = $length; |
714 $payload{headers} = hunpack($out); | 747 $payload{headers} = hunpack($out); |
715 return \%payload; | 748 return \%payload; |
716 } | 749 } |
717 | 750 |
718 sub rst_stream { | 751 sub rst_stream { |
719 my ($ctx, $skip, $buf) = @_; | 752 my ($ctx, $buf) = @_; |
720 my %payload; | 753 my %payload; |
721 | 754 my $skip = 5; |
722 $skip += 5; | 755 |
723 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; | 756 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; |
724 $payload{type} = 'RST_STREAM'; | 757 $payload{type} = 'RST_STREAM'; |
725 $payload{sid} = unpack "\@$skip N", $buf; $skip += 4; | 758 $payload{sid} = unpack "\@$skip N", $buf; $skip += 4; |
726 $payload{code} = unpack "\@$skip N", $buf; | 759 $payload{code} = unpack "\@$skip N", $buf; |
727 return \%payload; | 760 return \%payload; |
728 } | 761 } |
729 | 762 |
730 sub settings { | 763 sub settings { |
731 my ($ctx, $skip, $buf) = @_; | 764 my ($ctx, $buf) = @_; |
732 my %payload; | 765 my %payload; |
733 | 766 my $skip = 4; |
734 $skip += 4; | 767 |
735 $payload{flags} = unpack "\@$skip H", $buf; $skip += 1; | 768 $payload{flags} = unpack "\@$skip H", $buf; $skip += 1; |
736 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; | 769 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; |
737 $payload{type} = 'SETTINGS'; | 770 $payload{type} = 'SETTINGS'; |
738 | 771 |
739 my $nent = unpack "\@$skip N", $buf; $skip += 4; | 772 my $nent = unpack "\@$skip N", $buf; $skip += 4; |
745 } | 778 } |
746 return \%payload; | 779 return \%payload; |
747 } | 780 } |
748 | 781 |
749 sub ping { | 782 sub ping { |
750 my ($ctx, $skip, $buf) = @_; | 783 my ($ctx, $buf) = @_; |
751 my %payload; | 784 my %payload; |
752 | 785 my $skip = 5; |
753 $skip += 5; | 786 |
754 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; | 787 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; |
755 $payload{type} = 'PING'; | 788 $payload{type} = 'PING'; |
756 $payload{value} = unpack "\@$skip N", $buf; | 789 $payload{value} = unpack "\@$skip N", $buf; |
757 return \%payload; | 790 return \%payload; |
758 } | 791 } |
759 | 792 |
760 sub goaway { | 793 sub goaway { |
761 my ($ctx, $skip, $buf) = @_; | 794 my ($ctx, $buf) = @_; |
762 my %payload; | 795 my %payload; |
763 | 796 my $skip = 5; |
764 $skip += 5; | 797 |
765 $payload{length} = hex unpack "\@$skip H6", $buf; $skip += 3; | 798 $payload{length} = hex unpack "\@$skip H6", $buf; $skip += 3; |
766 $payload{type} = 'GOAWAY'; | 799 $payload{type} = 'GOAWAY'; |
767 $payload{sid} = unpack "\@$skip N", $buf; $skip += 4; | 800 $payload{sid} = unpack "\@$skip N", $buf; $skip += 4; |
768 $payload{code} = unpack "\@$skip N", $buf; | 801 $payload{code} = unpack "\@$skip N", $buf; |
769 return \%payload; | 802 return \%payload; |
770 } | 803 } |
771 | 804 |
772 sub window_update { | 805 sub window_update { |
773 my ($ctx, $skip, $buf) = @_; | 806 my ($ctx, $buf) = @_; |
774 my %payload; | 807 my %payload; |
775 | 808 my $skip = 5; |
776 $skip += 5; | |
777 | 809 |
778 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; | 810 $payload{length} = hex(unpack "\@$skip H6", $buf); $skip += 3; |
779 $payload{type} = 'WINDOW_UPDATE'; | 811 $payload{type} = 'WINDOW_UPDATE'; |
780 | 812 |
781 my $stream = unpack "\@$skip B32", $buf; $skip += 4; | 813 my $stream = unpack "\@$skip B32", $buf; $skip += 4; |
812 } | 844 } |
813 return \%headers; | 845 return \%headers; |
814 } | 846 } |
815 | 847 |
816 sub raw_read { | 848 sub raw_read { |
817 my ($s) = @_; | 849 my ($s, $buf, $len) = @_; |
818 my ($got, $buf); | 850 my $got = ''; |
819 | 851 |
820 $s->blocking(0); | 852 while (length($buf) < $len) { |
821 while (IO::Select->new($s)->can_read(0.4)) { | 853 $s->sysread($got, $len - length($buf)) or die; |
822 my $n = $s->sysread($buf, 1024); | 854 log_in($got); |
823 last unless $n; | 855 $buf .= $got; |
824 $got .= $buf; | 856 } |
825 }; | 857 return $buf; |
826 log_in($got); | |
827 return $got; | |
828 } | 858 } |
829 | 859 |
830 sub raw_write { | 860 sub raw_write { |
831 my ($s, $message) = @_; | 861 my ($s, $message) = @_; |
832 | 862 |
833 local $SIG{PIPE} = 'IGNORE'; | 863 local $SIG{PIPE} = 'IGNORE'; |
834 | 864 |
835 $s->blocking(0); | |
836 while (IO::Select->new($s)->can_write(0.4)) { | 865 while (IO::Select->new($s)->can_write(0.4)) { |
837 log_out($message); | 866 log_out($message); |
838 my $n = $s->syswrite($message); | 867 my $n = $s->syswrite($message); |
839 last unless $n; | 868 last unless $n; |
840 $message = substr($message, $n); | 869 $message = substr($message, $n); |