1#!/bin/sh
2#
3# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, you can obtain one at https://mozilla.org/MPL/2.0/.
8#
9# See the COPYRIGHT file distributed with this work for additional
10# information regarding copyright ownership.
11
12#
13# Run a system test.
14#
15
16SYSTEMTESTTOP="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"
17. $SYSTEMTESTTOP/conf.sh
18
19if [ "`id -u`" -eq "0" ] && ! ${NAMED} -V | grep -q -F -- "enable-developer"; then
20    echofail "Refusing to run test as root. Build with --enable-developer to override." >&2
21    exit 1
22fi
23
24export SYSTEMTESTTOP
25
26stopservers=true
27baseport=5300
28
29if [ ${SYSTEMTEST_NO_CLEAN:-0} -eq 1 ]; then
30    clean=false
31else
32    clean=true
33fi
34
35while getopts "knp:r-:" flag; do
36    case "$flag" in
37    -) case "${OPTARG}" in
38               keep) stopservers=false ;;
39               noclean) clean=false ;;
40           esac
41           ;;
42    k) stopservers=false ;;
43    n) clean=false ;;
44    p) baseport=$OPTARG ;;
45    esac
46done
47shift `expr $OPTIND - 1`
48
49if [ $# -eq 0 ]; then
50    echofail "Usage: $0 [-k] [-n] [-p <PORT>] test-directory [test-options]" >&2;
51    exit 1
52fi
53
54systest=${1%%/}
55shift
56
57if [ ! -d $systest ]; then
58    echofail "$0: $systest: no such test" >&2
59    exit 1
60fi
61
62# Define the number of ports allocated for each test, and the lowest and
63# highest valid values for the "-p" option.
64#
65# The lowest valid value is one more than the highest privileged port number
66# (1024).
67#
68# The highest valid value is calculated by noting that the value passed on the
69# command line is the lowest port number in a block of "numports" consecutive
70# ports and that the highest valid port number is 65,535.
71numport=100
72minvalid=`expr 1024 + 1`
73maxvalid=`expr 65535 - $numport + 1`
74
75test "$baseport" -eq "$baseport" > /dev/null 2>&1
76if [ $? -ne 0 ]; then
77    echofail "$0: $systest: must specify a numeric value for the port" >&2
78    exit 1
79elif [ $baseport -lt $minvalid -o $baseport -gt $maxvalid  ]; then
80    echofail "$0: $systest: the specified port must be in the range $minvalid to $maxvalid" >&2
81    exit 1
82fi
83
84# Name the first 10 ports in the set (it is assumed that each test has access
85# to ten or more ports): the query port, the control port and eight extra
86# ports.  Since the lowest numbered port (specified in the command line)
87# will usually be a multiple of 10, the names are chosen so that if this is
88# true, the last digit of EXTRAPORTn is "n".
89PORT=$baseport
90EXTRAPORT1=`expr $baseport + 1`
91EXTRAPORT2=`expr $baseport + 2`
92EXTRAPORT3=`expr $baseport + 3`
93EXTRAPORT4=`expr $baseport + 4`
94EXTRAPORT5=`expr $baseport + 5`
95EXTRAPORT6=`expr $baseport + 6`
96EXTRAPORT7=`expr $baseport + 7`
97EXTRAPORT8=`expr $baseport + 8`
98CONTROLPORT=`expr $baseport + 9`
99
100LOWPORT=$baseport
101HIGHPORT=`expr $baseport + $numport - 1`
102
103export PORT
104export EXTRAPORT1
105export EXTRAPORT2
106export EXTRAPORT3
107export EXTRAPORT4
108export EXTRAPORT5
109export EXTRAPORT6
110export EXTRAPORT7
111export EXTRAPORT8
112export CONTROLPORT
113
114export LOWPORT
115export HIGHPORT
116
117echostart "S:$systest:`date`"
118echoinfo  "T:$systest:1:A"
119echoinfo  "A:$systest:System test $systest"
120echoinfo  "I:$systest:PORTRANGE:${LOWPORT} - ${HIGHPORT}"
121
122if [ x${PERL:+set} = x ]
123then
124    echowarn "I:$systest:Perl not available.  Skipping test."
125    echowarn "R:$systest:UNTESTED"
126    echoend  "E:$systest:`date $dateargs`"
127    exit 0;
128fi
129
130$PERL testsock.pl -p $PORT  || {
131    echowarn "I:$systest:Network interface aliases not set up.  Skipping test."
132    echowarn "R:$systest:UNTESTED"
133    echoend  "E:$systest:`date $dateargs`"
134    exit 0;
135}
136
137# Check for test-specific prerequisites.
138test ! -f $systest/prereq.sh || ( cd $systest && $SHELL prereq.sh "$@" )
139result=$?
140
141if [ $result -eq 0 ]; then
142    : prereqs ok
143else
144    echowarn "I:$systest:Prerequisites missing, skipping test."
145    [ $result -eq 255 ] && echowarn "R:$systest:SKIPPED" || echowarn "R:$systest:UNTESTED"
146    echoend "E:$systest:`date $dateargs`"
147    exit 0
148fi
149
150# Check for PKCS#11 support
151if
152    test ! -f $systest/usepkcs11 || $SHELL cleanpkcs11.sh
153then
154    : pkcs11 ok
155else
156    echowarn "I:$systest:Need PKCS#11, skipping test."
157    echowarn "R:$systest:PKCS11ONLY"
158    echoend  "E:$systest:`date $dateargs`"
159    exit 0
160fi
161
162# Clean up files left from any potential previous runs
163if test -f $systest/clean.sh
164then
165   ( cd $systest && $SHELL clean.sh "$@" )
166fi
167
168# Set up any dynamically generated test data
169if test -f $systest/setup.sh
170then
171   ( cd $systest && $SHELL setup.sh "$@" )
172fi
173
174# Start name servers running
175$PERL start.pl --port $PORT $systest
176if [ $? -ne 0 ]; then
177    echofail "R:$systest:FAIL"
178    echoend  "E:$systest:`date $dateargs`"
179    exit 1
180fi
181
182# Run the tests
183( cd $systest ; $SHELL tests.sh "$@" )
184status=$?
185
186if $stopservers
187then
188    :
189else
190    exit $status
191fi
192
193# Shutdown
194$PERL stop.pl $systest
195
196status=`expr $status + $?`
197
198get_core_dumps() {
199    find "$systest/" \( -name 'core' -or -name 'core.*' -or -name '*.core' \) ! -name '*.gz' ! -name '*.txt' | sort
200}
201
202core_dumps=$(get_core_dumps | tr '\n' ' ')
203assertion_failures=$(find "$systest/" -name named.run -print0 | xargs -0 grep "assertion failure" | wc -l)
204sanitizer_summaries=$(find "$systest/" -name 'tsan.*' | wc -l)
205if [ -n "$core_dumps" ]; then
206    echoinfo "I:$systest:Core dump(s) found: $core_dumps"
207    echofail "R:$systest:FAIL"
208    get_core_dumps | while read -r coredump; do
209        SYSTESTDIR="$systest"
210        echoinfo "D:$systest:backtrace from $coredump:"
211        echoinfo "D:$systest:--------------------------------------------------------------------------------"
212        binary=$(gdb --batch --core="$coredump" 2>/dev/null | sed -ne "s|Core was generated by \`\([^' ]*\)[' ].*|\1|p")
213        if [ ! -f "${binary}" ]; then
214            binary=$(find "${TOP}" -path "*/.libs/${binary}" -type f)
215        fi
216        "${TOP}/libtool" --mode=execute gdb \
217                                  -batch \
218                                  -ex bt \
219                                  -core="$coredump" \
220                                  -- \
221                                  "$binary" 2>/dev/null | sed -n '/^Core was generated by/,$p' | cat_d
222        echoinfo "D:$systest:--------------------------------------------------------------------------------"
223        coredump_backtrace="${coredump}-backtrace.txt"
224        echoinfo "D:$systest:full backtrace from $coredump saved in $coredump_backtrace"
225        "${TOP}/libtool" --mode=execute gdb \
226                      -batch \
227                      -command=run.gdb \
228                      -core="$coredump" \
229                      -- \
230                      "$binary" > "$coredump_backtrace" 2>&1
231        echoinfo "D:$systest:core dump $coredump archived as $coredump.gz"
232        gzip -1 "${coredump}"
233    done
234elif [ "$assertion_failures" -ne 0 ]; then
235    echoinfo "I:$systest:$assertion_failures assertion failure(s) found"
236    find "$systest/" -name 'tsan.*' -print0 | xargs -0 grep "SUMMARY: " | sort -u | cat_d
237    echofail "R:$systest:FAIL"
238elif [ "$sanitizer_summaries" -ne 0 ]; then
239    echoinfo "I:$systest:$sanitizer_summaries sanitizer report(s) found"
240    echofail "R:$systest:FAIL"
241elif [ "$status" != 0 ]; then
242    echofail "R:$systest:FAIL"
243else
244    echopass "R:$systest:PASS"
245    if $clean; then
246        ( cd $systest && $SHELL clean.sh "$@" )
247        if test -d ../../../.git; then
248            git status -su --ignored "${systest}/" 2>/dev/null | \
249            sed -n -e 's|^?? \(.*\)|I:'${systest}':file \1 not removed|p' \
250            -e 's|^!! \(.*/named.run\)$|I:'${systest}':file \1 not removed|p' \
251            -e 's|^!! \(.*/named.memstats\)$|I:'${systest}':file \1 not removed|p'
252        fi
253    fi
254fi
255
256echoend "E:$systest:`date $dateargs`"
257
258exit $status
259