diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 000000000..dd2918c52 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,7 @@ + +test: + ./runtests.sh + +clean: + rm -rf log + find . -name "*~" | xargs rm -f diff --git a/tests/README b/tests/README new file mode 100644 index 000000000..5cad1f62d --- /dev/null +++ b/tests/README @@ -0,0 +1,16 @@ + +Describe the test stuff + +Requires: + perl, sh + +Run: + (should be) 'make test' + +Logs: + All logs are generated in the logs/ subdirctory (it is emtpied first + in the runtests.sh script) + +Data: + All test-data are put in the data/ subdirctory. Further descriptions on + the data format must be added here. diff --git a/tests/runserv.pl b/tests/runserv.pl new file mode 100755 index 000000000..fb39f47d2 --- /dev/null +++ b/tests/runserv.pl @@ -0,0 +1,177 @@ +#!/usr/bin/perl +# +# runserv.pl - run a dumb tcp server on a port for the curl test suite +# derived from 'ftproxy' by Björn Stenberg/Linus Nielsen that was +# derived from "fwdport.pl" by Tom Christiansen + +use FileHandle; +use Net::hostent; # Example 17-8 # by-name interface for host info +use IO::Socket; # for creating server and client sockets +use POSIX ":sys_wait_h"; # for reaping our dead children + +my $localip = $ARGV[0]; +my $localport = $ARGV[1]; + +if(($localip eq "") || + ($localport eq "")) { + print "Usage: runserv.pl \n"; + exit; +} + +my ( + %Children, # hash of outstanding child processes + $proxy_server, # the socket we accept() from + $ME, # basename of this program +); + +($ME = $0) =~ s,.*/,,; # retain just basename of script name + +start_server(); # launch our own server +service_clients(); # wait for incoming +print "[TCP server exited]\n"; +exit; + +# begin our server +sub start_server { + $proxy_server = IO::Socket::INET->new(Listen => 5, + LocalAddr => $localip, + LocalPort => $localport, + Proto => 'tcp', + Reuse => 1) + or die "can't open socket"; + +# print "[TCP server initialized"; +# print " on " . $proxy_server->sockhost() . ":" . +# $proxy_server->sockport() . "]\n"; +} + +sub service_clients { + my ( + $local_client, # someone internal wanting out + $lc_info, # local client's name/port information + @rs_config, # temp array for remote socket options + $rs_info, # remote server's name/port information + $kidpid, # spawned child for each connection + $file, + $request, + @headers + ); + + $SIG{CHLD} = \&REAPER; # harvest the moribund + +# print "Listening...\n"; + + while ($local_client = $proxy_server->accept()) { + $lc_info = peerinfo($local_client); + printf "[Connect from $lc_info]\n"; + + $kidpid = fork(); + die "Cannot fork" unless defined $kidpid; + if ($kidpid) { + $Children{$kidpid} = time(); # remember his start time + close $local_client; # likewise + next; # go get another client + } + + # now, read the data from the client + # and pass back what we want it to have + + undef $request; + undef $path; + undef $ver; + undef @headers; + $cl=0; + $left=0; + while(<$local_client>) { + if($_ =~ /(GET|POST|HEAD) (.*) HTTP\/1.(\d)/) { + $request=$1; + $path=$2; + $ver=$3; + } + elsif($_ =~ /^Content-Length: (\d*)/) { + $cl=$1; + } + # print "RCV: $_"; + + push @headers, $_; + + if($left > 0) { + $left -= length($_); + } + + if(($_ eq "\r\n") or ($_ eq "")) { + if($request eq "POST") { + $left=$cl; + } + else { + $left = -1; # force abort + } + } + if($left < 0) { + last; + } + } + # print "Request: $request\n", + # "Path: $path\n", + # "Version: $ver\n"; + + # + # we always start the path with a number, this is the + # test number that this server will use to know what + # contents to pass back to the client + # + if($path =~ /^\/(\d*)/) { + $testnum=$1; + } + else { + print "UKNOWN TEST CASE\n"; + exit; + } + open(INPUT, ">log/server.input"); + for(@headers) { + print INPUT $_; + } + close(INPUT); + + + # send a reply to the client + open(DATA, ") { + print $local_client $_; + } + close(DATA); + + exit; # whoever's still alive bites it + } +} + +# helper function to produce a nice string in the form HOST:PORT +sub peerinfo { + my $sock = shift; + my $hostinfo = gethostbyaddr($sock->peeraddr); + return sprintf("%s:%s", + $hostinfo->name || $sock->peerhost, + $sock->peerport); +} + +# somebody just died. keep harvesting the dead until +# we run out of them. check how long they ran. +sub REAPER { + my $child; + my $start; + while (($child = waitpid(-1,WNOHANG)) > 0) { + if ($start = $Children{$child}) { + my $runtime = time() - $start; + # printf "Child $child ran %dm%ss\n", + # $runtime / 60, $runtime % 60; + delete $Children{$child}; + } else { + # print "Unknown child process $child exited $?\n"; + } + } + # If I had to choose between System V and 4.2, I'd resign. --Peter Honeyman + $SIG{CHLD} = \&REAPER; +}; + + + diff --git a/tests/runtests.sh b/tests/runtests.sh new file mode 100755 index 000000000..de49aad7e --- /dev/null +++ b/tests/runtests.sh @@ -0,0 +1,156 @@ +#!/bin/sh +# +# Main curl test script +# +####################################################################### +# These should be the only variables that might be needed to get edited: + +HOSTIP=127.0.0.1 +HOSTPORT=8999 +CURL=../src/curl +LOGDIR=log +SERVERIN=$LOGDIR/server.input +CURLOUT=$LOGDIR/curl.out +NC=nc + +# Normally, all test cases should be run, but at times it is handy to +# simply run a particular one: +TESTCASES=" 1 2 3 4" + + +compare () { + # filter off the $4 pattern before compare! + + first="$1" + sec="$2" + text="$3" + strip="$4" + + if test -n "$strip"; then + egrep -v "$strip" < $first > $LOGDIR/generated.tmp + egrep -v "$strip" < $sec > $LOGDIR/stored.tmp + + first="$LOGDIR/generated.tmp" + sec="$LOGDIR/stored.tmp" + fi + + cmp $first $sec + if [ $? != "0" ]; then + echo " $text FAILED" + return 1 + else + echo " $text OK" + return 0 + fi +} + +singletest () +{ + NUMBER="$1" + + REPLY=data/reply$NUMBER.txt + CURLCMD=data/command$NUMBER.txt + HTTP=data/http$NUMBER.txt + DESC=`cat data/name$NUMBER.txt | tr -d '\012'` + + echo "test $NUMBER... [$DESC]" + + ./runserv.pl $HOSTIP $HOSTPORT & + + sleep 1 + + # get the command line options to use + cmd=`sed -e "s/%HOSTIP/$HOSTIP/g" -e "s/%HOSTPORT/$HOSTPORT/g" <$CURLCMD ` + + # run curl + CMDLINE="$CURL -o $CURLOUT -i --silent $cmd" + + # we do it the eval way to deal with quotes and similar stuff + eval $CMDLINE + + if test -n "$verbose"; then + echo "$CMDLINE" + fi + + if [ $? != "0" ]; then + echo "Failed to invoke curl for test $NUMBER" + else + # when curl is done, the server has closed down as well + + # verify the received data + compare $CURLOUT $REPLY " fetch" + + if [ $? != "0" ]; then + exit; + fi + + # verify the sent request + compare $SERVERIN $HTTP " command" "User-Agent:" + + if [ $? != "0" ]; then + exit; + fi + fi + + return 0 +} + + +####################################################################### +# Check options to this test program +# + +if test "$1" = "-v"; then + verbose="1" +fi + +if test -n "$NEWSETUP"; then + + ####################################################################### + # Make sure the Host: lines are correct for this setup + # + + HOST="$HOSTIP:$HOSTPORT" + for test in data/http*.txt; do + sed -e "s/Host: \([0-9.:]*\)/Host: $HOST/g" < $test > $test.tmp + mv $test.tmp $test + done +fi + +####################################################################### +# Output curl version being tested +# +VERSION=`$CURL -V` + +echo "Running tests on:" +echo $VERSION +echo "" + +####################################################################### +# remove and recreate logging directory: +# +rm -rf $LOGDIR +mkdir $LOGDIR + +####################################################################### +# First, start the TCP server +# +#./runserv.pl $HOSTIP $HOSTPORT & + +#if [ $? != "0" ]; then +# echo "failed starting the TCP server" +# exit +#fi + +#sleep 1 # give it a second to start + +####################################################################### +# The main test-loop +# + +for NUMBER in $TESTCASES; do + + singletest $NUMBER + + # loop for next test +done