diff options
Diffstat (limited to 'test')
37 files changed, 452 insertions, 211 deletions
diff --git a/test/.gitignore b/test/.gitignore index 3573444..9412f0d 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -11,3 +11,5 @@ nstool rampstream guest-key guest-key.pub +/exeter/ +*.bats diff --git a/test/Makefile b/test/Makefile index bf63db8..6ed233a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,7 +5,11 @@ # Copyright Red Hat # Author: David Gibson <david@gibson.dropbear.id.au> +BATS = bats -j $(shell nproc) +EXETOOL = exeter/exetool/exetool WGET = wget -c +FLAKE8 = flake8 +MYPY = mypy --strict DEBIAN_IMGS = debian-8.11.0-openstack-amd64.qcow2 \ debian-10-nocloud-amd64.qcow2 \ @@ -13,7 +17,7 @@ DEBIAN_IMGS = debian-8.11.0-openstack-amd64.qcow2 \ debian-10-generic-ppc64el-20220911-1135.qcow2 \ debian-11-nocloud-amd64.qcow2 \ debian-11-generic-arm64.qcow2 \ - debian-11-generic-ppc64el.qcow2 \ + debian-11-generic-ppc64el-20250703-2162.qcow2 \ debian-sid-nocloud-amd64-daily.qcow2 \ debian-sid-nocloud-arm64-daily.qcow2 \ debian-sid-nocloud-ppc64el-daily.qcow2 @@ -50,18 +54,27 @@ UBUNTU_NEW_IMGS = xenial-server-cloudimg-powerpc-disk1.img \ jammy-server-cloudimg-s390x.img UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS) -DOWNLOAD_ASSETS = mbuto podman \ +DOWNLOAD_ASSETS = $(EXETOOL) mbuto podman \ $(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS) TESTDATA_ASSETS = small.bin big.bin medium.bin \ rampstream LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \ $(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \ $(UBUNTU_NEW_IMGS:%=prepared-%) \ - nstool guest-key guest-key.pub \ - $(TESTDATA_ASSETS) + nstool guest-key guest-key.pub $(TESTDATA_ASSETS) ASSETS = $(DOWNLOAD_ASSETS) $(LOCAL_ASSETS) +EXETER_PYPATH = exeter/py3 +EXETER_PYTHON = build/build.py +EXETER_BATS = smoke/smoke.sh.bats \ + $(EXETER_PYTHON:%=%.bats) build/static_checkers.sh.bats +BATS_FILES = $(EXETER_BATS) \ + podman/test/system/505-networking-pasta.bats + +# Python test code (for linters) +PYPKGS = $(EXETER_PYTHON) + CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 assets: $(ASSETS) @@ -70,6 +83,11 @@ assets: $(ASSETS) pull-%: % git -C $* pull +exeter: + git clone https://gitlab.com/dgibson/exeter.git + +exeter/exetool/exetool: pull-exeter + mbuto: git clone git://mbuto.sh/mbuto @@ -115,6 +133,18 @@ medium.bin: big.bin: dd if=/dev/urandom bs=1M count=10 of=$@ +flake8: pull-exeter + PYTHONPATH=$(EXETER_PYPATH) $(FLAKE8) $(PYPKGS) + +mypy: pull-exeter + PYTHONPATH=$(EXETER_PYPATH) $(MYPY) $(PYPKGS) + +$(EXETER_BATS): %.bats: % $(EXETOOL) + PYTHONPATH=$(EXETER_PYPATH) $(EXETOOL) bats -- $< > $@ + +bats: $(BATS_FILES) pull-podman + PYTHONPATH=$(EXETER_PYPATH) CONTAINERS_HELPER_BINARY_DIR=.. $(BATS) $(BATS_FILES) + check: assets ./run @@ -123,7 +153,9 @@ debug: assets clean: rm -f perf.js *~ + rm -rf .mypy_cache rm -f $(LOCAL_ASSETS) + rm -f $(EXETER_BATS) rm -rf test_logs rm -f prepared-*.qcow2 prepared-*.img @@ -132,79 +164,82 @@ realclean: clean # Debian downloads debian-8.11.0-openstack-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/OpenStack/archive/8.11.0/debian-8.11.0-openstack-$*.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/OpenStack/archive/8.11.0/debian-8.11.0-openstack-$*.qcow2 debian-10-nocloud-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-$*.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-$*.qcow2 debian-10-generic-ppc64el-20220911-1135.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/20220911-1135/debian-10-generic-ppc64el-20220911-1135.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/20220911-1135/debian-10-generic-ppc64el-20220911-1135.qcow2 debian-10-generic-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-generic-$*.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-generic-$*.qcow2 debian-11-nocloud-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-$*.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-$*.qcow2 debian-11-generic-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-$*.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-$*.qcow2 + +debian-11-generic-ppc64el-20250703-2162.qcow2: + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/20250703-2162/debian-11-generic-ppc64el-20250703-2162.qcow2 debian-sid-nocloud-%-daily.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-$*-daily.qcow2 + -$(WGET) -O $@ https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-$*-daily.qcow2 # Fedora downloads Fedora-Cloud-Base-26-1.5.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/26/CloudImages/$*/images/Fedora-Cloud-Base-26-1.5.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/26/CloudImages/$*/images/Fedora-Cloud-Base-26-1.5.$*.qcow2 Fedora-Cloud-Base-27-1.6.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/27/CloudImages/$*/images/Fedora-Cloud-Base-27-1.6.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/27/CloudImages/$*/images/Fedora-Cloud-Base-27-1.6.$*.qcow2 Fedora-Cloud-Base-28-1.1.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Cloud/$*/images/Fedora-Cloud-Base-28-1.1.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Cloud/$*/images/Fedora-Cloud-Base-28-1.1.$*.qcow2 Fedora-Cloud-Base-29-1.2.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/29/Cloud/$*/images/Fedora-Cloud-Base-29-1.2.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/29/Cloud/$*/images/Fedora-Cloud-Base-29-1.2.$*.qcow2 Fedora-Cloud-Base-30-1.2.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/Cloud/$*/images/Fedora-Cloud-Base-30-1.2.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/Cloud/$*/images/Fedora-Cloud-Base-30-1.2.$*.qcow2 Fedora-Cloud-Base-31-1.9.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/31/Cloud/$*/images/Fedora-Cloud-Base-31-1.9.$*.qcow2 + -$(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/31/Cloud/$*/images/Fedora-Cloud-Base-31-1.9.$*.qcow2 Fedora-Cloud-Base-32-1.6.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/32/Cloud/$*/images/Fedora-Cloud-Base-32-1.6.$*.qcow2 + -$(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/32/Cloud/$*/images/Fedora-Cloud-Base-32-1.6.$*.qcow2 Fedora-Cloud-Base-33-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/33/Cloud/$*/images/Fedora-Cloud-Base-33-1.2.$*.qcow2 + -$(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/33/Cloud/$*/images/Fedora-Cloud-Base-33-1.2.$*.qcow2 Fedora-Cloud-Base-34-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Cloud/$*/images/Fedora-Cloud-Base-34-1.2.$*.qcow2 + -$(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Cloud/$*/images/Fedora-Cloud-Base-34-1.2.$*.qcow2 Fedora-Cloud-Base-35-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/35/Cloud/$*/images/Fedora-Cloud-Base-35-1.2.$*.qcow2 + -$(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/35/Cloud/$*/images/Fedora-Cloud-Base-35-1.2.$*.qcow2 # OpenSuSE downloads openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.1/jeos/openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2 + -$(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.1/jeos/openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2 openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.2/appliances/openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 + -$(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.2/appliances/openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.3/appliances/openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2 + -$(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.3/appliances/openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2 openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz: - $(WGET) -O $@ http://download.opensuse.org/ports/aarch64/tumbleweed/appliances/openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz + -$(WGET) -O $@ http://download.opensuse.org/ports/aarch64/tumbleweed/appliances/openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz: - $(WGET) -O $@ http://download.opensuse.org/ports/armv7hl/tumbleweed/appliances/openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz + -$(WGET) -O $@ http://download.opensuse.org/ports/armv7hl/tumbleweed/appliances/openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz # Ubuntu downloads trusty-server-cloudimg-%-disk1.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-$*-disk1.img + -$(WGET) -O $@ https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-$*-disk1.img xenial-server-cloudimg-powerpc-disk1.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-powerpc-disk1.img + -$(WGET) -O $@ https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-powerpc-disk1.img jammy-server-cloudimg-s390x.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-s390x.img + -$(WGET) -O $@ https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-s390x.img diff --git a/test/README.md b/test/README.md index 91ca603..0df7533 100644 --- a/test/README.md +++ b/test/README.md @@ -32,7 +32,7 @@ Example for Debian, and possibly most Debian-based distributions: git go iperf3 isc-dhcp-common jq libgpgme-dev libseccomp-dev linux-cpupower lm-sensors lz4 netavark netcat-openbsd psmisc qemu-efi-aarch64 qemu-system-arm qemu-system-misc qemu-system-ppc qemu-system-x86 - qemu-system-x86 sipcalc socat strace tmux uidmap valgrind + sipcalc socat strace tmux uidmap valgrind NOTE: the tests need a qemu version >= 7.2, or one that contains commit 13c6be96618c ("net: stream: add unix socket"): this change introduces support @@ -81,7 +81,12 @@ The following additional packages are commonly needed: ## Regular test -Just issue: +Before running the tests, you need to prepare the required assets: + + cd test + make assets + +Then issue: ./run @@ -91,6 +96,32 @@ variable settings: DEBUG=1 enables debugging messages, TRACE=1 enables tracing PCAP=1 TRACE=1 ./run +**Note:** + +* Don't run the tests as root, the whole point of passt is not to run as root. + +* If you switch users before running the tests, you may hit "Permission denied" + error. It's probably due to + [Bug 967509](https://bugzilla.redhat.com/show_bug.cgi?id=967509). + If you switch users with `su` or `sudo`, the directory `/run/user/ID` may + not be created, and `XDG_RUNTIME_DIR` points to the /run/user directory of + the previous user rather than the target user. + + **Workaround:** Log out and log back in as the intended user to ensure the + correct runtime directory is set up. Or use `machinectl shell --uid=$user`. + +* SELinux may prevent the tests from running correctly. To avoid this, + temporarily disable it by running: + + setenforce 0 + +* Some tests require a QEMU version >= 10.0.0, or a build that includes the + following commits: + + 60f543ad917f ("virtio-net: vhost-user: Implement internal migration") + 3f65357313e0 ("vhost: Add stubs for the migration state transfer + interface") + ## Running selected tests Rudimentary support to run a list of selected tests, without support for diff --git a/test/build/all b/test/build/all deleted file mode 100644 index 1f79e0d..0000000 --- a/test/build/all +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/all - Build targets, one by one, then all together, check output -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio@redhat.com> - -htools make cc rm uname getconf mkdir cp rm man - -test Build passt -host make clean -check ! [ -e passt ] -host CFLAGS="-Werror" make passt -check [ -f passt ] - -test Build pasta -host make clean -check ! [ -e pasta ] -host CFLAGS="-Werror" make pasta -check [ -h pasta ] - -test Build qrap -host make clean -check ! [ -e qrap ] -host CFLAGS="-Werror" make qrap -check [ -f qrap ] - -test Build all -host make clean -check ! [ -e passt ] -check ! [ -e pasta ] -check ! [ -e qrap ] -host CFLAGS="-Werror" make -check [ -f passt ] -check [ -h pasta ] -check [ -f qrap ] - -test Install -host mkdir __STATEDIR__/prefix -host prefix=__STATEDIR__/prefix make install -check [ -f __STATEDIR__/prefix/bin/passt ] -check [ -h __STATEDIR__/prefix/bin/pasta ] -check [ -f __STATEDIR__/prefix/bin/qrap ] -check man -M __STATEDIR__/prefix/share/man -W passt -check man -M __STATEDIR__/prefix/share/man -W pasta -check man -M __STATEDIR__/prefix/share/man -W qrap - -test Uninstall -host prefix=__STATEDIR__/prefix make uninstall -check ! [ -f __STATEDIR__/prefix/bin/passt ] -check ! [ -h __STATEDIR__/prefix/bin/pasta ] -check ! [ -f __STATEDIR__/prefix/bin/qrap ] -check ! man -M __STATEDIR__/prefix/share/man -W passt 2>/dev/null -check ! man -M __STATEDIR__/prefix/share/man -W pasta 2>/dev/null -check ! man -M __STATEDIR__/prefix/share/man -W qrap 2>/dev/null diff --git a/test/build/build.py b/test/build/build.py new file mode 100755 index 0000000..e3de830 --- /dev/null +++ b/test/build/build.py @@ -0,0 +1,110 @@ +#! /usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/build/build.py - Test build and install targets +# +# Copyright Red Hat +# Author: David Gibson <david@gibson.dropbear.id.au> + +import contextlib +import os +from pathlib import Path +import subprocess +import tempfile +from typing import Iterator + +import exeter + + +def sh(cmd: str) -> None: + """Run given command in a shell""" + subprocess.run(cmd, shell=True) + + +@contextlib.contextmanager +def clone_sources() -> Iterator[str]: + """Create a temporary copy of the passt sources. + + When the context enters create a temporary directory and copy the + passt sources into it. Clean it up when the context exits. + """ + + os.chdir('..') # Move from test/ to repo base + with tempfile.TemporaryDirectory(ignore_cleanup_errors=False) as tmpdir: + sh(f"cp --parents -d $(git ls-files) {tmpdir}") + os.chdir(tmpdir) + yield tmpdir + + +def test_make(target: str, expected_files: list[str]) -> None: + """Test `make {target}` + + Arguments: + target -- make target to invoke + expected_files -- files make is expected to create + + Verifies that + 1) `make target` completes successfully + 2) expected_files care created by `make target` + 3) expected_files are removed by `make clean` + """ + + ex_paths = [Path(f) for f in expected_files] + with clone_sources(): + for p in ex_paths: + assert not p.exists(), f"{p} existed before make" + sh(f'make {target} CFLAGS="-Werror"') + for p in ex_paths: + assert p.exists(), f"{p} wasn't made" + sh('make clean') + for p in ex_paths: + assert not p.exists(), f"{p} existed after make clean" + + +exeter.register('make_passt', test_make, 'passt', ['passt']) +exeter.register('make_pasta', test_make, 'pasta', ['pasta']) +exeter.register('make_qrap', test_make, 'qrap', ['qrap']) +exeter.register('make_all', test_make, 'all', ['passt', 'pasta', 'qrap']) + + +@exeter.test +def test_install_uninstall() -> None: + """Test `make install` and `make uninstall` + + Tests that `make install` installs the expected files to the + install prefix, and that `make uninstall` removes them again. + """ + + with clone_sources(): + with tempfile.TemporaryDirectory(ignore_cleanup_errors=False) \ + as prefix: + bindir = Path(prefix) / 'bin' + mandir = Path(prefix) / 'share/man' + progs = ['passt', 'pasta', 'qrap'] + + # Install + sh(f'make install CFLAGS="-Werror" prefix={prefix}') + + for prog in progs: + exe = bindir / prog + assert exe.is_file(), f"{exe} does not exist as a regular file" + sh(f'man -M {mandir} -W {prog}') + + # Uninstall + sh(f'make uninstall prefix={prefix}') + + for prog in progs: + exe = bindir / prog + assert not exe.exists(), f"{exe} exists after uninstall" + sh(f'! man -M {mandir} -W {prog}') + + +if __name__ == '__main__': + exeter.main() diff --git a/test/build/clang_tidy b/test/build/clang_tidy deleted file mode 100644 index 40573bf..0000000 --- a/test/build/clang_tidy +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/clang_tidy - Run source through clang-tidy(1) linter -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio@redhat.com> - -htools clang-tidy - -test Run clang-tidy -host make clang-tidy diff --git a/test/build/cppcheck b/test/build/cppcheck deleted file mode 100644 index 0e1dbce..0000000 --- a/test/build/cppcheck +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/cppcheck - Run source through cppcheck(1) linter -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio@redhat.com> - -htools cppcheck - -test Run cppcheck -host make cppcheck diff --git a/test/build/static_checkers.sh b/test/build/static_checkers.sh new file mode 100755 index 0000000..96679fb --- /dev/null +++ b/test/build/static_checkers.sh @@ -0,0 +1,42 @@ +#! /bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/build/static_checkers.sh - Run static checkers +# +# Copyright Red Hat +# Author: David Gibson <david@gibson.dropbear.id.au> + +. $(dirname ${0})/../exeter/sh/exeter.sh + +# do_check() - Run static checker as a test if the binary is available +# $1: Static checker (uased as both executable name and make target) +# $@: Any additional arguments required to make +do_check() { + checker="${1}" + shift + if ! which "${checker}" >/dev/null 2>/dev/null; then + exeter_skip "${checker} not available" + fi + make "${@}" "${checker}" +} + +exeter_register cppcheck do_check cppcheck -C .. +exeter_set_description cppcheck "passt sources pass cppcheck" + +exeter_register clang_tidy do_check clang-tidy -C .. +exeter_set_description clang_tidy "passt sources pass clang-tidy" + +exeter_register flake8 do_check flake8 +exeter_set_description flake8 "passt tests in Python pass flake8" + +exeter_register mypy do_check mypy +exeter_set_description mypy "passt tests in Python pass mypy --strict" + +exeter_main "${@}" diff --git a/test/demo/podman b/test/demo/podman index edd403a..393691c 100644 --- a/test/demo/podman +++ b/test/demo/podman @@ -310,8 +310,8 @@ nl say Everything is set now, let's start sleep 2 hout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -hout ADDR4 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' -hout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' +hout ADDR4 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope != "host" and .scope != "link").local' +hout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope != "host" and .scope != "link").local' hout GW4 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' hout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/lib/exeter b/test/lib/exeter new file mode 100644 index 0000000..ccdb19c --- /dev/null +++ b/test/lib/exeter @@ -0,0 +1,66 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/exeter - Run exeter tests within the rest of passt's tests +# +# Copyright Red Hat +# Author: David Gibson <david@gibson.dropbear.id.au> + +EXETOOL="${BASEPATH}/exeter/exetool/exetool" + +# is_exeter() - Determine if a test file is an exeter program +# $@: Command line to invoke test program +is_exeter() { + ${EXETOOL} probe -- "${@}" +} + +# exeter() - Run each test in an exeter program, logging each test separately +# $@: Command line to invoke exeter test program +exeter() { + STATESETUP="${STATEBASE}/${1}" + mkdir -p "${STATESETUP}" + + context_setup_host host + layout_host + + cd test + + __ntests=$(${EXETOOL} list -- "${@}" | wc -l) + if [ ${?} != 0 ]; then + info "Failed to get exeter manifest for ${@}" + pause_continue \ + "Press any key to pause test session" \ + "Resuming in " \ + "Paused, press any key to continue" \ + 5 + return + fi + + status_file_start "${*} (exeter)" ${__ntests} + [ ${CI} -eq 1 ] && video_link "${1}" + + for __testid in $(${EXETOOL} list -- "${@}"); do + __desc="$(${EXETOOL} desc -- "${@}" -- "${__testid}")" + status_test_start "${__desc}" + status=0 + context_run host "${*} '${__testid}'" || status="${?}" + if [ "${status}" = 0 ]; then + status_test_ok + elif [ "${status}" = 77 ]; then + status_test_skip + else + status_test_fail + fi + done + + cd .. + + teardown_context_watch ${PANE_HOST} host +} diff --git a/test/lib/setup b/test/lib/setup index 575bc21..5994598 100755 --- a/test/lib/setup +++ b/test/lib/setup @@ -350,7 +350,7 @@ setup_migrate() { sleep 1 - __opts="--vhost-user" + __opts="--vhost-user --migrate-exit --migrate-no-linger" [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_1.pcap" [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" @@ -360,7 +360,7 @@ setup_migrate() { context_run_bg passt_repair_1 "./passt-repair ${STATESETUP}/passt_1.socket.repair" - __opts="--vhost-user" + __opts="--vhost-user --migrate-exit --migrate-no-linger" [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_2.pcap" [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" diff --git a/test/lib/term b/test/lib/term index ed690de..f596364 100755 --- a/test/lib/term +++ b/test/lib/term @@ -19,6 +19,7 @@ STATUS_FILE_INDEX=0 STATUS_COLS= STATUS_PASS=0 STATUS_FAIL=0 +STATUS_SKIPPED=0 PR_RED='\033[1;31m' PR_GREEN='\033[1;32m' @@ -28,32 +29,32 @@ PR_NC='\033[0m' PR_DELAY_INIT=100 # ms # info() - Highlight test log pane, print message to it and to log file -# $@: Message to print +# $*: Message to print info() { tmux select-pane -t ${PANE_INFO} - printf "${@}\n" >> $STATEBASE/log_pipe - printf "${@}\n" >> "${LOGFILE}" + printf "%b\n" "${*}" >> $STATEBASE/log_pipe + printf "%b\n" "${*}" >> "${LOGFILE}" } # info_n() - Highlight, print message to pane and to log file without newline -# $@: Message to print +# $*: Message to print info_n() { tmux select-pane -t ${PANE_INFO} - printf "${@}" >> $STATEBASE/log_pipe - printf "${@}" >> "${LOGFILE}" + printf "%b" "${*}" >> $STATEBASE/log_pipe + printf "%b" "${*}" >> "${LOGFILE}" } # info_nolog() - Highlight test log pane, print message to it -# $@: Message to print +# $*: Message to print info_nolog() { tmux select-pane -t ${PANE_INFO} - printf "${@}\n" >> $STATEBASE/log_pipe + printf "%b\n" "${*}" >> $STATEBASE/log_pipe } # info_nolog() - Print message to log file -# $@: Message to print +# $*: Message to print log() { - printf "${@}\n" >> "${LOGFILE}" + printf "%b\n" "${*}" >> "${LOGFILE}" } # info_nolog_n() - Send message to pane without highlighting it, without newline @@ -362,8 +363,8 @@ status_test_start() { info_check() { switch_pane ${PANE_INFO} - printf "${PR_YELLOW}?${PR_NC} ${@}" >> $STATEBASE/log_pipe - printf "? ${@}" >> "${LOGFILE}" + printf "%b" "${PR_YELLOW}?${PR_NC} ${*}" >> $STATEBASE/log_pipe + printf "? %b" "${*}" >> "${LOGFILE}" } # info_check_passed() - Display and log a new line when a check passes @@ -439,19 +440,21 @@ info_layout() { # status_test_ok() - Update counter of passed tests, log and display message status_test_ok() { STATUS_PASS=$((STATUS_PASS + 1)) - tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)" + tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)" info_passed } # status_test_fail() - Update counter of failed tests, log and display message status_test_fail() { STATUS_FAIL=$((STATUS_FAIL + 1)) - tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)" + tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)" info_failed } # status_test_fail() - Update counter of failed tests, log and display message status_test_skip() { + STATUS_SKIPPED=$((STATUS_SKIPPED + 1)) + tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | SKIPPED: ${STATUS_SKIPPED} | #(TZ="UTC" date -Iseconds)" info_skipped } @@ -704,7 +707,7 @@ term() { tmux set window-status-current-style 'bg=colour1 fg=colour233 bold' tmux set status-right '#(TZ="UTC" date -Iseconds)' - tmux set status-right-length 50 + tmux set status-right-length 64 tmux set status-right-style 'bg=colour1 fg=colour233 bold' tmux set history-limit 500000 diff --git a/test/lib/test b/test/lib/test index 758250a..7349674 100755 --- a/test/lib/test +++ b/test/lib/test @@ -20,10 +20,7 @@ test_iperf3s() { __sctx="${1}" __port="${2}" - pane_or_context_run_bg "${__sctx}" \ - 'iperf3 -s -p'${__port}' & echo $! > s.pid' \ - - sleep 1 # Wait for server to be ready + pane_or_context_run "${__sctx}" 'iperf3 -s -p'${__port}' -D -I s.pid' } # test_iperf3k() - Kill iperf3 server @@ -31,7 +28,7 @@ test_iperf3s() { test_iperf3k() { __sctx="${1}" - pane_or_context_run "${__sctx}" 'kill -INT $(cat s.pid); rm s.pid' + pane_or_context_run "${__sctx}" 'kill -INT $(cat s.pid)' sleep 1 # Wait for kernel to free up ports } diff --git a/test/memory/passt b/test/memory/passt index 7e45724..c5142ea 100644 --- a/test/memory/passt +++ b/test/memory/passt @@ -51,7 +51,7 @@ guest sed /proc/slabinfo -ne 's/^\([^ ]* *[^ ]* *[^ ]* *[^ ]*\).*/\\\1/p' > /tmp guest kill \$(cat /tmp/pid) guest diff -y --suppress-common-lines /tmp/meminfo.before /tmp/meminfo.after || : guest nm -td -Sr --size-sort -P /bin/passt.avx2 | head -30 | tee /tmp/nm.size -guest sed /proc/slabinfo -ne 's/\(.*<objsize>\).*$/\1/p' | tail -1; (diff -y --suppress-common-lines /tmp/slabinfo.before /tmp/slabinfo.after | sort -grk8) +guest sed /proc/slabinfo -ne 's/\(.*<objsize>\).*$/\\\1/p' | tail -1; (diff -y --suppress-common-lines /tmp/slabinfo.before /tmp/slabinfo.after | sort -grk8) endef def summary diff --git a/test/migrate/basic b/test/migrate/basic index 3f11f7d..bab2d76 100644 --- a/test/migrate/basic +++ b/test/migrate/basic @@ -39,8 +39,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv4: guest1/guest2 > host g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/migrate/basic_fin b/test/migrate/basic_fin index aa61ec5..1d92c92 100644 --- a/test/migrate/basic_fin +++ b/test/migrate/basic_fin @@ -39,8 +39,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv4: guest1, half-close, guest2 > host g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/migrate/iperf3_bidir6 b/test/migrate/iperf3_bidir6 index 4bfefb5..e95eee8 100644 --- a/test/migrate/iperf3_bidir6 +++ b/test/migrate/iperf3_bidir6 @@ -44,8 +44,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv6 host <-> guest flood, many flows, during migration diff --git a/test/migrate/iperf3_in6 b/test/migrate/iperf3_in6 index 16cf504..0e863a4 100644 --- a/test/migrate/iperf3_in6 +++ b/test/migrate/iperf3_in6 @@ -44,8 +44,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv6 host to guest throughput during migration diff --git a/test/migrate/iperf3_many_out6 b/test/migrate/iperf3_many_out6 index 88133f2..179e269 100644 --- a/test/migrate/iperf3_many_out6 +++ b/test/migrate/iperf3_many_out6 @@ -44,8 +44,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv6 guest to host flood, many flows, during migration diff --git a/test/migrate/iperf3_out6 b/test/migrate/iperf3_out6 index 21fbfcd..20e6e95 100644 --- a/test/migrate/iperf3_out6 +++ b/test/migrate/iperf3_out6 @@ -44,8 +44,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv6 guest to host throughput during migration diff --git a/test/migrate/rampstream_in b/test/migrate/rampstream_in index df333ba..5212dfc 100644 --- a/test/migrate/rampstream_in +++ b/test/migrate/rampstream_in @@ -40,8 +40,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv4: sequence check, ramps, inbound g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/migrate/rampstream_out b/test/migrate/rampstream_out index 8ed3229..897396d 100644 --- a/test/migrate/rampstream_out +++ b/test/migrate/rampstream_out @@ -40,8 +40,8 @@ guest1 /sbin/dhclient -6 __IFNAME1__ # Wait for DAD to complete on the DHCP address guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" test TCP/IPv4: sequence check, ramps, outbound g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/passt.mbuto b/test/passt.mbuto index 5e00132..598c254 100755 --- a/test/passt.mbuto +++ b/test/passt.mbuto @@ -28,9 +28,12 @@ KMODS="${KMODS:- virtio_net virtio_pci vmw_vsock_virtio_transport}" LINKS="${LINKS:- ash,dash,bash /init - ash,dash,bash /bin/sh}" + ash,dash,bash /bin/sh + sshd /usr/sbin/sshd + dhclient /usr/sbin/dhclient + sysctl /usr/sbin/sysctl}" -DIRS="${DIRS} /tmp /usr/sbin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh" +DIRS="${DIRS} /tmp /usr/sbin /usr/bin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh" COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin rampstream,/bin/rampstream rampstream-check.sh,/bin/rampstream-check.sh" @@ -61,7 +64,9 @@ set >> \$LOG exit 0 EOF chmod 755 /sbin/dhclient-script - ln -s /bin /usr/bin + mv /bin/* /usr/bin || : + rm -rf /bin + ln -s /usr/bin /bin ln -s /run /var/run :> /etc/fstab diff --git a/test/passt.mem.mbuto b/test/passt.mem.mbuto index 532eae0..7554a43 100755 --- a/test/passt.mem.mbuto +++ b/test/passt.mem.mbuto @@ -12,7 +12,7 @@ PROGS="${PROGS:-ash,dash,bash chmod ip mount insmod mkdir ln cat chmod modprobe grep mknod sed chown sleep bc ls ps mount unshare chroot cp kill diff - head tail sort tr tee cut nm which switch_root}" + head tail sort tr tee cut nm which switch_root mv rm}" KMODS="${KMODS:- dummy}" @@ -22,12 +22,14 @@ LINKS="${LINKS:- ash,dash,bash /init ash,dash,bash /bin/sh}" -DIRS="${DIRS} /tmp /sbin" +DIRS="${DIRS} /tmp /sbin /usr/bin" COPIES="${COPIES} ../passt.avx2,/bin/passt.avx2" FIXUP="${FIXUP}"' -ln -s /bin /usr/bin +mv /bin/* /usr/bin || : +rm -rf /bin +ln -s /usr/bin /bin chmod 777 /tmp sh +m ' diff --git a/test/passt/dhcp b/test/passt/dhcp index 145f1ba..904faab 100644 --- a/test/passt/dhcp +++ b/test/passt/dhcp @@ -61,8 +61,8 @@ guest /sbin/dhclient -6 __IFNAME__ # Wait for DAD to complete guest while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR6__" test DHCPv6: route gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/passt/ndp b/test/passt/ndp index 516cd6b..80b72bb 100644 --- a/test/passt/ndp +++ b/test/passt/ndp @@ -25,9 +25,9 @@ check [ -n "__IFNAME__" ] test SLAAC: prefix gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.protocol == "kernel_ra") | .local + "/" + (.prefixlen | tostring)] | .[0]' gout PREFIX6 sipcalc __ADDR6__ | grep prefix | cut -d' ' -f4 -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 -check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join("/64 ")' +hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 | tr '\n' ' ' +check echo "__HOST_PREFIX6__" | grep -wq "__PREFIX6__" test SLAAC: route gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/passt_in_ns/dhcp b/test/passt_in_ns/dhcp index a38a690..9d89049 100644 --- a/test/passt_in_ns/dhcp +++ b/test/passt_in_ns/dhcp @@ -55,8 +55,8 @@ guest /sbin/dhclient -6 __IFNAME__ # Wait for DAD to complete guest while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done gout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(",")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR6__" test DHCPv6: route gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/pasta/dhcp b/test/pasta/dhcp index d4f3ad5..366935f 100644 --- a/test/pasta/dhcp +++ b/test/pasta/dhcp @@ -39,8 +39,8 @@ ns /sbin/dhclient -6 --no-pid __IFNAME__ ns while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ __ADDR6__ = __HOST_ADDR6__ ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR6__" test DHCPv6: route nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/pasta/ndp b/test/pasta/ndp index 952c1ea..1d385c7 100644 --- a/test/pasta/ndp +++ b/test/pasta/ndp @@ -24,9 +24,9 @@ ns while ! ip -j -6 addr show dev __IFNAME__ | jq -e '.[].addr_info.[] | select( test SLAAC: prefix nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.protocol == "kernel_ra") | .local + "/" + (.prefixlen | tostring)] | .[0]' nsout PREFIX6 sipcalc __ADDR6__ | grep prefix | cut -d' ' -f4 -hout HOST_ADDR6 ip -j -6 addr show|jq -rM ['.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 -check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM ['.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local]| join("/64 ")' +hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 | tr '\n' ' ' +check echo "__HOST_PREFIX6__" | grep -wq "__PREFIX6__" test SLAAC: route nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' diff --git a/test/pasta_options/log_to_file b/test/pasta_options/log_to_file index 3ead06c..db78b04 100644 --- a/test/pasta_options/log_to_file +++ b/test/pasta_options/log_to_file @@ -30,19 +30,19 @@ endef test Log creation -set PORTS -t 10001,10002 -u 10001,10002 +set PORTS -t 10001,10002 -u 10001,10002 -T none -U none set LOG_FILE __STATEDIR__/pasta.log -passt ./pasta -l __LOG_FILE__ -- /bin/true +passt ./pasta __PORTS__ -l __LOG_FILE__ -- /bin/true check [ -s __LOG_FILE__ ] test Log truncated on creation -passt ./pasta -l __LOG_FILE__ -- /bin/true & wait +passt ./pasta __PORTS__ -l __LOG_FILE__ -- /bin/true & wait pout PID2 echo $! check head -1 __LOG_FILE__ | grep '^pasta .* [(]__PID2__[)]$' test Maximum log size -passtb ./pasta --config-net -d -f -l __LOG_FILE__ --log-size $((100 * 1024)) -- sh -c 'while true; do tcp_crr --nolog -l1 -P 10001 -C 10002 -6; done' +passtb ./pasta __PORTS__ --config-net -d -f -l __LOG_FILE__ --log-size $((100 * 1024)) -- sh -c 'while true; do tcp_crr --nolog -l1 -P 10001 -C 10002 -6; done' sleep 1 flood_log_client @@ -67,7 +67,7 @@ passt unshare -rUm passt mkdir __STATEDIR__/t passt mount -t tmpfs none __STATEDIR__/t set LOG_FILE __STATEDIR__/t/log -passt ./pasta --config-net -d -l __LOG_FILE__ --log-size $((100 * 1024)) +passt ./pasta __PORTS__ --config-net -d -l __LOG_FILE__ --log-size $((100 * 1024)) flood_log_server flood_log_client diff --git a/test/perf/passt_tcp b/test/perf/passt_tcp index 5978c49..1a97a63 100644 --- a/test/perf/passt_tcp +++ b/test/perf/passt_tcp @@ -87,7 +87,7 @@ lat - lat - nsb tcp_crr --nolog -6 gout LAT tcp_crr --nolog -l1 -6 -c -H __MAP_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p' -lat __LAT__ 500 400 +lat __LAT__ 550 450 tr TCP throughput over IPv4: guest to host iperf3s ns 10002 @@ -137,7 +137,7 @@ lat - lat - nsb tcp_crr --nolog -4 gout LAT tcp_crr --nolog -l1 -4 -c -H __MAP_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p' -lat __LAT__ 500 400 +lat __LAT__ 550 450 tr TCP throughput over IPv6: host to guest iperf3s guest 10001 @@ -208,6 +208,6 @@ lat - guestb tcp_crr --nolog -P 10001 -C 10011 -4 sleep 1 nsout LAT tcp_crr --nolog -l1 -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' -lat __LAT__ 500 300 +lat __LAT__ 500 350 te diff --git a/test/perf/pasta_tcp b/test/perf/pasta_tcp index bc0de3c..496d0fe 100644 --- a/test/perf/pasta_tcp +++ b/test/perf/pasta_tcp @@ -211,7 +211,7 @@ tr TCP throughput over IPv6: host to ns iperf3s ns 10002 nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local] | .[0]' +nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope != "host" and .scope != "link").local] | .[0]' bw - bw - bw - diff --git a/test/perf/pasta_udp b/test/perf/pasta_udp index ab2f3e8..c51bb6c 100644 --- a/test/perf/pasta_udp +++ b/test/perf/pasta_udp @@ -39,7 +39,7 @@ iperf3s host 10003 # (datagram size) = (packet size) - 48: 40 bytes of IPv6 header, 8 of UDP header iperf3 BW ns ::1 10003 __TIME__ __OPTS__ -b 5G -l 1452 -bw __BW__ 1.0 1.5 +bw __BW__ 0.8 1.2 iperf3 BW ns ::1 10003 __TIME__ __OPTS__ -b 10G -l 3972 bw __BW__ 1.2 1.8 iperf3 BW ns ::1 10003 __TIME__ __OPTS__ -b 30G -l 16336 @@ -64,7 +64,7 @@ iperf3s host 10003 # (datagram size) = (packet size) - 28: 20 bytes of IPv4 header, 8 of UDP header iperf3 BW ns 127.0.0.1 10003 __TIME__ __OPTS__ -b 5G -l 1372 -bw __BW__ 1.0 1.5 +bw __BW__ 0.8 1.2 iperf3 BW ns 127.0.0.1 10003 __TIME__ __OPTS__ -b 10G -l 3972 bw __BW__ 1.2 1.8 iperf3 BW ns 127.0.0.1 10003 __TIME__ __OPTS__ -b 30G -l 16356 @@ -88,7 +88,7 @@ tr UDP throughput over IPv6: host to ns iperf3s ns 10002 iperf3 BW host ::1 10002 __TIME__ __OPTS__ -b 5G -l 1452 -bw __BW__ 1.0 1.5 +bw __BW__ 0.8 1.2 iperf3 BW host ::1 10002 __TIME__ __OPTS__ -b 10G -l 3972 bw __BW__ 1.2 1.8 iperf3 BW host ::1 10002 __TIME__ __OPTS__ -b 30G -l 16336 @@ -111,7 +111,7 @@ lat __LAT__ 200 150 tr UDP throughput over IPv4: host to ns iperf3s ns 10002 iperf3 BW host 127.0.0.1 10002 __TIME__ __OPTS__ -b 5G -l 1372 -bw __BW__ 1.0 1.5 +bw __BW__ 0.8 1.2 iperf3 BW host 127.0.0.1 10002 __TIME__ __OPTS__ -b 10G -l 3972 bw __BW__ 1.2 1.8 iperf3 BW host 127.0.0.1 10002 __TIME__ __OPTS__ -b 30G -l 16356 @@ -196,7 +196,7 @@ tr UDP throughput over IPv6: host to ns iperf3s ns 10002 nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local] | .[0]' +nsout ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope != "host" and .scope != "link").local] | .[0]' iperf3 BW host __ADDR6__ 10002 __TIME__ __OPTS__ -b 8G -l 1472 bw __BW__ 0.3 0.5 iperf3 BW host __ADDR6__ 10002 __TIME__ __OPTS__ -b 12G -l 3972 diff --git a/test/prepare-distro-img.sh b/test/prepare-distro-img.sh index 0d967c9..be2386e 100755 --- a/test/prepare-distro-img.sh +++ b/test/prepare-distro-img.sh @@ -3,6 +3,10 @@ IMG="$1" PASST_FILES="$(echo ../*.c ../*.h ../*.sh ../*.1 ../Makefile ../README.md)" +# This is just a workaround for Fedora and related distributions. +# Once it gets fixed, we can drop this. +export LIBGUESTFS_BACKEND=direct + virt-edit -a $IMG /lib/systemd/system/serial-getty@.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --autologin root -8 --keep-baud 115200,38400,9600 %I $TERM/g' guestfish --rw -a $IMG -i <<EOF @@ -43,6 +43,9 @@ KERNEL=${KERNEL:-"/boot/vmlinuz-$(uname -r)"} COMMIT="$(git log --oneline --no-decorate -1)" +# Let exeter tests written in Python find their modules +export PYTHONPATH=${BASEPATH}/exeter/py3 + . lib/util . lib/context . lib/setup @@ -53,6 +56,7 @@ COMMIT="$(git log --oneline --no-decorate -1)" . lib/layout_ugly . lib/test . lib/video +. lib/exeter # cleanup() - Remove temporary files cleanup() { @@ -67,11 +71,9 @@ run() { perf_init [ ${CI} -eq 1 ] && video_start ci - setup build - test build/all - test build/cppcheck - test build/clang_tidy - teardown build + exeter smoke/smoke.sh + exeter build/build.py + exeter build/static_checkers.sh setup pasta test pasta/ndp @@ -202,7 +204,7 @@ skip_distro() { perf_finish [ ${CI} -eq 1 ] && video_stop - log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}" + log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}, SKIPPED: ${STATUS_SKIPPED}" pause_continue \ "Press any key to keep test session open" \ @@ -223,6 +225,10 @@ run_selected() { __setup= for __test; do + if is_exeter "test/${__test}"; then + exeter "${__test}" + continue + fi # HACK: the migrate tests need the setup repeated for # each test if [ "${__test%%/*}" != "${__setup}" -o \ @@ -234,9 +240,9 @@ run_selected() { test "${__test}" done - teardown "${__setup}" + [ -n "${__setup}" ] && teardown "${__setup}" - log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}" + log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}, SKIPPED: ${STATUS_SKIPPED}" pause_continue \ "Press any key to keep test session open" \ @@ -307,4 +313,4 @@ fi tail -n1 ${LOGFILE} echo "Log at ${LOGFILE}" -exit $(tail -n1 ${LOGFILE} | sed -n 's/.*FAIL: \(.*\)$/\1/p') +exit $(tail -n1 ${LOGFILE} | sed -n 's/.*FAIL: \(.*\),.*$/\1/p') diff --git a/test/smoke/smoke.sh b/test/smoke/smoke.sh new file mode 100755 index 0000000..a642fb9 --- /dev/null +++ b/test/smoke/smoke.sh @@ -0,0 +1,33 @@ +#! /bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/smoke/smoke.sh - Basic smoke tests +# +# Copyright Red Hat +# Author: David Gibson <david@gibson.dropbear.id.au> + +. $(dirname $0)/../exeter/sh/exeter.sh + +PASST=$(dirname $0)/../../passt +PASTA=$(dirname $0)/../../pasta + +exeter_register passt_version $PASST --version +exeter_set_description passt_version "Check passt --version works" + +exeter_register pasta_version $PASTA --version +exeter_set_description pasta_version "Check pasta --version works" + +exeter_register passt_help $PASST --help +exeter_set_description passt_help "Check passt --help works" + +exeter_register pasta_help $PASTA --help +exeter_set_description pasta_help "Check pasta --help works" + +exeter_main "$@" diff --git a/test/two_guests/basic b/test/two_guests/basic index e2338ff..cb48bce 100644 --- a/test/two_guests/basic +++ b/test/two_guests/basic @@ -45,9 +45,9 @@ guest1 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; guest2 while ip -j -6 addr show tentative | jq -e '.[].addr_info'; do sleep 0.1; done g1out ADDR1_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local] | .[0]' g2out ADDR2_6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__IFNAME2__").addr_info[] | select(.prefixlen == 128).local] | .[0]' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global" and .deprecated != true).local] | .[0]' -check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] -check [ "__ADDR2_6__" = "__HOST_ADDR6__" ] +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '[.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope != "host" and .scope != "link" and .deprecated != true).local] | join(" ")' +check echo "__HOST_ADDR6__" | grep -wq "__ADDR1_6__" +check echo "__HOST_ADDR6__" | grep -wq "__ADDR2_6__" test TCP/IPv4: guest 1 > guest 2 g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' |
