source: mod_gnutls/test/runtests @ a08b25e

debian/masterdebian/stretch-backportsjessie-backportsupstream
Last change on this file since a08b25e was a08b25e, checked in by Thomas Klute <thomas2.klute@…>, 4 years ago

Test suite: Listen on IPv6 and IPv4 loopback by default

Distributions handle host names for loopback addresses and their
resolution differently, which caused trouble with the previous
defaults of TEST_HOST=localhost and TEST_IP=[::1]. While they work
fine on Debian, tests on Ubuntu failed apparently randomly because
connections to localhost sometimes used 127.0.0.1, and setting
TEST_IP=127.0.0.1 would sometimes be hit by the opposite effect.

The best solution seems to be to let the test servers listen on both
IPv4 and IPv6 loopback addresses (127.0.0.1 and [::1]): "localhost"
should always resolve to at least one of them, so we don't have to
care about the details. Apache handles the transport layer anyway, so
this change will not hide bugs in mod_gnutls itself.

Listening on both addresses is achieved by treating TEST_IP as a list
of addresses to listen on, changing the default to "[::1] 127.0.0.1",
and building a config file containing "Listen" directives for the test
servers from that. With this change there is no need to export TEST_IP
to the test environment any more.

Users who want to set their own TEST_IP can do so as before, but
should note that IPv6 addresses must be enclosed in square brackets.

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