Commit f8793068 authored by Stanislav Fomichev's avatar Stanislav Fomichev Committed by Jakub Kicinski

selftests: net: ksft: support marking tests as disruptive

Add new @ksft_disruptive decorator to mark the tests that might
be disruptive to the system. Depending on how well the previous
test works in the CI we might want to disable disruptive tests
by default and only let the developers run them manually.

KSFT framework runs disruptive tests by default. DISRUPTIVE=False
environment (or config file) can be used to disable these tests.
ksft_setup should be called by the test cases that want to use
new decorator (ksft_setup is only called via NetDrvEnv/NetDrvEpEnv for now).

In the future we can add similar decorators to, for example, avoid
running slow tests all the time. And/or have some option to run
only 'fast' tests for some sort of smoke test scenario.

  $ DISRUPTIVE=False ./stats.py
  KTAP version 1
  1..5
  ok 1 stats.check_pause
  ok 2 stats.check_fec
  ok 3 stats.pkt_byte_sum
  ok 4 stats.qstat_by_ifindex
  ok 5 stats.check_down # SKIP marked as disruptive
  # Totals: pass:4 fail:0 xfail:0 xpass:0 skip:1 error:0

v3:
- parse yes and properly treat non-zero nums as true (Petr)

v2:
- convert from cli argument to env variable (Jakub)
Signed-off-by: default avatarStanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20240802000309.2368-2-sdf@fomichev.meSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent ab100097
...@@ -4,6 +4,7 @@ import os ...@@ -4,6 +4,7 @@ import os
import time import time
from pathlib import Path from pathlib import Path
from lib.py import KsftSkipEx, KsftXfailEx from lib.py import KsftSkipEx, KsftXfailEx
from lib.py import ksft_setup
from lib.py import cmd, ethtool, ip from lib.py import cmd, ethtool, ip
from lib.py import NetNS, NetdevSimDev from lib.py import NetNS, NetdevSimDev
from .remote import Remote from .remote import Remote
...@@ -14,7 +15,7 @@ def _load_env_file(src_path): ...@@ -14,7 +15,7 @@ def _load_env_file(src_path):
src_dir = Path(src_path).parent.resolve() src_dir = Path(src_path).parent.resolve()
if not (src_dir / "net.config").exists(): if not (src_dir / "net.config").exists():
return env return ksft_setup(env)
with open((src_dir / "net.config").as_posix(), 'r') as fp: with open((src_dir / "net.config").as_posix(), 'r') as fp:
for line in fp.readlines(): for line in fp.readlines():
...@@ -30,7 +31,7 @@ def _load_env_file(src_path): ...@@ -30,7 +31,7 @@ def _load_env_file(src_path):
if len(pair) != 2: if len(pair) != 2:
raise Exception("Can't parse configuration line:", full_file) raise Exception("Can't parse configuration line:", full_file)
env[pair[0]] = pair[1] env[pair[0]] = pair[1]
return env return ksft_setup(env)
class NetDrvEnv: class NetDrvEnv:
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import errno import errno
from lib.py import ksft_run, ksft_exit, ksft_pr from lib.py import ksft_run, ksft_exit, ksft_pr
from lib.py import ksft_ge, ksft_eq, ksft_in, ksft_true, ksft_raises, KsftSkipEx, KsftXfailEx from lib.py import ksft_ge, ksft_eq, ksft_in, ksft_true, ksft_raises, KsftSkipEx, KsftXfailEx
from lib.py import ksft_disruptive
from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError
from lib.py import NetDrvEnv from lib.py import NetDrvEnv
from lib.py import ip, defer from lib.py import ip, defer
...@@ -135,6 +136,7 @@ def qstat_by_ifindex(cfg) -> None: ...@@ -135,6 +136,7 @@ def qstat_by_ifindex(cfg) -> None:
ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex') ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex')
@ksft_disruptive
def check_down(cfg) -> None: def check_down(cfg) -> None:
try: try:
qstat = netfam.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0] qstat = netfam.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
import builtins import builtins
import functools
import inspect import inspect
import sys import sys
import time import time
...@@ -10,6 +11,7 @@ from .utils import global_defer_queue ...@@ -10,6 +11,7 @@ from .utils import global_defer_queue
KSFT_RESULT = None KSFT_RESULT = None
KSFT_RESULT_ALL = True KSFT_RESULT_ALL = True
KSFT_DISRUPTIVE = True
class KsftFailEx(Exception): class KsftFailEx(Exception):
...@@ -127,6 +129,44 @@ def ksft_flush_defer(): ...@@ -127,6 +129,44 @@ def ksft_flush_defer():
KSFT_RESULT = False KSFT_RESULT = False
def ksft_disruptive(func):
"""
Decorator that marks the test as disruptive (e.g. the test
that can down the interface). Disruptive tests can be skipped
by passing DISRUPTIVE=False environment variable.
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
if not KSFT_DISRUPTIVE:
raise KsftSkipEx(f"marked as disruptive")
return func(*args, **kwargs)
return wrapper
def ksft_setup(env):
"""
Setup test framework global state from the environment.
"""
def get_bool(env, name):
value = env.get(name, "").lower()
if value in ["yes", "true"]:
return True
if value in ["no", "false"]:
return False
try:
return bool(int(value))
except:
raise Exception(f"failed to parse {name}")
if "DISRUPTIVE" in env:
global KSFT_DISRUPTIVE
KSFT_DISRUPTIVE = get_bool(env, "DISRUPTIVE")
return env
def ksft_run(cases=None, globs=None, case_pfx=None, args=()): def ksft_run(cases=None, globs=None, case_pfx=None, args=()):
cases = cases or [] cases = cases or []
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment