~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/kunit/kunit.py

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /tools/testing/kunit/kunit.py (Version linux-6.12-rc7) and /tools/testing/kunit/kunit.py (Version linux-6.4.16)


  1 #!/usr/bin/env python3                              1 #!/usr/bin/env python3
  2 # SPDX-License-Identifier: GPL-2.0                  2 # SPDX-License-Identifier: GPL-2.0
  3 #                                                   3 #
  4 # A thin wrapper on top of the KUnit Kernel         4 # A thin wrapper on top of the KUnit Kernel
  5 #                                                   5 #
  6 # Copyright (C) 2019, Google LLC.                   6 # Copyright (C) 2019, Google LLC.
  7 # Author: Felix Guo <felixguoxiuping@gmail.com>      7 # Author: Felix Guo <felixguoxiuping@gmail.com>
  8 # Author: Brendan Higgins <brendanhiggins@googl      8 # Author: Brendan Higgins <brendanhiggins@google.com>
  9                                                     9 
 10 import argparse                                    10 import argparse
 11 import os                                          11 import os
 12 import re                                          12 import re
 13 import shlex                                       13 import shlex
 14 import sys                                         14 import sys
 15 import time                                        15 import time
 16                                                    16 
 17 assert sys.version_info >= (3, 7), "Python ver     17 assert sys.version_info >= (3, 7), "Python version is too old"
 18                                                    18 
 19 from dataclasses import dataclass                  19 from dataclasses import dataclass
 20 from enum import Enum, auto                        20 from enum import Enum, auto
 21 from typing import Iterable, List, Optional, S     21 from typing import Iterable, List, Optional, Sequence, Tuple
 22                                                    22 
 23 import kunit_json                                  23 import kunit_json
 24 import kunit_kernel                                24 import kunit_kernel
 25 import kunit_parser                                25 import kunit_parser
 26 from kunit_printer import stdout                   26 from kunit_printer import stdout
 27                                                    27 
 28 class KunitStatus(Enum):                           28 class KunitStatus(Enum):
 29         SUCCESS = auto()                           29         SUCCESS = auto()
 30         CONFIG_FAILURE = auto()                    30         CONFIG_FAILURE = auto()
 31         BUILD_FAILURE = auto()                     31         BUILD_FAILURE = auto()
 32         TEST_FAILURE = auto()                      32         TEST_FAILURE = auto()
 33                                                    33 
 34 @dataclass                                         34 @dataclass
 35 class KunitResult:                                 35 class KunitResult:
 36         status: KunitStatus                        36         status: KunitStatus
 37         elapsed_time: float                        37         elapsed_time: float
 38                                                    38 
 39 @dataclass                                         39 @dataclass
 40 class KunitConfigRequest:                          40 class KunitConfigRequest:
 41         build_dir: str                             41         build_dir: str
 42         make_options: Optional[List[str]]          42         make_options: Optional[List[str]]
 43                                                    43 
 44 @dataclass                                         44 @dataclass
 45 class KunitBuildRequest(KunitConfigRequest):       45 class KunitBuildRequest(KunitConfigRequest):
 46         jobs: int                                  46         jobs: int
 47                                                    47 
 48 @dataclass                                         48 @dataclass
 49 class KunitParseRequest:                           49 class KunitParseRequest:
 50         raw_output: Optional[str]                  50         raw_output: Optional[str]
 51         json: Optional[str]                        51         json: Optional[str]
 52                                                    52 
 53 @dataclass                                         53 @dataclass
 54 class KunitExecRequest(KunitParseRequest):         54 class KunitExecRequest(KunitParseRequest):
 55         build_dir: str                             55         build_dir: str
 56         timeout: int                               56         timeout: int
 57         filter_glob: str                           57         filter_glob: str
 58         filter: str                            << 
 59         filter_action: Optional[str]           << 
 60         kernel_args: Optional[List[str]]           58         kernel_args: Optional[List[str]]
 61         run_isolated: Optional[str]                59         run_isolated: Optional[str]
 62         list_tests: bool                       << 
 63         list_tests_attr: bool                  << 
 64                                                    60 
 65 @dataclass                                         61 @dataclass
 66 class KunitRequest(KunitExecRequest, KunitBuil     62 class KunitRequest(KunitExecRequest, KunitBuildRequest):
 67         pass                                       63         pass
 68                                                    64 
 69                                                    65 
 70 def get_kernel_root_path() -> str:                 66 def get_kernel_root_path() -> str:
 71         path = sys.argv[0] if not __file__ els     67         path = sys.argv[0] if not __file__ else __file__
 72         parts = os.path.realpath(path).split('     68         parts = os.path.realpath(path).split('tools/testing/kunit')
 73         if len(parts) != 2:                        69         if len(parts) != 2:
 74                 sys.exit(1)                        70                 sys.exit(1)
 75         return parts[0]                            71         return parts[0]
 76                                                    72 
 77 def config_tests(linux: kunit_kernel.LinuxSour     73 def config_tests(linux: kunit_kernel.LinuxSourceTree,
 78                  request: KunitConfigRequest)      74                  request: KunitConfigRequest) -> KunitResult:
 79         stdout.print_with_timestamp('Configuri     75         stdout.print_with_timestamp('Configuring KUnit Kernel ...')
 80                                                    76 
 81         config_start = time.time()                 77         config_start = time.time()
 82         success = linux.build_reconfig(request     78         success = linux.build_reconfig(request.build_dir, request.make_options)
 83         config_end = time.time()                   79         config_end = time.time()
 84         status = KunitStatus.SUCCESS if succes     80         status = KunitStatus.SUCCESS if success else KunitStatus.CONFIG_FAILURE
 85         return KunitResult(status, config_end      81         return KunitResult(status, config_end - config_start)
 86                                                    82 
 87 def build_tests(linux: kunit_kernel.LinuxSourc     83 def build_tests(linux: kunit_kernel.LinuxSourceTree,
 88                 request: KunitBuildRequest) ->     84                 request: KunitBuildRequest) -> KunitResult:
 89         stdout.print_with_timestamp('Building      85         stdout.print_with_timestamp('Building KUnit Kernel ...')
 90                                                    86 
 91         build_start = time.time()                  87         build_start = time.time()
 92         success = linux.build_kernel(request.j     88         success = linux.build_kernel(request.jobs,
 93                                      request.b     89                                      request.build_dir,
 94                                      request.m     90                                      request.make_options)
 95         build_end = time.time()                    91         build_end = time.time()
 96         status = KunitStatus.SUCCESS if succes     92         status = KunitStatus.SUCCESS if success else KunitStatus.BUILD_FAILURE
 97         return KunitResult(status, build_end -     93         return KunitResult(status, build_end - build_start)
 98                                                    94 
 99 def config_and_build_tests(linux: kunit_kernel     95 def config_and_build_tests(linux: kunit_kernel.LinuxSourceTree,
100                            request: KunitBuild     96                            request: KunitBuildRequest) -> KunitResult:
101         config_result = config_tests(linux, re     97         config_result = config_tests(linux, request)
102         if config_result.status != KunitStatus     98         if config_result.status != KunitStatus.SUCCESS:
103                 return config_result               99                 return config_result
104                                                   100 
105         return build_tests(linux, request)        101         return build_tests(linux, request)
106                                                   102 
107 def _list_tests(linux: kunit_kernel.LinuxSourc    103 def _list_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> List[str]:
108         args = ['kunit.action=list']              104         args = ['kunit.action=list']
109                                                << 
110         if request.kernel_args:                << 
111                 args.extend(request.kernel_arg << 
112                                                << 
113         output = linux.run_kernel(args=args,   << 
114                            timeout=request.tim << 
115                            filter_glob=request << 
116                            filter=request.filt << 
117                            filter_action=reque << 
118                            build_dir=request.b << 
119         lines = kunit_parser.extract_tap_lines << 
120         # Hack! Drop the dummy TAP version hea << 
121         lines.pop()                            << 
122                                                << 
123         # Filter out any extraneous non-test o << 
124         return [l for l in output if re.match( << 
125                                                << 
126 def _list_tests_attr(linux: kunit_kernel.Linux << 
127         args = ['kunit.action=list_attr']      << 
128                                                << 
129         if request.kernel_args:                   105         if request.kernel_args:
130                 args.extend(request.kernel_arg    106                 args.extend(request.kernel_args)
131                                                   107 
132         output = linux.run_kernel(args=args,      108         output = linux.run_kernel(args=args,
133                            timeout=request.tim    109                            timeout=request.timeout,
134                            filter_glob=request    110                            filter_glob=request.filter_glob,
135                            filter=request.filt << 
136                            filter_action=reque << 
137                            build_dir=request.b    111                            build_dir=request.build_dir)
138         lines = kunit_parser.extract_tap_lines    112         lines = kunit_parser.extract_tap_lines(output)
139         # Hack! Drop the dummy TAP version hea    113         # Hack! Drop the dummy TAP version header that the executor prints out.
140         lines.pop()                               114         lines.pop()
141                                                   115 
142         # Filter out any extraneous non-test o    116         # Filter out any extraneous non-test output that might have gotten mixed in.
143         return lines                           !! 117         return [l for l in lines if re.match(r'^[^\s.]+\.[^\s.]+$', l)]
144                                                   118 
145 def _suites_from_test_list(tests: List[str]) -    119 def _suites_from_test_list(tests: List[str]) -> List[str]:
146         """Extracts all the suites from an ord    120         """Extracts all the suites from an ordered list of tests."""
147         suites = []  # type: List[str]            121         suites = []  # type: List[str]
148         for t in tests:                           122         for t in tests:
149                 parts = t.split('.', maxsplit=    123                 parts = t.split('.', maxsplit=2)
150                 if len(parts) != 2:               124                 if len(parts) != 2:
151                         raise ValueError(f'int    125                         raise ValueError(f'internal KUnit error, test name should be of the form "<suite>.<test>", got "{t}"')
152                 suite, _ = parts                  126                 suite, _ = parts
153                 if not suites or suites[-1] !=    127                 if not suites or suites[-1] != suite:
154                         suites.append(suite)      128                         suites.append(suite)
155         return suites                             129         return suites
156                                                   130 
                                                   >> 131 
                                                   >> 132 
157 def exec_tests(linux: kunit_kernel.LinuxSource    133 def exec_tests(linux: kunit_kernel.LinuxSourceTree, request: KunitExecRequest) -> KunitResult:
158         filter_globs = [request.filter_glob]      134         filter_globs = [request.filter_glob]
159         if request.list_tests:                 << 
160                 output = _list_tests(linux, re << 
161                 for line in output:            << 
162                         print(line.rstrip())   << 
163                 return KunitResult(status=Kuni << 
164         if request.list_tests_attr:            << 
165                 attr_output = _list_tests_attr << 
166                 for line in attr_output:       << 
167                         print(line.rstrip())   << 
168                 return KunitResult(status=Kuni << 
169         if request.run_isolated:                  135         if request.run_isolated:
170                 tests = _list_tests(linux, req    136                 tests = _list_tests(linux, request)
171                 if request.run_isolated == 'te    137                 if request.run_isolated == 'test':
172                         filter_globs = tests      138                         filter_globs = tests
173                 elif request.run_isolated == '    139                 elif request.run_isolated == 'suite':
174                         filter_globs = _suites    140                         filter_globs = _suites_from_test_list(tests)
175                         # Apply the test-part     141                         # Apply the test-part of the user's glob, if present.
176                         if '.' in request.filt    142                         if '.' in request.filter_glob:
177                                 test_glob = re    143                                 test_glob = request.filter_glob.split('.', maxsplit=2)[1]
178                                 filter_globs =    144                                 filter_globs = [g + '.'+ test_glob for g in filter_globs]
179                                                   145 
180         metadata = kunit_json.Metadata(arch=li    146         metadata = kunit_json.Metadata(arch=linux.arch(), build_dir=request.build_dir, def_config='kunit_defconfig')
181                                                   147 
182         test_counts = kunit_parser.TestCounts(    148         test_counts = kunit_parser.TestCounts()
183         exec_time = 0.0                           149         exec_time = 0.0
184         for i, filter_glob in enumerate(filter    150         for i, filter_glob in enumerate(filter_globs):
185                 stdout.print_with_timestamp('S    151                 stdout.print_with_timestamp('Starting KUnit Kernel ({}/{})...'.format(i+1, len(filter_globs)))
186                                                   152 
187                 test_start = time.time()          153                 test_start = time.time()
188                 run_result = linux.run_kernel(    154                 run_result = linux.run_kernel(
189                         args=request.kernel_ar    155                         args=request.kernel_args,
190                         timeout=request.timeou    156                         timeout=request.timeout,
191                         filter_glob=filter_glo    157                         filter_glob=filter_glob,
192                         filter=request.filter, << 
193                         filter_action=request. << 
194                         build_dir=request.buil    158                         build_dir=request.build_dir)
195                                                   159 
196                 _, test_result = parse_tests(r    160                 _, test_result = parse_tests(request, metadata, run_result)
197                 # run_kernel() doesn't block o    161                 # run_kernel() doesn't block on the kernel exiting.
198                 # That only happens after we g    162                 # That only happens after we get the last line of output from `run_result`.
199                 # So exec_time here actually c    163                 # So exec_time here actually contains parsing + execution time, which is fine.
200                 test_end = time.time()            164                 test_end = time.time()
201                 exec_time += test_end - test_s    165                 exec_time += test_end - test_start
202                                                   166 
203                 test_counts.add_subtest_counts    167                 test_counts.add_subtest_counts(test_result.counts)
204                                                   168 
205         if len(filter_globs) == 1 and test_cou    169         if len(filter_globs) == 1 and test_counts.crashed > 0:
206                 bd = request.build_dir            170                 bd = request.build_dir
207                 print('The kernel seems to hav    171                 print('The kernel seems to have crashed; you can decode the stack traces with:')
208                 print('$ scripts/decode_stackt    172                 print('$ scripts/decode_stacktrace.sh {}/vmlinux {} < {} | tee {}/decoded.log | {} parse'.format(
209                                 bd, bd, kunit_    173                                 bd, bd, kunit_kernel.get_outfile_path(bd), bd, sys.argv[0]))
210                                                   174 
211         kunit_status = _map_to_overall_status(    175         kunit_status = _map_to_overall_status(test_counts.get_status())
212         return KunitResult(status=kunit_status    176         return KunitResult(status=kunit_status, elapsed_time=exec_time)
213                                                   177 
214 def _map_to_overall_status(test_status: kunit_    178 def _map_to_overall_status(test_status: kunit_parser.TestStatus) -> KunitStatus:
215         if test_status in (kunit_parser.TestSt    179         if test_status in (kunit_parser.TestStatus.SUCCESS, kunit_parser.TestStatus.SKIPPED):
216                 return KunitStatus.SUCCESS        180                 return KunitStatus.SUCCESS
217         return KunitStatus.TEST_FAILURE           181         return KunitStatus.TEST_FAILURE
218                                                   182 
219 def parse_tests(request: KunitParseRequest, me    183 def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input_data: Iterable[str]) -> Tuple[KunitResult, kunit_parser.Test]:
220         parse_start = time.time()                 184         parse_start = time.time()
221                                                   185 
222         if request.raw_output:                    186         if request.raw_output:
223                 # Treat unparsed results as on    187                 # Treat unparsed results as one passing test.
224                 fake_test = kunit_parser.Test(    188                 fake_test = kunit_parser.Test()
225                 fake_test.status = kunit_parse    189                 fake_test.status = kunit_parser.TestStatus.SUCCESS
226                 fake_test.counts.passed = 1       190                 fake_test.counts.passed = 1
227                                                   191 
228                 output: Iterable[str] = input_    192                 output: Iterable[str] = input_data
229                 if request.raw_output == 'all'    193                 if request.raw_output == 'all':
230                         pass                      194                         pass
231                 elif request.raw_output == 'ku    195                 elif request.raw_output == 'kunit':
232                         output = kunit_parser.    196                         output = kunit_parser.extract_tap_lines(output)
233                 for line in output:               197                 for line in output:
234                         print(line.rstrip())      198                         print(line.rstrip())
235                 parse_time = time.time() - par    199                 parse_time = time.time() - parse_start
236                 return KunitResult(KunitStatus    200                 return KunitResult(KunitStatus.SUCCESS, parse_time), fake_test
237                                                   201 
238                                                   202 
239         # Actually parse the test results.        203         # Actually parse the test results.
240         test = kunit_parser.parse_run_tests(in    204         test = kunit_parser.parse_run_tests(input_data)
241         parse_time = time.time() - parse_start    205         parse_time = time.time() - parse_start
242                                                   206 
243         if request.json:                          207         if request.json:
244                 json_str = kunit_json.get_json    208                 json_str = kunit_json.get_json_result(
245                                         test=t    209                                         test=test,
246                                         metada    210                                         metadata=metadata)
247                 if request.json == 'stdout':      211                 if request.json == 'stdout':
248                         print(json_str)           212                         print(json_str)
249                 else:                             213                 else:
250                         with open(request.json    214                         with open(request.json, 'w') as f:
251                                 f.write(json_s    215                                 f.write(json_str)
252                         stdout.print_with_time    216                         stdout.print_with_timestamp("Test results stored in %s" %
253                                 os.path.abspat    217                                 os.path.abspath(request.json))
254                                                   218 
255         if test.status != kunit_parser.TestSta    219         if test.status != kunit_parser.TestStatus.SUCCESS:
256                 return KunitResult(KunitStatus    220                 return KunitResult(KunitStatus.TEST_FAILURE, parse_time), test
257                                                   221 
258         return KunitResult(KunitStatus.SUCCESS    222         return KunitResult(KunitStatus.SUCCESS, parse_time), test
259                                                   223 
260 def run_tests(linux: kunit_kernel.LinuxSourceT    224 def run_tests(linux: kunit_kernel.LinuxSourceTree,
261               request: KunitRequest) -> KunitR    225               request: KunitRequest) -> KunitResult:
262         run_start = time.time()                   226         run_start = time.time()
263                                                   227 
264         config_result = config_tests(linux, re    228         config_result = config_tests(linux, request)
265         if config_result.status != KunitStatus    229         if config_result.status != KunitStatus.SUCCESS:
266                 return config_result              230                 return config_result
267                                                   231 
268         build_result = build_tests(linux, requ    232         build_result = build_tests(linux, request)
269         if build_result.status != KunitStatus.    233         if build_result.status != KunitStatus.SUCCESS:
270                 return build_result               234                 return build_result
271                                                   235 
272         exec_result = exec_tests(linux, reques    236         exec_result = exec_tests(linux, request)
273                                                   237 
274         run_end = time.time()                     238         run_end = time.time()
275                                                   239 
276         stdout.print_with_timestamp((             240         stdout.print_with_timestamp((
277                 'Elapsed time: %.3fs total, %.    241                 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
278                 'building, %.3fs running\n') %    242                 'building, %.3fs running\n') % (
279                                 run_end - run_    243                                 run_end - run_start,
280                                 config_result.    244                                 config_result.elapsed_time,
281                                 build_result.e    245                                 build_result.elapsed_time,
282                                 exec_result.el    246                                 exec_result.elapsed_time))
283         return exec_result                        247         return exec_result
284                                                   248 
285 # Problem:                                        249 # Problem:
286 # $ kunit.py run --json                           250 # $ kunit.py run --json
287 # works as one would expect and prints the par    251 # works as one would expect and prints the parsed test results as JSON.
288 # $ kunit.py run --json suite_name                252 # $ kunit.py run --json suite_name
289 # would *not* pass suite_name as the filter_gl    253 # would *not* pass suite_name as the filter_glob and print as json.
290 # argparse will consider it to be another way     254 # argparse will consider it to be another way of writing
291 # $ kunit.py run --json=suite_name                255 # $ kunit.py run --json=suite_name
292 # i.e. it would run all tests, and dump the js    256 # i.e. it would run all tests, and dump the json to a `suite_name` file.
293 # So we hackily automatically rewrite --json =    257 # So we hackily automatically rewrite --json => --json=stdout
294 pseudo_bool_flag_defaults = {                     258 pseudo_bool_flag_defaults = {
295                 '--json': 'stdout',               259                 '--json': 'stdout',
296                 '--raw_output': 'kunit',          260                 '--raw_output': 'kunit',
297 }                                                 261 }
298 def massage_argv(argv: Sequence[str]) -> Seque    262 def massage_argv(argv: Sequence[str]) -> Sequence[str]:
299         def massage_arg(arg: str) -> str:         263         def massage_arg(arg: str) -> str:
300                 if arg not in pseudo_bool_flag    264                 if arg not in pseudo_bool_flag_defaults:
301                         return arg                265                         return arg
302                 return  f'{arg}={pseudo_bool_f    266                 return  f'{arg}={pseudo_bool_flag_defaults[arg]}'
303         return list(map(massage_arg, argv))       267         return list(map(massage_arg, argv))
304                                                   268 
305 def get_default_jobs() -> int:                    269 def get_default_jobs() -> int:
306         return len(os.sched_getaffinity(0))       270         return len(os.sched_getaffinity(0))
307                                                   271 
308 def add_common_opts(parser: argparse.ArgumentP    272 def add_common_opts(parser: argparse.ArgumentParser) -> None:
309         parser.add_argument('--build_dir',        273         parser.add_argument('--build_dir',
310                             help='As in the ma    274                             help='As in the make command, it specifies the build '
311                             'directory.',         275                             'directory.',
312                             type=str, default=    276                             type=str, default='.kunit', metavar='DIR')
313         parser.add_argument('--make_options',     277         parser.add_argument('--make_options',
314                             help='X=Y make opt    278                             help='X=Y make option, can be repeated.',
315                             action='append', m    279                             action='append', metavar='X=Y')
316         parser.add_argument('--alltests',         280         parser.add_argument('--alltests',
317                             help='Run all KUni    281                             help='Run all KUnit tests via tools/testing/kunit/configs/all_tests.config',
318                             action='store_true    282                             action='store_true')
319         parser.add_argument('--kunitconfig',      283         parser.add_argument('--kunitconfig',
320                              help='Path to Kco    284                              help='Path to Kconfig fragment that enables KUnit tests.'
321                              ' If given a dire    285                              ' If given a directory, (e.g. lib/kunit), "/.kunitconfig" '
322                              'will get  automa    286                              'will get  automatically appended. If repeated, the files '
323                              'blindly concaten    287                              'blindly concatenated, which might not work in all cases.',
324                              action='append',     288                              action='append', metavar='PATHS')
325         parser.add_argument('--kconfig_add',      289         parser.add_argument('--kconfig_add',
326                              help='Additional     290                              help='Additional Kconfig options to append to the '
327                              '.kunitconfig, e.    291                              '.kunitconfig, e.g. CONFIG_KASAN=y. Can be repeated.',
328                             action='append', m    292                             action='append', metavar='CONFIG_X=Y')
329                                                   293 
330         parser.add_argument('--arch',             294         parser.add_argument('--arch',
331                             help=('Specifies t    295                             help=('Specifies the architecture to run tests under. '
332                                   'The archite    296                                   'The architecture specified here must match the '
333                                   'string pass    297                                   'string passed to the ARCH make param, '
334                                   'e.g. i386,     298                                   'e.g. i386, x86_64, arm, um, etc. Non-UML '
335                                   'architectur    299                                   'architectures run on QEMU.'),
336                             type=str, default=    300                             type=str, default='um', metavar='ARCH')
337                                                   301 
338         parser.add_argument('--cross_compile',    302         parser.add_argument('--cross_compile',
339                             help=('Sets make\'    303                             help=('Sets make\'s CROSS_COMPILE variable; it should '
340                                   'be set to a    304                                   'be set to a toolchain path prefix (the prefix '
341                                   'of gcc and     305                                   'of gcc and other tools in your toolchain, for '
342                                   'example `sp    306                                   'example `sparc64-linux-gnu-` if you have the '
343                                   'sparc toolc    307                                   'sparc toolchain installed on your system, or '
344                                   '`$HOME/tool    308                                   '`$HOME/toolchains/microblaze/gcc-9.2.0-nolibc/microblaze-linux/bin/microblaze-linux-` '
345                                   'if you have    309                                   'if you have downloaded the microblaze toolchain '
346                                   'from the 0-    310                                   'from the 0-day website to a directory in your '
347                                   'home direct    311                                   'home directory called `toolchains`).'),
348                             metavar='PREFIX')     312                             metavar='PREFIX')
349                                                   313 
350         parser.add_argument('--qemu_config',      314         parser.add_argument('--qemu_config',
351                             help=('Takes a pat    315                             help=('Takes a path to a path to a file containing '
352                                   'a QemuArchP    316                                   'a QemuArchParams object.'),
353                             type=str, metavar=    317                             type=str, metavar='FILE')
354                                                   318 
355         parser.add_argument('--qemu_args',        319         parser.add_argument('--qemu_args',
356                             help='Additional Q    320                             help='Additional QEMU arguments, e.g. "-smp 8"',
357                             action='append', m    321                             action='append', metavar='')
358                                                   322 
359 def add_build_opts(parser: argparse.ArgumentPa    323 def add_build_opts(parser: argparse.ArgumentParser) -> None:
360         parser.add_argument('--jobs',             324         parser.add_argument('--jobs',
361                             help='As in the ma    325                             help='As in the make command, "Specifies  the number of '
362                             'jobs (commands) t    326                             'jobs (commands) to run simultaneously."',
363                             type=int, default=    327                             type=int, default=get_default_jobs(), metavar='N')
364                                                   328 
365 def add_exec_opts(parser: argparse.ArgumentPar    329 def add_exec_opts(parser: argparse.ArgumentParser) -> None:
366         parser.add_argument('--timeout',          330         parser.add_argument('--timeout',
367                             help='maximum numb    331                             help='maximum number of seconds to allow for all tests '
368                             'to run. This does    332                             'to run. This does not include time taken to build the '
369                             'tests.',             333                             'tests.',
370                             type=int,             334                             type=int,
371                             default=300,          335                             default=300,
372                             metavar='SECONDS')    336                             metavar='SECONDS')
373         parser.add_argument('filter_glob',        337         parser.add_argument('filter_glob',
374                             help='Filter which    338                             help='Filter which KUnit test suites/tests run at '
375                             'boot-time, e.g. l    339                             'boot-time, e.g. list* or list*.*del_test',
376                             type=str,             340                             type=str,
377                             nargs='?',            341                             nargs='?',
378                             default='',           342                             default='',
379                             metavar='filter_gl    343                             metavar='filter_glob')
380         parser.add_argument('--filter',        << 
381                             help='Filter KUnit << 
382                             'e.g. module=examp << 
383                             type=str,          << 
384                                 default='')    << 
385         parser.add_argument('--filter_action', << 
386                             help='If set to sk << 
387                                 'e.g. --filter << 
388                             type=str,          << 
389                                 choices=['skip << 
390         parser.add_argument('--kernel_args',      344         parser.add_argument('--kernel_args',
391                             help='Kernel comma    345                             help='Kernel command-line parameters. Maybe be repeated',
392                              action='append',     346                              action='append', metavar='')
393         parser.add_argument('--run_isolated',     347         parser.add_argument('--run_isolated', help='If set, boot the kernel for each '
394                             'individual suite/    348                             'individual suite/test. This is can be useful for debugging '
395                             'a non-hermetic te    349                             'a non-hermetic test, one that might pass/fail based on '
396                             'what ran before i    350                             'what ran before it.',
397                             type=str,             351                             type=str,
398                             choices=['suite',     352                             choices=['suite', 'test'])
399         parser.add_argument('--list_tests', he << 
400                             'run.',            << 
401                             action='store_true << 
402         parser.add_argument('--list_tests_attr << 
403                             'attributes.',     << 
404                             action='store_true << 
405                                                   353 
406 def add_parse_opts(parser: argparse.ArgumentPa    354 def add_parse_opts(parser: argparse.ArgumentParser) -> None:
407         parser.add_argument('--raw_output', he    355         parser.add_argument('--raw_output', help='If set don\'t parse output from kernel. '
408                             'By default, filte    356                             'By default, filters to just KUnit output. Use '
409                             '--raw_output=all     357                             '--raw_output=all to show everything',
410                              type=str, nargs='    358                              type=str, nargs='?', const='all', default=None, choices=['all', 'kunit'])
411         parser.add_argument('--json',             359         parser.add_argument('--json',
412                             nargs='?',            360                             nargs='?',
413                             help='Prints parse    361                             help='Prints parsed test results as JSON to stdout or a file if '
414                             'a filename is spe    362                             'a filename is specified. Does nothing if --raw_output is set.',
415                             type=str, const='s    363                             type=str, const='stdout', default=None, metavar='FILE')
416                                                   364 
417                                                   365 
418 def tree_from_args(cli_args: argparse.Namespac    366 def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree:
419         """Returns a LinuxSourceTree based on     367         """Returns a LinuxSourceTree based on the user's arguments."""
420         # Allow users to specify multiple argu    368         # Allow users to specify multiple arguments in one string, e.g. '-smp 8'
421         qemu_args: List[str] = []                 369         qemu_args: List[str] = []
422         if cli_args.qemu_args:                    370         if cli_args.qemu_args:
423                 for arg in cli_args.qemu_args:    371                 for arg in cli_args.qemu_args:
424                         qemu_args.extend(shlex    372                         qemu_args.extend(shlex.split(arg))
425                                                   373 
426         kunitconfigs = cli_args.kunitconfig if    374         kunitconfigs = cli_args.kunitconfig if cli_args.kunitconfig else []
427         if cli_args.alltests:                     375         if cli_args.alltests:
428                 # Prepend so user-specified op    376                 # Prepend so user-specified options take prio if we ever allow
429                 # --kunitconfig options to hav    377                 # --kunitconfig options to have differing options.
430                 kunitconfigs = [kunit_kernel.A    378                 kunitconfigs = [kunit_kernel.ALL_TESTS_CONFIG_PATH] + kunitconfigs
431                                                   379 
432         return kunit_kernel.LinuxSourceTree(cl    380         return kunit_kernel.LinuxSourceTree(cli_args.build_dir,
433                         kunitconfig_paths=kuni    381                         kunitconfig_paths=kunitconfigs,
434                         kconfig_add=cli_args.k    382                         kconfig_add=cli_args.kconfig_add,
435                         arch=cli_args.arch,       383                         arch=cli_args.arch,
436                         cross_compile=cli_args    384                         cross_compile=cli_args.cross_compile,
437                         qemu_config_path=cli_a    385                         qemu_config_path=cli_args.qemu_config,
438                         extra_qemu_args=qemu_a    386                         extra_qemu_args=qemu_args)
439                                                   387 
440                                                   388 
441 def run_handler(cli_args: argparse.Namespace)     389 def run_handler(cli_args: argparse.Namespace) -> None:
442         if not os.path.exists(cli_args.build_d    390         if not os.path.exists(cli_args.build_dir):
443                 os.mkdir(cli_args.build_dir)      391                 os.mkdir(cli_args.build_dir)
444                                                   392 
445         linux = tree_from_args(cli_args)          393         linux = tree_from_args(cli_args)
446         request = KunitRequest(build_dir=cli_a    394         request = KunitRequest(build_dir=cli_args.build_dir,
447                                         make_o    395                                         make_options=cli_args.make_options,
448                                         jobs=c    396                                         jobs=cli_args.jobs,
449                                         raw_ou    397                                         raw_output=cli_args.raw_output,
450                                         json=c    398                                         json=cli_args.json,
451                                         timeou    399                                         timeout=cli_args.timeout,
452                                         filter    400                                         filter_glob=cli_args.filter_glob,
453                                         filter << 
454                                         filter << 
455                                         kernel    401                                         kernel_args=cli_args.kernel_args,
456                                         run_is !! 402                                         run_isolated=cli_args.run_isolated)
457                                         list_t << 
458                                         list_t << 
459         result = run_tests(linux, request)        403         result = run_tests(linux, request)
460         if result.status != KunitStatus.SUCCES    404         if result.status != KunitStatus.SUCCESS:
461                 sys.exit(1)                       405                 sys.exit(1)
462                                                   406 
463                                                   407 
464 def config_handler(cli_args: argparse.Namespac    408 def config_handler(cli_args: argparse.Namespace) -> None:
465         if cli_args.build_dir and (               409         if cli_args.build_dir and (
466                         not os.path.exists(cli    410                         not os.path.exists(cli_args.build_dir)):
467                 os.mkdir(cli_args.build_dir)      411                 os.mkdir(cli_args.build_dir)
468                                                   412 
469         linux = tree_from_args(cli_args)          413         linux = tree_from_args(cli_args)
470         request = KunitConfigRequest(build_dir    414         request = KunitConfigRequest(build_dir=cli_args.build_dir,
471                                                   415                                                 make_options=cli_args.make_options)
472         result = config_tests(linux, request)     416         result = config_tests(linux, request)
473         stdout.print_with_timestamp((             417         stdout.print_with_timestamp((
474                 'Elapsed time: %.3fs\n') % (      418                 'Elapsed time: %.3fs\n') % (
475                         result.elapsed_time))     419                         result.elapsed_time))
476         if result.status != KunitStatus.SUCCES    420         if result.status != KunitStatus.SUCCESS:
477                 sys.exit(1)                       421                 sys.exit(1)
478                                                   422 
479                                                   423 
480 def build_handler(cli_args: argparse.Namespace    424 def build_handler(cli_args: argparse.Namespace) -> None:
481         linux = tree_from_args(cli_args)          425         linux = tree_from_args(cli_args)
482         request = KunitBuildRequest(build_dir=    426         request = KunitBuildRequest(build_dir=cli_args.build_dir,
483                                         make_o    427                                         make_options=cli_args.make_options,
484                                         jobs=c    428                                         jobs=cli_args.jobs)
485         result = config_and_build_tests(linux,    429         result = config_and_build_tests(linux, request)
486         stdout.print_with_timestamp((             430         stdout.print_with_timestamp((
487                 'Elapsed time: %.3fs\n') % (      431                 'Elapsed time: %.3fs\n') % (
488                         result.elapsed_time))     432                         result.elapsed_time))
489         if result.status != KunitStatus.SUCCES    433         if result.status != KunitStatus.SUCCESS:
490                 sys.exit(1)                       434                 sys.exit(1)
491                                                   435 
492                                                   436 
493 def exec_handler(cli_args: argparse.Namespace)    437 def exec_handler(cli_args: argparse.Namespace) -> None:
494         linux = tree_from_args(cli_args)          438         linux = tree_from_args(cli_args)
495         exec_request = KunitExecRequest(raw_ou    439         exec_request = KunitExecRequest(raw_output=cli_args.raw_output,
496                                         build_    440                                         build_dir=cli_args.build_dir,
497                                         json=c    441                                         json=cli_args.json,
498                                         timeou    442                                         timeout=cli_args.timeout,
499                                         filter    443                                         filter_glob=cli_args.filter_glob,
500                                         filter << 
501                                         filter << 
502                                         kernel    444                                         kernel_args=cli_args.kernel_args,
503                                         run_is !! 445                                         run_isolated=cli_args.run_isolated)
504                                         list_t << 
505                                         list_t << 
506         result = exec_tests(linux, exec_reques    446         result = exec_tests(linux, exec_request)
507         stdout.print_with_timestamp((             447         stdout.print_with_timestamp((
508                 'Elapsed time: %.3fs\n') % (re    448                 'Elapsed time: %.3fs\n') % (result.elapsed_time))
509         if result.status != KunitStatus.SUCCES    449         if result.status != KunitStatus.SUCCESS:
510                 sys.exit(1)                       450                 sys.exit(1)
511                                                   451 
512                                                   452 
513 def parse_handler(cli_args: argparse.Namespace    453 def parse_handler(cli_args: argparse.Namespace) -> None:
514         if cli_args.file is None:                 454         if cli_args.file is None:
515                 sys.stdin.reconfigure(errors='    455                 sys.stdin.reconfigure(errors='backslashreplace')  # type: ignore
516                 kunit_output = sys.stdin  # ty    456                 kunit_output = sys.stdin  # type: Iterable[str]
517         else:                                     457         else:
518                 with open(cli_args.file, 'r',     458                 with open(cli_args.file, 'r', errors='backslashreplace') as f:
519                         kunit_output = f.read(    459                         kunit_output = f.read().splitlines()
520         # We know nothing about how the result    460         # We know nothing about how the result was created!
521         metadata = kunit_json.Metadata()          461         metadata = kunit_json.Metadata()
522         request = KunitParseRequest(raw_output    462         request = KunitParseRequest(raw_output=cli_args.raw_output,
523                                         json=c    463                                         json=cli_args.json)
524         result, _ = parse_tests(request, metad    464         result, _ = parse_tests(request, metadata, kunit_output)
525         if result.status != KunitStatus.SUCCES    465         if result.status != KunitStatus.SUCCESS:
526                 sys.exit(1)                       466                 sys.exit(1)
527                                                   467 
528                                                   468 
529 subcommand_handlers_map = {                       469 subcommand_handlers_map = {
530         'run': run_handler,                       470         'run': run_handler,
531         'config': config_handler,                 471         'config': config_handler,
532         'build': build_handler,                   472         'build': build_handler,
533         'exec': exec_handler,                     473         'exec': exec_handler,
534         'parse': parse_handler                    474         'parse': parse_handler
535 }                                                 475 }
536                                                   476 
537                                                   477 
538 def main(argv: Sequence[str]) -> None:            478 def main(argv: Sequence[str]) -> None:
539         parser = argparse.ArgumentParser(         479         parser = argparse.ArgumentParser(
540                         description='Helps wri    480                         description='Helps writing and running KUnit tests.')
541         subparser = parser.add_subparsers(dest    481         subparser = parser.add_subparsers(dest='subcommand')
542                                                   482 
543         # The 'run' command will config, build    483         # The 'run' command will config, build, exec, and parse in one go.
544         run_parser = subparser.add_parser('run    484         run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
545         add_common_opts(run_parser)               485         add_common_opts(run_parser)
546         add_build_opts(run_parser)                486         add_build_opts(run_parser)
547         add_exec_opts(run_parser)                 487         add_exec_opts(run_parser)
548         add_parse_opts(run_parser)                488         add_parse_opts(run_parser)
549                                                   489 
550         config_parser = subparser.add_parser('    490         config_parser = subparser.add_parser('config',
551                                                   491                                                 help='Ensures that .config contains all of '
552                                                   492                                                 'the options in .kunitconfig')
553         add_common_opts(config_parser)            493         add_common_opts(config_parser)
554                                                   494 
555         build_parser = subparser.add_parser('b    495         build_parser = subparser.add_parser('build', help='Builds a kernel with KUnit tests')
556         add_common_opts(build_parser)             496         add_common_opts(build_parser)
557         add_build_opts(build_parser)              497         add_build_opts(build_parser)
558                                                   498 
559         exec_parser = subparser.add_parser('ex    499         exec_parser = subparser.add_parser('exec', help='Run a kernel with KUnit tests')
560         add_common_opts(exec_parser)              500         add_common_opts(exec_parser)
561         add_exec_opts(exec_parser)                501         add_exec_opts(exec_parser)
562         add_parse_opts(exec_parser)               502         add_parse_opts(exec_parser)
563                                                   503 
564         # The 'parse' option is special, as it    504         # The 'parse' option is special, as it doesn't need the kernel source
565         # (therefore there is no need for a bu    505         # (therefore there is no need for a build_dir, hence no add_common_opts)
566         # and the '--file' argument is not rel    506         # and the '--file' argument is not relevant to 'run', so isn't in
567         # add_parse_opts()                        507         # add_parse_opts()
568         parse_parser = subparser.add_parser('p    508         parse_parser = subparser.add_parser('parse',
569                                             he    509                                             help='Parses KUnit results from a file, '
570                                             'a    510                                             'and parses formatted results.')
571         add_parse_opts(parse_parser)              511         add_parse_opts(parse_parser)
572         parse_parser.add_argument('file',         512         parse_parser.add_argument('file',
573                                   help='Specif    513                                   help='Specifies the file to read results from.',
574                                   type=str, na    514                                   type=str, nargs='?', metavar='input_file')
575                                                   515 
576         cli_args = parser.parse_args(massage_a    516         cli_args = parser.parse_args(massage_argv(argv))
577                                                   517 
578         if get_kernel_root_path():                518         if get_kernel_root_path():
579                 os.chdir(get_kernel_root_path(    519                 os.chdir(get_kernel_root_path())
580                                                   520 
581         subcomand_handler = subcommand_handler    521         subcomand_handler = subcommand_handlers_map.get(cli_args.subcommand, None)
582                                                   522 
583         if subcomand_handler is None:             523         if subcomand_handler is None:
584                 parser.print_help()               524                 parser.print_help()
585                 return                            525                 return
586                                                   526 
587         subcomand_handler(cli_args)               527         subcomand_handler(cli_args)
588                                                   528 
589                                                   529 
590 if __name__ == '__main__':                        530 if __name__ == '__main__':
591         main(sys.argv[1:])                        531         main(sys.argv[1:])
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php