Skip to content

Commit db16798

Browse files
dlatypovshuahkh
authored andcommitted
kunit: tool: use dataclass instead of collections.namedtuple
namedtuple is a terse way of defining a collection of fields. However, it does not allow us to annotate the type of these fields. It also doesn't let us have any sort of inheritance between types. Since commit df4b080 ("kunit: tool: Assert the version requirement"), kunit.py has asserted that it's running on python >=3.7. So in that case use a 3.7 feature, dataclasses, to replace these. Changes in detail: * Make KunitExecRequest contain all the fields needed for exec_tests * Use inheritance to dedupe fields * also allows us to e.g. pass a KUnitRequest in as a KUnitParseRequest * this has changed around the order of some fields * Use named arguments when constructing all request objects in kunit.py * This is to prevent accidentally mixing up fields, etc. Signed-off-by: Daniel Latypov <[email protected]> Reviewed-by: Brendan Higgins <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent 7fa7ffc commit db16798

File tree

2 files changed

+75
-70
lines changed

2 files changed

+75
-70
lines changed

tools/testing/kunit/kunit.py

Lines changed: 72 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,57 @@
1515

1616
assert sys.version_info >= (3, 7), "Python version is too old"
1717

18-
from collections import namedtuple
18+
from dataclasses import dataclass
1919
from enum import Enum, auto
20-
from typing import Iterable, Sequence, List
20+
from typing import Any, Iterable, Sequence, List, Optional
2121

2222
import kunit_json
2323
import kunit_kernel
2424
import kunit_parser
2525

26-
KunitResult = namedtuple('KunitResult', ['status','result','elapsed_time'])
27-
28-
KunitConfigRequest = namedtuple('KunitConfigRequest',
29-
['build_dir', 'make_options'])
30-
KunitBuildRequest = namedtuple('KunitBuildRequest',
31-
['jobs', 'build_dir', 'alltests',
32-
'make_options'])
33-
KunitExecRequest = namedtuple('KunitExecRequest',
34-
['timeout', 'build_dir', 'alltests',
35-
'filter_glob', 'kernel_args', 'run_isolated'])
36-
KunitParseRequest = namedtuple('KunitParseRequest',
37-
['raw_output', 'build_dir', 'json'])
38-
KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs',
39-
'build_dir', 'alltests', 'filter_glob',
40-
'kernel_args', 'run_isolated', 'json', 'make_options'])
41-
42-
KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
43-
4426
class KunitStatus(Enum):
4527
SUCCESS = auto()
4628
CONFIG_FAILURE = auto()
4729
BUILD_FAILURE = auto()
4830
TEST_FAILURE = auto()
4931

32+
@dataclass
33+
class KunitResult:
34+
status: KunitStatus
35+
result: Any
36+
elapsed_time: float
37+
38+
@dataclass
39+
class KunitConfigRequest:
40+
build_dir: str
41+
make_options: Optional[List[str]]
42+
43+
@dataclass
44+
class KunitBuildRequest(KunitConfigRequest):
45+
jobs: int
46+
alltests: bool
47+
48+
@dataclass
49+
class KunitParseRequest:
50+
raw_output: Optional[str]
51+
build_dir: str
52+
json: Optional[str]
53+
54+
@dataclass
55+
class KunitExecRequest(KunitParseRequest):
56+
timeout: int
57+
alltests: bool
58+
filter_glob: str
59+
kernel_args: Optional[List[str]]
60+
run_isolated: Optional[str]
61+
62+
@dataclass
63+
class KunitRequest(KunitExecRequest, KunitBuildRequest):
64+
pass
65+
66+
67+
KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
68+
5069
def get_kernel_root_path() -> str:
5170
path = sys.argv[0] if not __file__ else __file__
5271
parts = os.path.realpath(path).split('tools/testing/kunit')
@@ -121,8 +140,7 @@ def _suites_from_test_list(tests: List[str]) -> List[str]:
121140

122141

123142

124-
def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest,
125-
parse_request: KunitParseRequest) -> KunitResult:
143+
def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> KunitResult:
126144
filter_globs = [request.filter_glob]
127145
if request.run_isolated:
128146
tests = _list_tests(linux, request)
@@ -147,7 +165,7 @@ def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest,
147165
filter_glob=filter_glob,
148166
build_dir=request.build_dir)
149167

150-
result = parse_tests(parse_request, run_result)
168+
result = parse_tests(request, run_result)
151169
# run_kernel() doesn't block on the kernel exiting.
152170
# That only happens after we get the last line of output from `run_result`.
153171
# So exec_time here actually contains parsing + execution time, which is fine.
@@ -217,27 +235,15 @@ def run_tests(linux: kunit_kernel.LinuxSourceTree,
217235
request: KunitRequest) -> KunitResult:
218236
run_start = time.time()
219237

220-
config_request = KunitConfigRequest(request.build_dir,
221-
request.make_options)
222-
config_result = config_tests(linux, config_request)
238+
config_result = config_tests(linux, request)
223239
if config_result.status != KunitStatus.SUCCESS:
224240
return config_result
225241

226-
build_request = KunitBuildRequest(request.jobs, request.build_dir,
227-
request.alltests,
228-
request.make_options)
229-
build_result = build_tests(linux, build_request)
242+
build_result = build_tests(linux, request)
230243
if build_result.status != KunitStatus.SUCCESS:
231244
return build_result
232245

233-
exec_request = KunitExecRequest(request.timeout, request.build_dir,
234-
request.alltests, request.filter_glob,
235-
request.kernel_args, request.run_isolated)
236-
parse_request = KunitParseRequest(request.raw_output,
237-
request.build_dir,
238-
request.json)
239-
240-
exec_result = exec_tests(linux, exec_request, parse_request)
246+
exec_result = exec_tests(linux, request)
241247

242248
run_end = time.time()
243249

@@ -413,16 +419,16 @@ def main(argv, linux=None):
413419
cross_compile=cli_args.cross_compile,
414420
qemu_config_path=cli_args.qemu_config)
415421

416-
request = KunitRequest(cli_args.raw_output,
417-
cli_args.timeout,
418-
cli_args.jobs,
419-
cli_args.build_dir,
420-
cli_args.alltests,
421-
cli_args.filter_glob,
422-
cli_args.kernel_args,
423-
cli_args.run_isolated,
424-
cli_args.json,
425-
cli_args.make_options)
422+
request = KunitRequest(build_dir=cli_args.build_dir,
423+
make_options=cli_args.make_options,
424+
jobs=cli_args.jobs,
425+
alltests=cli_args.alltests,
426+
raw_output=cli_args.raw_output,
427+
json=cli_args.json,
428+
timeout=cli_args.timeout,
429+
filter_glob=cli_args.filter_glob,
430+
kernel_args=cli_args.kernel_args,
431+
run_isolated=cli_args.run_isolated)
426432
result = run_tests(linux, request)
427433
if result.status != KunitStatus.SUCCESS:
428434
sys.exit(1)
@@ -439,8 +445,8 @@ def main(argv, linux=None):
439445
cross_compile=cli_args.cross_compile,
440446
qemu_config_path=cli_args.qemu_config)
441447

442-
request = KunitConfigRequest(cli_args.build_dir,
443-
cli_args.make_options)
448+
request = KunitConfigRequest(build_dir=cli_args.build_dir,
449+
make_options=cli_args.make_options)
444450
result = config_tests(linux, request)
445451
kunit_parser.print_with_timestamp((
446452
'Elapsed time: %.3fs\n') % (
@@ -456,10 +462,10 @@ def main(argv, linux=None):
456462
cross_compile=cli_args.cross_compile,
457463
qemu_config_path=cli_args.qemu_config)
458464

459-
request = KunitBuildRequest(cli_args.jobs,
460-
cli_args.build_dir,
461-
cli_args.alltests,
462-
cli_args.make_options)
465+
request = KunitBuildRequest(build_dir=cli_args.build_dir,
466+
make_options=cli_args.make_options,
467+
jobs=cli_args.jobs,
468+
alltests=cli_args.alltests)
463469
result = build_tests(linux, request)
464470
kunit_parser.print_with_timestamp((
465471
'Elapsed time: %.3fs\n') % (
@@ -475,16 +481,15 @@ def main(argv, linux=None):
475481
cross_compile=cli_args.cross_compile,
476482
qemu_config_path=cli_args.qemu_config)
477483

478-
exec_request = KunitExecRequest(cli_args.timeout,
479-
cli_args.build_dir,
480-
cli_args.alltests,
481-
cli_args.filter_glob,
482-
cli_args.kernel_args,
483-
cli_args.run_isolated)
484-
parse_request = KunitParseRequest(cli_args.raw_output,
485-
cli_args.build_dir,
486-
cli_args.json)
487-
result = exec_tests(linux, exec_request, parse_request)
484+
exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
485+
build_dir=cli_args.build_dir,
486+
json=cli_args.json,
487+
timeout=cli_args.timeout,
488+
alltests=cli_args.alltests,
489+
filter_glob=cli_args.filter_glob,
490+
kernel_args=cli_args.kernel_args,
491+
run_isolated=cli_args.run_isolated)
492+
result = exec_tests(linux, exec_request)
488493
kunit_parser.print_with_timestamp((
489494
'Elapsed time: %.3fs\n') % (result.elapsed_time))
490495
if result.status != KunitStatus.SUCCESS:
@@ -496,9 +501,9 @@ def main(argv, linux=None):
496501
else:
497502
with open(cli_args.file, 'r', errors='backslashreplace') as f:
498503
kunit_output = f.read().splitlines()
499-
request = KunitParseRequest(cli_args.raw_output,
500-
None,
501-
cli_args.json)
504+
request = KunitParseRequest(raw_output=cli_args.raw_output,
505+
build_dir='',
506+
json=cli_args.json)
502507
result = parse_tests(request, kunit_output)
503508
if result.status != KunitStatus.SUCCESS:
504509
sys.exit(1)

tools/testing/kunit/kunit_tool_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ def test_list_tests(self):
691691
self.linux_source_mock.run_kernel.return_value = ['TAP version 14', 'init: random output'] + want
692692

693693
got = kunit._list_tests(self.linux_source_mock,
694-
kunit.KunitExecRequest(300, '.kunit', False, 'suite*', None, 'suite'))
694+
kunit.KunitExecRequest(None, '.kunit', None, 300, False, 'suite*', None, 'suite'))
695695

696696
self.assertEqual(got, want)
697697
# Should respect the user's filter glob when listing tests.
@@ -706,7 +706,7 @@ def test_run_isolated_by_suite(self, mock_tests):
706706

707707
# Should respect the user's filter glob when listing tests.
708708
mock_tests.assert_called_once_with(mock.ANY,
709-
kunit.KunitExecRequest(300, '.kunit', False, 'suite*.test*', None, 'suite'))
709+
kunit.KunitExecRequest(None, '.kunit', None, 300, False, 'suite*.test*', None, 'suite'))
710710
self.linux_source_mock.run_kernel.assert_has_calls([
711711
mock.call(args=None, build_dir='.kunit', filter_glob='suite.test*', timeout=300),
712712
mock.call(args=None, build_dir='.kunit', filter_glob='suite2.test*', timeout=300),
@@ -719,7 +719,7 @@ def test_run_isolated_by_test(self, mock_tests):
719719

720720
# Should respect the user's filter glob when listing tests.
721721
mock_tests.assert_called_once_with(mock.ANY,
722-
kunit.KunitExecRequest(300, '.kunit', False, 'suite*', None, 'test'))
722+
kunit.KunitExecRequest(None, '.kunit', None, 300, False, 'suite*', None, 'test'))
723723
self.linux_source_mock.run_kernel.assert_has_calls([
724724
mock.call(args=None, build_dir='.kunit', filter_glob='suite.test1', timeout=300),
725725
mock.call(args=None, build_dir='.kunit', filter_glob='suite.test2', timeout=300),

0 commit comments

Comments
 (0)