1*9e965d6fSRomain Jobredeaux# Copyright 2020 The Bazel Authors. All rights reserved. 2*9e965d6fSRomain Jobredeaux# 3*9e965d6fSRomain Jobredeaux# Licensed under the Apache License, Version 2.0 (the "License"); 4*9e965d6fSRomain Jobredeaux# you may not use this file except in compliance with the License. 5*9e965d6fSRomain Jobredeaux# You may obtain a copy of the License at 6*9e965d6fSRomain Jobredeaux# 7*9e965d6fSRomain Jobredeaux# http://www.apache.org/licenses/LICENSE-2.0 8*9e965d6fSRomain Jobredeaux# 9*9e965d6fSRomain Jobredeaux# Unless required by applicable law or agreed to in writing, software 10*9e965d6fSRomain Jobredeaux# distributed under the License is distributed on an "AS IS" BASIS, 11*9e965d6fSRomain Jobredeaux# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e965d6fSRomain Jobredeaux# See the License for the specific language governing permissions and 13*9e965d6fSRomain Jobredeaux# limitations under the License. 14*9e965d6fSRomain Jobredeaux 15*9e965d6fSRomain Jobredeaux# Support for unittest.bash 16*9e965d6fSRomain Jobredeaux 17*9e965d6fSRomain Jobredeaux#### Set up the test environment. 18*9e965d6fSRomain Jobredeaux 19*9e965d6fSRomain Jobredeauxset -euo pipefail 20*9e965d6fSRomain Jobredeaux 21*9e965d6fSRomain Jobredeauxcat_jvm_log () { 22*9e965d6fSRomain Jobredeaux if [[ "$log_content" =~ \ 23*9e965d6fSRomain Jobredeaux "(error code:".*", error message: '".*"', log file: '"(.*)"')" ]]; then 24*9e965d6fSRomain Jobredeaux echo >&2 25*9e965d6fSRomain Jobredeaux echo "Content of ${BASH_REMATCH[1]}:" >&2 26*9e965d6fSRomain Jobredeaux cat "${BASH_REMATCH[1]}" >&2 27*9e965d6fSRomain Jobredeaux fi 28*9e965d6fSRomain Jobredeaux} 29*9e965d6fSRomain Jobredeaux 30*9e965d6fSRomain Jobredeaux# Print message in "$1" then exit with status "$2" 31*9e965d6fSRomain Jobredeauxdie () { 32*9e965d6fSRomain Jobredeaux # second argument is optional, defaulting to 1 33*9e965d6fSRomain Jobredeaux local status_code=${2:-1} 34*9e965d6fSRomain Jobredeaux # Stop capturing stdout/stderr, and dump captured output 35*9e965d6fSRomain Jobredeaux if [[ "$CAPTURED_STD_ERR" -ne 0 || "$CAPTURED_STD_OUT" -ne 0 ]]; then 36*9e965d6fSRomain Jobredeaux restore_outputs 37*9e965d6fSRomain Jobredeaux if [[ "$CAPTURED_STD_OUT" -ne 0 ]]; then 38*9e965d6fSRomain Jobredeaux cat "${TEST_TMPDIR}/captured.out" 39*9e965d6fSRomain Jobredeaux CAPTURED_STD_OUT=0 40*9e965d6fSRomain Jobredeaux fi 41*9e965d6fSRomain Jobredeaux if [[ "$CAPTURED_STD_ERR" -ne 0 ]]; then 42*9e965d6fSRomain Jobredeaux cat "${TEST_TMPDIR}/captured.err" 1>&2 43*9e965d6fSRomain Jobredeaux cat_jvm_log "$(cat "${TEST_TMPDIR}/captured.err")" 44*9e965d6fSRomain Jobredeaux CAPTURED_STD_ERR=0 45*9e965d6fSRomain Jobredeaux fi 46*9e965d6fSRomain Jobredeaux fi 47*9e965d6fSRomain Jobredeaux 48*9e965d6fSRomain Jobredeaux if [[ -n "${1-}" ]] ; then 49*9e965d6fSRomain Jobredeaux echo "$1" 1>&2 50*9e965d6fSRomain Jobredeaux fi 51*9e965d6fSRomain Jobredeaux if [[ -n "${BASH-}" ]]; then 52*9e965d6fSRomain Jobredeaux local caller_n=0 53*9e965d6fSRomain Jobredeaux while [[ $caller_n -lt 4 ]] && \ 54*9e965d6fSRomain Jobredeaux caller_out=$(caller $caller_n 2>/dev/null); do 55*9e965d6fSRomain Jobredeaux test $caller_n -eq 0 && echo "CALLER stack (max 4):" 56*9e965d6fSRomain Jobredeaux echo " $caller_out" 57*9e965d6fSRomain Jobredeaux let caller_n=caller_n+1 58*9e965d6fSRomain Jobredeaux done 1>&2 59*9e965d6fSRomain Jobredeaux fi 60*9e965d6fSRomain Jobredeaux if [[ -n "${status_code}" && "${status_code}" -ne 0 ]]; then 61*9e965d6fSRomain Jobredeaux exit "$status_code" 62*9e965d6fSRomain Jobredeaux else 63*9e965d6fSRomain Jobredeaux exit 1 64*9e965d6fSRomain Jobredeaux fi 65*9e965d6fSRomain Jobredeaux} 66*9e965d6fSRomain Jobredeaux 67*9e965d6fSRomain Jobredeaux# Print message in "$1" then record that a non-fatal error occurred in 68*9e965d6fSRomain Jobredeaux# ERROR_COUNT 69*9e965d6fSRomain JobredeauxERROR_COUNT="${ERROR_COUNT:-0}" 70*9e965d6fSRomain Jobredeauxerror () { 71*9e965d6fSRomain Jobredeaux if [[ -n "$1" ]] ; then 72*9e965d6fSRomain Jobredeaux echo "$1" 1>&2 73*9e965d6fSRomain Jobredeaux fi 74*9e965d6fSRomain Jobredeaux ERROR_COUNT=$(($ERROR_COUNT + 1)) 75*9e965d6fSRomain Jobredeaux} 76*9e965d6fSRomain Jobredeaux 77*9e965d6fSRomain Jobredeaux# Die if "$1" != "$2", print $3 as death reason 78*9e965d6fSRomain Jobredeauxcheck_eq () { 79*9e965d6fSRomain Jobredeaux [[ "$1" = "$2" ]] || die "Check failed: '$1' == '$2' ${3:+ ($3)}" 80*9e965d6fSRomain Jobredeaux} 81*9e965d6fSRomain Jobredeaux 82*9e965d6fSRomain Jobredeaux# Die if "$1" == "$2", print $3 as death reason 83*9e965d6fSRomain Jobredeauxcheck_ne () { 84*9e965d6fSRomain Jobredeaux [[ "$1" != "$2" ]] || die "Check failed: '$1' != '$2' ${3:+ ($3)}" 85*9e965d6fSRomain Jobredeaux} 86*9e965d6fSRomain Jobredeaux 87*9e965d6fSRomain Jobredeaux# The structure of the following if statements is such that if '[[' fails 88*9e965d6fSRomain Jobredeaux# (e.g., a non-number was passed in) then the check will fail. 89*9e965d6fSRomain Jobredeaux 90*9e965d6fSRomain Jobredeaux# Die if "$1" > "$2", print $3 as death reason 91*9e965d6fSRomain Jobredeauxcheck_le () { 92*9e965d6fSRomain Jobredeaux [[ "$1" -gt "$2" ]] || die "Check failed: '$1' <= '$2' ${3:+ ($3)}" 93*9e965d6fSRomain Jobredeaux} 94*9e965d6fSRomain Jobredeaux 95*9e965d6fSRomain Jobredeaux# Die if "$1" >= "$2", print $3 as death reason 96*9e965d6fSRomain Jobredeauxcheck_lt () { 97*9e965d6fSRomain Jobredeaux [[ "$1" -lt "$2" ]] || die "Check failed: '$1' < '$2' ${3:+ ($3)}" 98*9e965d6fSRomain Jobredeaux} 99*9e965d6fSRomain Jobredeaux 100*9e965d6fSRomain Jobredeaux# Die if "$1" < "$2", print $3 as death reason 101*9e965d6fSRomain Jobredeauxcheck_ge () { 102*9e965d6fSRomain Jobredeaux [[ "$1" -ge "$2" ]] || die "Check failed: '$1' >= '$2' ${3:+ ($3)}" 103*9e965d6fSRomain Jobredeaux} 104*9e965d6fSRomain Jobredeaux 105*9e965d6fSRomain Jobredeaux# Die if "$1" <= "$2", print $3 as death reason 106*9e965d6fSRomain Jobredeauxcheck_gt () { 107*9e965d6fSRomain Jobredeaux [[ "$1" -gt "$2" ]] || die "Check failed: '$1' > '$2' ${3:+ ($3)}" 108*9e965d6fSRomain Jobredeaux} 109*9e965d6fSRomain Jobredeaux 110*9e965d6fSRomain Jobredeaux# Die if $2 !~ $1; print $3 as death reason 111*9e965d6fSRomain Jobredeauxcheck_match () 112*9e965d6fSRomain Jobredeaux{ 113*9e965d6fSRomain Jobredeaux expr match "$2" "$1" >/dev/null || \ 114*9e965d6fSRomain Jobredeaux die "Check failed: '$2' does not match regex '$1' ${3:+ ($3)}" 115*9e965d6fSRomain Jobredeaux} 116*9e965d6fSRomain Jobredeaux 117*9e965d6fSRomain Jobredeaux# Run command "$1" at exit. Like "trap" but multiple atexits don't 118*9e965d6fSRomain Jobredeaux# overwrite each other. Will break if someone does call trap 119*9e965d6fSRomain Jobredeaux# directly. So, don't do that. 120*9e965d6fSRomain JobredeauxATEXIT="${ATEXIT-}" 121*9e965d6fSRomain Jobredeauxatexit () { 122*9e965d6fSRomain Jobredeaux if [[ -z "$ATEXIT" ]]; then 123*9e965d6fSRomain Jobredeaux ATEXIT="$1" 124*9e965d6fSRomain Jobredeaux else 125*9e965d6fSRomain Jobredeaux ATEXIT="$1 ; $ATEXIT" 126*9e965d6fSRomain Jobredeaux fi 127*9e965d6fSRomain Jobredeaux trap "$ATEXIT" EXIT 128*9e965d6fSRomain Jobredeaux} 129*9e965d6fSRomain Jobredeaux 130*9e965d6fSRomain Jobredeaux## TEST_TMPDIR 131*9e965d6fSRomain Jobredeauxif [[ -z "${TEST_TMPDIR:-}" ]]; then 132*9e965d6fSRomain Jobredeaux export TEST_TMPDIR="$(mktemp -d ${TMPDIR:-/tmp}/bazel-test.XXXXXXXX)" 133*9e965d6fSRomain Jobredeauxfi 134*9e965d6fSRomain Jobredeauxif [[ ! -e "${TEST_TMPDIR}" ]]; then 135*9e965d6fSRomain Jobredeaux mkdir -p -m 0700 "${TEST_TMPDIR}" 136*9e965d6fSRomain Jobredeaux # Clean TEST_TMPDIR on exit 137*9e965d6fSRomain Jobredeaux atexit "rm -fr ${TEST_TMPDIR}" 138*9e965d6fSRomain Jobredeauxfi 139*9e965d6fSRomain Jobredeaux 140*9e965d6fSRomain Jobredeaux# Functions to compare the actual output of a test to the expected 141*9e965d6fSRomain Jobredeaux# (golden) output. 142*9e965d6fSRomain Jobredeaux# 143*9e965d6fSRomain Jobredeaux# Usage: 144*9e965d6fSRomain Jobredeaux# capture_test_stdout 145*9e965d6fSRomain Jobredeaux# ... do something ... 146*9e965d6fSRomain Jobredeaux# diff_test_stdout "$TEST_SRCDIR/path/to/golden.out" 147*9e965d6fSRomain Jobredeaux 148*9e965d6fSRomain Jobredeaux# Redirect a file descriptor to a file. 149*9e965d6fSRomain JobredeauxCAPTURED_STD_OUT="${CAPTURED_STD_OUT:-0}" 150*9e965d6fSRomain JobredeauxCAPTURED_STD_ERR="${CAPTURED_STD_ERR:-0}" 151*9e965d6fSRomain Jobredeaux 152*9e965d6fSRomain Jobredeauxcapture_test_stdout () { 153*9e965d6fSRomain Jobredeaux exec 3>&1 # Save stdout as fd 3 154*9e965d6fSRomain Jobredeaux exec 4>"${TEST_TMPDIR}/captured.out" 155*9e965d6fSRomain Jobredeaux exec 1>&4 156*9e965d6fSRomain Jobredeaux CAPTURED_STD_OUT=1 157*9e965d6fSRomain Jobredeaux} 158*9e965d6fSRomain Jobredeaux 159*9e965d6fSRomain Jobredeauxcapture_test_stderr () { 160*9e965d6fSRomain Jobredeaux exec 6>&2 # Save stderr as fd 6 161*9e965d6fSRomain Jobredeaux exec 7>"${TEST_TMPDIR}/captured.err" 162*9e965d6fSRomain Jobredeaux exec 2>&7 163*9e965d6fSRomain Jobredeaux CAPTURED_STD_ERR=1 164*9e965d6fSRomain Jobredeaux} 165*9e965d6fSRomain Jobredeaux 166*9e965d6fSRomain Jobredeaux# Force XML_OUTPUT_FILE to an existing path 167*9e965d6fSRomain Jobredeauxif [[ -z "${XML_OUTPUT_FILE:-}" ]]; then 168*9e965d6fSRomain Jobredeaux XML_OUTPUT_FILE=${TEST_TMPDIR}/output.xml 169*9e965d6fSRomain Jobredeauxfi 170*9e965d6fSRomain Jobredeaux 171*9e965d6fSRomain Jobredeaux# Functions to provide easy access to external repository outputs in the sibling 172*9e965d6fSRomain Jobredeaux# repository layout. 173*9e965d6fSRomain Jobredeaux# 174*9e965d6fSRomain Jobredeaux# Usage: 175*9e965d6fSRomain Jobredeaux# bin_dir <repository name> 176*9e965d6fSRomain Jobredeaux# genfiles_dir <repository name> 177*9e965d6fSRomain Jobredeaux# testlogs_dir <repository name> 178*9e965d6fSRomain Jobredeaux 179*9e965d6fSRomain Jobredeauxtestlogs_dir() { 180*9e965d6fSRomain Jobredeaux echo $(bazel info bazel-testlogs | sed "s|bazel-out|bazel-out/$1|") 181*9e965d6fSRomain Jobredeaux} 182