File Coverage

lib/Test/Nginx/Util.pm
Criterion Covered Total %
statement 80 1422 5.6
branch 11 906 1.2
condition 3 247 1.2
subroutine 23 86 26.7
pod 0 65 0.0
total 117 2726 4.2


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