3
# Test infrastructure support.
5
# Copyright 2010 Canonical, Ltd.
7
# This program is free software; you can redistribute it and/or
8
# modify it under the terms of the GNU General Public License as
9
# published by the Free Software Foundation, version 2 of the
12
# This file should be included by each test case
13
# It does a lot of hidden 'magic', Downside is that
14
# this magic makes debugging fauling tests more difficult.
15
# Running the test with the '-r' option can help.
17
# Userchangeable variables (tmpdir etc) should be specified in
20
# Cleanup is automatically performed by epilogue.inc
22
# For this file, functions are first, entry point code is at end, see "MAIN"
29
_fatal=true # avoid cascading fatal errors
30
echo "Fatal Error ($testname): $*" >&2
37
fatalerror "Unable to run test sub-executable"
42
# global num_testfailures teststatus
43
num_testfailures=$(($num_testfailures + 1))
46
# if we are retaining the tmpdir we are debugging failures so
47
# stop so it can be looked at
48
if [ $retaintmpdir == "true" ] ; then
55
#invoke exit_handler to cleanup
58
fatalerror "Unexpected shell error. Run with -x to debug"
61
# invoked whenever we exit (normally, interrupt
62
# or exit due to testfailure()/error_handler()
74
# create a log so we can run test again if -retain specified
77
#global tmpdir profile outfile
79
if [ "$retaintmpdir" = "true" ]
81
runfile=$tmpdir/runtest
82
echo "$subdomain ${parser_args} $profile" > $runfile
83
echo -n "$testexec " >> $runfile
84
while [ $# -gt 0 ] ; do
85
echo -n "\"$1\" " >> $runfile
88
echo "2>&1 > $outfile" >> $runfile
89
echo "echo $testname: \`cat $outfile\`" >> $runfile
90
echo "$subdomain ${parser_args} -R $profile" >> $runfile
96
if [ -z "${__NO_TRAP_ERR}" ]
98
trap "error_handler" ERR
101
# global _testdesc _pfmode _known _pid outfile
104
if [ ${2:0:1} == "x" ] ; then
106
_known=" (known problem)"
116
$testexec "$@" > $outfile 2>&1 &
123
# global _pid _rc outfile
130
echo "SIGNAL$(($rc - 128))" > $outfile
137
# global _testdesc _pfmode _known outfile
139
if [ ${2:0:1} == "x" ] ; then
141
_known=" (known problem)"
150
$testexec "$@" > $outfile 2>&1 &
154
if [ $test_rc -gt 128 ]
156
echo "SIGNAL$(($test_rc - 128))" > $outfile
162
# global _pfmode _known _testdesc outfile teststatus testname
163
local ret expectedsig killedsig
165
ret=`cat $outfile 2>/dev/null`
169
PASS) if [ "$_pfmode" != "pass" -a -z "${_known}" ]
171
echo "Error: ${testname} passed. Test '${_testdesc}' was expected to '${_pfmode}'"
174
elif [ "$_pfmode" == "pass" -a -n "${_known}" ]
176
echo "Alert: ${testname} passed. Test '${_testdesc}' was marked as expected pass but known problem (xpass)"
179
FAIL*) if [ "$_pfmode" != "fail" -a -z "${_known}" ]
181
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'. Reason for failure '${ret}'"
184
elif [ "$_pfmode" == "fail" -a -n "${_known}" ]
186
echo "Alert: ${testname} failed. Test '${_testdesc}' was marked as expected fail but known problem (xfail)."
189
SIGNAL*) killedsig=`echo $ret | sed 's/SIGNAL//'`
191
signal*) expectedsig=`echo ${_pfmode} | sed 's/signal//'`
192
if [ -n "${expectedsig}" -a ${expectedsig} != ${killedsig} ]
194
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to terminate with signal ${expectedsig}${_known}. Instead it terminated with signal ${killedsig}"
199
*) echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'${_known}. Reason for failure 'killed by signal ${killedsig}'"
210
if [ -n "$VERBOSE" ]; then
211
echo "ok: ${_testdesc}"
217
if [ -z "${__NO_TRAP_ERR}" ]
219
trap "error_handler" ERR
228
local errno=$(perl -MPOSIX -e 'printf "%d\n", '$1';')
231
if [ -z "${__NO_TRAP_ERR}" ]
233
trap "error_handler" ERR
237
if [ "$test_rc" == "$errno" ] ; then
240
echo "Error: ${testname} failed. Test '${_testdesc}' was expected to '${_pfmode}'${_known}. Reason for failure expect errno ${errno} != ${test_rc}"
247
if [ -z "${__NO_TRAP_ERR}" ]
249
trap "error_handler" ERR
252
#global name outfile profile profilenames
256
$bin/mkprofile.pl ${mkflags} "$name" ${outfile}:w "$@" >> $profile
258
echo $name >> $profilenames
263
if [ -z "${__NO_TRAP_ERR}" ]
265
trap "error_handler" ERR
268
local num_emitted imagename hat args arg names1 names2
269
#global complainflag escapeflag nodefaults profile profilenames
276
"-C") complainflag="-C"
278
"-E") mkflags="${mkflags} -E"
280
"-N") mkflags="${mkflags} -N"
282
"-I") mkflags="${mkflags} -I"
290
# save previous profile
293
mv $profile ${profile}.old
294
mv $profilenames ${profilenames}.old
303
# image/subhat allows overriding of the default
304
# imagename which is based on the testname
306
# it is most often used after --, in fact it is basically
309
image=*) imagename=`echo $1 | sed 's/^image=\([^:]*\).*$/\1/'`
310
if [ ! -x "$imagename" ]
312
fatalerror "invalid imagename specified in input '$1'"
317
subhat=*) fatalerror "'subhat=hatname' is no longer supported ('$1')"
328
# -- is the separator between profiles
329
if [ "$arg" == "--" ]
331
eval emit_profile \"$imagename\" \
332
$(for i in $(seq 0 $((${num_args} - 1))) ; do echo \"\${args[${i}]}\" ; done)
333
num_emitted=$((num_emitted + 1))
337
args[${num_args}]=${arg}
338
num_args=$(($num_args + 1))
342
# output what is in args, or force empty profile
343
if [ -n "$args" -o $num_emitted -eq 0 ] ; then
344
eval emit_profile \"$imagename\" \
345
$(for i in $(seq 0 $((${num_args} - 1))) ; do echo \"\${args[${i}]}\" ; done)
351
# if old and new profiles consist of the same entries
352
# we can do a replace, else remove/reload
353
if [ $profileloaded -eq 1 ]
355
names1=$tmpdir/sorted1
356
names2=$tmpdir/sorted2
357
sort $profilenames > $names1
358
sort ${profilenames}.old > $names2
360
if cmp -s $names1 $names2
364
removeprofile ${profile}.old
368
rm -f $names1 $names2
374
if [ -e ${sys_profiles} ] ; then
375
#check to see if the profiles are actually loaded
376
for f in `cat $profilenames` ; do
377
grep -Eq "^$f"' \([^)]+\)$' ${sys_profiles}
379
if [ $rc -ne 0 ] ; then
380
echo "Genprofile failed to load profile \"$f\""
386
rm -f ${profile}.old ${profilenames}.old
391
#global complainflaf profile profileloaded
393
$subdomain ${parser_args} $complainflag $profile > /dev/null
397
fatalerror "Unable to load profile $profile"
405
#global complainflag profile
407
$subdomain ${parser_args} -r $complainflag $profile > /dev/null
410
fatalerror "Unable to replace profile $profile"
417
#global profile profileloaded
426
$subdomain ${parser_args} -R $remprofile > /dev/null
429
fatalerror "Unable to remove profile $remprofile"
437
if [ -z "${__NO_TRAP_ERR}" ]
439
trap "error_handler" ERR
442
#global test testname testexec outfile profileloaded
444
#testname is the basename of the test, i,e 'open'
445
#test is the full path to the test executable.
446
#testexec is the path than will be run, normally this is the same
447
# as $test, but occasionally, you may want to invoke a wrapper which
448
# will run the test. In this case 'settest <testname> "wrapper {}'
449
# will result in testexec invoking wrapper. {} will be replaced with
461
testexec=`echo $2 | sed "s~{}~$test~"`
463
fatalerror "settest, illegal usage"
466
outfile=$tmpdir/output.$1
468
# Remove any current profile if loaded
469
if [ $profileloaded -eq 1 ]
475
# ----------------------------------------------------------------------------
479
trap "exit_handler" EXIT
480
trap "error_handler" ERR 2> /dev/null
487
if [ `whoami` != "root" ]
489
fatalerror "Must be root to run $0"
494
fatalerror "$0 requires \$bin pointing to binary directory"
498
# -r/-retain: flag to retain last failing testcase in tmpdir
499
if [ "$1" == "-retain" -o "$1" == "-r" ]
506
# load user changeable variables
509
if [ ! -x $subdomain ]
511
fatalerror "AppArmor parser '$subdomain' is not executable"
516
tmpdir=$(mktemp -d $tmpdir-XXXXXX)
520
#set initial testname based on name of script
521
settest `basename $0 .sh`
523
profile=$tmpdir/profile
524
profilenames=$tmpdir/profile.names
525
num_testfailures=0 # exit code of script is set to #failures