diff --git a/CHANGES b/CHANGES index a1294cc..e6cca7c 100644 --- a/CHANGES +++ b/CHANGES @@ -238,6 +238,10 @@ Porting: Testing: Removed obselete parts from test.sh + Introduced function checkcond from test.sh + + Renamed test.sh option -foreign to -internet + Documentation: Removed obselete file doc/xio.help diff --git a/test.sh b/test.sh index a742828..ffbd64e 100755 --- a/test.sh +++ b/test.sh @@ -41,7 +41,7 @@ usage() { $ECHO "\t-C \t\tClear/remove left over certificates from previous runs" $ECHO "\t-x \t\tShow commands executed, even when test succeeded" #$ECHO "\t-d \t\tShow log output of commands, even when they did not fail" - $ECHO "\t-foreign \tAllow tests that send packets to Internet" + $ECHO "\t-internet \tAllow tests that send packets to Internet" $ECHO "\t-expect-fail N1,N2,... \tIgnore failure of these tests" $ECHO "\ttest-spec \Number of test or name of test" $ECHO "Contents of environment variable OPTS are passed to Socat invocations, e.'g:" @@ -57,7 +57,7 @@ NUMCOND=true #NUMCOND="test \$N -gt 70" VERBOSE= DEBUG= -FOREIGN= +INTERNET= OPT_EXPECT_FAIL= EXPECT_FAIL= while [ "$1" ]; do case "X$1" in @@ -71,7 +71,7 @@ while [ "$1" ]; do X-N?*) NUMCOND="test \$N -gt ${1#-N}" ;; X-N) shift; NUMCOND="test \$N -ge $1" ;; X-C) rm -f testcert*.conf testcert.dh testcli*.* testsrv*.* ;; - X-foreign|X--foreign) FOREIGN=1 ;; # allow access to 3rd party Internet hosts + X-internet|X--internet) INTERNET=1 ;; # allow access to 3rd party Internet hosts X-expect-fail|X--expect-fail) OPT_EXPECT_FAIL=1; shift; EXPECT_FAIL="$1" ;; X-*) echo "Unknown option \"$1\"" >&2 usage >&2 @@ -990,6 +990,90 @@ routesip6 () { return 0; } + +# Perform a couple of checks to make sure the test has a chance of a useful +# result: +# platform is supported, features compiled in, addresses and options +# available; needs root; is allowed to access the internet +checkconds() { + local unames="$(echo "$1")" # must be one of... exa: "Linux,FreeBSD" + local root="$2" # "root" or "" + local progs="$(echo "$3" |tr 'A-Z,' 'a-z ')" # exa: "nslookup" + local feats="$(echo "$4" |tr 'a-z,' 'A-Z ')" # list of req.features (socat -V) + local addrs="$(echo "$5" |tr 'a-z,' 'A-Z ')" # list of req.addresses (socat -h) + local opts="$(echo "$6" |tr 'A-Z,' 'a-z ')" # list of req.options (socat -hhh) + local runs="$(echo "$7" |tr , ' ')" # list of req.protocols, exa: "sctp6" + local inet="$8" # when "internet": needs allowance + local i + + if [ "$unames" ]; then + local uname="$(echo $UNAME |tr 'A-Z' 'a-z')" + for i in $unames; do + if [ "$uname" = "$(echo "$i" |tr 'A-Z,' 'a-z ')" ]; then + # good, mark as passed + i= + break; + fi + done + [ "$i" ] && { echo "Only on (one of) $unames"; return -1; } + fi + + if [ "$root" = "root" ]; then + if [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then + echo "Must be root" + return -1; + fi + fi + + if [ "$progs" ]; then + for i in $progs; do + if ! type >/dev/null 2>&1; then + echo "Program $i not available" + return -1 + fi + done + fi + + if [ "$feats" ]; then + if ! F=$(testfeats $feats); then + echo "Feature $F not configured in $SOCAT" + return -1 + fi + fi + + if [ "$addrs" ]; then + if ! A=$(testaddrs - $addrs); then + echo "Address $A not available in $SOCAT" + return -1 + fi + fi + + if [ "$opts" ]; then + if ! o=$(testoptions $opts); then + echo "Option $o not available in $SOCAT" + return -1 + fi + fi + + if [ "$runs" ]; then + for i in $runs; do + if ! runs$i >/dev/null; then + echo "$i not available on host" + return -1; + fi + done + fi + + if [ "$inet" ]; then + if [ -z "$NTERNET" ]; then + echo "Use test.sh option -internet" + return -1 + fi + fi + return 0 +} + + # wait until an IP4 protocol is ready waitip4proto () { local proto="$1" @@ -2047,10 +2131,19 @@ N=$((N+1)) NAME=TCP4 -if ! eval $NUMCOND; then :; else case "$TESTS" in *%$N%*|*%functions%*|*%ip4%*|*%ipapp%*|*%tcp%*|*%listen%*|*%$NAME%*) TEST="$NAME: echo via connection to TCP V4 socket" +if ! eval $NUMCOND; then : +elif ! cond=$(checkconds "" "" "" \ + "IP4 TCP LISTEN STDIO PIPE" \ + "TCP4-LISTEN PIPE STDIN STDOUT TCP4" \ + "so-reuseaddr" \ + "tcp4" ); then + $PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" +else tf="$td/test$N.stdout" te="$td/test$N.stderr" tdiff="$td/test$N.diff" @@ -2058,34 +2151,44 @@ newport tcp4; tsl=$PORT ts="127.0.0.1:$tsl" da="test$N $(date) $RANDOM" CMD1="$TRACE $SOCAT $opts TCP4-LISTEN:$tsl,$REUSEADDR PIPE" -CMD2="$TRACE $SOCAT $opts stdin!!stdout TCP4:$ts" +CMD2="$TRACE $SOCAT $opts STDIN!!STDOUT TCP4:$ts" printf "test $F_n $TEST... " $N $CMD1 >"$tf" 2>"${te}1" & pid1=$! waittcp4port $tsl 1 echo "$da" |$CMD2 >>"$tf" 2>>"${te}2" if [ $? -ne 0 ]; then - $PRINTF "$FAILED: $TRACE $SOCAT:\n" - echo "$CMD1 &" - cat "${te}1" - echo "$CMD2" - cat "${te}2" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" elif ! echo "$da" |diff - "$tf" >"$tdiff"; then - $PRINTF "$FAILED\n" - cat "$tdiff" - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + echo "// diff:" >&2 + cat "$tdiff" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" else - $PRINTF "$OK\n" - if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi - numOK=$((numOK+1)) + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + numOK=$((numOK+1)) fi kill $pid1 2>/dev/null -wait ;; +wait +fi ;; # NUMCOND, checkconds esac -fi # NUMCOND N=$((N+1)) @@ -13689,7 +13792,7 @@ N=$((N+1)) # Test the OpenSSL SNI feature NAME=OPENSSL_SNI case "$TESTS" in -*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%foreign%*|*%listen%*|*%$NAME%*) +*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%internet%*|*%listen%*|*%$NAME%*) TEST="$NAME: Test the OpenSSL SNI feature" # Connect to a server that is known to use SNI. Use an SNI name, not the # certifications default name. When the TLS connection is established @@ -13704,8 +13807,8 @@ elif ! feat=$(testoptions openssl-snihost); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif [ -z "$FOREIGN" ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N +elif [ -z "$INTERNET" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -13736,7 +13839,7 @@ N=$((N+1)) # Test the openssl-no-sni option NAME=OPENSSL_NO_SNI case "$TESTS" in -*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%foreign%*|*%listen%*|*%$NAME%*) +*%$N%*|*%functions%*|*%socket%*|*%openssl%*|*%internet%*|*%listen%*|*%$NAME%*) TEST="$NAME: Test the openssl-no-sni option" # Connect to a server that is known to use SNI. Use an SNI name, not the # certifications default name, and use option openssl-no-sni. @@ -13752,8 +13855,8 @@ elif ! feat=$(testoptions openssl-no-sni); then $PRINTF "test $F_n $TEST... ${YELLOW}$feat not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif [ -z "$FOREIGN" ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N +elif [ -z "$INTERNET" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -16077,7 +16180,6 @@ newport tcp6 CMD0a="$TRACE $SOCAT $opts -lp server1 -6 OPENSSL-LISTEN:$PORT,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD0b="$TRACE $SOCAT $opts -lp server2 -6 OPENSSL-LISTEN:$PORT,accept-timeout=.01,cert=testsrv.crt,key=testsrv.key,verify=0 PIPE" CMD1="$TRACE $SOCAT $opts -lp client -6 -T 0.1 PIPE OPENSSL-CONNECT:$LOCALHOST6:$PORT,verify=0" -printf "test $F_n $TEST... " $N $CMD0a >/dev/null 2>"${te}0a" & pid0=$! waittcp6port $PORT 1 @@ -16198,7 +16300,7 @@ N=$((N+1)) # Test if Socats TCP4-client tries all addresses if necessary NAME=TRY_ADDRS_4 case "$TESTS" in -*%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%socket%*|*%foreign%*|*%$NAME%*) +*%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%socket%*|*%internet%*|*%$NAME%*) TEST="$NAME: try all available TCP4 addresses" # Connect to a TCP4 port of a hostname that resolves to two addresses where at # least on the first one the port is closed. @@ -16228,8 +16330,8 @@ elif ! runsip4 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif [ -z "$FOREIGN" ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N +elif [ -z "$INTERNET" ]; then + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -16283,7 +16385,7 @@ N=$((N+1)) # Test if Socats TCP-client tries all addresses (IPv4+IPv6) if necessary NAME=TRY_ADDRS_4_6 case "$TESTS" in -*%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%tcp6%*|*%socket%*|*%foreign%*|*%$NAME%*) +*%$N%*|*%functions%*|*%tcp%*|*%tcp4%*|*%tcp6%*|*%socket%*|*%internet%*|*%$NAME%*) TEST="$NAME: for TCP try all available IPv4 and IPv6 addresses" # Connect to a TCP port that is not open on localhost-4-6.dest-unreach.net, # neither IPv4 nor IPv6 @@ -16313,8 +16415,8 @@ elif ! runsip6 >/dev/null; then $PRINTF "test $F_n $TEST... ${YELLOW}IPv6 not available or not routable${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" -elif [ -z "$FOREIGN" ]; then # only needs Internet DNS - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N +elif [ -z "$INTERNET" ]; then # only needs Internet DNS + $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -internet${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" else @@ -18031,97 +18133,76 @@ exit NAME=SHORT_UNIQUE_TESTNAME case "$TESTS" in *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*) -#*%foreign%*|*%root%*|*%listen%*|*%fork%*|*%ip4%*|*%tcp4%*|*%bug%*|... +#*%internet%*|*%root%*|*%listen%*|*%fork%*|*%ip4%*|*%tcp4%*|*%bug%*|... TEST="$NAME: give a one line description of test" # Describe how the test is performed, and what's the success criteria -if ! eval $NUMCOND; then :; +if ! eval $NUMCOND; then : # Remove unneeded checks, adapt lists of the remaining ones -elif [ "$UNAME" != Linux ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}Only on Linux${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif [ $(id -u) -ne 0 -a "$withroot" -eq 0 ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}Must be root${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif ! $(type nslookup >/dev/null 2>&1); then - $PRINTF "test $F_n $TEST... ${YELLOW}nslookup not available${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif ! F=$(testfeats STDIO IP4 TCP PIPE); then - $PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not configured in $SOCAT${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif ! A=$(testaddrs - TCP4 TCP4-LISTEN PIPE); then - $PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif ! o=$(testoptions so-reuseaddr fork) >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif ! runsip4 >/dev/null; then - $PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available on host${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -elif [ -z "$FOREIGN" ]; then - $PRINTF "test $F_n $TEST... ${YELLOW}use test.sh option -foreign${NORMAL}\n" $N - numCANT=$((numCANT+1)) - listCANT="$listCANT $N" -else -tf="$td/test$N.stdout" -te="$td/test$N.stderr" -tdiff="$td/test$N.diff" -da="test$N $(date) $RANDOM" -newport tcp4 # or whatever proto, or drop this line -CMD0="$TRACE $SOCAT $opts server-address PIPE" -CMD1="$TRACE $SOCAT $opts - client-address" -printf "test $F_n $TEST... " $N -$CMD0 >/dev/null 2>"${te}0" & -pid0=$! -waitport $PORT 1 -#relsleep 1 # if no matching wait*port function -echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" -rc1=$? -kill $pid0 2>/dev/null; wait -if [ "$rc1" -ne 0 ]; then - $PRINTF "$FAILED (rc=$rc1)\n" - echo "$CMD0 &" - cat "${te}0" >&2 - echo "$CMD1" - cat "${te}1" >&2 - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" - namesFAIL="$namesFAIL $NAME" -elif ! echo "$da" |diff "${tf}1" - >$tdiff; then - $PRINTF "$FAILED (diff)\n" - echo "$CMD0 &" - cat "${te}0" >&2 - echo "$CMD1" - cat "${te}1" >&2 - echo "// diff:" >&2 - cat "$tdiff" >&2 - numFAIL=$((numFAIL+1)) - listFAIL="$listFAIL $N" - namesFAIL="$namesFAIL $NAME" -elif [ ??? ]; then - # The test could not run meaningfully - $PRINTF "$CANT\n" - if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi - if [ "$DEBUG" ]; then cat "${te}0" >&2; fi - if [ "$VERBOSE" ]; then echo "$CMD1"; fi - if [ "$DEBUG" ]; then cat "${te}1" >&2; fi +elif ! cond=$(checkconds \ + "Linux,FreeBSD" \ + "root" \ + "nslookup" \ + "IP4 TCP LISTEN STDIO PIPE" \ + "TCP4-LISTEN PIPE STDIN STDOUT TCP4" \ + "so-reuseaddr" \ + "tcp4" ); then + $PRINTF "test $F_n $TEST... ${YELLOW}$cond${NORMAL}\n" $N numCANT=$((numCANT+1)) listCANT="$listCANT $N" namesCANT="$namesCANT $NAME" else - $PRINTF "$OK\n" - if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi - if [ "$DEBUG" ]; then cat "${te}0" >&2; fi - if [ "$VERBOSE" ]; then echo "$CMD1"; fi - if [ "$DEBUG" ]; then cat "${te}1" >&2; fi - numOK=$((numOK+1)) -fi + tf="$td/test$N.stdout" + te="$td/test$N.stderr" + tdiff="$td/test$N.diff" + da="test$N $(date) $RANDOM" + newport tcp4 # or whatever proto, or drop this line + CMD0="$TRACE $SOCAT $opts server-address PIPE" + CMD1="$TRACE $SOCAT $opts - client-address" + printf "test $F_n $TEST... " $N + $CMD0 >/dev/null 2>"${te}0" & + pid0=$! + waitport $PORT 1 + #relsleep 1 # if no matching wait*port function + echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" + rc1=$? + kill $pid0 2>/dev/null; wait + if [ "$rc1" -ne 0 ]; then + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" + elif ! echo "$da" |diff "${tf}1" - >$tdiff; then + $PRINTF "$FAILED\n" + echo "$CMD0 &" + cat "${te}0" >&2 + echo "$CMD1" + cat "${te}1" >&2 + echo "// diff:" >&2 + cat "$tdiff" >&2 + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" + namesFAIL="$namesFAIL $NAME" + elif [ ??? ]; then + # The test could not run meaningfully + $PRINTF "$CANT\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + numCANT=$((numCANT+1)) + listCANT="$listCANT $N" + else + $PRINTF "$OK\n" + if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi + if [ "$DEBUG" ]; then cat "${te}0" >&2; fi + if [ "$VERBOSE" ]; then echo "$CMD1"; fi + if [ "$DEBUG" ]; then cat "${te}1" >&2; fi + numOK=$((numOK+1)) + fi fi # NUMCOND ;; esac