---------------------------- HTTP Server Test Script - autotest_http.sh ---------------------------- -Ian! D. Allen - idallen@idallen.ca - www.idallen.com We will be using a shell script autotest_http.sh to execute an automated test of our HTTP server; so, we don't have to redo all the tests manually every time we change something in our server and we want to re-test it. To test our HTTP server responses, we can "fake" a whole set of HTTP requests from an HTTP client by putting the lines we want the fake client to send in a text file and using "nc" as the fake HTTP client: $ nc -v localhost 55555 &1 | tee test_out.txt Usage (run all tests; no prompting; no display on screen; use "tail -f"): $ ./autotest_http.sh test_out.txt 2>&1 If you don't use "tee", then in a separate window you can run "tail -f test_out.txt" to see the progress of a test script in writing to the test_out file. Errors detected while running the various tests cause an exit with a non-zero status. ----- cut here --------------------- #!/bin/sh -u # # Syntax: $0 (no arguments) # # This script runs tests on an HTTP server in the current directory. # It creates a fake HTTP client using "nc" that feeds test HTTP request # lines to the server and displays the server responses. # # The script waits for RETURN before every test, if stdin is a terminal. # (To run tests without prompting, redirect stdin from /dev/null ) # # This only runs tests of the HTTP server by connecting to "localhost". # Some other testing should verify that other clients on other hosts # can also connect. # # Software License: GNU GPL version 2 or later # - Ian! D. Allen - idallen@idallen.ca - www.idallen.com # set standard shell PATH and file creation mask # PATH=/bin:/usr/bin ; export PATH LC_COLLATE=C ; export LC_COLLATE LANG=C ; export LANG umask 022 hostname=$( hostname ) # name of this computer cmd=$( basename "$0" ) # shortened name of this script # We expect the server to be named as follows: # PROGNAME=PigLatinHTTP HTTPSERVER="java $PROGNAME" # how to run the HTTP server PORT=55555 # an unused port WEBDIR=/tmp # directory from which to serve files class="$PROGNAME.class" if [ ! -s "$class" ] ; then echo 1>&2 " " echo 1>&2 "$cmd: Cannot find '$class' to run with java" exit 1 fi src="$PROGNAME.java" ls -lid "$src" if [ "$src" -nt "$class" ] ; then echo 1>&2 " " echo 1>&2 "$cmd: WARNING '$src' is newer than '$class'" sleep 5 fi echo "$cmd: Using web directory on $hostname: $WEBDIR" # The command line used to start the server (done once, at test start): # RUNSERVER=" $HTTPSERVER $PORT $WEBDIR " echo "$cmd: Using command line: $RUNSERVER" # A temp file used as the HTTP request being sent (input to the client): # A temp file used to collect client output (the response from the server). # http=/tmp/$USER.http.$$ rm -f $http clientout=/tmp/$USER.out.$$ rm -f $clientout # Remove the temp files on exit, SIGHUP, or SIGINT. # Also kill any left over "nc" processes run by this $USER. # Try to show the PID of the running java programs. # You may try auto-killing all your running java programs... # trap 'MyTrap' 0 1 2 MyTrap () { rm -f $http $clientout # rm -f $name.txt $name.bin $name.000 pgrep -u $USER -l -s 0 java # show all running java pkill -u $USER -s 0 java # kill off all running java (danger) echo 1>&2 " " echo 1>&2 "*** $cmd EXIT ($0)" trap 0 # remove exit trap exit } # Create a data file in $WEBDIR with two names: one text, one binary: # The HTTP server content guessing routine will produce text/plain for # the text file, which we will use to make it PigLatin. # (These files have to be in the directory given by $WEBDIR, above.) # basename=$USER-$$ name=$WEBDIR/$basename rm -f $name.txt $name.bin $name.000 cat >$name.txt <&1 | perl -we '$| = 1; while(<>){ s/([\000-\011\013-\037\177])/"{" . ord($1) . "}"/ge; print " SERVER: "; print; }' & serverpid=$! sleep 2 # wait a bit - java is slow to start... if ! kill -0 $serverpid 2>/dev/null ; then echo 1>&2 " " echo 1>&2 "$cmd: Unable to start a new server: $RUNSERVER" echo 1>&2 "$cmd: Is a server already running on port $PORT?" pgrep -f -l java # look for anyone's java running exit 1 fi # This is how we actually run a test. # - all passed arguments are used as the title of the test ($*) # - pause and ask to run this test (only ask if stdin is a tty) # - start the server we want to test in the background # - run the client against the server, reading from the file # DoTest () { echo " " # If stdin is a terminal, prompt to continue with this test. # (To run tests without prompting, redirect stdin from /dev/null ) # if [ -t 0 ] ; then echo 1>&2 "==> TEST $*" echo 1>&2 -n "==> Press RETURN to execute this test ..." read junk || exit 1 # exit testing if EOF is seen echo 1>&2 " " fi echo "==============================================================" echo "Test $*" echo "$(date) on $hostname" echo "==============================================================" # Run the fake HTTP client using input from the prepared file. # Save responses received by the client (including stderr) in a temp file. # Use cat -v to make control characters (e.g. ^M) visible. # if [ ! -e $http ] ; then echo 1>&2 " " echo 1>&2 "$cmd: missing input file '$http'" exit 1 fi option='' if [ ! -s $http ] ; then echo 1>&2 " " echo 1>&2 "$cmd: WARNING: empty input file '$http'" if [ -e /etc/debian_version ] ; then option=' -q 10 ' else option=' -w 5 ' fi fi # Display the request that we are about to send. cat -v $http | sed -e 's/^/ SEND: /' echo " " nc $option localhost $PORT <$http >$clientout 2>&1 rm $http # so that we don't accidentally run it twice # Sleep a bit to give the server time to finish its own debug output. # Increase this if needed to keep the client and server output separate. # Output the client response lines prefaced with a prefix. # sleep 1 echo " " cat -v $clientout | sed -e 's/^/RESPONSE: /' rm $clientout } # Give time to allow any server output to appear before we continue. sleep 2 ########################################################################## # Tests of the HTTP server go below this line. # Our toy HTTP server only reads one Request line from a client. # For this script, the request to be tried must be placed in the file $http, # then run the test using the function: # DoTest "number: comment" # The $http file will be removed after each test. See the examples below. ########################################################################## echo " " echo "===============================" echo "You could echo your assignment label here." echo "===============================" echo " " # Decide on some test categories. # Implement tests in those categories. # Fix up this set of tests to have a logical order and numbering. # No marks are awarded for copying the tests below verbatim. echo " " echo "===============================" echo "Category A: Some Category of Tests (FIX ME)" echo "===============================" echo " " echo "HEAD /$basename.bin HTTP/1.0" >$http DoTest "A-1: HEAD a file with a non-text name: $basename.bin" echo "GET /$basename.bin HTTP/1.0" >$http DoTest "V-9: GET a file with a non-text name: $basename.bin" echo "HEAD /$basename.txt HTTP/1.0" >$http DoTest "Q-3: HEAD a file with a text name: $basename.txt" echo "GET /$basename.txt HTTP/1.0" >$http DoTest "D-4: GET a file with a text name: $basename.txt" echo "GET /$basename.txt HTTP/1.0" >$http DoTest "Y-5: GET with extra spaces (should work)" echo "GET//$basename.txt HTTP/1.0" >$http DoTest "F-2: GET invalid syntax: missing leading blank (should fail as invalid)" echo "GET /$basename.txtHTTP/1.0" >$http DoTest "P-7: GET invalid syntax: missing trailing blank (should fail as invalid)" >$http DoTest "Z-99: empty input (should fail as invalid)" echo "get /$basename.bin HTTP/1.0" >$http DoTest "R-6: GET in wrong case (should fail as invalid)" echo "GET /$basename.bin http/1.0" >$http DoTest "N-8: HTTP in wrong case (should fail as invalid)" echo "GET /$basename.bin HTTP/2.0" >$http DoTest "M-5: GET with unknown version (should fail as invalid)" echo "GET /$basename.000 HTTP/1.0" >$http DoTest "U-4: GET file with no read permissions (should fail - forbidden)" echo "GET /$basename.XXX HTTP/1.0" >$http DoTest "W-1: GET wrong file name (should fail - not found)" echo " " echo "===============================" echo "Category ?: Some Category of Tests (FIX ME)" echo "===============================" echo " " echo "# Fix up this set of tests to have a logical order and numbering." echo "# No marks are awarded for copying the tests above verbatim." echo "# Remove these comment lines when you reorganize the tests." echo "# More test categories and more tests go here ..." echo " "