1#!/bin/ksh 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$(cat $tmpin)" 52 log_note "output:\n$(cat $tmpout)" 53 log_note "error:\n$(cat $tmperr)" 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 69 outdiff=$(diff "$basename.out" "$tmpout") 70 if [[ $? -ne 0 ]]; then 71 output=$(cat $tmpout) 72 rm $tmpout $tmperr $tmpin 73 log_fail "Output mismatch. Expected:\n" \ 74 "$(cat $basename.out)\nBut got:\n$output\n" \ 75 "Diff:\n$outdiff" 76 fi 77 78 elif [[ -f "$basename.err" ]] && [[ $expectexit -ne 0 ]]; then 79 80 outdiff=$(diff "$basename.err" "$tmperr") 81 if [[ $? -ne 0 ]]; then 82 outputerror=$(cat $tmperr) 83 rm $tmpout $tmperr $tmpin 84 log_fail "Error mismatch. Expected:\n" \ 85 "$(cat $basename.err)\nBut got:\n$outputerror\n" \ 86 "Diff:\n$outdiff" 87 fi 88 89 elif [[ -n $expecterror ]] && [[ $expectexit -ne 0 ]]; then 90 91 grep -q "$expecterror" $tmperr 92 if [[ $? -ne 0 ]]; then 93 outputerror=$(cat $tmperr) 94 rm $tmpout $tmperr $tmpin 95 log_fail "Error mismatch. Expected to contain:\n" \ 96 "$expecterror\nBut got:\n$outputerror\n" 97 fi 98 99 elif [[ $expectexit -ne 0 ]]; then 100 # 101 # If there's no expected output, error reporting is allowed to 102 # vary, but ensure that we didn't fail silently. 103 # 104 if [[ -z "$(cat $tmperr)" ]]; then 105 rm $tmpout $tmperr $tmpin 106 log_fail "error with no stderr output" 107 fi 108 fi 109 110 # 111 # Clean up all temp files except $tmpin which is 112 # reused for the second invocation of log_program. 113 # 114 rm $tmpout $tmperr 115} 116 117# 118# Even though the command's arguments are passed correctly 119# to the log_must_program family of wrappers the majority 120# of the time, zcp scripts passed as HERE documents can 121# make things trickier (see comment within the fucntion 122# below) in the ordering of the commands arguments and how 123# they are passed. Thus, with this function we reconstruct 124# them to ensure that they are passed properly. 125# 126function log_program_construct_args 127{ 128 typeset tmpin=$1 129 shift 130 131 args="" 132 i=0 133 while getopts "nt:m:" opt; do 134 case $opt in 135 t) args=$args" -t $OPTARG"; i=$(($i + 2)) ;; 136 m) args=$args" -m $OPTARG"; i=$(($i + 2)) ;; 137 n) args=$args" -n"; i=$(($i + 1)) ;; 138 esac 139 done 140 shift $i 141 142 pool=$1 143 shift 144 145 # 146 # Catch HERE document if it exists and save it within our 147 # temp file. The reason we do this is that since the 148 # log_must_program wrapper calls zfs-program twice (once 149 # for open context and once for syncing) the HERE doc 150 # is consumed in the first invocation and the second one 151 # does not have a program to run. 152 # 153 cat > $tmpin 154 155 # 156 # If $tmpin has contents it means that we consumed a HERE 157 # doc and $1 currently holds "-" (a dash). If there is no 158 # HERE doc and $tmpin is empty, then we copy the contents 159 # of the original channel program to $tmpin. 160 # 161 [[ -s $tmpin ]] || cp $1 $tmpin 162 shift 163 164 lua_args=$@ 165 166 echo "$args $pool $tmpin $lua_args" 167} 168 169# 170# Program should complete successfully 171# when run in either context. 172# 173function log_must_program 174{ 175 typeset tmpin=$(mktemp) 176 177 program_args=$(log_program_construct_args $tmpin $@) 178 179 log_program 0 "" $tmpin "-n $program_args" 180 log_program 0 "" $tmpin "$program_args" 181 182 rm $tmpin 183} 184# 185# Program should error as expected in 186# the same way in both contexts. 187# 188function log_mustnot_checkerror_program 189{ 190 typeset expecterror=$1 191 shift 192 typeset tmpin=$(mktemp) 193 194 program_args=$(log_program_construct_args $tmpin $@) 195 196 log_program 1 "$expecterror" $tmpin "-n $program_args" 197 log_program 1 "$expecterror" $tmpin "$program_args" 198 199 rm $tmpin 200} 201 202# 203# Program should fail when run in either 204# context. 205# 206function log_mustnot_program 207{ 208 log_mustnot_checkerror_program "" $@ 209} 210 211 212# 213# Program should error as expected in 214# open context but complete successfully 215# in syncing context. 216# 217function log_mustnot_checkerror_program_open 218{ 219 typeset expecterror=$1 220 shift 221 typeset tmpin=$(mktemp) 222 223 program_args=$(log_program_construct_args $tmpin $@) 224 225 log_program 1 "$expecterror" $tmpin "-n $program_args" 226 log_program 0 "" $tmpin "$program_args" 227 228 rm $tmpin 229} 230 231# 232# Program should complete successfully 233# when run in syncing context but fail 234# when attempted to run in open context. 235# 236function log_must_program_sync 237{ 238 log_mustnot_checkerror_program_open "requires passing sync=TRUE" $@ 239} 240