summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/globalconfig.pm3
-rw-r--r--tests/runner.pm92
-rwxr-xr-xtests/runtests.pl36
3 files changed, 110 insertions, 21 deletions
diff --git a/tests/globalconfig.pm b/tests/globalconfig.pm
index 9287e2b0d..e44781f95 100644
--- a/tests/globalconfig.pm
+++ b/tests/globalconfig.pm
@@ -85,7 +85,8 @@ our $CURLVERSION=""; # curl's reported version number
our $pwd = getcwd(); # current working directory
our $srcdir = $ENV{'srcdir'} || '.'; # root of the test source code
our $perl="perl -I$srcdir"; # invoke perl like this
-our $LOGDIR="log"; # root of the log directory
+our $LOGDIR="log"; # root of the log directory; this will be different for
+ # each runner in multiprocess mode
our $LIBDIR="./libtest";
our $TESTDIR="$srcdir/data";
our $CURL="../src/curl".exe_ext('TOOL'); # what curl binary to run on the tests
diff --git a/tests/runner.pm b/tests/runner.pm
index 71e20ce58..8ea50de89 100644
--- a/tests/runner.pm
+++ b/tests/runner.pm
@@ -22,7 +22,15 @@
#
###########################################################################
-# This module contains entry points to run a single test
+# This module contains entry points to run a single test. runner_init
+# determines whether they will run in a separate process or in the process of
+# the caller. The relevant interface is asynchronous so it will work in either
+# case. Program arguments are marshalled and then written to the end of a pipe
+# (in controlleripccall) which is later read from and the arguments
+# unmarshalled (in ipcrecv) before the desired function is called normally.
+# The function return values are then marshalled and written into another pipe
+# (again in ipcrecv) when is later read from and unmarshalled (in runnerar)
+# before being returned to the caller.
package runner;
@@ -36,6 +44,7 @@ BEGIN {
our @EXPORT = qw(
checktestcmd
prepro
+ readtestkeywords
restore_test_env
runner_init
runnerac_clearlocks
@@ -59,7 +68,6 @@ BEGIN {
# these are for debugging only
our @EXPORT_OK = qw(
- readtestkeywords
singletest_preprocess
);
}
@@ -99,6 +107,7 @@ use testutil qw(
#######################################################################
# Global variables set elsewhere but used only by this package
+# These may only be set *before* runner_init is called
our $DBGCURL=$CURL; #"../src/.libs/curl"; # alternative for debugging
our $valgrind_logfile="--log-file"; # the option name for valgrind >=3
our $valgrind_tool="--tool=memcheck";
@@ -121,7 +130,8 @@ my $controllerw; # pipe that controller writes to
my $runnerr; # pipe that runner reads from
my $runnerw; # pipe that runner writes to
my $controllerr; # pipe that controller reads from
-
+my $multiprocess; # nonzero with a separate test runner process
+my $onerunnerid; # a single runner ID
# redirected stdout/stderr to these files
sub stdoutfilename {
@@ -140,12 +150,9 @@ sub stderrfilename {
# runnerac_* functions
# Called by controller
sub runner_init {
- my ($logdir)=@_;
+ my ($logdir, $jobs)=@_;
- # Set this directory as ours
- # TODO: This will need to be uncommented once there are multiple runners
- #$LOGDIR = $logdir;
- mkdir("$LOGDIR/$PIDDIR", 0777);
+ $multiprocess = !!$jobs;
# enable memory debugging if curl is compiled with it
$ENV{'CURL_MEMDEBUG'} = "$LOGDIR/$MEMDUMP";
@@ -161,8 +168,58 @@ sub runner_init {
pipe $runnerr, $controllerw;
pipe $controllerr, $runnerw;
- # There is only one runner right now
- return "singleton";
+ if($multiprocess) {
+ # Create a separate process in multiprocess mode
+ my $child = fork();
+ if(0 == $child) {
+ # TODO: set up a better signal handler
+ $SIG{INT} = 'IGNORE';
+ $SIG{TERM} = 'IGNORE';
+
+ $onerunnerid = $$;
+ print "Runner $onerunnerid starting\n" if($verbose);
+
+ # Here we are the child (runner).
+ close($controllerw);
+ close($controllerr);
+
+ # Set this directory as ours
+ $LOGDIR = $logdir;
+ mkdir("$LOGDIR/$PIDDIR", 0777);
+
+ # handle IPC calls
+ event_loop();
+
+ # Can't rely on logmsg here in case it's buffered
+ print "Runner $onerunnerid exiting\n" if($verbose);
+ exit 0;
+ }
+
+ # Here we are the parent (controller).
+ close($runnerw);
+ close($runnerr);
+
+ $onerunnerid = $child;
+
+ } else {
+ # Create our pid directory
+ mkdir("$LOGDIR/$PIDDIR", 0777);
+
+ # Don't create a separate process
+ $onerunnerid = "integrated";
+ }
+
+ return $onerunnerid;
+}
+
+#######################################################################
+# Loop to execute incoming IPC calls until the shutdown call
+sub event_loop {
+ while () {
+ if(ipcrecv()) {
+ last;
+ }
+ }
}
#######################################################################
@@ -980,6 +1037,11 @@ sub runner_test_preprocess {
readtestkeywords();
###################################################################
+ # Restore environment variables that were modified in a previous run.
+ # Test definition may instruct to (un)set environment vars.
+ restore_test_env(1);
+
+ ###################################################################
# Start the servers needed to run this test case
my ($why, $error) = singletest_startservers($testnum, \%testtimings);
@@ -1115,10 +1177,10 @@ sub controlleripccall {
# Send IPC call via pipe
syswrite($controllerw, (pack "L", length($margs)) . $margs);
- # Call the remote function
- # TODO: this will eventually be done in a separate runner process
- # kicked off by runner_init()
- ipcrecv();
+ if(!$multiprocess) {
+ # Call the remote function here in single process mode
+ ipcrecv();
+ }
}
###################################################################
@@ -1140,7 +1202,7 @@ sub runnerar {
my $resarrayref = thaw $buf;
# First argument is runner ID
- unshift @$resarrayref, "singleton";
+ unshift @$resarrayref, $onerunnerid;
return @$resarrayref;
}
diff --git a/tests/runtests.pl b/tests/runtests.pl
index bf90583a0..dca495076 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -174,6 +174,7 @@ my $postmortem; # display detailed info about failed tests
my $run_disabled; # run the specific tests even if listed in DISABLED
my $scrambleorder;
my $randseed = 0;
+my $jobs = 0;
# Azure Pipelines specific variables
my $AZURE_RUN_ID = 0;
@@ -748,6 +749,10 @@ sub checksystemfeatures {
"* System: $hosttype",
"* OS: $hostos\n");
+ if($jobs) {
+ # Only show if not the default for now
+ logmsg "* Jobs: $jobs\n";
+ }
if($feature{"TrackMemory"} && $feature{"threaded-resolver"}) {
logmsg("*\n",
"*** DISABLES memory tracking when using threaded resolver\n",
@@ -1633,7 +1638,6 @@ sub singletest {
if($singletest_state == ST_INIT) {
my $logdir = getlogdir($testnum);
-
# first, remove all lingering log files
if(!cleardir($logdir) && $clearlocks) {
runnerac_clearlocks($runnerid, $logdir);
@@ -1661,7 +1665,7 @@ sub singletest {
# Test definition may instruct to (un)set environment vars.
# This is done this early so that leftover variables don't affect
# starting servers or CI registration.
- restore_test_env(1);
+ # restore_test_env(1);
###################################################################
# Load test file so CI registration can get the right data before the
@@ -1688,6 +1692,11 @@ sub singletest {
updatetesttimings($testnum, %$testtimings);
#######################################################################
+ # Load test file for this test number
+ my $logdir = getlogdir($testnum);
+ loadtest("${logdir}/test${testnum}");
+
+ #######################################################################
# Print the test name and count tests
$error = singletest_count($testnum, $why);
if($error) {
@@ -1739,6 +1748,12 @@ sub singletest {
#######################################################################
# Verify that the test succeeded
+ #
+ # Load test file for this test number
+ my $logdir = getlogdir($testnum);
+ loadtest("${logdir}/test${testnum}");
+ readtestkeywords();
+
$error = singletest_check($runnerid, $testnum, $cmdres, $CURLOUT, $tool, $usedvalgrind);
if($error == -1) {
my $err = ignoreresultcode($testnum);
@@ -2076,6 +2091,14 @@ while(@ARGV) {
# lists the test case names only
$listonly=1;
}
+ elsif($ARGV[0] =~ /^-j(.*)/) {
+ # parallel jobs
+ $jobs=1;
+ my $xtra = $1;
+ if($xtra =~ s/(\d+)$//) {
+ $jobs = $1;
+ }
+ }
elsif($ARGV[0] eq "-k") {
# keep stdout and stderr files after tests
$keepoutfiles=1;
@@ -2133,6 +2156,7 @@ Usage: runtests.pl [options] [test selection(s)]
-g run the test case with gdb
-gw run the test case with gdb as a windowed application
-h this help text
+ -j[N] spawn this number of processes to run tests (default 0, max. 1)
-k keep stdout and stderr files present after tests
-L path require an additional perl library file to replace certain functions
-l list all test case names/descriptions
@@ -2291,8 +2315,10 @@ mkdir($LOGDIR, 0777);
#
get_disttests();
-# Disable buffered logging for now
-setlogfunc(\&logmsg);
+if(!$jobs) {
+ # Disable buffered logging with only one test job
+ setlogfunc(\&logmsg);
+}
#######################################################################
# Output curl version and host info being tested
@@ -2560,7 +2586,7 @@ citest_starttestrun();
# Initialize the runner to prepare to run tests
cleardir($LOGDIR);
mkdir($LOGDIR, 0777);
-my $runnerid = runner_init($LOGDIR);
+my $runnerid = runner_init($LOGDIR, $jobs);
#######################################################################
# The main test-loop