~ [ 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.1.116)


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