kunit.py (50501936288d6a29d7ef78f25d00e33240fad45f) kunit.py (723c8258c8fe167191b53e274dea435c4522e4d7)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3#
4# A thin wrapper on top of the KUnit Kernel
5#
6# Copyright (C) 2019, Google LLC.
7# Author: Felix Guo <felixguoxiuping@gmail.com>
8# Author: Brendan Higgins <brendanhiggins@google.com>

--- 41 unchanged lines hidden (view full) ---

50 raw_output: Optional[str]
51 json: Optional[str]
52
53@dataclass
54class KunitExecRequest(KunitParseRequest):
55 build_dir: str
56 timeout: int
57 filter_glob: str
1#!/usr/bin/env python3
2# SPDX-License-Identifier: GPL-2.0
3#
4# A thin wrapper on top of the KUnit Kernel
5#
6# Copyright (C) 2019, Google LLC.
7# Author: Felix Guo <felixguoxiuping@gmail.com>
8# Author: Brendan Higgins <brendanhiggins@google.com>

--- 41 unchanged lines hidden (view full) ---

50 raw_output: Optional[str]
51 json: Optional[str]
52
53@dataclass
54class KunitExecRequest(KunitParseRequest):
55 build_dir: str
56 timeout: int
57 filter_glob: str
58 filter: str
59 filter_action: Optional[str]
58 kernel_args: Optional[List[str]]
59 run_isolated: Optional[str]
60 kernel_args: Optional[List[str]]
61 run_isolated: Optional[str]
62 list_tests: bool
63 list_tests_attr: bool
60
61@dataclass
62class KunitRequest(KunitExecRequest, KunitBuildRequest):
63 pass
64
65
66def get_kernel_root_path() -> str:
67 path = sys.argv[0] if not __file__ else __file__

--- 29 unchanged lines hidden (view full) ---

97 config_result = config_tests(linux, request)
98 if config_result.status != KunitStatus.SUCCESS:
99 return config_result
100
101 return build_tests(linux, request)
102
103def _list_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> List[str]:
104 args = ['kunit.action=list']
64
65@dataclass
66class KunitRequest(KunitExecRequest, KunitBuildRequest):
67 pass
68
69
70def get_kernel_root_path() -> str:
71 path = sys.argv[0] if not __file__ else __file__

--- 29 unchanged lines hidden (view full) ---

101 config_result = config_tests(linux, request)
102 if config_result.status != KunitStatus.SUCCESS:
103 return config_result
104
105 return build_tests(linux, request)
106
107def _list_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> List[str]:
108 args = ['kunit.action=list']
109
105 if request.kernel_args:
106 args.extend(request.kernel_args)
107
108 output = linux.run_kernel(args=args,
109 timeout=request.timeout,
110 filter_glob=request.filter_glob,
110 if request.kernel_args:
111 args.extend(request.kernel_args)
112
113 output = linux.run_kernel(args=args,
114 timeout=request.timeout,
115 filter_glob=request.filter_glob,
116 filter=request.filter,
117 filter_action=request.filter_action,
111 build_dir=request.build_dir)
112 lines = kunit_parser.extract_tap_lines(output)
113 # Hack! Drop the dummy TAP version header that the executor prints out.
114 lines.pop()
115
116 # Filter out any extraneous non-test output that might have gotten mixed in.
118 build_dir=request.build_dir)
119 lines = kunit_parser.extract_tap_lines(output)
120 # Hack! Drop the dummy TAP version header that the executor prints out.
121 lines.pop()
122
123 # Filter out any extraneous non-test output that might have gotten mixed in.
117 return [l for l in lines if re.match(r'^[^\s.]+\.[^\s.]+$', l)]
124 return [l for l in output if re.match(r'^[^\s.]+\.[^\s.]+$', l)]
118
125
126def _list_tests_attr(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> Iterable[str]:
127 args = ['kunit.action=list_attr']
128
129 if request.kernel_args:
130 args.extend(request.kernel_args)
131
132 output = linux.run_kernel(args=args,
133 timeout=request.timeout,
134 filter_glob=request.filter_glob,
135 filter=request.filter,
136 filter_action=request.filter_action,
137 build_dir=request.build_dir)
138 lines = kunit_parser.extract_tap_lines(output)
139 # Hack! Drop the dummy TAP version header that the executor prints out.
140 lines.pop()
141
142 # Filter out any extraneous non-test output that might have gotten mixed in.
143 return lines
144
119def _suites_from_test_list(tests: List[str]) -> List[str]:
120 """Extracts all the suites from an ordered list of tests."""
121 suites = [] # type: List[str]
122 for t in tests:
123 parts = t.split('.', maxsplit=2)
124 if len(parts) != 2:
125 raise ValueError(f'internal KUnit error, test name should be of the form "<suite>.<test>", got "{t}"')
126 suite, _ = parts
127 if not suites or suites[-1] != suite:
128 suites.append(suite)
129 return suites
130
145def _suites_from_test_list(tests: List[str]) -> List[str]:
146 """Extracts all the suites from an ordered list of tests."""
147 suites = [] # type: List[str]
148 for t in tests:
149 parts = t.split('.', maxsplit=2)
150 if len(parts) != 2:
151 raise ValueError(f'internal KUnit error, test name should be of the form "<suite>.<test>", got "{t}"')
152 suite, _ = parts
153 if not suites or suites[-1] != suite:
154 suites.append(suite)
155 return suites
156
131
132
133def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> KunitResult:
134 filter_globs = [request.filter_glob]
157def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> KunitResult:
158 filter_globs = [request.filter_glob]
159 if request.list_tests:
160 output = _list_tests(linux, request)
161 for line in output:
162 print(line.rstrip())
163 return KunitResult(status=KunitStatus.SUCCESS, elapsed_time=0.0)
164 if request.list_tests_attr:
165 attr_output = _list_tests_attr(linux, request)
166 for line in attr_output:
167 print(line.rstrip())
168 return KunitResult(status=KunitStatus.SUCCESS, elapsed_time=0.0)
135 if request.run_isolated:
136 tests = _list_tests(linux, request)
137 if request.run_isolated == 'test':
138 filter_globs = tests
139 elif request.run_isolated == 'suite':
140 filter_globs = _suites_from_test_list(tests)
141 # Apply the test-part of the user's glob, if present.
142 if '.' in request.filter_glob:

--- 7 unchanged lines hidden (view full) ---

150 for i, filter_glob in enumerate(filter_globs):
151 stdout.print_with_timestamp('Starting KUnit Kernel ({}/{})...'.format(i+1, len(filter_globs)))
152
153 test_start = time.time()
154 run_result = linux.run_kernel(
155 args=request.kernel_args,
156 timeout=request.timeout,
157 filter_glob=filter_glob,
169 if request.run_isolated:
170 tests = _list_tests(linux, request)
171 if request.run_isolated == 'test':
172 filter_globs = tests
173 elif request.run_isolated == 'suite':
174 filter_globs = _suites_from_test_list(tests)
175 # Apply the test-part of the user's glob, if present.
176 if '.' in request.filter_glob:

--- 7 unchanged lines hidden (view full) ---

184 for i, filter_glob in enumerate(filter_globs):
185 stdout.print_with_timestamp('Starting KUnit Kernel ({}/{})...'.format(i+1, len(filter_globs)))
186
187 test_start = time.time()
188 run_result = linux.run_kernel(
189 args=request.kernel_args,
190 timeout=request.timeout,
191 filter_glob=filter_glob,
192 filter=request.filter,
193 filter_action=request.filter_action,
158 build_dir=request.build_dir)
159
160 _, test_result = parse_tests(request, metadata, run_result)
161 # run_kernel() doesn't block on the kernel exiting.
162 # That only happens after we get the last line of output from `run_result`.
163 # So exec_time here actually contains parsing + execution time, which is fine.
164 test_end = time.time()
165 exec_time += test_end - test_start

--- 170 unchanged lines hidden (view full) ---

336 metavar='SECONDS')
337 parser.add_argument('filter_glob',
338 help='Filter which KUnit test suites/tests run at '
339 'boot-time, e.g. list* or list*.*del_test',
340 type=str,
341 nargs='?',
342 default='',
343 metavar='filter_glob')
194 build_dir=request.build_dir)
195
196 _, test_result = parse_tests(request, metadata, run_result)
197 # run_kernel() doesn't block on the kernel exiting.
198 # That only happens after we get the last line of output from `run_result`.
199 # So exec_time here actually contains parsing + execution time, which is fine.
200 test_end = time.time()
201 exec_time += test_end - test_start

--- 170 unchanged lines hidden (view full) ---

372 metavar='SECONDS')
373 parser.add_argument('filter_glob',
374 help='Filter which KUnit test suites/tests run at '
375 'boot-time, e.g. list* or list*.*del_test',
376 type=str,
377 nargs='?',
378 default='',
379 metavar='filter_glob')
380 parser.add_argument('--filter',
381 help='Filter KUnit tests with attributes, '
382 'e.g. module=example or speed>slow',
383 type=str,
384 default='')
385 parser.add_argument('--filter_action',
386 help='If set to skip, filtered tests will be skipped, '
387 'e.g. --filter_action=skip. Otherwise they will not run.',
388 type=str,
389 choices=['skip'])
344 parser.add_argument('--kernel_args',
345 help='Kernel command-line parameters. Maybe be repeated',
346 action='append', metavar='')
347 parser.add_argument('--run_isolated', help='If set, boot the kernel for each '
348 'individual suite/test. This is can be useful for debugging '
349 'a non-hermetic test, one that might pass/fail based on '
350 'what ran before it.',
351 type=str,
352 choices=['suite', 'test'])
390 parser.add_argument('--kernel_args',
391 help='Kernel command-line parameters. Maybe be repeated',
392 action='append', metavar='')
393 parser.add_argument('--run_isolated', help='If set, boot the kernel for each '
394 'individual suite/test. This is can be useful for debugging '
395 'a non-hermetic test, one that might pass/fail based on '
396 'what ran before it.',
397 type=str,
398 choices=['suite', 'test'])
399 parser.add_argument('--list_tests', help='If set, list all tests that will be '
400 'run.',
401 action='store_true')
402 parser.add_argument('--list_tests_attr', help='If set, list all tests and test '
403 'attributes.',
404 action='store_true')
353
354def add_parse_opts(parser: argparse.ArgumentParser) -> None:
355 parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
356 'By default, filters to just KUnit output. Use '
357 '--raw_output=all to show everything',
358 type=str, nargs='?', const='all', default=None, choices=['all', 'kunit'])
359 parser.add_argument('--json',
360 nargs='?',

--- 32 unchanged lines hidden (view full) ---

393 linux = tree_from_args(cli_args)
394 request = KunitRequest(build_dir=cli_args.build_dir,
395 make_options=cli_args.make_options,
396 jobs=cli_args.jobs,
397 raw_output=cli_args.raw_output,
398 json=cli_args.json,
399 timeout=cli_args.timeout,
400 filter_glob=cli_args.filter_glob,
405
406def add_parse_opts(parser: argparse.ArgumentParser) -> None:
407 parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
408 'By default, filters to just KUnit output. Use '
409 '--raw_output=all to show everything',
410 type=str, nargs='?', const='all', default=None, choices=['all', 'kunit'])
411 parser.add_argument('--json',
412 nargs='?',

--- 32 unchanged lines hidden (view full) ---

445 linux = tree_from_args(cli_args)
446 request = KunitRequest(build_dir=cli_args.build_dir,
447 make_options=cli_args.make_options,
448 jobs=cli_args.jobs,
449 raw_output=cli_args.raw_output,
450 json=cli_args.json,
451 timeout=cli_args.timeout,
452 filter_glob=cli_args.filter_glob,
453 filter=cli_args.filter,
454 filter_action=cli_args.filter_action,
401 kernel_args=cli_args.kernel_args,
455 kernel_args=cli_args.kernel_args,
402 run_isolated=cli_args.run_isolated)
456 run_isolated=cli_args.run_isolated,
457 list_tests=cli_args.list_tests,
458 list_tests_attr=cli_args.list_tests_attr)
403 result = run_tests(linux, request)
404 if result.status != KunitStatus.SUCCESS:
405 sys.exit(1)
406
407
408def config_handler(cli_args: argparse.Namespace) -> None:
409 if cli_args.build_dir and (
410 not os.path.exists(cli_args.build_dir)):

--- 25 unchanged lines hidden (view full) ---

436
437def exec_handler(cli_args: argparse.Namespace) -> None:
438 linux = tree_from_args(cli_args)
439 exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
440 build_dir=cli_args.build_dir,
441 json=cli_args.json,
442 timeout=cli_args.timeout,
443 filter_glob=cli_args.filter_glob,
459 result = run_tests(linux, request)
460 if result.status != KunitStatus.SUCCESS:
461 sys.exit(1)
462
463
464def config_handler(cli_args: argparse.Namespace) -> None:
465 if cli_args.build_dir and (
466 not os.path.exists(cli_args.build_dir)):

--- 25 unchanged lines hidden (view full) ---

492
493def exec_handler(cli_args: argparse.Namespace) -> None:
494 linux = tree_from_args(cli_args)
495 exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
496 build_dir=cli_args.build_dir,
497 json=cli_args.json,
498 timeout=cli_args.timeout,
499 filter_glob=cli_args.filter_glob,
500 filter=cli_args.filter,
501 filter_action=cli_args.filter_action,
444 kernel_args=cli_args.kernel_args,
502 kernel_args=cli_args.kernel_args,
445 run_isolated=cli_args.run_isolated)
503 run_isolated=cli_args.run_isolated,
504 list_tests=cli_args.list_tests,
505 list_tests_attr=cli_args.list_tests_attr)
446 result = exec_tests(linux, exec_request)
447 stdout.print_with_timestamp((
448 'Elapsed time: %.3fs\n') % (result.elapsed_time))
449 if result.status != KunitStatus.SUCCESS:
450 sys.exit(1)
451
452
453def parse_handler(cli_args: argparse.Namespace) -> None:

--- 78 unchanged lines hidden ---
506 result = exec_tests(linux, exec_request)
507 stdout.print_with_timestamp((
508 'Elapsed time: %.3fs\n') % (result.elapsed_time))
509 if result.status != KunitStatus.SUCCESS:
510 sys.exit(1)
511
512
513def parse_handler(cli_args: argparse.Namespace) -> None:

--- 78 unchanged lines hidden ---