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  }