2016-06-22 23:40:23 +00:00
|
|
|
#!/bin/bash
|
2016-06-22 23:38:31 +00:00
|
|
|
### Copyright 2010 Manuel Carrasco Moñino. (manolo at apache.org)
|
|
|
|
###
|
|
|
|
### Licensed under the Apache License, Version 2.0.
|
|
|
|
### You may obtain a copy of it at
|
|
|
|
### http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
###
|
|
|
|
### A library for shell scripts which creates reports in jUnit format.
|
|
|
|
### These reports can be used in Jenkins, or any other CI.
|
|
|
|
###
|
|
|
|
### Usage:
|
|
|
|
### - Include this file in your shell script
|
|
|
|
### - Use juLog to call your command any time you want to produce a new report
|
|
|
|
### Usage: juLog <options> command arguments
|
|
|
|
### options:
|
|
|
|
### -class="MyClass" : a class name which will be shown in the junit report
|
|
|
|
### -name="TestName" : the test name which will be shown in the junit report
|
|
|
|
### -error="RegExp" : a regexp which sets the test as failure when the output matches it
|
|
|
|
### -ierror="RegExp" : same as -error but case insensitive
|
2016-06-22 23:40:23 +00:00
|
|
|
### -output="Path" : path to output directory, defaults to "./results"
|
2016-06-22 23:38:31 +00:00
|
|
|
### - Junit reports are left in the folder 'result' under the directory where the script is executed.
|
|
|
|
### - Configure Jenkins to parse junit files from the generated folder
|
|
|
|
###
|
|
|
|
|
|
|
|
asserts=00; errors=0; total=0; content=""
|
|
|
|
date=`which gdate 2>/dev/null || which date`
|
|
|
|
|
2016-06-22 23:40:23 +00:00
|
|
|
# default output folder
|
2016-06-22 23:38:31 +00:00
|
|
|
juDIR=`pwd`/results
|
|
|
|
|
|
|
|
# The name of the suite is calculated based in your script name
|
|
|
|
suite=""
|
|
|
|
|
2018-01-25 21:30:25 +00:00
|
|
|
if LANG=C sed --help 2>&1 | grep -q GNU; then
|
|
|
|
SED="sed"
|
|
|
|
elif which gsed &>/dev/null; then
|
|
|
|
SED="gsed"
|
|
|
|
else
|
|
|
|
echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2016-06-22 23:38:31 +00:00
|
|
|
# A wrapper for the eval method witch allows catching seg-faults and use tee
|
|
|
|
errfile=/tmp/evErr.$$.log
|
2016-06-22 23:40:23 +00:00
|
|
|
function eVal() {
|
|
|
|
(eval "$1")
|
2016-06-22 23:38:31 +00:00
|
|
|
# stdout and stderr may currently be inverted (see below) so echo may write to stderr
|
2018-01-26 23:11:53 +00:00
|
|
|
echo "$?" 2>&1 | tr -d "\n" > "${errfile}"
|
2016-06-22 23:38:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Method to clean old tests
|
2016-06-22 23:40:23 +00:00
|
|
|
function juLogClean() {
|
2018-01-26 22:08:25 +00:00
|
|
|
echo "+++ Removing old junit reports from: ${juDIR} "
|
|
|
|
rm -f "${juDIR}"/junit-*
|
2016-06-22 23:38:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Execute a command and record its results
|
2016-06-22 23:40:23 +00:00
|
|
|
function juLog() {
|
2016-06-22 23:38:31 +00:00
|
|
|
suite="";
|
|
|
|
errfile=/tmp/evErr.$$.log
|
2018-02-27 15:27:57 +00:00
|
|
|
date=`which gdate 2>/dev/null || which date`
|
2016-06-22 23:38:31 +00:00
|
|
|
asserts=00; errors=0; total=0; content=""
|
|
|
|
|
|
|
|
# parse arguments
|
|
|
|
ya=""; icase=""
|
2018-01-26 23:11:53 +00:00
|
|
|
while [[ -z "$ya" ]]; do
|
2016-06-22 23:38:31 +00:00
|
|
|
case "$1" in
|
2018-01-25 21:30:25 +00:00
|
|
|
-name=*) name=`echo "$1" | ${SED} -e 's/-name=//'`; shift;;
|
|
|
|
-class=*) class=`echo "$1" | ${SED} -e 's/-class=//'`; shift;;
|
|
|
|
-ierror=*) ereg=`echo "$1" | ${SED} -e 's/-ierror=//'`; icase="-i"; shift;;
|
|
|
|
-error=*) ereg=`echo "$1" | ${SED} -e 's/-error=//'`; shift;;
|
|
|
|
-output=*) juDIR=`echo "$1" | ${SED} -e 's/-output=//'`; shift;;
|
2016-06-22 23:38:31 +00:00
|
|
|
*) ya=1;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2016-06-22 23:40:23 +00:00
|
|
|
# create output directory
|
2018-01-26 22:08:25 +00:00
|
|
|
mkdir -p "${juDIR}" || exit
|
2016-06-22 23:38:31 +00:00
|
|
|
# use first arg as name if it was not given
|
2018-01-26 23:11:53 +00:00
|
|
|
if [[ -z "${name}" ]]; then
|
2018-01-26 22:08:25 +00:00
|
|
|
name="${asserts}-$1"
|
2016-06-22 23:38:31 +00:00
|
|
|
shift
|
|
|
|
fi
|
|
|
|
|
2018-01-26 22:08:25 +00:00
|
|
|
if [[ "${class}" = "" ]]; then
|
2016-06-22 23:38:31 +00:00
|
|
|
class="default"
|
|
|
|
fi
|
|
|
|
|
2018-01-26 22:08:25 +00:00
|
|
|
suite=${class}
|
2016-06-22 23:38:31 +00:00
|
|
|
|
|
|
|
# calculate command to eval
|
2018-01-26 23:11:53 +00:00
|
|
|
[[ -z "$1" ]] && return
|
2016-06-22 23:38:31 +00:00
|
|
|
cmd="$1"; shift
|
2018-01-26 23:11:53 +00:00
|
|
|
while [[ -n "${1:-}" ]]
|
2016-06-22 23:38:31 +00:00
|
|
|
do
|
2018-01-26 22:08:25 +00:00
|
|
|
cmd="${cmd} \"$1\""
|
2016-06-22 23:38:31 +00:00
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
# eval the command sending output to a file
|
|
|
|
outf=/var/tmp/ju$$.txt
|
|
|
|
errf=/var/tmp/ju$$-err.txt
|
2018-01-26 22:08:25 +00:00
|
|
|
>${outf}
|
|
|
|
echo "" | tee -a ${outf}
|
|
|
|
echo "+++ Running case: ${class}.${name} " | tee -a ${outf}
|
|
|
|
echo "+++ working dir: "`pwd` | tee -a ${outf}
|
|
|
|
echo "+++ command: ${cmd}" | tee -a ${outf}
|
|
|
|
ini=`${date} +%s.%N`
|
2016-06-22 23:38:31 +00:00
|
|
|
# execute the command, temporarily swapping stderr and stdout so they can be tee'd to separate files,
|
|
|
|
# then swapping them back again so that the streams are written correctly for the invoking process
|
2018-01-26 22:08:25 +00:00
|
|
|
( (eVal "${cmd}" | tee -a ${outf}) 3>&1 1>&2 2>&3 | tee ${errf}) 3>&1 1>&2 2>&3
|
|
|
|
evErr=`cat ${errfile}`
|
|
|
|
rm -f ${errfile}
|
|
|
|
end=`${date} +%s.%N`
|
|
|
|
echo "+++ exit code: ${evErr}" | tee -a ${outf}
|
2016-06-22 23:38:31 +00:00
|
|
|
|
|
|
|
# set the appropriate error, based in the exit code and the regex
|
2018-01-26 23:11:53 +00:00
|
|
|
[[ ${evErr} != 0 ]] && err=1 || err=0
|
2018-01-25 21:30:25 +00:00
|
|
|
out=`cat $outf | ${SED} -e 's/^\([^+]\)/| \1/g'`
|
2018-01-26 22:08:25 +00:00
|
|
|
if [ ${err} = 0 -a -n "${ereg:-}" ]; then
|
|
|
|
H=`echo "${out}" | egrep ${icase} "${ereg}"`
|
2018-01-26 23:11:53 +00:00
|
|
|
[[ -n "${H}" ]] && err=1
|
2016-06-22 23:38:31 +00:00
|
|
|
fi
|
2018-01-26 23:11:53 +00:00
|
|
|
[[ ${err} != 0 ]] && echo "+++ error: ${err}" | tee -a ${outf}
|
2018-01-26 22:08:25 +00:00
|
|
|
rm -f ${outf}
|
2016-06-22 23:38:31 +00:00
|
|
|
|
2018-01-26 22:08:25 +00:00
|
|
|
errMsg=`cat ${errf}`
|
|
|
|
rm -f ${errf}
|
2016-06-22 23:38:31 +00:00
|
|
|
# calculate vars
|
2016-06-22 23:40:23 +00:00
|
|
|
asserts=$(($asserts+1))
|
|
|
|
errors=$(($errors+$err))
|
2018-03-02 07:29:44 +00:00
|
|
|
time=`echo "${end} ${ini}" | awk '{print $1 - $2}'`
|
|
|
|
total=`echo "${total} ${time}" | awk '{print $1 + $2}'`
|
2016-06-22 23:38:31 +00:00
|
|
|
|
|
|
|
# write the junit xml report
|
|
|
|
## failure tag
|
2018-01-26 23:11:53 +00:00
|
|
|
[[ ${err} = 0 ]] && failure="" || failure="
|
2018-03-29 03:10:31 +00:00
|
|
|
<failure type=\"ScriptError\" message=\"Script Error\"><![CDATA[${errMsg}]]></failure>
|
2016-06-22 23:38:31 +00:00
|
|
|
"
|
|
|
|
## testcase tag
|
2018-01-26 22:08:25 +00:00
|
|
|
content="${content}
|
|
|
|
<testcase assertions=\"1\" name=\"${name}\" time=\"${time}\" classname=\"${class}\">
|
|
|
|
${failure}
|
2018-03-29 03:10:31 +00:00
|
|
|
<system-err><![CDATA[${errMsg}]]></system-err>
|
2016-06-22 23:38:31 +00:00
|
|
|
</testcase>
|
|
|
|
"
|
|
|
|
## testsuite block
|
|
|
|
|
2018-01-26 22:08:25 +00:00
|
|
|
if [[ -e "${juDIR}/junit_${suite}.xml" ]]; then
|
2016-06-22 23:40:23 +00:00
|
|
|
# file exists. first update the failures count
|
2018-01-26 22:08:25 +00:00
|
|
|
failCount=`${SED} -n "s/.*testsuite.*failures=\"\([0-9]*\)\".*/\1/p" "${juDIR}/junit_${suite}.xml"`
|
2016-06-22 23:40:23 +00:00
|
|
|
errors=$(($failCount+$errors))
|
2018-01-26 22:08:25 +00:00
|
|
|
${SED} -i "0,/failures=\"${failCount}\"/ s/failures=\"${failCount}\"/failures=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
|
|
|
|
${SED} -i "0,/errors=\"${failCount}\"/ s/errors=\"${failCount}\"/errors=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
|
2016-06-22 23:38:31 +00:00
|
|
|
|
|
|
|
# file exists. Need to append to it. If we remove the testsuite end tag, we can just add it in after.
|
2018-01-26 22:08:25 +00:00
|
|
|
${SED} -i "s^</testsuite>^^g" ${juDIR}/junit_${suite}.xml ## remove testSuite so we can add it later
|
|
|
|
${SED} -i "s^</testsuites>^^g" ${juDIR}/junit_${suite}.xml
|
2017-06-15 20:38:41 +00:00
|
|
|
cat <<EOF >> "$juDIR/junit_$suite.xml"
|
2018-01-26 22:08:25 +00:00
|
|
|
${content:-}
|
2016-06-22 23:38:31 +00:00
|
|
|
</testsuite>
|
2017-06-14 01:35:29 +00:00
|
|
|
</testsuites>
|
2016-06-22 23:38:31 +00:00
|
|
|
EOF
|
|
|
|
|
|
|
|
else
|
|
|
|
# no file exists. Adding a new file
|
2018-01-26 22:08:25 +00:00
|
|
|
cat <<EOF > "${juDIR}/junit_${suite}.xml"
|
2017-06-14 01:35:29 +00:00
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<testsuites>
|
2018-01-26 22:08:25 +00:00
|
|
|
<testsuite failures="${errors}" assertions="${assertions:-}" name="${suite}" tests="1" errors="${errors}" time="${total}">
|
|
|
|
${content:-}
|
2016-06-22 23:38:31 +00:00
|
|
|
</testsuite>
|
2017-06-14 01:35:29 +00:00
|
|
|
</testsuites>
|
2016-06-22 23:38:31 +00:00
|
|
|
EOF
|
|
|
|
fi
|
|
|
|
|
2018-01-26 23:11:53 +00:00
|
|
|
return ${err}
|
2016-09-16 19:22:11 +00:00
|
|
|
}
|