Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Stanislav Fomichev <sdf@fomichev.me>
Link: https://patch.msgid.link/20240802000309.2368-2-sdf@fomichev.me
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Stanislav Fomichev and committed by
Jakub Kicinski
f8793068 ab100097

+45 -2
+3 -2
tools/testing/selftests/drivers/net/lib/py/env.py
··· 4 4 import time 5 5 from pathlib import Path 6 6 from lib.py import KsftSkipEx, KsftXfailEx 7 + from lib.py import ksft_setup 7 8 from lib.py import cmd, ethtool, ip 8 9 from lib.py import NetNS, NetdevSimDev 9 10 from .remote import Remote ··· 15 14 16 15 src_dir = Path(src_path).parent.resolve() 17 16 if not (src_dir / "net.config").exists(): 18 - return env 17 + return ksft_setup(env) 19 18 20 19 with open((src_dir / "net.config").as_posix(), 'r') as fp: 21 20 for line in fp.readlines(): ··· 31 30 if len(pair) != 2: 32 31 raise Exception("Can't parse configuration line:", full_file) 33 32 env[pair[0]] = pair[1] 34 - return env 33 + return ksft_setup(env) 35 34 36 35 37 36 class NetDrvEnv:
+2
tools/testing/selftests/drivers/net/stats.py
··· 4 4 import errno 5 5 from lib.py import ksft_run, ksft_exit, ksft_pr 6 6 from lib.py import ksft_ge, ksft_eq, ksft_in, ksft_true, ksft_raises, KsftSkipEx, KsftXfailEx 7 + from lib.py import ksft_disruptive 7 8 from lib.py import EthtoolFamily, NetdevFamily, RtnlFamily, NlError 8 9 from lib.py import NetDrvEnv 9 10 from lib.py import ip, defer ··· 136 135 ksft_eq(cm.exception.nl_msg.extack['bad-attr'], '.ifindex') 137 136 138 137 138 + @ksft_disruptive 139 139 def check_down(cfg) -> None: 140 140 try: 141 141 qstat = netfam.qstats_get({"ifindex": cfg.ifindex}, dump=True)[0]
+40
tools/testing/selftests/net/lib/py/ksft.py
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 import builtins 4 + import functools 4 5 import inspect 5 6 import sys 6 7 import time ··· 11 10 12 11 KSFT_RESULT = None 13 12 KSFT_RESULT_ALL = True 13 + KSFT_DISRUPTIVE = True 14 14 15 15 16 16 class KsftFailEx(Exception): ··· 127 125 for line in tb.strip().split('\n'): 128 126 ksft_pr("Defer Exception|", line) 129 127 KSFT_RESULT = False 128 + 129 + 130 + def ksft_disruptive(func): 131 + """ 132 + Decorator that marks the test as disruptive (e.g. the test 133 + that can down the interface). Disruptive tests can be skipped 134 + by passing DISRUPTIVE=False environment variable. 135 + """ 136 + 137 + @functools.wraps(func) 138 + def wrapper(*args, **kwargs): 139 + if not KSFT_DISRUPTIVE: 140 + raise KsftSkipEx(f"marked as disruptive") 141 + return func(*args, **kwargs) 142 + return wrapper 143 + 144 + 145 + def ksft_setup(env): 146 + """ 147 + Setup test framework global state from the environment. 148 + """ 149 + 150 + def get_bool(env, name): 151 + value = env.get(name, "").lower() 152 + if value in ["yes", "true"]: 153 + return True 154 + if value in ["no", "false"]: 155 + return False 156 + try: 157 + return bool(int(value)) 158 + except: 159 + raise Exception(f"failed to parse {name}") 160 + 161 + if "DISRUPTIVE" in env: 162 + global KSFT_DISRUPTIVE 163 + KSFT_DISRUPTIVE = get_bool(env, "DISRUPTIVE") 164 + 165 + return env 130 166 131 167 132 168 def ksft_run(cases=None, globs=None, case_pfx=None, args=()):