File Coverage

lib/Test/Nginx/Util.pm
Criterion Covered Total %
statement 68 1025 6.6
branch 9 668 1.3
condition 3 195 1.5
subroutine 20 73 27.4
pod 0 52 0.0
total 100 2013 4.9


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