github.com/containers/podman/v5@v5.1.0-rc1/test/system/helpers.t (about) 1 #!/usr/bin/env bash 2 # 3 # regression tests for helpers.bash 4 # 5 # Some of those helper functions are fragile, and we don't want to break 6 # anything if we have to mess with them. 7 # 8 9 source "$(dirname $0)"/helpers.bash 10 source "$(dirname $0)"/helpers.network.bash 11 12 die() { 13 echo "$(basename $0): $*" >&2 14 exit 1 15 } 16 17 # Iterator and return code; updated in check_result() 18 testnum=0 19 rc=0 20 21 # Possibly used by the code we're testing 22 PODMAN_TMPDIR=$(mktemp -d --tmpdir=${TMPDIR:-/tmp} podman_helper_tests.XXXXXX) 23 trap 'rm -rf $PODMAN_TMPDIR' 0 24 25 ############################################################################### 26 # BEGIN test the parse_table helper 27 28 function check_result { 29 testnum=$(expr $testnum + 1) 30 if [ "$1" = "$2" ]; then 31 # Multi-level echo flattens newlines, makes success messages readable 32 echo $(echo "ok $testnum $3 = $1") 33 else 34 echo "not ok $testnum $3" 35 echo "# expected: $2" 36 echo "# actual: $1" 37 rc=1 38 fi 39 } 40 41 # IMPORTANT NOTE: you have to do 42 # this: while ... done < <(parse_table) 43 # and not: parse_table | while read ... 44 # 45 # ...because piping to 'while' makes it a subshell, hence testnum and rc 46 # will not be updated. 47 # 48 while read x y z; do 49 check_result "$x" "a" "parse_table simple: column 1" 50 check_result "$y" "b" "parse_table simple: column 2" 51 check_result "$z" "c" "parse_table simple: column 3" 52 done < <(parse_table "a | b | c") 53 54 # More complicated example, with spaces 55 while read x y z; do 56 check_result "$x" "a b" "parse_table with spaces: column 1" 57 check_result "$y" "c d" "parse_table with spaces: column 2" 58 check_result "$z" "e f g" "parse_table with spaces: column 3" 59 done < <(parse_table "a b | c d | e f g") 60 61 # Multi-row, with spaces and with blank lines 62 table=" 63 a | b | c d e 64 d e f | g h | i j 65 " 66 declare -A expect=( 67 [0,0]="a" 68 [0,1]="b" 69 [0,2]="c d e" 70 [1,0]="d e f" 71 [1,1]="g h" 72 [1,2]="i j" 73 ) 74 row=0 75 while read x y z;do 76 check_result "$x" "${expect[$row,0]}" "parse_table multi_row[$row,0]" 77 check_result "$y" "${expect[$row,1]}" "parse_table multi_row[$row,1]" 78 check_result "$z" "${expect[$row,2]}" "parse_table multi_row[$row,2]" 79 row=$(expr $row + 1) 80 done < <(parse_table "$table") 81 82 # Backslash handling. The first element should have none, the second some 83 while read x y;do 84 check_result "$x" '[0-9]{2}' "backslash test - no backslashes" 85 check_result "$y" '[0-9]\{3\}' "backslash test - one backslash each" 86 done < <(parse_table "[0-9]{2} | [0-9]\\\{3\\\}") 87 88 # Empty strings. I wish we could convert those to real empty strings. 89 while read x y z; do 90 check_result "$x" "''" "empty string - left-hand" 91 check_result "$y" "''" "empty string - middle" 92 check_result "$z" "''" "empty string - right" 93 done < <(parse_table " | |") 94 95 # Quotes 96 while read x y z;do 97 check_result "$x" "a 'b c'" "single quotes" 98 check_result "$y" "d \"e f\" g" "double quotes" 99 check_result "$z" "h" "no quotes" 100 101 # FIXME FIXME FIXME: this is the only way I can find to get bash-like 102 # splitting of tokens. It really should be done inside parse_table 103 # but I can't find any way of doing so. If you can find a way, please 104 # update this test and any BATS tests that rely on quoting. 105 eval set "$x" 106 check_result "$1" "a" "single quotes - token split - 1" 107 check_result "$2" "b c" "single quotes - token split - 2" 108 check_result "$3" "" "single quotes - token split - 3" 109 110 eval set "$y" 111 check_result "$1" "d" "double quotes - token split - 1" 112 check_result "$2" "e f" "double quotes - token split - 2" 113 check_result "$3" "g" "double quotes - token split - 3" 114 done < <(parse_table "a 'b c' | d \"e f\" g | h") 115 116 # Split on '|' only when bracketed by spaces or at beginning/end of line 117 while read x y z;do 118 check_result "$x" "|x" "pipe in strings - pipe at start" 119 check_result "$y" "y|y1" "pipe in strings - pipe in middle" 120 check_result "$z" "z|" "pipe in strings - pipe at end" 121 done < <(parse_table "|x | y|y1 | z|") 122 123 # END test the parse_table helper 124 ############################################################################### 125 # BEGIN dprint 126 127 function dprint_test_1() { 128 dprint "$*" 129 } 130 131 # parse_table works, might as well use it 132 # 133 # <value of PODMAN_TEST_DEBUG> | <blank for no msg, - for msg> | <desc> 134 # 135 table=" 136 | | debug unset 137 dprint_test | - | substring match 138 dprint_test_1 | - | exact match 139 dprint_test_10 | | caller name mismatch 140 xxx yyy zzz | | multiple callers, no match 141 dprint_test_1 xxx yyy zzz | - | multiple callers, match at start 142 xxx dprint_test_1 yyy zzz | - | multiple callers, match in middle 143 xxx yyy zzz dprint_test_1 | - | multiple callers, match at end 144 " 145 while read var expect name; do 146 random_string=$(random_string 20) 147 PODMAN_TEST_DEBUG="$var" result=$(dprint_test_1 "$random_string" 3>&1) 148 expect_full="" 149 if [ -n "$expect" -a "$expect" != "''" ]; then 150 expect_full="# dprint_test_1() : $random_string" 151 fi 152 check_result "$result" "$expect_full" "DEBUG='$var' - $name" 153 done < <(parse_table "$table") 154 155 # END dprint 156 ############################################################################### 157 # BEGIN remove_same_dev_warning 158 159 # Test-helper function: runs remove_same_dev_warning, compares resulting 160 # value of $lines and $output to expected values given on command line 161 function check_same_dev() { 162 local testname="$1"; shift 163 local -a expect_lines=("$@") 164 local nl=" 165 " 166 167 remove_same_dev_warning 168 169 # After processing, check the expected number of lines 170 check_result "${#lines[@]}" "${#@}" "$testname: expected # of lines" 171 172 # ...and each expected line 173 local expect_output="" 174 local i=0 175 while [ $i -lt ${#expect_lines[@]} ]; do 176 check_result "${lines[$i]}" "${expect_lines[$i]}" "$testname: line $i" 177 expect_output+="${expect_lines[$i]}$nl" 178 i=$(( i + 1 )) 179 done 180 181 # ...and the possibly-multi-line $output 182 check_result "$output" "${expect_output%%$nl}" "$testname: output" 183 } 184 185 # Simplest case: nothing removed. 186 declare -a lines=("a b c" "d" "e f") 187 check_same_dev "abc" "a b c" "d" "e f" 188 189 # Confirm that the warning message is removed from the beginning 190 declare -a lines=( 191 "WARNING: The same type, major and minor should not be used for multiple devices." 192 "a" 193 "b" 194 "c" 195 ) 196 check_same_dev "warning is removed" a b c 197 198 # ...and from the middle (we do not expect to see this) 199 declare -a lines=( 200 "WARNING: The same type, major and minor should not be used for multiple devices." 201 "a" 202 "b" 203 "WARNING: The same type, major and minor should not be used for multiple devices." 204 "c" 205 ) 206 check_same_dev "multiple warnings removed" a b c 207 208 # Corner case: two lines of output, only one of which we care about 209 declare -a lines=( 210 "WARNING: The same type, major and minor should not be used for multiple devices." 211 "this is the only line we care about" 212 ) 213 check_same_dev "one-line output" "this is the only line we care about" 214 215 # Corner case: one line of output, but we expect zero. 216 declare -a lines=( 217 "WARNING: The same type, major and minor should not be used for multiple devices." 218 ) 219 check_same_dev "zero-line output" 220 221 # END remove_same_dev_warning 222 ############################################################################### 223 # BEGIN random_free_port 224 225 # Assumes that 16700 is open 226 found=$(random_free_port 16700-16700) 227 228 check_result "$found" "16700" "random_free_port" 229 230 # END random_free_port 231 ############################################################################### 232 # BEGIN ipv6_to_procfs 233 234 # Table of IPv6 short forms and their procfs equivalents. For readability, 235 # spaces separate each 16-bit word. Spaces are removed when testing. 236 table=" 237 2b06::1 | 2B06 0000 0000 0000 0000 0000 0000 0001 238 ::1 | 0000 0000 0000 0000 0000 0000 0000 0001 239 0::1 | 0000 0000 0000 0000 0000 0000 0000 0001 240 " 241 242 while read shortform expect; do 243 actual=$(ipv6_to_procfs $shortform) 244 check_result "$actual" "${expect// }" "ipv6_to_procfs $shortform" 245 done < <(parse_table "$table") 246 247 # END ipv6_to_procfs 248 ############################################################################### 249 # BEGIN subnet_in_use ... because that's complicated 250 251 # Override ip command 252 function ip() { 253 echo "default foo" 254 echo "192.168.0.0/16" 255 echo "172.17.2.3/30" 256 echo "172.128.0.0/9" 257 } 258 259 # x.y.z | result (1 = in use, 0 = not in use - opposite of exit code) 260 table=" 261 172 | 0 | 0 | 0 262 172 | 0 | 255 | 0 263 172 | 1 | 1 | 0 264 172 | 1 | 2 | 0 265 172 | 1 | 3 | 0 266 172 | 17 | 1 | 0 267 172 | 17 | 2 | 1 268 172 | 17 | 3 | 0 269 172 | 127 | 0 | 0 270 172 | 128 | 0 | 1 271 172 | 255 | 2 | 1 272 192 | 168 | 1 | 1 273 " 274 275 while read n1 n2 n3 expect; do 276 subnet_in_use $n1 $n2 $n3 277 actual=$? 278 check_result "$((1 - $actual))" "$expect" "subnet_in_use $n1.$n2.$n3" 279 done < <(parse_table "$table") 280 281 unset -f ip 282 283 # END subnet_in_use 284 ############################################################################### 285 # BEGIN check_assert 286 # 287 # This is way, way more complicated than it should be. The purpose is 288 # to generate readable error messages should any of the tests ever fail. 289 # 290 291 # Args: the last one is "" (expect to pass) or non-"" (expect that as msg). 292 # All other args are what we feed to assert() 293 function check_assert() { 294 local argv=("$@") 295 testnum=$(expr $testnum + 1) 296 297 # Final arg: "" to expect pass, anything else is expected error message 298 local expect="${argv[-1]}" 299 unset 'argv[-1]' 300 301 # Descriptive test name. If multiline, use sed to make the rest '[...]' 302 local testname="assert ${argv[*]}" 303 testname="$(sed -z -e 's/[\r\n].\+/ [...]/' <<<"$testname")" 304 305 # HERE WE GO. This is the actual test. 306 actual=$(assert "${argv[@]}" 2>&1) 307 status=$? 308 309 # Now compare actual to expect. 310 if [[ -z "$expect" ]]; then 311 # expect: pass 312 if [[ $status -eq 0 ]]; then 313 # got: pass 314 echo "ok $testnum $testname" 315 else 316 # got: fail 317 echo "not ok $testnum $testname" 318 echo "# expected success; got:" 319 local -a actual_split 320 IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true 321 if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then 322 unset 'actual_split[0]' 323 unset 'actual_split[1]' 324 unset 'actual_split[-1]' 325 actual_split=("${actual_split[@]}") 326 fi 327 for line in "${actual_split[@]}"; do 328 echo "# $line" 329 done 330 rc=1 331 fi 332 else 333 # expect: fail 334 if [[ $status -eq 0 ]]; then 335 # got: pass 336 echo "not ok $testnum $testname" 337 echo "# expected it to fail, but it passed" 338 rc=1 339 else 340 # Expected failure, got failure. But is it the desired failure? 341 342 # Split what we got into lines, and remove the top/bottom borders 343 local -a actual_split 344 IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true 345 if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then 346 unset 'actual_split[0]' 347 unset 'actual_split[1]' 348 unset 'actual_split[-1]' 349 actual_split=("${actual_split[@]}") 350 fi 351 352 # Split the expect string into lines, and remove first if empty 353 local -a expect_split 354 IFS=$'\n' read -rd '' -a expect_split <<<"$expect" || true 355 if [[ -z "${expect_split[0]}" ]]; then 356 unset 'expect_split[0]' 357 expect_split=("${expect_split[@]}") 358 fi 359 360 if [[ "${actual_split[*]}" = "${expect_split[*]}" ]]; then 361 # Yay. 362 echo "ok $testnum $testname" 363 else 364 # Nope. Mismatch between actual and expected output 365 echo "not ok $testnum $testname" 366 rc=1 367 368 # Ugh, this is complicated. Try to produce a useful err msg. 369 local n_e=${#expect_split[*]} 370 local n_a=${#actual_split[*]} 371 local n_max=${n_e} 372 if [[ $n_max -lt $n_a ]]; then 373 n_max=${n_a} 374 fi 375 printf "# %-35s | actual\n" "expect" 376 printf "# ----------------------------------- | ------\n" 377 for i in $(seq 0 $((${n_max}-1))); do 378 local e="${expect_split[$i]}" 379 local a="${actual_split[$i]}" 380 local same=' ' 381 local eq='=' 382 if [[ "$e" != "$a" ]]; then 383 same='!' 384 eq='|' 385 fi 386 printf "# %s %-35s %s %s\n" "$same" "$e" "$eq" "$a" 387 done 388 fi 389 fi 390 fi 391 } 392 393 # Positive tests 394 check_assert "a" = "a" "" 395 check_assert "abc" =~ "a" "" 396 check_assert "abc" =~ "b" "" 397 check_assert "abc" =~ "c" "" 398 check_assert "abc" =~ "a.*c" "" 399 check_assert "a" != "b" "" 400 401 # Simple Failure tests 402 check_assert "a" = "b" " 403 #| expected: = b 404 #| actual: a" 405 406 # This is the one that triggered #17509 407 expect="abcd efg 408 hijk lmnop" 409 actual="abcd efg 410 411 hijk lmnop" 412 check_assert "$actual" = "$expect" " 413 #| expected: = abcd efg 414 #| > hijk lmnop 415 #| actual: abcd efg 416 #| > '' 417 #| > hijk lmnop" 418 419 # Undesired carriage returns 420 cr=$'\r' 421 expect="this is line 1 422 this is line 2" 423 actual="this is line 1$cr 424 this is line 2$cr" 425 check_assert "$actual" = "$expect" " 426 #| expected: = this is line 1 427 #| > this is line 2 428 #| actual: \$'this is line 1\r' 429 #| > \$'this is line 2\r'" 430 431 # Anchored expressions; the 2nd and 3rd are 15 and 17 characters, not 16 432 check_assert "0123456789abcdef" =~ "^[0-9a-f]{16}\$" "" 433 check_assert "0123456789abcde" =~ "^[0-9a-f]{16}\$" " 434 #| expected: =~ \^\[0-9a-f\]\{16\}\\$ 435 #| actual: 0123456789abcde" 436 check_assert "0123456789abcdeff" =~ "^[0-9a-f]{16}\$" " 437 #| expected: =~ \^\[0-9a-f\]\{16\}\\$ 438 #| actual: 0123456789abcdeff" 439 440 # END check_assert 441 ############################################################################### 442 443 exit $rc