diff options
Diffstat (limited to '')
-rwxr-xr-x | scripts/raduat | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/scripts/raduat b/scripts/raduat new file mode 100755 index 0000000..9778b2a --- /dev/null +++ b/scripts/raduat @@ -0,0 +1,366 @@ +#!/bin/bash + +# Simple test wrapper around radclient to allow automated UATs +# +# Author Arran Cudbard-Bell <a.cudbardb@freeradius.org> +# Copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org> +# Copyright 2015 The FreeRADIUS Project + +# A POSIX variable +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Environmental variables +: ${TESTDIR=$(dirname $0)"/tests"} +: ${RADCLIENT='radclient'} +: ${FILTER_SUFFIX='_expected'} +: ${DICTPATH=$(dirname $0)/share} +PATH="$(dirname $0)/bin:${PATH}" + +# Initialize our own variables +verbose=0 +cluster= +role= +type= +parallel=40 +retries=3 +timeout=2 +target='127.0.0.1' +secret='testing123' + +# Some very basic logging functions +function ERROR +{ + echo "$@" 1>&2; +} + +function INFO +{ + echo "$@" +} + +function DEBUG +{ + if [ $verbose -gt 0 ]; then + echo "$@" + fi +} + +function show_help +{ + echo $(basename $0)" [options] [-- <test_glob0> <test_glob1> <test_globN>]" + echo " -h Display this help message." + echo " -H <host>[:port] Send test packets to specified host and port (defaults to 127.0.0.1)" + echo " -v Verbose mode." + echo " -p <number> Run tests in parallel (defaults to 20)." + echo " -s <secret> Shared secret." + if [ ! -z "$role_types" ]; then + echo " -c <cluster> Specify cluster type one of ($cluster_types)." + echo " -r <type> Specify server role one of ($role_types)." + echo + echo "Note: Test path globs are relative to ${TESTDIR}/<cluster>/<type>/" + fi + + echo + echo "For role based test file layout create test files under ${TESTDIR}/<cluster>/<type>" + echo "Where <cluster> and <type> are substrings found in the FQDN of <host>." + echo "For simplified test layout create test files under ${TESTDIR}" + echo + echo "The directory containing the tests should contains pairs of request files and filter files." + echo "The request file name must contain 'test<num><num><num>." + echo "The filter name must match the test name but with a '${FILTER_SUFFIX}' suffix." + echo "For example:" + echo " ${TESTDIR}/test000_my_first_test" + echo " ${TESTDIR}/test000_my_first_test${FILTER_SUFFIX}" + echo + echo "The directory containing the tests may have multiple subdirectories to group the tests." +} + +RADCLIENT=$(command -v "$RADCLIENT") +if [ ! -x "$RADCLIENT" ]; then + ERROR "Can't find radclient binary, modify your \$PATH or set RADCLIENT" + exit 64 +fi + +if [ ! -d "$TESTDIR" ]; then + ERROR "Test dir $TESTDIR does not exist, create it or specify it with TESTDIR=<dir>" + show_help + exit 64 +fi + +# Definitions (build these dynamically by looking at the files under tests) +cluster_dirs=$(find "$TESTDIR/" -mindepth 1 -maxdepth 1 -type d) +cluster_types=$(echo $cluster_dirs | sed 's/\s/ /g') + +role_types= +for i in $cluster_dirs; do + for j in $(find "$TESTDIR/$(basename $i)/" -mindepth 1 -maxdepth 1 -type d); do + role=$(basename "$j") + if [ "$role_types" == '' ]; then + role_types="$role" + else + role_types+="\n$role" + fi + done +done + +if [ -z "$role_types" ]; then + DEBUG "Using simple test file layout" +else + DEBUG "Using role based test file layout" + role_types=$(echo -e "$role_types" | sort | uniq) # Remove duplicates + role_types=$(echo $role_types | sed 's/\s/ /g') # Change \n back to spaces +fi + +while getopts "h?H:vc:r:s:p:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + + v) + verbose=1 + ;; + + c) + found=0 + for i in $cluster_types; do + if [ "$i" == "$OPTARG" ]; then + found=1 + fi + done + if [ $found -ne 1 ]; then + ERROR "'$OPTARG' is not a valid cluster type" + show_help + exit 64 + fi + cluster="$OPTARG" + ;; + + r) + found=0 + for i in $role_types; do + if [ "$i" == "$OPTARG" ]; then + found=1 + fi + done + if [ $found -ne 1 ]; then + ERROR "'$OPTARG' is not a valid role type" + show_help + exit 64 + fi + role="$OPTARG" + ;; + + s) + secret="$OPTARG" + ;; + + p) + if ! echo "$OPTARG" | grep -E '^[0-9]+$' > /dev/null; then + ERROR "Non integer argument '$OPTARG' specified for -p" + show_help + exit 64 + fi + parallel=$OPTARG + ;; + + H) + target="$OPTARG" + ;; + + esac +done + +shift $((OPTIND-1)) + +[ "$1" = "--" ] && shift +test_files=$@ + +# +# Match keywords from the hostname to clusters or roles +# +if [ ! -z "$role_types" ]; then + this_host=$(hostname -f) + for tok in $(echo "$this_host" | sed 's/\./ /g'); do + for key in ${cluster_types}; do + if echo "$tok" | grep "$key" > /dev/null && [ "$cluster" = '' ]; then cluster="$key"; fi + done + for key in ${role_types}; do + if echo "$tok" | grep "$key" > /dev/null && [ "$role" = '' ]; then role="$key"; fi + done + done + + if [ "$cluster" == '' ]; then + ERROR "Couldn't determine the cluster $this_host belongs to"; + show_help + exit 64; + fi + + if [ "$role" == '' ]; then + ERROR "Couldn't determine the role $this_host performs"; + show_help + exit 64; + fi + + test_path="${TESTDIR}/${cluster}/${role}" +# +# Otherwise just use the tests in the test dir +# +else + test_path="${TESTDIR}" +fi + +if [ "$test_files" != '' ]; then + tmp= + for glob in $test_files; do + # Filter out response files (makes wildcards easier), and expand the globs + for file in $(find "${test_path}" -depth -path "*${glob}" -and -not -path "*${FILTER_SUFFIX}" -and '(' -type f -or -type l ')'); do + tmp+="${file} " + done + done + test_files="${tmp}" +else + # Lexicographical, depth-first + 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 ')') + if [ "$test_files" == '' ]; then + ERROR "No test files found in $test_path" + exit 64; + fi + INFO "Executing"$(echo "$test_files" | wc -l)" test(s) from ${test_path}" +fi + +# +# Check if we got any test files +# +if [ "$test_files" == '' ]; then + ERROR "No test files to process" + exit 1 +fi + +# +# Output which files were going to be using for testing +# +if [ $verbose -eq 0 ]; then + INFO "Executing specified tests" + INFO "Use -v to see full list" +else + INFO "Executing specified tests:" + for i in $test_files; do + DEBUG "$i" + done +fi + +# +# Figure out which tests we can munge into a single file which we can +# use to parallelise testing +# +base=$(basename $0) +packets=$(mktemp -t "${base}XXX") || exit 1 +filters=$(mktemp -t "${base}XXX") || exit 1 + +args= +file_args= +serial_file_args= +for i in $test_files; do + if [ ! -f "$i" -a ! -L "$i" ]; then + INFO "Skipping $i: not file" + continue + fi + + if [ ! -r "$i" ]; then + INFO "Skipping $i: not readable (check permissions)" + continue + fi + + expected="${i}${FILTER_SUFFIX}" + if [ ! -f "$expected" -a ! -L "$expected" ]; then + DEBUG "$i cannot be parallelised: Can't find 'expected' file" + file_args+=" -f \"$i\"" + continue + fi + + if [ ! -r "$expected" ]; then + INFO "$i cannot be parallelised: 'expected' file not readable" + file_args+=" -f \"${i}:${expected}\"" + continue + fi + + if head -n 1 "$i" | grep -i -E '^#\s*serial' > /dev/null; then + DEBUG "$i marked as serial only" + serial_file_args+=" -f \"${i}:${expected}\"" + continue + fi + + # Else add it to the master test file + printf '%s\n' "$(cat "$i")" >> "$packets" + + # Add the name of the file so it appears in radclient debug output + # and can later be specified with -v -- <test> to drill down. + echo "Radclient-Test-Name := \""$(echo "$i" | sed -e "s@${test_path}/\?@@")"\"" >> "$packets" + echo >> "$packets" + printf '%s\n' "$(cat "${i}_expected")" >> "$filters" + echo >> "$filters" +done + +if [ `cat "$packets" | wc -l` -gt 0 ]; then + file_args+=" -f \"${packets}:${filters}\"" +fi + +if [ ! -z "$file_args" ]; then + args="$file_args" + + if [ $verbose -ne 0 ]; then + args+=" -x" + fi + + args+=" -s" + args+=" -t \"$timeout\"" + args+=" -r \"$retries\"" + args+=" -p \"$parallel\"" + args+=" -D \"$DICTPATH\"" + args+=" \"$target\"" + args+=" auto" + args+=" \"$secret\"" + + DEBUG "Executing: $RADCLIENT $args" + eval $RADCLIENT $args; ret=$? + INFO "(Parallelised tests)" + INFO "" + + rm -f "$packets" 2>&1 > /dev/null + rm -f "$filters" 2>&1 > /dev/null + + if [ $ret -ne 0 ]; then + ERROR "One or more tests failed (radclient exited with $ret)" + exit $ret + fi +fi + +if [ ! -z "$serial_file_args" ]; then + args="$serial_file_args" + + if [ $verbose -ne 0 ]; then + args+=" -x" + fi + + args+=" -s" + args+=" -t \"$timeout\"" + args+=" -r \"$retries\"" + args+=" -p 1" + args+=" -D \"$DICTPATH\"" + args+=" \"$target\"" + args+=" auto" + args+=" \"$secret\"" + + DEBUG "Executing: $RADCLIENT $args" + eval $RADCLIENT $args; ret=$? + INFO "(Serialised tests)" + + if [ $ret -ne 0 ]; then + ERROR "One or more tests failed (radclient exited with $ret)" + exit $ret + fi +fi + +exit 0 |