...

Text file src/edge-infra.dev/third_party/sh/shell2junit/sh2ju.sh

Documentation: edge-infra.dev/third_party/sh/shell2junit

     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###             -output="Path"   : path to output directory, defaults to "./results"
    22###     - Junit reports are left in the folder 'result' under the directory where the script is executed.
    23###     - Configure Jenkins to parse junit files from the generated folder
    24###
    25
    26asserts=00; errors=0; total=0; content=""
    27date="$(which gdate 2>/dev/null || which date)"
    28
    29# default output folder
    30juDIR="$(pwd)/results"
    31
    32# The name of the suite is calculated based in your script name
    33suite=""
    34
    35if LANG=C sed --help 2>&1 | grep -q GNU; then
    36  SED="sed"
    37elif which gsed &>/dev/null; then
    38  SED="gsed"
    39else
    40  echo "Failed to find GNU sed as sed or gsed. If you are on Mac: brew install gnu-sed." >&2
    41  exit 1
    42fi
    43
    44# A wrapper for the eval method witch allows catching seg-faults and use tee
    45errfile=/tmp/evErr.$$.log
    46function eVal() {
    47  (eval "$1")
    48  # stdout and stderr may currently be inverted (see below) so echo may write to stderr
    49  echo "$?" 2>&1 | tr -d "\n" > "${errfile}"
    50}
    51
    52# Method to clean old tests
    53function juLogClean() {
    54  echo "+++ Removing old junit reports from: ${juDIR} "
    55  rm -f "${juDIR}"/junit-*
    56}
    57
    58# Execute a command and record its results
    59function juLog() {
    60  tmpdir=${TEST_TMPDIR:-"/var/tmp"}
    61  suite="";
    62  errfile=$tmpdir/evErr.$$.log
    63  date="$(which gdate 2>/dev/null || which date)"
    64  asserts=00; errors=0; total=0; content=""
    65
    66  # parse arguments
    67  ya=""; icase=""
    68  while [[ -z "$ya" ]]; do
    69    case "$1" in
    70      -name=*)   name="$(echo "$1" | ${SED} -e 's/-name=//')";   shift;;
    71      -class=*)  class="$(echo "$1" | ${SED} -e 's/-class=//')";   shift;;
    72      -ierror=*) ereg="$(echo "$1" | ${SED} -e 's/-ierror=//')"; icase="-i"; shift;;
    73      -error=*)  ereg="$(echo "$1" | ${SED} -e 's/-error=//')";  shift;;
    74      -output=*) juDIR="$(echo "$1" | ${SED} -e 's/-output=//')";  shift;;
    75      *)         ya=1;;
    76    esac
    77  done
    78
    79  # create output directory
    80  mkdir -p "${juDIR}" || exit
    81  # use first arg as name if it was not given
    82  if [[ -z "${name}" ]]; then
    83    name="${asserts}-$1"
    84    shift
    85  fi
    86
    87  if [[ "${class}" = "" ]]; then
    88    class="default"
    89  fi
    90
    91  suite=${class}
    92
    93  # calculate command to eval
    94  [[ -z "$1" ]] && return
    95  cmd="$1"; shift
    96  while [[ -n "${1:-}" ]]
    97  do
    98     cmd="${cmd} \"$1\""
    99     shift
   100  done
   101
   102  # eval the command sending output to a file
   103  outf=$tmpdir/ju$$.txt
   104  errf=$tmpdir/ju$$-err.txt
   105  :>${outf}
   106  echo ""                         | tee -a ${outf}
   107  echo "+++ Running case: ${class}.${name} " | tee -a ${outf}
   108  echo "+++ working dir: $(pwd)"           | tee -a ${outf}
   109  echo "+++ command: ${cmd}"            | tee -a ${outf}
   110  ini="$(${date} +%s.%N)"
   111  # execute the command, temporarily swapping stderr and stdout so they can be tee'd to separate files,
   112  # then swapping them back again so that the streams are written correctly for the invoking process
   113  ( (eVal "${cmd}" | tee -a ${outf}) 3>&1 1>&2 2>&3 | tee ${errf}) 3>&1 1>&2 2>&3
   114  evErr="$(cat ${errfile})"
   115  rm -f ${errfile}
   116  end="$(${date} +%s.%N)"
   117  echo "+++ exit code: ${evErr}"        | tee -a ${outf}
   118
   119  # set the appropriate error, based in the exit code and the regex
   120  [[ ${evErr} != 0 ]] && err=1 || err=0
   121  out="$(${SED} -e 's/^\([^+]\)/| \1/g' "$outf")"
   122  if [ ${err} = 0 ] && [ -n "${ereg:-}" ]; then
   123      H=$(echo "${out}" | grep -E ${icase} "${ereg}")
   124      [[ -n "${H}" ]] && err=1
   125  fi
   126  [[ ${err} != 0 ]] && echo "+++ error: ${err}"         | tee -a ${outf}
   127  rm -f ${outf}
   128
   129  errMsg=$(cat ${errf})
   130  rm -f ${errf}
   131  # calculate vars
   132  asserts=$((asserts+1))
   133  errors=$((errors+err))
   134  time=$(echo "${end} ${ini}" | awk '{print $1 - $2}')
   135  total=$(echo "${total} ${time}" | awk '{print $1 + $2}')
   136
   137  # write the junit xml report
   138  ## failure tag
   139  [[ ${err} = 0 ]] && failure="" || failure="
   140      <failure type=\"ScriptError\" message=\"Script Error\"><![CDATA[${errMsg}]]></failure>
   141  "
   142  ## testcase tag
   143  content="${content}
   144    <testcase assertions=\"1\" name=\"${name}\" time=\"${time}\" classname=\"${class}\">
   145    ${failure}
   146    <system-err><![CDATA[${errMsg}]]></system-err>
   147    </testcase>
   148  "
   149  ## testsuite block
   150
   151  if [[ -e "${juDIR}/junit_${suite}.xml" ]]; then
   152    # file exists. first update the failures count
   153    failCount=$(${SED} -n "s/.*testsuite.*failures=\"\([0-9]*\)\".*/\1/p" "${juDIR}/junit_${suite}.xml")
   154    errors=$((failCount+errors))
   155    ${SED} -i "0,/failures=\"${failCount}\"/ s/failures=\"${failCount}\"/failures=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
   156    ${SED} -i "0,/errors=\"${failCount}\"/ s/errors=\"${failCount}\"/errors=\"${errors}\"/" "${juDIR}/junit_${suite}.xml"
   157
   158    # file exists. Need to append to it. If we remove the testsuite end tag, we can just add it in after.
   159    ${SED} -i "s^</testsuite>^^g" "${juDIR}/junit_${suite}.xml" ## remove testSuite so we can add it later
   160    ${SED} -i "s^</testsuites>^^g" "${juDIR}/junit_${suite}.xml"
   161    cat <<EOF >> "$juDIR/junit_$suite.xml"
   162     ${content:-}
   163    </testsuite>
   164</testsuites>
   165EOF
   166
   167  else
   168    # no file exists. Adding a new file
   169    cat <<EOF > "${juDIR}/junit_${suite}.xml"
   170<?xml version="1.0" encoding="UTF-8"?>
   171<testsuites>
   172    <testsuite failures="${errors}" assertions="${assertions:-}" name="${suite}" tests="1" errors="${errors}" time="${total}">
   173    ${content:-}
   174    </testsuite>
   175</testsuites>
   176EOF
   177  fi
   178
   179  return ${err}
   180}

View as plain text