kunit.py (de4fb176622d54a82ea3ceb7362392aaf5ff0b5a) | kunit.py (00f75043e46d5bd2bba87b3fada6c1090b61bd40) |
---|---|
1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# A thin wrapper on top of the KUnit Kernel 5# 6# Copyright (C) 2019, Google LLC. 7# Author: Felix Guo <felixguoxiuping@gmail.com> 8# Author: Brendan Higgins <brendanhiggins@google.com> 9 10import argparse 11import os 12import re 13import sys 14import time 15 16assert sys.version_info >= (3, 7), "Python version is too old" 17 18from dataclasses import dataclass 19from enum import Enum, auto | 1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# 4# A thin wrapper on top of the KUnit Kernel 5# 6# Copyright (C) 2019, Google LLC. 7# Author: Felix Guo <felixguoxiuping@gmail.com> 8# Author: Brendan Higgins <brendanhiggins@google.com> 9 10import argparse 11import os 12import re 13import sys 14import time 15 16assert sys.version_info >= (3, 7), "Python version is too old" 17 18from dataclasses import dataclass 19from enum import Enum, auto |
20from typing import Any, Iterable, Sequence, List, Optional | 20from typing import Iterable, List, Optional, Sequence, Tuple |
21 22import kunit_json 23import kunit_kernel 24import kunit_parser 25 26class KunitStatus(Enum): 27 SUCCESS = auto() 28 CONFIG_FAILURE = auto() 29 BUILD_FAILURE = auto() 30 TEST_FAILURE = auto() 31 32@dataclass 33class KunitResult: 34 status: KunitStatus | 21 22import kunit_json 23import kunit_kernel 24import kunit_parser 25 26class KunitStatus(Enum): 27 SUCCESS = auto() 28 CONFIG_FAILURE = auto() 29 BUILD_FAILURE = auto() 30 TEST_FAILURE = auto() 31 32@dataclass 33class KunitResult: 34 status: KunitStatus |
35 result: Any | |
36 elapsed_time: float 37 38@dataclass 39class KunitConfigRequest: 40 build_dir: str 41 make_options: Optional[List[str]] 42 43@dataclass --- 33 unchanged lines hidden (view full) --- 77 request: KunitConfigRequest) -> KunitResult: 78 kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...') 79 80 config_start = time.time() 81 success = linux.build_reconfig(request.build_dir, request.make_options) 82 config_end = time.time() 83 if not success: 84 return KunitResult(KunitStatus.CONFIG_FAILURE, | 35 elapsed_time: float 36 37@dataclass 38class KunitConfigRequest: 39 build_dir: str 40 make_options: Optional[List[str]] 41 42@dataclass --- 33 unchanged lines hidden (view full) --- 76 request: KunitConfigRequest) -> KunitResult: 77 kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...') 78 79 config_start = time.time() 80 success = linux.build_reconfig(request.build_dir, request.make_options) 81 config_end = time.time() 82 if not success: 83 return KunitResult(KunitStatus.CONFIG_FAILURE, |
85 'could not configure kernel', | |
86 config_end - config_start) 87 return KunitResult(KunitStatus.SUCCESS, | 84 config_end - config_start) 85 return KunitResult(KunitStatus.SUCCESS, |
88 'configured kernel successfully', | |
89 config_end - config_start) 90 91def build_tests(linux: kunit_kernel.LinuxSourceTree, 92 request: KunitBuildRequest) -> KunitResult: 93 kunit_parser.print_with_timestamp('Building KUnit Kernel ...') 94 95 build_start = time.time() 96 success = linux.build_kernel(request.alltests, 97 request.jobs, 98 request.build_dir, 99 request.make_options) 100 build_end = time.time() 101 if not success: 102 return KunitResult(KunitStatus.BUILD_FAILURE, | 86 config_end - config_start) 87 88def build_tests(linux: kunit_kernel.LinuxSourceTree, 89 request: KunitBuildRequest) -> KunitResult: 90 kunit_parser.print_with_timestamp('Building KUnit Kernel ...') 91 92 build_start = time.time() 93 success = linux.build_kernel(request.alltests, 94 request.jobs, 95 request.build_dir, 96 request.make_options) 97 build_end = time.time() 98 if not success: 99 return KunitResult(KunitStatus.BUILD_FAILURE, |
103 'could not build kernel', | |
104 build_end - build_start) 105 if not success: 106 return KunitResult(KunitStatus.BUILD_FAILURE, | 100 build_end - build_start) 101 if not success: 102 return KunitResult(KunitStatus.BUILD_FAILURE, |
107 'could not build kernel', | |
108 build_end - build_start) 109 return KunitResult(KunitStatus.SUCCESS, | 103 build_end - build_start) 104 return KunitResult(KunitStatus.SUCCESS, |
110 'built kernel successfully', | |
111 build_end - build_start) 112 113def config_and_build_tests(linux: kunit_kernel.LinuxSourceTree, 114 request: KunitBuildRequest) -> KunitResult: 115 config_result = config_tests(linux, request) 116 if config_result.status != KunitStatus.SUCCESS: 117 return config_result 118 --- 49 unchanged lines hidden (view full) --- 168 169 test_start = time.time() 170 run_result = linux.run_kernel( 171 args=request.kernel_args, 172 timeout=None if request.alltests else request.timeout, 173 filter_glob=filter_glob, 174 build_dir=request.build_dir) 175 | 105 build_end - build_start) 106 107def config_and_build_tests(linux: kunit_kernel.LinuxSourceTree, 108 request: KunitBuildRequest) -> KunitResult: 109 config_result = config_tests(linux, request) 110 if config_result.status != KunitStatus.SUCCESS: 111 return config_result 112 --- 49 unchanged lines hidden (view full) --- 162 163 test_start = time.time() 164 run_result = linux.run_kernel( 165 args=request.kernel_args, 166 timeout=None if request.alltests else request.timeout, 167 filter_glob=filter_glob, 168 build_dir=request.build_dir) 169 |
176 result = parse_tests(request, run_result) | 170 _, test_result = parse_tests(request, run_result) |
177 # run_kernel() doesn't block on the kernel exiting. 178 # That only happens after we get the last line of output from `run_result`. 179 # So exec_time here actually contains parsing + execution time, which is fine. 180 test_end = time.time() 181 exec_time += test_end - test_start 182 | 171 # run_kernel() doesn't block on the kernel exiting. 172 # That only happens after we get the last line of output from `run_result`. 173 # So exec_time here actually contains parsing + execution time, which is fine. 174 test_end = time.time() 175 exec_time += test_end - test_start 176 |
183 test_counts.add_subtest_counts(result.result.counts) | 177 test_counts.add_subtest_counts(test_result.counts) |
184 185 if len(filter_globs) == 1 and test_counts.crashed > 0: 186 bd = request.build_dir 187 print('The kernel seems to have crashed; you can decode the stack traces with:') 188 print('$ scripts/decode_stacktrace.sh {}/vmlinux {} < {} | tee {}/decoded.log | {} parse'.format( 189 bd, bd, kunit_kernel.get_outfile_path(bd), bd, sys.argv[0])) 190 191 kunit_status = _map_to_overall_status(test_counts.get_status()) | 178 179 if len(filter_globs) == 1 and test_counts.crashed > 0: 180 bd = request.build_dir 181 print('The kernel seems to have crashed; you can decode the stack traces with:') 182 print('$ scripts/decode_stacktrace.sh {}/vmlinux {} < {} | tee {}/decoded.log | {} parse'.format( 183 bd, bd, kunit_kernel.get_outfile_path(bd), bd, sys.argv[0])) 184 185 kunit_status = _map_to_overall_status(test_counts.get_status()) |
192 return KunitResult(status=kunit_status, result=result, elapsed_time=exec_time) | 186 return KunitResult(status=kunit_status, elapsed_time=exec_time) |
193 194def _map_to_overall_status(test_status: kunit_parser.TestStatus) -> KunitStatus: 195 if test_status in (kunit_parser.TestStatus.SUCCESS, kunit_parser.TestStatus.SKIPPED): 196 return KunitStatus.SUCCESS 197 else: 198 return KunitStatus.TEST_FAILURE 199 | 187 188def _map_to_overall_status(test_status: kunit_parser.TestStatus) -> KunitStatus: 189 if test_status in (kunit_parser.TestStatus.SUCCESS, kunit_parser.TestStatus.SKIPPED): 190 return KunitStatus.SUCCESS 191 else: 192 return KunitStatus.TEST_FAILURE 193 |
200def parse_tests(request: KunitParseRequest, input_data: Iterable[str]) -> KunitResult: | 194def parse_tests(request: KunitParseRequest, input_data: Iterable[str]) -> Tuple[KunitResult, kunit_parser.Test]: |
201 parse_start = time.time() 202 203 test_result = kunit_parser.Test() 204 205 if request.raw_output: 206 # Treat unparsed results as one passing test. 207 test_result.status = kunit_parser.TestStatus.SUCCESS 208 test_result.counts.passed = 1 --- 8 unchanged lines hidden (view full) --- 217 for line in output: 218 print(line.rstrip()) 219 220 else: 221 test_result = kunit_parser.parse_run_tests(input_data) 222 parse_end = time.time() 223 224 if request.json: | 195 parse_start = time.time() 196 197 test_result = kunit_parser.Test() 198 199 if request.raw_output: 200 # Treat unparsed results as one passing test. 201 test_result.status = kunit_parser.TestStatus.SUCCESS 202 test_result.counts.passed = 1 --- 8 unchanged lines hidden (view full) --- 211 for line in output: 212 print(line.rstrip()) 213 214 else: 215 test_result = kunit_parser.parse_run_tests(input_data) 216 parse_end = time.time() 217 218 if request.json: |
225 json_obj = kunit_json.get_json_result( | 219 json_str = kunit_json.get_json_result( |
226 test=test_result, 227 def_config='kunit_defconfig', | 220 test=test_result, 221 def_config='kunit_defconfig', |
228 build_dir=request.build_dir, 229 json_path=request.json) | 222 build_dir=request.build_dir) |
230 if request.json == 'stdout': | 223 if request.json == 'stdout': |
231 print(json_obj) | 224 print(json_str) 225 else: 226 with open(request.json, 'w') as f: 227 f.write(json_str) 228 kunit_parser.print_with_timestamp("Test results stored in %s" % 229 os.path.abspath(request.json)) |
232 233 if test_result.status != kunit_parser.TestStatus.SUCCESS: | 230 231 if test_result.status != kunit_parser.TestStatus.SUCCESS: |
234 return KunitResult(KunitStatus.TEST_FAILURE, test_result, 235 parse_end - parse_start) | 232 return KunitResult(KunitStatus.TEST_FAILURE, parse_end - parse_start), test_result |
236 | 233 |
237 return KunitResult(KunitStatus.SUCCESS, test_result, 238 parse_end - parse_start) | 234 return KunitResult(KunitStatus.SUCCESS, parse_end - parse_start), test_result |
239 240def run_tests(linux: kunit_kernel.LinuxSourceTree, 241 request: KunitRequest) -> KunitResult: 242 run_start = time.time() 243 244 config_result = config_tests(linux, request) 245 if config_result.status != KunitStatus.SUCCESS: 246 return config_result --- 261 unchanged lines hidden (view full) --- 508 sys.stdin.reconfigure(errors='backslashreplace') # pytype: disable=attribute-error 509 kunit_output = sys.stdin 510 else: 511 with open(cli_args.file, 'r', errors='backslashreplace') as f: 512 kunit_output = f.read().splitlines() 513 request = KunitParseRequest(raw_output=cli_args.raw_output, 514 build_dir='', 515 json=cli_args.json) | 235 236def run_tests(linux: kunit_kernel.LinuxSourceTree, 237 request: KunitRequest) -> KunitResult: 238 run_start = time.time() 239 240 config_result = config_tests(linux, request) 241 if config_result.status != KunitStatus.SUCCESS: 242 return config_result --- 261 unchanged lines hidden (view full) --- 504 sys.stdin.reconfigure(errors='backslashreplace') # pytype: disable=attribute-error 505 kunit_output = sys.stdin 506 else: 507 with open(cli_args.file, 'r', errors='backslashreplace') as f: 508 kunit_output = f.read().splitlines() 509 request = KunitParseRequest(raw_output=cli_args.raw_output, 510 build_dir='', 511 json=cli_args.json) |
516 result = parse_tests(request, kunit_output) | 512 result, _ = parse_tests(request, kunit_output) |
517 if result.status != KunitStatus.SUCCESS: 518 sys.exit(1) 519 else: 520 parser.print_help() 521 522if __name__ == '__main__': 523 main(sys.argv[1:]) | 513 if result.status != KunitStatus.SUCCESS: 514 sys.exit(1) 515 else: 516 parser.print_help() 517 518if __name__ == '__main__': 519 main(sys.argv[1:]) |