[PATCH] Tests: run syslog and error_log tests on win32

Sergey Kandaurov pluknet at nginx.com
Wed Mar 29 00:05:20 UTC 2023


> On 22 Mar 2023, at 05:02, Maxim Dounin <mdounin at mdounin.ru> wrote:
> 
> Hello!
> 
> On Mon, Mar 20, 2023 at 06:13:34PM +0400, Sergey Kandaurov wrote:
> 
>> # HG changeset patch
>> # User Sergey Kandaurov <pluknet at nginx.com>
>> # Date 1679321601 -14400
>> #      Mon Mar 20 18:13:21 2023 +0400
>> # Node ID f3225ad9300ee2c11c0dec54b9605e67060b7347
>> # Parent  1e1d0f3874b0c5b1e399ec76b0198b5c9c265a36
>> Tests: run syslog and error_log tests on win32.
>> 
>> They are supposed to work well now, no reason to skip them.
> 
> It might be a good idea to explicitly mention why it wasn't 
> supposed to work.

It wasn't supposed to work due to stderr tests, now fixed.
See full description below in the updated series.

> 
>> An exception is logging to stderr.
> 
> And why stderr is not supposed to.
> 
> (Just in case, the culprit is CreateProcess(CREATE_NO_WINDOW) used 
> when starting worker processes, which creates a process without a 
> console.  This probably can be improved to preserve console if 
> logging to stderr is used.)

Thanks, applied to description.

> 
>> 
>> diff --git a/error_log.t b/error_log.t
>> --- a/error_log.t
>> +++ b/error_log.t
>> @@ -22,8 +22,6 @@ use Test::Nginx;
>> select STDERR; $| = 1;
>> select STDOUT; $| = 1;
>> 
>> -plan(skip_all => 'win32') if $^O eq 'MSWin32';
>> -
>> my $t = Test::Nginx->new()->has(qw/http limit_req/)
>> 	->plan(25)->write_file_expand('nginx.conf', <<'EOF');
>> 
>> @@ -110,7 +108,7 @@ EOF
>> open OLDERR, ">&", \*STDERR;
>> open STDERR, '>', $t->testdir() . '/stderr' or die "Can't reopen STDERR: $!";
>> open my $stderr, '<', $t->testdir() . '/stderr'
>> -	or die "Can't open stderr file: $!";
>> +	or die "Can't open stderr file: $!" unless $^O eq 'MSWin32';
> 
> It shouldn't be a problem to open the file on Windows.  Though 
> will require explicitly closing it at the end of the test, so the 
> test suite will be able to remove the test directory in 
> destructor.
> 
> (In other tests this will also require reordering of daemon 
> startup, to avoid leaking the descriptor to daemons.)

Applied too.

>> [..]
>> @@ -255,13 +259,16 @@ sub syslog_daemon {
>> 		LocalAddr => "127.0.0.1:$port"
>> 	);
>> 
>> -	open my $fh, '>', $t->testdir() . '/' . $file;
>> -	select $fh; $| = 1;
>> +	my $path = $t->testdir() . '/' . $file;
>> +	open my $fh, '>', $path;
>> +	close $fh;
>> 
>> 	while (1) {
>> 		my $buffer;
>> 		$s->recv($buffer, 4096);
>> +		open $fh, '>>', $path;
>> 		print $fh $buffer . "\n";
>> +		close $fh;
>> 	}
> 
> It might be a good idea to clarify in the commit log why this is 
> needed.  (Notably, that pseudo-processes created by Perl's fork() 
> emulation on win32 cannot be gracefully stopped when they are 
> blocked in a system call, and using kill('KILL') as nginx does 
> seems to leave the files open.)

Well, I don't like this kind of open/close tango.
Reading syslog can be done in the main process, without
invoking pseudo-processes with their limitations.
This should work with minor number of syslog messages
as seen in tests.  Below is updated series, syslog part
is extracted into a separate change.

# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1680046138 -14400
#      Wed Mar 29 03:28:58 2023 +0400
# Node ID be1832cdf571d465aed741b7dcbd583cedc43365
# Parent  0351dee227a8341e442feeb03920a46b259adeb5
Tests: revised reading syslog messages with test daemon.

On win32, terminating test daemons blocked by a system call leads
to leaking file descriptors, which breaks temp directory removal.
See limitations of pseudo-processes used in Perl's fork() emulation.
Now it is replaced with reading syslog in the main process.

diff --git a/mail_error_log.t b/mail_error_log.t
--- a/mail_error_log.t
+++ b/mail_error_log.t
@@ -90,12 +90,16 @@ open my $stderr, '<', $t->testdir() . '/
 	or die "Can't open stderr file: $!";
 
 $t->run_daemon(\&Test::Nginx::IMAP::imap_test_daemon);
-$t->run_daemon(\&syslog_daemon, port(8981), $t, 's_glob.log');
-$t->run_daemon(\&syslog_daemon, port(8982), $t, 's_info.log');
+
+my ($s_glob, $s_info) = map {
+	IO::Socket::INET->new(
+		Proto => 'udp',
+		LocalAddr => '127.0.0.1:' . port($_)
+	)
+		or die "Can't open syslog socket: $!";
+} 8981, 8982;
 
 $t->waitforsocket('127.0.0.1:' . port(8144));
-$t->waitforfile($t->testdir . '/s_glob.log');
-$t->waitforfile($t->testdir . '/s_info.log');
 
 $t->run();
 
@@ -124,16 +128,16 @@ is(lines($t, 'stderr', '[debug]'), 0, 's
 
 like($t->read_file('e_glob.log'), qr!nginx/[.0-9]+!, 'error global');
 like($t->read_file('e_glob2.log'), qr!nginx/[.0-9]+!, 'error global 2');
-is_deeply(levels($t, 'e_glob.log'), levels($t, 'e_glob2.log'),
-	'multiple error global');
+is_deeply(levels($t->read_file('e_glob.log')),
+	levels($t->read_file('e_glob2.log')), 'multiple error global');
 
 # syslog
 
 parse_syslog_message('syslog', get_syslog());
 
-is_deeply(levels($t, 's_glob.log'), levels($t, 'e_glob.log'),
+is_deeply(levels(read_syslog($s_glob)), levels($t->read_file('e_glob.log')),
 	'global syslog messages');
-is_deeply(levels($t, 's_info.log'), levels($t, 'e_info.log'),
+is_deeply(levels(read_syslog($s_info)), levels($t->read_file('e_info.log')),
 	'mail syslog messages');
 
 ###############################################################################
@@ -153,10 +157,10 @@ sub lines {
 }
 
 sub levels {
-	my ($t, $file) = @_;
+	my ($file) = @_;
 	my %levels_hash;
 
-	map { $levels_hash{$_}++; } ($t->read_file($file) =~ /(\[\w+\])/g);
+	map { $levels_hash{$_}++; } ($file =~ /(\[\w+\])/g);
 
 	return \%levels_hash;
 }
@@ -193,6 +197,19 @@ sub get_syslog {
 	return $data;
 }
 
+sub read_syslog {
+	my ($s) = @_;
+	my $data = '';
+
+	IO::Select->new($s)->can_read(1);
+	while (IO::Select->new($s)->can_read(0.1)) {
+		my $buffer;
+		sysread($s, $buffer, 4096);
+		$data .= $buffer;
+	}
+	return $data;
+}
+
 sub parse_syslog_message {
 	my ($desc, $line) = @_;
 
@@ -246,23 +263,3 @@ SKIP: {
 }
 
 ###############################################################################
-
-sub syslog_daemon {
-	my ($port, $t, $file) = @_;
-
-	my $s = IO::Socket::INET->new(
-		Proto => 'udp',
-		LocalAddr => "127.0.0.1:$port"
-	);
-
-	open my $fh, '>', $t->testdir() . '/' . $file;
-	select $fh; $| = 1;
-
-	while (1) {
-		my $buffer;
-		$s->recv($buffer, 4096);
-		print $fh $buffer . "\n";
-	}
-}
-
-###############################################################################
diff --git a/stream_error_log.t b/stream_error_log.t
--- a/stream_error_log.t
+++ b/stream_error_log.t
@@ -78,12 +78,16 @@ open my $stderr, '<', $t->testdir() . '/
 	or die "Can't open stderr file: $!";
 
 $t->run_daemon(\&stream_daemon);
-$t->run_daemon(\&syslog_daemon, port(8983), $t, 's_glob.log');
-$t->run_daemon(\&syslog_daemon, port(8984), $t, 's_stream.log');
+
+my ($s_glob, $s_stream) = map {
+	IO::Socket::INET->new(
+		Proto => 'udp',
+		LocalAddr => '127.0.0.1:' . port($_)
+	)
+		or die "Can't open syslog socket: $!";
+} 8983, 8984;
 
 $t->waitforsocket('127.0.0.1:' . port(8081));
-$t->waitforfile($t->testdir . '/s_glob.log');
-$t->waitforfile($t->testdir . '/s_stream.log');
 
 $t->run();
 
@@ -111,17 +115,17 @@ is(lines($t, 'stderr', '[debug]'), 0, 's
 
 like($t->read_file('e_glob.log'), qr!nginx/[.0-9]+!, 'error global');
 like($t->read_file('e_glob2.log'), qr!nginx/[.0-9]+!, 'error global 2');
-is_deeply(levels($t, 'e_glob.log'), levels($t, 'e_glob2.log'),
-	'multiple error global');
+is_deeply(levels($t->read_file('e_glob.log')),
+	levels($t->read_file('e_glob2.log')), 'multiple error global');
 
 # syslog
 
 parse_syslog_message('syslog', get_syslog('data2', '127.0.0.1:' . port(8082),
 	port(8985)));
 
-is_deeply(levels($t, 's_glob.log'), levels($t, 'e_glob.log'),
+is_deeply(levels(read_syslog($s_glob)), levels($t->read_file('e_glob.log')),
 	'global syslog messages');
-is_deeply(levels($t, 's_stream.log'), levels($t, 'e_stream.log'),
+is_deeply(levels(read_syslog($s_stream)), levels($t->read_file('e_stream.log')),
 	'stream syslog messages');
 
 # error_log context
@@ -161,10 +165,10 @@ sub lines {
 }
 
 sub levels {
-	my ($t, $file) = @_;
+	my ($file) = @_;
 	my %levels_hash;
 
-	map { $levels_hash{$_}++; } ($t->read_file($file) =~ /(\[\w+\])/g);
+	map { $levels_hash{$_}++; } ($file =~ /(\[\w+\])/g);
 
 	return \%levels_hash;
 }
@@ -202,6 +206,19 @@ sub get_syslog {
 	return $data;
 }
 
+sub read_syslog {
+	my ($s) = @_;
+	my $data = '';
+
+	IO::Select->new($s)->can_read(1);
+	while (IO::Select->new($s)->can_read(0.1)) {
+		my $buffer;
+		sysread($s, $buffer, 4096);
+		$data .= $buffer;
+	}
+	return $data;
+}
+
 sub parse_syslog_message {
 	my ($desc, $line) = @_;
 
@@ -256,24 +273,6 @@ SKIP: {
 
 ###############################################################################
 
-sub syslog_daemon {
-	my ($port, $t, $file) = @_;
-
-	my $s = IO::Socket::INET->new(
-		Proto => 'udp',
-		LocalAddr => "127.0.0.1:$port"
-	);
-
-	open my $fh, '>', $t->testdir() . '/' . $file;
-	select $fh; $| = 1;
-
-	while (1) {
-		my $buffer;
-		$s->recv($buffer, 4096);
-		print $fh $buffer . "\n";
-	}
-}
-
 sub stream_daemon {
 	my $server = IO::Socket::INET->new(
 		Proto => 'tcp',
diff --git a/syslog.t b/syslog.t
--- a/syslog.t
+++ b/syslog.t
@@ -25,8 +25,6 @@ use Test::Nginx;
 select STDERR; $| = 1;
 select STDOUT; $| = 1;
 
-plan(skip_all => 'win32') if $^O eq 'MSWin32';
-
 my $t = Test::Nginx->new()->has(qw/http limit_req/)->plan(62);
 
 $t->write_file_expand('nginx.conf', <<'EOF');
@@ -142,13 +140,13 @@ http {
 
 EOF
 
-$t->run_daemon(\&syslog_daemon, port(8981), $t, 's_glob.log');
-$t->run_daemon(\&syslog_daemon, port(8982), $t, 's_http.log');
-$t->run_daemon(\&syslog_daemon, port(8983), $t, 's_if.log');
-
-$t->waitforfile($t->testdir . '/s_glob.log');
-$t->waitforfile($t->testdir . '/s_http.log');
-$t->waitforfile($t->testdir . '/s_if.log');
+my ($s_glob, $s_http, $s_if) = map {
+	IO::Socket::INET->new(
+		Proto => 'udp',
+		LocalAddr => '127.0.0.1:' . port($_)
+	)
+		or die "Can't open syslog socket: $!";
+} 8981, 8982, 8983;
 
 $t->run();
 
@@ -186,7 +184,6 @@ is($lines[1], $lines[2], 'error_log many
 # error_log log levels
 
 SKIP: {
-
 skip "no --with-debug", 1 unless $t->has_module('--with-debug');
 
 isnt(syslog_lines('/debug', '[debug]'), 0, 'debug');
@@ -210,8 +207,10 @@ is(syslog_lines('/high', '[error]'), 1, 
 
 # check for the presence of the syslog messages in the global and http contexts
 
-is_deeply(levels($t, 's_glob.log'), levels($t, 'f_glob.log'), 'master syslog');
-is_deeply(levels($t, 's_http.log'), levels($t, 'f_http.log'), 'http syslog');
+is_deeply(levels(read_syslog($s_glob)), levels($t->read_file('f_glob.log')),
+	'master syslog');
+is_deeply(levels(read_syslog($s_http)), levels($t->read_file('f_http.log')),
+	'http syslog');
 
 http_get('/if');
 http_get('/if/empty?logme=');
@@ -219,11 +218,11 @@ http_get('/if/zero?logme=0');
 http_get('/if/good?logme=1');
 http_get('/if/work?logme=yes');
 
-get_syslog('/a');
+my $syslog_if = read_syslog($s_if);
 
-like($t->read_file('s_if.log'), qr/good:404/s, 'syslog if success');
-like($t->read_file('s_if.log'), qr/work:404/s, 'syslog if success 2');
-unlike($t->read_file('s_if.log'), qr/(if:|empty:|zero:)404/, 'syslog if fail');
+like($syslog_if, qr/good:404/s, 'syslog if success');
+like($syslog_if, qr/work:404/s, 'syslog if success 2');
+unlike($syslog_if, qr/(if:|empty:|zero:)404/, 'syslog if fail');
 
 like(get_syslog('/nohostname'),
 	qr/^<(\d{1,3})>				# PRI
@@ -258,10 +257,10 @@ sub syslog_lines {
 }
 
 sub levels {
-	my ($t, $file) = @_;
+	my ($file) = @_;
 	my %levels_hash;
 
-	map { $levels_hash{$_}++; } ($t->read_file($file) =~ /(\[\w+\])/g);
+	map { $levels_hash{$_}++; } ($file =~ /(\[\w+\])/g);
 
 	return \%levels_hash;
 }
@@ -281,6 +280,19 @@ sub get_syslog {
 	return $data;
 }
 
+sub read_syslog {
+	my ($s) = @_;
+	my $data = '';
+
+	IO::Select->new($s)->can_read(1);
+	while (IO::Select->new($s)->can_read(0.1)) {
+		my $buffer;
+		sysread($s, $buffer, 4096);
+		$data .= $buffer;
+	}
+	return $data;
+}
+
 sub parse_syslog_message {
 	my ($desc, $line) = @_;
 
@@ -331,23 +343,3 @@ sub parse_syslog_message {
 }
 
 ###############################################################################
-
-sub syslog_daemon {
-	my ($port, $t, $file) = @_;
-
-	my $s = IO::Socket::INET->new(
-		Proto => 'udp',
-		LocalAddr => "127.0.0.1:$port"
-	);
-
-	open my $fh, '>', $t->testdir() . '/' . $file;
-	select $fh; $| = 1;
-
-	while (1) {
-		my $buffer;
-		$s->recv($buffer, 4096);
-		print $fh $buffer . "\n";
-	}
-}
-
-###############################################################################
# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1680046139 -14400
#      Wed Mar 29 03:28:59 2023 +0400
# Node ID 98fb93f9328c15b432d04fc372e0614c2c720f0a
# Parent  be1832cdf571d465aed741b7dcbd583cedc43365
Tests: allow to run error_log tests on win32.

Tests are supposed to work now with stderr parts isolated.
In particular, leaking stderr file descriptor was fixed
to allow Test::Nginx destructor to remove temp directory.

Logging to stderr doesn't currently work in worker processes
on win32.  This is caused by CreateProcess(CREATE_NO_WINDOW).
Such tests are marked TODO.

diff --git a/error_log.t b/error_log.t
--- a/error_log.t
+++ b/error_log.t
@@ -22,8 +22,6 @@ use Test::Nginx;
 select STDERR; $| = 1;
 select STDOUT; $| = 1;
 
-plan(skip_all => 'win32') if $^O eq 'MSWin32';
-
 my $t = Test::Nginx->new()->has(qw/http limit_req/)
 	->plan(25)->write_file_expand('nginx.conf', <<'EOF');
 
@@ -123,40 +121,69 @@ open STDERR, ">&", \*OLDERR;
 http_get('/');
 
 SKIP: {
-
 skip "no --with-debug", 3 unless $t->has_module('--with-debug');
 
 http_get('/debug');
 isnt(lines($t, 'e_debug_debug.log', '[debug]'), 0, 'file debug debug');
 is(lines($t, 'e_debug_info.log', '[debug]'), 0, 'file debug info');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 isnt(lines($t, 'stderr', '[debug]'), 0, 'stderr debug');
 
 }
 
+}
+
 http_get('/info');
 is(lines($t, 'e_info_debug.log', '[info]'), 1, 'file info debug');
 is(lines($t, 'e_info_info.log', '[info]'), 1, 'file info info');
 is(lines($t, 'e_info_notice.log', '[info]'), 0, 'file info notice');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 is(lines($t, 'stderr', '[info]'), 1, 'stderr info');
 
+}
+
 http_get('/notice');
 is(lines($t, 'e_notice_info.log', '[notice]'), 1, 'file notice info');
 is(lines($t, 'e_notice_notice.log', '[notice]'), 1, 'file notice notice');
 is(lines($t, 'e_notice_warn.log', '[notice]'), 0, 'file notice warn');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 is(lines($t, 'stderr', '[notice]'), 1, 'stderr notice');
 
+}
+
 http_get('/warn');
 is(lines($t, 'e_warn_notice.log', '[warn]'), 1, 'file warn notice');
 is(lines($t, 'e_warn_warn.log', '[warn]'), 1, 'file warn warn');
 is(lines($t, 'e_warn_error.log', '[warn]'), 0, 'file warn error');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 is(lines($t, 'stderr', '[warn]'), 1, 'stderr warn');
 
+}
+
 http_get('/error');
 is(lines($t, 'e_error_warn.log', '[error]'), 1, 'file error warn');
 is(lines($t, 'e_error_error.log', '[error]'), 1, 'file error error');
 is(lines($t, 'e_error_alert.log', '[error]'), 0, 'file error alert');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 is(lines($t, 'stderr', '[error]'), 1, 'stderr error');
 
+}
+
 # count log messages emitted with various error_log levels
 
 http_get('/file_low');
@@ -168,6 +195,9 @@ is(lines($t, 'e_multi.log', '[error]'), 
 http_get('/file_high');
 is(lines($t, 'e_multi_high.log', '[error]'), 1, 'file high');
 
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 http_get('/stderr_low');
 is(lines($t, 'stderr', '[error]'), 2, 'stderr low');
 
@@ -177,6 +207,10 @@ is(lines($t, 'stderr', '[error]'), 2, 's
 http_get('/stderr_high');
 is(lines($t, 'stderr', '[error]'), 1, 'stderr high');
 
+}
+
+close $stderr;
+
 ###############################################################################
 
 sub lines {
diff --git a/mail_error_log.t b/mail_error_log.t
--- a/mail_error_log.t
+++ b/mail_error_log.t
@@ -26,8 +26,6 @@ use Test::Nginx::IMAP;
 select STDERR; $| = 1;
 select STDOUT; $| = 1;
 
-plan(skip_all => 'win32') if $^O eq 'MSWin32';
-
 my $t = Test::Nginx->new()->has(qw/mail imap http rewrite/);
 
 $t->plan(30)->write_file_expand('nginx.conf', <<'EOF');
@@ -84,13 +82,13 @@ http {
 
 EOF
 
+$t->run_daemon(\&Test::Nginx::IMAP::imap_test_daemon);
+
 open OLDERR, ">&", \*STDERR;
 open STDERR, '>', $t->testdir() . '/stderr' or die "Can't reopen STDERR: $!";
 open my $stderr, '<', $t->testdir() . '/stderr'
 	or die "Can't open stderr file: $!";
 
-$t->run_daemon(\&Test::Nginx::IMAP::imap_test_daemon);
-
 my ($s_glob, $s_info) = map {
 	IO::Socket::INET->new(
 		Proto => 'udp',
@@ -121,7 +119,14 @@ isnt(lines($t, 'e_debug.log', '[debug]')
 
 isnt(lines($t, 'e_info.log', '[info]'), 0, 'file info in info');
 is(lines($t, 'e_info.log', '[debug]'), 0, 'file debug in info');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 isnt(lines($t, 'stderr', '[info]'), 0, 'stderr info in info');
+
+}
+
 is(lines($t, 'stderr', '[debug]'), 0, 'stderr debug in info');
 
 # multiple error_log
@@ -140,6 +145,8 @@ is_deeply(levels(read_syslog($s_glob)), 
 is_deeply(levels(read_syslog($s_info)), levels($t->read_file('e_info.log')),
 	'mail syslog messages');
 
+close $stderr;
+
 ###############################################################################
 
 sub lines {
diff --git a/stream_error_log.t b/stream_error_log.t
--- a/stream_error_log.t
+++ b/stream_error_log.t
@@ -26,8 +26,6 @@ use Test::Nginx::Stream qw/ stream /;
 select STDERR; $| = 1;
 select STDOUT; $| = 1;
 
-plan(skip_all => 'win32') if $^O eq 'MSWin32';
-
 my $t = Test::Nginx->new()->has(qw/stream/)->plan(34);
 
 $t->write_file_expand('nginx.conf', <<'EOF');
@@ -72,13 +70,13 @@ stream {
 
 EOF
 
+$t->run_daemon(\&stream_daemon);
+
 open OLDERR, ">&", \*STDERR;
 open STDERR, '>', $t->testdir() . '/stderr' or die "Can't reopen STDERR: $!";
 open my $stderr, '<', $t->testdir() . '/stderr'
 	or die "Can't open stderr file: $!";
 
-$t->run_daemon(\&stream_daemon);
-
 my ($s_glob, $s_stream) = map {
 	IO::Socket::INET->new(
 		Proto => 'udp',
@@ -108,7 +106,14 @@ isnt(lines($t, 'e_debug.log', '[debug]')
 
 isnt(lines($t, 'e_info.log', '[info]'), 0, 'file info in info');
 is(lines($t, 'e_info.log', '[debug]'), 0, 'file debug in info');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 isnt(lines($t, 'stderr', '[info]'), 0, 'stderr info in info');
+
+}
+
 is(lines($t, 'stderr', '[debug]'), 0, 'stderr debug in info');
 
 # multiple error_log
@@ -139,8 +144,14 @@ my $msg = 'no live upstreams while conne
 
 unlike($t->read_file('e_glob.log'), qr/$msg/ms, 'stream error in global');
 like($t->read_file('e_info.log'), qr/$msg/ms, 'stream error in info');
+unlike($t->read_file('e_emerg.log'), qr/$msg/ms, 'stream error in emerg');
+
+TODO: {
+local $TODO = 'win32' if $^O eq 'MSWin32';
+
 like($t->read_file('stderr'), qr/$msg/ms, 'stream error in info stderr');
-unlike($t->read_file('e_emerg.log'), qr/$msg/ms, 'stream error in emerg');
+
+}
 
 $msg = "bytes from/to client:5/4, bytes from/to upstream:4/5";
 
@@ -148,6 +159,8 @@ like($t->read_file('e_stream.log'), qr/$
 
 }
 
+close $stderr;
+
 ###############################################################################
 
 sub lines {

-- 
Sergey Kandaurov


More information about the nginx-devel mailing list