1# 2# This file and its contents are supplied under the terms of the 3# Common Development and Distribution License ("CDDL"), version 1.0. 4# You may only use this file in accordance with the terms of version 5# 1.0 of the CDDL. 6# 7# A full copy of the text of the CDDL should have accompanied this 8# source. A copy of the CDDL is also available via the Internet at 9# http://www.illumos.org/license/CDDL. 10# 11 12# 13# Copyright (c) 2016, 2017 by Delphix. All rights reserved. 14# 15 16. $STF_SUITE/include/libtest.shlib 17 18ZCP_ROOT=$STF_SUITE/tests/functional/channel_program 19 20# 21# Note: In case of failure (log_fail) in this function 22# we delete the file passed as <input file> so the 23# test suite doesn't leak temp files on failures. So it 24# is expected that <input file> is a temp file and not 25# an installed file. 26# 27# <exitcode> <expected error string> <input file> <zfs program args> 28# e.g. log_program 0 "" tmp.7a12V $POOL foo.zcp arg1 arg2 29function log_program 30{ 31 typeset expectexit=$1 32 shift 33 typeset expecterror=$1 34 shift 35 typeset tmpin=$1 36 shift 37 typeset cmdargs=$@ tmpout=$(mktemp) tmperr=$(mktemp) 38 39 # Expected output/error filename is the same as the .zcp name 40 typeset basename 41 if [[ $2 != "-" ]]; then 42 basename=${2%.*} 43 fi 44 45 log_note "running: zfs program $cmdargs:" 46 47 zfs program $cmdargs >$tmpout 2>$tmperr 48 typeset ret=$? 49 50 log_note $'input:\n'"$(<$tmpin)" 51 log_note $'output:\n'"$(<$tmpout)" 52 log_note $'error:\n'"$(<$tmperr)" 53 log_note "ret: $ret" 54 55 # 56 # Verify correct return value 57 # 58 if [[ $ret -ne $expectexit ]]; then 59 rm $tmpout $tmperr $tmpin 60 log_fail "return mismatch: expected $expectexit, got $ret" 61 fi 62 63 # 64 # Check the output or reported error for successful or error returns, 65 # respectively. 66 # 67 if [[ -f "$basename.out" ]] && [[ $expectexit -eq 0 ]]; then 68 if ! outdiff=$(diff "$basename.out" "$tmpout"); then 69 output=$(<$tmpout) 70 rm $tmpout $tmperr $tmpin 71 log_fail $'Output mismatch. Expected:\n' \ 72 "$(<$basename.out)"$'\nBut got:\n'"$output"$'\n' \ 73 $'Diff:\n'"$outdiff" 74 fi 75 76 elif [[ -f "$basename.err" ]] && [[ $expectexit -ne 0 ]]; then 77 if ! outdiff=$(diff "$basename.err" "$tmperr"); then 78 outputerror=$(<$tmperr) 79 rm $tmpout $tmperr $tmpin 80 log_fail $'Error mismatch. Expected:\n' \ 81 "$(<$basename.err)"$'\nBut got:\n'"$outputerror"$'\n' \ 82 $'Diff:\n'"$outdiff" 83 fi 84 85 elif [[ -n $expecterror ]] && [[ $expectexit -ne 0 ]]; then 86 if ! grep -q "$expecterror" $tmperr; then 87 outputerror=$(<$tmperr) 88 rm $tmpout $tmperr $tmpin 89 log_fail $'Error mismatch. Expected to contain:\n' \ 90 "$expecterror"$'\nBut got:\n'"$outputerror"$'\n' 91 fi 92 93 elif [[ $expectexit -ne 0 ]]; then 94 # 95 # If there's no expected output, error reporting is allowed to 96 # vary, but ensure that we didn't fail silently. 97 # 98 if [[ -z "$(<$tmperr)" ]]; then 99 rm $tmpout $tmperr $tmpin 100 log_fail "error with no stderr output" 101 fi 102 fi 103 104 # 105 # Clean up all temp files except $tmpin which is 106 # reused for the second invocation of log_program. 107 # 108 rm $tmpout $tmperr 109} 110 111# 112# Even though the command's arguments are passed correctly 113# to the log_must_program family of wrappers the majority 114# of the time, zcp scripts passed as HERE documents can 115# make things trickier (see comment within the function 116# below) in the ordering of the commands arguments and how 117# they are passed. Thus, with this function we reconstruct 118# them to ensure that they are passed properly. 119# 120function log_program_construct_args 121{ 122 typeset tmpin=$1 123 shift 124 125 args="" 126 i=0 127 while getopts "nt:m:" opt; do 128 case $opt in 129 t) args="$args -t $OPTARG"; i=$(($i + 2)) ;; 130 m) args="$args -m $OPTARG"; i=$(($i + 2)) ;; 131 n) args="$args -n"; i=$(($i + 1)) ;; 132 esac 133 done 134 shift $i 135 136 pool=$1 137 shift 138 139 infile=$1 140 shift 141 142 # 143 # Copy the contents of the original channel program to $tmpin. 144 # 145 # If $infile currently holds "-" (a dash) it means that we consume a 146 # HERE doc from stdin, otherwise $infile is a file path. 147 # 148 cat $infile > $tmpin 149 150 lua_args=$@ 151 152 echo "$args $pool $tmpin $lua_args" 153} 154 155# 156# Program should complete successfully 157# when run in either context. 158# 159function log_must_program 160{ 161 typeset tmpin=$(mktemp) 162 163 program_args=$(log_program_construct_args $tmpin $@) 164 165 log_program 0 "" $tmpin "-n $program_args" 166 log_program 0 "" $tmpin "$program_args" 167 168 rm $tmpin 169} 170# 171# Program should error as expected in 172# the same way in both contexts. 173# 174function log_mustnot_checkerror_program 175{ 176 typeset expecterror=$1 177 shift 178 typeset tmpin=$(mktemp) 179 180 program_args=$(log_program_construct_args $tmpin $@) 181 182 log_program 1 "$expecterror" $tmpin "-n $program_args" 183 log_program 1 "$expecterror" $tmpin "$program_args" 184 185 rm $tmpin 186} 187 188# 189# Program should fail when run in either 190# context. 191# 192function log_mustnot_program 193{ 194 log_mustnot_checkerror_program "" $@ 195} 196 197 198# 199# Program should error as expected in 200# open context but complete successfully 201# in syncing context. 202# 203function log_mustnot_checkerror_program_open 204{ 205 typeset expecterror=$1 206 shift 207 typeset tmpin=$(mktemp) 208 209 program_args=$(log_program_construct_args $tmpin $@) 210 211 log_program 1 "$expecterror" $tmpin "-n $program_args" 212 log_program 0 "" $tmpin "$program_args" 213 214 rm $tmpin 215} 216 217# 218# Program should complete successfully 219# when run in syncing context but fail 220# when attempted to run in open context. 221# 222function log_must_program_sync 223{ 224 log_mustnot_checkerror_program_open "requires passing sync=TRUE" $@ 225} 226