aboutsummaryrefslogtreecommitdiff
path: root/tests/ftp.pm
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ftp.pm')
-rw-r--r--tests/ftp.pm368
1 files changed, 332 insertions, 36 deletions
diff --git a/tests/ftp.pm b/tests/ftp.pm
index 015f9f08a..32c6779e3 100644
--- a/tests/ftp.pm
+++ b/tests/ftp.pm
@@ -1,63 +1,359 @@
-#######################################################################
-# Return the pid of the server as found in the given pid file
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
#
-sub serverpid {
- my $PIDFILE = $_[0];
- open(PFILE, "<$PIDFILE");
- my $PID=0+<PFILE>;
- close(PFILE);
- return $PID;
-}
+# Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+# $Id$
+###########################################################################
+
+use strict;
+use warnings;
-#######################################################################
-# Check the given test server if it is still alive.
+
+my $DEFAULT_TIMEOUT_START = 90; # default allowed time for a process to startup
+my $DEFAULT_TIMEOUT_STOP = 90; # default allowed time for a process to stop
+
+my $ONE_HALF_STOP_TIMEOUT = int($DEFAULT_TIMEOUT_STOP / 2);
+my $ONE_THIRD_STOP_TIMEOUT = int($DEFAULT_TIMEOUT_STOP / 3);
+my $ONE_SIXTH_STOP_TIMEOUT = int($DEFAULT_TIMEOUT_STOP / 6);
+
+my $pidpattern = qr/^\-?(\d+)$/; # pre-compiled pid pattern regexp
+
+
+######################################################################
+# pidfromfile returns the pid stored in the given pidfile. The value
+# of the returned pid will never be a negative value. It will be zero
+# on any file related error or if a pid can not be extracted from the
+# file. Otherwise it will be a positive value, even If the pid number
+# stored in the file is a negative one.
#
-sub checkserver {
+sub pidfromfile {
my ($pidfile)=@_;
- my $pid=0;
- # check for pidfile
- if ( -f $pidfile ) {
- $pid=serverpid($pidfile);
- if ($pid ne "" && kill(0, $pid)) {
- return $pid;
+ my $pid = 0; # on failure or empty file return 0
+ my $pidline;
+
+ if(not defined $pidfile) {
+ return 0;
+ }
+ if(-f $pidfile) {
+ if(open(PIDF, "<$pidfile")) {
+ my $pidline = <PIDF>;
+ close(PIDF);
+ chomp $pidline;
+ $pidline =~ s/^\s+//;
+ $pidline =~ s/\s+$//;
+ $pidline =~ s/^[+-]?0+//;
+ if($pidline =~ $pidpattern) {
+ $pid = $1;
+ }
+ }
+ }
+ return $pid;
+}
+
+
+######################################################################
+# unlinkpidfiles unlinks/deletes the given pidfiles. The first argument
+# 'pidfiles' is a string of whitespace separated pidfiles. If successful
+# returns 0, on error it returns the number of files not deleted.
+#
+sub unlinkpidfiles {
+ my ($pidfiles)=@_;
+
+ if(not defined $pidfiles) {
+ return 0;
+ }
+ my $pidfile;
+ my $errcount = 0;
+ for $pidfile (split(" ", $pidfiles)) {
+ if($pidfile) {
+ if(unlink($pidfile) == 0) {
+ $errcount++;
+ }
+ }
+ }
+ return $errcount;
+}
+
+
+######################################################################
+# checkalivepid checks if the process of the given pid is alive. The
+# argument must represent a single pid and be a valid number, if not
+# it will return 0. It will also return 0 if the pid argument is zero
+# or negative. If the pid argument is positive and it is alive returns
+# the same positive pid, otherwise, if it is not alive it will return
+# the negative value of the pid argument.
+#
+sub checkalivepid {
+ my ($pid)=@_;
+
+ if(not defined $pid) {
+ return 0;
+ }
+ if ($pid !~ $pidpattern) {
+ return 0; # invalid argument
+ }
+ if($pid > 0) {
+ if(kill(0, $pid)) {
+ return $pid; # positive means it is alive
}
else {
return -$pid; # negative means dead process
}
}
- return 0;
+ return 0; # not a positive pid argument
+}
+
+
+######################################################################
+# checkalivepidfile checks if the process of the pid stored in the
+# given pidfile is alive. It will return 0 on any file related error
+# or if a pid can not be extracted from the file. If the process of
+# the pid present in the file is alive it returns that positive pid,
+# if it is not alive it will return the negative value of the pid.
+#
+sub checkalivepidfile {
+ my ($pidfile)=@_;
+
+ my $pid = pidfromfile($pidfile);
+ my $ret = checkalivepid($pid);
+ return $ret;
+}
+
+
+######################################################################
+# signalpids signals processes in the second argument with the signal
+# given in the first argument. The second argument 'pids' is a string
+# of whitespace separated pids. Of the given pids only those that are
+# positive and are actually alive will be signalled, and no matter
+# how many times a pid is repeated it will only be signalled once.
+#
+sub signalpids {
+ my ($signal, $pids)=@_;
+
+ if((not defined $signal) || (not defined $pids)) {
+ return;
+ }
+ my $prev = 0;
+ for(sort({$a <=> $b} split(" ", $pids))) {
+ if($_ =~ $pidpattern) {
+ my $pid = $1;
+ if($prev != $pid) {
+ $prev = $pid;
+ if(checkalivepid($pid) > 0) {
+ kill($signal, $pid);
+ }
+ }
+ }
+ }
+}
+
+
+######################################################################
+# signalpidfile signals the process of the pid stored in the given
+# pidfile with the signal given in the first argument if the process
+# with that pid is actually alive.
+#
+sub signalpidfile {
+ my ($signal, $pidfile)=@_;
+
+ my $pid = pidfromfile($pidfile);
+ if($pid > 0) {
+ signalpids($signal, $pid);
+ }
+}
+
+
+######################################################################
+# waitdeadpid waits until all processes given in the first argument
+# are not alive, waiting at most timeout seconds. The first argument
+# 'pids' is a string of whitespace separated pids. Returns 1 when all
+# pids are not alive. Returns 0 when the specified timeout has expired
+# and at least one of the specified pids is still alive.
+#
+sub waitdeadpid {
+ my ($pids, $timeout)=@_;
+
+ if(not defined $pids) {
+ return 1;
+ }
+ if((not defined $timeout) || ($timeout < 1)) {
+ $timeout = $DEFAULT_TIMEOUT_STOP;
+ }
+ while($timeout--) {
+ my $alive = 0;
+ for(split(" ", $pids)) {
+ if($_ =~ $pidpattern) {
+ my $pid = $1;
+ if(checkalivepid($pid) > 0) {
+ $alive++;
+ }
+ }
+ }
+ if($alive == 0) {
+ return 1; # not a single pid is alive
+ }
+ sleep(1);
+ }
+ return 0; # at least one pid is still alive after timeout seconds
}
-#############################################################################
-# Kill a specific slave
+
+######################################################################
+# waitalivepidfile waits until the given pidfile has a pid that is
+# alive, waiting at most timeout seconds. It returns the positive pid
+# When it is alive, otherwise it returns 0 when timeout seconds have
+# elapsed and the pidfile does not have a pid that is alive.
+#
+sub waitalivepidfile {
+ my ($pidfile, $timeout)=@_;
+
+ if(not defined $pidfile) {
+ return 0;
+ }
+ if((not defined $timeout) || ($timeout < 1)) {
+ $timeout = $DEFAULT_TIMEOUT_START;
+ }
+ while($timeout--) {
+ my $pid = checkalivepidfile($pidfile);
+ if($pid > 0) {
+ return $pid; # positive means it is alive
+ }
+ sleep(1);
+ }
+ return 0; # no pid in pidfile or not alive
+}
+
+
+######################################################################
+# stopprocess ends the given pid(s), waiting for them to die. The 'pids'
+# argument is a string of whitespace separated pids. Returns 1 if all
+# of the processes have been successfully stopped. If unable to stop
+# any of them in DEFAULT_TIMEOUT_STOP seconds then it returns 0.
+#
+sub stopprocess {
+ my ($pids)=@_;
+
+ if(not defined $pids) {
+ return 1;
+ }
+ signalpids("TERM", $pids);
+ if(waitdeadpid($pids, $ONE_HALF_STOP_TIMEOUT) == 0) {
+ signalpids("INT", $pids);
+ if(waitdeadpid($pids, $ONE_THIRD_STOP_TIMEOUT) == 0) {
+ signalpids("KILL", $pids);
+ if(waitdeadpid($pids, $ONE_SIXTH_STOP_TIMEOUT) == 0) {
+ return 0; # at least one pid is still alive !!!
+ }
+ }
+ }
+ return 1; # not a single pid is alive
+}
+
+
+######################################################################
+# stopprocesspidfile ends the test server process of the given pidfile,
+# waiting for it to die, and unlinking/deleting the given pidfile. If
+# the given process was not running or has been successfully stopped it
+# returns 1. If unable to stop it in DEFAULT_TIMEOUT_STOP seconds then
+# returns 0.
+#
+sub stopprocesspidfile {
+ my ($pidfile)=@_;
+
+ if(not defined $pidfile) {
+ return 1;
+ }
+ my $ret = 1; # assume success stopping it
+ my $pid = checkalivepidfile($pidfile);
+ if($pid > 0) {
+ $ret = stopprocess($pid);
+ }
+ unlinkpidfiles($pidfile);
+ return $ret;
+}
+
+
+######################################################################
+# ftpkillslave ends a specific slave, waiting for it to die, and
+# unlinking/deleting its pidfiles. If the given ftpslave was not
+# running or has been successfully stopped it returns 1. If unable
+# to stop it in DEFAULT_TIMEOUT_STOP seconds then it returns 0.
#
sub ftpkillslave {
- my ($id, $ext, $verbose)=@_;
- my $base;
- for $base (('filt', 'data')) {
- my $f = ".sock$base$id$ext.pid";
- my $pid = checkserver($f);
+ my ($id, $ext)=@_;
+
+ my $ret = 1; # assume success stopping them
+ my $pids = "";
+ my $pidfiles = "";
+ for my $base (('filt', 'data')) {
+ my $pidfile = ".sock$base$id$ext.pid";
+ my $pid = checkalivepidfile($pidfile);
+ $pidfiles .= " $pidfile";
if($pid > 0) {
- printf ("* kill pid for %s => %d\n", "ftp-$base$id$ext", $pid) if($verbose);
- kill (9, $pid); # die!
+ $pids .= " $pid";
}
- unlink($f);
}
+ if($pids) {
+ $ret = stopprocess($pids);
+ }
+ if($pidfiles) {
+ unlinkpidfiles($pidfiles);
+ }
+ return $ret;
}
-#############################################################################
-# Make sure no FTP leftovers are still running. Kill all slave processes.
-# This uses pidfiles since it might be used by other processes.
+######################################################################
+# ftpkillslaves ends all the ftpslave processes, waiting for them to
+# die, unlinking/deleting its pidfiles. If they were not running or
+# have been successfully stopped it returns 1. If unable to stop any
+# of them in DEFAULT_TIMEOUT_STOP seconds then returns 0.
#
sub ftpkillslaves {
- my ($versbose) = @_;
- for $ext (("", "ipv6")) {
- for $id (("", "2")) {
- ftpkillslave ($id, $ext, $verbose);
+
+ my $ret = 1; # assume success stopping them
+ my $pids = "";
+ my $pidfiles = "";
+ for my $ext (("", "ipv6")) {
+ for my $id (("", "2")) {
+ for my $base (('filt', 'data')) {
+ my $pidfile = ".sock$base$id$ext.pid";
+ my $pid = checkalivepidfile($pidfile);
+ $pidfiles .= " $pidfile";
+ if($pid > 0) {
+ $pids .= " $pid";
+ }
+ }
}
}
+ if($pids) {
+ $ret = stopprocess($pids);
+ }
+ if($pidfiles) {
+ unlinkpidfiles($pidfiles);
+ }
+ return $ret;
}
+
+######################################################################
+# library files end with 1; to make 'require' and 'use' succeed.
1;
+