k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/third_party/forked/shell2junit/sh2ju.sh (about) 1 #!/usr/bin/env bash 2 ### Copyright 2010 Manuel Carrasco MoƱino. (manolo at apache.org) 3 ### 4 ### Licensed under the Apache License, Version 2.0. 5 ### You may obtain a copy of it at 6 ### http://www.apache.org/licenses/LICENSE-2.0 7 8 ### 9 ### A library for shell scripts which creates reports in jUnit format. 10 ### These reports can be used in Jenkins, or any other CI. 11 ### 12 ### Usage: 13 ### - Include this file in your shell script 14 ### - Use juLog to call your command any time you want to produce a new report 15 ### Usage: juLog <options> command arguments 16 ### options: 17 ### -class="MyClass" : a class name which will be shown in the junit report 18 ### -name="TestName" : the test name which will be shown in the junit report 19 ### -error="RegExp" : a regexp which sets the test as failure when the output matches it 20 ### -ierror="RegExp" : same as -error but case insensitive 21 ### -fail="RegExp" : Any line from stderr which contains this pattern becomes part of 22 ### the failure messsage, without the text matching that pattern. 23 ### Example: -failure="^ERROR: " 24 ### Default is to use the entire stderr as failure message. 25 ### -output="Path" : path to output directory, defaults to "./results" 26 ### - Junit reports are left in the folder 'result' under the directory where the script is executed. 27 ### - Configure Jenkins to parse junit files from the generated folder 28 ### 29 30 asserts=00; errors=0; total=0; content="" 31 date="$(which gdate 2>/dev/null || which date)" 32 33 # default output folder 34 juDIR="$(pwd)/results" 35 36 # The name of the suite is calculated based in your script name 37 suite="" 38 39 if LANG=C sed --help 2>&1 | grep -q GNU; then 40 SED="sed" 41 elif which gsed &>/dev/null; then 42 SED="gsed" 43 else 44 echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2 45 exit 1 46 fi 47 48 # A wrapper for the eval method witch allows catching seg-faults and use tee 49 errfile=/tmp/evErr.$$.log 50 function eVal() { 51 (eval "$1") 52 # stdout and stderr may currently be inverted (see below) so echo may write to stderr 53 echo "$?" 2>&1 | tr -d "\n" > "${errfile}" 54 } 55 56 # Method to clean old tests 57 function juLogClean() { 58 echo "+++ Removing old junit reports from: ${juDIR} " 59 rm -f "${juDIR}"/junit-* 60 } 61 62 # Execute a command and record its results 63 function juLog() { 64 suite=""; 65 errfile=/tmp/evErr.$$.log 66 date="$(which gdate 2>/dev/null || which date)" 67 asserts=00; errors=0; total=0; content="" 68 local failureRe="" 69 70 # parse arguments 71 ya=""; icase="" 72 while [[ -z "$ya" ]]; do 73 case "$1" in 74 -name=*) name="$(echo "$1" | ${SED} -e 's/-name=//')"; shift;; 75 -class=*) class="$(echo "$1" | ${SED} -e 's/-class=//')"; shift;; 76 -ierror=*) ereg="$(echo "$1" | ${SED} -e 's/-ierror=//')"; icase="-i"; shift;; 77 -error=*) ereg="$(echo "$1" | ${SED} -e 's/-error=//')"; shift;; 78 -fail=*) failureRe="$(echo "$1" | ${SED} -e 's/-fail=//')"; shift;; 79 -output=*) juDIR="$(echo "$1" | ${SED} -e 's/-output=//')"; shift;; 80 *) ya=1;; 81 esac 82 done 83 84 # create output directory 85 mkdir -p "${juDIR}" || exit 86 # use first arg as name if it was not given 87 if [[ -z "${name}" ]]; then 88 name="${asserts}-$1" 89 shift 90 fi 91 92 if [[ "${class}" = "" ]]; then 93 class="default" 94 fi 95 96 suite=${class} 97 98 # calculate command to eval 99 [[ -z "$1" ]] && return 100 cmd="$1"; shift 101 while [[ -n "${1:-}" ]] 102 do 103 cmd="${cmd} \"$1\"" 104 shift 105 done 106 107 # eval the command sending output to a file 108 outf=/var/tmp/ju$$.txt 109 errf=/var/tmp/ju$$-err.txt 110 :>${outf} 111 echo "" | tee -a ${outf} 112 echo "+++ Running case: ${class}.${name} " | tee -a ${outf} 113 echo "+++ working dir: $(pwd)" | tee -a ${outf} 114 echo "+++ command: ${cmd}" | tee -a ${outf} 115 ini="$(${date} +%s.%N)" 116 # execute the command, temporarily swapping stderr and stdout so they can be tee'd to separate files, 117 # then swapping them back again so that the streams are written correctly for the invoking process 118 ( (eVal "${cmd}" | tee -a ${outf}) 3>&1 1>&2 2>&3 | tee ${errf}) 3>&1 1>&2 2>&3 119 evErr="$(cat ${errfile})" 120 rm -f ${errfile} 121 end="$(${date} +%s.%N)" 122 echo "+++ exit code: ${evErr}" | tee -a ${outf} 123 124 # set the appropriate error, based in the exit code and the regex 125 [[ ${evErr} -ne 0 ]] && err=1 || err=0 126 out="$(${SED} -e 's/^\([^+]\)/| \1/g' "$outf")" 127 if [ "${err}" -eq 0 ] && [ -n "${ereg:-}" ]; then 128 H=$(echo "${out}" | grep -E ${icase} "${ereg}") 129 [[ -n "${H}" ]] && err=1 130 fi 131 [[ ${err} -ne 0 ]] && echo "+++ error: ${err}" | tee -a ${outf} 132 rm -f ${outf} 133 134 errMsg=$(cat ${errf}) 135 rm -f ${errf} 136 # calculate vars 137 asserts=$((asserts+1)) 138 errors=$((errors+err)) 139 time=$(echo "${end} ${ini}" | awk '{print $1 - $2}') 140 total=$(echo "${total} ${time}" | awk '{print $1 + $2}') 141 142 # write the junit xml report 143 ## failure tag 144 local failure="" 145 if [[ ${err} -ne 0 ]]; then 146 local failureMsg 147 if [ -n "${failureRe}" ]; then 148 failureMsg="$(echo "${errMsg}" | grep -e "${failureRe}" | ${SED} -e "s;${failureRe};;")" 149 if [ -z "${failureMsg}" ]; then 150 failureMsg="see stderr for details" 151 fi 152 else 153 failureMsg="${errMsg}" 154 fi 155 failure=" 156 <failure type=\"ScriptError\"><![CDATA[ 157 ${failureMsg} 158 ]]></failure> 159 " 160 fi 161 ## testcase tag 162 content="${content} 163 <testcase assertions=\"1\" name=\"${name}\" time=\"${time}\" classname=\"${class}\"> 164 ${failure} 165 <system-err><![CDATA[${errMsg}]]></system-err> 166 </testcase> 167 " 168 ## testsuite block 169 170 if [[ -e "${juDIR}/junit_${suite}.xml" ]]; then 171 # file exists. first update the failures count 172 failCount=$(${SED} -n "s/.*testsuite.*failures=\"\([0-9]*\)\".*/\1/p" "${juDIR}/junit_${suite}.xml") 173 errors=$((failCount+errors)) 174 ${SED} -i "0,/failures=\"${failCount}\"/ s/failures=\"${failCount}\"/failures=\"${errors}\"/" "${juDIR}/junit_${suite}.xml" 175 ${SED} -i "0,/errors=\"${failCount}\"/ s/errors=\"${failCount}\"/errors=\"${errors}\"/" "${juDIR}/junit_${suite}.xml" 176 177 # file exists. Need to append to it. If we remove the testsuite end tag, we can just add it in after. 178 ${SED} -i "s^</testsuite>^^g" "${juDIR}/junit_${suite}.xml" ## remove testSuite so we can add it later 179 ${SED} -i "s^</testsuites>^^g" "${juDIR}/junit_${suite}.xml" 180 cat <<EOF >> "$juDIR/junit_$suite.xml" 181 ${content:-} 182 </testsuite> 183 </testsuites> 184 EOF 185 186 else 187 # no file exists. Adding a new file 188 cat <<EOF > "${juDIR}/junit_${suite}.xml" 189 <?xml version="1.0" encoding="UTF-8"?> 190 <testsuites> 191 <testsuite failures="${errors}" assertions="${assertions:-}" name="${suite}" tests="1" errors="${errors}" time="${total}"> 192 ${content:-} 193 </testsuite> 194 </testsuites> 195 EOF 196 fi 197 198 return "${err}" 199 }