1package Test::Nginx::Socket; 2 3use lib 'lib'; 4use lib 'inc'; 5 6use v5.10.1; 7use Test::Base -Base; 8 9our $VERSION = '0.29'; 10 11use POSIX qw( SIGQUIT SIGKILL SIGTERM SIGHUP ); 12use Encode; 13#use Data::Dumper; 14use Time::HiRes qw(sleep time); 15use Test::LongString; 16use List::MoreUtils qw( any ); 17use List::Util qw( sum min ); 18use IO::Select (); 19use File::Temp qw( tempfile ); 20use Digest::MD5 (); 21use Digest::SHA (); 22use POSIX ":sys_wait_h"; 23 24use Test::Nginx::Util; 25 26#use Smart::Comments::JSON '###'; 27use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); 28use POSIX qw(EAGAIN); 29use IO::Socket; 30 31#our ($PrevRequest, $PrevConfig); 32 33our @EXPORT = qw( env_to_nginx is_str plan run_tests run_test 34 repeat_each config_preamble worker_connections 35 master_process_enabled 36 no_long_string workers master_on master_off 37 log_level no_shuffle no_root_location use_hup 38 server_name 39 server_addr server_root html_dir server_port server_port_for_client 40 timeout no_nginx_manager check_accum_error_log 41 add_block_preprocessor bail_out add_cleanup_handler 42 add_response_body_check 43); 44 45our $CheckLeakCount = $ENV{TEST_NGINX_CHECK_LEAK_COUNT} // 100; 46our $UseHttp2 = $Test::Nginx::Util::UseHttp2; 47our $TotalConnectingTimeouts = 0; 48our $PrevNginxPid; 49 50sub send_request ($$$$@); 51sub send_http2_req ($$$); 52 53sub run_filter_helper($$$); 54sub run_test_helper ($$); 55sub test_stap ($$); 56 57sub error_event_handler ($); 58sub read_event_handler ($); 59sub write_event_handler ($); 60sub transform_response_body ($$$); 61sub check_response_body ($$$$$$); 62sub fmt_str ($); 63sub gen_ab_cmd_from_req ($$@); 64sub gen_curl_cmd_from_req ($$); 65sub get_linear_regression_slope ($); 66sub value_contains ($$); 67 68$RunTestHelper = \&run_test_helper; 69$CheckErrorLog = \&check_error_log; 70$CheckShutdownErrorLog = \&check_shutdown_error_log; 71 72sub set_http_config_filter ($) { 73 $FilterHttpConfig = shift; 74} 75 76our @ResponseBodyChecks; 77 78sub add_response_body_check ($) { 79 push @ResponseBodyChecks, shift; 80} 81 82# This will parse a "request"" string. The expected format is: 83# - One line for the HTTP verb (POST, GET, etc.) plus optional relative URL 84# (default is /) plus optional HTTP version (default is HTTP/1.1). 85# - More lines considered as the body of the request. 86# Most people don't care about headers and this is enough. 87# 88# This function will return a reference to a hash with the parsed elements 89# plus information on the parsing itself like "how many white spaces were 90# skipped before the VERB" (skipped_before_method), "was the version provided" 91# (http_ver_size = 0). 92sub parse_request ($$) { 93 my ( $name, $rrequest ) = @_; 94 open my $in, '<', $rrequest; 95 my $first = <$in>; 96 if ( !$first ) { 97 bail_out("$name - Request line should be non-empty"); 98 } 99 #$first =~ s/^\s+|\s+$//gs; 100 my ($before_meth, $meth, $after_meth); 101 my ($rel_url, $rel_url_size, $after_rel_url); 102 my ($http_ver, $http_ver_size, $after_http_ver); 103 my $end_line_size; 104 if ($first =~ /^(\s*)(\S+)( *)((\S+)( *))?((\S+)( *))?(\s*)$/) { 105 $before_meth = defined $1 ? length($1) : undef; 106 $meth = $2; 107 $after_meth = defined $3 ? length($3) : undef; 108 $rel_url = $5; 109 $rel_url_size = defined $5 ? length($5) : undef; 110 $after_rel_url = defined $6 ? length($6) : undef; 111 $http_ver = $8; 112 if (!defined $8) { 113 $http_ver_size = undef; 114 } else { 115 $http_ver_size = defined $8 ? length($8) : undef; 116 } 117 if (!defined $9) { 118 $after_http_ver = undef; 119 } else { 120 $after_http_ver = defined $9 ? length($9) : undef; 121 } 122 $end_line_size = defined $10 ? length($10) : undef; 123 } else { 124 bail_out("$name - Request line is not valid. Should be 'meth [url [version]]' but got \"$first\"."); 125 } 126 if ( !defined $rel_url ) { 127 $rel_url = '/'; 128 $rel_url_size = 0; 129 $after_rel_url = 0; 130 } 131 if ( !defined $http_ver ) { 132 $http_ver = 'HTTP/1.1'; 133 $http_ver_size = 0; 134 $after_http_ver = 0; 135 } 136 137 #my $url = "http://localhost:$ServerPortForClient" . $rel_url; 138 139 my $content = do { local $/; <$in> }; 140 my $content_size; 141 if ( !defined $content ) { 142 $content = ""; 143 $content_size = 0; 144 } else { 145 $content_size = length($content); 146 } 147 148 #warn Dumper($content); 149 150 close $in; 151 152 return { 153 method => $meth, 154 url => $rel_url, 155 content => $content, 156 http_ver => $http_ver, 157 skipped_before_method => $before_meth, 158 method_size => length($meth), 159 skipped_after_method => $after_meth, 160 url_size => $rel_url_size, 161 skipped_after_url => $after_rel_url, 162 http_ver_size => $http_ver_size, 163 skipped_after_http_ver => $after_http_ver + $end_line_size, 164 content_size => $content_size, 165 }; 166} 167 168# From a parsed request, builds the "moves" to apply to the original request 169# to transform it (e.g. add missing version). Elements of the returned array 170# are of 2 types: 171# - d : number of characters to remove. 172# - s_* : number of characters (s_s) to replace by value (s_v). 173sub get_moves($) { 174 my ($parsed_req) = @_; 175 return ({d => $parsed_req->{skipped_before_method}}, 176 {s_s => $parsed_req->{method_size}, 177 s_v => $parsed_req->{method}}, 178 {d => $parsed_req->{skipped_after_method}}, 179 {s_s => $parsed_req->{url_size}, 180 s_v => $parsed_req->{url}}, 181 {d => $parsed_req->{skipped_after_url}}, 182 {s_s => $parsed_req->{http_ver_size}, 183 s_v => $parsed_req->{http_ver}}, 184 {d => $parsed_req->{skipped_after_http_ver}}, 185 {s_s => 0, 186 s_v => $parsed_req->{headers}}, 187 {s_s => $parsed_req->{content_size}, 188 s_v => $parsed_req->{content}} 189 ); 190} 191 192# Apply moves (see above) to an array of packets that correspond to a request. 193# The use of this function is explained in the build_request_from_packets 194# function. 195sub apply_moves($$) { 196 my ($r_packet, $r_move) = @_; 197 my $current_packet = shift @$r_packet; 198 my $current_move = shift @$r_move; 199 my $in_packet_cursor = 0; 200 my @result = (); 201 while (defined $current_packet) { 202 if (!defined $current_move) { 203 push @result, $current_packet; 204 $current_packet = shift @$r_packet; 205 $in_packet_cursor = 0; 206 } elsif (defined $current_move->{d}) { 207 # Remove stuff from packet 208 if ($current_move->{d} > length($current_packet) - $in_packet_cursor) { 209 # Eat up what is left of packet. 210 $current_move->{d} -= length($current_packet) - $in_packet_cursor; 211 if ($in_packet_cursor > 0) { 212 # Something in packet from previous iteration. 213 push @result, $current_packet; 214 } 215 $current_packet = shift @$r_packet; 216 $in_packet_cursor = 0; 217 } else { 218 # Remove from current point in current packet 219 substr($current_packet, $in_packet_cursor, $current_move->{d}) = ''; 220 $current_move = shift @$r_move; 221 } 222 } else { 223 # Substitute stuff 224 if ($current_move->{s_s} > length($current_packet) - $in_packet_cursor) { 225 # {s_s=>3, s_v=>GET} on ['GE', 'T /foo'] 226 $current_move->{s_s} -= length($current_packet) - $in_packet_cursor; 227 substr($current_packet, $in_packet_cursor) = substr($current_move->{s_v}, 0, length($current_packet) - $in_packet_cursor); 228 push @result, $current_packet; 229 $current_move->{s_v} = substr($current_move->{s_v}, length($current_packet) - $in_packet_cursor); 230 $current_packet = shift @$r_packet; 231 $in_packet_cursor = 0; 232 } else { 233 substr($current_packet, $in_packet_cursor, $current_move->{s_s}) = $current_move->{s_v}; 234 $in_packet_cursor += length($current_move->{s_v}); 235 $current_move = shift @$r_move; 236 } 237 } 238 } 239 return \@result; 240} 241# Given a request as an array of packets, will parse it, append the appropriate 242# headers and return another array of packets. 243# The function implemented here can be high-level summarized as: 244# 1 - Concatenate all packets to obtain a string representation of request. 245# 2 - Parse the string representation 246# 3 - Get the "moves" from the parsing 247# 4 - Apply the "moves" to the packets. 248sub build_request_from_packets($$$$$) { 249 my ( $name, $more_headers, $is_chunked, $conn_header, $request_packets ) = @_; 250 # Concatenate packets as a string 251 my $parsable_request = ''; 252 my @packet_length; 253 for my $one_packet (@$request_packets) { 254 $parsable_request .= $one_packet; 255 push @packet_length, length($one_packet); 256 } 257 # Parse the string representation. 258 my $parsed_req = parse_request( $name, \$parsable_request ); 259 260 # Append headers 261 my $len_header = ''; 262 if ( !$is_chunked 263 && defined $parsed_req->{content} 264 && $parsed_req->{content} ne '' 265 && $more_headers !~ /(?:^|\n)Content-Length:/ ) 266 { 267 $parsed_req->{content} =~ s/^\s+|\s+$//gs; 268 269 $len_header .= 270 "Content-Length: " . length( $parsed_req->{content} ) . "\r\n"; 271 } 272 273 $more_headers =~ s/(?<!\r)\n/\r\n/gs; 274 275 my $headers = ''; 276 277 if ($more_headers !~ /(?:^|\n)Host:/msi) { 278 $headers .= "Host: $ServerName\r\n"; 279 } 280 281 if ($more_headers !~ /(?:^|\n)Connection/msi) { 282 $headers .= "Connection: $conn_header\r\n"; 283 } 284 285 $headers .= "$more_headers$len_header\r\n"; 286 287 $parsed_req->{method} .= ' '; 288 $parsed_req->{url} .= ' '; 289 $parsed_req->{http_ver} .= "\r\n"; 290 $parsed_req->{headers} = $headers; 291 292 # Get the moves from parsing 293 my @elements_moves = get_moves($parsed_req); 294 # Apply them to the packets. 295 return apply_moves($request_packets, \@elements_moves); 296} 297 298sub parse_more_headers ($) { 299 my ($in) = @_; 300 my @headers = split /\n+/, $in; 301 my $is_chunked; 302 my $out = ''; 303 for my $header (@headers) { 304 next if $header =~ /^\s*\#/; 305 #warn "HEADER: $header"; 306 my ($key, $val) = split /:\s*/, $header, 2; 307 if (!defined $val) { 308 $val = ''; 309 } 310 if (lc($key) eq 'transfer-encoding' and $val eq 'chunked') { 311 $is_chunked = 1; 312 } 313 314 #warn "[$key, $val]\n"; 315 $out .= "$key: $val\r\n"; 316 } 317 return $out, $is_chunked; 318} 319 320# Returns an array of array of hashes from the block. Each element of 321# the first-level array is a request. 322# Each request is an array of the "packets" to be sent. Each packet is a 323# string to send, with an (optionnal) delay before sending it. 324# This function parses (and therefore defines the syntax) of "request*" 325# sections. See documentation for supported syntax. 326sub get_req_from_block ($) { 327 my ($block) = @_; 328 my $name = $block->name; 329 330 my @req_list = (); 331 332 if (defined $block->raw_request) { 333 334 # Should be deprecated. 335 if (ref $block->raw_request && ref $block->raw_request eq 'ARRAY') { 336 337 # User already provided an array. So, he/she specified where the 338 # data should be split. This allows for backward compatibility but 339 # should use request with arrays as it provides the same functionnality. 340 my @rr_list = (); 341 for my $elt (@{ $block->raw_request }) { 342 push @rr_list, {value => $elt}; 343 } 344 push @req_list, \@rr_list; 345 346 } else { 347 push @req_list, [{value => $block->raw_request}]; 348 } 349 350 } else { 351 my $request; 352 if (defined $block->request_eval) { 353 354 diag "$name - request_eval DEPRECATED. Use request eval instead."; 355 $request = eval $block->request_eval; 356 if ($@) { 357 warn $@; 358 } 359 360 } else { 361 $request = $block->request; 362 if (defined $request) { 363 while ($request =~ s/^\s*\#[^\n]+\s+|^\s+//gs) { 364 # do nothing 365 } 366 } 367 #warn "my req: $request"; 368 } 369 370 my $more_headers = $block->more_headers || ''; 371 372 if ( $block->pipelined_requests ) { 373 my $reqs = $block->pipelined_requests; 374 if (!ref $reqs || ref $reqs ne 'ARRAY') { 375 bail_out( 376 "$name - invalid entries in --- pipelined_requests"); 377 } 378 my $i = 0; 379 my $prq = ""; 380 for my $request (@$reqs) { 381 my $conn_type; 382 if ($i == @$reqs - 1) { 383 $conn_type = 'close'; 384 385 } else { 386 $conn_type = 'keep-alive'; 387 } 388 389 my ($hdr, $is_chunked); 390 if (ref $more_headers eq 'ARRAY') { 391 #warn "Found ", scalar @$more_headers, " entries in --- more_headers."; 392 $hdr = $more_headers->[$i]; 393 if (!defined $hdr) { 394 bail_out("--- more_headers lacks data for the $i pipelined request"); 395 } 396 ($hdr, $is_chunked) = parse_more_headers($hdr); 397 #warn "more headers: $hdr"; 398 399 } else { 400 ($hdr, $is_chunked) = parse_more_headers($more_headers); 401 } 402 403 my $r_br = build_request_from_packets($name, $hdr, 404 $is_chunked, $conn_type, 405 [$request] ); 406 $prq .= $$r_br[0]; 407 $i++; 408 } 409 push @req_list, [{value =>$prq}]; 410 411 } else { 412 my ($is_chunked, $hdr); 413 414 # request section. 415 if (!ref $request) { 416 if (ref $more_headers eq 'ARRAY') { 417 #warn "Found ", scalar @$more_headers, " entries in --- more_headers."; 418 $hdr = $more_headers->[0]; 419 if (!defined $hdr) { 420 bail_out("--- more_headers lacks data for the request"); 421 } 422 ($hdr, $is_chunked) = parse_more_headers($hdr); 423 #warn "more headers: $hdr"; 424 425 } else { 426 ($hdr, $is_chunked) = parse_more_headers($more_headers); 427 } 428 429 # One request and it is a good old string. 430 my $r_br = build_request_from_packets($name, $hdr, 431 $is_chunked, 'close', 432 [$request] ); 433 push @req_list, [{value => $$r_br[0]}]; 434 435 } elsif (ref $request eq 'ARRAY') { 436 # A bunch of requests... 437 my $i = 0; 438 for my $one_req (@$request) { 439 440 if (ref $more_headers eq 'ARRAY') { 441 #warn "Found ", scalar @$more_headers, " entries in --- more_headers."; 442 $hdr = $more_headers->[$i]; 443 if (!defined $hdr) { 444 bail_out("--- more_headers lacks data for the " 445 . "${i}th request"); 446 } 447 ($hdr, $is_chunked) = parse_more_headers($hdr); 448 #warn "more headers: $hdr"; 449 450 } else { 451 ($hdr, $is_chunked) = parse_more_headers($more_headers); 452 } 453 454 if (!ref $one_req) { 455 # This request is a good old string. 456 my $r_br = build_request_from_packets($name, $hdr, 457 $is_chunked, 'close', 458 [$one_req] ); 459 push @req_list, [{value => $$r_br[0]}]; 460 461 } elsif (ref $one_req eq 'ARRAY') { 462 # Request expressed as a serie of packets 463 my @packet_array = (); 464 for my $one_packet (@$one_req) { 465 if (!ref $one_packet) { 466 # Packet is a string. 467 push @packet_array, $one_packet; 468 } elsif (ref $one_packet eq 'HASH'){ 469 # Packet is a hash with a value... 470 push @packet_array, $one_packet->{value}; 471 } else { 472 bail_out "$name - Invalid syntax. $one_packet should be a string or hash with value."; 473 } 474 } 475 476 my $transformed_packet_array = build_request_from_packets($name, $hdr, 477 $is_chunked, 'close', 478 \@packet_array); 479 my @transformed_req = (); 480 my $idx = 0; 481 for my $one_transformed_packet (@$transformed_packet_array) { 482 if (!ref $$one_req[$idx]) { 483 push @transformed_req, {value => $one_transformed_packet}; 484 } else { 485 # Is a HASH (checked above as $one_packet) 486 $$one_req[$idx]->{value} = $one_transformed_packet; 487 push @transformed_req, $$one_req[$idx]; 488 } 489 $idx++; 490 } 491 push @req_list, \@transformed_req; 492 493 } else { 494 bail_out "$name - Invalid syntax. $one_req should be a string or an array of packets."; 495 } 496 497 $i++; 498 } 499 500 } else { 501 bail_out( 502 "$name - invalid ---request : MUST be string or array of requests"); 503 } 504 } 505 506 } 507 return \@req_list; 508} 509 510sub quote_sh_args ($) { 511 my ($args) = @_; 512 for my $arg (@$args) { 513 if ($arg =~ m{^[- "&%;,|?*.+=\w:/()]*$}) { 514 if ($arg =~ /[ "&%;,|?*()]/) { 515 $arg = "'$arg'"; 516 } 517 next; 518 } 519 $arg =~ s/\\/\\\\/g; 520 $arg =~ s/'/\\'/g; 521 $arg =~ s/\n/\\n/g; 522 $arg =~ s/\r/\\r/g; 523 $arg =~ s/\t/\\t/g; 524 $arg = "\$'$arg'"; 525 } 526 return "@$args"; 527} 528 529sub run_filter_helper($$$) { 530 my ($block, $filter, $content) = @_; 531 532 my $name = $block->name; 533 534 if (ref $filter && ref $filter eq 'CODE') { 535 $content = $filter->($content); 536 537 } elsif (!ref $filter) { 538 539 for ($filter) { 540 if ($_ eq 'md5_hex') { 541 $content = Digest::MD5::md5_hex($content); 542 } elsif ($_ eq 'sha1_hex') { 543 $content = Digest::SHA::sha1_hex($content); 544 } elsif ($_ eq 'uc') { 545 $content = uc($content); 546 } elsif ($_ eq 'lc') { 547 $content = lc($content); 548 } elsif ($_ eq 'ucfirst') { 549 $content = ucfirst($content); 550 } elsif ($_ eq 'lcfirst') { 551 $content = lcfirst($content); 552 } elsif ($_ eq 'length') { 553 $content = length($content); 554 } else { 555 bail_out("$name - unknown filter, \"$filter\", " 556 . "specified in the --- response_body_filters section"); 557 } 558 } 559 560 } else { 561 bail_out("$name - the --- response_body_filters section " 562 . "only supports subroutine reference values and string values"); 563 } 564 565 return $content; 566} 567 568sub run_test_helper ($$) { 569 my ($block, $dry_run, $repeated_req_idx) = @_; 570 571 #warn "repeated req idx: $repeated_req_idx"; 572 573 my $name = $block->name; 574 575 my $r_req_list = get_req_from_block($block); 576 577 if ( $#$r_req_list < 0 ) { 578 bail_out("$name - request empty"); 579 } 580 581 if (defined $block->curl) { 582 my $req = $r_req_list->[0]; 583 my $cmd = gen_curl_cmd_from_req($block, $req); 584 warn "# ", quote_sh_args($cmd), "\n"; 585 } 586 587 if ($CheckLeak) { 588 $dry_run = "the \"check leak\" testing mode"; 589 } 590 591 if ($Benchmark) { 592 $dry_run = "the \"benchmark\" testing mode"; 593 } 594 595 if ($Benchmark && !defined $block->no_check_leak) { 596 warn "$name\n"; 597 598 my $req = $r_req_list->[0]; 599 my ($nreqs, $concur); 600 if ($Benchmark =~ /^\s*(\d+)(?:\s+(\d+))?\s*$/) { 601 ($nreqs, $concur) = ($1, $2); 602 } 603 604 if ($BenchmarkWarmup) { 605 my $cmd = gen_ab_cmd_from_req($block, $req, $BenchmarkWarmup, $concur); 606 warn "Warming up with $BenchmarkWarmup requests...\n"; 607 system @$cmd; 608 } 609 610 my $cmd = gen_ab_cmd_from_req($block, $req, $nreqs, $concur); 611 $cmd = quote_sh_args($cmd); 612 613 warn "$cmd\n"; 614 system "unbuffer $cmd > /dev/stderr"; 615 } 616 617 if ($CheckLeak && !defined $block->no_check_leak) { 618 warn "$name\n"; 619 620 my $req = $r_req_list->[0]; 621 my $cmd = gen_ab_cmd_from_req($block, $req); 622 623 # start a sub-process to run ab or weighttp 624 my $pid = fork(); 625 if (!defined $pid) { 626 bail_out("$name - fork() failed: $!"); 627 628 } elsif ($pid == 0) { 629 # child process 630 exec @$cmd; 631 632 } else { 633 # main process 634 635 $Test::Nginx::Util::ChildPid = $pid; 636 637 sleep(1); 638 my $ngx_pid = get_pid_from_pidfile($name); 639 if ($PrevNginxPid && $ngx_pid) { 640 my $i = 0; 641 while ($ngx_pid == $PrevNginxPid) { 642 sleep 0.01; 643 $ngx_pid = get_pid_from_pidfile($name); 644 if (++$i > 1000) { 645 bail_out("nginx cannot be started"); 646 } 647 } 648 } 649 $PrevNginxPid = $ngx_pid; 650 my @rss_list; 651 for (my $i = 0; $i < $CheckLeakCount; $i++) { 652 sleep 0.02; 653 my $out = `ps -eo pid,rss|grep $ngx_pid`; 654 if ($? != 0 && !is_running($ngx_pid)) { 655 if (is_running($pid)) { 656 kill(SIGKILL, $pid); 657 waitpid($pid, 0); 658 } 659 660 my $tb = Test::More->builder; 661 $tb->no_ending(1); 662 663 Test::More::fail("$name - the nginx process $ngx_pid is gone"); 664 last; 665 } 666 667 my @lines = grep { $_->[0] eq $ngx_pid } 668 map { s/^\s+|\s+$//g; [ split /\s+/, $_ ] } 669 split /\n/, $out; 670 671 if (@lines == 0) { 672 last; 673 } 674 675 if (@lines > 1) { 676 warn "Bad ps output: \"$out\"\n"; 677 next; 678 } 679 680 my $ln = shift @lines; 681 push @rss_list, $ln->[1]; 682 } 683 684 #if ($Test::Nginx::Util::Verbose) { 685 warn "LeakTest: [@rss_list]\n"; 686 #} 687 688 if (@rss_list == 0) { 689 warn "LeakTest: k=N/A\n"; 690 691 } else { 692 my $k = get_linear_regression_slope(\@rss_list); 693 warn "LeakTest: k=$k\n"; 694 #$k = get_linear_regression_slope([1 .. 100]); 695 #warn "K = $k (1 expected)\n"; 696 #$k = get_linear_regression_slope([map { $_ * 2 } 1 .. 100]); 697 #warn "K = $k (2 expected)\n"; 698 } 699 700 if (is_running($pid)) { 701 kill(SIGKILL, $pid); 702 waitpid($pid, 0); 703 } 704 } 705 } 706 707 #warn "request: $req\n"; 708 709 my $timeout = parse_time($block->timeout); 710 if ( !defined $timeout ) { 711 $timeout = timeout(); 712 } 713 714 my $res; 715 my $req_idx = 0; 716 my ($n, $need_array); 717 718 for my $one_req (@$r_req_list) { 719 my ($raw_resp, $head_req); 720 721 if ($dry_run) { 722 $raw_resp = "200 OK HTTP/1.0\r\nContent-Length: 0\r\n\r\n"; 723 724 } else { 725 ($raw_resp, $head_req) = send_request( $one_req, $block->raw_request_middle_delay, 726 $timeout, $block ); 727 } 728 729 #warn "raw resonse: [$raw_resp]\n"; 730 731 if ($block->pipelined_requests) { 732 $n = @{ $block->pipelined_requests }; 733 $need_array = 1; 734 735 } else { 736 $need_array = $#$r_req_list > 0; 737 } 738 739again: 740 741 if ($Test::Nginx::Util::Verbose) { 742 warn "!!! resp: [$raw_resp]"; 743 } 744 745 if (!defined $raw_resp) { 746 $raw_resp = ''; 747 } 748 749 my ( $raw_headers, $left ); 750 751 if (!defined $block->ignore_response) { 752 753 if ($Test::Nginx::Util::Verbose) { 754 warn "parse response\n"; 755 } 756 757 if (defined $block->http09) { 758 $res = HTTP::Response->new(200, "OK", [], $raw_resp); 759 $raw_headers = ''; 760 761 } else { 762 ( $res, $raw_headers, $left ) = parse_response( $name, $raw_resp, $head_req ); 763 } 764 } 765 766 if (!$n) { 767 if ($left) { 768 my $name = $block->name; 769 $left =~ s/([\0-\037\200-\377])/sprintf('\x{%02x}',ord $1)/eg; 770 warn "WARNING: $name - unexpected extra bytes after last chunk in ", 771 "response: \"$left\"\n"; 772 } 773 774 } else { 775 $raw_resp = $left; 776 $n--; 777 } 778 779 if (!defined $block->ignore_response) { 780 check_error_code($block, $res, $dry_run, $req_idx, $need_array); 781 check_raw_response_headers($block, $raw_headers, $dry_run, $req_idx, $need_array); 782 check_response_headers($block, $res, $raw_headers, $dry_run, $req_idx, $need_array); 783 transform_response_body($block, $res, $req_idx); 784 check_response_body($block, $res, $dry_run, $req_idx, $repeated_req_idx, $need_array); 785 } 786 787 if ($n || $req_idx < @$r_req_list - 1) { 788 if ($block->wait) { 789 sleep($block->wait); 790 } 791 792 check_error_log($block, $res, $dry_run, $repeated_req_idx, $need_array); 793 794 if (!defined $block->ignore_response) { 795 check_access_log($block, $dry_run, $repeated_req_idx); 796 } 797 } 798 799 $req_idx++; 800 801 if ($n) { 802 goto again; 803 } 804 } 805 806 if ($block->wait) { 807 sleep($block->wait); 808 } 809 810 if ($Test::Nginx::Util::Verbose) { 811 warn "Testing stap...\n"; 812 } 813 814 test_stap($block, $dry_run); 815 816 check_error_log($block, $res, $dry_run, $repeated_req_idx, $need_array); 817 818 if (!defined $block->ignore_response) { 819 check_access_log($block, $dry_run, $repeated_req_idx); 820 } 821} 822 823 824sub test_stap ($$) { 825 my ($block, $dry_run) = @_; 826 return if !$block->{stap}; 827 828 my $name = $block->name; 829 830 my $reason; 831 832 if ($dry_run) { 833 $reason = "the lack of directive $dry_run"; 834 } 835 836 if (!$UseStap) { 837 $dry_run = 1; 838 $reason ||= "env TEST_NGINX_USE_STAP is not set"; 839 } 840 841 my $fname = stap_out_fname(); 842 843 if ($fname && ($fname eq '/dev/stdout' || $fname eq '/dev/stderr')) { 844 $dry_run = 1; 845 $reason ||= "TEST_NGINX_TAP_OUT is set to $fname"; 846 } 847 848 my $stap_out = $block->stap_out; 849 my $stap_out_like = $block->stap_out_like; 850 my $stap_out_unlike = $block->stap_out_unlike; 851 852 SKIP: { 853 skip "$name - stap_out - tests skipped due to $reason", 1 if $dry_run; 854 855 my $fh = stap_out_fh(); 856 if (!$fh) { 857 bail_out("no stap output file handle found"); 858 } 859 860 my $out = ''; 861 for (1..2) { 862 if (sleep_time() < 0.2) { 863 sleep 0.2; 864 865 } else { 866 sleep sleep_time(); 867 } 868 869 while (<$fh>) { 870 $out .= $_; 871 } 872 873 if ($out) { 874 last; 875 } 876 } 877 878 if ($Test::Nginx::Util::Verbose) { 879 warn "stap out: $out\n"; 880 } 881 882 if (defined $stap_out) { 883 if ($NoLongString) { 884 is($out, $block->stap_out, "$name - stap output expected"); 885 } else { 886 is_string($out, $block->stap_out, "$name - stap output expected"); 887 } 888 } 889 890 if (defined $stap_out_like) { 891 like($out || '', qr/$stap_out_like/sm, 892 "$name - stap output should match the pattern"); 893 } 894 895 if (defined $stap_out_unlike) { 896 unlike($out || '', qr/$stap_out_unlike/sm, 897 "$name - stap output should not match the pattern"); 898 } 899 } 900} 901 902 903# Helper function to retrieve a "check" (e.g. error_code) section. This also 904# checks that tests with arrays of requests are arrays themselves. 905sub get_indexed_value($$$$) { 906 my ($name, $value, $req_idx, $need_array) = @_; 907 if ($need_array) { 908 if (ref $value && ref $value eq 'ARRAY') { 909 return $$value[$req_idx]; 910 } 911 912 bail_out("$name - You asked for many requests, the expected results should be arrays as well."); 913 914 } else { 915 # One element but still provided as an array. 916 if (ref $value && ref $value eq 'ARRAY') { 917 if ($req_idx != 0) { 918 bail_out("$name - SHOULD NOT HAPPEN: idx != 0 and don't need array."); 919 } 920 921 return $$value[0]; 922 } 923 924 return $value; 925 } 926} 927 928sub check_error_code ($$$$$) { 929 my ($block, $res, $dry_run, $req_idx, $need_array) = @_; 930 931 my $name = $block->name; 932 SKIP: { 933 skip "$name - tests skipped due to $dry_run", 1 if $dry_run; 934 935 if ( defined $block->error_code_like ) { 936 937 my $val = get_indexed_value($name, $block->error_code_like, $req_idx, $need_array); 938 like( ($res && $res->code) || '', 939 qr/$val/sm, 940 "$name - status code ok" ); 941 942 } elsif ( defined $block->error_code ) { 943 is( ($res && $res->code) || '', 944 get_indexed_value($name, $block->error_code, $req_idx, $need_array), 945 "$name - status code ok" ); 946 947 } else { 948 is( ($res && $res->code) || '', 200, "$name - status code ok" ); 949 } 950 } 951} 952 953sub check_raw_response_headers($$$$$) { 954 my ($block, $raw_headers, $dry_run, $req_idx, $need_array) = @_; 955 my $name = $block->name; 956 if (defined $block->raw_response_headers_like) { 957 SKIP: { 958 skip "$name - raw_response_headers_like - tests skipped due to $dry_run", 1 if $dry_run; 959 my $expected = get_indexed_value($name, 960 $block->raw_response_headers_like, 961 $req_idx, 962 $need_array); 963 like $raw_headers, qr/$expected/s, "$name - raw resp headers like"; 964 } 965 } 966 967 if (defined $block->raw_response_headers_unlike) { 968 SKIP: { 969 skip "$name - raw_response_headers_unlike - tests skipped due to $dry_run", 1 if $dry_run; 970 my $expected = get_indexed_value($name, 971 $block->raw_response_headers_unlike, 972 $req_idx, 973 $need_array); 974 unlike $raw_headers, qr/$expected/s, "$name - raw resp headers unlike"; 975 } 976 } 977} 978 979sub check_response_headers($$$$$) { 980 my ($block, $res, $raw_headers, $dry_run, $req_idx, $need_array) = @_; 981 my $name = $block->name; 982 if ( defined $block->response_headers ) { 983 my $headers = parse_headers( get_indexed_value($name, 984 $block->response_headers, 985 $req_idx, 986 $need_array)); 987 while ( my ( $key, $val ) = each %$headers ) { 988 if ( !defined $val ) { 989 990 #warn "HIT"; 991 SKIP: { 992 skip "$name - response_headers - tests skipped due to $dry_run", 1 if $dry_run; 993 unlike $raw_headers, qr/^\s*\Q$key\E\s*:/ms, 994 "$name - header $key not present in the raw headers"; 995 } 996 next; 997 } 998 999 $val =~ s/\$ServerPort\b/$ServerPort/g; 1000 $val =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; 1001 1002 my $actual_val = $res ? $res->header($key) : undef; 1003 if ( !defined $actual_val ) { 1004 $actual_val = ''; 1005 } 1006 1007 SKIP: { 1008 skip "$name - response_headers - tests skipped due to $dry_run", 1 if $dry_run; 1009 is $actual_val, $val, "$name - header $key ok"; 1010 } 1011 } 1012 } 1013 elsif ( defined $block->response_headers_like ) { 1014 my $headers = parse_headers( get_indexed_value($name, 1015 $block->response_headers_like, 1016 $req_idx, 1017 $need_array) ); 1018 while ( my ( $key, $val ) = each %$headers ) { 1019 my $expected_val = $res->header($key); 1020 if ( !defined $expected_val ) { 1021 $expected_val = ''; 1022 } 1023 SKIP: { 1024 skip "$name - response_headers_like - tests skipped due to $dry_run", 1 if $dry_run; 1025 like $expected_val, qr/^$val$/, "$name - header $key like ok"; 1026 } 1027 } 1028 } 1029} 1030 1031sub value_contains ($$) { 1032 my ($val, $pat) = @_; 1033 1034 if (!ref $val || ref $val eq 'Regexp') { 1035 return $val =~ /\Q$pat\E/; 1036 } 1037 1038 if (ref $val eq 'ARRAY') { 1039 for my $v (@$val) { 1040 if (value_contains($v, $pat)) { 1041 return 1; 1042 } 1043 } 1044 } 1045 1046 return undef; 1047} 1048 1049sub check_access_log ($$$) { 1050 my ($block, $dry_run, $repeated_req_idx) = @_; 1051 my $name = $block->name; 1052 my $lines; 1053 1054 if (defined $block->access_log) { 1055 my $pats = $block->access_log; 1056 1057 if (!ref $pats) { 1058 chomp $pats; 1059 my @lines = split /\n+/, $pats; 1060 $pats = \@lines; 1061 1062 } elsif (ref $pats eq 'Regexp') { 1063 $pats = [$pats]; 1064 1065 } else { 1066 my @clone = @$pats; 1067 $pats = \@clone; 1068 } 1069 1070 $lines ||= access_log_data(); 1071 for my $line (@$lines) { 1072 for my $pat (@$pats) { 1073 next if !defined $pat; 1074 if (ref $pat && $line =~ /$pat/ || $line =~ /\Q$pat\E/) { 1075 SKIP: { 1076 skip "$name - access_log - tests skipped due to $dry_run", 1 if $dry_run; 1077 pass("$name - pattern \"$pat\" matches a line in access.log (req $repeated_req_idx)"); 1078 } 1079 undef $pat; 1080 } 1081 } 1082 } 1083 1084 for my $pat (@$pats) { 1085 if (defined $pat) { 1086 SKIP: { 1087 skip "$name - access_log - tests skipped due to $dry_run", 1 if $dry_run; 1088 fail("$name - pattern \"$pat\" should match a line in access.log (req $repeated_req_idx)"); 1089 #die join("", @$lines); 1090 } 1091 } 1092 } 1093 } 1094} 1095 1096sub check_error_log ($$$$) { 1097 my ($block, $res, $dry_run, $repeated_req_idx, $need_array) = @_; 1098 my $name = $block->name; 1099 my $lines; 1100 1101 my $check_write_guard_message = 1; 1102 my $check_alert_message = 1; 1103 my $check_crit_message = 1; 1104 my $check_emerg_message = 1; 1105 1106 my $grep_pat; 1107 my $grep_pats = $block->grep_error_log; 1108 if (defined $grep_pats) { 1109 if (ref $grep_pats && ref $grep_pats eq 'ARRAY') { 1110 $grep_pat = $grep_pats->[$repeated_req_idx]; 1111 1112 } else { 1113 $grep_pat = $grep_pats; 1114 } 1115 } 1116 1117 if (defined $grep_pat) { 1118 my $expected = $block->grep_error_log_out; 1119 if (!defined $expected) { 1120 bail_out("$name - No --- grep_error_log_out defined but --- grep_error_log is defined"); 1121 } 1122 1123 #warn "ref grep error log: ", ref $expected; 1124 1125 if (ref $expected && ref $expected eq 'ARRAY') { 1126 #warn "grep error log out is an ARRAY"; 1127 $expected = $expected->[$repeated_req_idx]; 1128 } 1129 1130 SKIP: { 1131 skip "$name - error_log - tests skipped due to $dry_run", 1 if $dry_run; 1132 1133 $lines ||= error_log_data(); 1134 1135 my $matched_lines = ''; 1136 for my $line (@$lines) { 1137 if (ref $grep_pat && $line =~ /$grep_pat/ || $line =~ /\Q$grep_pat\E/) { 1138 my $matched = $&; 1139 if ($matched !~ /\n/) { 1140 $matched_lines .= $matched . "\n"; 1141 } 1142 } 1143 } 1144 1145 if (ref $expected eq 'Regexp') { 1146 like($matched_lines, $expected, "$name - grep_error_log_out (req $repeated_req_idx)"); 1147 1148 } else { 1149 if ($NoLongString) { 1150 is($matched_lines, $expected, 1151 "$name - grep_error_log_out (req $repeated_req_idx)" ); 1152 } else { 1153 is_string($matched_lines, $expected, 1154 "$name - grep_error_log_out (req $repeated_req_idx)"); 1155 } 1156 } 1157 } 1158 } 1159 1160 if (defined $block->error_log) { 1161 my $pats = $block->error_log; 1162 1163 if (value_contains($pats, 1164 "writing a global lua variable")) 1165 { 1166 undef $check_write_guard_message; 1167 } 1168 1169 if (value_contains($pats, "[alert")) { 1170 undef $check_alert_message; 1171 } 1172 1173 if (value_contains($pats, "[crit")) { 1174 undef $check_crit_message; 1175 } 1176 1177 if (value_contains($pats, "[emerg")) { 1178 undef $check_emerg_message; 1179 } 1180 1181 if (!ref $pats) { 1182 chomp $pats; 1183 my @lines = split /\n+/, $pats; 1184 $pats = \@lines; 1185 1186 } elsif (ref $pats eq 'Regexp') { 1187 $pats = [$pats]; 1188 1189 } else { 1190 my @clone = @$pats; 1191 $pats = \@clone; 1192 } 1193 1194 $lines ||= error_log_data(); 1195 #warn "error log data: ", join "\n", @$lines; 1196 for my $line (@$lines) { 1197 for my $pat (@$pats) { 1198 next if !defined $pat; 1199 if (ref $pat && $line =~ /$pat/ || $line =~ /\Q$pat\E/) { 1200 SKIP: { 1201 skip "$name - error_log - tests skipped due to $dry_run", 1 if $dry_run; 1202 pass("$name - pattern \"$pat\" matches a line in error.log (req $repeated_req_idx)"); 1203 } 1204 undef $pat; 1205 } 1206 } 1207 } 1208 1209 for my $pat (@$pats) { 1210 if (defined $pat) { 1211 SKIP: { 1212 skip "$name - error_log - tests skipped due to $dry_run", 1 if $dry_run; 1213 fail("$name - pattern \"$pat\" should match a line in error.log (req $repeated_req_idx)"); 1214 #die join("", @$lines); 1215 } 1216 } 1217 } 1218 } 1219 1220 if (defined $block->no_error_log) { 1221 #warn "HERE"; 1222 my $pats = $block->no_error_log; 1223 1224 if (value_contains($pats, 1225 "writing a global lua variable")) 1226 { 1227 undef $check_write_guard_message; 1228 } 1229 1230 if (value_contains($pats, "[alert")) { 1231 undef $check_alert_message; 1232 } 1233 1234 if (value_contains($pats, "[crit")) { 1235 undef $check_crit_message; 1236 } 1237 1238 if (value_contains($pats, "[emerg")) { 1239 undef $check_emerg_message; 1240 } 1241 1242 if (!ref $pats) { 1243 chomp $pats; 1244 my @lines = split /\n+/, $pats; 1245 $pats = \@lines; 1246 1247 } elsif (ref $pats eq 'Regexp') { 1248 $pats = [$pats]; 1249 1250 } else { 1251 my @clone = @$pats; 1252 $pats = \@clone; 1253 } 1254 1255 my %found; 1256 $lines ||= error_log_data(); 1257 my $i = 0; 1258 for my $line (@$lines) { 1259 for my $pat (@$pats) { 1260 next if !defined $pat; 1261 #warn "test $pat\n"; 1262 if ((ref $pat && $line =~ /$pat/) || $line =~ /\Q$pat\E/) { 1263 if ($found{$pat}) { 1264 my $tb = Test::More->builder; 1265 $tb->no_ending(1); 1266 1267 } else { 1268 $found{$pat} = 1; 1269 } 1270 1271 SKIP: { 1272 skip "$name - no_error_log - tests skipped due to $dry_run ($line)", 1 if $dry_run; 1273 my $ln = fmt_str($line); 1274 my $p = fmt_str($pat); 1275 my @more_lines; 1276 for (my $j = $i + 1; $j < min($i + 10, @$lines - 1); $j++) { 1277 push @more_lines, $lines->[$j]; 1278 } 1279 1280 fail("$name - pattern \"$p\" should not match any line in error.log but matches line \"$ln\" (req $repeated_req_idx)\n" 1281 . join "", @more_lines); 1282 } 1283 } 1284 } 1285 1286 } continue { 1287 $i++; 1288 } 1289 1290 for my $pat (@$pats) { 1291 next if $found{$pat}; 1292 if (defined $pat) { 1293 SKIP: { 1294 skip "$name - no_error_log - tests skipped due to $dry_run", 1 if $dry_run; 1295 my $p = fmt_str($pat); 1296 pass("$name - pattern \"$p\" does not match a line in error.log (req $repeated_req_idx)"); 1297 } 1298 } 1299 } 1300 } 1301 1302 if ($check_write_guard_message && !$dry_run) { 1303 $lines ||= error_log_data(); 1304 for my $line (@$lines) { 1305 #warn "test $pat\n"; 1306 if ($line =~ /writing a global lua variable/) { 1307 my $ln = fmt_str($line); 1308 warn("WARNING: $name - $ln\n"); 1309 } 1310 } 1311 } 1312 1313 if ($check_alert_message && !$dry_run) { 1314 $lines ||= error_log_data(); 1315 for my $line (@$lines) { 1316 #warn "test $pat\n"; 1317 if ($line =~ /\[alert\]/) { 1318 my $ln = fmt_str($line); 1319 warn("WARNING: $name - $ln\n"); 1320 } 1321 } 1322 } 1323 1324 if ($check_crit_message && !$dry_run) { 1325 $lines ||= error_log_data(); 1326 for my $line (@$lines) { 1327 #warn "test $pat\n"; 1328 if ($line =~ /\[crit\]/) { 1329 my $ln = fmt_str($line); 1330 warn("WARNING: $name - $ln\n"); 1331 } 1332 } 1333 } 1334 1335 if ($check_emerg_message && !$dry_run) { 1336 $lines ||= error_log_data(); 1337 for my $line (@$lines) { 1338 #warn "test $pat\n"; 1339 if ($line =~ /\[emerg\]/) { 1340 my $ln = fmt_str($line); 1341 warn("WARNING: $name - $ln"); 1342 } 1343 } 1344 } 1345 1346 for my $line (@$lines) { 1347 #warn "test $pat\n"; 1348 if ($line =~ /\bAssertion .*?failed\b/) { 1349 my $tb = Test::More->builder; 1350 $tb->no_ending(1); 1351 1352 chomp $line; 1353 fail("$name - $line\n"); 1354 } 1355 } 1356} 1357 1358sub check_shutdown_error_log ($$) { 1359 my ($block, $dry_run) = @_; 1360 my $name = $block->name; 1361 my $lines; 1362 1363 my $pats = $block->shutdown_error_log; 1364 1365 if (!ref $pats) { 1366 chomp $pats; 1367 my @lines = split /\n+/, $pats; 1368 $pats = \@lines; 1369 1370 } elsif (ref $pats eq 'Regexp') { 1371 $pats = [$pats]; 1372 1373 } else { 1374 my @clone = @$pats; 1375 $pats = \@clone; 1376 } 1377 1378 if (defined $block->no_shutdown_error_log) { 1379 # warn "HERE"; 1380 my $pats = $block->no_shutdown_error_log; 1381 1382 if (!ref $pats) { 1383 chomp $pats; 1384 my @lines = split /\n+/, $pats; 1385 $pats = \@lines; 1386 1387 } elsif (ref $pats eq 'Regexp') { 1388 $pats = [$pats]; 1389 1390 } else { 1391 my @clone = @$pats; 1392 $pats = \@clone; 1393 } 1394 1395 my %found; 1396 $lines ||= error_log_data(); 1397 # warn "error log data: ", join "\n", @$lines; 1398 for my $line (@$lines) { 1399 for my $pat (@$pats) { 1400 next if !defined $pat; 1401 #warn "test $pat\n"; 1402 if ((ref $pat && $line =~ /$pat/) || $line =~ /\Q$pat\E/) { 1403 if ($found{$pat}) { 1404 my $tb = Test::More->builder; 1405 $tb->no_ending(1); 1406 1407 } else { 1408 $found{$pat} = 1; 1409 } 1410 1411 SKIP: { 1412 skip "$name - no_shutdown_error_log - tests skipped due to $dry_run ($line)", 1 if $dry_run; 1413 my $ln = fmt_str($line); 1414 my $p = fmt_str($pat); 1415 fail("$name - pattern \"$p\" should not match any line in error.log but matches line \"$ln\""); 1416 } 1417 } 1418 } 1419 } 1420 1421 for my $pat (@$pats) { 1422 next if $found{$pat}; 1423 if (defined $pat) { 1424 SKIP: { 1425 skip "$name - no_shutdown_error_log - tests skipped due to $dry_run", 1 if $dry_run; 1426 my $p = fmt_str($pat); 1427 pass("$name - pattern \"$p\" does not match a line in error.log"); 1428 } 1429 } 1430 } 1431 } 1432 1433 $lines ||= error_log_data(); 1434 #warn "error log data: ", join "\n", @$lines; 1435 for my $line (@$lines) { 1436 for my $pat (@$pats) { 1437 next if !defined $pat; 1438 1439 if (ref $pat && $line =~ /$pat/ || $line =~ /\Q$pat\E/) { 1440 SKIP: { 1441 skip "$name - shutdown_error_log - tests skipped due to dry_run", 1 if $dry_run; 1442 pass("$name - pattern \"$pat\" matches a line in error.log"); 1443 } 1444 undef $pat; 1445 } 1446 } 1447 } 1448 1449 for my $pat (@$pats) { 1450 if (defined $pat) { 1451 SKIP: { 1452 skip "$name - shutdown_error_log - tests skipped due to dry_run", 1 if $dry_run; 1453 fail("$name - pattern \"$pat\" should match a line in error.log"); 1454 #die join("", @$lines); 1455 } 1456 } 1457 } 1458 1459 for my $line (@$lines) { 1460 #warn "test $line\n"; 1461 if ($line =~ /\bAssertion .*? failed\.$/) { 1462 my $tb = Test::More->builder; 1463 $tb->no_ending(1); 1464 1465 chomp $line; 1466 fail("$name - $line"); 1467 } 1468 } 1469} 1470 1471sub fmt_str ($) { 1472 my $str = shift; 1473 chomp $str; 1474 $str =~ s/"/\\"/g; 1475 $str =~ s/\r/\\r/g; 1476 $str =~ s/\n/\\n/g; 1477 $str; 1478} 1479 1480sub transform_response_body ($$$) { 1481 my ($block, $res, $req_idx) = @_; 1482 1483 return unless defined $res; 1484 1485 my $content = $res->content; 1486 return unless defined $content; 1487 1488 my $is_2d_array = 0; 1489 my $name = $block->name; 1490 my $response_body_filters = $block->response_body_filters; 1491 1492 if (defined $response_body_filters) { 1493 1494 if (!ref $response_body_filters) { 1495 $response_body_filters =~ s/^\s+|\s+$//gs; 1496 $response_body_filters = [split /\s+/, $response_body_filters]; 1497 1498 } elsif (ref $response_body_filters ne 'ARRAY') { 1499 $response_body_filters = [$response_body_filters]; 1500 } 1501 1502 if (ref $response_body_filters eq 'ARRAY') { 1503 1504 if (ref $response_body_filters->[0] eq 'ARRAY') { 1505 $is_2d_array = 1; 1506 1507 for my $elem (@$response_body_filters) { 1508 if (ref $elem ne "ARRAY") { 1509 bail_out("$name - the --- response_body_filters two-dimensional array " 1510 . "only be like [[uc], [lc]] not [[uc], lc]"); 1511 } 1512 } 1513 } 1514 } 1515 1516 my $new = $content; 1517 my $filter = $response_body_filters; 1518 1519 if ($is_2d_array) { 1520 $filter = $response_body_filters->[$req_idx]; 1521 1522 bail_out("$name - the ---response_body_filters two-dimensional array " 1523 . "unmatch the specified request($req_idx)") unless defined $filter; 1524 } 1525 1526 if (ref $filter && ref $filter eq 'ARRAY') { 1527 1528 for my $f (@$filter) { 1529 $new = run_filter_helper($block, $f, $new); 1530 } 1531 1532 } else { 1533 $new = run_filter_helper($block, $filter, $new); 1534 } 1535 1536 $res->content($new); 1537 } 1538 1539} 1540 1541sub check_response_body ($$$$$$) { 1542 my ($block, $res, $dry_run, $req_idx, $repeated_req_idx, $need_array) = @_; 1543 my $name = $block->name; 1544 if ( defined $block->response_body 1545 || defined $block->response_body_eval ) 1546 { 1547 my $content = $res ? $res->content : undef; 1548 if ( defined $content ) { 1549 $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; 1550 $content =~ s/^Connection: TE, close\r\n//gms; 1551 } 1552 1553 my $expected; 1554 if ( $block->response_body_eval ) { 1555 diag "$name - response_body_eval is DEPRECATED. Use response_body eval instead."; 1556 $expected = eval get_indexed_value($name, 1557 $block->response_body_eval, 1558 $req_idx, 1559 $need_array); 1560 if ($@) { 1561 warn $@; 1562 } 1563 } 1564 else { 1565 $expected = get_indexed_value($name, 1566 $block->response_body, 1567 $req_idx, 1568 $need_array); 1569 } 1570 1571 if ( $block->charset ) { 1572 Encode::from_to( $expected, 'UTF-8', $block->charset ); 1573 } 1574 1575 unless (!defined $expected || ref $expected) { 1576 $expected =~ s/\$ServerPort\b/$ServerPort/g; 1577 $expected =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; 1578 } 1579 1580 #warn show_all_chars($content); 1581 1582 #warn "no long string: $NoLongString"; 1583 SKIP: { 1584 skip "$name - response_body - tests skipped due to $dry_run", 1 if $dry_run; 1585 if (ref $expected) { 1586 like $content, $expected, "$name - response_body - like (repeated req $repeated_req_idx, req $req_idx)"; 1587 1588 } else { 1589 if ($NoLongString) { 1590 is( $content, $expected, 1591 "$name - response_body - response is expected (repeated req $repeated_req_idx, req $req_idx)" ); 1592 } 1593 else { 1594 is_string( $content, $expected, 1595 "$name - response_body - response is expected (repeated req $repeated_req_idx, req $req_idx)" ); 1596 } 1597 } 1598 } 1599 1600 } elsif (defined $block->response_body_like 1601 || defined $block->response_body_unlike) 1602 { 1603 my $patterns; 1604 my $type; 1605 my $cmp; 1606 if (defined $block->response_body_like) { 1607 $patterns = $block->response_body_like; 1608 $type = "like"; 1609 $cmp = \&like; 1610 1611 } else { 1612 $patterns = $block->response_body_unlike; 1613 $type = "unlike"; 1614 $cmp = \&unlike; 1615 } 1616 1617 my $content = $res ? $res->content : undef; 1618 if ( defined $content ) { 1619 $content =~ s/^TE: deflate,gzip;q=0\.3\r\n//gms; 1620 $content =~ s/^Connection: TE, close\r\n//gms; 1621 } 1622 my $expected_pat = get_indexed_value($name, 1623 $patterns, 1624 $req_idx, 1625 $need_array); 1626 $expected_pat =~ s/\$ServerPort\b/$ServerPort/g; 1627 $expected_pat =~ s/\$ServerPortForClient\b/$ServerPortForClient/g; 1628 my $summary = trim($content); 1629 if (!defined $summary) { 1630 $summary = ""; 1631 } 1632 1633 SKIP: { 1634 skip "$name - response_body_$type - tests skipped due to $dry_run", 1 if $dry_run; 1635 $cmp->( $content, qr/$expected_pat/s, 1636 "$name - response_body_$type - response is expected ($summary)" 1637 ); 1638 } 1639 } 1640 1641 for my $check (@ResponseBodyChecks) { 1642 $check->($block, $res->content, $req_idx, $repeated_req_idx, $dry_run); 1643 } 1644} 1645 1646sub parse_response($$$) { 1647 my ( $name, $raw_resp, $head_req ) = @_; 1648 1649 my $left; 1650 1651 my $raw_headers = ''; 1652 if ( $raw_resp =~ /(.*?\r\n)\r\n/s ) { 1653 1654 #warn "\$1: $1"; 1655 $raw_headers = $1; 1656 } 1657 1658 #warn "raw headers: $raw_headers\n"; 1659 1660 my $res = HTTP::Response->parse($raw_resp); 1661 1662 my $code = $res->code; 1663 1664 my $enc = $res->header('Transfer-Encoding'); 1665 my $len = $res->header('Content-Length'); 1666 1667 if ($code && $code !~ /^\d+$/) { 1668 undef $code; 1669 $res->code(undef); 1670 } 1671 1672 if ($code && ($code == 304 || $code == 101)) { 1673 return $res, $raw_headers 1674 } 1675 1676 if ( defined $enc && $enc eq 'chunked' ) { 1677 1678 #warn "Found chunked!"; 1679 my $raw = $res->content; 1680 if ( !defined $raw ) { 1681 $raw = ''; 1682 } 1683 1684 my $decoded = ''; 1685 while (1) { 1686 if ( $raw =~ /\G 0 [\ \t]* \r\n \r\n /gcsx ) { 1687 if ( $raw =~ /\G (.+) /gcsx ) { 1688 $left = $1; 1689 } 1690 1691 last; 1692 } 1693 1694 if ( $raw =~ m{ \G [\ \t]* ( [A-Fa-f0-9]+ ) [\ \t]* \r\n }gcsx ) { 1695 my $rest = hex($1); 1696 1697 #warn "chunk size: $rest\n"; 1698 my $bit_sz = 32765; 1699 while ( $rest > 0 ) { 1700 my $bit = $rest < $bit_sz ? $rest : $bit_sz; 1701 1702 #warn "bit: $bit\n"; 1703 if ( $raw =~ /\G(.{$bit})/gcs ) { 1704 $decoded .= $1; 1705 1706 #warn "decoded: [$1]\n"; 1707 1708 } else { 1709 my $tb = Test::More->builder; 1710 $tb->no_ending(1); 1711 1712 fail("$name - invalid chunked data received " 1713 ."(not enought octets for the data section)" 1714 ); 1715 return; 1716 } 1717 1718 $rest -= $bit; 1719 } 1720 1721 if ( $raw !~ /\G\r\n/gcs ) { 1722 my $tb = Test::More->builder; 1723 $tb->no_ending(1); 1724 1725 fail( 1726 "$name - invalid chunked data received (expected CRLF)." 1727 ); 1728 return; 1729 } 1730 1731 } elsif ( $raw =~ /\G.+/gcs ) { 1732 my $tb = Test::More->builder; 1733 $tb->no_ending(1); 1734 1735 fail "$name - invalid chunked body received: $&"; 1736 return; 1737 1738 } else { 1739 my $tb = Test::More->builder; 1740 $tb->no_ending(1); 1741 1742 fail "$name - no last chunk found - $raw"; 1743 return; 1744 } 1745 } 1746 1747 #warn "decoded: $decoded\n"; 1748 $res->content($decoded); 1749 1750 } elsif (defined $len && $len ne '' && $len >= 0) { 1751 my $raw = $res->content; 1752 if (length $raw < $len) { 1753 if (!$head_req) { 1754 warn "WARNING: $name - response body truncated: ", 1755 "$len expected, but got ", length $raw, "\n"; 1756 } 1757 1758 } elsif (length $raw > $len) { 1759 my $content = substr $raw, 0, $len; 1760 $left = substr $raw, $len; 1761 $res->content($content); 1762 #warn "parsed body: [", $res->content, "]\n"; 1763 } 1764 } 1765 1766 return ( $res, $raw_headers, $left ); 1767} 1768 1769sub send_http2_req ($$$) { 1770 my ($block, $req, $timeout) = @_; 1771 1772 my $name = $block->name; 1773 1774 my $cmd = gen_curl_cmd_from_req($block, $req); 1775 1776 if ($Test::Nginx::Util::Verbose) { 1777 warn "running cmd @$cmd"; 1778 } 1779 1780 my $ok = IPC::Run::run($cmd, \(my $in), \(my $out), \(my $err), 1781 IPC::Run::timeout($timeout)); 1782 1783 if (!defined $ok) { 1784 fail "failed to run curl: $?: " . ($err // ''); 1785 return; 1786 } 1787 1788 if (!$out) { 1789 if ($err) { 1790 fail "$name - command \"@$cmd\" generates stderr output: $err"; 1791 return; 1792 } 1793 1794 fail "$name - curl command \"@$cmd\" generates no stdout output"; 1795 return; 1796 } 1797 1798 if ($err) { 1799 warn "WARNING: $name - command \"@$cmd\" generates stderr output: $err"; 1800 } 1801 1802 return $out; 1803} 1804 1805sub send_request ($$$$@) { 1806 my ( $req, $middle_delay, $timeout, $block, $tries ) = @_; 1807 1808 my $name = $block->name; 1809 1810 #warn "connecting...\n"; 1811 1812 my $server_addr = $block->server_addr_for_client; 1813 1814 if (!defined $server_addr) { 1815 $server_addr = $ServerAddr; 1816 } 1817 1818 my $sock = IO::Socket::INET->new( 1819 PeerAddr => $server_addr, 1820 PeerPort => $ServerPortForClient, 1821 Proto => 'tcp', 1822 #ReuseAddr => 1, 1823 #ReusePort => 1, 1824 Blocking => 0, 1825 Timeout => $timeout, 1826 ); 1827 1828 if (!defined $sock) { 1829 $tries ||= 1; 1830 my $total_tries = $TotalConnectingTimeouts ? 20 : 50; 1831 if ($tries <= $total_tries) { 1832 my $wait = (sleep_time() + sleep_time() * $tries) * $tries / 2; 1833 if ($wait >= 1) { 1834 $wait = 1; 1835 } 1836 1837 if (defined $Test::Nginx::Util::ChildPid) { 1838 my $errcode = $!; 1839 if (waitpid($Test::Nginx::Util::ChildPid, WNOHANG) == -1) { 1840 warn "WARNING: Child process $Test::Nginx::Util::ChildPid is already gone.\n"; 1841 warn `tail -n20 $Test::Nginx::Util::ErrLogFile`; 1842 1843 my $tb = Test::More->builder; 1844 $tb->no_ending(1); 1845 1846 fail("$name - Can't connect to $server_addr:$ServerPortForClient: $errcode (aborted)\n"); 1847 return; 1848 } 1849 } 1850 1851 if ($wait >= 0.6) { 1852 warn "$name - Can't connect to $server_addr:$ServerPortForClient: $!\n"; 1853 if ($tries + 1 <= $total_tries) { 1854 warn "\tRetry connecting after $wait sec\n"; 1855 } 1856 } 1857 1858 sleep $wait; 1859 1860 #warn "sending request"; 1861 return send_request($req, $middle_delay, $timeout, $block, $tries + 1); 1862 1863 } 1864 1865 my $msg = "$name - Can't connect to $server_addr:$ServerPortForClient: $! (aborted)\n"; 1866 if (++$TotalConnectingTimeouts < 3) { 1867 my $tb = Test::More->builder; 1868 $tb->no_ending(1); 1869 fail($msg); 1870 1871 } else { 1872 bail_out($msg); 1873 } 1874 1875 return; 1876 } 1877 1878 #warn "connected"; 1879 1880 my @req_bits = ref $req ? @$req : ($req); 1881 1882 my $head_req = 0; 1883 { 1884 my $req = join '', map { $_->{value} } @req_bits; 1885 #warn "Request: $req\n"; 1886 if ($req =~ /^\s*HEAD\s+/) { 1887 #warn "Found HEAD request!\n"; 1888 $head_req = 1; 1889 } 1890 } 1891 1892 if (use_http2($block)) { 1893 return send_http2_req($block, $req, $timeout), $head_req; 1894 } 1895 1896 #my $flags = fcntl $sock, F_GETFL, 0 1897 #or die "Failed to get flags: $!\n"; 1898 1899 #fcntl $sock, F_SETFL, $flags | O_NONBLOCK 1900 #or die "Failed to set flags: $!\n"; 1901 1902 my $ctx = { 1903 resp => '', 1904 write_offset => 0, 1905 buf_size => 1024, 1906 req_bits => \@req_bits, 1907 write_buf => (shift @req_bits)->{"value"}, 1908 middle_delay => $middle_delay, 1909 sock => $sock, 1910 name => $name, 1911 block => $block, 1912 }; 1913 1914 my $readable_hdls = IO::Select->new($sock); 1915 my $writable_hdls = IO::Select->new($sock); 1916 my $err_hdls = IO::Select->new($sock); 1917 1918 while (1) { 1919 if ( $readable_hdls->count == 0 1920 && $writable_hdls->count == 0 1921 && $err_hdls->count == 0 ) 1922 { 1923 last; 1924 } 1925 1926 #warn "doing select...\n"; 1927 1928 my ($new_readable, $new_writable, $new_err) = 1929 IO::Select->select($readable_hdls, $writable_hdls, $err_hdls, 1930 $timeout); 1931 1932 if (!defined $new_err 1933 && !defined $new_readable 1934 && !defined $new_writable) 1935 { 1936 1937 # timed out 1938 timeout_event_handler($ctx); 1939 last; 1940 } 1941 1942 for my $hdl (@$new_err) { 1943 next if !defined $hdl; 1944 1945 error_event_handler($ctx); 1946 1947 if ( $err_hdls->exists($hdl) ) { 1948 $err_hdls->remove($hdl); 1949 } 1950 1951 if ( $readable_hdls->exists($hdl) ) { 1952 $readable_hdls->remove($hdl); 1953 } 1954 1955 if ( $writable_hdls->exists($hdl) ) { 1956 $writable_hdls->remove($hdl); 1957 } 1958 1959 for my $h (@$readable_hdls) { 1960 next if !defined $h; 1961 if ( $h eq $hdl ) { 1962 undef $h; 1963 last; 1964 } 1965 } 1966 1967 for my $h (@$writable_hdls) { 1968 next if !defined $h; 1969 if ( $h eq $hdl ) { 1970 undef $h; 1971 last; 1972 } 1973 } 1974 1975 close $hdl; 1976 } 1977 1978 for my $hdl (@$new_readable) { 1979 next if !defined $hdl; 1980 1981 my $res = read_event_handler($ctx); 1982 if ( !$res ) { 1983 1984 # error occured 1985 if ( $err_hdls->exists($hdl) ) { 1986 $err_hdls->remove($hdl); 1987 } 1988 1989 if ( $readable_hdls->exists($hdl) ) { 1990 $readable_hdls->remove($hdl); 1991 } 1992 1993 if ( $writable_hdls->exists($hdl) ) { 1994 $writable_hdls->remove($hdl); 1995 } 1996 1997 for my $h (@$writable_hdls) { 1998 next if !defined $h; 1999 if ( $h eq $hdl ) { 2000 undef $h; 2001 last; 2002 } 2003 } 2004 2005 close $hdl; 2006 } 2007 } 2008 2009 for my $hdl (@$new_writable) { 2010 next if !defined $hdl; 2011 2012 my $res = write_event_handler($ctx); 2013 if ( !$res ) { 2014 2015 # error occured 2016 if ( $err_hdls->exists($hdl) ) { 2017 $err_hdls->remove($hdl); 2018 } 2019 2020 if ( $readable_hdls->exists($hdl) ) { 2021 $readable_hdls->remove($hdl); 2022 } 2023 2024 if ( $writable_hdls->exists($hdl) ) { 2025 $writable_hdls->remove($hdl); 2026 } 2027 2028 close $hdl; 2029 2030 } elsif ( $res == 2 ) { 2031 # all data has been written 2032 2033 my $shutdown = $block->shutdown; 2034 if (defined $shutdown) { 2035 if ($shutdown =~ /^$/s) { 2036 $shutdown = 1; 2037 } 2038 2039 #warn "shutting down with $shutdown"; 2040 shutdown($sock, $shutdown); 2041 } 2042 2043 if ( $writable_hdls->exists($hdl) ) { 2044 $writable_hdls->remove($hdl); 2045 } 2046 } 2047 } 2048 } 2049 2050 return ($ctx->{resp}, $head_req); 2051} 2052 2053sub timeout_event_handler ($) { 2054 my $ctx = shift; 2055 2056 close($ctx->{sock}); 2057 2058 if (!defined $ctx->{block}->abort) { 2059 my $tb = Test::More->builder; 2060 $tb->no_ending(1); 2061 2062 fail("ERROR: client socket timed out - $ctx->{name}\n"); 2063 2064 } else { 2065 sleep 0.005; 2066 } 2067} 2068 2069sub error_event_handler ($) { 2070 warn "exception occurs on the socket: $!\n"; 2071} 2072 2073sub write_event_handler ($) { 2074 my ($ctx) = @_; 2075 2076 while (1) { 2077 return undef if !defined $ctx->{write_buf}; 2078 2079 my $rest = length( $ctx->{write_buf} ) - $ctx->{write_offset}; 2080 2081 #warn "offset: $write_offset, rest: $rest, length ", length($write_buf), "\n"; 2082 #die; 2083 2084 if ( $rest > 0 ) { 2085 my $bytes; 2086 eval { 2087 $bytes = syswrite( 2088 $ctx->{sock}, $ctx->{write_buf}, 2089 $rest, $ctx->{write_offset} 2090 ); 2091 }; 2092 2093 if ($@) { 2094 my $errmsg = "write failed: $@"; 2095 warn "$errmsg\n"; 2096 $ctx->{resp} = $errmsg; 2097 return undef; 2098 } 2099 2100 if ( !defined $bytes ) { 2101 if ( $! == EAGAIN ) { 2102 2103 #warn "write again..."; 2104 #sleep 0.002; 2105 return 1; 2106 } 2107 my $errmsg = "write failed: $!"; 2108 warn "$errmsg\n"; 2109 if ( !$ctx->{resp} ) { 2110 $ctx->{resp} = "$errmsg"; 2111 } 2112 return undef; 2113 } 2114 2115 #warn "wrote $bytes bytes.\n"; 2116 $ctx->{write_offset} += $bytes; 2117 2118 } else { 2119 # $rest == 0 2120 2121 my $next_send = shift @{ $ctx->{req_bits} }; 2122 2123 if (!defined $next_send) { 2124 return 2; 2125 } 2126 2127 $ctx->{write_buf} = $next_send->{'value'}; 2128 $ctx->{write_offset} = 0; 2129 2130 my $wait_time; 2131 2132 if (!defined $next_send->{'delay_before'}) { 2133 if (defined $ctx->{middle_delay}) { 2134 $wait_time = $ctx->{middle_delay}; 2135 } 2136 2137 } else { 2138 $wait_time = $next_send->{'delay_before'}; 2139 } 2140 2141 if ($wait_time) { 2142 #warn "sleeping.."; 2143 sleep $wait_time; 2144 } 2145 } 2146 } 2147 2148 # impossible to reach here... 2149 return undef; 2150} 2151 2152sub read_event_handler ($) { 2153 my ($ctx) = @_; 2154 while (1) { 2155 my $read_buf; 2156 my $bytes = sysread( $ctx->{sock}, $read_buf, $ctx->{buf_size} ); 2157 2158 if ( !defined $bytes ) { 2159 if ( $! == EAGAIN ) { 2160 2161 #warn "read again..."; 2162 #sleep 0.002; 2163 return 1; 2164 } 2165 warn "WARNING: $ctx->{name} - HTTP response read failure: $!"; 2166 return undef; 2167 } 2168 2169 if ( $bytes == 0 ) { 2170 return undef; # connection closed 2171 } 2172 2173 $ctx->{resp} .= $read_buf; 2174 2175 #warn "read $bytes ($read_buf) bytes.\n"; 2176 } 2177 2178 # impossible to reach here... 2179 return undef; 2180} 2181 2182sub gen_curl_cmd_from_req ($$) { 2183 my ($block, $req) = @_; 2184 2185 my $name = $block->name; 2186 2187 $req = join '', map { $_->{value} } @$req; 2188 2189 #use JSON::XS; 2190 #warn "Req: ", JSON::XS->new->encode([$req]), "\n"; 2191 2192 my ($meth, $uri, $http_ver); 2193 if ($req =~ m{^\s*(\w+)\s+(\S+)\s+HTTP/(\S+)\r?\n}smig) { 2194 ($meth, $uri, $http_ver) = ($1, $2, $3); 2195 2196 } elsif ($req =~ m{^\s*(\w+)\s+(.*\S)\r?\n}smig) { 2197 ($meth, $uri) = ($1, $2); 2198 $http_ver = '0.9'; 2199 2200 } else { 2201 bail_out "$name - cannot parse the status line in the request: $req"; 2202 } 2203 2204 my @args = ('curl', '-i'); 2205 2206 if ($Test::Nginx::Util::Verbose) { 2207 push @args, "-vv"; 2208 2209 } else { 2210 push @args, '-sS'; 2211 } 2212 2213 if (use_http2($block)) { 2214 push @args, '--http2', '--http2-prior-knowledge'; 2215 } 2216 2217 if ($meth eq 'HEAD') { 2218 push @args, '-I'; 2219 2220 } else { 2221 push @args, "-X", $meth; 2222 } 2223 2224 if ($http_ver ne '1.1') { 2225 # HTTP 1.0 or HTTP 0.9 2226 push @args, '-0'; 2227 } 2228 2229 my @headers; 2230 if ($http_ver ge '1.0') { 2231 if ($req =~ m{\G(.*?)\r?\n\r?\n}gcs) { 2232 my $headers = $1; 2233 #warn "raw headers: $headers\n"; 2234 @headers = grep { 2235 !/^Connection\s*:/i 2236 && !/^Host: \Q$ServerName\E$/i 2237 && !/^Content-Length\s*:/i 2238 } split /\r\n/, $headers; 2239 2240 } else { 2241 bail_out "cannot parse the header entries in the request: $req"; 2242 } 2243 } 2244 2245 #warn "headers: @headers ", scalar(@headers), "\n"; 2246 2247 my $found_content_type; 2248 2249 for my $h (@headers) { 2250 #warn "h: $h\n"; 2251 if ($h =~ /^\s*User-Agent\s*:\s*(.*\S)/i) { 2252 push @args, '-A', $1; 2253 2254 } else { 2255 if ($h =~ /^\s*Content-Type\s*:/i) { 2256 $found_content_type = 1; 2257 } 2258 2259 push @args, '-H', $h; 2260 } 2261 } 2262 2263 if ($req =~ m{\G(.+)}gcsm) { 2264 #warn "!! POST body data len: ", length($1); 2265 if (!$found_content_type) { 2266 push @args, "-H", 'Content-Type: '; 2267 } 2268 push @args, '--data-binary', $1; 2269 } 2270 2271 my $timeout = $block->timeout; 2272 if (!$timeout) { 2273 $timeout = timeout(); 2274 } 2275 2276 push @args, '--connect-timeout', $timeout; 2277 2278 my $link; 2279 2280 my $server_addr = $block->server_addr_for_client; 2281 2282 if (!defined $server_addr) { 2283 $server_addr = $ServerAddr; 2284 } 2285 2286 { 2287 my $server = $server_addr; 2288 my $port = $ServerPortForClient; 2289 $link = "http://$server:$port$uri"; 2290 } 2291 2292 push @args, $link; 2293 2294 return \@args; 2295} 2296 2297sub gen_ab_cmd_from_req ($$@) { 2298 my ($block, $req, $nreqs, $concur) = @_; 2299 2300 $nreqs ||= 100000000; 2301 $concur ||= 2; 2302 2303 if ($nreqs < $concur) { 2304 $concur = $nreqs; 2305 } 2306 2307 my $name = $block->name; 2308 2309 $req = join '', map { $_->{value} } @$req; 2310 2311 #use JSON::XS; 2312 #warn "Req: ", JSON::XS->new->encode([$req]), "\n"; 2313 2314 my ($meth, $uri, $http_ver); 2315 if ($req =~ m{^\s*(\w+)\s+(\S+)\s+HTTP/(\S+)\r?\n}smig) { 2316 ($meth, $uri, $http_ver) = ($1, $2, $3); 2317 2318 } elsif ($req =~ m{^\s*(\w+)\s+(.*\S)\r?\n}smig) { 2319 ($meth, $uri) = ($1, $2); 2320 $http_ver = '0.9'; 2321 2322 } else { 2323 bail_out "$name - cannot parse the status line in the request: $req"; 2324 } 2325 2326 #warn "HTTP version: $http_ver\n"; 2327 2328 my @opts = ("-c$concur", '-k', "-n$nreqs"); 2329 2330 my $prog; 2331 if ($http_ver eq '1.1' && $meth eq 'GET') { 2332 $prog = 'weighttp'; 2333 2334 } else { 2335 # HTTP 1.0 or HTTP 0.9 2336 $prog = 'ab'; 2337 unshift @opts, '-r', '-d', '-S'; 2338 } 2339 2340 my @headers; 2341 if ($http_ver ge '1.0') { 2342 if ($req =~ m{\G(.*?)\r?\n\r?\n}gcs) { 2343 my $headers = $1; 2344 #warn "raw headers: $headers\n"; 2345 @headers = grep { 2346 !/^Connection\s*:/i 2347 && !/^Host: \Q$ServerName\E$/i 2348 && !/^Content-Length\s*:/i 2349 } split /\r\n/, $headers; 2350 2351 } else { 2352 bail_out "cannot parse the header entries in the request: $req"; 2353 } 2354 } 2355 2356 #warn "headers: @headers ", scalar(@headers), "\n"; 2357 2358 for my $h (@headers) { 2359 #warn "h: $h\n"; 2360 if ($prog eq 'ab' && $h =~ /^\s*Content-Type\s*:\s*(.*\S)/i) { 2361 my $type = $1; 2362 push @opts, '-T', $type; 2363 2364 } else { 2365 push @opts, '-H', $h; 2366 } 2367 } 2368 2369 my $bodyfile; 2370 2371 if ($req =~ m{\G.+}gcs || $meth eq 'POST' || $meth eq 'PUT') { 2372 my $body = $&; 2373 2374 if (!defined $body) { 2375 $body = ''; 2376 } 2377 2378 my ($out, $bodyfile) = tempfile("bodyXXXXXXX", UNLINK => 1, 2379 SUFFIX => '.temp', TMPDIR => 1); 2380 print $out $body; 2381 close $out; 2382 2383 if ($meth eq 'PUT') { 2384 push @opts, '-u', $bodyfile; 2385 2386 } elsif ($meth eq 'POST') { 2387 push @opts, '-p', $bodyfile; 2388 2389 } elsif ($meth eq 'GET') { 2390 warn "WARNING: method $meth not supported for ab when taking a request body\n"; 2391 2392 } else { 2393 warn "WARNING: method $meth not supported for ab when taking a request body\n"; 2394 $meth = 'PUT'; 2395 push @opts, '-p', $bodyfile; 2396 } 2397 } 2398 2399 if ($meth eq 'HEAD') { 2400 unshift @opts, '-i'; 2401 } 2402 2403 my $link; 2404 2405 my $server_addr = $block->server_addr_for_client; 2406 2407 if (!defined $server_addr) { 2408 $server_addr = $ServerAddr; 2409 } 2410 2411 { 2412 my $server = $server_addr; 2413 my $port = $ServerPortForClient; 2414 $link = "http://$server:$port$uri"; 2415 } 2416 2417 my @cmd = ($prog, @opts, $link); 2418 2419 if ($Test::Nginx::Util::Verbose) { 2420 warn "command: @cmd\n"; 2421 } 2422 2423 return \@cmd; 2424} 2425 2426sub get_linear_regression_slope ($) { 2427 my $list = shift; 2428 2429 my $n = @$list; 2430 my $avg_x = ($n + 1) / 2; 2431 my $avg_y = sum(@$list) / $n; 2432 2433 my $x = 0; 2434 my $avg_xy = sum(map { $x++; $x * $_ } @$list) / $n; 2435 my $avg_x2 = sum(map { $_ * $_ } 1 .. $n) / $n; 2436 my $denom = $avg_x2 - $avg_x * $avg_x; 2437 if ($denom == 0) { 2438 return 'Inf'; 2439 } 2440 my $k = ($avg_xy - $avg_x * $avg_y) / $denom; 2441 return sprintf("%.01f", $k); 2442} 2443 24441; 2445__END__ 2446 2447=encoding utf-8 2448 2449=head1 NAME 2450 2451Test::Nginx::Socket - Socket-backed test scaffold for the Nginx C modules and Nginx/OpenResty-based libraries and applications 2452 2453=head1 SYNOPSIS 2454 2455 use Test::Nginx::Socket; 2456 2457 repeat_each(2); 2458 plan tests => repeat_each() * 3 * blocks(); 2459 2460 no_shuffle(); 2461 run_tests(); 2462 2463 __DATA__ 2464 2465 === TEST 1: sanity 2466 --- config 2467 location /echo { 2468 echo_before_body hello; 2469 echo world; 2470 } 2471 --- request 2472 GET /echo 2473 --- response_body 2474 hello 2475 world 2476 --- error_code: 200 2477 2478 2479 === TEST 2: set Server 2480 --- config 2481 location /foo { 2482 echo hi; 2483 more_set_headers 'Server: Foo'; 2484 } 2485 --- request 2486 GET /foo 2487 --- response_headers 2488 Server: Foo 2489 --- response_body 2490 hi 2491 2492 2493 === TEST 3: clear Server 2494 --- config 2495 location /foo { 2496 echo hi; 2497 more_clear_headers 'Server: '; 2498 } 2499 --- request 2500 GET /foo 2501 --- response_headers_like 2502 Server: nginx.* 2503 --- response_body 2504 hi 2505 2506 2507 === TEST 3: chunk size too small 2508 --- config 2509 chunkin on; 2510 location /main { 2511 echo_request_body; 2512 } 2513 --- more_headers 2514 Transfer-Encoding: chunked 2515 --- request eval 2516 "POST /main 2517 4\r 2518 hello\r 2519 0\r 2520 \r 2521 " 2522 --- error_code: 400 2523 --- response_body_like: 400 Bad Request 2524 2525=head1 DESCRIPTION 2526 2527This module provides a test scaffold based on non-blocking L<IO::Socket> for automated testing in Nginx C module development. 2528 2529This class inherits from L<Test::Base>, thus bringing all its 2530declarative power to the Nginx C module testing practices. 2531 2532You need to terminate or kill any Nginx processes before running the test suite if you have changed the Nginx server binary. Normally it's as simple as 2533 2534 killall nginx 2535 PATH=/path/to/your/nginx-with-memc-module:$PATH prove -r t 2536 2537This module will create a temporary server root under t/servroot/ of the current working directory and starts and uses the nginx executable in the PATH environment. 2538 2539You will often want to look into F<t/servroot/logs/error.log> 2540when things go wrong ;) 2541 2542=head2 User Guide 2543 2544You can find a comprehensive user guide on this test framework in my upcoming book "Programming OpenResty": 2545 2546L<https://openresty.gitbooks.io/programming-openresty/content/testing/index.html> 2547 2548=head2 Features inherited from L<Test::Base> 2549 2550All the features of L<Test::Base> are inherited since it is an ancestor 2551class of this module anyway. 2552 2553Still we would highlight some of the inherited features here for those 2554unfamiliar with L<Test::Base>. 2555 2556=head3 Meta sections 2557 2558=over 2559 2560=item C<--- ONLY> 2561 2562Runs the surrounding test block only. You need to remember removing 2563C<--- ONLY> before committing your changes though. Don't 2564worry, the test scaffold would warn you loudly on the console 2565when you left a C<--- ONLY> in some test file. 2566 2567It is also very intuitive for the developer's workflow. One does not have 2568to specify a (unique) test name on the command-line; just find the 2569block in the editor, insert a C<--- ONLY> line right away, and run 2570the current test file immediately (for Vim users, the final step 2571is as simple as entering C<:!prove %> where C<:!> is the Vim way 2572of running an external shell command and C<%> would get substituted 2573with the current file being edited in Vim's buffer). 2574 2575This is definitely one of the most useful and frequently used features. 2576 2577=item C<--- SKIP> 2578 2579Skips the surrounding test block unconditionally. You can use C<--- skip_nginx> 2580and C<--- skip_nginx2> providied by this module (see their documentation below) 2581to conditionally skip tests according to the current NGINX server versions. You 2582can also use C<--- skip_openssl> (see its documentation below) to conditionally 2583skip tests according to the current OpenSSL version. 2584 2585=back 2586 2587=head3 Filters 2588 2589We can use filters to preprocess the values of our blocks, which can make 2590specifying special values much easier. 2591 2592For example, we could chop off 2593the last new-line character (if any) of the current section value by 2594specifying the C<chomp> filter, like this: 2595 2596 --- response_body chomp 2597 Hello world! 2598 2599Without the C<chomp> filter, the value of the C<response_body> section would 2600take a trailing new line. 2601 2602We list some of the common filters below (please keep in mind that one can 2603define custom filters!) 2604 2605=over 2606 2607=item C<chomp> 2608 2609Remove the last character if it is a newline. 2610 2611=item C<chop> 2612 2613Remove the last character no matter what it is. 2614 2615=item C<eval> 2616 2617Treat the section value as a Perl source code snippet, evaluate it right away, and use 2618the returned value of the Perl code snippet (usually being the value of the last expression). 2619 2620This is very useful for specifying non-printable characters in section values, as in 2621 2622 --- response_body eval 2623 "I don't know what \0 is.\n" 2624 2625=back 2626 2627=head1 Exported Perl Functions 2628 2629The following Perl functions are exported by default: 2630 2631=head2 run_tests 2632 2633This is the main entry point of the test scaffold. Calling this Perl function before C<__DATA__> makes all the tests run. 2634Other configuration Perl functions I<must> be called before calling this C<run_tests> function. 2635 2636=head2 no_shuffle 2637 2638By default, the test scaffold always shuffles the order of the test blocks automatically. Calling this function before 2639calling C<run_tests> will disable the shuffling. 2640 2641=head2 use_hup 2642 2643Calling this function before calling C<run_tests> will make the current test 2644scaffold behave as if C<TEST_NGINX_USE_HUP> was set to 1. 2645 2646=head2 no_long_string 2647 2648By default, failed string equality test will use the L<Test::LongString> module to generate the error message. Calling this function 2649before calling C<run_tests> will turn this off. 2650 2651=head2 no_diff 2652 2653When the C<no_long_string> function is called, the C<Text::Diff> module will be used to generate a diff for failed string equality test. Calling this C<no_diff> function before calling C<run_tests> will turn this diff output format off and just generate the raw "got" text and "expected" text. 2654 2655=head2 worker_connections 2656 2657Call this function before calling C<run_tests> to set the Nginx's C<worker_connections> configuration value. For example, 2658 2659 worker_connections(1024); 2660 run_tests(); 2661 2662Default to 64. 2663 2664=head2 repeat_each 2665 2666Call this function with an integer argument before C<run_tests()> to ask the test scaffold 2667to run the specified number of duplicate requests for each test block. When it is called without argument, it returns the current setting. 2668 2669Default to 1. 2670 2671=head2 shutdown_error_log 2672 2673You can use this section to check the error log generated during nginx exit. 2674 2675For example, 2676 2677 --- shutdown_error_log 2678 cleanup resolver 2679 2680or an example for using an array value, 2681 2682 --- shutdown_error_log eval 2683 ["cleanup", "resolver"] 2684 2685B<WARNING:> skip the shutdown_error_log tests under the HUP reload mode. 2686 2687=head2 no_shutdown_error_log 2688 2689Very much like the C<--- shutdown_error_log> section, but does the opposite test, i.e., 2690pass only when the specified patterns of lines do not appear in the F<error.log> file at all. 2691 2692Here is an example: 2693 2694 --- no_shutdown_error_log 2695 [error] 2696 2697This test will fail when any of the line in the F<error.log> file contains the string C<"[error]">. 2698 2699=head2 env_to_nginx 2700 2701Specify additional system environmnt variables to be passed into the nginx server. 2702 2703For example, 2704 2705 env_to_nginx("foo", "bar=123", "baz=hello world"); 2706 run_tests(); 2707 2708will result in the following lines to be inserted into the resulting F<nginx.conf> file generated by the test scaffold: 2709 2710 env foo; 2711 env bar=123; 2712 env 'baz=hello world'; 2713 2714The latter two are examples of setting values directly to the environments. You can also set values directly on the Perl land, before calling this C<env_to_nginx> function, for instance, 2715 2716 $ENV{baz} = 'hello world'; 2717 env_to_nginx("baz"); 2718 2719If you just want to pass certain environments to a particular test case (or test block), you can just 2720use the C<--- main_config> secion directly. For example, 2721 2722 --- main_config 2723 env foo; 2724 env bar=123; 2725 2726You can check out nginx's official document on its C<env> directive below: 2727 2728L<http://nginx.org/r/env> 2729 2730By default, only the following environments are passed: 2731 2732=over 2733 2734=item * 2735 2736MOCKEAGAIN_VERBOSE 2737 2738=item * 2739 2740MOCKEAGAIN 2741 2742=item * 2743 2744MOCKEAGAIN_WRITE_TIMEOUT_PATTERN 2745 2746=item * 2747 2748LD_PRELOAD 2749 2750=item * 2751 2752LD_LIBRARY_PATH 2753 2754=item * 2755 2756DYLD_INSERT_LIBRARIES 2757 2758=item * 2759 2760DYLD_FORCE_FLAT_NAMESPACE 2761 2762=item * 2763 2764ASAN_OPTIONS 2765 2766=item * 2767 2768MOCKNOEAGAIN_VERBOSE 2769 2770=item * 2771 2772MOCKNOEAGAIN 2773 2774=back 2775 2776=head2 workers 2777 2778Call this function before C<run_tests()> to configure Nginx's C<worker_processes> directive's value. For example, 2779 2780 workers(2); 2781 2782Default to 1. 2783 2784=head2 master_on 2785 2786Call this function before C<run_tests()> to turn on the Nginx master process. 2787 2788By default, the master process is not enabled unless in the "HUP reload" testing mode. 2789 2790=head2 log_level 2791 2792Call this function before C<run_tests()> to set the default error log filtering level in Nginx. 2793 2794This global setting can be overridden by the per-test-block C<--- log_level> sections. 2795 2796Default to C<debug>. 2797 2798=head2 check_accum_error_log 2799 2800Make C<--- error_log> and C<--- no_error_log> check accumulated error log across duplicate requests controlled by C<repeat_each>. By default, only the error logs belonging to the individual C<repeat_each> request is tested. 2801 2802=head2 no_root_location 2803 2804By default, the Nginx configuration file generated by the test scaffold 2805automatically emits a C<location />. Calling this function before C<run_tests()> 2806disables this behavior such that the test blocks can have their own root locations. 2807 2808=head2 bail_out 2809 2810Aborting the whole test session (not just the current test file) with a specified message. 2811 2812This function will also do all the necessary cleanup work. So always use this function instead of calling C<Test::More::BAIL_OUT()> directly. 2813 2814For example, 2815 2816 bail_out("something bad happened!"); 2817 2818=head2 add_cleanup_handler 2819 2820Rigister custom cleanup handler for the current perl/prove process by specifying a Perl subroutine object as the argument. 2821 2822For example, 2823 2824 add_cleanup_handler(sub { 2825 kill INT => $my_own_child_pid; 2826 $my_own_socket->close() 2827 }); 2828 2829=head2 add_block_preprocessor 2830 2831Add a custom Perl preprocessor to each test block by specifying a Perl subroutine object as the argument. 2832 2833The processor subroutine is always run right before processing the test block. 2834 2835This mechanism can be used to add custom sections or modify existing ones. 2836 2837For example, 2838 2839 add_block_preprocessor(sub { 2840 my $block = shift; 2841 2842 # use "--- req_headers" for "--- more_Headers": 2843 $block->set_value("more_headers", $block->req_headers); 2844 2845 # initialize external dependencies like memcached services here... 2846 }); 2847 2848We can leverage this feature to specify a default value for one or more sections in a single test file. For instance, 2849 2850 use Test::Nginx::Socket 'no_plan'; 2851 2852 add_block_preprocessor(sub { 2853 my $block = shift; 2854 2855 if (!defined $block->config) { 2856 $block->set_value("config", <<'_END_'); 2857 location = /t { 2858 echo $arg_a; 2859 } 2860 _END_ 2861 } 2862 }); 2863 2864 run_tests(); 2865 2866 __DATA__ 2867 2868 === TEST 1: 2869 --- request 2870 GET /t?a=3 2871 --- response_body 2872 3 2873 2874 2875 2876 === TEST 2: 2877 --- request 2878 GET /t?a=blah 2879 --- response_body 2880 blah 2881 2882 2883 2884 === TEST 3: 2885 --- config 2886 location = /t { 2887 echo ok; 2888 } 2889 --- request 2890 GET /t?a=blah 2891 --- response_body 2892 ok 2893 2894Here all the test blocks in this file have a default C<--- config> section configured. Some of the test blocks can still 2895specify its own C<--- config> section to override the default, as in the `TEST 3` test block above. 2896 2897You can also make the defaults applicable to all the test files. Just create a subclass of L<Test::Nginx::Socket> (or one of its 2898subclasses like L<Test::Nginx::Socket::Lua>, as in, 2899 2900 package t::MyTester; 2901 2902 use Test::Nginx::Socket -Base; 2903 2904 add_block_preprocessor(sub { 2905 my $block = shift; 2906 2907 if (!defined $block->config) { 2908 $block->set_value("config", <<'_END_'); 2909 location = /t { 2910 echo $arg_a; 2911 } 2912 _END_ 2913 } 2914 }); 2915 2916 1; 2917 2918Save this as file F<t/MyTester.pm>. And then in one of your test file: 2919 2920 use t::MyTester 'no_plan'; 2921 2922 run_tests(); 2923 2924 __DATA__ 2925 2926 === TEST 1: 2927 --- request 2928 GET /t?a=3 2929 --- response_body 2930 3 2931 2932 2933 2934 === TEST 2: 2935 --- request 2936 GET /t?a=blah 2937 --- response_body 2938 blah 2939 2940You can do the same with the C<--- http_config> section, or even inventing your own new sections. This is very powerful. 2941 2942=head2 add_response_body_check 2943 2944Add custom checks for testing response bodies by specifying a Perl subroutine object as the argument. 2945 2946Below is an example for doing HTML title checks: 2947 2948 add_response_body_check(sub { 2949 my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_; 2950 2951 my $name = $block->name; 2952 my $expected_title = $block->resp_title; 2953 2954 if ($expected_title && !ref $expected_title) { 2955 $expected_title =~ s/^\s*|\s*$//gs; 2956 } 2957 2958 if (defined $expected_title) { 2959 SKIP: { 2960 skip "$name - resp_title - tests skipped due to $dry_run", 1 if $dry_run; 2961 2962 my $title; 2963 if ($body =~ m{<\s*title\s*>\s*(.*?)<\s*/\s*title\s*>}) { 2964 $title = $1; 2965 $title =~ s/\s*$//s; 2966 } 2967 2968 is_str($title, $expected_title, 2969 "$name - resp_title (req $repeated_req_idx)" ); 2970 } 2971 } 2972 }); 2973 2974=head2 is_str 2975 2976Performs intelligent string comparison subtests which honors both C<no_long_string> and regular expression references in the "expected" argument. 2977 2978=head1 Sections supported 2979 2980The following sections are supported: 2981 2982=head2 http2 2983 2984Enforces the test scaffold to use the HTTP/2 wire protocol to send the test request. 2985 2986Under the hood, the test scaffold uses the `curl` command-line utility to do the wire communication 2987with the NGINX server. The `curl` utility must be recent enough to support both the C<--http2> 2988and C<--http2-prior-knowledge> command-line options. 2989 2990B<WARNING:> not all the sections and features are supported when this C<--- http2> section is 2991specified. For example, this section cannot be used with C<--- pipelined_requests> or 2992C<--- raw_request>. 2993 2994See also the L<TEST_NGINX_USE_HTTP2> system environment for the "http2" test mode. 2995 2996=head2 config 2997 2998Content of this section will be included in the "server" part of the generated 2999config file. This is the place where you want to put the "location" directive 3000enabling the module you want to test. Example: 3001 3002 location /echo { 3003 echo_before_body hello; 3004 echo world; 3005 } 3006 3007Sometimes you simply don't want to bother copying ten times the same 3008configuration for the ten tests you want to run against your module. One way 3009to do this is to write a config section only for the first test in your C<.t> 3010file. All subsequent tests will re-use the same config. Please note that this 3011depends on the order of test, so you should run C<prove> with variable 3012C<TEST_NGINX_NO_SHUFFLE=1> (see below for more on this variable). 3013 3014Please note that config section goes through environment variable expansion 3015provided the variables to expand start with TEST_NGINX. 3016So, the following is a perfectly legal (provided C<TEST_NGINX_HTML_DIR> is 3017set correctly): 3018 3019 location /main { 3020 echo_subrequest POST /sub -f $TEST_NGINX_HTML_DIR/blah.txt; 3021 } 3022 3023=head2 http_config 3024 3025Content of this section will be included in the "http" part of the generated 3026config file. This is the place where you want to put the "upstream" directive 3027you might want to test. Example: 3028 3029 upstream database { 3030 postgres_server 127.0.0.1:$TEST_NGINX_POSTGRESQL_PORT 3031 dbname=ngx_test user=ngx_test 3032 password=wrong_pass; 3033 } 3034 3035As you guessed from the example above, this section goes through environment 3036variable expansion (variables have to start with TEST_NGINX). 3037 3038=head2 main_config 3039 3040Content of this section will be included in the "main" part (or toplevel) of the generated 3041config file. This is very rarely used, except if you are testing nginx core 3042itself. Everything in C<--- main_config> will be put before the C<http {}> block generated automatically by the test scaffold. 3043 3044This section goes through environment 3045variable expansion (variables have to start with TEST_NGINX). 3046 3047=head2 post_main_config 3048 3049Similar to C<main_config>, but the content will be put I<after> the C<http {}> 3050block generated by this module. 3051 3052=head2 server_name 3053 3054Specify a custom server name (via the "server_name" nginx config directive) for the 3055current test block. Default to "localhost". 3056 3057=head2 init 3058 3059Run a piece of Perl code specified as the content of this C<--- init> section before running the tests for the blocks. Note that it is only run once before *all* the repeated requests for this test block. 3060 3061=head2 request 3062 3063This is probably the most important section. It defines the request(s) you 3064are going to send to the nginx server. It offers a pretty powerful grammar 3065which we are going to walk through one example at a time. 3066 3067In its most basic form, this section looks like that: 3068 3069 --- request 3070 GET 3071 3072This will just do a GET request on the root (i.e. /) of the server using 3073HTTP/1.1. 3074 3075Of course, you might want to test something else than the root of your 3076web server and even use a different version of HTTP. This is possible: 3077 3078 --- request 3079 GET /foo HTTP/1.0 3080 3081Please note that specifying HTTP/1.0 will not prevent Test::Nginx from 3082sending the C<Host> header. Actually Test::Nginx always sends 2 headers: 3083C<Host> (with value localhost) and C<Connection> (with value C<close> for 3084simple requests and keep-alive for all but the last pipelined_requests). 3085 3086You can also add a content to your request: 3087 3088 --- request 3089 POST /foo 3090 Hello world 3091 3092Test::Nginx will automatically calculate the content length and add the 3093corresponding header for you. 3094 3095This being said, as soon as you want to POST real data, you will be interested 3096in using the more_headers section and using the power of Test::Base filters 3097to urlencode the content you are sending. Which gives us a 3098slightly more realistic example: 3099 3100 --- more_headers 3101 Content-type: application/x-www-form-urlencoded 3102 --- request eval 3103 use URI::Escape; 3104 "POST /rrd/foo 3105 value=".uri_escape("N:12345") 3106 3107Sometimes a test is more than one request. Typically you want to POST some 3108data and make sure the data has been taken into account with a GET. You can 3109do it using arrays: 3110 3111 --- request eval 3112 ["POST /users 3113 name=foo", "GET /users/foo"] 3114 3115This way, REST-like interfaces are pretty easy to test. 3116 3117When you develop nifty nginx modules you will eventually want to test things 3118with buffers and "weird" network conditions. This is where you split 3119your request into network packets: 3120 3121 --- request eval 3122 [["POST /users\nna", "me=foo"]] 3123 3124Here, Test::Nginx will first send the request line, the headers it 3125automatically added for you and the first two letters of the body ("na" in 3126our example) in ONE network packet. Then, it will send the next packet (here 3127it's "me=foo"). When we talk about packets here, this is not exactly correct 3128as there is no way to guarantee the behavior of the TCP/IP stack. What 3129Test::Nginx can guarantee is that this will result in two calls to 3130C<syswrite>. 3131 3132A good way to make I<almost> sure the two calls result in two packets is to 3133introduce a delay (let's say 2 seconds)before sending the second packet: 3134 3135 --- request eval 3136 [["POST /users\nna", {value => "me=foo", delay_before => 2}]] 3137 3138Of course, everything can be combined till your brain starts boiling ;) : 3139 3140 --- request eval 3141 use URI::Escape; 3142 my $val="value=".uri_escape("N:12346"); 3143 [["POST /rrd/foo 3144 ".substr($val, 0, 6), 3145 {value => substr($val, 6, 5), delay_before=>5}, 3146 substr($val, 11)], "GET /rrd/foo"] 3147 3148Adding comments before the actual request spec is also supported, for example, 3149 3150 --- request 3151 # this request contains the URI args 3152 # "foo" and "bar": 3153 GET /api?foo=1&bar=2 3154 3155=head2 request_eval 3156 3157Use of this section is deprecated and tests using it should replace it with 3158a C<request> section with an C<eval> filter. More explicitly: 3159 3160 --- request_eval 3161 "POST /echo_body 3162 hello\x00\x01\x02 3163 world\x03\x04\xff" 3164 3165should be replaced by: 3166 3167 --- request eval 3168 "POST /echo_body 3169 hello\x00\x01\x02 3170 world\x03\x04\xff" 3171 3172=head2 pipelined_requests 3173 3174Specify pipelined requests that use a single keep-alive connection to the server. 3175 3176Here is an example from ngx_lua's test suite: 3177 3178 === TEST 7: discard body 3179 --- config 3180 location = /foo { 3181 content_by_lua ' 3182 ngx.req.discard_body() 3183 ngx.say("body: ", ngx.var.request_body) 3184 '; 3185 } 3186 location = /bar { 3187 content_by_lua ' 3188 ngx.req.read_body() 3189 ngx.say("body: ", ngx.var.request_body) 3190 '; 3191 } 3192 --- pipelined_requests eval 3193 ["POST /foo 3194 hello, world", 3195 "POST /bar 3196 hiya, world"] 3197 --- response_body eval 3198 ["body: nil\n", 3199 "body: hiya, world\n"] 3200 3201=head2 more_headers 3202 3203Adds the content of this section as headers to the request being sent. Example: 3204 3205 --- more_headers 3206 X-Foo: blah 3207 3208This will add C<X-Foo: blah> to the request (on top of the automatically 3209generated headers like C<Host>, C<Connection> and potentially 3210C<Content-Length>). 3211 3212=head2 curl 3213 3214When this section is specified, the test scaffold will try generating a C<curl> command line for the (first) test request. 3215 3216For example, 3217 3218 --- request 3219 GET /foo/bar?baz=3 3220 3221 --- more_headers 3222 X-Foo: 3 3223 User-Agent: openresty 3224 3225 --- curl 3226 3227will produce the following line (to C<stderr>) while running this test block: 3228 3229 # curl -i -sS -H 'X-Foo: 3' -A openresty 'http://127.0.0.1:1984/foo/bar?baz=3' 3230 3231You need to remember to set the C<TEST_NGINX_NO_CLEAN> environment to 1 to prevent the nginx 3232and other processes from quitting automatically upon test exits. 3233 3234=head2 response_body_filters 3235 3236Transforms the value of the I<actual> response body data through a series of filters, before being matched against the expected response body 3237data specified by the C<response_body> or C<response_body_like> sections. 3238 3239The filters can be specified either as names (for builtin filters) or as arbitrary Perl subroutine references. 3240 3241The following builtin filter names are supported: 3242 3243=over 3244 3245=item md5_hex 3246 3247=item sha1_hex 3248 3249=item length 3250 3251=item uc 3252 3253=item lc 3254 3255=item ucfirst 3256 3257=item lcfirst 3258 3259=back 3260 3261Their meanings are self-explanatory. 3262 3263Here is an example: 3264 3265 === TEST 1: 3266 --- config 3267 location = /t { 3268 echo hello; 3269 } 3270 --- request 3271 GET /t 3272 --- response_body_filters 3273 uc 3274 --- response_body 3275 HELLO 3276 3277Here the actual response body data, C<hello>, will go through the fitler, C<uc>, to become all-upper-case, before getting matched 3278against the expected pattern specified by the C<response_body> section, C<HELLO>. 3279 3280The example above can be rewritten by using raw Perl subroutine reference values: 3281 3282 === TEST 1: 3283 --- config 3284 location = /t { 3285 echo hello; 3286 } 3287 --- request 3288 GET /t 3289 --- response_body_filters eval 3290 \&CORE::uc 3291 --- response_body 3292 HELLO 3293 3294To reference builtin Perl functions like C<\&CORE::uc> and C<\&CORE::lc>, you need at least perl 5.16. 3295 3296Multiple builtin filter names can be specified at the same time and they will be applied in order. For example, 3297 3298 === TEST 2: 3299 --- config 3300 location = /t { 3301 echo hello; 3302 } 3303 --- request 3304 GET /hello 3305 --- response_body_filters 3306 uc lc 3307 --- response_body 3308 hello 3309 3310If the response_body_filters value can also be an array reference, mostly useful for specifying multiple Perl subroutine 3311references as the filters: 3312 3313 === TEST 3: 3314 --- config 3315 location = /t { 3316 echo hello; 3317 } 3318 --- request 3319 GET /hello 3320 --- response_body_filters eval 3321 [\&CORE::uc, \&CORE::lc] 3322 --- response_body 3323 hello 3324 3325If the response_body_filters value can also be an two-dimensional array reference, it means the actual response body data will be C<isolatedly> applied by the indexed array's filters: 3326 3327 === TEST 4: 3328 --- config 3329 location = /t { 3330 echo hello; 3331 } 3332 --- request eval 3333 ['GET /t', 'GET /t'] 3334 --- response_body_filters eval 3335 [[\&CORE::uc, \&CORE::lc], [\&CORE::uc]] 3336 --- response_body eval 3337 ['hello', 'HELLO'] 3338 3339=head2 response_body 3340 3341The expected value for the body of the submitted request. 3342 3343 --- response_body 3344 hello 3345 3346If the test is made of multiple requests, then the response_body B<MUST> 3347be an array and each request B<MUST> return the corresponding expected 3348body: 3349 3350 --- request eval 3351 ["GET /hello", "GET /world"] 3352 --- response_body eval 3353 ["hello", "world"] 3354 3355=head2 response_body_eval 3356 3357Use of this section is deprecated and tests using it should replace it 3358with a C<request> section with an C<eval> filter. Therefore: 3359 3360 --- response_body_eval 3361 "hello\x00\x01\x02 3362 world\x03\x04\xff" 3363 3364should be replaced by: 3365 3366 --- response_body eval 3367 "hello\x00\x01\x02 3368 world\x03\x04\xff" 3369 3370=head2 response_body_like 3371 3372The body returned by the request MUST match the pattern provided by this 3373section. Example: 3374 3375 --- response_body_like 3376 ^elapsed 0\.00[0-5] sec\.$ 3377 3378If the test is made of multiple requests, then response_body_like B<MUST> 3379be an array and each request B<MUST> match the corresponding pattern. 3380 3381=head2 response_body_unlike 3382 3383Just like C<response_body_like> but this test only pass when the specified pattern 3384does I<not> match the actual response body data. 3385 3386=head2 response_headers 3387 3388The headers specified in this section are in the response sent by nginx. 3389 3390 --- response_headers 3391 Content-Type: application/x-resty-dbd-stream 3392 3393Of course, you can specify many headers in this section: 3394 3395 --- response_headers 3396 X-Resty-DBD-Module: 3397 Content-Type: application/x-resty-dbd-stream 3398 3399The test will be successful only if all headers are found in the response with 3400the appropriate values. 3401 3402If the test is made of multiple requests, then response_headers B<MUST> 3403be an array and each element of the array is checked against the 3404response to the corresponding request. 3405 3406=head2 response_headers_like 3407 3408The value of the headers returned by nginx match the patterns. 3409 3410 --- response_headers_like 3411 X-Resty-DBD-Module: ngx_drizzle \d+\.\d+\.\d+ 3412 Content-Type: application/x-resty-dbd-stream 3413 3414This will check that the response's C<Content-Type> is 3415application/x-resty-dbd-stream and that the C<X-Resty-DBD-Module> matches 3416C<ngx_drizzle \d+\.\d+\.\d+>. 3417 3418The test will be successful only if all headers are found in the response and 3419if the values match the patterns. 3420 3421If the test is made of multiple requests, then response_headers_like B<MUST> 3422be an array and each element of the array is checked against the 3423response to the corresponding request. 3424 3425=head2 raw_response_headers_like 3426 3427Checks the headers part of the response against this pattern. This is 3428particularly useful when you want to write tests of redirect functions 3429that are not bound to the value of the port your nginx server (under 3430test) is listening to: 3431 3432 --- raw_response_headers_like: Location: http://localhost(?::\d+)?/foo\r\n 3433 3434As usual, if the test is made of multiple requests, then 3435raw_response_headers_like B<MUST> be an array. 3436 3437=head2 raw_response_headers_unlike 3438 3439Just like C<raw_response_headers_like> but the subtest only passes when 3440the regex does I<not> match the raw response headers string. 3441 3442=head2 error_code 3443 3444The expected value of the HTTP response code. If not set, this is assumed 3445to be 200. But you can expect other things such as a redirect: 3446 3447 --- error_code: 302 3448 3449If the test is made of multiple requests, then 3450error_code B<MUST> be an array with the expected value for the response status 3451of each request in the test. 3452 3453=head2 error_code_like 3454 3455Just like C<error_code>, but accepts a Perl regex as the value, for example: 3456 3457 --- error_code_like: ^(?:500)?$ 3458 3459If the test is made of multiple requests, then 3460error_code_like B<MUST> be an array with the expected value for the response status 3461of each request in the test. 3462 3463=head2 timeout 3464 3465Specify the timeout value (in seconds) for the HTTP client embedded into the test scaffold. This has nothing 3466to do with the server side configuration. When the timeout expires, the test scaffold will immediately 3467close the socket for connecting to the Nginx server being tested. 3468 3469Note that, just as almost all the timeout settings in the Nginx world, this timeout 3470also specifies the maximum waiting time between two successive I/O events on the same socket handle, 3471rather than the total waiting time for the current socket operation. 3472 3473When the timeout setting expires, a test failure will be 3474triggered with the message "ERROR: client socket timed out - TEST NAME", unless you have specified 3475C<--- abort> at the same time. 3476 3477Here is an example: 3478 3479 === TEST 1: test timeout 3480 --- location 3481 location = /t { 3482 echo_sleep 1; 3483 echo ok; 3484 } 3485 --- request 3486 GET /t 3487 --- response_body 3488 ok 3489 --- timeout: 1.5 3490 3491An optional time unit can be specified, for example, 3492 3493 --- timeout: 50ms 3494 3495Acceptable time units are C<s> (seconds) and C<ms> (milliseconds). If no time unit is specified, then default to seconds. 3496 3497Default to 3s. 3498 3499=head2 error_log_file 3500 3501Specify the global error log file for the current test block only. 3502 3503Right now, it will not affect the C<--- error_log> section and etc accordingly. 3504 3505=head2 error_log 3506 3507Checks if the pattern or multiple patterns all appear in lines of the F<error.log> file. 3508 3509For example, 3510 3511 === TEST 1: matched with j 3512 --- config 3513 location /re { 3514 content_by_lua ' 3515 m = ngx.re.match("hello, 1234", "([0-9]+)", "j") 3516 if m then 3517 ngx.say(m[0]) 3518 else 3519 ngx.say("not matched!") 3520 end 3521 '; 3522 } 3523 --- request 3524 GET /re 3525 --- response_body 3526 1234 3527 --- error_log: pcre JIT compiling result: 1 3528 3529Then the substring "pcre JIT compiling result: 1" must appear literally in a line of F<error.log>. 3530 3531Multiple patterns are also supported, for example: 3532 3533 --- error_log eval 3534 ["abc", qr/blah/] 3535 3536then the substring "abc" must appear literally in a line of F<error.log>, and the regex C<qr/blah> 3537must also match a line in F<error.log>. 3538 3539By default, only the part of the error logs corresponding to the current request is checked. You can make it check accumulated error logs by calling the C<check_accum_error_log> Perl function before calling C<run_tests> in the boilerplate Perl code above the C<__DATA__> line. 3540 3541=head2 access_log 3542 3543Similar to the L<error_log> section, but for asserting appearance of patterns in the nginx access log file. 3544 3545Below is an example: 3546 3547 === TEST 1: check access log 3548 --- config 3549 location /t { 3550 content_by_lua_block { 3551 ngx.say("hello") 3552 } 3553 } 3554 3555 --- request 3556 GET /t 3557 --- response_body 3558 hello 3559 --- access_log 3560 GET /t 3561 3562=head2 abort 3563 3564Makes the test scaffold not to treat C<--- timeout> expiration as a test failure. 3565 3566=head2 shutdown 3567 3568Perform a C<shutdown>() operation on the client socket connecting to Nginx as soon as sending out 3569all the request data. This section takes an (optional) integer value for the argument to the 3570C<shutdown> function call. For example, 3571 3572 --- shutdown: 1 3573 3574will make the connection stop sending data, which is the default. 3575 3576=head2 no_error_log 3577 3578Very much like the C<--- error_log> section, but does the opposite test, i.e., 3579pass only when the specified patterns of lines do not appear in the F<error.log> file at all. 3580 3581Here is an example: 3582 3583 --- no_error_log 3584 [error] 3585 3586This test will fail when any of the line in the F<error.log> file contains the string C<"[error]">. 3587 3588Just like the C<--- error_log> section, one can also specify multiple patterns: 3589 3590 --- no_error_log eval 3591 ["abc", qr/blah/] 3592 3593Then if any line in F<error.log> contains the string C<"abc"> or match the Perl regex C<qr/blah/>, then the test will fail. 3594 3595=head2 grep_error_log 3596 3597This section specifies the Perl regex pattern for filtering out the Nginx error logs. 3598 3599You can specify a verbatim substring being matched in the error log messages, as in 3600 3601 --- grep_error_log chop 3602 some thing we want to see 3603 3604or specify a Perl regex object to match against the error log message lines, as in 3605 3606 --- grep_error_log eval 3607 qr/something should be: \d+/ 3608 3609All the matched substrings in the error log messages will be concatenated by a newline character as a whole to be compared with the value of the C<--- grep_error_log_out> section. 3610 3611=head2 grep_error_log_out 3612 3613This section contains the expected output for the filtering operations specified by the C<--- grep_error_log> section. 3614 3615If the filtered output varies among the repeated requests (specified by the C<repeat_each> function, then you can specify a Perl array as the value, as in 3616 3617 --- grep_error_log_out eval 3618 ["output for req 0", "output for req 1"] 3619 3620=head2 log_level 3621 3622Overrides the default error log level for the current test block. 3623 3624For example: 3625 3626 --- log_level: debug 3627 3628The default error log level can be specified in the Perl code by calling the C<log_level()> function, as in 3629 3630 use Test::Nginx::Socket; 3631 3632 repeat_each(2); 3633 plan tests => repeat_each() * (3 * blocks()); 3634 3635 log_level('warn'); 3636 3637 run_tests(); 3638 3639 __DATA__ 3640 ... 3641 3642=head2 raw_request 3643 3644The exact request to send to nginx. This is useful when you want to test 3645some behaviors that are not available with "request" such as an erroneous 3646C<Content-Length> header or splitting packets right in the middle of headers: 3647 3648 --- raw_request eval 3649 ["POST /rrd/taratata HTTP/1.1\r 3650 Host: localhost\r 3651 Connection: close\r 3652 Content-Type: application/", 3653 "x-www-form-urlencoded\r 3654 Content-Length:15\r\n\r\nvalue=N%3A12345"] 3655 3656This can also be useful to tests "invalid" request lines: 3657 3658 --- raw_request 3659 GET /foo HTTP/2.0 THE_FUTURE_IS_NOW 3660 3661=head2 http09 3662 3663Specifies that the HTTP 0.9 protocol is used. This affects how C<Test::Nginx::Socket> 3664parses the response. 3665 3666Below is an example from ngx_headers_more module's test suite: 3667 3668 === TEST 38: HTTP 0.9 (set) 3669 --- config 3670 location /foo { 3671 more_set_input_headers 'X-Foo: howdy'; 3672 echo "x-foo: $http_x_foo"; 3673 } 3674 --- raw_request eval 3675 "GET /foo\r\n" 3676 --- response_headers 3677 ! X-Foo 3678 --- response_body 3679 x-foo: 3680 --- http09 3681 3682=head2 ignore_response 3683 3684Do not attempt to parse the response or run the response related subtests. 3685 3686=head2 reload_fails 3687 3688Allows the NGINX HUP reload fails, which means that the server will still use the previous test block's nginx configuration. 3689 3690This only makes sense in the HUP reload testing mode. 3691 3692=head2 user_files 3693 3694With this section you can create a file that will be copied in the 3695html directory of the nginx server under test. For example: 3696 3697 --- user_files 3698 >>> blah.txt 3699 Hello, world 3700 3701will create a file named C<blah.txt> in the html directory of the nginx 3702server tested. The file will contain the text "Hello, world". 3703 3704Multiple files are supported, for example, 3705 3706 --- user_files 3707 >>> foo.txt 3708 Hello, world! 3709 >>> bar.txt 3710 Hello, heaven! 3711 3712An optional last modified timestamp (in elpased seconds since Epoch) is supported, for example, 3713 3714 --- user_files 3715 >>> blah.txt 199801171935.33 3716 Hello, world 3717 3718It's also possible to specify a Perl data structure for the user files 3719to be created, for example, 3720 3721 --- user_files eval 3722 [ 3723 [ "foo.txt" => "Hello, world!", 199801171935.33 ], 3724 [ "bar.txt" => "Hello, heaven!" ], 3725 ] 3726 3727=head2 skip_eval 3728 3729Skip the specified number of subtests (in the current test block) if the result of running a piece of Perl code is true. 3730 3731The format for this section is 3732 3733 --- skip_eval 3734 <subtest-count>: <perl-code> 3735 3736For example, to skip 3 subtests when the current operating system is not Linux: 3737 3738 --- skip_eval 3739 3: $^O ne 'linux' 3740 3741or equivalently, 3742 3743 --- skip_eval: 3: $^O ne 'linux' 3744 3745=head2 skip_nginx 3746 3747Skip the specified number of subtests (in the current test block) 3748for the specified version range of nginx. 3749 3750The format for this section is 3751 3752 --- skip_nginx 3753 <subtest-count>: <op> <version> 3754 3755The <subtest-count> value must be a positive integer. 3756The <op> value could be either C<< > >>, C<< >= >>, C<< < >>, or C<< <= >>. the <version> part is a valid nginx version number, like C<1.0.2>. 3757 3758An example is 3759 3760 === TEST 1: sample 3761 --- config 3762 location /t { echo hello; } 3763 --- request 3764 GET /t 3765 --- response_body 3766 --- skip_nginx 3767 2: < 0.8.54 3768 3769That is, skipping 2 subtests in this test block for nginx versions older than 0.8.54. 3770 3771This C<skip_nginx> section only allows you to specify one boolean expression as 3772the skip condition. If you want to use two boolean expressions, you should use the C<skip_nginx2> section instead. 3773 3774=head2 skip_nginx2 3775 3776This section is similar to C<skip_nginx>, but the skip condition consists of two boolean expressions joined by the operator C<and> or C<or>. 3777 3778The format for this section is 3779 3780 --- skip_nginx2 3781 <subtest-count>: <op> <version> and|or <op> <version> 3782 3783For example: 3784 3785 === TEST 1: sample 3786 --- config 3787 location /t { echo hello; } 3788 --- request 3789 GET /t 3790 --- response_body 3791 --- skip_nginx2 3792 2: < 0.8.53 and >= 0.8.41 3793 3794=head2 skip_openssl 3795 3796Skip the specified number of subtests (in the current test block) 3797for the specified version range of OpenSSL. 3798 3799The format for this section is 3800 3801 --- skip_openssl 3802 <subtest-count>: <op> <version> 3803 3804The <subtest-count> value must be a positive integer. 3805The <op> value could be either C<< > >>, C<< >= >>, C<< < >>, or C<< <= >>. 3806The <version> part is a valid OpenSSL version number, like C<1.1.1> or C<1.1.0h>. 3807 3808An example is 3809 3810 === TEST 1: sample 3811 --- config 3812 location /t { echo hello; } 3813 --- request 3814 GET /t 3815 --- response_body 3816 --- skip_openssl 3817 2: < 1.1.1 3818 3819That is, skipping 2 subtests in this test block for OpenSSL versions older than 1.1.1. 3820 3821This C<skip_openssl> section only allows you to specify one boolean expression as 3822the skip condition. 3823 3824=head2 todo 3825 3826Mark tests as todo. Currently they are not used but they should be. 3827 3828The format for this section is 3829 3830 --- todo 3831 <subtest-count>: <reason> 3832 3833The <subtest-count> value must be a positive integer. 3834 3835<reason> is logged when you run tests with --directives. 3836 3837=head2 stap 3838 3839This section is used to specify user systemtap script file (.stp file) 3840 3841Here's an example: 3842 3843 === TEST 1: stap sample 3844 --- config 3845 location /t { echo hello; } 3846 --- stap 3847 probe process("nginx").function("ngx_http_finalize_request") 3848 { 3849 printf("finalize %s?%s\n", ngx_http_req_uri($r), 3850 ngx_http_req_args($r)) 3851 } 3852 --- stap_out 3853 finalize /test?a=3&b=4 3854 --- request 3855 GET /test?a=3&b=4 3856 --- response_body 3857 hello 3858 3859There's some macros that can be used in the "--- stap" section value. These macros 3860will be expanded by the test scaffold automatically. 3861 3862=over 3863 3864=item C<F(function_name)> 3865 3866This expands to C<probe process("nginx").function("function_name")>. For example, 3867 the sample above can be rewritten as 3868 3869 === TEST 1: stap sample 3870 --- config 3871 location /t { echo hello; } 3872 --- stap 3873 F(ngx_http_finalize_request) 3874 { 3875 printf("finalize %s?%s\n", ngx_http_req_uri($r), 3876 ngx_http_req_args($r)) 3877 } 3878 --- stap_out 3879 finalize /test?a=3&b=4 3880 --- request 3881 GET /test?a=3&b=4 3882 --- response_body 3883 hello 3884 3885=item C<T()> 3886 3887This macro will be expanded to C<println("Fire ", pp())>. 3888 3889=item C<M(static-probe-name)> 3890 3891This macro will be expanded to C<probe process("nginx").mark("static-probe-name")>. 3892 3893For example, 3894 3895 M(http-subrequest-start) 3896 { 3897 ... 3898 } 3899 3900will be expanded to 3901 3902 probe process("nginx").mark("http-subrequest-start") 3903 { 3904 ... 3905 } 3906 3907=back 3908 3909=head2 stap_out 3910 3911This section specifies the expected literal output of the systemtap script specified by C<stap>. 3912 3913=head2 stap_out_like 3914 3915Just like C<stap_out>, but specify a Perl regex pattern instead. 3916 3917=head2 stap_out_unlike 3918 3919Just like C<stap_like>, but the subtest only passes when the specified pattern does I<not> match the output of the systemtap script. 3920 3921=head2 wait 3922 3923Takes an integer value for the seconds of time to wait right after processing the Nginx response and 3924before performing the error log and/or systemtap output checks. 3925 3926=head2 udp_listen 3927 3928Instantiates a UDP server listening on the port specified in the background for the test 3929case to access. The server will be started and shut down at each iteration of the test case 3930(if repeat_each is set to 3, then there are 3 iterations). 3931 3932The UDP server will first read and discard a datagram and then send back a datagram with the content 3933specified by the C<udp_reply> section value. 3934 3935Here is an example: 3936 3937 === TEST 1: udp access 3938 --- config 3939 location = /t { 3940 content_by_lua ' 3941 local udp = ngx.socket.udp() 3942 udp:setpeername("127.0.0.1", 19232) 3943 udp:send("blah") 3944 local data, err = udp:receive() 3945 ngx.say("received: ", data) 3946 '; 3947 } 3948 --- udp_listen: 19232 3949 --- udp_reply: hello world 3950 --- request 3951 GET /t 3952 --- response_body 3953 received: hello world 3954 3955Datagram UNIX domain socket is also supported if a path name ending with ".sock" is given to this directive. For instance, 3956 3957 === TEST 2: datagram unix domain socket access 3958 --- config 3959 location = /t { 3960 content_by_lua ' 3961 local udp = ngx.socket.udp() 3962 udp:setpeername("unix:a.sock") 3963 udp:send("blah") 3964 local data, err = udp:receive() 3965 ngx.say("received: ", data) 3966 '; 3967 } 3968 --- udp_listen: a.sock 3969 --- udp_reply: hello world 3970 --- request 3971 GET /t 3972 --- response_body 3973 received: hello world 3974 3975=head2 udp_reply 3976 3977This section specifies the datagram reply content for the UDP server created by the C<udp_listen> section. 3978 3979You can also specify a delay time before sending out the reply via the C<udp_reply_delay> section. By default, there is no delay. 3980 3981An array value can be specified to make the embedded UDP server to send multiple replies as specified, for example: 3982 3983 --- udp_reply eval 3984 [ "hello", "world" ] 3985 3986This section also accepts a Perl subroutine value that can be used to 3987generate dynamic response packet or packets based on the actual query, for example: 3988 3989 --- udp_reply eval 3990 sub { 3991 my $req = shift; 3992 return "hello, $req"; 3993 } 3994 3995The custom Perl subroutine can also return an array reference, for example, 3996 3997 --- udp_reply eval 3998 sub { 3999 my $req = shift; 4000 return ["hello, $req", "hiya, $req"]; 4001 } 4002 4003See the C<udp_listen> section for more details. 4004 4005=head2 udp_reply_delay 4006 4007This section specifies the delay time before sending out the reply specified by the C<udp_reply> section. 4008 4009It is C<0> delay by default. 4010 4011An optional time unit can be specified, for example, 4012 4013 --- udp_reply_delay: 50ms 4014 4015Acceptable time units are C<s> (seconds) and C<ms> (milliseconds). If no time unit is specified, then default to seconds. 4016 4017=head2 udp_query 4018 4019Tests whether the UDP query sent to the embedded UDP server is equal to what is specified by this directive. 4020 4021For example, 4022 4023 === TEST 1: udp access 4024 --- config 4025 location = /t { 4026 content_by_lua ' 4027 local udp = ngx.socket.udp() 4028 udp:setpeername("127.0.0.1", 19232) 4029 udp:send("blah") 4030 local data, err = udp:receive() 4031 ngx.say("received: ", data) 4032 '; 4033 } 4034 --- udp_listen: 19232 4035 --- udp_reply: hello world 4036 --- request 4037 GET /t 4038 --- udp_query: hello world 4039 --- response_body 4040 received: hello world 4041 4042=head2 tcp_listen 4043 4044Just like C<udp_listen>, but starts an embedded TCP server listening on the port specified. For example, 4045 4046 --- tcp_listen: 12345 4047 4048Stream-typed unix domain socket is also supported. Just specify the path to the socket file, as in 4049 4050 --- tcp_listen: /tmp/my-socket.sock 4051 4052=head2 tcp_no_close 4053 4054When this section is present, the embedded TCP server (if any) will not close 4055the current TCP connection. 4056 4057=head2 tcp_reply_delay 4058 4059Just like C<udp_reply_delay>, but for the embedded TCP server. 4060 4061=head2 tcp_reply 4062 4063Just like C<udp_reply>, but for the embedded TCP server. 4064 4065Like the C<udp_reply> section, this section also accepts a Perl subroutine value 4066that can be used to generate dynamic response packet or packets based on the actual query, for example: 4067 4068 --- tcp_reply eval 4069 sub { 4070 my $req = shift; 4071 return "hello, $req"; 4072 } 4073 4074The custom Perl subroutine can also return an array reference, for example, 4075 4076 --- tcp_reply eval 4077 sub { 4078 my $req = shift; 4079 return ["hello, $req", "hiya, $req"]; 4080 } 4081 4082=head2 tcp_query 4083 4084Just like C<udp_query>, but for the embedded TCP server. 4085 4086=head2 tcp_query_len 4087 4088Specifies the expected TCP query received by the embedded TCP server. 4089 4090If C<tcp_query> is specified, C<tcp_query_len> defaults to the length of the value of C<tcp_query>. 4091 4092=head2 tcp_shutdown 4093 4094Shuts down the reading part, writing part, or both in the embedded TCP server as soon as a new connection is established. Its value specifies which part to shut down: 0 for read part only, 1 for write part only, and 2 for both directions. 4095 4096=head2 raw_request_middle_delay 4097 4098Delay in sec between sending successive packets in the "raw_request" array 4099value. Also used when a request is split in packets. 4100 4101=head2 no_check_leak 4102 4103Skip the tests in the current test block in the "check leak" testing mode 4104(i.e, with C<TEST_NGINX_CHECK_LEAK>=1). 4105 4106=head2 must_die 4107 4108Test the cases that Nginx must die right after starting. If a value is specified, the exit code must match the specified value. 4109 4110Normal request and response cycle is not done. But you can still use the 4111C<error_log> section to check if there is an error message to be seen. 4112 4113This is meant to test bogus configuration is noticed and given proper 4114error message. It is normal to see stderr error message when running these tests. 4115 4116Below is an example: 4117 4118 === TEST 1: bad "return" directive 4119 --- config 4120 location = /t { 4121 return a b c; 4122 } 4123 --- request 4124 GET /t 4125 --- must_die 4126 --- error_log 4127 invalid number of arguments in "return" directive 4128 --- no_error_log 4129 [error] 4130 4131This configuration ignores C<TEST_NGINX_USE_VALGRIND> 4132C<TEST_NGINX_USE_STAP> or C<TEST_NGINX_CHECK_LEAK> since there is no point to check other things when the nginx is expected to die right away. 4133 4134This directive is handled before checking C<TEST_NGINX_IGNORE_MISSING_DIRECTIVES>. 4135 4136=head2 server_addr_for_client 4137 4138This section specifies the server address Test::Nginx will connect to. If server_addr_for_client is not set, then 127.0.0.1 is used. 4139 4140=head1 Environment variables 4141 4142All environment variables starting with C<TEST_NGINX_> are expanded in the 4143sections used to build the configuration of the server that tests automatically 4144starts. The following environment variables are supported by this module: 4145 4146=head2 TEST_NGINX_REUSE_PORT 4147 4148When this environment is set to a true value, the test scaffold would add the "resuseport" 4149parameter to the "listen" directive automatically generated in F<nginx.conf>. 4150 4151=head2 TEST_NGINX_USE_HTTP2 4152 4153Enables the "http2" test mode by enforcing using the (plain text) HTTP/2 protocol to send the 4154test request. 4155 4156Under the hood, the test scaffold uses the `curl` command-line utility to do the wire communication 4157with the NGINX server. The `curl` utility must be recent enough to support both the C<--http2> 4158and C<--http2-prior-knowledge> command-line options. 4159 4160B<WARNING:> not all the sections and features are supported in the "http2" test mode. For example, the L<pipelined_requests> and 4161L<raw_request> will still use the HTTP/1 protocols even in the "http2" test mode. Similarly, test blocks explicitly require 4162the HTTP 1.0 protocol will still use HTTP 1.0. 4163 4164One can enable HTTP/2 mode for an individual test block by specifying the L<http2> section, as in 4165 4166 --- http2 4167 4168=head2 TEST_NGINX_VERBOSE 4169 4170Controls whether to output verbose debugging messages in Test::Nginx. Default to empty. 4171 4172=head2 TEST_NGINX_BENCHMARK 4173 4174When set to an non-empty and non-zero value, then the test scaffold enters the benchmarking testing mode by invoking C<weighttp> (for HTTP 1.1 requests) and C<ab> (for HTTP 1.0 requests) 4175to run each test case with the test request repeatedly. 4176 4177When specifying a positive number as the value, then this number is used for the total number of repeated requests. For example, 4178 4179 export TEST_NGINX_BENCHMARK=1000 4180 4181will result in 1000 repeated requests for each test block. Default to C<100000>. 4182 4183When a second number is specified (separated from the first number by spaces), then this second number is used for the concurrency level for the benchmark. For example, 4184 4185 export TEST_NGINX_BENCHMARK='1000 10' 4186 4187will result in 1000 repeated requests over 10 concurrent connections for each test block. The default concurrency level is 2 (or 1 if the number of requests is 1). 4188 4189The "benchmark" testing mode will also output to stderr the actual "ab" or "weighttp" command line used by the test scaffold. For example, 4190 4191 weighttp -c2 -k -n2000 -H 'Host: foo.com' http://127.0.0.1:1984/t 4192 4193See also the C<TEST_NGINX_BENCHMARK_WARMUP> environment. 4194 4195This testing mode requires the C<unbuffer> command-line utility from the C<expect> package. 4196 4197=head2 TEST_NGINX_BENCHMARK_WARMUP 4198 4199Specify the number of "warm-up" requests performed before the actual benchmark requests for each test block. 4200 4201The latencies of the warm-up requests never get included in the final benchmark results. 4202 4203Only meaningful in the "benchmark" testing mode. 4204 4205See also the C<TEST_NGINX_BENCHMARK> environment. 4206 4207=head2 TEST_NGINX_CHECK_LEAK 4208 4209When set to 1, the test scaffold performs the most general memory 4210leak test by means of calling C<weighttpd>/C<ab> and C<ps>. 4211 4212Specifically, it starts C<weighttp> (for HTTP 1.1 C<GET> requests) or 4213C<ab> (for HTTP 1.0 requests) to repeatedly hitting Nginx for 4214seconds in a sub-process, and then after about 1 second, it will 4215start sampling the RSS value of the Nginx process by calling 4216the C<ps> utility every 20 ms. Finally, it will output all 4217the sample point data and the 4218line slope of the linear regression result on the 100 sample points. 4219 4220One typical output for non-leaking test cases: 4221 4222 t/075-logby.t .. 3/17 TEST 2: log_by_lua_file 4223 LeakTest: [2176 2176 2176 2176 2176 2176 2176 4224 2176 2176 2176 2176 2176 2176 2176 2176 2176 4225 2176 2176 2176 2176 2176 2176 2176 2176 2176 4226 2176 2176 2176 2176 2176 2176 2176 2176 2176 4227 2176 2176 2176 2176 2176 2176 2176 2176 2176 4228 2176 2176 2176 2176 2176 2176 2176 2176 2176 4229 2176 2176 2176 2176 2176 2176 2176 2176 2176 4230 2176 2176 2176 2176 2176 2176 2176 2176 2176 4231 2176 2176 2176 2176 2176 2176 2176 2176 2176 4232 2176 2176 2176 2176 2176 2176 2176 2176 2176 4233 2176 2176 2176 2176 2176 2176 2176 2176 2176 4234 2176 2176 2176] 4235 LeakTest: k=0.0 4236 4237and here is an example of leaking: 4238 4239 TEST 5: ngx.ctx available in log_by_lua (not defined yet) 4240 LeakTest: [4396 4440 4476 4564 4620 4708 4752 4241 4788 4884 4944 4996 5032 5080 5132 5188 5236 4242 5348 5404 5464 5524 5596 5652 5700 5776 5828 4243 5912 5964 6040 6108 6108 6316 6316 6584 6672 4244 6672 6752 6820 6912 6912 6980 7064 7152 7152 4245 7240 7340 7340 7432 7508 7508 7600 7700 7700 4246 7792 7896 7896 7992 7992 8100 8100 8204 8296 4247 8296 8416 8416 8512 8512 8624 8624 8744 8744 4248 8848 8848 8968 8968 9084 9084 9204 9204 9324 4249 9324 9444 9444 9584 9584 9704 9704 9832 9832 4250 9864 9964 9964 10096 10096 10488 10488 10488 4251 10488 10488 11052 11052] 4252 LeakTest: k=64.1 4253 4254Even very small leaks can be amplified and caught easily by this 4255testing mode because their slopes will usually be far above C<1.0>. 4256 4257One can configure the number of sample points via the L<TEST_NGINX_CHECK_LEAK_COUNT> 4258system environment, for example, to sample 1000 data points, we can set 4259the following environment I<before> running the test: 4260 4261 export TEST_NGINX_CHECK_LEAK_COUNT=1000 4262 4263For now, only C<GET>, C<POST>, C<PUT>, and C<HEAD> requests are supported 4264(due to the limited HTTP support in both C<ab> and C<weighttp>). 4265Other methods specified in the test cases will turn to C<GET> with force. 4266 4267The tests in this mode will always succeed because this mode also 4268enforces the "dry-run" mode. 4269 4270Test blocks carrying the "--- no_check_leak" directive will be skipped in this testing mode. 4271 4272=head2 TEST_NGINX_CHECK_LEAK_COUNT 4273 4274Takes a number value which controls how many data points to be sampled 4275in the "check leak" test mode. See L<TEST_NGINX_CHECK_LEAK> for more details. 4276 4277Defaults to 100. 4278 4279=head2 TEST_NGINX_USE_HUP 4280 4281When set to 1, the test scaffold will try to send C<HUP> signal to the 4282Nginx master process to reload the config file between 4283successive test blocks (but not successive C<repeat_each> 4284sub-tests within the same test block). When this environment is set 4285to 1, it will also enforce the "master_process on" config line 4286in the F<nginx.conf> file, 4287because Nginx is buggy in processing HUP signal when the master process is off. 4288 4289=head2 TEST_NGINX_LOAD_MODULES 4290 4291This environment takes a list of dynamic NGINX module files' paths. The test scaffold generates 4292a series of C<load_module> directives in the top-level scope of F<nginx.conf>. 4293 4294For example, when this environment takes the value C<../../work/nginx/modules/ngx_http_headers_more_filter_module.so ../../work/nginx/modules/ngx_http_lua_module.so >, 4295then the following snippet will be generated in F<nginx.conf>: 4296 4297 load_module ../../work/nginx/modules/ngx_http_headers_more_filter_module.so; 4298 load_module ../../work/nginx/modules/ngx_http_lua_module.so; 4299 4300This requires at least NGINX 1.9.11 to work. 4301 4302=head2 TEST_NGINX_POSTPONE_OUTPUT 4303 4304Defaults to empty. This environment takes positive integer numbers as its value and it will cause the auto-generated nginx.conf file to have a "postpone_output" setting in the http {} block. 4305 4306For example, setting TEST_NGINX_POSTPONE_OUTPUT to 1 will have the following line in nginx.conf's http {} block: 4307 4308 postpone_output 1; 4309 4310and it will effectively disable the write buffering in nginx's ngx_http_write_module. 4311 4312=head2 TEST_NGINX_NO_CLEAN 4313 4314When this environment is set to 1, it will prevent the test scaffold from quitting the Nginx server 4315at the end of the run. This is very useful when you want to use other tools like gdb or curl 4316inspect the Nginx server manually afterwards. 4317 4318=head2 TEST_NGINX_NO_NGINX_MANAGER 4319 4320Defaults to 0. If set to 1, Test::Nginx module will not manage 4321(configure/start/stop) the C<nginx> process. Can be useful to run tests 4322against an already configured (and running) nginx server. 4323 4324=head2 TEST_NGINX_NO_SHUFFLE 4325 4326Defaults to 0. If set to 1, will make sure the tests are run in the order 4327they appear in the test file (and not in random order). 4328 4329=head2 TEST_NGINX_USE_VALGRIND 4330 4331If set, Test::Nginx will start nginx with valgrind with the the value of this environment as the options. 4332 4333Nginx is actually started with 4334C<valgrind -q $TEST_NGINX_USE_VALGRIND --gen-suppressions=all --suppressions=valgrind.suppress>, 4335the suppressions option being used only if there is actually 4336a valgrind.suppress file. 4337 4338If this environment is set to the number C<1> or any other 4339non-zero numbers, then it is equivalent to taking the value 4340C<--tool=memcheck --leak-check=full>. 4341 4342=head2 TEST_NGINX_USE_RR 4343 4344Uses Mozilla rr to record the execution of the nginx server run by the test 4345scaffold. 4346 4347This feature is experimental. 4348 4349=head2 TEST_NGINX_USE_STAP 4350 4351When set to true values (like 1), the test scaffold will use systemtap to instrument the nginx 4352process. 4353 4354You can specify the stap script in the C<stap> section. 4355 4356Note that you need to use the C<stap-nginx> script from the C<nginx-dtrace> project. 4357 4358=head2 TEST_NGINX_STAP_OUT 4359 4360You can specify the output file for the systemtap tool. By default, a random file name 4361under the system temporary directory is generated. 4362 4363It's common to specify C<TEST_NGINX_STAP_OUT=/dev/stderr> when debugging. 4364 4365=head2 TEST_NGINX_BINARY 4366 4367The command to start nginx. Defaults to C<nginx>. Can be used as an alternative 4368to setting C<PATH> to run a specific nginx instance. 4369 4370=head2 TEST_NGINX_LOG_LEVEL 4371 4372Value of the last argument of the C<error_log> configuration directive. 4373Defaults to C<debug>. 4374 4375=head2 TEST_NGINX_MASTER_PROCESS 4376 4377Value of the C<master_process> configuration directive. Defaults to C<off>. 4378 4379=head2 TEST_NGINX_SERVER_PORT 4380 4381Value of the port the server started by Test::Nginx will listen to. If not 4382set, C<TEST_NGINX_PORT> is used. If C<TEST_NGINX_PORT> is not set, 4383then C<1984> is used. See below for typical use. 4384 4385=head2 TEST_NGINX_CLIENT_PORT 4386 4387Value of the port Test::Nginx will direct requests to. If not 4388set, C<TEST_NGINX_PORT> is used. If C<TEST_NGINX_PORT> is not set, 4389then C<1984> is used. A typical use of this feature is to test extreme 4390network conditions by adding a "proxy" between Test::Nginx and nginx 4391itself. This is described in the C<etcproxy integration> section of this 4392module README. 4393 4394=head2 TEST_NGINX_PORT 4395 4396A shortcut for setting both C<TEST_NGINX_CLIENT_PORT> and 4397C<TEST_NGINX_SERVER_PORT>. 4398 4399=head2 TEST_NGINX_SLEEP 4400 4401How much time (in seconds) should Test::Nginx sleep between two calls to C<syswrite> when 4402sending request data. Defaults to 0.015 (seconds). 4403 4404=head2 TEST_NGINX_FORCE_RESTART_ON_TEST 4405 4406Defaults to 1. If set to 0, Test::Nginx will not restart the nginx 4407server when the config does not change between two tests. 4408 4409=head2 TEST_NGINX_SERVROOT 4410 4411The root of the nginx "hierarchy" (where you find the conf, *_tmp and logs 4412directories). This value will be used with the C<-p> option of C<nginx>. 4413Defaults to appending C<t/servroot> to the current directory. 4414 4415=head2 TEST_NGINX_IGNORE_MISSING_DIRECTIVES 4416 4417If set to 1 will SKIP all tests which C<config> sections resulted in a 4418C<unknown directive> when trying to start C<nginx>. Useful when you want to 4419run tests on a build of nginx that does not include all modules it should. 4420By default, these tests will FAIL. 4421 4422=head2 TEST_NGINX_EVENT_TYPE 4423 4424This environment can be used to specify a event API type to be used by Nginx. Possible values are C<epoll>, C<kqueue>, C<select>, C<rtsig>, C<poll>, and others. 4425 4426For example, 4427 4428 $ TEST_NGINX_EVENT_TYPE=select prove -r t 4429 4430=head2 TEST_NGINX_ERROR_LOG 4431 4432Error log files from all tests will be appended to the file specified with 4433this variable. There is no default value which disables the feature. This 4434is very useful when debugging. By default, each test triggers a start/stop 4435cycle for C<nginx>. All logs are removed before each restart, so you can 4436only see the logs for the last test run (which you usually do not control 4437except if you set C<TEST_NGINX_NO_SHUFFLE=1>). With this, you accumulate 4438all logs into a single file that is never cleaned up by Test::Nginx. 4439 4440=head2 TEST_NGINX_RANDOMIZE 4441 4442When set, the test scaffold forces the use of random server listening port numbers as 4443well as random C<t/servroot_XXXX/> directories. This can help test suite run in multiple 4444parallel jobs via C<prove -jN> where C<N> is an integer bigger than 1. For instance, 4445C<prove -j8 -r t> runs the test suite under F<t/> in 8 parallel jobs, utilizing up to 44468 (logical) CPU cores in the same machine. 4447 4448Note that only test suite I<without> external shared and writable service dependencies (like Memcached, 4449Redis or MySQL) can run in parallel in this way, obviously. 4450 4451=head2 TEST_NGINX_WORKER_USER 4452 4453Sets the user account used to run the nginx worker processes when the master process is enabled. 4454This requires root access to run the nginx master process. For instance, 4455 4456 export TEST_NGINX_WORKER_USER='agentzh' 4457 4458Defaults to the `root` when the master is run by `root` also. Otherwise defaults to the current 4459user. 4460 4461One can also add an optional user group separated by spaces, as in 4462 4463 export TEST_NGINX_WORKER_USER='agentzh wheel' 4464 4465=head2 Special Variables 4466 4467=head3 TEST_NGINX_RAND_PORT_XXX 4468 4469Variables like C<TEST_NGINX_RAND_PORT_XXX> are expanded to random and unused 4470unprivileged ports numbers to build the configuration of the server, 4471where C<XXX> is an integer from 1985 to 65535. 4472 4473For instance, C<TEST_NGINX_RAND_PORT_1> will be expanded to an port number, 4474such as 1986, and C<TEST_NGINX_RAND_PORT_2> will be expanded to another port 4475number, such as 65535. 4476 4477=head2 Valgrind Integration 4478 4479Test::Nginx has integrated support for valgrind (L<http://valgrind.org>) even though by 4480default it does not bother running it with the tests because valgrind 4481will significantly slow down the test suite. 4482 4483First ensure that your valgrind executable visible in your PATH env. 4484And then run your test suite with the C<TEST_NGINX_USE_VALGRIND> env set 4485to true: 4486 4487 TEST_NGINX_USE_VALGRIND=1 prove -r t 4488 4489If you see false alarms, you do have a chance to skip them by defining 4490a ./valgrind.suppress file at the root of your module source tree, as 4491in 4492 4493L<https://github.com/chaoslawful/drizzle-nginx-module/blob/master/valgrind.suppress> 4494 4495This is the suppression file for ngx_drizzle. Test::Nginx will 4496automatically use it to start nginx with valgrind memcheck if this 4497file does exist at the expected location. 4498 4499If you do see a lot of "Connection refused" errors while running the 4500tests this way, then you probably have a slow machine (or a very busy 4501one) that the default waiting time is not sufficient for valgrind to 4502start. You can define the sleep time to a larger value by setting the 4503C<TEST_NGINX_SLEEP> env: 4504 4505 TEST_NGINX_SLEEP=1 prove -r t 4506 4507The time unit used here is "second". The default sleep setting just 4508fits my ThinkPad (C<Core2Duo T9600>). 4509 4510Applying the no-pool patch to your nginx core is recommended while 4511running nginx with valgrind: 4512 4513L<https://github.com/shrimp/no-pool-nginx> 4514 4515The nginx memory pool can prevent valgrind from spotting lots of 4516invalid memory reads/writes as well as certain double-free errors. We 4517did find a lot more memory issues in many of our modules when we first 4518introduced the no-pool patch in practice ;) 4519 4520There's also more advanced features in Test::Nginx that have never 4521documented. I'd like to write more about them in the near future ;) 4522 4523=head2 Etcproxy Integration 4524 4525B<WARNING:> use etcproxy is no longer recommended because the mockeagain is way more effective and efficient: 4526 4527L<https://github.com/openresty/mockeagain> 4528 4529The default settings in etcproxy (https://github.com/chaoslawful/etcproxy) 4530makes this small TCP proxy split the TCP packets into bytes and introduce 1 ms latency among them. 4531 4532There's usually various TCP chains that we can put etcproxy into, for example 4533 4534=head3 Test::Nginx <=> nginx 4535 4536 $ ./etcproxy 1234 1984 4537 4538Here we tell etcproxy to listen on port 1234 and to delegate all the 4539TCP traffic to the port 1984, the default port that Test::Nginx makes 4540nginx listen to. 4541 4542And then we tell Test::Nginx to test against the port 1234, where 4543etcproxy listens on, rather than the port 1984 that nginx directly 4544listens on: 4545 4546 $ TEST_NGINX_CLIENT_PORT=1234 prove -r t/ 4547 4548Then the TCP chain now looks like this: 4549 4550 Test::Nginx <=> etcproxy (1234) <=> nginx (1984) 4551 4552So etcproxy can effectively emulate extreme network conditions and 4553exercise "unusual" code paths in your nginx server by your tests. 4554 4555In practice, *tons* of weird bugs can be captured by this setting. 4556Even ourselves didn't expect that this simple approach is so 4557effective. 4558 4559=head3 nginx <=> memcached 4560 4561We first start the memcached server daemon on port 11211: 4562 4563 memcached -p 11211 -vv 4564 4565and then we another etcproxy instance to listen on port 11984 like this 4566 4567 $ ./etcproxy 11984 11211 4568 4569Then we tell our t/foo.t test script to connect to 11984 rather than 11211: 4570 4571 # foo.t 4572 use Test::Nginx::Socket; 4573 repeat_each(1); 4574 plan tests => 2 * repeat_each() * blocks(); 4575 $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; # make this env take a default value 4576 run_tests(); 4577 4578 __DATA__ 4579 4580 === TEST 1: sanity 4581 --- config 4582 location /foo { 4583 set $memc_cmd set; 4584 set $memc_key foo; 4585 set $memc_value bar; 4586 memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; 4587 } 4588 --- request 4589 GET /foo 4590 --- response_body_like: STORED 4591 --- error_code: 201 4592 4593The Test::Nginx library will automatically expand the special macro 4594C<$TEST_NGINX_MEMCACHED_PORT> to the environment with the same name. 4595You can define your own C<$TEST_NGINX_BLAH_BLAH_PORT> macros as long as 4596its prefix is C<TEST_NGINX_> and all in upper case letters. 4597 4598And now we can run your test script against the etcproxy port 11984: 4599 4600 TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t 4601 4602Then the TCP chains look like this: 4603 4604 Test::Nginx <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) 4605 4606If C<TEST_NGINX_MEMCACHED_PORT> is not set, then it will take the default 4607value 11211, which is what we want when there's no etcproxy 4608configured: 4609 4610 Test::Nginx <=> nginx (1984) <=> memcached (11211) 4611 4612This approach also works for proxied mysql and postgres traffic. 4613Please see the live test suite of ngx_drizzle and ngx_postgres for 4614more details. 4615 4616Usually we set both C<TEST_NGINX_CLIENT_PORT> and 4617C<TEST_NGINX_MEMCACHED_PORT> (and etc) at the same time, effectively 4618yielding the following chain: 4619 4620 Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211) 4621 4622as long as you run two separate etcproxy instances in two separate terminals. 4623 4624It's easy to verify if the traffic actually goes through your etcproxy 4625server. Just check if the terminal running etcproxy emits outputs. By 4626default, etcproxy always dump out the incoming and outgoing data to 4627stdout/stderr. 4628 4629=head1 SOURCE REPOSITORY 4630 4631This module has a Git repository on Github, which has access for all: 4632 4633L<https://github.com/openresty/test-nginx> 4634 4635If you want a commit bit, feel free to drop me a line. 4636 4637=head1 Community 4638 4639=head2 English Mailing List 4640 4641The C<openresty-en> mailing list is for English speakers: L<https://groups.google.com/group/openresty-en> 4642 4643=head2 Chinese Mailing List 4644 4645The C<openresty> mailing list is for Chinese speakers: L<https://groups.google.com/group/openresty> 4646 4647=head1 AUTHORS 4648 4649Yichun "agentzh" Zhang (章亦春) C<< <agentzh@gmail.com> >>, OpenResty Inc. 4650 4651Antoine BONAVITA C<< <antoine.bonavita@gmail.com> >> 4652 4653=head1 COPYRIGHT & LICENSE 4654 4655Copyright (c) 2009-2016, Yichun Zhang C<< <agentzh@gmail.com> >>, OpenResty Inc. 4656 4657Copyright (c) 2011-2012, Antoine BONAVITA C<< <antoine.bonavita@gmail.com> >>. 4658 4659This module is licensed under the terms of the BSD license. 4660 4661Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4662 4663=over 4664 4665=item * 4666 4667Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 4668 4669=item * 4670 4671Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 4672 4673=item * 4674 4675Neither the name of the authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 4676 4677=back 4678 4679THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4680 4681=head1 SEE ALSO 4682 4683L<Test::Nginx::Lua>, L<Test::Nginx::Lua::Stream>, L<Test::Nginx::LWP>, L<Test::Base>. 4684 4685