summaryrefslogtreecommitdiff
path: root/tests/LightyTest.pm
diff options
context:
space:
mode:
authorGlenn Strauss <gstrauss@gluelogic.com>2021-01-01 13:44:00 -0500
committerGlenn Strauss <gstrauss@gluelogic.com>2021-01-05 12:52:11 -0500
commit5b1b9f78247e122804490b17112e94df32851464 (patch)
treee8b7580206627e5cd84e9fa4c01dcd0296344da6 /tests/LightyTest.pm
parent048af4c5063485b65d9919f6a7a5d28c1db02d66 (diff)
downloadlighttpd-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.pm65
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;