[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87ecpucbt7.fsf@nvidia.com>
Date: Wed, 19 Nov 2025 15:42:39 +0100
From: Petr Machata <petrm@...dia.com>
To: Jakub Kicinski <kuba@...nel.org>
CC: <davem@...emloft.net>, <netdev@...r.kernel.org>, <edumazet@...gle.com>,
<pabeni@...hat.com>, <andrew+netdev@...n.ch>, <horms@...nel.org>,
<willemdebruijn.kernel@...il.com>, <shuah@...nel.org>, <sdf@...ichev.me>,
<krakauer@...gle.com>, <linux-kselftest@...r.kernel.org>, <petrm@...dia.com>,
<matttbe@...nel.org>
Subject: Re: [PATCH net-next v2 03/12] selftests: net: py: add test variants
Jakub Kicinski <kuba@...nel.org> writes:
> diff --git a/tools/testing/selftests/net/lib/py/ksft.py b/tools/testing/selftests/net/lib/py/ksft.py
> index 52c42c313cf2..47e0af210bee 100644
> --- a/tools/testing/selftests/net/lib/py/ksft.py
> +++ b/tools/testing/selftests/net/lib/py/ksft.py
> @@ -185,6 +185,49 @@ KSFT_DISRUPTIVE = True
> return wrapper
>
>
> +class KsftNamedVariant:
> + """ Named string name + argument list tuple for @ksft_variants """
> +
> + def __init__(self, name, *params):
> + self.params = params
> + self.name = name or "_".join([str(x) for x in self.params])
> +
> +
> +def ksft_variants(params):
> + """
> + Decorator defining the sets of inputs for a test.
> + The parameters will be included in the name of the resulting sub-case.
> + Parameters can be either single object, tuple or a KsftNamedVariant.
> + The argument can be a list or a generator.
> +
> + Example:
> +
> + @ksft_variants([
> + (1, "a"),
> + (2, "b"),
> + KsftNamedVariant("three", 3, "c"),
> + ])
> + def my_case(cfg, a, b):
> + pass # ...
> +
> + ksft_run(cases=[my_case], args=(cfg, ))
> +
> + Will generate cases:
> + my_case.1_a
> + my_case.2_b
> + my_case.three
> + """
> +
> + def decorator(func):
> + @functools.wraps(func)
> + def wrapper():
> + return func
> + wrapper.ksft_variants = params
> + wrapper.original_func = func
> + return wrapper
> + return decorator
This uses the wrapper() merely as a vessel to carry the three
attributes. I think the idea would be better expressed as a namedtupple
from collections import namedtuple
KsftCaseFunction = namedtuple("KsftCaseFunction",
['name', 'original_func', 'variants'])
def ksft_variants(params):
return lambda func: KsftCaseFunction(func.__name__, func, params)
> +
> +
> def ksft_setup(env):
> """
> Setup test framework global state from the environment.
> @@ -236,7 +279,19 @@ KSFT_DISRUPTIVE = True
> break
>
> for func in cases:
> - test_cases.append((func, args, func.__name__))
> + if hasattr(func, 'ksft_variants'):
Then this could just be if callable(func) just call it, else the complex
processing.
I'm not married to the namedtuple idea, but I consider using a function
as essentially a struct wrong. It should be a general object.
> + # Parametrized test - create case for each param
> + for param in func.ksft_variants:
> + if not isinstance(param, KsftNamedVariant):
> + if not isinstance(param, tuple):
> + param = (param, )
> + param = KsftNamedVariant(None, *param)
> +
> + test_cases.append((func.original_func,
> + (*args, *param.params),
> + func.__name__ + "." + param.name))
> + else:
> + test_cases.append((func, args, func.__name__))
>
> return test_cases
Powered by blists - more mailing lists