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