xref: /freebsd/contrib/unbound/testdata/common.sh (revision ee3960cba1068e12fb032a68c46d74841d9edab3)
1# common.sh - an include file for commonly used functions for test code.
2# BSD licensed (see LICENSE file).
3#
4# Version 7
5# 2025-04-04: speed up kill_pid.
6# 2023-12-06: list wait_for_soa_serial in overview
7# 2023-12-06: get_ldns_notify, skip_test and teststep, and previous changes
8# also included are wait_logfile, cpu_count, process_cpu_list, and
9# kill_from_pidfile, and use HOME variable for HOME/bin.
10# 2011-04-06: tpk wait_logfile to wait (with timeout) for a logfile line to appear
11# 2011-02-23: get_pcat for PCAT, PCAT_DIFF and PCAT_PRINT defines.
12# 2011-02-18: ports check on BSD,Solaris. wait_nsd_up.
13# 2011-02-11: first version.
14#
15# include this file from a tdir script with
16#   . ../common.sh
17#
18# overview of functions available:
19# error x		: print error and exit
20# info x		: print info
21# test_tool_avail x	: see if program in path and complain, exit if not.
22# get_ldns_testns	: set LDNS_TESTNS to executable ldns-testns
23# get_ldns_notify	: set LDNS_NOTIFY to executable ldns-notify
24# get_make		: set MAKE to gmake or make tool.
25# get_gcc		: set cc or gcc in CC
26# get_pcat		: set PCAT, PCAT_DIFF and PCAT_PRINT executables.
27# set_doxygen_path	: set doxygen path
28# skip_if_in_list	: set SKIP=1 if name in list and tool not available.
29# get_random_port x	: get RND_PORT a sequence of free random port numbers.
30# wait_logfile		: wait on logfile to see entry.
31# wait_server_up	: wait on logfile to see when server comes up.
32# wait_ldns_testns_up   : wait for ldns-testns to come up.
33# wait_unbound_up	: wait for unbound to come up.
34# wait_petal_up		: wait for petal to come up.
35# wait_nsd_up		: wait for nsd to come up.
36# wait_server_up_or_fail: wait for server to come up or print a failure string
37# wait_for_soa_serial	: wait and dig at server for serial.
38# skip_test x		: print message and skip test (must be called in .pre)
39# kill_pid		: kill a server, make sure and wait for it to go down.
40# cpu_count		: get number of cpus in system
41# process_cpu_list	: get cpu affinity list for process
42# kill_from_pidfile     : kill the pid in the given pid file
43# teststep		: print the current test step in the output
44
45
46# print error and exit
47# $0: name of program
48# $1: error to printout.
49error () {
50	echo "$0: error: $1" >&2
51	exit 1
52}
53
54# print info
55# $0: name of program
56# $1: to printout.
57info () {
58	echo "$0: info: $1"
59}
60
61# test if 'tool' is available in path and complain otherwise.
62# $1: tool
63test_tool_avail () {
64	if test ! -x "`which $1 2>&1`"; then
65		echo No "$1" in path
66		exit 1
67	fi
68}
69
70# get ldns-testns tool in LDNS_TESTNS variable.
71get_ldns_testns () {
72	if test -x "`which ldns-testns 2>&1`"; then
73		LDNS_TESTNS=ldns-testns
74	else
75		LDNS_TESTNS=$HOME/bin/ldns-testns
76	fi
77}
78
79# get ldns-notify tool in LDNS_NOTIFY variable.
80get_ldns_notify () {
81	if test -x "`which ldns-notify 2>&1`"; then
82		LDNS_NOTIFY=ldns-notify
83	else
84		LDNS_NOTIFY=$HOME/bin/ldns-notify
85	fi
86}
87
88# get make tool in MAKE variable, gmake is used if present.
89get_make () {
90	if test -x "`which gmake 2>&1`"; then
91		MAKE=gmake
92	else
93		MAKE=make
94	fi
95}
96
97# get cc tool in CC variable, gcc is used if present.
98get_gcc () {
99	if test -x "`which gcc 2>&1`"; then
100		CC=gcc
101	else
102		CC=cc
103	fi
104}
105
106# get pcat, pcat-print and pcat-diff
107get_pcat () {
108	PCAT=`which pcat`
109	PCAT_PRINT=`which pcat-print`
110	PCAT_DIFF=`which pcat-diff`
111}
112
113# set SKIP=1 if the name is in list and tool is not available.
114# $1: name of package to check.
115# $2: list of packages that need the tool.
116# #3: name of the tool required.
117skip_if_in_list () {
118	if echo $2 | grep $1 >/dev/null; then
119		if test ! -x "`which $3 2>&1`"; then
120			SKIP=1;
121		fi
122	fi
123}
124
125# Print a message and skip the test. Must be called in the .pre file.
126# $1: message to print.
127skip_test () {
128	echo "$1"
129	exit 3
130}
131
132# function to get a number of random port numbers.
133# $1: number of random ports.
134# RND_PORT is returned as the starting port number
135get_random_port () {
136	local plist
137	local cont
138	local collisions
139	local i
140	local MAXCOLLISION=1000
141	cont=1
142	collisions=0
143	while test "$cont" = 1; do
144		#netstat -n -A ip -A ip6 -a | sed -e "s/^.*:\([0-9]*\) .*$/\1/"
145		RND_PORT=$(( $RANDOM + 5354 ))
146		# depending on uname try to check for collisions in port numbers
147		case "`uname`" in
148		linux|Linux)
149			plist=`netstat -n -A ip -A ip6 -a 2>/dev/null | sed -e 's/^.*:\([0-9]*\) .*$/\1/'`
150		;;
151		FreeBSD|freebsd|NetBSD|netbsd|OpenBSD|openbsd)
152			plist=`netstat -n -a | grep "^[ut][dc]p[46] " | sed -e 's/^.*\.\([0-9]*\) .*$/\1/'`
153		;;
154		Solaris|SunOS)
155			plist=`netstat -n -a | sed -e 's/^.*\.\([0-9]*\) .*$/\1/' | grep '^[0-9]*$'`
156		;;
157		*)
158			plist=""
159		;;
160		esac
161		cont=0
162		for (( i=0 ; i < $1 ; i++ )); do
163			if echo "$plist" | grep '^'`expr $i + $RND_PORT`'$' >/dev/null 2>&1; then
164				cont=1;
165				collisions=`expr $collisions + 1`
166			fi
167		done
168		if test $collisions = $MAXCOLLISION; then
169			error "too many collisions getting random port number"
170		fi
171	done
172}
173
174# wait for  a logfile line to appear, with a timeout.
175# pass <logfilename> <string to watch> <timeout>
176# $1 : logfilename
177# $2 : string to watch for.
178# $3 : timeout in seconds.
179# exits with failure if it times out
180wait_logfile () {
181	local WAIT_THRES=30
182	local MAX_UP_TRY=`expr $3 + $WAIT_THRES`
183	local try
184	for (( try=0 ; try <= $MAX_UP_TRY ; try++ )) ; do
185		if test -f $1 && grep -F "$2" $1 >/dev/null; then
186			#echo "done on try $try"
187			break;
188		fi
189		if test $try -eq $MAX_UP_TRY; then
190			echo "Logfile in $1 did not get $2!"
191			cat $1
192			exit 1;
193		fi
194		if test $try -ge $WAIT_THRES; then
195			sleep 1
196		fi
197	done
198}
199
200# wait for server to go up, pass <logfilename> <string to watch>
201# $1 : logfilename
202# $2 : string to watch for.
203# exits with failure if it does not come up
204wait_server_up () {
205	local WAIT_THRES=30
206	local MAX_UP_TRY=120
207	local try
208	for (( try=0 ; try <= $MAX_UP_TRY ; try++ )) ; do
209		if test -f $1 && grep -F "$2" $1 >/dev/null; then
210			#echo "done on try $try"
211			break;
212		fi
213		if test $try -eq $MAX_UP_TRY; then
214			echo "Server in $1 did not go up!"
215			cat $1
216			exit 1;
217		fi
218		if test $try -ge $WAIT_THRES; then
219			sleep 1
220		fi
221	done
222}
223
224# wait for ldns-testns to come up
225# $1 : logfilename that is watched.
226wait_ldns_testns_up () {
227	wait_server_up "$1" "Listening on port"
228}
229
230# wait for unbound to come up
231# string 'Start of service' in log.
232# $1 : logfilename that is watched.
233wait_unbound_up () {
234	wait_server_up "$1" "start of service"
235}
236
237# wait for petal to come up
238# string 'petal start' in log.
239# $1 : logfilename that is watched.
240wait_petal_up () {
241	wait_server_up "$1" "petal start"
242}
243
244# wait for nsd to come up
245# string nsd start in log.
246# $1 : logfilename that is watched.
247wait_nsd_up () {
248	wait_server_up "$1" " started (NSD "
249}
250
251# wait for server to go up, pass <logfilename> <string to watch> <badstr>
252# $1 : logfile
253# $2 : success string
254# $3 : failure string
255wait_server_up_or_fail () {
256	local MAX_UP_TRY=120
257	local WAIT_THRES=30
258	local try
259	for (( try=0 ; try <= $MAX_UP_TRY ; try++ )) ; do
260		if test -f $1 && grep -F "$2" $1 >/dev/null; then
261			echo "done on try $try"
262			break;
263		fi
264		if test -f $1 && grep -F "$3" $1 >/dev/null; then
265			echo "failed on try $try"
266			break;
267		fi
268		if test $try -eq $MAX_UP_TRY; then
269			echo "Server in $1 did not go up!"
270			cat $1
271			exit 1;
272		fi
273		if test $try -ge $WAIT_THRES; then
274			sleep 1
275		fi
276	done
277}
278
279# $1: zone
280# $2: serial to be expected
281# $3: server to query
282# $4: port
283# $5: # times to try (# seconds dig is ran)
284wait_for_soa_serial () {
285	TS_START=`date +%s`
286	for i in `seq 1 $5`
287	do
288		SERIAL=`dig -p $4 @$3 $1 SOA +short | awk '{ print $3 }'`
289		if test "$?" != "0"
290		then
291			echo "** \"dig -p $4 @$3 $1 SOA +short\" failed!"
292			return 1
293		fi
294		if test "$SERIAL" = "$2"
295		then
296			TS_END=`date +%s`
297			echo "*** Serial $2 was seen in $i tries (`expr $TS_END - $TS_START`) seconds"
298			return 0
299		fi
300		sleep 1
301	done
302	echo "** Serial $2 was not seen in $5 tries (did see: $SERIAL)"
303	return 1
304}
305
306# kill a pid, make sure and wait for it to go down.
307# $1 : pid to kill
308kill_pid () {
309	local MAX_DOWN_TRY=120
310	local WAIT_THRES=30
311	local try
312	kill $1
313	sleep .001
314	for (( try=0 ; try <= $MAX_DOWN_TRY ; try++ )) ; do
315		if kill -0 $1 >/dev/null 2>&1; then
316			:
317		else
318			#echo "done on try $try"
319			break;
320		fi
321		if test $try -eq $MAX_DOWN_TRY; then
322			echo "Server in $1 did not go down! Send SIGKILL"
323			kill -9 $1 >/dev/null 2>&1
324		fi
325		if test $try -ge $WAIT_THRES; then
326			sleep 1
327		else
328			sleep .01
329		fi
330		# re-send the signal
331		kill $1 >/dev/null 2>&1
332	done
333	return 0
334}
335
336# set doxygen path, so that make doc can find doxygen
337set_doxygen_path () {
338	if test -x '$HOME/bin/doxygen'; then
339	        export PATH="$HOME/bin:$PATH"
340	fi
341}
342
343# get number of cpus in system
344cpu_count()
345{
346  local sys=$(uname -s)
347  if [ "${sys}" = "Linux" ]; then
348    nproc
349  elif [ "${sys}" = "FreeBSD" ]; then
350    sysctl -n hw.ncpu
351  fi
352}
353
354# get cpu affinity list for process
355# $1 : pid
356process_cpu_list() {
357  local pid=${1}
358  local sys=$(uname -s)
359
360  if [ "${sys}" = "Linux" ]; then
361    local defl=$(taskset -pc ${pid} | sed -n -e 's/^.*: //p' | head -n 1)
362  elif [ "${sys}" = "FreeBSD" ]; then
363    local defl=$(cpuset -g -p ${pid} | sed -n -e 's/^.*: //p' | head -n 1)
364  fi
365
366  if [ -n "${defl}" ]; then
367    local infl
368    defl=$(echo "${defl}" | sed -e 's/,/ /g')
369    for i in ${defl}; do
370      rng=$(echo "${i}-${i}" | sed -e 's/^\([0-9]*\)-\([0-9]*\).*$/\1 \2/')
371      infl="${infl} $(seq -s ' ' ${rng})"
372    done
373    infl=$(echo ${infl} | sed -e 's/ */ /' -e 's/^ *//')
374    echo "${infl}"
375  fi
376}
377
378#
379#
380kill_from_pidfile() {
381  local pidfile="$1"
382  if test -f "$pidfile"; then
383    local pid=`head -n 1 "$pidfile"`
384    if test ! -z "$pid"; then
385      kill_pid "$pid"
386    fi
387  fi
388}
389
390# Print the current test step in the output
391teststep () {
392	echo
393	echo "STEP [ $1 ]"
394}
395