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