diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-01-01 13:44:00 -0500 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-01-05 12:52:11 -0500 |
commit | 5b1b9f78247e122804490b17112e94df32851464 (patch) | |
tree | e8b7580206627e5cd84e9fa4c01dcd0296344da6 /tests/LightyTest.pm | |
parent | 048af4c5063485b65d9919f6a7a5d28c1db02d66 (diff) | |
download | lighttpd-git-5b1b9f78247e122804490b17112e94df32851464.tar.gz |
[tests] use ephemeral ports in tests
avoid spurious test failures due to conflicts with ports in use by
other processes, which might occur when tests use hard-coded ports
Diffstat (limited to 'tests/LightyTest.pm')
-rw-r--r-- | tests/LightyTest.pm | 65 |
1 files changed, 48 insertions, 17 deletions
diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm index 04496f66..2392e6e8 100644 --- a/tests/LightyTest.pm +++ b/tests/LightyTest.pm @@ -1,12 +1,10 @@ package LightyTest; use strict; -use IO::Socket; -use Test::More; +use IO::Socket (); +use Test::More; # diag() use Socket; use Cwd 'abs_path'; -use POSIX qw(:sys_wait_h dup2); -use Errno qw(EADDRINUSE); sub find_program { my @DEFAULT_PATHS = ('/usr/bin/', '/usr/local/bin/'); @@ -80,7 +78,6 @@ sub new { if (exists $ENV{LIGHTTPD_EXE_PATH}) { $self->{LIGHTTPD_PATH} = $ENV{LIGHTTPD_EXE_PATH}; } - $self->{PORT} = 2048; my ($name, $aliases, $addrtype, $net) = gethostbyaddr(inet_aton("127.0.0.1"), AF_INET); @@ -131,7 +128,8 @@ sub wait_for_port_with_proc { $timeout--; # the process is gone, we failed - if (0 != waitpid($child, WNOHANG)) { + require POSIX; + if (0 != waitpid($child, POSIX::WNOHANG)) { return -1; } if (0 >= $timeout) { @@ -144,15 +142,32 @@ sub wait_for_port_with_proc { return 0; } +sub bind_ephemeral_tcp_socket { + my $SOCK; + socket($SOCK, PF_INET, SOCK_STREAM, 0) || die "socket: $!"; + setsockopt($SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; + bind($SOCK, sockaddr_in(0, INADDR_LOOPBACK)) || die "bind: $!"; + my($port) = sockaddr_in(getsockname($SOCK)); + return ($SOCK, $port); +} + +sub get_ephemeral_tcp_port { + # bind to an ephemeral port, close() it, and return port that was used + # (While there is a race condition before caller may reuse the port, + # the port is likely to remain available for the serialized tests) + my $port; + (undef, $port) = bind_ephemeral_tcp_socket(); + return $port; +} + sub start_proc { my $self = shift; # kill old proc if necessary #$self->stop_proc; - if ($self->listening_on($self->{PORT})) { - diag("\nPort ".$self->{PORT}." already in use"); - return -1; - } + # listen on localhost and kernel-assigned ephemeral port + my $SOCK; + ($SOCK, $self->{PORT}) = bind_ephemeral_tcp_socket(); # pre-process configfile if necessary # @@ -175,11 +190,26 @@ sub start_proc { my $child = fork(); if (not defined $child) { diag("\nFork failed"); + close($SOCK); return -1; } if ($child == 0) { + # set up systemd socket activation env vars + $ENV{LISTEN_FDS} = "1"; + $ENV{LISTEN_PID} = $$; + listen($SOCK, 1024) || die "listen: $!"; + if (fileno($SOCK) != 3) { # SD_LISTEN_FDS_START 3 + require POSIX; + POSIX::dup2(fileno($SOCK), 3) || die "dup2: $!"; + close($SOCK); + } + else { + require Fcntl; + fcntl($SOCK, Fcntl::F_SETFD, 0); # clr FD_CLOEXEC + } exec @cmdline or die($?); } + close($SOCK); if (0 != $self->wait_for_port_with_proc($self->{PORT}, $child)) { diag(sprintf('\nThe process %i is not up', $child)); @@ -237,15 +267,15 @@ sub handle_http { print $remote $_; diag("<< ".$_."\n") if $is_debug; - select(undef, undef, undef, 0.001); + select(undef, undef, undef, 0.0001); print $remote "\015"; - select(undef, undef, undef, 0.001); + select(undef, undef, undef, 0.0001); print $remote "\012"; - select(undef, undef, undef, 0.001); + select(undef, undef, undef, 0.0001); print $remote "\015"; - select(undef, undef, undef, 0.001); + select(undef, undef, undef, 0.0001); print $remote "\012"; - select(undef, undef, undef, 0.001); + select(undef, undef, undef, 0.0001); } } @@ -428,7 +458,8 @@ sub spawnfcgi { setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) || die "setsockopt: $!"; bind(SOCK, sockaddr_in($port, $iaddr)) || die "bind: $!"; listen(SOCK, 1024) || die "listen: $!"; - dup2(fileno(SOCK), 0) || die "dup2: $!"; + require POSIX; + POSIX::dup2(fileno(SOCK), 0) || die "dup2: $!"; exec { $binary } ($binary) or die($?); } else { if (0 != $self->wait_for_port_with_proc($port, $child)) { @@ -467,7 +498,7 @@ sub has_crypto { my $FH; open($FH, "-|",$self->{LIGHTTPD_PATH}, "-V") || return 0; while (<$FH>) { - return 1 if (/[+] (?i:OpenSSL|mbedTLS|GnuTLS|WolfSSL|Nettle) support/); + return 1 if (/[+] (?i:OpenSSL|mbedTLS|GnuTLS|WolfSSL|Nettle|NSS crypto) support/); } close $FH; return 0; |