3 # Simple test wrapper around radclient to allow automated UATs
5 # Author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
6 # Copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
7 # Copyright 2015 The FreeRADIUS Project
10 OPTIND=1 # Reset in case getopts has been used previously in the shell.
12 # Environmental variables
13 : ${TESTDIR=$(dirname $0)"/tests"}
14 : ${RADCLIENT='radclient'}
15 : ${FILTER_SUFFIX='_expected'}
16 : ${DICTPATH=$(dirname $0)/share}
17 PATH="$(dirname $0)/bin:${PATH}"
19 # Initialize our own variables
30 # Some very basic logging functions
43 if [ $verbose -gt 0 ]; then
50 echo $(basename $0)" [options] [-- <test_glob0> <test_glob1> <test_globN>]"
51 echo " -h Display this help message."
52 echo " -H <host>[:port] Send test packets to specified host and port (defaults to 127.0.0.1)"
53 echo " -v Verbose mode."
54 echo " -p <number> Run tests in parallel (defaults to 20)."
55 echo " -s <secret> Shared secret."
56 if [ ! -z "$role_types" ]; then
57 echo " -c <cluster> Specify cluster type one of ($cluster_types)."
58 echo " -r <type> Specify server role one of ($role_types)."
60 echo "Note: Test path globs are relative to ${TESTDIR}/<cluster>/<type>/"
64 echo "For role based test file layout create test files under ${TESTDIR}/<cluster>/<type>"
65 echo "Where <cluster> and <type> are substrings found in the FQDN of <host>."
66 echo "For simplified test layout create test files under ${TESTDIR}"
68 echo "The directory containing the tests should contains pairs of request files and filter files."
69 echo "The request file name must contain 'test<num><num><num>."
70 echo "The filter name must match the test name but with a '${FILTER_SUFFIX}' suffix."
72 echo " ${TESTDIR}/test000_my_first_test"
73 echo " ${TESTDIR}/test000_my_first_test${FILTER_SUFFIX}"
75 echo "The directory containing the tests may have multiple subdirectories to group the tests."
78 RADCLIENT=$(which "$RADCLIENT")
79 if [ ! -x "$RADCLIENT" ]; then
80 ERROR "Can't find radclient binary, modify your \$PATH or set RADCLIENT"
84 if [ ! -d "$TESTDIR" ]; then
85 ERROR "Test dir $TESTDIR does not exist, create it or specify it with TESTDIR=<dir>"
90 # Definitions (build these dynamically by looking at the files under tests)
91 cluster_dirs=$(find "$TESTDIR/" -mindepth 1 -maxdepth 1 -type d)
92 cluster_types=$(echo $cluster_dirs | sed 's/\s/ /g')
95 for i in $cluster_dirs; do
96 for j in $(find "$TESTDIR/$(basename $i)/" -mindepth 1 -maxdepth 1 -type d); do
98 if [ "$role_types" == '' ]; then
101 role_types+="\n$role"
106 if [ -z "$role_types" ]; then
107 DEBUG "Using simple test file layout"
109 DEBUG "Using role based test file layout"
110 role_types=$(echo -e "$role_types" | sort | uniq) # Remove duplicates
111 role_types=$(echo $role_types | sed 's/\s/ /g') # Change \n back to spaces
114 while getopts "h?H:vc:r:s:p:" opt; do
127 for i in $cluster_types; do
128 if [ "$i" == "$OPTARG" ]; then
132 if [ $found -ne 1 ]; then
133 ERROR "'$OPTARG' is not a valid cluster type"
142 for i in $role_types; do
143 if [ "$i" == "$OPTARG" ]; then
147 if [ $found -ne 1 ]; then
148 ERROR "'$OPTARG' is not a valid role type"
160 if ! echo "$OPTARG" | grep -E '^[0-9]+$' > /dev/null; then
161 ERROR "Non integer argument '$OPTARG' specified for -p"
177 [ "$1" = "--" ] && shift
181 # Match keywords from the hostname to clusters or roles
183 if [ ! -z "$role_types" ]; then
184 this_host=$(hostname -f)
185 for tok in $(echo "$this_host" | sed 's/\./ /g'); do
186 for key in ${cluster_types}; do
187 if echo "$tok" | grep "$key" > /dev/null && [ "$cluster" = '' ]; then cluster="$key"; fi
189 for key in ${role_types}; do
190 if echo "$tok" | grep "$key" > /dev/null && [ "$role" = '' ]; then role="$key"; fi
194 if [ "$cluster" == '' ]; then
195 ERROR "Couldn't determine the cluster $this_host belongs to";
200 if [ "$role" == '' ]; then
201 ERROR "Couldn't determine the role $this_host performs";
206 test_path="${TESTDIR}/${cluster}/${role}"
208 # Otherwise just use the tests in the test dir
211 test_path="${TESTDIR}"
214 if [ "$test_files" != '' ]; then
216 for glob in $test_files; do
217 # Filter out response files (makes wildcards easier), and expand the globs
218 for file in $(find "${test_path}" -depth -path "*${glob}" -and -not -path "*${FILTER_SUFFIX}" -and '(' -type f -or -type l ')'); do
224 # Lexicographical, depth-first
225 test_files=$(find "$test_path" -depth -path '*test[0-9][0-9][0-9]*' -and -not -path "*${FILTER_SUFFIX}" -and '(' -type f -or -type l ')')
226 if [ "$test_files" == '' ]; then
227 ERROR "No test files found in $test_path"
230 INFO "Executing"$(echo "$test_files" | wc -l)" test(s) from ${test_path}"
234 # Check if we got any test files
236 if [ "$test_files" == '' ]; then
237 ERROR "No test files to process"
242 # Output which files were going to be using for testing
244 if [ $verbose -eq 0 ]; then
245 INFO "Executing specified tests"
246 INFO "Use -v to see full list"
248 INFO "Executing specified tests:"
249 for i in $test_files; do
255 # Figure out which tests we can munge into a single file which we can
256 # use to parallelise testing
259 packets=$(mktemp -t "${base}XXX") || exit 1
260 filters=$(mktemp -t "${base}XXX") || exit 1
265 for i in $test_files; do
266 if [ ! -f "$i" -a ! -L "$i" ]; then
267 INFO "Skipping $i: not file"
271 if [ ! -r "$i" ]; then
272 INFO "Skipping $i: not readable (check permissions)"
276 expected="${i}${FILTER_SUFFIX}"
277 if [ ! -f "$expected" -a ! -L "$expected" ]; then
278 DEBUG "$i cannot be parallelised: Can't find 'expected' file"
279 file_args+=" -f \"$i\""
283 if [ ! -r "$expected" ]; then
284 INFO "$i cannot be parallelised: 'expected' file not readable"
285 file_args+=" -f \"${i}:${expected}\""
289 if head -n 1 "$i" | grep -i -E '^#\s*serial' > /dev/null; then
290 DEBUG "$i marked as serial only"
291 serial_file_args+=" -f \"${i}:${expected}\""
295 # Else add it to the master test file
296 printf '%s\n' "$(cat "$i")" >> "$packets"
298 # Add the name of the file so it appears in radclient debug output
299 # and can later be specified with -v -- <test> to drill down.
300 echo "Radclient-Test-Name := \""$(echo "$i" | sed -e "s@${test_path}/\?@@")"\"" >> "$packets"
302 printf '%s\n' "$(cat "${i}_expected")" >> "$filters"
306 if [ `cat "$packets" | wc -l` -gt 0 ]; then
307 file_args+=" -f \"${packets}:${filters}\""
310 if [ ! -z "$file_args" ]; then
313 if [ $verbose -ne 0 ]; then
318 args+=" -t \"$timeout\""
319 args+=" -r \"$retries\""
320 args+=" -p \"$parallel\""
325 DEBUG "Executing: radclient $args"
326 eval radclient $args; ret=$?
327 INFO "(Parallelised tests)"
330 rm -f "$packets" 2>&1 > /dev/null
331 rm -f "$filters" 2>&1 > /dev/null
333 if [ $ret -ne 0 ]; then
334 ERROR "One or more tests failed (radclient exited with $ret)"
339 if [ ! -z "$serial_file_args" ]; then
340 args="$serial_file_args"
342 if [ $verbose -ne 0 ]; then
347 args+=" -t \"$timeout\""
348 args+=" -r \"$retries\""
354 DEBUG "Executing: radclient $args"
355 eval radclient $args; ret=$?
356 INFO "(Serialised tests)"
358 if [ $ret -ne 0 ]; then
359 ERROR "One or more tests failed (radclient exited with $ret)"