source: mod_gnutls/test/runtests @ 26ae700

debian/masterdebian/stretch-backportsproxy-ticketupstream
Last change on this file since 26ae700 was d39ea18, checked in by Thomas Klute <thomas2.klute@…>, 4 years ago

Test suite: Do not continue test case if Apache instance fails to start

On systems where namespaces aren't available, test cases in which
Apache HTTPD is expected not to start would sometimes fail when
running in parallel. The reason was a possible timing issue, where an
Apache instance for another test case might start before gnutls-cli is
run, and the TLS connection would unexpectedly succeed by connecting
to it.

Not attempting the TLS connection if HTTPD failed avoids this problem,
and also (slightly) speeds up tests.

  • Property mode set to 100755
File size: 7.1 KB
RevLine 
[4b53371]1#!/bin/bash
2
[ae38a49]3# Authors:
4# Daniel Kahn Gillmor <dkg@fifthhorseman.net>
5# Thomas Klute <thomas2.klute@uni-dortmund.de>
[4b53371]6
7set -e
[412ee84]8. ${srcdir}/common.bash
[cf4e708]9netns_reexec ${@}
[4b53371]10
[56056de]11testid="${1##t-}"
12
13if [ -z "$testid" ] ; then
14    echo -e "No test case selected.\nUsage: ${0} t-N" >&2
15    exit 1
16else
17    testid=${srcdir}/tests/"$(printf "%02d" "$testid")"_*
18fi
[4b53371]19
20BADVARS=0
[a08b25e]21for v in APACHE2 TEST_HOST TEST_PORT TEST_QUERY_DELAY TEST_MSVA_WAIT \
[412ee84]22                 MSVA_PORT; do
[4b53371]23    if [ ! -v "$v" ]; then
24        printf "You need to set the %s environment variable\n" "$v" >&2
25        BADVARS=1
26    fi
27done
28
29if [ 0 != "$BADVARS" ]; then
30    exit 1
31fi
32
[45ae2ef]33# write script file and line to stderr on error
34function pinpoint_error()
35{
36    echo "${1} failed at line ${2}!" >&2
37}
38trap 'pinpoint_error ${BASH_SOURCE} ${LINENO}' ERR
39
[ae38a49]40function stop_msva()
41{
42    kill_by_pidfile "${msva_pidfile}"
43    unset msva_pidfile
[e3cbda4]44}
45
[a213967]46# Compare expected/actual outputs, filtering out headers from actual
47# output that are expected to change between runs or builds (currently
48# "Date" and "Server"). The headers must be excluded in the expected
49# output.
[54aa269]50#
51# Parameters:
52# $1: path to expected output
53# $2: path to actual output
54# $3: additional options for diff (optional)
[a213967]55function diff_output_filter_headers()
[54aa269]56{
[232fb60]57    local expected="$1"
58    local actual="$2"
[54aa269]59    diff $3 -u "${expected}" <( cat "${actual}" | \
[a213967]60        grep -v -P '^Date:\s.*GMT\s?$' | \
61        grep -v -P '^Server:\sApache'  | \
62        tail -n "$(wc -l < ${expected})" )
[54aa269]63}
64
[232fb60]65# Run a command, storing its PID in the given file
66# Usage: run_with_pidfile PIDFILE COMMAND [ARGS]
67function run_with_pidfile()
68{
69    local pidfile=$1
70    local cmd=$2
71    shift 2
72    echo $BASHPID >${pidfile}
73    exec ${cmd} $*
74}
75
76# Kills the process with the PID contained in a given file, then
77# deletes the file.
78# Usage: kill_by_pidfile PIDFILE
79function kill_by_pidfile()
80{
81    local pidfile="${1}"
82    # In some testcases with expected failure, gnutls-cli sometimes
83    # failed before the subshell in front of the pipe (see gnutls-cli
84    # call below) got so far as to write the PID, much less exec
85    # sleep. So we need to check if there actually is anything to
86    # kill.
87    if [ -n "${pidfile}" ]; then
88        local pid=$(cat "${pidfile}")
89        if [ -n "${pid}" ] && ps -p "${pid}"; then
90            kill "${pid}"
91        fi
92        rm "${pidfile}"
93    fi
94}
95
[4b53371]96function apache_down_err() {
97    printf "FAILURE: %s\n" "$TEST_NAME"
[af7da2d]98    ${APACHE2} -f "${t}/apache.conf" -k stop || true
[4b53371]99    if [ -e output ]; then
[54aa269]100        printf "\ngnutls-cli outputs:\n"
[a213967]101        diff_output_filter_headers "output" "$output" || true
[4b53371]102    fi
[232fb60]103
104    if [ -n "${sleep_pidfile}" ]; then
105        kill_by_pidfile "${sleep_pidfile}"
106    fi
107
[03295a9]108    local errlog="logs/${TEST_NAME}.error.log"
109    if [ -r "${errlog}" ]; then
110        printf "\nApache error logs:\n"
111        tail "${errlog}"
112    fi
[232fb60]113
[302965e]114    if [ -n "${USE_MSVA}" ]; then
115        stop_msva
116    fi
[4b53371]117}
118
[302965e]119if [ -n "${USE_MSVA}" ]; then
[ae38a49]120    msva_pidfile="$(mktemp mod_gnutls_test-XXXXXX.pid)"
121    GNUPGHOME=msva.gnupghome MSVA_KEYSERVER_POLICY=never run_with_pidfile "${msva_pidfile}" monkeysphere-validation-agent &
[302965e]122    trap stop_msva EXIT
[e3cbda4]123
[302965e]124    printf "TESTING: initial MSVA verification\n"
[7adbcd7]125    # set to 0 if MSVA is up
126    ret=1
127    export MONKEYSPHERE_VALIDATION_AGENT_SOCKET="http://127.0.0.1:$MSVA_PORT"
[a61edfd]128
129    # convert TEST_MSVA_WAIT to seconds because that's what "sleep" expects
130    TEST_MSVA_SLEEP="$((${TEST_MSVA_WAIT} / 1000)).$((${TEST_MSVA_WAIT} % 1000))"
131    # wait at most TEST_MSVA_MAX_WAIT milliseconds for MSVA to get ready
132    waited=0
[7adbcd7]133    until [ ${ret} -eq 0 ] \
[a61edfd]134              || [ ${waited} -ge ${TEST_MSVA_MAX_WAIT} ]; do
[7adbcd7]135        if msva-query-agent https "$(cat client.uid)" x509pem client < client/x509.pem
136        then
137            ret=0
138        else
139            echo "MSVA not ready yet"
140        fi
[a61edfd]141        sleep "${TEST_MSVA_SLEEP}"
142        waited=$((${waited} + ${TEST_MSVA_WAIT}))
[7adbcd7]143    done
144
145    # check if MSVA is up, fail if not
146    if [ ${ret} -eq 0 ]; then
147        printf "\nSUCCESS: initial MSVA verification\n"
148    else
149        printf "\nFAIL: initial MSVA verification\n"
150        exit 1
151    fi
[302965e]152fi
[e3cbda4]153
[412ee84]154TEST_PID="apache2.pid"
[dbec528]155# configure locking for the Apache process
[cf4e708]156if [ -n "${USE_TEST_NAMESPACE}" ]; then
157    echo "Using namespaces to isolate tests, no need for locking."
158    flock_cmd=""
159elif [ -n "${TEST_LOCK}" ]; then
[412ee84]160    flock_cmd="${FLOCK} -w ${TEST_LOCK_WAIT} $(realpath ${TEST_LOCK})"
161else
162    echo "Locking disabled, using wait based on Apache PID file."
163    wait_pid_gone "${TEST_PID}"
164    flock_cmd=""
165fi
[dbec528]166
[5d85ad3]167t="$(realpath ${testid})"
168export srcdir="$(realpath ${srcdir})"
169export TEST_NAME="$(basename "$t")"
170output="outputs/${TEST_NAME}.output"
171rm -f "$output"
172
173if [ -e ${t}/fail.* ]; then
174    EXPECTED_FAILURE="$(printf " (expected: %s)" fail.*)"
175else
176    unset EXPECTED_FAILURE
177fi
178printf "TESTING: %s%s\n" "$TEST_NAME" "$EXPECTED_FAILURE"
179trap apache_down_err EXIT
180if [ -n "${USE_MSVA}" ]; then
[d39ea18]181    export MONKEYSPHERE_VALIDATION_AGENT_SOCKET="http://127.0.0.1:$MSVA_PORT"
182fi
183if ! ${flock_cmd} ${APACHE2} -f "${t}/apache.conf" -k start; then
184    if [ -e "${t}/fail.server" ]; then
185        echo "Apache HTTPD failed to start as expected."
186        exit 0
187    else
188        echo "Apache HTTPD unexpectedly failed to start."
189        exit 1
190    fi
[5d85ad3]191fi
[4b53371]192
[c4d6e77]193# check OCSP server
194if [ -n "${CHECK_OCSP_SERVER}" ]; then
[94cb972]195    if [ -n "${OCSP_RESPONSE_FILE}" ]; then
196        store_ocsp="--outfile ${OCSP_RESPONSE_FILE}"
197    fi
[c4d6e77]198    echo "---- Testing OCSP server ----"
[94cb972]199    ocsptool --ask --nonce --load-issuer authority/x509.pem --load-cert server/x509.pem ${store_ocsp}
[c4d6e77]200    echo "---- OCSP test done ----"
201fi
202
[5d85ad3]203# PID file for sleep command (explanation below)
204sleep_pidfile="$(mktemp mod_gnutls_test-XXXXXX.pid)"
205
206# The sleep call keeps the pipe from the subshell to gnutls-cli
207# open. Without it gnutls-cli would terminate as soon as sed is
208# done, and not wait for a response from the server, leading to
209# failing tests. Sending sleep to the background allows the test
210# case to proceed instead of waiting for it to return. The sleep
211# process is stopped after gnutls-cli terminates.
[0a12ff8]212#
213# The line end manipulation in sed guarantees that all header lines
214# end with CRLF as required by RFC 7230, Section 3.1.1 regardless of
215# the line ends in the input file.
216if (sed -r "s/__HOSTNAME__/${TEST_HOST}/;s/\r?$/\r/" <${t}/input && \
[5d85ad3]217           run_with_pidfile "${sleep_pidfile}" sleep "${TEST_QUERY_DELAY}" &) | \
218       gnutls-cli -p "${TEST_PORT}" $(cat ${t}/gnutls-cli.args) "${TEST_HOST}" \
[28fc74b]219       | tee "$output" && test "${PIPESTATUS[1]}" -eq 0;
[5d85ad3]220then
221    if [ -e ${t}/fail* ]; then
222        printf "%s should have failed but succeeded\n" "$(basename "$t")" >&2
223        exit 1
[4b53371]224    fi
[5d85ad3]225else
226    if [ ! -e ${t}/fail* ]; then
227        printf "%s should have succeeded but failed\n" "$(basename "$t")" >&2
228        exit 1
229    fi
230fi
[dda3acf]231
[5d85ad3]232kill_by_pidfile "${sleep_pidfile}"
233unset sleep_pidfile
[232fb60]234
[5d85ad3]235if [ -e ${t}/output ] ; then
[13ffeff]236    diff_output_filter_headers "${t}/output" "$output" >&2
[5d85ad3]237fi
238if [ -n "${USE_MSVA}" ]; then
239    trap stop_msva EXIT
240else
241    trap - EXIT
242fi
243${APACHE2} -f "${t}/apache.conf" -k stop || [ -e ${t}/fail.server ]
244printf "SUCCESS: %s\n" "$TEST_NAME"
[e3cbda4]245
[302965e]246if [ -n "${USE_MSVA}" ]; then
247    stop_msva
[ae38a49]248    # Without explicitly resetting the trap function, it would be
249    # called again on exit. Of course, we could just not stop MSVA and
250    # let the trap do the work, but I think the code is easier to
251    # understand like this.
252    trap - EXIT
[302965e]253fi
Note: See TracBrowser for help on using the repository browser.