From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202408 header.b=EYiejODf; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id 6F5A15A0276 for ; Mon, 26 Aug 2024 04:09:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202408; t=1724638184; bh=Z14NQjmUmGp6mN6T3Jevejb4Vtp+QtLRRNrRAmzGl+0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EYiejODfvv8hxB+rNZ2+k0T00ehmlBV/aRnBnq0RRYB1bOxWz25rPVDSElBfGUbHe lfLhW9/gVe8sjb9MZvd/imUofZxYVVTq2OcWBW/nqalqG/A3bVnrbZBn6h5hMOxNWs P9gV/Slw0NcfqGfp+l2lnkGLXT/IflRY9f+CDXr6vzGfvyAArIJLRCzEmrBHGji6QH nmaAoI1x9krReQfd5P4OWqMGi1SJ9JNb3C2odcFvNCeRNZtsO+vyKX7g/cNvleRk92 k7EPC+v2gLyOom9X4j7Ko6Cv3XmjqlgKDHzjFTsrxXefMkLlPIrRVbLxAtIHBAoaLE vnbC2OseIIAAA== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4WsYyw6FjSz4xDL; Mon, 26 Aug 2024 12:09:44 +1000 (AEST) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v3 15/15] avocado: Convert basic pasta tests Date: Mon, 26 Aug 2024 12:09:42 +1000 Message-ID: <20240826020942.545155-16-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20240826020942.545155-1-david@gibson.dropbear.id.au> References: <20240826020942.545155-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: AEBJIZKPYJL3PBADW4X35ZZ5H27SMYM7 X-Message-ID-Hash: AEBJIZKPYJL3PBADW4X35ZZ5H27SMYM7 X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Cleber Rosa , David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Convert the old-style tests for pasta (DHCP, NDP, TCP and UDP transfers) to using avocado. There are a few differences in what we test, but this should generally improve coverage: * We run in a constructed network environment, so we no longer depend on the real host's networking configuration * We do independent setup for each individual test * We add explicit tests for --config-net, which we use to accelerate that setup for the TCP and UDP tests * The TCP and UDP tests now test transfers between the guest and a (simulated) remote site that's on a different network from the simulated pasta host. Thus testing the no NAT case that passt/pasta emphasizes. (We need to add tests for the NAT cases back in). Signed-off-by: David Gibson --- test/Makefile | 4 +- test/pasta/.gitignore | 1 + test/pasta/pasta.py | 130 ++++++++++++++++++++++++++++++++++++++++++ test/tasst/pasta.py | 48 ++++++++++++++++ 4 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 test/pasta/.gitignore create mode 100644 test/pasta/pasta.py create mode 100644 test/tasst/pasta.py diff --git a/test/Makefile b/test/Makefile index 3ac67b66..23dcd368 100644 --- a/test/Makefile +++ b/test/Makefile @@ -64,11 +64,11 @@ LOCAL_ASSETS = mbuto.img mbuto.mem.img podman/bin/podman QEMU_EFI.fd \ $(TESTDATA_ASSETS) ASSETS = $(DOWNLOAD_ASSETS) $(LOCAL_ASSETS) -AVOCADO_ASSETS = +AVOCADO_ASSETS = nstool small.bin medium.bin big.bin META_ASSETS = nstool small.bin medium.bin big.bin EXETER_SH = build/static_checkers.sh -EXETER_PY = build/build.py +EXETER_PY = build/build.py pasta/pasta.py EXETER_JOBS = $(EXETER_SH:%.sh=%.json) $(EXETER_PY:%.py=%.json) AVOCADO_JOBS = $(EXETER_JOBS) avocado/static_checkers.json diff --git a/test/pasta/.gitignore b/test/pasta/.gitignore new file mode 100644 index 00000000..a6c57f5f --- /dev/null +++ b/test/pasta/.gitignore @@ -0,0 +1 @@ +*.json diff --git a/test/pasta/pasta.py b/test/pasta/pasta.py new file mode 100644 index 00000000..b7d5ee2e --- /dev/null +++ b/test/pasta/pasta.py @@ -0,0 +1,130 @@ +#! /usr/bin/env avocado-runner-avocado-classless + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright Red Hat +# Author: David Gibson + +""" +avocado/pasta.py - Basic tests for pasta mode +""" + +import contextlib +import ipaddress +from typing import Any, Iterator + +import exeter + +import tasst +from tasst import cmdsite, dhcp, ndp, pasta, unshare +from tasst.scenario.simple import simple_net + +IN_FWD_PORT = 10002 +SPLICE_FWD_PORT = 10003 +FWD_OPTS = ['-t', f'{IN_FWD_PORT}', '-u', f'{IN_FWD_PORT}', + '-T', f'{SPLICE_FWD_PORT}', '-U', f'{SPLICE_FWD_PORT}'] + + +@contextlib.contextmanager +def pasta_unconfigured(*opts: str) -> Iterator[tuple[Any, unshare.Unshare]]: + with simple_net() as simnet: + with unshare.unshare('pastans', '-Ucnpf', '--mount-proc', + parent=simnet.simhost, privilege=True) \ + as guestns: + with pasta.pasta(simnet.simhost, guestns, *opts) as p: + yield simnet, p.ns + + +@exeter.test +def test_ifname() -> None: + with pasta_unconfigured() as (simnet, ns): + expected = set(['lo', simnet.IFNAME]) + exeter.assert_eq(set(tasst.ip.ifs(ns)), expected) + + +@ndp.NdpScenario.test +def pasta_ndp_setup() -> Iterator[ndp.NdpScenario]: + with pasta_unconfigured() as (simnet, guestns): + tasst.ip.ifup(guestns, simnet.IFNAME) + yield ndp.NdpScenario(client=guestns, + ifname=simnet.IFNAME, + network=simnet.IP6.network, + gateway=simnet.gw_ip6_ll.ip) + + +@dhcp.Dhcp4Scenario.test +def pasta_dhcp() -> Iterator[dhcp.Dhcp4Scenario]: + with pasta_unconfigured() as (simnet, guestns): + yield dhcp.Dhcp4Scenario(client=guestns, + ifname=simnet.IFNAME, + addr=simnet.IP4.ip, + gateway=simnet.GW_IP4.ip, + mtu=65520) + + +@dhcp.Dhcp6Scenario.test +def pasta_dhcpv6() -> Iterator[dhcp.Dhcp6Scenario]: + with pasta_unconfigured() as (simnet, guestns): + yield dhcp.Dhcp6Scenario(client=guestns, + ifname=simnet.IFNAME, + addr=simnet.IP6.ip) + + +@contextlib.contextmanager +def pasta_configured() -> Iterator[tuple[Any, unshare.Unshare]]: + with pasta_unconfigured('--config-net', *FWD_OPTS) as (simnet, ns): + # Wait for DAD to complete on the --config-net address + tasst.ip.addr_wait(ns, simnet.IFNAME, family='inet6', scope='global') + yield simnet, ns + + +@exeter.test +def test_config_net_addr() -> None: + with pasta_configured() as (simnet, ns): + addrs = tasst.ip.addrs(ns, simnet.IFNAME, scope='global') + exeter.assert_eq(set(addrs), set([simnet.IP4, simnet.IP6])) + + +@exeter.test +def test_config_net_route4() -> None: + with pasta_configured() as (simnet, ns): + (defroute,) = tasst.ip.routes4(ns, dst='default') + gateway = ipaddress.ip_address(defroute['gateway']) + exeter.assert_eq(gateway, simnet.GW_IP4.ip) + + +@exeter.test +def test_config_net_route6() -> None: + with pasta_configured() as (simnet, ns): + (defroute,) = tasst.ip.routes6(ns, dst='default') + gateway = ipaddress.ip_address(defroute['gateway']) + exeter.assert_eq(gateway, simnet.gw_ip6_ll.ip) + + +@exeter.test +def test_config_net_mtu() -> None: + with pasta_configured() as (simnet, ns): + mtu = tasst.ip.mtu(ns, simnet.IFNAME) + exeter.assert_eq(mtu, 65520) + + +@contextlib.contextmanager +def outward_transfer() -> Iterator[tuple[Any, cmdsite.CmdSite]]: + with pasta_configured() as (simnet, ns): + yield ns, simnet.gw + + +@contextlib.contextmanager +def inward_transfer() -> Iterator[tuple[Any, cmdsite.CmdSite]]: + with pasta_configured() as (simnet, ns): + yield simnet.gw, ns + + +@contextlib.contextmanager +def spliced_transfer() -> Iterator[tuple[cmdsite.CmdSite, cmdsite.CmdSite]]: + with pasta_configured() as (simnet, ns): + yield ns, simnet.simhost + + +if __name__ == '__main__': + exeter.main() diff --git a/test/tasst/pasta.py b/test/tasst/pasta.py new file mode 100644 index 00000000..e224b81b --- /dev/null +++ b/test/tasst/pasta.py @@ -0,0 +1,48 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright Red Hat +# Author: David Gibson + +""" +Test A Simple Socket Transport + +pasta.py - Helpers for starting pasta +""" + +import contextlib +import os.path +import tempfile +from typing import Iterator + +from . import cmdsite, unshare + + +PASTA_BIN = '../pasta' + + +class _Pasta: + """A running pasta instance""" + + ns: unshare.Unshare + + def __init__(self, ns: unshare.Unshare): + self.ns = ns + + +@contextlib.contextmanager +def pasta(host: cmdsite.CmdSite, ns: unshare.Unshare, *opts: str) \ + -> Iterator[_Pasta]: + with tempfile.TemporaryDirectory() as piddir: + pidfile = os.path.join(piddir, 'pasta.pid') + relpid = ns.relative_pid(host) + cmd = [PASTA_BIN, '-f', '-P', pidfile] + list(opts) + [f'{relpid}'] + with host.bg(*cmd): + # Wait for the PID file to be written + pidstr = None + while not pidstr: + pidstr = host.output('cat', pidfile, check=False) + pid = int(pidstr) + yield _Pasta(ns) + host.fg('kill', '-TERM', f'{pid}') -- 2.46.0