File Coverage

lib/Test/Nginx/Util.pm
Criterion Covered Total %
statement 72 1159 6.2
branch 10 742 1.3
condition 3 207 1.4
subroutine 21 79 26.5
pod 0 58 0.0
total 106 2245 4.7


line stmt bran cond sub pod time code
1             package Test::Nginx::Util;
2              
3 5     5   37 use strict;
  5         17  
  5         155  
4 5     5   25 use warnings;
  5         10  
  5         213  
5              
6             our $VERSION = '0.29';
7              
8 5     5   34 use base 'Exporter';
  5         12  
  5         35  
9              
10 5     5   36 use POSIX qw( SIGQUIT SIGKILL SIGTERM SIGHUP );
  5         29  
  5         34  
11 5     5   445 use File::Spec ();
  5         9  
  5         102  
12 5     5   2636 use HTTP::Response;
  5         27728  
  5         194  
13 5     5   41 use Cwd qw( cwd );
  5         12  
  5         332  
14 5     5   32 use List::Util qw( shuffle );
  5         9  
  5         306  
15 5     5   34 use Time::HiRes qw( sleep );
  5         11  
  5         49  
16 5     5   681 use File::Path qw(make_path remove_tree);
  5         18  
  5         300  
17 5     5   35 use File::Find qw(find);
  5         13  
  5         449  
18 5     5   35 use File::Temp qw( tempfile :POSIX );
  5         10  
  5         620  
19 5     5   34 use Scalar::Util qw( looks_like_number );
  5         17  
  5         296  
20 5     5   2640 use IO::Socket::INET;
  5         64566  
  5         31  
21 5     5   2383 use IO::Socket::UNIX;
  5         12  
  5         37  
22 5     5   4127 use Test::LongString;
  5         11  
  5         55  
23 5     5   512 use Carp qw( croak );
  5         17  
  5         89781  
24              
25             our $ConfigVersion;
26             our $FilterHttpConfig;
27             my $LoadedIPCRun;
28              
29             our $NoLongString = undef;
30             our $FirstTime = 1;
31              
32             our $ReusePort = $ENV{TEST_NGINX_REUSE_PORT};
33              
34             our $UseHttp2 = $ENV{TEST_NGINX_USE_HTTP2};
35              
36             our $UseHup = $ENV{TEST_NGINX_USE_HUP};
37              
38             our $UseRr = $ENV{TEST_NGINX_USE_RR};
39              
40             our $Verbose = $ENV{TEST_NGINX_VERBOSE};
41              
42             our $LatestNginxVersion = 0.008039;
43              
44             our $NoNginxManager = $ENV{TEST_NGINX_NO_NGINX_MANAGER} || 0;
45             our $Profiling = 0;
46              
47             sub use_http2 ($);
48              
49             our $InSubprocess;
50             our $RepeatEach = 1;
51             our $MAX_PROCESSES = 10;
52              
53             our $LoadModules = $ENV{TEST_NGINX_LOAD_MODULES};
54              
55             our $NoShuffle = $ENV{TEST_NGINX_NO_SHUFFLE} || 0;
56              
57             our $UseValgrind = $ENV{TEST_NGINX_USE_VALGRIND};
58              
59             our $UseStap = $ENV{TEST_NGINX_USE_STAP};
60              
61             our $StapOutFile = $ENV{TEST_NGINX_STAP_OUT};
62              
63             our $EventType = $ENV{TEST_NGINX_EVENT_TYPE};
64              
65             our $PostponeOutput = $ENV{TEST_NGINX_POSTPONE_OUTPUT};
66              
67             our $Timeout = $ENV{TEST_NGINX_TIMEOUT} || 3;
68              
69             our $CheckLeak = $ENV{TEST_NGINX_CHECK_LEAK} || 0;
70              
71             our $Benchmark = $ENV{TEST_NGINX_BENCHMARK} || 0;
72              
73             our $BenchmarkWarmup = $ENV{TEST_NGINX_BENCHMARK_WARMUP} || 0;
74              
75             our $CheckAccumErrLog = $ENV{TEST_NGINX_CHECK_ACCUM_ERR_LOG};
76              
77             our $ServerAddr = '127.0.0.1';
78              
79             our $ServerName = 'localhost';
80              
81             our $WorkerUser = $ENV{TEST_NGINX_WORKER_USER};
82             if (defined $WorkerUser && $WorkerUser !~ /^\w+(?:\s+\w+)?$/) {
83             die "Bad value in the env TEST_NGINX_WORKER_USER: $WorkerUser\n";
84             }
85              
86             our $StapOutFileHandle;
87              
88             our @RandStrAlphabet = ('A' .. 'Z', 'a' .. 'z', '0' .. '9',
89             '#', '@', '-', '_', '^');
90              
91             our $PrevBlock;
92              
93             our $ErrLogFilePos;
94              
95             if ($Benchmark) {
96             if ($UseStap) {
97             warn "WARNING: TEST_NGINX_BENCHMARK and TEST_NGINX_USE_STAP "
98             ."are both set and the former wins.\n";
99             undef $UseStap;
100             }
101              
102             if ($UseValgrind) {
103             warn "WARNING: TEST_NGINX_BENCHMARK and TEST_NGINX_USE_VALGRIND "
104             ."are both set and the former wins.\n";
105             undef $UseValgrind;
106             }
107              
108             if ($UseHup) {
109             warn "WARNING: TEST_NGINX_BENCHMARK and TEST_NGINX_USE_HUP "
110             ."are both set and the former wins.\n";
111             undef $UseHup;
112             }
113              
114             if ($CheckLeak) {
115             warn "WARNING: TEST_NGINX_BENCHMARK and TEST_NGINX_CHECK_LEAK "
116             ."are both set and the former wins.\n";
117             undef $CheckLeak;
118             }
119             }
120              
121             if ($CheckLeak) {
122             if ($UseStap) {
123             warn "WARNING: TEST_NGINX_CHECK_LEAK and TEST_NGINX_USE_STAP "
124             ."are both set and the former wins.\n";
125             undef $UseStap;
126             }
127              
128             if ($UseValgrind) {
129             warn "WARNING: TEST_NGINX_CHECK_LEAK and TEST_NGINX_USE_VALGRIND "
130             ."are both set and the former wins.\n";
131             undef $UseValgrind;
132             }
133              
134             if ($UseHup) {
135             warn "WARNING: TEST_NGINX_CHECK_LEAK and TEST_NGINX_USE_HUP "
136             ."are both set and the former wins.\n";
137             undef $UseHup;
138             }
139             }
140              
141             if ($UseHup) {
142             if ($UseStap) {
143             warn "WARNING: TEST_NGINX_USE_HUP and TEST_NGINX_USE_STAP "
144             ."are both set and the former wins.\n";
145             undef $UseStap;
146             }
147             }
148              
149             if ($UseValgrind) {
150             if ($UseStap) {
151             warn "WARNING: TEST_NGINX_USE_VALGRIND and TEST_NGINX_USE_STAP "
152             ."are both set and the former wins.\n";
153             undef $UseStap;
154             }
155             }
156              
157             #$SIG{CHLD} = 'IGNORE';
158              
159             sub is_running ($) {
160 0     0 0 0 my $pid = shift;
161 0         0 return kill 0, $pid;
162             }
163              
164             sub gen_rand_str {
165 0     0 0 0 my $len = shift;
166              
167 0         0 my $s = '';
168 0         0 for (my $i = 0; $i < $len; $i++) {
169 0         0 my $j = int rand scalar @RandStrAlphabet;
170 0         0 my $c = $RandStrAlphabet[$j];
171 0         0 $s .= $c;
172             }
173              
174 0         0 return $s;
175             }
176              
177             sub gen_rand_port (;$$) {
178 0     0 0 0 my ($tries, $used_ports) = @_;
179              
180 0   0     0 $tries //= 1000;
181 0   0     0 $used_ports //= {};
182              
183 0         0 my $rand_port;
184              
185 0         0 for (my $i = 0; $i < $tries; $i++) {
186 0         0 my $port = int(rand 63550) + 1985;
187              
188 0 0       0 next if $used_ports->{$port};
189              
190 0         0 my $sock = IO::Socket::INET->new(
191             LocalAddr => $ServerAddr,
192             LocalPort => $port,
193             Proto => 'tcp',
194             Timeout => 0.1,
195             );
196              
197 0 0       0 if (defined $sock) {
198 0         0 $sock->close();
199 0         0 $rand_port = $port;
200 0         0 last;
201             }
202              
203 0 0       0 if ($Verbose) {
204 0         0 warn "Try again, port $port is already in use: $@\n";
205             }
206             }
207              
208 0         0 return $rand_port;
209             }
210              
211             sub no_long_string () {
212 0     0 0 0 $NoLongString = 1;
213             }
214              
215             sub is_str (@) {
216 0     0 0 0 my ($got, $expected, $desc) = @_;
217              
218 0 0 0     0 if (ref $expected && ref $expected eq 'Regexp') {
219 0         0 return Test::More::like($got, $expected, $desc);
220             }
221              
222 0 0       0 if ($NoLongString) {
223 0         0 return Test::More::is($got, $expected, $desc);
224             }
225              
226 0         0 return is_string($got, $expected, $desc);
227             }
228              
229             sub server_addr (@) {
230 0 0   0 0 0 if (@_) {
231              
232             #warn "setting server addr to $_[0]\n";
233 0         0 $ServerAddr = shift;
234             }
235             else {
236 0         0 return $ServerAddr;
237             }
238             }
239              
240             sub server_name (@) {
241 0 0   0 0 0 if (@_) {
242 0         0 $ServerName = shift;
243              
244             } else {
245 0         0 return $ServerName;
246             }
247             }
248              
249             sub stap_out_fh {
250 0     0 0 0 return $StapOutFileHandle;
251             }
252              
253             sub stap_out_fname {
254 0     0 0 0 return $StapOutFile;
255             }
256              
257             sub timeout (@) {
258 0 0   0 0 0 if (@_) {
259 0         0 $Timeout = shift;
260             }
261             else {
262 0         0 $Timeout;
263             }
264             }
265              
266             sub no_shuffle () {
267 0     0 0 0 $NoShuffle = 1;
268             }
269              
270             sub no_nginx_manager () {
271 0     0 0 0 $NoNginxManager = 1;
272             }
273              
274             sub use_hup() {
275 0     0 0 0 $UseHup = 1;
276             }
277              
278             our @CleanupHandlers;
279             our @BlockPreprocessors;
280              
281             sub bail_out (@);
282              
283             our $Randomize = $ENV{TEST_NGINX_RANDOMIZE};
284             our $NginxBinary = $ENV{TEST_NGINX_BINARY} || 'nginx';
285             our $Workers = 1;
286             our $WorkerConnections = 64;
287             our $LogLevel = $ENV{TEST_NGINX_LOG_LEVEL} || 'debug';
288             our $MasterProcessEnabled = $ENV{TEST_NGINX_MASTER_PROCESS} || 'off';
289             our $DaemonEnabled = 'on';
290             our $ServerPort = $ENV{TEST_NGINX_SERVER_PORT} || $ENV{TEST_NGINX_PORT} || 1984;
291             our $ServerPortForClient = $ENV{TEST_NGINX_CLIENT_PORT} || $ServerPort || 1984;
292             our $NoRootLocation = 0;
293             our $TestNginxSleep = $ENV{TEST_NGINX_SLEEP} || 0.015;
294             our $BuildSlaveName = $ENV{TEST_NGINX_BUILDSLAVE};
295             our $ForceRestartOnTest = (defined $ENV{TEST_NGINX_FORCE_RESTART_ON_TEST})
296             ? $ENV{TEST_NGINX_FORCE_RESTART_ON_TEST} : 1;
297             srand $$;
298              
299             if ($Randomize) {
300             my $tries = 1000;
301              
302             $ServerPort = gen_rand_port $tries;
303              
304             if (!defined $ServerPort) {
305             bail_out "Cannot find an available listening port number after $tries attempts.\n";
306             }
307              
308             $ServerPortForClient = $ServerPort;
309             }
310              
311             our $ChildPid;
312             our $UdpServerPid;
313             our $TcpServerPid;
314             our @EnvToNginx;
315              
316             sub env_to_nginx (@) {
317 0 0   0 0 0 if (!@_) {
318 0         0 croak "env_to_nginx: no arguments specified";
319             }
320 0         0 for my $v (@_) {
321 0 0 0     0 if ($v !~ /^[A-Za-z_]/ || $v =~ /\n/) {
322 0         0 croak "env_to_nginx: bad argument value: $v\n";
323             }
324 0         0 push @EnvToNginx, $v;
325             }
326             }
327              
328             sub sleep_time {
329 0     0 0 0 return $TestNginxSleep;
330             }
331              
332             sub verbose {
333 0     0 0 0 return $Verbose;
334             }
335              
336             sub server_port (@) {
337 0 0   0 0 0 if (@_) {
338 0         0 $ServerPort = shift;
339             } else {
340 0         0 $ServerPort;
341             }
342             }
343              
344             sub server_port_for_client (@) {
345 0 0   0 0 0 if (@_) {
346 0         0 $ServerPortForClient = shift;
347             } else {
348 0         0 $ServerPortForClient;
349             }
350             }
351              
352             sub repeat_each (@) {
353 0 0   0 0 0 if (@_) {
354 0 0 0     0 if ($CheckLeak || $Benchmark) {
355 0         0 return;
356             }
357 0         0 $RepeatEach = shift;
358             }
359              
360 0         0 return $RepeatEach;
361             }
362              
363             sub worker_connections (@) {
364 0 0   0 0 0 if (@_) {
365 0         0 $WorkerConnections = shift;
366             } else {
367 0         0 return $WorkerConnections;
368             }
369             }
370              
371             sub no_root_location () {
372 0     0 0 0 $NoRootLocation = 1;
373             }
374              
375             sub workers (@) {
376 0 0   0 0 0 if (@_) {
377             #warn "setting workers to $_[0]";
378 0         0 $Workers = shift;
379             } else {
380 0         0 return $Workers;
381             }
382             }
383              
384             sub log_level (@) {
385 0 0   0 0 0 if (@_) {
386 0         0 $LogLevel = shift;
387             } else {
388 0         0 return $LogLevel;
389             }
390             }
391              
392             sub check_accum_error_log () {
393 0     0 0 0 $CheckAccumErrLog = 1;
394             }
395              
396             sub master_on () {
397 0 0   0 0 0 if ($CheckLeak) {
398 0         0 return;
399             }
400 0         0 $MasterProcessEnabled = 'on';
401             }
402              
403             sub master_off () {
404 0     0 0 0 $MasterProcessEnabled = 'off';
405             }
406              
407             sub master_process_enabled (@) {
408 0 0   0 0 0 if ($CheckLeak) {
409 0         0 return;
410             }
411              
412 0 0       0 if (@_) {
413 0 0       0 $MasterProcessEnabled = shift() ? 'on' : 'off';
414             } else {
415 0         0 return $MasterProcessEnabled;
416             }
417             }
418              
419             our @EXPORT = qw(
420             use_http2
421             env_to_nginx
422             is_str
423             check_accum_error_log
424             is_running
425             $NoLongString
426             no_long_string
427             $ServerAddr
428             server_addr
429             $ServerName
430             server_name
431             parse_time
432             $UseStap
433             verbose
434             sleep_time
435             stap_out_fh
436             stap_out_fname
437             bail_out
438             add_cleanup_handler
439             access_log_data
440             error_log_data
441             setup_server_root
442             write_config_file
443             get_canon_version
444             get_nginx_version
445             trim
446             show_all_chars
447             parse_headers
448             run_tests
449             get_pid_from_pidfile
450             $ServerPortForClient
451             $ServerPort
452             $NginxVersion
453             $PidFile
454             $ServRoot
455             $ConfFile
456             $RunTestHelper
457             $CheckErrorLog
458             $CheckShutdownErrorLog
459             $FilterHttpConfig
460             $NoNginxManager
461             $RepeatEach
462             $CheckLeak
463             $Benchmark
464             $BenchmarkWarmup
465             add_block_preprocessor
466             timeout
467             worker_connections
468             workers
469             master_on
470             master_off
471             config_preamble
472             repeat_each
473             master_process_enabled
474             log_level
475             no_shuffle
476             no_root_location
477             html_dir
478             server_root
479             server_port
480             server_port_for_client
481             no_nginx_manager
482             use_hup
483             );
484              
485              
486             if ($Profiling || $UseValgrind || $UseStap) {
487             $DaemonEnabled = 'off';
488             if (!$UseValgrind) {
489             $MasterProcessEnabled = 'off';
490             }
491             }
492              
493             our $ConfigPreamble = '';
494              
495             sub config_preamble ($) {
496 0     0 0 0 $ConfigPreamble = shift;
497             }
498              
499             our $RunTestHelper;
500             our $CheckErrorLog;
501             our $CheckShutdownErrorLog;
502              
503             our $NginxVersion;
504             our $NginxRawVersion;
505             our $OpenSSLVersion;
506              
507             sub add_block_preprocessor(&) {
508 0     0 0 0 unshift @BlockPreprocessors, shift;
509             }
510              
511             #our ($PrevRequest)
512             our $PrevConfig;
513              
514             our $ServRoot;
515              
516             if ($Randomize) {
517             $ServRoot = File::Spec->rel2abs("t/servroot_" . $ServerPort);
518              
519             } else {
520             $ServRoot = $ENV{TEST_NGINX_SERVROOT} || File::Spec->rel2abs('t/servroot');
521             }
522             $ENV{TEST_NGINX_SERVER_ROOT} = $ServRoot;
523              
524             our $LogDir = File::Spec->catfile($ServRoot, 'logs');
525             our $ErrLogFile = File::Spec->catfile($LogDir, 'error.log');
526             our $AccLogFile = File::Spec->catfile($LogDir, 'access.log');
527             our $HtmlDir = File::Spec->catfile($ServRoot, 'html');
528             our $ConfDir = File::Spec->catfile($ServRoot, 'conf');
529             our $ConfFile = File::Spec->catfile($ConfDir, 'nginx.conf');
530             our $PidFile = File::Spec->catfile($LogDir, 'nginx.pid');
531              
532             sub parse_time ($) {
533 0     0 0 0 my $tm = shift;
534              
535 0 0       0 if (defined $tm) {
536 0 0       0 if ($tm =~ s/([^_a-zA-Z])ms$/$1/) {
    0          
537 0         0 $tm = $tm / 1000;
538             } elsif ($tm =~ s/([^_a-zA-Z])s$/$1/) {
539             # do nothing
540             } else {
541             # do nothing
542             }
543             }
544              
545 0         0 return $tm;
546             }
547              
548             sub html_dir () {
549 0     0 0 0 return $HtmlDir;
550             }
551              
552             sub server_root () {
553 0     0 0 0 return $ServRoot;
554             }
555              
556             sub add_cleanup_handler ($) {
557 0     0 0 0 unshift @CleanupHandlers, shift;
558             }
559              
560             sub bail_out (@) {
561 0     0 0 0 cleanup();
562 0         0 Test::More::BAIL_OUT(@_);
563             }
564              
565             sub kill_process ($$$) {
566 0     0 0 0 my ($pid, $wait, $name) = @_;
567              
568 0 0       0 if ($wait) {
569 0         0 eval {
570 0 0       0 if (defined $pid) {
571 0 0       0 if ($Verbose) {
572 0         0 warn "sending QUIT signal to $pid";
573             }
574              
575 0         0 kill(SIGQUIT, $pid);
576             }
577              
578 0 0       0 if ($Verbose) {
579 0         0 warn "waitpid timeout: ", timeout();
580             }
581              
582 0     0   0 local $SIG{ALRM} = sub { die "alarm\n" };
  0         0  
583 0         0 alarm timeout();
584 0         0 waitpid($pid, 0);
585 0         0 alarm 0;
586             };
587              
588 0 0       0 if ($@) {
589 0 0       0 if ($Verbose) {
590 0         0 warn "$name - WARNING: child process $pid timed out.\n";
591             }
592             }
593             }
594              
595 0         0 my $i = 1;
596 0         0 my $step = $TestNginxSleep;
597 0         0 while ($i <= 20) {
598             #warn "ps returns: ", system("ps -p $pid > /dev/stderr"), "\n";
599             #warn "$pid is running? ", is_running($pid) ? "Y" : "N", "\n";
600              
601 0 0       0 if (!is_running($pid)) {
602 0         0 return;
603             }
604              
605 0 0       0 if ($Verbose) {
606 0         0 warn "WARNING: killing the child process $pid.\n";
607             }
608              
609 0 0       0 if (kill(SIGTERM, $pid) == 0) { # send term signal
610 0         0 warn "WARNING: failed to send term signal to the child process with PID $pid.\n";
611             }
612              
613 0         0 $step *= 1.2;
614 0 0       0 $step = 0.5 if $step > 0.5;
615 0         0 sleep $step;
616              
617             } continue {
618 0         0 $i++;
619             }
620              
621             #system("ps aux|grep $pid > /dev/stderr");
622 0         0 warn "$name - WARNING: killing the child process $pid with force...";
623              
624 0         0 kill(SIGKILL, $pid);
625 0         0 waitpid($pid, 0);
626              
627 0 0       0 if (is_running($pid)) {
628 0     0   0 local $SIG{ALRM} = sub { die "alarm\n" };
  0         0  
629 0         0 alarm timeout();
630 0         0 waitpid($pid, 0);
631 0         0 alarm 0;
632             }
633             }
634              
635             sub cleanup () {
636 5 50   5 0 16 if ($Verbose) {
637 0         0 warn "cleaning up everything";
638             }
639              
640 5         19 for my $hdl (@CleanupHandlers) {
641 0         0 $hdl->();
642             }
643              
644 5 50       16 if (defined $UdpServerPid) {
645 0         0 kill_process($UdpServerPid, 1, "cleanup");
646 0         0 undef $UdpServerPid;
647             }
648              
649 5 50       16 if (defined $TcpServerPid) {
650 0         0 kill_process($TcpServerPid, 1, "cleanup");
651 0         0 undef $TcpServerPid;
652             }
653              
654 5 50       15 if (defined $ChildPid) {
655 0         0 kill_process($ChildPid, 1, "cleanup");
656 0         0 undef $ChildPid;
657             }
658             }
659              
660             sub access_log_data () {
661 0     0 0 0 sleep $TestNginxSleep * 3;
662              
663 0 0       0 open my $in, $AccLogFile or do {
664 0 0       0 if ($AccLogFile ne "off") {
665 0         0 die "open $AccLogFile failed: $!";
666             }
667              
668 0         0 return undef;
669             };
670              
671 0         0 my @lines = <$in>;
672              
673 0         0 close $in;
674 0         0 return \@lines;
675             }
676              
677             sub error_log_data () {
678             # this is for logging in the log-phase which is after the server closes the connection:
679 0     0 0 0 sleep $TestNginxSleep * 3;
680              
681 0 0       0 open my $in, $ErrLogFile or
682             return undef;
683              
684 0 0 0     0 if (!$CheckAccumErrLog && $ErrLogFilePos > 0) {
685 0         0 seek $in, $ErrLogFilePos, 0;
686             }
687              
688 0         0 my @lines = <$in>;
689              
690 0 0       0 if (!$CheckAccumErrLog) {
691 0         0 $ErrLogFilePos = tell($in);
692             }
693              
694 0         0 close $in;
695 0         0 return \@lines;
696             }
697              
698             sub check_prev_block_shutdown_error_log () {
699 5     5 0 13 my $block = $PrevBlock;
700              
701 5 50       26 if (!defined $block) {
702 5         13 return;
703             }
704              
705 0         0 my $name = $block->name;
706 0         0 my $dry_run;
707              
708 0 0       0 if (defined $block->shutdown_error_log) {
709 0 0       0 if ($UseHup) {
710 0         0 $dry_run = 1;
711             }
712              
713 0 0       0 if ($ENV{TEST_NGINX_NO_CLEAN}) {
714 0         0 $dry_run = 1;
715             }
716              
717 0         0 $CheckShutdownErrorLog->($block, $dry_run);
718             }
719             }
720              
721             sub run_tests () {
722 0     0 0 0 $NginxVersion = get_nginx_version();
723              
724 0 0       0 if (defined $NginxVersion) {
725             #warn "[INFO] Using nginx version $NginxVersion ($NginxRawVersion)\n";
726             }
727              
728 0 0       0 if (!defined $ENV{TEST_NGINX_SERVER_PORT}) {
729 0         0 $ENV{TEST_NGINX_SERVER_PORT} = $ServerPort;
730             }
731              
732 0 0       0 for my $block ($NoShuffle ? Test::Base::blocks() : shuffle Test::Base::blocks()) {
733 0         0 for my $hdl (@BlockPreprocessors) {
734 0         0 $hdl->($block);
735             }
736              
737 0         0 run_test($block);
738              
739 0         0 $PrevBlock = $block;
740             }
741              
742 0         0 cleanup();
743             }
744              
745             sub setup_server_root ($) {
746 0     0 0 0 my $first_time = shift;
747              
748 0 0       0 if (-d $ServRoot) {
749             # Take special care, so we won't accidentally remove
750             # real user data when TEST_NGINX_SERVROOT is mis-used.
751 0         0 remove_tree($ConfDir, glob("$ServRoot/*_cache"),
752             glob("$ServRoot/*_temp"));
753              
754 0 0       0 if ($UseHup) {
755             find({ bydepth => 1, no_chdir => 1, wanted => sub {
756 0 0   0   0 if (! -d $_) {
757 0 0       0 if ($_ =~ /(?:\bnginx\.pid|\.sock|\.crt|\.key)$/) {
758 0 0       0 return unless $first_time;
759             }
760              
761             #warn "removing file $_";
762 0 0       0 system("rm $_") == 0 or warn "Failed to remove $_\n";
763             }
764              
765 0         0 }}, $ServRoot);
766              
767             } else {
768 0         0 remove_tree($HtmlDir, $LogDir);
769 0 0       0 rmdir $ServRoot or
770             bail_out "Can't remove $ServRoot (not empty?): $!";
771             }
772             }
773 0 0       0 if (!-d $ServRoot) {
774 0 0       0 mkdir $ServRoot or
775             bail_out "Failed to do mkdir $ServRoot\n";
776             }
777 0 0       0 if (!-d $LogDir) {
778 0 0       0 mkdir $LogDir or
779             bail_out "Failed to do mkdir $LogDir\n";
780             }
781 0 0       0 if (!-d $HtmlDir) {
782 0 0       0 mkdir $HtmlDir or
783             bail_out "Failed to do mkdir $HtmlDir\n";
784             }
785              
786 0         0 my $index_file = "$HtmlDir/index.html";
787              
788 0 0       0 open my $out, ">$index_file" or
789             bail_out "Can't open $index_file for writing: $!\n";
790              
791 0         0 print $out 'It works!It works!';
792              
793 0         0 close $out;
794              
795 0 0       0 mkdir $ConfDir or
796             bail_out "Failed to do mkdir $ConfDir\n";
797             }
798              
799             sub write_user_files ($$) {
800 0     0 0 0 my ($block, $rand_ports) = @_;
801              
802 0         0 my $name = $block->name;
803              
804 0         0 my $files = $block->user_files;
805 0 0       0 if ($files) {
806 0 0       0 if (!ref $files) {
    0          
807 0         0 my $raw = $files;
808              
809 0         0 open my $in, '<', \$raw;
810              
811 0         0 $files = [];
812 0         0 my ($fname, $body, $date);
813 0         0 while (<$in>) {
814 0 0       0 if (/>>> (\S+)(?:\s+(.+))?/) {
815 0 0       0 if ($fname) {
816 0         0 push @$files, [$fname, $body, $date];
817             }
818              
819 0         0 $fname = $1;
820 0         0 $date = $2;
821 0         0 undef $body;
822             } else {
823 0         0 $body .= $_;
824             }
825             }
826              
827 0 0       0 if ($fname) {
828 0         0 push @$files, [$fname, $body, $date];
829             }
830              
831             } elsif (ref $files ne 'ARRAY') {
832 0         0 bail_out "$name - wrong value type: ", ref $files,
833             ", only scalar or ARRAY are accepted";
834             }
835              
836 0         0 for my $file (@$files) {
837 0         0 my ($fname, $body, $date) = @$file;
838             #warn "write file $fname with content [$body]\n";
839              
840 0 0       0 if (!defined $body) {
841 0         0 $body = '';
842             }
843              
844 0         0 my $path;
845 0 0       0 if ($fname !~ m{^/}) {
846 0         0 $path = "$HtmlDir/$fname";
847              
848             } else {
849 0         0 $path = $fname;
850             }
851              
852 0 0       0 if ($path =~ /(.*)\//) {
853 0         0 my $dir = $1;
854 0 0       0 if (! -d $dir) {
855 0 0       0 make_path($dir) or bail_out "$name - Cannot create directory ", $dir;
856             }
857             }
858              
859 0         0 $body = expand_env_in_text($body, $name, $rand_ports);
860              
861 0 0       0 open my $out, ">$path" or
862             bail_out "$name - Cannot open $path for writing: $!\n";
863 0         0 binmode $out;
864             #warn "write file $path with data len ", length $body;
865 0         0 print $out $body;
866 0         0 close $out;
867              
868 0 0       0 if ($date) {
869 0         0 my $cmd = "TZ=GMT touch -t '$date' $HtmlDir/$fname";
870 0 0       0 system($cmd) == 0 or
871             bail_out "Failed to run shell command: $cmd\n";
872             }
873             }
874             }
875             }
876              
877             sub write_config_file ($$$) {
878 0     0 0 0 my ($block, $config, $rand_ports) = @_;
879              
880 0         0 my $name = $block->name;
881 0         0 my $http_config = $block->http_config;
882 0         0 my $main_config = $block->main_config;
883 0         0 my $post_main_config = $block->post_main_config;
884 0         0 my $err_log_file = $block->error_log_file;
885 0         0 my $server_name = $block->server_name;
886              
887 0 0 0     0 if ($UseHup) {
    0          
    0          
888 0         0 master_on(); # config reload is buggy when master is off
889              
890             } elsif ($UseValgrind) {
891             #master_off();
892              
893             } elsif ($UseStap && defined $block->stap) {
894 0         0 master_off();
895             }
896              
897 0         0 $http_config = expand_env_in_text($http_config, $name, $rand_ports);
898              
899 0 0       0 if (!defined $config) {
900 0         0 $config = '';
901             }
902              
903 0 0       0 if (!defined $http_config) {
904 0         0 $http_config = '';
905             }
906              
907 0 0       0 if ($FilterHttpConfig) {
908 0         0 $http_config = $FilterHttpConfig->($http_config)
909             }
910              
911 0 0       0 if ($http_config =~ /\bpostpone_output\b/) {
912 0         0 undef $PostponeOutput;
913             }
914              
915 0         0 my $extra_http_config = '';
916              
917 0 0       0 if (defined $PostponeOutput) {
918 0 0       0 if ($PostponeOutput !~ /^\d+$/) {
919 0         0 bail_out "Bad TEST_NGINX_POSTPONE_OUTPUT value: $PostponeOutput\n";
920             }
921 0         0 $extra_http_config .= "\n postpone_output $PostponeOutput;\n";
922             }
923              
924 0 0       0 if (!defined $main_config) {
925 0         0 $main_config = '';
926             }
927              
928 0 0       0 if ($LoadModules) {
929 0         0 my @modules = map { "load_module $_;" } grep { $_ } split /\s+/, $LoadModules;
  0         0  
  0         0  
930 0 0       0 if (@modules) {
931 0         0 $main_config .= join " ", @modules;
932             }
933             }
934              
935 0         0 $main_config = expand_env_in_text($main_config, $name, $rand_ports);
936              
937 0 0       0 if (!defined $post_main_config) {
938 0         0 $post_main_config = '';
939             }
940              
941 0         0 $post_main_config = expand_env_in_text($post_main_config, $name, $rand_ports);
942              
943 0 0 0     0 if ($CheckLeak || $Benchmark) {
944 0         0 $LogLevel = 'warn';
945 0         0 $AccLogFile = 'off';
946             }
947              
948 0 0       0 if (!$err_log_file) {
949 0         0 $err_log_file = $ErrLogFile;
950             }
951              
952 0 0       0 if (!defined $server_name) {
953 0         0 $server_name = $ServerName;
954             }
955              
956 0         0 (my $quoted_server_name = $server_name) =~ s/\\/\\\\/g;
957 0         0 $quoted_server_name =~ s/'/\\'/g;
958              
959 0 0       0 open my $out, ">$ConfFile" or
960             bail_out "Can't open $ConfFile for writing: $!\n";
961 0         0 print $out <<_EOC_;
962             worker_processes $Workers;
963             daemon $DaemonEnabled;
964             master_process $MasterProcessEnabled;
965             error_log $err_log_file $LogLevel;
966             pid $PidFile;
967             env MOCKEAGAIN_VERBOSE;
968             env MOCKEAGAIN;
969             env MOCKEAGAIN_WRITE_TIMEOUT_PATTERN;
970             env LD_PRELOAD;
971             env LD_LIBRARY_PATH;
972             env DYLD_INSERT_LIBRARIES;
973             env DYLD_FORCE_FLAT_NAMESPACE;
974             _EOC_
975              
976 0         0 for my $v (@EnvToNginx) {
977 0 0       0 if ($v =~ /\s/) {
978 0         0 $v = "'$v'";
979             }
980 0         0 print $out "env $v;\n";
981             }
982              
983 0         0 my $listen_opts = '';
984              
985 0 0       0 if (use_http2($block)) {
986 0         0 $listen_opts .= " http2";
987             }
988              
989 0 0       0 if ($ReusePort) {
990 0         0 $listen_opts .= " reuseport";
991             }
992              
993 0         0 print $out <<_EOC_;
994             #env LUA_PATH;
995             #env LUA_CPATH;
996              
997             $main_config
998              
999             http {
1000             access_log $AccLogFile;
1001             #access_log off;
1002              
1003             default_type text/plain;
1004             keepalive_timeout 68;
1005              
1006             $http_config
1007              
1008             server {
1009             listen $ServerPort$listen_opts;
1010             server_name '$server_name';
1011              
1012             client_max_body_size 30M;
1013             #client_body_buffer_size 4k;
1014              
1015             # Begin preamble config...
1016             $ConfigPreamble
1017             # End preamble config...
1018              
1019             # Begin test case config...
1020             $config
1021             # End test case config.
1022              
1023             _EOC_
1024              
1025 0 0       0 if (! $NoRootLocation) {
1026 0         0 print $out <<_EOC_;
1027             location / {
1028             root $HtmlDir;
1029             index index.html index.htm;
1030             }
1031             _EOC_
1032             }
1033              
1034 0         0 print $out " }\n";
1035              
1036 0 0       0 if ($UseHup) {
1037 0         0 print $out <<_EOC_;
1038             server {
1039             listen $ServerPort$listen_opts;
1040             server_name 'Test-Nginx';
1041              
1042             location = /ver {
1043             return 200 '$ConfigVersion';
1044             }
1045             }
1046              
1047             $extra_http_config
1048             _EOC_
1049             }
1050              
1051 0         0 print $out <<_EOC_;
1052             }
1053              
1054             $post_main_config
1055              
1056             #timer_resolution 100ms;
1057              
1058             events {
1059             accept_mutex off;
1060              
1061             worker_connections $WorkerConnections;
1062             _EOC_
1063              
1064 0 0       0 if ($EventType) {
1065 0         0 print $out <<_EOC_;
1066             use $EventType;
1067             _EOC_
1068             }
1069              
1070 0         0 print $out "}\n";
1071              
1072 0         0 print $out <<_EOC_;
1073             env ASAN_OPTIONS;
1074             env MOCKNOEAGAIN_VERBOSE;
1075             env MOCKNOEAGAIN;
1076             _EOC_
1077              
1078 0 0       0 if (defined $WorkerUser) {
    0          
1079 0         0 print $out "user $WorkerUser;\n";
1080              
1081             } elsif ($> == 0) { # being root
1082 0         0 print $out "user root;\n";
1083             }
1084              
1085 0         0 close $out;
1086             }
1087              
1088             sub get_canon_version (@) {
1089 0     0 0 0 sprintf "%d.%03d%03d", $_[0], $_[1], $_[2];
1090             }
1091              
1092             sub get_canon_version_for_OpenSSL (@) {
1093 0 0   0 0 0 if (defined $_[3]) {
1094 0         0 return sprintf "%d.%03d%03d%03d", $_[0], $_[1], $_[2], ord($_[3]) - ord('a');
1095             }
1096              
1097 0         0 get_canon_version @_;
1098             }
1099              
1100             sub get_nginx_version () {
1101 0     0 0 0 my $out = `$NginxBinary -V 2>&1`;
1102 0 0 0     0 if (!defined $out || $? != 0) {
1103 0   0     0 $out //= "";
1104 0         0 bail_out("Failed to get the version of the Nginx in PATH: $out");
1105             }
1106              
1107 0 0       0 if ($out =~ m{built with OpenSSL (\d+)\.(\d+)\.(\d+)([a-z])}s) {
1108 0         0 $OpenSSLVersion = get_canon_version_for_OpenSSL($1, $2, $3, $4);
1109             }
1110              
1111 0 0       0 if ($out =~ m{(?:nginx|openresty)[^/]*/(\d+)\.(\d+)\.(\d+)}s) {
1112 0         0 $NginxRawVersion = "$1.$2.$3";
1113 0         0 return get_canon_version($1, $2, $3);
1114             }
1115              
1116 0 0       0 if ($out =~ m{\w+/(\d+)\.(\d+)\.(\d+)}s) {
1117 0         0 $NginxRawVersion = "$1.$2.$3";
1118 0         0 return get_canon_version($1, $2, $3);
1119             }
1120              
1121 0         0 bail_out("Failed to parse the output of \"nginx -V\": $out\n");
1122             }
1123              
1124             sub get_pid_from_pidfile ($) {
1125 0     0 0 0 my ($name) = @_;
1126              
1127 0 0       0 open my $in, $PidFile or
1128             bail_out("$name - Failed to open the pid file $PidFile for reading: $!");
1129 0         0 my $pid = do { local $/; <$in> };
  0         0  
  0         0  
1130 0         0 chomp $pid;
1131             #warn "Pid: $pid\n";
1132 0         0 close $in;
1133 0         0 return $pid;
1134             }
1135              
1136             sub trim ($) {
1137 7     7 0 13 my $s = shift;
1138 7 50       15 return undef if !defined $s;
1139 7         78 $s =~ s/^\s+|\s+$//g;
1140 7         18 $s =~ s/\n/ /gs;
1141 7         16 $s =~ s/\s{2,}/ /gs;
1142 7         16 $s;
1143             }
1144              
1145             sub show_all_chars ($) {
1146 0     0 0   my $s = shift;
1147 0           $s =~ s/\n/\\n/gs;
1148 0           $s =~ s/\r/\\r/gs;
1149 0           $s =~ s/\t/\\t/gs;
1150 0           $s;
1151             }
1152              
1153             sub test_config_version ($$) {
1154 0     0 0   my ($name, $block) = @_;
1155 0           my $total = 200;
1156 0           my $sleep = sleep_time();
1157 0           my $nsucc = 0;
1158              
1159             #$ConfigVersion = '322';
1160              
1161 0           for (my $tries = 1; $tries <= $total; $tries++) {
1162              
1163 0           my $extra_curl_opts = '';
1164              
1165 0 0         if (use_http2($block)) {
1166 0           $extra_curl_opts .= ' --http2 --http2-prior-knowledge';
1167             }
1168              
1169 0           my $cmd = "curl$extra_curl_opts -sS -H 'Host: Test-Nginx' --connect-timeout 2 'http://$ServerAddr:$ServerPort/ver'";
1170             #warn $cmd;
1171 0           my $ver = `$cmd`;
1172             #chop $ver;
1173              
1174 0 0         if ($Verbose) {
1175 0           warn "$name - ConfigVersion: $ver == $ConfigVersion\n";
1176             }
1177              
1178 0 0         if ($ver eq $ConfigVersion) {
1179 0           $nsucc++;
1180              
1181 0 0         if ($nsucc == 5) {
1182 0           sleep $sleep;
1183             }
1184              
1185 0 0         if ($nsucc >= 20) {
1186             #warn "MATCHED!!!\n";
1187 0           return;
1188             }
1189              
1190             #sleep $sleep;
1191 0           next;
1192              
1193             } else {
1194 0 0         if ($nsucc) {
1195 0 0         if ($Verbose) {
1196 0           warn "$name - reset nsucc $nsucc\n";
1197             }
1198              
1199 0           $nsucc = 0;
1200             }
1201             }
1202              
1203 0           my $wait = ($sleep + $sleep * $tries) * $tries / 2;
1204 0 0         if ($wait > 1) {
1205 0           $wait = 1;
1206             }
1207              
1208 0 0         if ($wait > 0.5) {
1209 0           warn "$name - waiting $wait sec for nginx to reload the configuration\n";
1210             }
1211              
1212 0           sleep $wait;
1213             }
1214              
1215 0           my $tb = Test::More->builder;
1216 0           $tb->no_ending(1);
1217              
1218 0           Test::More::fail("$name - failed to reload configuration after $total "
1219             . "failed test requests");
1220             }
1221              
1222             sub parse_headers ($) {
1223 0     0 0   my $s = shift;
1224 0           my %headers;
1225 0           open my $in, '<', \$s;
1226 0           while (<$in>) {
1227 0           s/^\s+|\s+$//g;
1228 0           my $neg = ($_ =~ s/^!\s*//);
1229             #warn "neg: $neg ($_)";
1230 0 0         if ($neg) {
1231 0           $headers{$_} = undef;
1232             } else {
1233 0           my ($key, $val) = split /\s*:\s*/, $_, 2;
1234 0           $headers{$key} = $val;
1235             }
1236             }
1237 0           close $in;
1238 0           return \%headers;
1239             }
1240              
1241             sub expand_env_in_text ($$$) {
1242 0     0 0   my ($text, $name, $rand_ports) = @_;
1243              
1244 0 0         if (!defined $text) {
1245 0           return;
1246             }
1247              
1248             my $used_ports = {
1249             $ServerPort => 1,
1250 0           map { $_ => 1 } values %$rand_ports
  0            
1251             };
1252              
1253 0           $text =~ s/\$(TEST_NGINX_[_A-Z0-9]+)/
1254 0           my $expanded_env;
1255              
1256 0 0         if ($1 =~ m{^(TEST_NGINX_RAND_PORT_[0-9]+)$}) {
1257 0 0         if (!defined $rand_ports->{$1}) {
1258 0           my $rand_port = gen_rand_port 1000, $used_ports;
1259              
1260 0 0         if (!defined $rand_port) {
1261 0           bail_out "$name - Cannot find an available listening port number for $1.\n";
1262             }
1263              
1264 0           $rand_ports->{$1} = $rand_port;
1265 0           $used_ports->{$rand_port} = 1;
1266 0           $expanded_env = $rand_port;
1267              
1268             } else {
1269 0           $expanded_env = $rand_ports->{$1};
1270             }
1271             } else {
1272 0 0         if (!defined $ENV{$1}) {
1273 0           bail_out "$name - No environment $1 defined.\n";
1274             }
1275 0           $expanded_env = $ENV{$1};
1276             }
1277 0           $expanded_env;
1278             /eg;
1279              
1280 0           $text;
1281             }
1282              
1283             sub check_if_missing_directives () {
1284 0 0   0 0   open my $in, $ErrLogFile or
1285             bail_out "check_if_missing_directives: Cannot open $ErrLogFile for reading: $!\n";
1286              
1287 0           while (<$in>) {
1288             #warn $_;
1289 0 0         if (/\[emerg\] \S+?: unknown directive "([^"]+)"/) {
1290             #warn "MATCHED!!! $1";
1291 0           return $1;
1292             }
1293             }
1294              
1295 0           close $in;
1296              
1297             #warn "NOT MATCHED!!!";
1298              
1299 0           return 0;
1300             }
1301              
1302             sub run_tcp_server_tests ($$$) {
1303 0     0 0   my ($block, $tcp_socket, $tcp_query_file) = @_;
1304              
1305 0           my $name = $block->name;
1306              
1307 0 0         if (defined $tcp_socket) {
1308 0           my $buf = '';
1309 0 0         if ($tcp_query_file) {
1310 0 0         if (open my $in, $tcp_query_file) {
1311 0           $buf = do { local $/; <$in> };
  0            
  0            
1312 0           close $in;
1313             }
1314             }
1315              
1316 0 0         if (defined $block->tcp_query) {
1317 0           is_str($buf, $block->tcp_query, "$name - tcp_query ok");
1318             }
1319              
1320 0 0         if (defined $block->tcp_query_len) {
1321 0           Test::More::is(length($buf), $block->tcp_query_len, "$name - TCP query length ok");
1322             }
1323             }
1324             }
1325              
1326             sub run_udp_server_tests ($$$) {
1327 0     0 0   my ($block, $udp_socket, $udp_query_file) = @_;
1328              
1329 0           my $name = $block->name;
1330              
1331 0 0         if (defined $udp_socket) {
1332 0           my $buf = '';
1333 0 0         if ($udp_query_file) {
1334 0 0         if (!open my $in, $udp_query_file) {
1335 0           warn "WARNING: cannot open udp query file $udp_query_file for reading: $!\n";
1336              
1337             } else {
1338 0           $buf = do { local $/; <$in> };
  0            
  0            
1339 0           close $in;
1340             }
1341             }
1342              
1343 0 0         if (defined $block->udp_query) {
1344 0           is_str($buf, $block->udp_query, "$name - udp_query ok");
1345             }
1346             }
1347             }
1348              
1349             sub run_test ($) {
1350 0     0 0   my $block = shift;
1351              
1352 0 0         return if defined $block->SKIP;
1353              
1354 0           my $name = $block->name;
1355              
1356 0           my $first_time;
1357 0 0         if ($FirstTime) {
1358 0           $first_time = 1;
1359 0           undef $FirstTime;
1360             }
1361              
1362 0           my $rand_ports = {};
1363              
1364 0           my $config = $block->config;
1365              
1366 0           $config = expand_env_in_text($config, $name, $rand_ports);
1367              
1368 0           my $dry_run = 0;
1369 0           my $should_restart = 1;
1370 0           my $should_reconfig = 1;
1371              
1372 0           local $StapOutFile = $StapOutFile;
1373              
1374             #warn "run test\n";
1375 0           local $LogLevel = $LogLevel;
1376 0 0         if ($block->log_level) {
1377 0           $LogLevel = $block->log_level;
1378             }
1379              
1380 0           my $must_die;
1381 0           local $UseStap = $UseStap;
1382 0           local $UseValgrind = $UseValgrind;
1383 0           local $UseHup = $UseHup;
1384 0           local $Profiling = $Profiling;
1385              
1386 0 0         if (defined $block->must_die) {
1387 0           $must_die = $block->must_die;
1388 0 0         if (defined $block->stap) {
1389 0           bail_out("$name: --- stap cannot be used with --- must_die");
1390             }
1391              
1392 0 0         if ($UseStap) {
1393 0           undef $UseStap;
1394             }
1395              
1396 0 0         if ($UseValgrind) {
1397 0           undef $UseValgrind;
1398             }
1399              
1400 0 0         if ($UseHup) {
1401 0           undef $UseHup;
1402             }
1403              
1404 0 0         if ($Profiling) {
1405 0           undef $Profiling;
1406             }
1407             }
1408              
1409 0 0         if (!defined $config) {
    0          
1410 0 0         if (!$NoNginxManager) {
1411             # Manager without config.
1412 0 0         if (!defined $PrevConfig) {
1413 0           bail_out("$name - No '--- config' section specified and could not get previous one. Use TEST_NGINX_NO_NGINX_MANAGER ?");
1414 0           die;
1415             }
1416 0           $should_reconfig = 0; # There is nothing to reconfig to.
1417 0           $should_restart = $ForceRestartOnTest;
1418             }
1419             # else: not manager without a config. This is not a problem at all.
1420             # setting these values to something meaningful but should not be used
1421 0           $should_restart = 0;
1422 0           $should_reconfig = 0;
1423              
1424             } elsif ($NoNginxManager) {
1425             # One config but not manager: it's worth a warning.
1426 0           Test::Base::diag("NO_NGINX_MANAGER activated: config for $name ignored");
1427             # Like above: setting them to something meaningful just in case.
1428 0           $should_restart = 0;
1429 0           $should_reconfig = 0;
1430              
1431             } else {
1432             # One config and manager. Restart only if forced to or if config
1433             # changed.
1434 0 0 0       if ((!defined $PrevConfig) || ($config ne $PrevConfig)) {
1435 0           $should_reconfig = 1;
1436             } else {
1437 0           $should_reconfig = 0;
1438             }
1439 0 0 0       if ($should_reconfig || $ForceRestartOnTest) {
1440 0           $should_restart = 1;
1441             } else {
1442 0           $should_restart = 0;
1443             }
1444             }
1445              
1446             #warn "should restart: $should_restart\n";
1447              
1448 0           my $skip_nginx = $block->skip_nginx;
1449 0           my $skip_nginx2 = $block->skip_nginx2;
1450 0           my $skip_openssl = $block->skip_openssl;
1451 0           my $skip_eval = $block->skip_eval;
1452 0           my $skip_slave = $block->skip_slave;
1453 0           my ($tests_to_skip, $should_skip, $skip_reason);
1454              
1455 0 0 0       if (defined $block->reload_fails || defined $block->http2) {
1456 0           $block->set_value("no_check_leak", 1);
1457             }
1458              
1459 0 0 0       if (($CheckLeak || $Benchmark) && defined $block->no_check_leak) {
      0        
1460 0           $should_skip = 1;
1461             }
1462              
1463 0 0         if (defined $skip_eval) {
1464 0 0         if ($skip_eval =~ m{
1465             ^ \s* (\d+) \s* : \s* (.*)
1466             }xs)
1467             {
1468 0           $tests_to_skip = $1;
1469 0           $skip_reason = "skip_eval";
1470 0           my $code = $2;
1471 0           $should_skip = eval $code;
1472 0 0         if ($@) {
1473 0           bail_out("$name - skip_eval - failed to eval the Perl code "
1474             . "\"$code\": $@");
1475             }
1476             }
1477             }
1478              
1479 0 0 0       if (defined $skip_nginx) {
    0          
    0          
1480 0 0         if ($skip_nginx =~ m{
1481             ^ \s* (\d+) \s* : \s*
1482             ([<>]=?) \s* (\d+)\.(\d+)\.(\d+)
1483             (?: \s* : \s* (.*) )?
1484             \s*$}x) {
1485 0           $tests_to_skip = $1;
1486 0           my ($op, $ver1, $ver2, $ver3) = ($2, $3, $4, $5);
1487 0           $skip_reason = $6;
1488 0 0         if (!$skip_reason) {
1489 0           $skip_reason = "nginx version $op $ver1.$ver2.$ver3";
1490             }
1491             #warn "$ver1 $ver2 $ver3";
1492 0           my $ver = get_canon_version($ver1, $ver2, $ver3);
1493 0 0 0       if ((!defined $NginxVersion and $op =~ /^
      0        
1494             or eval "$NginxVersion $op $ver")
1495             {
1496 0           $should_skip = 1;
1497             }
1498             } else {
1499 0           bail_out("$name - Invalid --- skip_nginx spec: " .
1500             $skip_nginx);
1501 0           die;
1502             }
1503             } elsif (defined $skip_nginx2) {
1504 0 0         if ($skip_nginx2 =~ m{
1505             ^ \s* (\d+) \s* : \s*
1506             ([<>]=?) \s* (\d+)\.(\d+)\.(\d+)
1507             \s* (or|and) \s*
1508             ([<>]=?) \s* (\d+)\.(\d+)\.(\d+)
1509             (?: \s* : \s* (.*) )?
1510             \s*$}x) {
1511 0           $tests_to_skip = $1;
1512 0           my ($opa, $ver1a, $ver2a, $ver3a) = ($2, $3, $4, $5);
1513 0           my $opx = $6;
1514 0           my ($opb, $ver1b, $ver2b, $ver3b) = ($7, $8, $9, $10);
1515 0           $skip_reason = $11;
1516 0           my $vera = get_canon_version($ver1a, $ver2a, $ver3a);
1517 0           my $verb = get_canon_version($ver1b, $ver2b, $ver3b);
1518              
1519 0 0 0       if ((!defined $NginxVersion)
      0        
      0        
      0        
      0        
      0        
1520             or (($opx eq "or") and (eval "$NginxVersion $opa $vera"
1521             or eval "$NginxVersion $opb $verb"))
1522             or (($opx eq "and") and (eval "$NginxVersion $opa $vera"
1523             and eval "$NginxVersion $opb $verb")))
1524             {
1525 0           $should_skip = 1;
1526             }
1527             } else {
1528 0           bail_out("$name - Invalid --- skip_nginx2 spec: " .
1529             $skip_nginx2);
1530 0           die;
1531             }
1532             } elsif (defined $skip_slave and defined $BuildSlaveName) {
1533 0 0         if ($skip_slave =~ m{
1534             ^ \s* (\d+) \s* : \s*
1535             (\w+) \s* (?: (\w+) \s* )? (?: (\w+) \s* )?
1536             (?: \s* : \s* (.*) )? \s*$}x)
1537             {
1538 0           $tests_to_skip = $1;
1539 0           my ($slave1, $slave2, $slave3) = ($2, $3, $4);
1540 0           $skip_reason = $5;
1541 0 0 0       if ((defined $slave1 and $slave1 eq "all")
      0        
      0        
      0        
      0        
      0        
      0        
1542             or (defined $slave1 and $slave1 eq $BuildSlaveName)
1543             or (defined $slave2 and $slave2 eq $BuildSlaveName)
1544             or (defined $slave3 and $slave3 eq $BuildSlaveName)
1545             )
1546             {
1547 0           $should_skip = 1;
1548             }
1549             } else {
1550 0           bail_out("$name - Invalid --- skip_slave spec: " .
1551             $skip_slave);
1552 0           die;
1553             }
1554             }
1555              
1556 0 0         if (defined $skip_openssl) {
1557 0 0         if ($skip_openssl =~ m{
1558             ^ \s* (\d+) \s* : \s*
1559             ([<>]=?) \s* (\d+)\.(\d+)\.(\d+)([a-z])?
1560             (?: \s* : \s* (.*) )?
1561             \s*$}x) {
1562 0           $tests_to_skip = $1;
1563 0           my ($op, $ver1, $ver2, $ver3, $ver4) = ($2, $3, $4, $5, $6);
1564 0           $skip_reason = $7;
1565 0 0         if (!$skip_reason) {
1566 0 0         if (!defined $OpenSSLVersion) {
    0          
1567 0           $skip_reason = "Not built with OpenSSL";
1568              
1569             } elsif (defined $ver4) {
1570 0           $skip_reason = "OpenSSL version $op $ver1.$ver2.$ver3$ver4";
1571              
1572             } else {
1573 0           $skip_reason = "OpenSSL version $op $ver1.$ver2.$ver3";
1574             }
1575             }
1576              
1577 0           my $ver = get_canon_version_for_OpenSSL($ver1, $ver2, $ver3, $ver4);
1578 0 0 0       if (!defined $OpenSSLVersion or eval "$OpenSSLVersion $op $ver") {
1579 0           $should_skip = 1;
1580             }
1581              
1582             } else {
1583 0           bail_out("$name - Invalid --- skip_openssl spec: " .
1584             $skip_openssl);
1585 0           die;
1586             }
1587             }
1588              
1589 0 0         if (!defined $skip_reason) {
1590 0           $skip_reason = "various reasons";
1591             }
1592              
1593 0           my $todo_nginx = $block->todo_nginx;
1594 0           my ($should_todo, $todo_reason);
1595 0 0         if (defined $todo_nginx) {
1596 0 0         if ($todo_nginx =~ m{
1597             ^ \s*
1598             ([<>]=?) \s* (\d+)\.(\d+)\.(\d+)
1599             (?: \s* : \s* (.*) )?
1600             \s*$}x) {
1601 0           my ($op, $ver1, $ver2, $ver3) = ($1, $2, $3, $4);
1602 0           $todo_reason = $5;
1603 0           my $ver = get_canon_version($ver1, $ver2, $ver3);
1604 0 0 0       if ((!defined $NginxVersion and $op =~ /^
      0        
1605             or eval "$NginxVersion $op $ver")
1606             {
1607 0           $should_todo = 1;
1608             }
1609             } else {
1610 0           bail_out("$name - Invalid --- todo_nginx spec: " .
1611             $todo_nginx);
1612 0           die;
1613             }
1614             }
1615              
1616 0           my $todo = $block->todo;
1617 0 0         if (defined $todo) {
1618 0 0         if ($todo =~ m{
1619             ^ \s* (\d+) \s* : \s* (.*)
1620             }xs)
1621             {
1622 0           $should_todo = 1;
1623 0           $tests_to_skip = $1;
1624 0           $todo_reason = $2;
1625             } else {
1626 0           bail_out("$name - Invalid --- todo spec: " .
1627             $todo);
1628 0           die;
1629             }
1630             }
1631              
1632 0 0         if (!defined $todo_reason) {
1633 0           $todo_reason = "various reasons";
1634             }
1635              
1636             #warn "HERE";
1637              
1638 0 0 0       if (!$NoNginxManager && !$should_skip && $should_restart) {
      0        
1639             #warn "HERE";
1640              
1641 0 0         if ($UseHup) {
1642 0           $ConfigVersion = gen_rand_str(10);
1643             }
1644              
1645 0 0         if ($should_reconfig) {
1646 0           $PrevConfig = $config;
1647             }
1648              
1649 0           my $nginx_is_running = 1;
1650              
1651             #warn "pid file: ", -f $PidFile;
1652              
1653 0 0         if (-f $PidFile) {
1654             #warn "HERE";
1655 0           my $pid = get_pid_from_pidfile($name);
1656              
1657             #warn "PID: $pid\n";
1658              
1659 0 0 0       if (!defined $pid or $pid eq '') {
1660             #warn "HERE";
1661 0           undef $nginx_is_running;
1662 0           goto start_nginx;
1663             }
1664              
1665             #warn "HERE";
1666              
1667 0 0         if (is_running($pid)) {
1668             #warn "found running nginx...";
1669              
1670 0 0         if ($UseHup) {
1671 0 0         if ($first_time) {
1672 0           kill_process($pid, 1, $name);
1673              
1674 0           undef $nginx_is_running;
1675 0           goto start_nginx;
1676             }
1677              
1678 0           setup_server_root($first_time);
1679 0           write_user_files($block, $rand_ports);
1680 0           write_config_file($block, $config, $rand_ports);
1681              
1682 0 0         if ($Verbose) {
1683 0           warn "sending USR1 signal to $pid.\n";
1684             }
1685 0 0         if (system("kill -USR1 $pid") == 0) {
1686 0           sleep $TestNginxSleep;
1687              
1688 0 0         if ($Verbose) {
1689 0           warn "sending HUP signal to $pid.\n";
1690             }
1691              
1692 0 0         if (system("kill -HUP $pid") == 0) {
1693 0           sleep $TestNginxSleep * 3;
1694              
1695 0 0         if ($Verbose) {
1696 0           warn "skip starting nginx from scratch\n";
1697             }
1698              
1699 0           $nginx_is_running = 1;
1700              
1701 0 0         if ($UseValgrind) {
1702 0           warn "$name\n";
1703             }
1704              
1705 0 0         if (defined $block->reload_fails) {
1706 0           sleep 0.3;
1707              
1708             } else {
1709 0           test_config_version($name, $block);
1710             }
1711              
1712 0           check_prev_block_shutdown_error_log();
1713              
1714 0           goto request;
1715              
1716             } else {
1717 0 0         if ($Verbose) {
1718 0           warn "$name - Failed to send HUP signal";
1719             }
1720             }
1721              
1722             } else {
1723 0           warn "$name - Failed to send USR1 signal";
1724             }
1725             }
1726              
1727 0           kill_process($pid, 1, $name);
1728              
1729 0           undef $nginx_is_running;
1730              
1731             } else {
1732 0 0         if (-f $PidFile) {
1733 0 0         unlink $PidFile or
1734             warn "WARNING: failed to remove pid file $PidFile\n";
1735             }
1736              
1737 0           undef $nginx_is_running;
1738             }
1739              
1740             } else {
1741 0           undef $nginx_is_running;
1742             }
1743              
1744 0           start_nginx:
1745              
1746             check_prev_block_shutdown_error_log();
1747              
1748 0 0         unless ($nginx_is_running) {
1749 0 0         if ($Verbose) {
1750 0           warn "starting nginx from scratch\n";
1751             }
1752              
1753             #system("killall -9 nginx");
1754              
1755             #warn "*** Restarting the nginx server...\n";
1756 0           setup_server_root($first_time);
1757 0           write_user_files($block, $rand_ports);
1758 0           write_config_file($block, $config, $rand_ports);
1759             #warn "nginx binary: $NginxBinary";
1760 0 0         if (!can_run($NginxBinary)) {
1761 0           bail_out("$name - Cannot find the nginx executable in the PATH environment");
1762 0           die;
1763             }
1764             #if (system("nginx -p $ServRoot -c $ConfFile -t") != 0) {
1765             #Test::More::BAIL_OUT("$name - Invalid config file");
1766             #}
1767             #my $cmd = "nginx -p $ServRoot -c $ConfFile > /dev/null";
1768 0 0         if (!defined $NginxVersion) {
1769 0           $NginxVersion = $LatestNginxVersion;
1770             }
1771              
1772 0           my $cmd;
1773              
1774 0 0         if ($NginxVersion >= 0.007053) {
1775 0           $cmd = "$NginxBinary -p $ServRoot/ -c $ConfFile > /dev/null";
1776             } else {
1777 0           $cmd = "$NginxBinary -c $ConfFile > /dev/null";
1778             }
1779              
1780 0 0         if ($UseRr) {
1781 0           $cmd = "rr record $cmd";
1782             }
1783              
1784 0 0         if ($UseValgrind) {
    0          
1785 0           my $opts;
1786              
1787 0 0         if ($UseValgrind =~ /^\d+$/) {
1788 0           $opts = "--tool=memcheck --leak-check=full --show-possibly-lost=no";
1789              
1790 0 0         if (-f 'valgrind.suppress') {
1791 0           $cmd = "valgrind --num-callers=100 -q $opts --gen-suppressions=all --suppressions=valgrind.suppress $cmd";
1792             } else {
1793 0           $cmd = "valgrind --num-callers=100 -q $opts --gen-suppressions=all $cmd";
1794             }
1795              
1796             } else {
1797 0           $opts = $UseValgrind;
1798 0           $cmd = "valgrind -q $opts $cmd";
1799             }
1800              
1801 0           warn "$name\n";
1802             #warn "$cmd\n";
1803              
1804 0           undef $UseStap;
1805              
1806             } elsif ($UseStap) {
1807              
1808 0 0         if ($StapOutFileHandle) {
1809 0           close $StapOutFileHandle;
1810 0           undef $StapOutFileHandle;
1811             }
1812              
1813 0 0         if ($block->stap) {
1814 0           my ($stap_fh, $stap_fname) = tempfile("XXXXXXX",
1815             SUFFIX => '.stp',
1816             TMPDIR => 1,
1817             UNLINK => 1);
1818 0           my $stap = $block->stap;
1819              
1820 0 0         if ($stap =~ /\$LIB([_A-Z0-9]+)_PATH\b/) {
1821 0           my $name = $1;
1822 0           my $libname = 'lib' . lc($name);
1823 0           my $nginx_path = can_run($NginxBinary);
1824             #warn "nginx path: ", $nginx_path;
1825 0           my $line = `ldd $nginx_path|grep -E '$libname.*?\.so'`;
1826             #warn "line: $line";
1827 0           my $liblua_path;
1828 0 0         if ($line =~ m{\S+/$libname.*?\.so(?:\.\d+)*}) {
1829 0           $liblua_path = $&;
1830              
1831             } else {
1832             # static linking is used?
1833 0           $liblua_path = $nginx_path;
1834             }
1835              
1836 0           $stap =~ s/\$LIB${name}_PATH\b/$liblua_path/gi;
1837             }
1838              
1839 0           $stap =~ s/^\bS\(([^)]+)\)/probe process("nginx").statement("*\@$1")/smg;
1840 0           $stap =~ s/^\bF\(([^\)]+)\)/probe process("nginx").function("$1")/smg;
1841 0           $stap =~ s/^\bM\(([-\w]+)\)/probe process("nginx").mark("$1")/smg;
1842 0           $stap =~ s/\bT\(\)/println("Fire ", pp())/smg;
1843 0           print $stap_fh $stap;
1844 0           close $stap_fh;
1845              
1846 0           my ($out, $outfile);
1847              
1848 0 0 0       if (!defined $block->stap_out
      0        
1849             && !defined $block->stap_out_like
1850             && !defined $block->stap_out_unlike)
1851             {
1852 0           $StapOutFile = "/dev/stderr";
1853             }
1854              
1855 0 0         if (!$StapOutFile) {
1856 0           ($out, $outfile) = tempfile("XXXXXXXX",
1857             SUFFIX => '.stp-out',
1858             TMPDIR => 1,
1859             UNLINK => 1);
1860 0           close $out;
1861              
1862 0           $StapOutFile = $outfile;
1863              
1864             } else {
1865 0           $outfile = $StapOutFile;
1866             }
1867              
1868 0 0         open $out, $outfile or
1869             bail_out("Cannot open $outfile for reading: $!\n");
1870              
1871 0           $StapOutFileHandle = $out;
1872 0           $cmd = "exec $cmd";
1873              
1874 0 0         if (defined $ENV{LD_PRELOAD}) {
1875 0           $cmd = qq!LD_PRELOAD="$ENV{LD_PRELOAD}" $cmd!;
1876             }
1877              
1878 0 0         if (defined $ENV{LD_LIBRARY_PATH}) {
1879 0           $cmd = qq!LD_LIBRARY_PATH="$ENV{LD_LIBRARY_PATH}" $cmd!;
1880             }
1881              
1882 0           $cmd = "stap-nginx -c '$cmd' -o $outfile $stap_fname";
1883              
1884             #warn "CMD: $cmd\n";
1885              
1886 0           warn "$name\n";
1887             }
1888             }
1889              
1890 0 0 0       if ($Profiling || $UseValgrind || $UseStap) {
      0        
1891 0           my $pid = fork();
1892              
1893 0 0         if (!defined $pid) {
    0          
1894 0           bail_out("$name - fork() failed: $!");
1895              
1896             } elsif ($pid == 0) {
1897             # child process
1898             #my $rc = system($cmd);
1899              
1900 0           my $tb = Test::More->builder;
1901 0           $tb->no_ending(1);
1902              
1903 0           $InSubprocess = 1;
1904              
1905 0 0         if ($Verbose) {
1906 0           warn "command: $cmd\n";
1907             }
1908              
1909 0           exec "exec $cmd";
1910              
1911             } else {
1912             # main process
1913 0           $ChildPid = $pid;
1914             }
1915              
1916 0           sleep $TestNginxSleep;
1917              
1918             } else {
1919 0           my $i = 0;
1920 0           $ErrLogFilePos = 0;
1921 0           my ($exec_failed, $coredump, $exit_code);
1922 0           my $waited = 0;
1923              
1924 0           RUN_AGAIN:
1925              
1926             #warn "CMD: $cmd";
1927             system($cmd);
1928              
1929 0           my $status = $?;
1930              
1931 0 0         if ($status == -1) {
1932 0           $exec_failed = 1;
1933              
1934             } else {
1935 0           $exit_code = $status >> 8;
1936              
1937 0 0         if ($? > (128 << 8)) {
1938 0           $coredump = ($exit_code & 128);
1939 0           $exit_code = ($exit_code >> 8);
1940              
1941             } else {
1942 0           $coredump = ($status & 128);
1943             }
1944             }
1945              
1946 0 0         if (defined $must_die) {
1947             # Always should be able to execute
1948 0 0         if ($exec_failed) {
    0          
    0          
1949 0           Test::More::fail("$name - failed to execute the nginx command line")
1950              
1951             } elsif ($coredump) {
1952 0           Test::More::fail("$name - nginx core dumped")
1953              
1954             } elsif (looks_like_number($must_die)) {
1955 0           Test::More::is($must_die, $exit_code,
1956             "$name - die with the expected exit code")
1957              
1958             } else {
1959 0           Test::More::isnt($status, 0, "$name - die as expected")
1960             }
1961              
1962 0           $CheckErrorLog->($block, undef, $dry_run, $i, 0);
1963              
1964             #warn "Status: $status\n";
1965 0 0         if ($status == 0) {
1966 0           warn("WARNING: $name - nginx must die but it does ",
1967             "not; killing it (req $i)");
1968 0           my $tries = 15;
1969 0           for (my $i = 1; $i <= $tries; $i++) {
1970 0 0         if (-f $PidFile) {
1971 0           last;
1972             }
1973 0           sleep $TestNginxSleep;
1974             }
1975 0           my $pid = get_pid_from_pidfile($name);
1976 0           kill_process($pid, 1, $name);
1977             }
1978              
1979 0 0         goto RUN_AGAIN if ++$i < $RepeatEach;
1980 0           return;
1981             }
1982              
1983 0 0         if ($status != 0) {
1984 0 0 0       if ($ENV{TEST_NGINX_IGNORE_MISSING_DIRECTIVES} and
1985             my $directive = check_if_missing_directives())
1986             {
1987 0           $dry_run = "the lack of directive $directive";
1988              
1989             } else {
1990 0           $i++;
1991 0           my $delay = 0.1 * $i;
1992 0 0         if ($delay > 1) {
1993 0           $delay = 1;
1994             }
1995 0           sleep $delay;
1996 0           $waited += $delay;
1997 0 0         goto RUN_AGAIN if $waited < 30;
1998 0           bail_out("$name - Cannot start nginx using command \"$cmd\" (status code $status).");
1999             }
2000             }
2001             }
2002              
2003 0           sleep $TestNginxSleep;
2004             }
2005             }
2006              
2007             request:
2008              
2009 0 0         if ($Verbose) {
2010 0           warn "preparing requesting...\n";
2011             }
2012              
2013 0 0         if ($block->init) {
2014 0           eval $block->init;
2015 0 0         if ($@) {
2016 0           bail_out("$name - init failed: $@");
2017             }
2018             }
2019              
2020 0           my $i = 0;
2021 0           $ErrLogFilePos = 0;
2022 0           while ($i++ < $RepeatEach) {
2023             #warn "Use hup: $UseHup, i: $i\n";
2024              
2025 0 0         if ($Verbose) {
2026 0           warn "Run the test block...\n";
2027             }
2028              
2029 0 0 0       if (($CheckLeak || $Benchmark) && defined $block->tcp_listen) {
      0        
2030              
2031 0 0         my $n = defined($block->tcp_query_len) ? 1 : 0;
2032 0 0         $n += defined($block->tcp_query) ? 1 : 0;
2033              
2034 0 0         if ($n) {
2035             SKIP: {
2036 0           Test::More::skip(qq{$name -- tests skipped because embedded TCP }
  0            
2037             .qq{server does not work with the "check leak" mode}, $n);
2038             }
2039             }
2040             }
2041              
2042 0           my ($tcp_socket, $tcp_query_file);
2043 0 0 0       if (!($CheckLeak || $Benchmark) && defined $block->tcp_listen) {
      0        
2044              
2045 0           my $target = $block->tcp_listen;
2046              
2047 0           my $reply = $block->tcp_reply;
2048 0 0 0       if (!defined $reply && !defined $block->tcp_shutdown) {
2049 0           bail_out("$name - no --- tcp_reply specified but --- tcp_listen is specified");
2050             }
2051              
2052 0           my $req_len = $block->tcp_query_len;
2053              
2054 0 0 0       if (defined $block->tcp_query || defined $req_len) {
2055 0 0         if (!defined $req_len) {
2056 0           $req_len = length($block->tcp_query);
2057             }
2058 0           $tcp_query_file = tmpnam();
2059             }
2060              
2061             #warn "Reply: ", $reply;
2062              
2063 0           my $err;
2064 0           for (my $i = 0; $i < 30; $i++) {
2065 0 0         if ($target =~ /^\d+$/) {
    0          
2066 0           $tcp_socket = IO::Socket::INET->new(
2067             LocalHost => '127.0.0.1',
2068             LocalPort => $target,
2069             Proto => 'tcp',
2070             Reuse => 1,
2071             Listen => 5,
2072             Timeout => timeout(),
2073             );
2074             } elsif ($target =~ m{\S+\.sock$}) {
2075 0 0         if (-e $target) {
2076 0 0         unlink $target or die "cannot remove $target: $!";
2077             }
2078              
2079 0           $tcp_socket = IO::Socket::UNIX->new(
2080             Local => $target,
2081             Type => SOCK_STREAM,
2082             Listen => 5,
2083             Timeout => timeout(),
2084             );
2085             } else {
2086 0           bail_out("$name - bad tcp_listen target: $target");
2087             }
2088              
2089 0 0         if ($tcp_socket) {
2090 0           last;
2091             }
2092              
2093 0 0         if ($!) {
2094 0           $err = $!;
2095 0 0         if ($err =~ /address already in use/i) {
2096 0           warn "WARNING: failed to create the tcp listening socket: $err\n";
2097 0 0         if ($i >= 20) {
2098 0           my $pids = `fuser -n tcp $target`;
2099 0 0         if ($pids) {
2100 0           $pids =~ s/^\s+|\s+$//g;
2101 0           my @pids = split /\s+/, $pids;
2102 0           for my $pid (@pids) {
2103 0 0         if ($pid == $$) {
2104 0           warn "WARNING: Test::Nginx leaks mocked TCP sockets on target $target\n";
2105 0           next;
2106             }
2107              
2108 0           warn "WARNING: killing process $pid listening on target $target.\n";
2109 0           kill_process($pid, 1, $name);
2110             }
2111             }
2112             }
2113 0           sleep 1;
2114 0           next;
2115             }
2116             }
2117              
2118 0           last;
2119             }
2120              
2121 0 0 0       if (!$tcp_socket && $err) {
2122 0           bail_out("$name - failed to create the tcp listening socket: $err");
2123             }
2124              
2125 0           my $pid = fork();
2126              
2127 0 0         if (!defined $pid) {
    0          
2128 0           bail_out("$name - fork() failed: $!");
2129              
2130             } elsif ($pid == 0) {
2131             # child process
2132              
2133 0           my $tb = Test::More->builder;
2134 0           $tb->no_ending(1);
2135              
2136             #my $rc = system($cmd);
2137              
2138 0           $InSubprocess = 1;
2139              
2140 0 0         if ($Verbose) {
2141 0           warn "TCP server is listening on $target ...\n";
2142             }
2143              
2144 0           local $| = 1;
2145              
2146 0           my $client;
2147              
2148 0           while (1) {
2149 0           $client = $tcp_socket->accept();
2150 0 0         last if $client;
2151 0           warn("WARNING: $name - TCP server: failed to accept: $!\n");
2152 0           sleep $TestNginxSleep;
2153             }
2154              
2155 0           my ($no_read, $no_write);
2156 0 0         if (defined $block->tcp_shutdown) {
2157 0           my $shutdown = $block->tcp_shutdown;
2158 0 0         if ($block->tcp_shutdown_delay) {
2159 0           sleep $block->tcp_shutdown_delay;
2160             }
2161 0           $client->shutdown($shutdown);
2162 0 0 0       if ($shutdown == 0 || $shutdown == 2) {
2163 0 0         if ($Verbose) {
2164 0           warn "tcp server shutdown the read part.\n";
2165             }
2166 0           $no_read = 1;
2167              
2168             } else {
2169 0 0         if ($Verbose) {
2170 0           warn "tcp server shutdown the write part.\n";
2171             }
2172 0           $no_write = 1;
2173             }
2174             }
2175              
2176 0           my $buf;
2177              
2178 0 0         unless ($no_read) {
2179 0 0         if ($Verbose) {
2180 0           warn "TCP server reading request...\n";
2181             }
2182              
2183 0           while (1) {
2184 0           my $b;
2185 0           my $ret = $client->recv($b, 4096);
2186 0 0         if (!defined $ret) {
2187 0           die "failed to receive: $!\n";
2188             }
2189              
2190 0 0         if ($Verbose) {
2191             #warn "TCP server read data: [", $b, "]\n";
2192             }
2193              
2194 0           $buf .= $b;
2195              
2196              
2197             # flush read data to the file as soon as possible:
2198              
2199 0 0         if ($tcp_query_file) {
2200 0 0         open my $out, ">$tcp_query_file"
2201             or die "cannot open $tcp_query_file for writing: $!\n";
2202              
2203 0 0         if ($Verbose) {
2204 0           warn "writing received data [$buf] to file $tcp_query_file\n";
2205             }
2206              
2207 0           print $out $buf;
2208 0           close $out;
2209             }
2210              
2211 0 0 0       if (!$req_len || length($buf) >= $req_len) {
2212 0 0         if ($Verbose) {
2213 0           warn "len: ", length($buf), ", req len: $req_len\n";
2214             }
2215 0           last;
2216             }
2217             }
2218             }
2219              
2220 0           my $delay = parse_time($block->tcp_reply_delay);
2221 0 0         if ($delay) {
2222 0 0         if ($Verbose) {
2223 0           warn "sleep $delay before sending TCP reply\n";
2224             }
2225 0           sleep $delay;
2226             }
2227              
2228 0 0         unless ($no_write) {
2229 0 0         if (defined $reply) {
2230 0 0         if ($Verbose) {
2231 0           warn "TCP server writing reply...\n";
2232             }
2233              
2234 0           my $ref = ref $reply;
2235 0 0 0       if ($ref && $ref eq 'CODE') {
2236 0           $reply = $reply->($buf);
2237 0           $ref = ref $reply;
2238             }
2239              
2240 0 0         if (ref $reply) {
2241 0 0         if ($ref ne 'ARRAY') {
2242 0           bail_out('bad --- tcp_reply value');
2243             }
2244              
2245 0           for my $r (@$reply) {
2246 0 0         if ($Verbose) {
2247 0           warn "sending reply $r";
2248             }
2249 0           my $bytes = $client->send($r);
2250 0 0         if (!defined $bytes) {
2251 0           warn "WARNING: tcp server failed to send reply: $!\n";
2252             }
2253             }
2254              
2255             } else {
2256 0           my $bytes = $client->send($reply);
2257 0 0         if (!defined $bytes) {
2258 0           warn "WARNING: tcp server failed to send reply: $!\n";
2259             }
2260             }
2261             }
2262             }
2263              
2264 0 0         if ($Verbose) {
2265 0           warn "TCP server is shutting down...\n";
2266             }
2267              
2268 0 0         if (defined $block->tcp_no_close) {
2269 0           while (1) {
2270 0           sleep 1;
2271             }
2272             }
2273              
2274 0           $client->close();
2275 0           $tcp_socket->close();
2276              
2277 0           exit;
2278              
2279             } else {
2280             # main process
2281 0 0         if ($Verbose) {
2282 0           warn "started sub-process $pid for the TCP server\n";
2283             }
2284              
2285 0           $TcpServerPid = $pid;
2286             }
2287             }
2288              
2289 0 0 0       if (($CheckLeak || $Benchmark) && defined $block->udp_listen) {
      0        
2290              
2291 0 0         my $n = defined($block->udp_query) ? 1 : 0;
2292              
2293 0 0         if ($n) {
2294             SKIP: {
2295 0           Test::More::skip(qq{$name -- tests skipped because embedded UDP }
  0            
2296             .qq{server does not work with the "check leak" mode}, $n);
2297             }
2298             }
2299             }
2300              
2301 0           my ($udp_socket, $uds_socket_file, $udp_query_file);
2302 0 0 0       if (!($CheckLeak || $Benchmark) && defined $block->udp_listen) {
      0        
2303 0           my $reply = $block->udp_reply;
2304 0 0         if (!defined $reply) {
2305 0           bail_out("$name - no --- udp_reply specified but --- udp_listen is specified");
2306             }
2307              
2308 0 0         if (defined $block->udp_query) {
2309 0           $udp_query_file = tmpnam();
2310             }
2311              
2312 0           my $target = $block->udp_listen;
2313 0 0         if ($target =~ /^\d+$/) {
    0          
2314 0           my $port = $target;
2315              
2316 0 0         $udp_socket = IO::Socket::INET->new(
2317             LocalPort => $port,
2318             Proto => 'udp',
2319             Reuse => 1,
2320             Timeout => timeout(),
2321             ) or bail_out("$name - failed to create the udp listening socket: $!");
2322              
2323             } elsif ($target =~ m{\S+\.sock$}) {
2324 0 0         if (-e $target) {
2325 0 0         unlink $target or die "cannot remove $target: $!";
2326             }
2327              
2328 0 0         $udp_socket = IO::Socket::UNIX->new(
2329             Local => $target,
2330             Type => SOCK_DGRAM,
2331             Reuse => 1,
2332             Timeout => timeout(),
2333             ) or die "$!";
2334              
2335 0           $uds_socket_file = $target;
2336              
2337             } else {
2338 0           bail_out("$name - bad udp_listen target: $target");
2339             }
2340              
2341             #warn "Reply: ", $reply;
2342              
2343 0           my $pid = fork();
2344              
2345 0 0         if (!defined $pid) {
    0          
2346 0           bail_out("$name - fork() failed: $!");
2347              
2348             } elsif ($pid == 0) {
2349             # child process
2350              
2351 0           my $tb = Test::More->builder;
2352 0           $tb->no_ending(1);
2353              
2354             #my $rc = system($cmd);
2355              
2356 0           $InSubprocess = 1;
2357              
2358 0 0         if ($Verbose) {
2359 0           warn "UDP server is listening on $target ...\n";
2360             }
2361              
2362 0           local $| = 1;
2363              
2364 0 0         if ($Verbose) {
2365 0           warn "UDP server reading data...\n";
2366             }
2367              
2368 0           my $buf = '';
2369 0           my $sender = $udp_socket->recv($buf, 4096);
2370             #warn "sender: $sender";
2371 0 0         if (!defined $sender) {
2372 0           warn "udp recv failed: $!";
2373             }
2374              
2375 0 0         if ($Verbose) {
2376 0           warn "UDP server has got data: ", length $buf, "\n";
2377             }
2378              
2379 0 0         if ($udp_query_file) {
2380 0 0         open my $out, ">$udp_query_file"
2381             or die "cannot open $udp_query_file for writing: $!\n";
2382              
2383 0 0         if ($Verbose) {
2384 0           warn "writing received data [$buf] to file $udp_query_file\n";
2385             }
2386              
2387 0           print $out $buf;
2388 0           close $out;
2389             }
2390              
2391 0           my $delay = parse_time($block->udp_reply_delay);
2392 0 0         if ($delay) {
2393 0 0         if ($Verbose) {
2394 0           warn "$name - sleep $delay before sending UDP reply\n";
2395             }
2396 0           sleep $delay;
2397             }
2398              
2399 0 0         if (defined $reply) {
2400 0           my $ref = ref $reply;
2401 0 0 0       if ($ref && $ref eq 'CODE') {
2402 0           $reply = $reply->($buf);
2403 0           $ref = ref $reply;
2404             }
2405              
2406 0 0         if ($ref) {
2407 0 0         if ($ref ne 'ARRAY') {
2408 0           warn("$name - Bad --- udp_reply value");
2409             }
2410              
2411 0           for my $r (@$reply) {
2412             #warn "sending reply $r";
2413 0           my $bytes = $udp_socket->send($r);
2414 0 0         if (!defined $bytes) {
2415 0           warn "$name - WARNING: udp server failed to send reply: $!\n";
2416             }
2417             }
2418              
2419             } else {
2420 0 0         if ($reply =~ /syntax error at \(eval \d+\) line \d+, near/) {
2421 0           bail_out("$name - Bad --- udp_reply: $reply");
2422             }
2423              
2424 0           my $bytes = $udp_socket->send($reply);
2425 0 0         if (!defined $bytes) {
2426 0           warn "$name - WARNING: udp server failed to send reply: $!\n";
2427             }
2428             }
2429             }
2430              
2431 0 0         if ($Verbose) {
2432 0           warn "UDP server is shutting down...\n";
2433             }
2434              
2435 0           exit;
2436              
2437             } else {
2438             # main process
2439 0 0         if ($Verbose) {
2440 0           warn "started sub-process $pid for the UDP server\n";
2441             }
2442              
2443 0           $UdpServerPid = $pid;
2444             }
2445             }
2446              
2447 0 0         if ($i > 1) {
2448 0           write_user_files($block, $rand_ports);
2449             }
2450              
2451 0 0 0       if ($should_skip && defined $tests_to_skip) {
    0          
2452             SKIP: {
2453 0           Test::More::skip("$name - $skip_reason", $tests_to_skip);
  0            
2454              
2455 0           $RunTestHelper->($block, $dry_run, $i - 1);
2456 0           run_tcp_server_tests($block, $tcp_socket, $tcp_query_file);
2457 0           run_udp_server_tests($block, $udp_socket, $udp_query_file);
2458             }
2459              
2460             } elsif ($should_todo) {
2461             TODO: {
2462 0           Test::More::todo_skip("$name - $todo_reason", $tests_to_skip);
  0            
2463              
2464 0           $RunTestHelper->($block, $dry_run, $i - 1);
2465 0           run_tcp_server_tests($block, $tcp_socket, $tcp_query_file);
2466 0           run_udp_server_tests($block, $udp_socket, $udp_query_file);
2467             }
2468              
2469             } else {
2470 0           $RunTestHelper->($block, $dry_run, $i - 1);
2471 0           run_tcp_server_tests($block, $tcp_socket, $tcp_query_file);
2472 0           run_udp_server_tests($block, $udp_socket, $udp_query_file);
2473             }
2474              
2475 0 0         if (defined $udp_socket) {
2476 0 0         if (defined $UdpServerPid) {
2477 0           kill_process($UdpServerPid, 1, $name);
2478 0           undef $UdpServerPid;
2479             }
2480              
2481 0           $udp_socket->close();
2482 0           undef $udp_socket;
2483             }
2484              
2485 0 0         if (defined $uds_socket_file) {
2486 0 0         unlink($uds_socket_file)
2487             or warn "failed to unlink $uds_socket_file";
2488             }
2489              
2490 0 0         if (defined $tcp_socket) {
2491 0 0         if (defined $TcpServerPid) {
2492 0 0         if ($Verbose) {
2493 0           warn "killing TCP server, pid $TcpServerPid\n";
2494             }
2495 0           kill_process($TcpServerPid, 1, $name);
2496 0           undef $TcpServerPid;
2497             }
2498              
2499 0 0         if ($Verbose) {
2500 0           warn "closing the TCP socket\n";
2501             }
2502              
2503 0           $tcp_socket->close();
2504 0           undef $tcp_socket;
2505             }
2506             }
2507              
2508 0 0         if ($StapOutFileHandle) {
2509 0           close $StapOutFileHandle;
2510 0           undef $StapOutFileHandle;
2511             }
2512              
2513 0 0         if (my $total_errlog = $ENV{TEST_NGINX_ERROR_LOG}) {
2514 0           my $errlog = $ErrLogFile;
2515 0 0         if (-s $errlog) {
2516 0 0         open my $out, ">>$total_errlog" or
2517             bail_out "Failed to append test case title to $total_errlog: $!\n";
2518 0           print $out "\n=== $0 $name\n";
2519 0           close $out;
2520 0 0         system("cat $errlog >> $total_errlog") == 0 or
2521             bail_out "Failed to append $errlog to $total_errlog. Abort.\n";
2522             }
2523             }
2524              
2525 0 0 0       if (($Profiling || $UseValgrind || $UseStap) && !$UseHup) {
      0        
2526             #warn "Found quit...";
2527 0 0         if (-f $PidFile) {
2528             #warn "found pid file...";
2529 0           my $pid = get_pid_from_pidfile($name);
2530 0           my $i = 0;
2531             retry:
2532 0 0         if (is_running($pid)) {
2533 0           write_config_file($block, $config, $rand_ports);
2534              
2535 0 0         if ($Verbose) {
2536 0           warn "sending QUIT signal to $pid";
2537             }
2538              
2539 0 0         if (kill(SIGQUIT, $pid) == 0) { # send quit signal
2540 0           warn("$name - Failed to send quit signal to the nginx process with PID $pid");
2541             }
2542              
2543 0           sleep $TestNginxSleep;
2544              
2545 0 0         if (-f $PidFile) {
2546 0 0         if ($i++ < 20) {
2547 0 0         if ($Verbose) {
2548 0           warn "nginx not quitted, retrying...\n";
2549             }
2550              
2551 0           goto retry;
2552             }
2553              
2554 0 0         if ($Verbose) {
2555 0           warn "sending KILL signal to $pid";
2556             }
2557              
2558 0           kill(SIGKILL, $pid);
2559 0           waitpid($pid, 0);
2560              
2561 0 0 0       if (!unlink($PidFile) && -f $PidFile) {
2562 0           bail_out "Failed to remove pid file $PidFile: $!\n";
2563             }
2564              
2565             } else {
2566             #warn "nginx killed";
2567             }
2568              
2569             } else {
2570 0 0 0       if (!unlink($PidFile) && -f $PidFile) {
2571 0           bail_out "Failed to remove pid file $PidFile: $!\n";
2572             }
2573             }
2574             } else {
2575             #warn "pid file not found";
2576             }
2577             }
2578             }
2579              
2580             END {
2581 5 50   5   141 return if $InSubprocess;
2582              
2583 5         29 cleanup();
2584              
2585 5 50 33     70 if ($UseStap || $UseValgrind || !$ENV{TEST_NGINX_NO_CLEAN}) {
      33        
2586 5         24 local $?; # to avoid confusing Test::Builder::_ending
2587 5 50 33     123 if (defined $PidFile && -f $PidFile) {
2588 0         0 my $pid = get_pid_from_pidfile('');
2589 0 0       0 if (!$pid) {
2590 0         0 bail_out "No pid found.";
2591             }
2592 0 0       0 if (is_running($pid)) {
2593 0         0 kill_process($pid, 1, "END");
2594              
2595             } else {
2596 0         0 unlink $PidFile;
2597             }
2598             }
2599             }
2600              
2601 5         28 check_prev_block_shutdown_error_log();
2602              
2603 5 50       81 if ($Randomize) {
2604 0 0 0     0 if (defined $ServRoot && -d $ServRoot && $ServRoot =~ m{/t/servroot_\d+}) {
      0        
2605 0         0 system("rm -rf $ServRoot");
2606             }
2607             }
2608             }
2609              
2610             # check if we can run some command
2611             sub can_run {
2612 0     0 0   my ($cmd) = @_;
2613              
2614             #warn "can run: $cmd\n";
2615 0 0         if ($cmd =~ m{[/\\]}) {
2616 0 0 0       if (-f $cmd && -x $cmd) {
2617 0           return $cmd;
2618             }
2619              
2620 0           return undef;
2621             }
2622              
2623 0           for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') {
2624 0 0         next if $dir eq '';
2625 0           my $abs = File::Spec->catfile($dir, $cmd);
2626             #warn $abs;
2627 0 0 0       return $abs if -f $abs && -x $abs;
2628             }
2629              
2630 0           return undef;
2631             }
2632              
2633             sub use_http2 ($) {
2634 0     0 0   my $block = shift;
2635              
2636 0           my $cached = $block->test_nginx_enabled_http2;
2637 0 0         if (defined $cached) {
2638 0           return $cached;
2639             }
2640              
2641 0 0         if (defined $block->http2) {
2642 0 0         if ($block->raw_request) {
2643 0           bail_out("cannot use --- http2 with --- raw_request");
2644             }
2645              
2646 0 0         if ($block->pipelined_requests) {
2647 0           bail_out("cannot use --- http2 with --- pipelined_requests");
2648             }
2649              
2650 0           $block->set_value("test_nginx_enabled_http2", 1);
2651              
2652 0 0         if (!$LoadedIPCRun) {
2653 0           require IPC::Run;
2654 0           $LoadedIPCRun = 1;
2655             }
2656 0           return 1;
2657             }
2658              
2659 0 0         if ($UseHttp2) {
2660 0 0         if ($block->raw_request) {
2661 0           warn "WARNING: ", $block->name, " - using raw_request HTTP/2, will not use HTTP/2\n";
2662 0           $block->set_value("test_nginx_enabled_http2", 0);
2663 0           return undef;
2664             }
2665              
2666 0 0         if ($block->pipelined_requests) {
2667 0           warn "WARNING: ", $block->name, " - using pipelined_requests, will not use HTTP/2\n";
2668 0           $block->set_value("test_nginx_enabled_http2", 0);
2669 0           return undef;
2670             }
2671              
2672 0 0         if (!defined $block->request) {
2673 0           $block->set_value("test_nginx_enabled_http2", 0);
2674 0           return undef;
2675             }
2676              
2677 0 0 0       if (!ref $block->request && $block->request =~ m{HTTP/1\.0}s) {
2678 0           warn "WARNING: ", $block->name, " - explicitly rquires HTTP 1.0, so will not use HTTP/2\n";
2679 0           $block->set_value("test_nginx_enabled_http2", 0);
2680 0           return undef;
2681             }
2682              
2683 0           $block->set_value("test_nginx_enabled_http2", 1);
2684              
2685 0 0         if (!$LoadedIPCRun) {
2686 0           require IPC::Run;
2687 0           $LoadedIPCRun = 1;
2688             }
2689              
2690 0           return 1;
2691             }
2692              
2693 0           $block->set_value("test_nginx_enabled_http2", 0);
2694 0           return undef;
2695             }
2696              
2697             1;