]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/TEST-64-UDEV-STORAGE/test.sh
man/systemd.mount: tmpfs automatically gains After=swap.target dep
[thirdparty/systemd.git] / test / TEST-64-UDEV-STORAGE / test.sh
1 #!/usr/bin/env bash
2 # SPDX-License-Identifier: LGPL-2.1-or-later
3 # vi: ts=4 sw=4 tw=0 et:
4 #
5 # TODO:
6 # * SW raid (mdadm)
7 # * MD (mdadm) -> dm-crypt -> LVM
8 # * iSCSI -> dm-crypt -> LVM
9 set -e
10
11 TEST_DESCRIPTION="systemd-udev storage tests"
12 TEST_NO_NSPAWN=1
13 # Save only journals of failing test cases by default (to conserve space)
14 TEST_SAVE_JOURNAL="${TEST_SAVE_JOURNAL:-fail}"
15
16 # shellcheck source=test/test-functions
17 . "${TEST_BASE_DIR:?}/test-functions"
18
19 USER_QEMU_OPTIONS="${QEMU_OPTIONS:-}"
20 USER_KERNEL_APPEND="${KERNEL_APPEND:-}"
21
22 _host_has_feature() {(
23 set -e
24
25 case "${1:?}" in
26 btrfs)
27 modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
28 ;;
29 iscsi)
30 # Client/initiator (Open-iSCSI)
31 command -v iscsiadm && command -v iscsid || return $?
32 # Server/target (TGT)
33 command -v tgtadm && command -v tgtd || return $?
34 ;;
35 lvm)
36 command -v lvm || return $?
37 ;;
38 mdadm)
39 command -v mdadm || return $?
40 ;;
41 multipath)
42 command -v multipath && command -v multipathd || return $?
43 ;;
44 *)
45 echo >&2 "ERROR: Unknown feature '$1'"
46 # Make this a hard error to distinguish an invalid feature from
47 # a missing feature
48 exit 1
49 esac
50 )}
51
52 test_append_files() {(
53 local feature
54 # An associative array of requested (but optional) features and their
55 # respective "handlers" from test/test-functions
56 #
57 # Note: we install cryptsetup unconditionally, hence it's not explicitly
58 # checked for here
59 local -A features=(
60 [btrfs]=install_btrfs
61 [iscsi]=install_iscsi
62 [lvm]=install_lvm
63 [mdadm]=install_mdadm
64 [multipath]=install_multipath
65 )
66
67 instmods "=block" "=md" "=nvme" "=scsi"
68 install_dmevent
69 image_install lsblk swapoff swapon wc wipefs
70
71 # Install the optional features if the host has the respective tooling
72 for feature in "${!features[@]}"; do
73 if _host_has_feature "$feature"; then
74 "${features[$feature]}"
75 fi
76 done
77
78 generate_module_dependencies
79
80 for i in {0..127}; do
81 dd if=/dev/zero of="${TESTDIR:?}/disk$i.img" bs=1M count=1
82 echo "device$i" >"${TESTDIR:?}/disk$i.img"
83 done
84 )}
85
86 _image_cleanup() {
87 mount_initdir
88 # Clean up certain "problematic" files which may be left over by failing tests
89 : >"${initdir:?}/etc/fstab"
90 : >"${initdir:?}/etc/crypttab"
91 # Clear previous assignment
92 QEMU_OPTIONS_ARRAY=()
93 }
94
95 test_run_one() {
96 local test_id="${1:?}"
97
98 if run_qemu "$test_id"; then
99 check_result_qemu || { echo "qemu test failed"; return 1; }
100 fi
101
102 return 0
103 }
104
105 test_run() {
106 local test_id="${1:?}"
107 local passed=()
108 local failed=()
109 local skipped=()
110 local ec state
111
112 mount_initdir
113
114 if get_bool "${TEST_NO_QEMU:=}" || ! find_qemu_bin; then
115 dwarn "can't run qemu, skipping"
116 return 0
117 fi
118
119 # Execute each currently defined function starting with "testcase_"
120 for testcase in "${TESTCASES[@]}"; do
121 _image_cleanup
122 echo "------ $testcase: BEGIN ------"
123 # Note for my future frustrated self: `fun && xxx` (as well as ||, if, while,
124 # until, etc.) _DISABLES_ the `set -e` behavior in _ALL_ nested function
125 # calls made from `fun()`, i.e. the function _CONTINUES_ even when a called
126 # command returned non-zero EC. That may unexpectedly hide failing commands
127 # if not handled properly. See: bash(1) man page, `set -e` section.
128 #
129 # So, be careful when adding clean up snippets in the testcase_*() functions -
130 # if the `test_run_one()` function isn't the last command, you have propagate
131 # the exit code correctly (e.g. `test_run_one() || return $?`, see below).
132 ec=0
133 "$testcase" "$test_id" || ec=$?
134 case $ec in
135 0)
136 passed+=("$testcase")
137 state="PASS"
138 ;;
139 77)
140 skipped+=("$testcase")
141 state="SKIP"
142 ;;
143 *)
144 failed+=("$testcase")
145 state="FAIL"
146 esac
147 echo "------ $testcase: END ($state) ------"
148 done
149
150 echo "Passed tests: ${#passed[@]}"
151 printf " * %s\n" "${passed[@]}"
152 echo "Skipped tests: ${#skipped[@]}"
153 printf " * %s\n" "${skipped[@]}"
154 echo "Failed tests: ${#failed[@]}"
155 printf " * %s\n" "${failed[@]}"
156
157 [[ ${#failed[@]} -eq 0 ]] || return 1
158
159 return 0
160 }
161
162 testcase_megasas2_basic() {
163 if ! "${QEMU_BIN:?}" -device help | grep 'name "megasas-gen2"'; then
164 echo "megasas-gen2 device driver is not available, skipping test..."
165 return 77
166 fi
167
168 local i
169 local qemu_opts=(
170 "-device megasas-gen2,id=scsi0"
171 "-device megasas-gen2,id=scsi1"
172 "-device megasas-gen2,id=scsi2"
173 "-device megasas-gen2,id=scsi3"
174 )
175
176 for i in {0..127}; do
177 # Add 128 drives, 32 per bus
178 qemu_opts+=(
179 "-device scsi-hd,drive=drive$i,bus=scsi$((i / 32)).0,channel=0,scsi-id=$((i % 32)),lun=0"
180 "-drive format=raw,cache=unsafe,file=${TESTDIR:?}/disk$i.img,if=none,id=drive$i"
181 )
182 done
183
184 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
185 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
186 test_run_one "${1:?}"
187 }
188
189 testcase_nvme_basic() {
190 if ! "${QEMU_BIN:?}" -device help | grep 'name "nvme"'; then
191 echo "nvme device driver is not available, skipping test..."
192 return 77
193 fi
194
195 local i
196 local qemu_opts=()
197
198 for (( i = 0; i < 5; i++ )); do
199 qemu_opts+=(
200 "-device" "nvme,drive=nvme$i,serial=deadbeef$i,num_queues=8"
201 "-drive" "format=raw,cache=unsafe,file=${TESTDIR:?}/disk$i.img,if=none,id=nvme$i"
202 )
203 done
204 for (( i = 5; i < 10; i++ )); do
205 qemu_opts+=(
206 "-device" "nvme,drive=nvme$i,serial= deadbeef $i ,num_queues=8"
207 "-drive" "format=raw,cache=unsafe,file=${TESTDIR:?}/disk$i.img,if=none,id=nvme$i"
208 )
209 done
210 for (( i = 10; i < 15; i++ )); do
211 qemu_opts+=(
212 "-device" "nvme,drive=nvme$i,serial= dead/beef/$i ,num_queues=8"
213 "-drive" "format=raw,cache=unsafe,file=${TESTDIR:?}/disk$i.img,if=none,id=nvme$i"
214 )
215 done
216 for (( i = 15; i < 20; i++ )); do
217 qemu_opts+=(
218 "-device" "nvme,drive=nvme$i,serial=dead/../../beef/$i,num_queues=8"
219 "-drive" "format=raw,cache=unsafe,file=${TESTDIR:?}/disk$i.img,if=none,id=nvme$i"
220 )
221 done
222
223 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
224 QEMU_OPTIONS="${USER_QEMU_OPTIONS}"
225 QEMU_OPTIONS_ARRAY=("${qemu_opts[@]}")
226 test_run_one "${1:?}"
227 }
228
229 # Testcase for:
230 # * https://github.com/systemd/systemd/pull/24748
231 # * https://github.com/systemd/systemd/pull/24766
232 # * https://github.com/systemd/systemd/pull/24946
233 # Docs: https://qemu.readthedocs.io/en/latest/system/devices/nvme.html#nvm-subsystems
234 testcase_nvme_subsystem() {
235 if ! "${QEMU_BIN:?}" -device help | grep 'name "nvme-subsys"'; then
236 echo "nvme-subsystem device driver is not available, skipping test..."
237 return 77
238 fi
239
240 local i
241 local qemu_opts=(
242 # Create an NVM Subsystem Device
243 "-device nvme-subsys,id=nvme-subsys-64,nqn=subsys64"
244 # Attach two NVM controllers to it
245 "-device nvme,subsys=nvme-subsys-64,serial=deadbeef"
246 "-device nvme,subsys=nvme-subsys-64,serial=deadbeef"
247 # And create two shared namespaces attached to both controllers
248 "-device nvme-ns,drive=nvme0,nsid=16,shared=on"
249 "-drive format=raw,cache=unsafe,file=${TESTDIR:?}/disk0.img,if=none,id=nvme0"
250 "-device nvme-ns,drive=nvme1,nsid=17,shared=on"
251 "-drive format=raw,cache=unsafe,file=${TESTDIR:?}/disk1.img,if=none,id=nvme1"
252 )
253
254 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
255 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
256 test_run_one "${1:?}"
257 }
258
259 # Test for issue https://github.com/systemd/systemd/issues/20212
260 testcase_virtio_scsi_identically_named_partitions() {
261
262 if ! "${QEMU_BIN:?}" -device help | grep 'name "virtio-scsi-pci"'; then
263 echo "virtio-scsi-pci device driver is not available, skipping test..."
264 return 77
265 fi
266
267 # Create 16 disks, with 8 partitions per disk (all identically named)
268 # and attach them to a virtio-scsi controller
269 local qemu_opts=("-device virtio-scsi-pci,id=scsi0,num_queues=4")
270 local diskpath="${TESTDIR:?}/namedpart0.img"
271 local i lodev num_disk num_part qemu_timeout
272
273 if get_bool "${IS_BUILT_WITH_ASAN:=}" || ! get_bool "$QEMU_KVM"; then
274 num_disk=4
275 num_part=4
276 else
277 num_disk=16
278 num_part=8
279 fi
280
281 dd if=/dev/zero of="$diskpath" bs=1M count=18
282 lodev="$(losetup --show -f -P "$diskpath")"
283 sfdisk "${lodev:?}" <<EOF
284 label: gpt
285
286 $(for ((i = 1; i <= num_part; i++)); do echo 'name="Hello world", size=2M'; done)
287 EOF
288 losetup -d "$lodev"
289
290 for ((i = 0; i < num_disk; i++)); do
291 diskpath="${TESTDIR:?}/namedpart$i.img"
292 if [[ $i -gt 0 ]]; then
293 cp -uv "${TESTDIR:?}/namedpart0.img" "$diskpath"
294 fi
295
296 qemu_opts+=(
297 "-device scsi-hd,drive=drive$i,bus=scsi0.0,channel=0,scsi-id=0,lun=$i"
298 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
299 )
300 done
301
302 # Bump the timeout when collecting test coverage, since the test is a bit
303 # slower in that case
304 if get_bool "${IS_BUILT_WITH_ASAN:=}" || ! get_bool "$QEMU_KVM"; then
305 qemu_timeout=240
306 elif is_built_with_coverage; then
307 qemu_timeout=120
308 else
309 qemu_timeout=60
310 fi
311
312 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
313 # Limit the number of VCPUs and set a timeout to make sure we trigger the issue
314 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
315 QEMU_SMP=1 QEMU_TIMEOUT=$qemu_timeout test_run_one "${1:?}" || return $?
316
317 rm -f "${TESTDIR:?}"/namedpart*.img
318 }
319
320 testcase_multipath_basic_failover() {
321 if ! _host_has_feature "multipath"; then
322 echo "Missing multipath tools, skipping the test..."
323 return 77
324 fi
325
326 local qemu_opts=("-device virtio-scsi-pci,id=scsi")
327 local partdisk="${TESTDIR:?}/multipathpartitioned.img"
328 local image lodev nback ndisk wwn
329
330 dd if=/dev/zero of="$partdisk" bs=1M count=16
331 lodev="$(losetup --show -f -P "$partdisk")"
332 sfdisk "${lodev:?}" <<EOF
333 label: gpt
334
335 name="first_partition", size=5M
336 uuid="deadbeef-dead-dead-beef-000000000000", name="failover_part", size=5M
337 EOF
338 udevadm settle
339 mkfs.ext4 -U "deadbeef-dead-dead-beef-111111111111" -L "failover_vol" "${lodev}p2"
340 losetup -d "$lodev"
341
342 # Add 16 multipath devices, each backed by 4 paths
343 for ndisk in {0..15}; do
344 wwn="0xDEADDEADBEEF$(printf "%.4d" "$ndisk")"
345 # Use a partitioned disk for the first device to test failover
346 [[ $ndisk -eq 0 ]] && image="$partdisk" || image="${TESTDIR:?}/disk$ndisk.img"
347
348 for nback in {0..3}; do
349 qemu_opts+=(
350 "-device scsi-hd,drive=drive${ndisk}x${nback},serial=MPIO$ndisk,wwn=$wwn"
351 "-drive format=raw,cache=unsafe,file=$image,file.locking=off,if=none,id=drive${ndisk}x${nback}"
352 )
353 done
354 done
355
356 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
357 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
358 test_run_one "${1:?}" || return $?
359
360 rm -f "$partdisk"
361 }
362
363 # Test case for issue https://github.com/systemd/systemd/issues/19946
364 testcase_simultaneous_events() {
365 local qemu_opts=("-device virtio-scsi-pci,id=scsi")
366 local diskpath i
367
368 for i in {0..9}; do
369 diskpath="${TESTDIR:?}/simultaneousevents${i}.img"
370
371 dd if=/dev/zero of="$diskpath" bs=1M count=128
372 qemu_opts+=(
373 "-device scsi-hd,drive=drive$i,serial=deadbeeftest$i"
374 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
375 )
376 done
377
378 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
379 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
380 test_run_one "${1:?}" || return $?
381
382 rm -f "$diskpath"
383 }
384
385 testcase_lvm_basic() {
386 if ! _host_has_feature "lvm"; then
387 echo "Missing lvm tools, skipping the test..."
388 return 77
389 fi
390
391 local qemu_opts=("-device ahci,id=ahci0")
392 local diskpath i
393
394 # Attach 4 SATA disks to the VM (and set their model and serial fields
395 # to something predictable, so we can refer to them later)
396 for i in {0..3}; do
397 diskpath="${TESTDIR:?}/lvmbasic${i}.img"
398 dd if=/dev/zero of="$diskpath" bs=1M count=32
399 qemu_opts+=(
400 "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeeflvm$i"
401 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
402 )
403 done
404
405 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
406 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
407 test_run_one "${1:?}" || return $?
408
409 rm -f "${TESTDIR:?}"/lvmbasic*.img
410 }
411
412 testcase_btrfs_basic() {
413 if ! _host_has_feature "btrfs"; then
414 echo "Missing btrfs tools/modules, skipping the test..."
415 return 77
416 fi
417
418 local qemu_opts=("-device ahci,id=ahci0")
419 local diskpath i size
420
421 for i in {0..3}; do
422 diskpath="${TESTDIR:?}/btrfsbasic${i}.img"
423 # Make the first disk larger for multi-partition tests
424 [[ $i -eq 0 ]] && size=350 || size=128
425
426 dd if=/dev/zero of="$diskpath" bs=1M count="$size"
427 qemu_opts+=(
428 "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefbtrfs$i"
429 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
430 )
431 done
432
433 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
434 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
435 test_run_one "${1:?}" || return $?
436
437 rm -f "${TESTDIR:?}"/btrfsbasic*.img
438 }
439
440 testcase_iscsi_lvm() {
441 if ! _host_has_feature "iscsi" || ! _host_has_feature "lvm"; then
442 echo "Missing iSCSI client/server tools (Open-iSCSI/TGT) or LVM utilities, skipping the test..."
443 return 77
444 fi
445
446 local qemu_opts=("-device ahci,id=ahci0")
447 local diskpath i size
448
449 for i in {0..3}; do
450 diskpath="${TESTDIR:?}/iscsibasic${i}.img"
451 # Make the first disk larger for multi-partition tests
452 [[ $i -eq 0 ]] && size=150 || size=64
453 # Make the first disk larger for multi-partition tests
454
455 dd if=/dev/zero of="$diskpath" bs=1M count="$size"
456 qemu_opts+=(
457 "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefiscsi$i"
458 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
459 )
460 done
461
462 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
463 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
464 test_run_one "${1:?}" || return $?
465
466 rm -f "${TESTDIR:?}"/iscsibasic*.img
467 }
468
469 testcase_long_sysfs_path() {
470 local brid
471 local testdisk="${TESTDIR:?}/longsysfspath.img"
472 local qemu_opts=(
473 "-drive if=none,id=drive0,format=raw,cache=unsafe,file=$testdisk"
474 "-device pci-bridge,id=pci_bridge0,chassis_nr=64"
475 )
476
477 dd if=/dev/zero of="$testdisk" bs=1M count=64
478 lodev="$(losetup --show -f -P "$testdisk")"
479 sfdisk "${lodev:?}" <<EOF
480 label: gpt
481
482 name="test_swap", size=32M
483 uuid="deadbeef-dead-dead-beef-000000000000", name="test_part", size=5M
484 EOF
485 udevadm settle
486 mkswap -U "deadbeef-dead-dead-beef-111111111111" -L "swap_vol" "${lodev}p1"
487 mkfs.ext4 -U "deadbeef-dead-dead-beef-222222222222" -L "data_vol" "${lodev}p2"
488 losetup -d "$lodev"
489
490 # Create 25 additional PCI bridges, each one connected to the previous one
491 # (basically a really long extension cable), and attach a virtio drive to
492 # the last one. This should force udev into attempting to create a device
493 # unit with a _really_ long name.
494 for brid in {1..25}; do
495 qemu_opts+=("-device pci-bridge,id=pci_bridge$brid,bus=pci_bridge$((brid-1)),chassis_nr=$((64+brid))")
496 done
497
498 qemu_opts+=("-device virtio-blk-pci,drive=drive0,scsi=off,bus=pci_bridge$brid")
499
500 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
501 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
502 test_run_one "${1:?}" || return $?
503
504 rm -f "${testdisk:?}"
505 }
506
507 testcase_mdadm_basic() {
508 if ! _host_has_feature "mdadm"; then
509 echo "Missing mdadm tools/modules, skipping the test..."
510 return 77
511 fi
512
513 local qemu_opts=("-device ahci,id=ahci0")
514 local diskpath i size
515
516 for i in {0..4}; do
517 diskpath="${TESTDIR:?}/mdadmbasic${i}.img"
518
519 dd if=/dev/zero of="$diskpath" bs=1M count=64
520 qemu_opts+=(
521 "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefmdadm$i"
522 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
523 )
524 done
525
526 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
527 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
528 test_run_one "${1:?}" || return $?
529
530 rm -f "${TESTDIR:?}"/mdadmbasic*.img
531 }
532
533 testcase_mdadm_lvm() {
534 if ! _host_has_feature "mdadm" || ! _host_has_feature "lvm"; then
535 echo "Missing mdadm tools/modules or LVM tools, skipping the test..."
536 return 77
537 fi
538
539 local qemu_opts=("-device ahci,id=ahci0")
540 local diskpath i size
541
542 for i in {0..4}; do
543 diskpath="${TESTDIR:?}/mdadmlvm${i}.img"
544
545 dd if=/dev/zero of="$diskpath" bs=1M count=64
546 qemu_opts+=(
547 "-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefmdadmlvm$i"
548 "-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
549 )
550 done
551
552 KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
553 QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
554 test_run_one "${1:?}" || return $?
555
556 rm -f "${TESTDIR:?}"/mdadmlvm*.img
557 }
558 # Allow overriding which tests should be run from the "outside", useful for manual
559 # testing (make -C test/... TESTCASES="testcase1 testcase2")
560 if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then
561 read -ra TESTCASES <<< "$TESTCASES"
562 else
563 # This must run after all functions were defined, otherwise `declare -F` won't
564 # see them
565 mapfile -t TESTCASES < <(declare -F | awk '$3 ~ /^testcase_/ {print $3;}')
566 fi
567
568 do_test "$@"