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