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);