kunit.py (d053cf0d771f6547cb0537759a9af63cf402908d) | kunit.py (01397e822af42f8485e876ba9d1309b63646d886) |
---|---|
1#!/usr/bin/python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# A thin wrapper on top of the KUnit Kernel 5# 6# Copyright (C) 2019, Google LLC. 7# Author: Felix Guo <felixguoxiuping@gmail.com> 8# Author: Brendan Higgins <brendanhiggins@google.com> --- 6 unchanged lines hidden (view full) --- 15 16from collections import namedtuple 17from enum import Enum, auto 18 19import kunit_config 20import kunit_kernel 21import kunit_parser 22 | 1#!/usr/bin/python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# A thin wrapper on top of the KUnit Kernel 5# 6# Copyright (C) 2019, Google LLC. 7# Author: Felix Guo <felixguoxiuping@gmail.com> 8# Author: Brendan Higgins <brendanhiggins@google.com> --- 6 unchanged lines hidden (view full) --- 15 16from collections import namedtuple 17from enum import Enum, auto 18 19import kunit_config 20import kunit_kernel 21import kunit_parser 22 |
23KunitResult = namedtuple('KunitResult', ['status','result']) | 23KunitResult = namedtuple('KunitResult', ['status','result','elapsed_time']) |
24 | 24 |
25KunitConfigRequest = namedtuple('KunitConfigRequest', 26 ['build_dir', 'make_options']) 27KunitBuildRequest = namedtuple('KunitBuildRequest', 28 ['jobs', 'build_dir', 'alltests', 29 'make_options']) 30KunitExecRequest = namedtuple('KunitExecRequest', 31 ['timeout', 'build_dir', 'alltests']) 32KunitParseRequest = namedtuple('KunitParseRequest', 33 ['raw_output', 'input_data']) |
|
25KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', | 34KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', |
26 'build_dir', 'defconfig', 27 'alltests', 'make_options']) | 35 'build_dir', 'alltests', 36 'make_options']) |
28 29KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0] 30 31class KunitStatus(Enum): 32 SUCCESS = auto() 33 CONFIG_FAILURE = auto() 34 BUILD_FAILURE = auto() 35 TEST_FAILURE = auto() --- 5 unchanged lines hidden (view full) --- 41 42def get_kernel_root_path(): 43 parts = sys.argv[0] if not __file__ else __file__ 44 parts = os.path.realpath(parts).split('tools/testing/kunit') 45 if len(parts) != 2: 46 sys.exit(1) 47 return parts[0] 48 | 37 38KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0] 39 40class KunitStatus(Enum): 41 SUCCESS = auto() 42 CONFIG_FAILURE = auto() 43 BUILD_FAILURE = auto() 44 TEST_FAILURE = auto() --- 5 unchanged lines hidden (view full) --- 50 51def get_kernel_root_path(): 52 parts = sys.argv[0] if not __file__ else __file__ 53 parts = os.path.realpath(parts).split('tools/testing/kunit') 54 if len(parts) != 2: 55 sys.exit(1) 56 return parts[0] 57 |
49def run_tests(linux: kunit_kernel.LinuxSourceTree, 50 request: KunitRequest) -> KunitResult: | 58def config_tests(linux: kunit_kernel.LinuxSourceTree, 59 request: KunitConfigRequest) -> KunitResult: 60 kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...') 61 |
51 config_start = time.time() | 62 config_start = time.time() |
63 create_default_kunitconfig() |
|
52 success = linux.build_reconfig(request.build_dir, request.make_options) 53 config_end = time.time() 54 if not success: | 64 success = linux.build_reconfig(request.build_dir, request.make_options) 65 config_end = time.time() 66 if not success: |
55 return KunitResult(KunitStatus.CONFIG_FAILURE, 'could not configure kernel') | 67 return KunitResult(KunitStatus.CONFIG_FAILURE, 68 'could not configure kernel', 69 config_end - config_start) 70 return KunitResult(KunitStatus.SUCCESS, 71 'configured kernel successfully', 72 config_end - config_start) |
56 | 73 |
74def build_tests(linux: kunit_kernel.LinuxSourceTree, 75 request: KunitBuildRequest) -> KunitResult: |
|
57 kunit_parser.print_with_timestamp('Building KUnit Kernel ...') 58 59 build_start = time.time() 60 success = linux.build_um_kernel(request.alltests, 61 request.jobs, 62 request.build_dir, 63 request.make_options) 64 build_end = time.time() 65 if not success: 66 return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel') | 76 kunit_parser.print_with_timestamp('Building KUnit Kernel ...') 77 78 build_start = time.time() 79 success = linux.build_um_kernel(request.alltests, 80 request.jobs, 81 request.build_dir, 82 request.make_options) 83 build_end = time.time() 84 if not success: 85 return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel') |
86 if not success: 87 return KunitResult(KunitStatus.BUILD_FAILURE, 88 'could not build kernel', 89 build_end - build_start) 90 return KunitResult(KunitStatus.SUCCESS, 91 'built kernel successfully', 92 build_end - build_start) |
|
67 | 93 |
94def exec_tests(linux: kunit_kernel.LinuxSourceTree, 95 request: KunitExecRequest) -> KunitResult: |
|
68 kunit_parser.print_with_timestamp('Starting KUnit Kernel ...') 69 test_start = time.time() | 96 kunit_parser.print_with_timestamp('Starting KUnit Kernel ...') 97 test_start = time.time() |
70 kunit_output = linux.run_kernel( | 98 result = linux.run_kernel( |
71 timeout=None if request.alltests else request.timeout, 72 build_dir=request.build_dir) | 99 timeout=None if request.alltests else request.timeout, 100 build_dir=request.build_dir) |
101 102 test_end = time.time() 103 104 return KunitResult(KunitStatus.SUCCESS, 105 result, 106 test_end - test_start) 107 108def parse_tests(request: KunitParseRequest) -> KunitResult: 109 parse_start = time.time() 110 111 test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS, 112 [], 113 'Tests not Parsed.') |
|
73 if request.raw_output: | 114 if request.raw_output: |
74 raw_output = kunit_parser.raw_output(kunit_output) 75 isolated = list(kunit_parser.isolate_kunit_output(raw_output)) 76 test_result = kunit_parser.parse_test_result(isolated) | 115 kunit_parser.raw_output(request.input_data) |
77 else: | 116 else: |
78 test_result = kunit_parser.parse_run_tests(kunit_output) 79 test_end = time.time() | 117 test_result = kunit_parser.parse_run_tests(request.input_data) 118 parse_end = time.time() |
80 | 119 |
120 if test_result.status != kunit_parser.TestStatus.SUCCESS: 121 return KunitResult(KunitStatus.TEST_FAILURE, test_result, 122 parse_end - parse_start) 123 124 return KunitResult(KunitStatus.SUCCESS, test_result, 125 parse_end - parse_start) 126 127 128def run_tests(linux: kunit_kernel.LinuxSourceTree, 129 request: KunitRequest) -> KunitResult: 130 run_start = time.time() 131 132 config_request = KunitConfigRequest(request.build_dir, 133 request.make_options) 134 config_result = config_tests(linux, config_request) 135 if config_result.status != KunitStatus.SUCCESS: 136 return config_result 137 138 build_request = KunitBuildRequest(request.jobs, request.build_dir, 139 request.alltests, 140 request.make_options) 141 build_result = build_tests(linux, build_request) 142 if build_result.status != KunitStatus.SUCCESS: 143 return build_result 144 145 exec_request = KunitExecRequest(request.timeout, request.build_dir, 146 request.alltests) 147 exec_result = exec_tests(linux, exec_request) 148 if exec_result.status != KunitStatus.SUCCESS: 149 return exec_result 150 151 parse_request = KunitParseRequest(request.raw_output, 152 exec_result.result) 153 parse_result = parse_tests(parse_request) 154 155 run_end = time.time() 156 |
|
81 kunit_parser.print_with_timestamp(( 82 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' + 83 'building, %.3fs running\n') % ( | 157 kunit_parser.print_with_timestamp(( 158 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' + 159 'building, %.3fs running\n') % ( |
84 test_end - config_start, 85 config_end - config_start, 86 build_end - build_start, 87 test_end - test_start)) | 160 run_end - run_start, 161 config_result.elapsed_time, 162 build_result.elapsed_time, 163 exec_result.elapsed_time)) 164 return parse_result |
88 | 165 |
89 if test_result.status != kunit_parser.TestStatus.SUCCESS: 90 return KunitResult(KunitStatus.TEST_FAILURE, test_result) 91 else: 92 return KunitResult(KunitStatus.SUCCESS, test_result) | 166def add_common_opts(parser): 167 parser.add_argument('--build_dir', 168 help='As in the make command, it specifies the build ' 169 'directory.', 170 type=str, default='.kunit', metavar='build_dir') 171 parser.add_argument('--make_options', 172 help='X=Y make option, can be repeated.', 173 action='append') 174 parser.add_argument('--alltests', 175 help='Run all KUnit tests through allyesconfig', 176 action='store_true') |
93 | 177 |
178def add_build_opts(parser): 179 parser.add_argument('--jobs', 180 help='As in the make command, "Specifies the number of ' 181 'jobs (commands) to run simultaneously."', 182 type=int, default=8, metavar='jobs') 183 184def add_exec_opts(parser): 185 parser.add_argument('--timeout', 186 help='maximum number of seconds to allow for all tests ' 187 'to run. This does not include time taken to build the ' 188 'tests.', 189 type=int, 190 default=300, 191 metavar='timeout') 192 193def add_parse_opts(parser): 194 parser.add_argument('--raw_output', help='don\'t format output from kernel', 195 action='store_true') 196 197 |
|
94def main(argv, linux=None): 95 parser = argparse.ArgumentParser( 96 description='Helps writing and running KUnit tests.') 97 subparser = parser.add_subparsers(dest='subcommand') 98 | 198def main(argv, linux=None): 199 parser = argparse.ArgumentParser( 200 description='Helps writing and running KUnit tests.') 201 subparser = parser.add_subparsers(dest='subcommand') 202 |
203 # The 'run' command will config, build, exec, and parse in one go. |
|
99 run_parser = subparser.add_parser('run', help='Runs KUnit tests.') | 204 run_parser = subparser.add_parser('run', help='Runs KUnit tests.') |
100 run_parser.add_argument('--raw_output', help='don\'t format output from kernel', 101 action='store_true') | 205 add_common_opts(run_parser) 206 add_build_opts(run_parser) 207 add_exec_opts(run_parser) 208 add_parse_opts(run_parser) |
102 | 209 |
103 run_parser.add_argument('--timeout', 104 help='maximum number of seconds to allow for all tests ' 105 'to run. This does not include time taken to build the ' 106 'tests.', 107 type=int, 108 default=300, 109 metavar='timeout') | 210 config_parser = subparser.add_parser('config', 211 help='Ensures that .config contains all of ' 212 'the options in .kunitconfig') 213 add_common_opts(config_parser) |
110 | 214 |
111 run_parser.add_argument('--jobs', 112 help='As in the make command, "Specifies the number of ' 113 'jobs (commands) to run simultaneously."', 114 type=int, default=8, metavar='jobs') | 215 build_parser = subparser.add_parser('build', help='Builds a kernel with KUnit tests') 216 add_common_opts(build_parser) 217 add_build_opts(build_parser) |
115 | 218 |
116 run_parser.add_argument('--build_dir', 117 help='As in the make command, it specifies the build ' 118 'directory.', 119 type=str, default='', metavar='build_dir') | 219 exec_parser = subparser.add_parser('exec', help='Run a kernel with KUnit tests') 220 add_common_opts(exec_parser) 221 add_exec_opts(exec_parser) 222 add_parse_opts(exec_parser) |
120 | 223 |
121 run_parser.add_argument('--defconfig', 122 help='Uses a default .kunitconfig.', 123 action='store_true') | 224 # The 'parse' option is special, as it doesn't need the kernel source 225 # (therefore there is no need for a build_dir, hence no add_common_opts) 226 # and the '--file' argument is not relevant to 'run', so isn't in 227 # add_parse_opts() 228 parse_parser = subparser.add_parser('parse', 229 help='Parses KUnit results from a file, ' 230 'and parses formatted results.') 231 add_parse_opts(parse_parser) 232 parse_parser.add_argument('file', 233 help='Specifies the file to read results from.', 234 type=str, nargs='?', metavar='input_file') |
124 | 235 |
125 run_parser.add_argument('--alltests', 126 help='Run all KUnit tests through allyesconfig', 127 action='store_true') 128 129 run_parser.add_argument('--make_options', 130 help='X=Y make option, can be repeated.', 131 action='append') 132 | |
133 cli_args = parser.parse_args(argv) 134 135 if cli_args.subcommand == 'run': | 236 cli_args = parser.parse_args(argv) 237 238 if cli_args.subcommand == 'run': |
136 if get_kernel_root_path(): 137 os.chdir(get_kernel_root_path()) | 239 if not os.path.exists(cli_args.build_dir): 240 os.mkdir(cli_args.build_dir) 241 kunit_kernel.kunitconfig_path = os.path.join( 242 cli_args.build_dir, 243 kunit_kernel.kunitconfig_path) |
138 | 244 |
139 if cli_args.build_dir: 140 if not os.path.exists(cli_args.build_dir): 141 os.mkdir(cli_args.build_dir) 142 kunit_kernel.kunitconfig_path = os.path.join( 143 cli_args.build_dir, 144 kunit_kernel.kunitconfig_path) 145 146 if cli_args.defconfig: | 245 if not os.path.exists(kunit_kernel.kunitconfig_path): |
147 create_default_kunitconfig() 148 149 if not linux: 150 linux = kunit_kernel.LinuxSourceTree() 151 152 request = KunitRequest(cli_args.raw_output, 153 cli_args.timeout, 154 cli_args.jobs, 155 cli_args.build_dir, | 246 create_default_kunitconfig() 247 248 if not linux: 249 linux = kunit_kernel.LinuxSourceTree() 250 251 request = KunitRequest(cli_args.raw_output, 252 cli_args.timeout, 253 cli_args.jobs, 254 cli_args.build_dir, |
156 cli_args.defconfig, | |
157 cli_args.alltests, 158 cli_args.make_options) 159 result = run_tests(linux, request) 160 if result.status != KunitStatus.SUCCESS: 161 sys.exit(1) | 255 cli_args.alltests, 256 cli_args.make_options) 257 result = run_tests(linux, request) 258 if result.status != KunitStatus.SUCCESS: 259 sys.exit(1) |
260 elif cli_args.subcommand == 'config': 261 if cli_args.build_dir: 262 if not os.path.exists(cli_args.build_dir): 263 os.mkdir(cli_args.build_dir) 264 kunit_kernel.kunitconfig_path = os.path.join( 265 cli_args.build_dir, 266 kunit_kernel.kunitconfig_path) 267 268 if not os.path.exists(kunit_kernel.kunitconfig_path): 269 create_default_kunitconfig() 270 271 if not linux: 272 linux = kunit_kernel.LinuxSourceTree() 273 274 request = KunitConfigRequest(cli_args.build_dir, 275 cli_args.make_options) 276 result = config_tests(linux, request) 277 kunit_parser.print_with_timestamp(( 278 'Elapsed time: %.3fs\n') % ( 279 result.elapsed_time)) 280 if result.status != KunitStatus.SUCCESS: 281 sys.exit(1) 282 elif cli_args.subcommand == 'build': 283 if cli_args.build_dir: 284 if not os.path.exists(cli_args.build_dir): 285 os.mkdir(cli_args.build_dir) 286 kunit_kernel.kunitconfig_path = os.path.join( 287 cli_args.build_dir, 288 kunit_kernel.kunitconfig_path) 289 290 if not os.path.exists(kunit_kernel.kunitconfig_path): 291 create_default_kunitconfig() 292 293 if not linux: 294 linux = kunit_kernel.LinuxSourceTree() 295 296 request = KunitBuildRequest(cli_args.jobs, 297 cli_args.build_dir, 298 cli_args.alltests, 299 cli_args.make_options) 300 result = build_tests(linux, request) 301 kunit_parser.print_with_timestamp(( 302 'Elapsed time: %.3fs\n') % ( 303 result.elapsed_time)) 304 if result.status != KunitStatus.SUCCESS: 305 sys.exit(1) 306 elif cli_args.subcommand == 'exec': 307 if cli_args.build_dir: 308 if not os.path.exists(cli_args.build_dir): 309 os.mkdir(cli_args.build_dir) 310 kunit_kernel.kunitconfig_path = os.path.join( 311 cli_args.build_dir, 312 kunit_kernel.kunitconfig_path) 313 314 if not os.path.exists(kunit_kernel.kunitconfig_path): 315 create_default_kunitconfig() 316 317 if not linux: 318 linux = kunit_kernel.LinuxSourceTree() 319 320 exec_request = KunitExecRequest(cli_args.timeout, 321 cli_args.build_dir, 322 cli_args.alltests) 323 exec_result = exec_tests(linux, exec_request) 324 parse_request = KunitParseRequest(cli_args.raw_output, 325 exec_result.result) 326 result = parse_tests(parse_request) 327 kunit_parser.print_with_timestamp(( 328 'Elapsed time: %.3fs\n') % ( 329 exec_result.elapsed_time)) 330 if result.status != KunitStatus.SUCCESS: 331 sys.exit(1) 332 elif cli_args.subcommand == 'parse': 333 if cli_args.file == None: 334 kunit_output = sys.stdin 335 else: 336 with open(cli_args.file, 'r') as f: 337 kunit_output = f.read().splitlines() 338 request = KunitParseRequest(cli_args.raw_output, 339 kunit_output) 340 result = parse_tests(request) 341 if result.status != KunitStatus.SUCCESS: 342 sys.exit(1) |
|
162 else: 163 parser.print_help() 164 165if __name__ == '__main__': 166 main(sys.argv[1:]) | 343 else: 344 parser.print_help() 345 346if __name__ == '__main__': 347 main(sys.argv[1:]) |