mirror of
https://github.com/containers/podman.git
synced 2025-05-20 08:36:23 +08:00

...by using a crude port lock-and-reserve mechanism. This is a small cherrypick from code that has been working in #23275 over dozens of CI runs. Am separating out into a small PR because it's stable, harmless to serial runs, and will simplify the eventual review of #23275. Closes: #23488 Signed-off-by: Ed Santiago <santiago@redhat.com>
447 lines
14 KiB
Bash
Executable File
447 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# regression tests for helpers.bash
|
|
#
|
|
# Some of those helper functions are fragile, and we don't want to break
|
|
# anything if we have to mess with them.
|
|
#
|
|
|
|
source "$(dirname $0)"/helpers.bash
|
|
source "$(dirname $0)"/helpers.network.bash
|
|
|
|
die() {
|
|
echo "$(basename $0): $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Iterator and return code; updated in check_result()
|
|
testnum=0
|
|
rc=0
|
|
|
|
# Possibly used by the code we're testing
|
|
PODMAN_TMPDIR=$(mktemp -d --tmpdir=${TMPDIR:-/tmp} podman_helper_tests.XXXXXX)
|
|
trap 'rm -rf $PODMAN_TMPDIR' 0
|
|
|
|
# Used by random_free_port.
|
|
PORT_LOCK_DIR=$PODMAN_TMPDIR/reserved-ports
|
|
|
|
###############################################################################
|
|
# BEGIN test the parse_table helper
|
|
|
|
function check_result {
|
|
testnum=$(expr $testnum + 1)
|
|
if [ "$1" = "$2" ]; then
|
|
# Multi-level echo flattens newlines, makes success messages readable
|
|
echo $(echo "ok $testnum $3 = $1")
|
|
else
|
|
echo "not ok $testnum $3"
|
|
echo "# expected: $2"
|
|
echo "# actual: $1"
|
|
rc=1
|
|
fi
|
|
}
|
|
|
|
# IMPORTANT NOTE: you have to do
|
|
# this: while ... done < <(parse_table)
|
|
# and not: parse_table | while read ...
|
|
#
|
|
# ...because piping to 'while' makes it a subshell, hence testnum and rc
|
|
# will not be updated.
|
|
#
|
|
while read x y z; do
|
|
check_result "$x" "a" "parse_table simple: column 1"
|
|
check_result "$y" "b" "parse_table simple: column 2"
|
|
check_result "$z" "c" "parse_table simple: column 3"
|
|
done < <(parse_table "a | b | c")
|
|
|
|
# More complicated example, with spaces
|
|
while read x y z; do
|
|
check_result "$x" "a b" "parse_table with spaces: column 1"
|
|
check_result "$y" "c d" "parse_table with spaces: column 2"
|
|
check_result "$z" "e f g" "parse_table with spaces: column 3"
|
|
done < <(parse_table "a b | c d | e f g")
|
|
|
|
# Multi-row, with spaces and with blank lines
|
|
table="
|
|
a | b | c d e
|
|
d e f | g h | i j
|
|
"
|
|
declare -A expect=(
|
|
[0,0]="a"
|
|
[0,1]="b"
|
|
[0,2]="c d e"
|
|
[1,0]="d e f"
|
|
[1,1]="g h"
|
|
[1,2]="i j"
|
|
)
|
|
row=0
|
|
while read x y z;do
|
|
check_result "$x" "${expect[$row,0]}" "parse_table multi_row[$row,0]"
|
|
check_result "$y" "${expect[$row,1]}" "parse_table multi_row[$row,1]"
|
|
check_result "$z" "${expect[$row,2]}" "parse_table multi_row[$row,2]"
|
|
row=$(expr $row + 1)
|
|
done < <(parse_table "$table")
|
|
|
|
# Backslash handling. The first element should have none, the second some
|
|
while read x y;do
|
|
check_result "$x" '[0-9]{2}' "backslash test - no backslashes"
|
|
check_result "$y" '[0-9]\{3\}' "backslash test - one backslash each"
|
|
done < <(parse_table "[0-9]{2} | [0-9]\\\{3\\\}")
|
|
|
|
# Empty strings. I wish we could convert those to real empty strings.
|
|
while read x y z; do
|
|
check_result "$x" "''" "empty string - left-hand"
|
|
check_result "$y" "''" "empty string - middle"
|
|
check_result "$z" "''" "empty string - right"
|
|
done < <(parse_table " | |")
|
|
|
|
# Quotes
|
|
while read x y z;do
|
|
check_result "$x" "a 'b c'" "single quotes"
|
|
check_result "$y" "d \"e f\" g" "double quotes"
|
|
check_result "$z" "h" "no quotes"
|
|
|
|
# FIXME FIXME FIXME: this is the only way I can find to get bash-like
|
|
# splitting of tokens. It really should be done inside parse_table
|
|
# but I can't find any way of doing so. If you can find a way, please
|
|
# update this test and any BATS tests that rely on quoting.
|
|
eval set "$x"
|
|
check_result "$1" "a" "single quotes - token split - 1"
|
|
check_result "$2" "b c" "single quotes - token split - 2"
|
|
check_result "$3" "" "single quotes - token split - 3"
|
|
|
|
eval set "$y"
|
|
check_result "$1" "d" "double quotes - token split - 1"
|
|
check_result "$2" "e f" "double quotes - token split - 2"
|
|
check_result "$3" "g" "double quotes - token split - 3"
|
|
done < <(parse_table "a 'b c' | d \"e f\" g | h")
|
|
|
|
# Split on '|' only when bracketed by spaces or at beginning/end of line
|
|
while read x y z;do
|
|
check_result "$x" "|x" "pipe in strings - pipe at start"
|
|
check_result "$y" "y|y1" "pipe in strings - pipe in middle"
|
|
check_result "$z" "z|" "pipe in strings - pipe at end"
|
|
done < <(parse_table "|x | y|y1 | z|")
|
|
|
|
# END test the parse_table helper
|
|
###############################################################################
|
|
# BEGIN dprint
|
|
|
|
function dprint_test_1() {
|
|
dprint "$*"
|
|
}
|
|
|
|
# parse_table works, might as well use it
|
|
#
|
|
# <value of PODMAN_TEST_DEBUG> | <blank for no msg, - for msg> | <desc>
|
|
#
|
|
table="
|
|
| | debug unset
|
|
dprint_test | - | substring match
|
|
dprint_test_1 | - | exact match
|
|
dprint_test_10 | | caller name mismatch
|
|
xxx yyy zzz | | multiple callers, no match
|
|
dprint_test_1 xxx yyy zzz | - | multiple callers, match at start
|
|
xxx dprint_test_1 yyy zzz | - | multiple callers, match in middle
|
|
xxx yyy zzz dprint_test_1 | - | multiple callers, match at end
|
|
"
|
|
while read var expect name; do
|
|
random_string=$(random_string 20)
|
|
PODMAN_TEST_DEBUG="$var" result=$(dprint_test_1 "$random_string" 3>&1)
|
|
expect_full=""
|
|
if [ -n "$expect" -a "$expect" != "''" ]; then
|
|
expect_full="# dprint_test_1() : $random_string"
|
|
fi
|
|
check_result "$result" "$expect_full" "DEBUG='$var' - $name"
|
|
done < <(parse_table "$table")
|
|
|
|
# END dprint
|
|
###############################################################################
|
|
# BEGIN remove_same_dev_warning
|
|
|
|
# Test-helper function: runs remove_same_dev_warning, compares resulting
|
|
# value of $lines and $output to expected values given on command line
|
|
function check_same_dev() {
|
|
local testname="$1"; shift
|
|
local -a expect_lines=("$@")
|
|
local nl="
|
|
"
|
|
|
|
remove_same_dev_warning
|
|
|
|
# After processing, check the expected number of lines
|
|
check_result "${#lines[@]}" "${#@}" "$testname: expected # of lines"
|
|
|
|
# ...and each expected line
|
|
local expect_output=""
|
|
local i=0
|
|
while [ $i -lt ${#expect_lines[@]} ]; do
|
|
check_result "${lines[$i]}" "${expect_lines[$i]}" "$testname: line $i"
|
|
expect_output+="${expect_lines[$i]}$nl"
|
|
i=$(( i + 1 ))
|
|
done
|
|
|
|
# ...and the possibly-multi-line $output
|
|
check_result "$output" "${expect_output%%$nl}" "$testname: output"
|
|
}
|
|
|
|
# Simplest case: nothing removed.
|
|
declare -a lines=("a b c" "d" "e f")
|
|
check_same_dev "abc" "a b c" "d" "e f"
|
|
|
|
# Confirm that the warning message is removed from the beginning
|
|
declare -a lines=(
|
|
"WARNING: The same type, major and minor should not be used for multiple devices."
|
|
"a"
|
|
"b"
|
|
"c"
|
|
)
|
|
check_same_dev "warning is removed" a b c
|
|
|
|
# ...and from the middle (we do not expect to see this)
|
|
declare -a lines=(
|
|
"WARNING: The same type, major and minor should not be used for multiple devices."
|
|
"a"
|
|
"b"
|
|
"WARNING: The same type, major and minor should not be used for multiple devices."
|
|
"c"
|
|
)
|
|
check_same_dev "multiple warnings removed" a b c
|
|
|
|
# Corner case: two lines of output, only one of which we care about
|
|
declare -a lines=(
|
|
"WARNING: The same type, major and minor should not be used for multiple devices."
|
|
"this is the only line we care about"
|
|
)
|
|
check_same_dev "one-line output" "this is the only line we care about"
|
|
|
|
# Corner case: one line of output, but we expect zero.
|
|
declare -a lines=(
|
|
"WARNING: The same type, major and minor should not be used for multiple devices."
|
|
)
|
|
check_same_dev "zero-line output"
|
|
|
|
# END remove_same_dev_warning
|
|
###############################################################################
|
|
# BEGIN random_free_port
|
|
|
|
# Assumes that 16700 is open
|
|
found=$(random_free_port 16700-16700)
|
|
|
|
check_result "$found" "16700" "random_free_port"
|
|
|
|
# END random_free_port
|
|
###############################################################################
|
|
# BEGIN ipv6_to_procfs
|
|
|
|
# Table of IPv6 short forms and their procfs equivalents. For readability,
|
|
# spaces separate each 16-bit word. Spaces are removed when testing.
|
|
table="
|
|
2b06::1 | 2B06 0000 0000 0000 0000 0000 0000 0001
|
|
::1 | 0000 0000 0000 0000 0000 0000 0000 0001
|
|
0::1 | 0000 0000 0000 0000 0000 0000 0000 0001
|
|
"
|
|
|
|
while read shortform expect; do
|
|
actual=$(ipv6_to_procfs $shortform)
|
|
check_result "$actual" "${expect// }" "ipv6_to_procfs $shortform"
|
|
done < <(parse_table "$table")
|
|
|
|
# END ipv6_to_procfs
|
|
###############################################################################
|
|
# BEGIN subnet_in_use ... because that's complicated
|
|
|
|
# Override ip command
|
|
function ip() {
|
|
echo "default foo"
|
|
echo "192.168.0.0/16"
|
|
echo "172.17.2.3/30"
|
|
echo "172.128.0.0/9"
|
|
}
|
|
|
|
# x.y.z | result (1 = in use, 0 = not in use - opposite of exit code)
|
|
table="
|
|
172 | 0 | 0 | 0
|
|
172 | 0 | 255 | 0
|
|
172 | 1 | 1 | 0
|
|
172 | 1 | 2 | 0
|
|
172 | 1 | 3 | 0
|
|
172 | 17 | 1 | 0
|
|
172 | 17 | 2 | 1
|
|
172 | 17 | 3 | 0
|
|
172 | 127 | 0 | 0
|
|
172 | 128 | 0 | 1
|
|
172 | 255 | 2 | 1
|
|
192 | 168 | 1 | 1
|
|
"
|
|
|
|
while read n1 n2 n3 expect; do
|
|
subnet_in_use $n1 $n2 $n3
|
|
actual=$?
|
|
check_result "$((1 - $actual))" "$expect" "subnet_in_use $n1.$n2.$n3"
|
|
done < <(parse_table "$table")
|
|
|
|
unset -f ip
|
|
|
|
# END subnet_in_use
|
|
###############################################################################
|
|
# BEGIN check_assert
|
|
#
|
|
# This is way, way more complicated than it should be. The purpose is
|
|
# to generate readable error messages should any of the tests ever fail.
|
|
#
|
|
|
|
# Args: the last one is "" (expect to pass) or non-"" (expect that as msg).
|
|
# All other args are what we feed to assert()
|
|
function check_assert() {
|
|
local argv=("$@")
|
|
testnum=$(expr $testnum + 1)
|
|
|
|
# Final arg: "" to expect pass, anything else is expected error message
|
|
local expect="${argv[-1]}"
|
|
unset 'argv[-1]'
|
|
|
|
# Descriptive test name. If multiline, use sed to make the rest '[...]'
|
|
local testname="assert ${argv[*]}"
|
|
testname="$(sed -z -e 's/[\r\n].\+/ [...]/' <<<"$testname")"
|
|
|
|
# HERE WE GO. This is the actual test.
|
|
actual=$(assert "${argv[@]}" 2>&1)
|
|
status=$?
|
|
|
|
# Now compare actual to expect.
|
|
if [[ -z "$expect" ]]; then
|
|
# expect: pass
|
|
if [[ $status -eq 0 ]]; then
|
|
# got: pass
|
|
echo "ok $testnum $testname"
|
|
else
|
|
# got: fail
|
|
echo "not ok $testnum $testname"
|
|
echo "# expected success; got:"
|
|
local -a actual_split
|
|
IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true
|
|
if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then
|
|
unset 'actual_split[0]'
|
|
unset 'actual_split[1]'
|
|
unset 'actual_split[-1]'
|
|
actual_split=("${actual_split[@]}")
|
|
fi
|
|
for line in "${actual_split[@]}"; do
|
|
echo "# $line"
|
|
done
|
|
rc=1
|
|
fi
|
|
else
|
|
# expect: fail
|
|
if [[ $status -eq 0 ]]; then
|
|
# got: pass
|
|
echo "not ok $testnum $testname"
|
|
echo "# expected it to fail, but it passed"
|
|
rc=1
|
|
else
|
|
# Expected failure, got failure. But is it the desired failure?
|
|
|
|
# Split what we got into lines, and remove the top/bottom borders
|
|
local -a actual_split
|
|
IFS=$'\n' read -rd '' -a actual_split <<<"$actual" || true
|
|
if [[ "${actual_split[0]}" =~ 'vvvvv' ]]; then
|
|
unset 'actual_split[0]'
|
|
unset 'actual_split[1]'
|
|
unset 'actual_split[-1]'
|
|
actual_split=("${actual_split[@]}")
|
|
fi
|
|
|
|
# Split the expect string into lines, and remove first if empty
|
|
local -a expect_split
|
|
IFS=$'\n' read -rd '' -a expect_split <<<"$expect" || true
|
|
if [[ -z "${expect_split[0]}" ]]; then
|
|
unset 'expect_split[0]'
|
|
expect_split=("${expect_split[@]}")
|
|
fi
|
|
|
|
if [[ "${actual_split[*]}" = "${expect_split[*]}" ]]; then
|
|
# Yay.
|
|
echo "ok $testnum $testname"
|
|
else
|
|
# Nope. Mismatch between actual and expected output
|
|
echo "not ok $testnum $testname"
|
|
rc=1
|
|
|
|
# Ugh, this is complicated. Try to produce a useful err msg.
|
|
local n_e=${#expect_split[*]}
|
|
local n_a=${#actual_split[*]}
|
|
local n_max=${n_e}
|
|
if [[ $n_max -lt $n_a ]]; then
|
|
n_max=${n_a}
|
|
fi
|
|
printf "# %-35s | actual\n" "expect"
|
|
printf "# ----------------------------------- | ------\n"
|
|
for i in $(seq 0 $((${n_max}-1))); do
|
|
local e="${expect_split[$i]}"
|
|
local a="${actual_split[$i]}"
|
|
local same=' '
|
|
local eq='='
|
|
if [[ "$e" != "$a" ]]; then
|
|
same='!'
|
|
eq='|'
|
|
fi
|
|
printf "# %s %-35s %s %s\n" "$same" "$e" "$eq" "$a"
|
|
done
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Positive tests
|
|
check_assert "a" = "a" ""
|
|
check_assert "abc" =~ "a" ""
|
|
check_assert "abc" =~ "b" ""
|
|
check_assert "abc" =~ "c" ""
|
|
check_assert "abc" =~ "a.*c" ""
|
|
check_assert "a" != "b" ""
|
|
|
|
# Simple Failure tests
|
|
check_assert "a" = "b" "
|
|
#| expected: = b
|
|
#| actual: a"
|
|
|
|
# This is the one that triggered #17509
|
|
expect="abcd efg
|
|
hijk lmnop"
|
|
actual="abcd efg
|
|
|
|
hijk lmnop"
|
|
check_assert "$actual" = "$expect" "
|
|
#| expected: = abcd efg
|
|
#| > hijk lmnop
|
|
#| actual: abcd efg
|
|
#| > ''
|
|
#| > hijk lmnop"
|
|
|
|
# Undesired carriage returns
|
|
cr=$'\r'
|
|
expect="this is line 1
|
|
this is line 2"
|
|
actual="this is line 1$cr
|
|
this is line 2$cr"
|
|
check_assert "$actual" = "$expect" "
|
|
#| expected: = this is line 1
|
|
#| > this is line 2
|
|
#| actual: \$'this is line 1\r'
|
|
#| > \$'this is line 2\r'"
|
|
|
|
# Anchored expressions; the 2nd and 3rd are 15 and 17 characters, not 16
|
|
check_assert "0123456789abcdef" =~ "^[0-9a-f]{16}\$" ""
|
|
check_assert "0123456789abcde" =~ "^[0-9a-f]{16}\$" "
|
|
#| expected: =~ \^\[0-9a-f\]\{16\}\\$
|
|
#| actual: 0123456789abcde"
|
|
check_assert "0123456789abcdeff" =~ "^[0-9a-f]{16}\$" "
|
|
#| expected: =~ \^\[0-9a-f\]\{16\}\\$
|
|
#| actual: 0123456789abcdeff"
|
|
|
|
# END check_assert
|
|
###############################################################################
|
|
|
|
exit $rc
|