File Coverage

lib/Test/Nginx/Util.pm
Criterion Covered Total %
statement 72 1129 6.3
branch 10 730 1.3
condition 3 203 1.4
subroutine 21 78 26.9
pod 0 57 0.0
total 106 2197 4.8


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