File: helpers.t

package info (click to toggle)
podman 5.4.2%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 23,124 kB
  • sloc: sh: 6,119; perl: 2,710; python: 2,258; ansic: 1,556; makefile: 1,022; xml: 121; ruby: 42; awk: 12; csh: 8
file content (446 lines) | stat: -rwxr-xr-x 14,421 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#!/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