summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/topotests/conftest.py16
-rw-r--r--tests/topotests/example_munet/munet.yaml17
-rw-r--r--tests/topotests/example_munet/r1/daemons6
-rw-r--r--tests/topotests/example_munet/r1/frr.conf7
-rw-r--r--tests/topotests/example_munet/r1/vtysh.conf1
-rw-r--r--tests/topotests/example_munet/r2/daemons6
-rw-r--r--tests/topotests/example_munet/r2/frr.conf10
-rw-r--r--tests/topotests/example_munet/r2/vtysh.conf1
-rw-r--r--tests/topotests/example_munet/r3/daemons6
-rw-r--r--tests/topotests/example_munet/r3/frr.conf7
-rw-r--r--tests/topotests/example_munet/r3/vtysh.conf1
-rw-r--r--tests/topotests/example_munet/test_munet.py10
-rw-r--r--tests/topotests/kinds.yaml30
-rw-r--r--tests/topotests/lib/micronet_compat.py3
-rw-r--r--tests/topotests/munet/base.py13
-rw-r--r--tests/topotests/munet/compat.py10
-rw-r--r--tests/topotests/munet/config.py54
-rw-r--r--tests/topotests/munet/native.py47
-rw-r--r--tests/topotests/munet/parser.py2
-rw-r--r--tests/topotests/pytest.ini4
20 files changed, 215 insertions, 36 deletions
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index 2b33aa24b0..ce59554b1a 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -5,6 +5,7 @@ Topotest conftest.py file.
# pylint: disable=consider-using-f-string
import glob
+import logging
import os
import re
import resource
@@ -16,7 +17,7 @@ import lib.fixtures
import pytest
from lib.micronet_compat import ConfigOptionsProxy, Mininet
from lib.topogen import diagnose_env, get_topogen
-from lib.topolog import logger
+from lib.topolog import get_test_logdir, logger
from lib.topotest import json_cmp_result
from munet import cli
from munet.base import Commander, proc_error
@@ -25,6 +26,19 @@ from munet.testing.util import pause_test
from lib import topolog, topotest
+try:
+ # Used by munet native tests
+ from munet.testing.fixtures import event_loop, unet # pylint: disable=all # noqa
+
+ @pytest.fixture(scope="module")
+ def rundir_module(pytestconfig):
+ d = os.path.join(pytestconfig.option.rundir, get_test_logdir())
+ logging.debug("rundir_module: test module rundir %s", d)
+ return d
+
+except (AttributeError, ImportError):
+ pass
+
def pytest_addoption(parser):
"""
diff --git a/tests/topotests/example_munet/munet.yaml b/tests/topotests/example_munet/munet.yaml
new file mode 100644
index 0000000000..34e1470103
--- /dev/null
+++ b/tests/topotests/example_munet/munet.yaml
@@ -0,0 +1,17 @@
+version: 1
+topology:
+ ipv6-enable: true
+ networks-autonumber: true
+ networks:
+ - name: net1
+ - name: net2
+ nodes:
+ - name: r1
+ kind: frr
+ connections: ["net1"]
+ - name: r2
+ kind: frr
+ connections: ["net1", "net2"]
+ - name: r3
+ kind: frr
+ connections: ["net2"]
diff --git a/tests/topotests/example_munet/r1/daemons b/tests/topotests/example_munet/r1/daemons
new file mode 100644
index 0000000000..a454c95923
--- /dev/null
+++ b/tests/topotests/example_munet/r1/daemons
@@ -0,0 +1,6 @@
+zebra=1
+staticd=1
+vtysh_enable=1
+watchfrr_enable=1
+zebra_options="-d -F traditional --log=file:/var/log/frr/zebra.log"
+staticd_options="-d -F traditional --log=file:/var/log/frr/staticd.log"
diff --git a/tests/topotests/example_munet/r1/frr.conf b/tests/topotests/example_munet/r1/frr.conf
new file mode 100644
index 0000000000..468bda5e01
--- /dev/null
+++ b/tests/topotests/example_munet/r1/frr.conf
@@ -0,0 +1,7 @@
+log file /var/log/frr/frr.log
+service integrated-vtysh-config
+
+interface eth0
+ ip address 10.0.1.1/24
+
+ip route 10.0.0.0/8 blackhole
diff --git a/tests/topotests/example_munet/r1/vtysh.conf b/tests/topotests/example_munet/r1/vtysh.conf
new file mode 100644
index 0000000000..f863f560f1
--- /dev/null
+++ b/tests/topotests/example_munet/r1/vtysh.conf
@@ -0,0 +1 @@
+service integrated-vtysh-config \ No newline at end of file
diff --git a/tests/topotests/example_munet/r2/daemons b/tests/topotests/example_munet/r2/daemons
new file mode 100644
index 0000000000..a454c95923
--- /dev/null
+++ b/tests/topotests/example_munet/r2/daemons
@@ -0,0 +1,6 @@
+zebra=1
+staticd=1
+vtysh_enable=1
+watchfrr_enable=1
+zebra_options="-d -F traditional --log=file:/var/log/frr/zebra.log"
+staticd_options="-d -F traditional --log=file:/var/log/frr/staticd.log"
diff --git a/tests/topotests/example_munet/r2/frr.conf b/tests/topotests/example_munet/r2/frr.conf
new file mode 100644
index 0000000000..77d9892485
--- /dev/null
+++ b/tests/topotests/example_munet/r2/frr.conf
@@ -0,0 +1,10 @@
+log file /var/log/frr/frr.log
+service integrated-vtysh-config
+
+interface eth0
+ ip address 10.0.1.2/24
+
+interface eth1
+ ip address 10.0.2.2/24
+
+ip route 10.0.0.0/8 blackhole
diff --git a/tests/topotests/example_munet/r2/vtysh.conf b/tests/topotests/example_munet/r2/vtysh.conf
new file mode 100644
index 0000000000..f863f560f1
--- /dev/null
+++ b/tests/topotests/example_munet/r2/vtysh.conf
@@ -0,0 +1 @@
+service integrated-vtysh-config \ No newline at end of file
diff --git a/tests/topotests/example_munet/r3/daemons b/tests/topotests/example_munet/r3/daemons
new file mode 100644
index 0000000000..a454c95923
--- /dev/null
+++ b/tests/topotests/example_munet/r3/daemons
@@ -0,0 +1,6 @@
+zebra=1
+staticd=1
+vtysh_enable=1
+watchfrr_enable=1
+zebra_options="-d -F traditional --log=file:/var/log/frr/zebra.log"
+staticd_options="-d -F traditional --log=file:/var/log/frr/staticd.log"
diff --git a/tests/topotests/example_munet/r3/frr.conf b/tests/topotests/example_munet/r3/frr.conf
new file mode 100644
index 0000000000..e0839e6d8a
--- /dev/null
+++ b/tests/topotests/example_munet/r3/frr.conf
@@ -0,0 +1,7 @@
+log file /var/log/frr/frr.log
+service integrated-vtysh-config
+
+interface eth0
+ ip address 10.0.2.3/24
+
+ip route 10.0.0.0/8 blackhole
diff --git a/tests/topotests/example_munet/r3/vtysh.conf b/tests/topotests/example_munet/r3/vtysh.conf
new file mode 100644
index 0000000000..f863f560f1
--- /dev/null
+++ b/tests/topotests/example_munet/r3/vtysh.conf
@@ -0,0 +1 @@
+service integrated-vtysh-config \ No newline at end of file
diff --git a/tests/topotests/example_munet/test_munet.py b/tests/topotests/example_munet/test_munet.py
new file mode 100644
index 0000000000..0d9599fa54
--- /dev/null
+++ b/tests/topotests/example_munet/test_munet.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# April 23 2023, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2023, LabN Consulting, L.L.C.
+#
+async def test_native_test(unet):
+ o = unet.hosts["r1"].cmd_nostatus("ip addr")
+ print(o)
diff --git a/tests/topotests/kinds.yaml b/tests/topotests/kinds.yaml
new file mode 100644
index 0000000000..127790ed07
--- /dev/null
+++ b/tests/topotests/kinds.yaml
@@ -0,0 +1,30 @@
+version: 1
+kinds:
+ - name: frr
+ cmd: |
+ chown frr:frr -R /var/run/frr
+ chown frr:frr -R /var/log/frr
+ /usr/lib/frr/frrinit.sh start
+ tail -F /var/log/frr/frr.log
+ cleanup-cmd: |
+ /usr/lib/frr/frrinit.sh stop
+ volumes:
+ - "./%NAME%:/etc/frr"
+ - "%RUNDIR%/var.log.frr:/var/log/frr"
+ - "%RUNDIR%/var.run.frr:/var/run/frr"
+ cap-add:
+ - SYS_ADMIN
+ - AUDIT_WRITE
+ merge: ["volumes"]
+cli:
+ commands:
+ - name: ""
+ exec: "vtysh -c '{}'"
+ format: "[ROUTER ...] COMMAND"
+ help: "execute vtysh COMMAND on the router[s]"
+ kinds: ["frr"]
+ - name: "vtysh"
+ exec: "/usr/bin/vtysh"
+ format: "vtysh ROUTER [ROUTER ...]"
+ new-window: true
+ kinds: ["frr"]
diff --git a/tests/topotests/lib/micronet_compat.py b/tests/topotests/lib/micronet_compat.py
index ccb3e56b61..f49db805ba 100644
--- a/tests/topotests/lib/micronet_compat.py
+++ b/tests/topotests/lib/micronet_compat.py
@@ -59,7 +59,6 @@ class Node(LinuxNamespace):
"""Node (mininet compat)."""
def __init__(self, name, rundir=None, **kwargs):
-
nkwargs = {}
if "unet" in kwargs:
@@ -177,8 +176,6 @@ class Mininet(BaseMunet):
self.host_params = {}
self.prefix_len = 8
- self.cfgopt = ConfigOptionsProxy(pytestconfig)
-
# SNMPd used to require this, which was set int he mininet shell
# that all commands executed from. This is goofy default so let's not
# do it if we don't have to. The snmpd.conf files have been updated
diff --git a/tests/topotests/munet/base.py b/tests/topotests/munet/base.py
index 38da7faa01..eb4b088442 100644
--- a/tests/topotests/munet/base.py
+++ b/tests/topotests/munet/base.py
@@ -26,6 +26,7 @@ from collections import defaultdict
from pathlib import Path
from typing import Union
+from . import config as munet_config
from . import linux
@@ -2493,7 +2494,15 @@ class Bridge(SharedNamespace, InterfaceMixin):
class BaseMunet(LinuxNamespace):
"""Munet."""
- def __init__(self, name="munet", isolated=True, pid=True, rundir=None, **kwargs):
+ def __init__(
+ self,
+ name="munet",
+ isolated=True,
+ pid=True,
+ rundir=None,
+ pytestconfig=None,
+ **kwargs,
+ ):
"""Create a Munet."""
# logging.warning("BaseMunet: %s", name)
@@ -2562,6 +2571,8 @@ class BaseMunet(LinuxNamespace):
roothost = self.rootcmd
+ self.cfgopt = munet_config.ConfigOptionsProxy(pytestconfig)
+
super().__init__(
name, mount=True, net=isolated, uts=isolated, pid=pid, unet=None, **kwargs
)
diff --git a/tests/topotests/munet/compat.py b/tests/topotests/munet/compat.py
index bf9092e53a..e82a7d5b77 100644
--- a/tests/topotests/munet/compat.py
+++ b/tests/topotests/munet/compat.py
@@ -11,8 +11,18 @@
class PytestConfig:
"""Pytest config duck-type-compatible object using argprase args."""
+ class Namespace:
+ """A namespace defined by a dictionary of values."""
+
+ def __init__(self, args):
+ self.args = args
+
+ def __getattr__(self, attr):
+ return self.args[attr] if attr in self.args else None
+
def __init__(self, args):
self.args = vars(args)
+ self.option = PytestConfig.Namespace(self.args)
def getoption(self, name, default=None, skip=False):
assert not skip
diff --git a/tests/topotests/munet/config.py b/tests/topotests/munet/config.py
index b66e4d17da..1b02f2e8ff 100644
--- a/tests/topotests/munet/config.py
+++ b/tests/topotests/munet/config.py
@@ -156,3 +156,57 @@ def merge_kind_config(kconf, config):
if k not in new:
new[k] = config[k]
return new
+
+
+def cli_opt_list(option_list):
+ if not option_list:
+ return []
+ if isinstance(option_list, str):
+ return [x for x in option_list.split(",") if x]
+ return [x for x in option_list if x]
+
+
+def name_in_cli_opt_str(name, option_list):
+ ol = cli_opt_list(option_list)
+ return name in ol or "all" in ol
+
+
+class ConfigOptionsProxy:
+ """Proxy options object to fill in for any missing pytest config."""
+
+ class DefNoneObject:
+ """An object that returns None for any attribute access."""
+
+ def __getattr__(self, attr):
+ return None
+
+ def __init__(self, pytestconfig=None):
+ if isinstance(pytestconfig, ConfigOptionsProxy):
+ self.config = pytestconfig.config
+ self.option = self.config.option
+ else:
+ self.config = pytestconfig
+ if self.config:
+ self.option = self.config.option
+ else:
+ self.option = ConfigOptionsProxy.DefNoneObject()
+
+ def getoption(self, opt, defval=None):
+ if not self.config:
+ return defval
+
+ try:
+ return self.config.getoption(opt, default=defval)
+ except ValueError:
+ return defval
+
+ def get_option(self, opt, defval=None):
+ return self.getoption(opt, defval)
+
+ def get_option_list(self, opt):
+ value = self.get_option(opt, "")
+ return cli_opt_list(value)
+
+ def name_in_option_list(self, name, opt):
+ optlist = self.get_option_list(opt)
+ return "all" in optlist or name in optlist
diff --git a/tests/topotests/munet/native.py b/tests/topotests/munet/native.py
index 5e79b04b8a..fecf709d1a 100644
--- a/tests/topotests/munet/native.py
+++ b/tests/topotests/munet/native.py
@@ -423,37 +423,37 @@ class NodeMixin:
stdout: file-like object with a ``name`` attribute, or a path to a file.
stderr: file-like object with a ``name`` attribute, or a path to a file.
"""
- if not self.unet or not self.unet.pytest_config:
+ if not self.unet:
return
- outopt = self.unet.pytest_config.getoption("--stdout")
+ outopt = self.unet.cfgopt.getoption("--stdout")
outopt = outopt if outopt is not None else ""
if outopt == "all" or self.name in outopt.split(","):
outname = stdout.name if hasattr(stdout, "name") else stdout
self.run_in_window(f"tail -F {outname}", title=f"O:{self.name}")
if stderr:
- erropt = self.unet.pytest_config.getoption("--stderr")
+ erropt = self.unet.cfgopt.getoption("--stderr")
erropt = erropt if erropt is not None else ""
if erropt == "all" or self.name in erropt.split(","):
errname = stderr.name if hasattr(stderr, "name") else stderr
self.run_in_window(f"tail -F {errname}", title=f"E:{self.name}")
def pytest_hook_open_shell(self):
- if not self.unet or not self.unet.pytest_config:
+ if not self.unet:
return
gdbcmd = self.config.get("gdb-cmd")
- shellopt = self.unet.pytest_config.getoption("--gdb", "")
+ shellopt = self.unet.cfgopt.getoption("--gdb", "")
should_gdb = gdbcmd and (shellopt == "all" or self.name in shellopt.split(","))
- use_emacs = self.unet.pytest_config.getoption("--gdb-use-emacs", False)
+ use_emacs = self.unet.cfgopt.getoption("--gdb-use-emacs", False)
if should_gdb and not use_emacs:
cmds = self.config.get("gdb-target-cmds", [])
for cmd in cmds:
gdbcmd += f" '-ex={cmd}'"
- bps = self.unet.pytest_config.getoption("--gdb-breakpoints", "").split(",")
+ bps = self.unet.cfgopt.getoption("--gdb-breakpoints", "").split(",")
for bp in bps:
gdbcmd += f" '-ex=b {bp}'"
@@ -497,7 +497,7 @@ class NodeMixin:
]
)
- bps = self.unet.pytest_config.getoption("--gdb-breakpoints", "").split(",")
+ bps = self.unet.cfgopt.getoption("--gdb-breakpoints", "").split(",")
for bp in bps:
cmd = f"br {bp}"
self.cmd_raises(
@@ -520,8 +520,8 @@ class NodeMixin:
)
gdbcmd += f" '-ex={cmd}'"
- shellopt = self.unet.pytest_config.getoption("--shell")
- shellopt = shellopt if shellopt is not None else ""
+ shellopt = self.unet.cfgopt.getoption("--shell")
+ shellopt = shellopt if shellopt else ""
if shellopt == "all" or self.name in shellopt.split(","):
self.run_in_window("bash")
@@ -1968,7 +1968,7 @@ class L3QemuVM(L3NodeMixin, LinuxNamespace):
con.cmd_raises(f"ip -6 route add default via {switch.ip6_address}")
con.cmd_raises("ip link set lo up")
- if self.unet.pytest_config and self.unet.pytest_config.getoption("--coverage"):
+ if self.unet.cfgopt.getoption("--coverage"):
con.cmd_raises("mount -t debugfs none /sys/kernel/debug")
async def gather_coverage_data(self):
@@ -2402,7 +2402,6 @@ class Munet(BaseMunet):
self,
rundir=None,
config=None,
- pytestconfig=None,
pid=True,
logger=None,
**kwargs,
@@ -2433,8 +2432,6 @@ class Munet(BaseMunet):
self.config_pathname = ""
self.config_dirname = ""
- self.pytest_config = pytestconfig
-
# Done in BaseMunet now
# # We need some way to actually get back to the root namespace
# if not self.isolated:
@@ -2573,10 +2570,8 @@ ff02::2\tip6-allrouters
# # Let's hide podman details
# self.tmpfs_mount("/var/lib/containers/storage/overlay-containers")
- shellopt = (
- self.pytest_config.getoption("--shell") if self.pytest_config else None
- )
- shellopt = shellopt if shellopt is not None else ""
+ shellopt = self.cfgopt.getoption("--shell")
+ shellopt = shellopt if shellopt else ""
if shellopt == "all" or "." in shellopt.split(","):
self.run_in_window("bash")
@@ -2795,11 +2790,8 @@ ff02::2\tip6-allrouters
x for x in hosts if hasattr(x, "has_ready_cmd") and x.has_ready_cmd()
]
- if not self.pytest_config:
- pcapopt = ""
- else:
- pcapopt = self.pytest_config.getoption("--pcap")
- pcapopt = pcapopt if pcapopt else ""
+ pcapopt = self.cfgopt.getoption("--pcap")
+ pcapopt = pcapopt if pcapopt else ""
if pcapopt == "all":
pcapopt = self.switches.keys()
if pcapopt:
@@ -2868,7 +2860,7 @@ ff02::2\tip6-allrouters
self.logger.debug("%s: deleting.", self)
- if self.pytest_config and self.pytest_config.getoption("--coverage"):
+ if self.cfgopt.getoption("--coverage"):
nodes = (
x for x in self.hosts.values() if hasattr(x, "gather_coverage_data")
)
@@ -2877,11 +2869,8 @@ ff02::2\tip6-allrouters
except Exception as error:
logging.warning("Error gathering coverage data: %s", error)
- if not self.pytest_config:
- pause = False
- else:
- pause = bool(self.pytest_config.getoption("--pause-at-end"))
- pause = pause or bool(self.pytest_config.getoption("--pause"))
+ pause = bool(self.cfgopt.getoption("--pause-at-end"))
+ pause = pause or bool(self.cfgopt.getoption("--pause"))
if pause:
try:
await async_pause_test("Before MUNET delete")
diff --git a/tests/topotests/munet/parser.py b/tests/topotests/munet/parser.py
index f92138d7b8..4fc0c75a60 100644
--- a/tests/topotests/munet/parser.py
+++ b/tests/topotests/munet/parser.py
@@ -235,7 +235,7 @@ def load_kinds(args, search=None):
if search is None:
search = [cwd]
with importlib.resources.path("munet", "kinds.yaml") as datapath:
- search.append(str(datapath.parent))
+ search.insert(0, str(datapath.parent))
configs = []
if args_config:
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index ccbc9d2a16..f779bf0a74 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -1,6 +1,8 @@
# Skip pytests example directory
[pytest]
+asyncio_mode = auto
+
# We always turn this on inside conftest.py, default shown
# addopts = --junitxml=<rundir>/topotests.xml
@@ -24,7 +26,7 @@ log_file_date_format = %Y-%m-%d %H:%M:%S
junit_logging = all
junit_log_passing_tests = true
-norecursedirs = .git example_test example_topojson_test lib munet docker
+norecursedirs = .git example_munet example_test example_topojson_test lib munet docker
# Directory to store test results and run logs in, default shown
# rundir = /tmp/topotests