public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
* [PATCH 0/3] RFC: Preview of tunbridge based tests
@ 2025-10-02  7:57 David Gibson
  2025-10-02  7:57 ` [PATCH 1/3] test: Prepare for " David Gibson
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: David Gibson @ 2025-10-02  7:57 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

Here's a preliminary cut at some exeter+tunbridge based test cases.
Specifically, this converts the pasta NDP tests from the existing
framework.

This is pretty unpolished at this stage, and obviously doesn't cover
much.  At this stage I'm looking less for detailed review and more for
first impressions both of how the code looks for writing tests and how
the logs appear when running.

I think both have a lot of room for improvement, so I'd like to start
incorporating feedback ASAP, hence this early version.

David Gibson (3):
  test: Prepare for tunbridge based tests
  test: Add some missing quoting in exeter runner
  test: Re-implement pasta NDP tests using tunbridge & exeter

 test/.gitignore        |  2 ++
 test/Makefile          | 19 ++++++++------
 test/lib/exeter        |  4 +--
 test/pasta/dhcp        |  5 ++++
 test/pasta/ndp.py      | 59 ++++++++++++++++++++++++++++++++++++++++++
 test/run               |  8 +++---
 test/smoke/smoke.py    | 26 +++++++++++++++++++
 test/tasst/__init__.py | 14 ++++++++++
 test/tasst/pasta.py    | 40 ++++++++++++++++++++++++++++
 9 files changed, 164 insertions(+), 13 deletions(-)
 create mode 100755 test/pasta/ndp.py
 create mode 100755 test/smoke/smoke.py
 create mode 100644 test/tasst/__init__.py
 create mode 100644 test/tasst/pasta.py

-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] test: Prepare for tunbridge based tests
  2025-10-02  7:57 [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
@ 2025-10-02  7:57 ` David Gibson
  2025-10-02  7:57 ` [PATCH 2/3] test: Add some missing quoting in exeter runner David Gibson
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: David Gibson @ 2025-10-02  7:57 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

I plan to start converting many of our tests to the tunbridge[0] network
simulator framework.  This is the first step: downloading and setting up
tunbridge to work within our test scripts.  It also introduces a 'tasst'
Python library for code that we might want to reuse across various
tunbridge based tests.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 test/.gitignore        |  2 ++
 test/Makefile          | 19 +++++++++++--------
 test/run               |  2 +-
 test/smoke/smoke.py    | 26 ++++++++++++++++++++++++++
 test/tasst/__init__.py | 10 ++++++++++
 5 files changed, 50 insertions(+), 9 deletions(-)
 create mode 100755 test/smoke/smoke.py
 create mode 100644 test/tasst/__init__.py

diff --git a/test/.gitignore b/test/.gitignore
index 9412f0d3..71409c51 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -12,4 +12,6 @@ rampstream
 guest-key
 guest-key.pub
 /exeter/
+/tunbridge/
 *.bats
+__pycache__/
diff --git a/test/Makefile b/test/Makefile
index 5b5f0fc1..f66c7e7e 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -54,7 +54,7 @@ UBUNTU_NEW_IMGS = xenial-server-cloudimg-powerpc-disk1.img \
 	jammy-server-cloudimg-s390x.img
 UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS)
 
-DOWNLOAD_ASSETS = $(EXETOOL) mbuto podman \
+DOWNLOAD_ASSETS = $(EXETOOL) tunbridge mbuto podman \
 	$(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS)
 TESTDATA_ASSETS = small.bin big.bin medium.bin \
 	rampstream
@@ -65,15 +65,15 @@ LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \
 
 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
+EXETER_SH = smoke/smoke.sh build/static_checkers.sh
+EXETER_PYPATH = exeter/py3:tunbridge/:.
+EXETER_PYTHON = smoke/smoke.py build/build.py
+EXETER_BATS = $(EXETER_SH:%=%.bats) $(EXETER_PYTHON:%=%.bats)
 BATS_FILES = $(EXETER_BATS) \
 	podman/test/system/505-networking-pasta.bats
 
 # Python test code (for linters)
-PYPKGS = $(EXETER_PYTHON)
+PYPKGS = $(EXETER_PYTHON) tasst
 
 CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99
 
@@ -88,6 +88,9 @@ exeter:
 
 exeter/exetool/exetool: pull-exeter
 
+tunbridge:
+	git clone https://gitlab.com/dgibson/tunbridge.git
+
 mbuto:
 	git clone git://mbuto.sh/mbuto
 
@@ -139,7 +142,7 @@ flake8: pull-exeter
 mypy: pull-exeter
 	PYTHONPATH=$(EXETER_PYPATH) $(MYPY) $(PYPKGS)
 
-$(EXETER_BATS): %.bats: % $(EXETOOL)
+$(EXETER_BATS): %.bats: % $(EXETOOL) pull-tunbridge
 	PYTHONPATH=$(EXETER_PYPATH) $(EXETOOL) bats -- $< > $@
 
 bats: $(BATS_FILES) pull-podman
@@ -153,7 +156,7 @@ debug: assets
 
 clean:
 	rm -f perf.js *~
-	rm -rf .mypy_cache
+	rm -rf .mypy_cache __pycache__
 	rm -f $(LOCAL_ASSETS)
 	rm -f $(EXETER_BATS)
 	rm -rf test_logs
diff --git a/test/run b/test/run
index f858e558..3872a56e 100755
--- a/test/run
+++ b/test/run
@@ -44,7 +44,7 @@ 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
+export PYTHONPATH=${BASEPATH}/exeter/py3:${BASEPATH}/tunbridge:${BASEPATH}
 
 . lib/util
 . lib/context
diff --git a/test/smoke/smoke.py b/test/smoke/smoke.py
new file mode 100755
index 00000000..cbf77ad9
--- /dev/null
+++ b/test/smoke/smoke.py
@@ -0,0 +1,26 @@
+#! /usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# test/smoke/smoke.py - Python smoke tests
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import exeter
+
+
+@exeter.test
+def py_test_libraries() -> None:
+    """Check test in Python have access to the libraries we need"""
+
+    import tunbridge
+    import tasst
+
+    print(f"Imported exeter: {exeter}")
+    print(f"Imported tunbridge: {tunbridge}")
+    print(f"Imported tasst: {tasst}")
+
+
+if __name__ == '__main__':
+    exeter.main()
diff --git a/test/tasst/__init__.py b/test/tasst/__init__.py
new file mode 100644
index 00000000..fd4fe9a8
--- /dev/null
+++ b/test/tasst/__init__.py
@@ -0,0 +1,10 @@
+#! /usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# TASST - Test A Simple Socket Transport
+#
+# test/tasst/__init.py__ - Python library code useful for test cases
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 2/3] test: Add some missing quoting in exeter runner
  2025-10-02  7:57 [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
  2025-10-02  7:57 ` [PATCH 1/3] test: Prepare for " David Gibson
@ 2025-10-02  7:57 ` David Gibson
  2025-10-02  7:57 ` [PATCH 3/3] test: Re-implement pasta NDP tests using tunbridge & exeter David Gibson
  2025-10-02  7:57 ` [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
  3 siblings, 0 replies; 5+ messages in thread
From: David Gibson @ 2025-10-02  7:57 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

exeter() quoted ${__testid}, but in some places we use it there's an
extra level of shell, which needs another layer of quoting.  This breaks
if testids include ';', which is quite common in exeter tests created as
a composition/pipeline of two functions.  Add the required extra quoting.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 test/lib/exeter | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/lib/exeter b/test/lib/exeter
index 3b19beaa..530c6909 100644
--- a/test/lib/exeter
+++ b/test/lib/exeter
@@ -47,9 +47,9 @@ exeter() {
 	[ ${CI} -eq 1 ] && video_link "${1}"
 
 	for __testid in $($EXETOOL list -- "$@"); do
-		__desc="$($EXETOOL desc -- "$@" -- ${__testid})"
+		__desc="$($EXETOOL desc -- "$@" -- "${__testid}")"
 		status_test_start "${__desc}"
-		context_run host "$@" "${__testid}" && status_test_ok || status_test_fail
+		context_run host "$* '${__testid}'" && status_test_ok || status_test_fail
 	done
 
 	cd ..
-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 3/3] test: Re-implement pasta NDP tests using tunbridge & exeter
  2025-10-02  7:57 [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
  2025-10-02  7:57 ` [PATCH 1/3] test: Prepare for " David Gibson
  2025-10-02  7:57 ` [PATCH 2/3] test: Add some missing quoting in exeter runner David Gibson
@ 2025-10-02  7:57 ` David Gibson
  2025-10-02  7:57 ` [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
  3 siblings, 0 replies; 5+ messages in thread
From: David Gibson @ 2025-10-02  7:57 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio; +Cc: David Gibson

Convert the pasta NDP tests from shell and our own DSL to Python using
the exeter test protocol and tunbridge network simulation library.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 test/Makefile          |  2 +-
 test/pasta/dhcp        |  5 ++++
 test/pasta/ndp.py      | 59 ++++++++++++++++++++++++++++++++++++++++++
 test/run               |  6 +++--
 test/tasst/__init__.py |  4 +++
 test/tasst/pasta.py    | 40 ++++++++++++++++++++++++++++
 6 files changed, 113 insertions(+), 3 deletions(-)
 create mode 100755 test/pasta/ndp.py
 create mode 100644 test/tasst/pasta.py

diff --git a/test/Makefile b/test/Makefile
index f66c7e7e..95e3d75e 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -67,7 +67,7 @@ ASSETS = $(DOWNLOAD_ASSETS) $(LOCAL_ASSETS)
 
 EXETER_SH = smoke/smoke.sh build/static_checkers.sh
 EXETER_PYPATH = exeter/py3:tunbridge/:.
-EXETER_PYTHON = smoke/smoke.py build/build.py
+EXETER_PYTHON = smoke/smoke.py build/build.py pasta/ndp.py
 EXETER_BATS = $(EXETER_SH:%=%.bats) $(EXETER_PYTHON:%=%.bats)
 BATS_FILES = $(EXETER_BATS) \
 	podman/test/system/505-networking-pasta.bats
diff --git a/test/pasta/dhcp b/test/pasta/dhcp
index e1c66be6..61279fbf 100644
--- a/test/pasta/dhcp
+++ b/test/pasta/dhcp
@@ -18,6 +18,11 @@ test	Interface name
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 check	[ -n "__IFNAME__" ]
 
+# Bring up the interface
+ns	ip link set dev __IFNAME__ up
+# Wait for SLAAC & DAD to complete
+ns	while ! ip -j -6 addr show dev __IFNAME__ | jq -e '.[].addr_info.[] | select(.protocol == "kernel_ra")'; do sleep 0.1; done
+
 test	DHCP: address
 ns	/sbin/dhclient -4 --no-pid __IFNAME__
 nsout	ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local'
diff --git a/test/pasta/ndp.py b/test/pasta/ndp.py
new file mode 100755
index 00000000..8c7ce31e
--- /dev/null
+++ b/test/pasta/ndp.py
@@ -0,0 +1,59 @@
+#! /usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# test/pasta/ndp.py - pasta NDP functionality
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import contextlib
+import dataclasses
+from typing import Iterator
+
+import exeter
+import tunbridge
+import tasst
+
+
+@dataclasses.dataclass
+class UnconfiguredScenario(exeter.Scenario):
+    """Tests for a pasta instance without --config-net"""
+
+    host: tunbridge.Site
+    guest: tunbridge.Site
+    ifname: str
+    addr6: tunbridge.ip.AddrMask6
+    gw6: tunbridge.ip.Addr6
+
+    @exeter.scenariotest
+    def test_ifname(self) -> None:
+        ifs = tunbridge.ip.ifs(self.guest)
+        exeter.assert_eq(set(ifs), {'lo', self.ifname})
+
+    @tunbridge.ndp.NdpScenario.subscenario
+    def test_ndp(self) -> tunbridge.ndp.NdpScenario:
+        tunbridge.ip.ifup(self.guest, self.ifname)
+        return tunbridge.ndp.NdpScenario(client=self.guest,
+                                         ifname=self.ifname,
+                                         network=self.addr6.network,
+                                         gateway=self.gw6)
+
+
+@UnconfiguredScenario.test
+@contextlib.contextmanager
+def simh_pasta_setup() -> Iterator[UnconfiguredScenario]:
+    with (tunbridge.sample.simple_host('host') as simh,
+          tunbridge.sample.isolated('guest', simh.site) as guest):
+        assert simh.ip6 is not None
+        assert simh.gw6_ll is not None
+        with tasst.pasta.pasta(simh.site, guest):
+            yield UnconfiguredScenario(host=simh.site,
+                                       guest=guest,
+                                       ifname=simh.ifname,
+                                       addr6=simh.ip6,
+                                       gw6=simh.gw6_ll)
+
+
+if __name__ == '__main__':
+    exeter.main()
diff --git a/test/run b/test/run
index 3872a56e..4f09d767 100755
--- a/test/run
+++ b/test/run
@@ -43,8 +43,10 @@ KERNEL=${KERNEL:-"/boot/vmlinuz-$(uname -r)"}
 
 COMMIT="$(git log --oneline --no-decorate -1)"
 
-# Let exeter tests written in Python find their modules
+# Let exeter tests written in Python find their modules and binaries to run
 export PYTHONPATH=${BASEPATH}/exeter/py3:${BASEPATH}/tunbridge:${BASEPATH}
+export PASTA=${PASTA:-${BASEPATH}/../pasta}
+
 
 . lib/util
 . lib/context
@@ -75,8 +77,8 @@ run() {
 	exeter build/build.py
 	exeter build/static_checkers.sh
 
+	exeter pasta/ndp.py
 	setup pasta
-	test pasta/ndp
 	test pasta/dhcp
 	test pasta/tcp
 	test pasta/udp
diff --git a/test/tasst/__init__.py b/test/tasst/__init__.py
index fd4fe9a8..f5386b3a 100644
--- a/test/tasst/__init__.py
+++ b/test/tasst/__init__.py
@@ -8,3 +8,7 @@
 #
 # Copyright Red Hat
 # Author: David Gibson <david@gibson.dropbear.id.au>
+
+from . import pasta
+
+__all__ = ['pasta']
diff --git a/test/tasst/pasta.py b/test/tasst/pasta.py
new file mode 100644
index 00000000..91f59036
--- /dev/null
+++ b/test/tasst/pasta.py
@@ -0,0 +1,40 @@
+#! /usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# TASST - Test A Simple Socket Transport
+#
+# test/tasst/pasta.py - Helpers for seeting up pasta instances
+#
+# Copyright Red Hat
+# Author: David Gibson <david@gibson.dropbear.id.au>
+
+import contextlib
+import os
+from typing import Iterator
+
+import tunbridge
+
+
+@contextlib.contextmanager
+def pasta(host: tunbridge.Site, guest: tunbridge.Site, *opts: str) \
+        -> Iterator[tunbridge.site.SiteProcess]:
+    if tunbridge.unshare.parent(guest) is not host:
+        raise ValueError("pasta guest must be a namespace under host site")
+
+    # This implies guest is a namespace site
+    assert isinstance(guest, tunbridge.unshare.NsenterSite)
+
+    exe = os.environ['PASTA']
+
+    with host.tempdir() as piddir:
+        pidfile = os.path.join(piddir, 'pasta.pid')
+        cmd = [exe, '-f', '-P', pidfile] + list(opts) + [f'{guest.pid}']
+        with host.bg(*cmd, stop=True) as pasta:
+            # Wait for the PID file to be written
+            pidstr = None
+            while not pidstr:
+                pidstr = host.readfile(pidfile, check=False)
+            pid = int(pidstr)
+            print(f'pasta started, host: {host}, guest: {guest}, pid: {pid}')
+            yield pasta
-- 
2.51.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 0/3] RFC: Preview of tunbridge based tests
  2025-10-02  7:57 [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
                   ` (2 preceding siblings ...)
  2025-10-02  7:57 ` [PATCH 3/3] test: Re-implement pasta NDP tests using tunbridge & exeter David Gibson
@ 2025-10-02  7:57 ` David Gibson
  3 siblings, 0 replies; 5+ messages in thread
From: David Gibson @ 2025-10-02  7:57 UTC (permalink / raw)
  To: passt-dev, Stefano Brivio

[-- Attachment #1: Type: text/plain, Size: 920 bytes --]

On Thu, Oct 02, 2025 at 05:57:05PM +1000, David Gibson wrote:
> Here's a preliminary cut at some exeter+tunbridge based test cases.
> Specifically, this converts the pasta NDP tests from the existing
> framework.
> 
> This is pretty unpolished at this stage, and obviously doesn't cover
> much.  At this stage I'm looking less for detailed review and more for
> first impressions both of how the code looks for writing tests and how
> the logs appear when running.
> 
> I think both have a lot of room for improvement, so I'd like to start
> incorporating feedback ASAP, hence this early version.

Forgot to add, this series is based on the series of small test
Makefile and linter fixups I posted earlier.

-- 
David Gibson (he or they)	| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you, not the other way
				| around.
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2025-10-02  7:57 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-02  7:57 [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson
2025-10-02  7:57 ` [PATCH 1/3] test: Prepare for " David Gibson
2025-10-02  7:57 ` [PATCH 2/3] test: Add some missing quoting in exeter runner David Gibson
2025-10-02  7:57 ` [PATCH 3/3] test: Re-implement pasta NDP tests using tunbridge & exeter David Gibson
2025-10-02  7:57 ` [PATCH 0/3] RFC: Preview of tunbridge based tests David Gibson

Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).