Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'linux-kselftest-kunit-fixes-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull Kunit updates from Shuah Khan:
"Several kunit tool bug fixes in flag handling, run outside kernel
tree, make errors, and generating results"

* tag 'linux-kselftest-kunit-fixes-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
kunit: tool: fix display of make errors
kunit: tool: handle when .kunit exists but .kunitconfig does not
kunit: tool: fix --alltests flag
kunit: tool: allow generating test results in JSON
kunit: tool: fix running kunit_tool from outside kernel tree

+154 -28
+1
tools/testing/kunit/configs/broken_on_uml.config
··· 39 39 # CONFIG_QCOM_CPR is not set 40 40 # CONFIG_RESET_BRCMSTB_RESCAL is not set 41 41 # CONFIG_RESET_INTEL_GW is not set 42 + # CONFIG_ADI_AXI_ADC is not set
+41 -17
tools/testing/kunit/kunit.py
··· 17 17 from enum import Enum, auto 18 18 19 19 import kunit_config 20 + import kunit_json 20 21 import kunit_kernel 21 22 import kunit_parser 22 23 ··· 31 30 KunitExecRequest = namedtuple('KunitExecRequest', 32 31 ['timeout', 'build_dir', 'alltests']) 33 32 KunitParseRequest = namedtuple('KunitParseRequest', 34 - ['raw_output', 'input_data']) 33 + ['raw_output', 'input_data', 'build_dir', 'json']) 35 34 KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 36 - 'build_dir', 'alltests', 35 + 'build_dir', 'alltests', 'json', 37 36 'make_options']) 38 37 39 38 KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0] ··· 114 113 test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS, 115 114 [], 116 115 'Tests not Parsed.') 116 + 117 117 if request.raw_output: 118 118 kunit_parser.raw_output(request.input_data) 119 119 else: 120 120 test_result = kunit_parser.parse_run_tests(request.input_data) 121 121 parse_end = time.time() 122 + 123 + if request.json: 124 + json_obj = kunit_json.get_json_result( 125 + test_result=test_result, 126 + def_config='kunit_defconfig', 127 + build_dir=request.build_dir, 128 + json_path=request.json) 129 + if request.json == 'stdout': 130 + print(json_obj) 122 131 123 132 if test_result.status != kunit_parser.TestStatus.SUCCESS: 124 133 return KunitResult(KunitStatus.TEST_FAILURE, test_result, ··· 162 151 return exec_result 163 152 164 153 parse_request = KunitParseRequest(request.raw_output, 165 - exec_result.result) 154 + exec_result.result, 155 + request.build_dir, 156 + request.json) 166 157 parse_result = parse_tests(parse_request) 167 158 168 159 run_end = time.time() ··· 208 195 def add_parse_opts(parser): 209 196 parser.add_argument('--raw_output', help='don\'t format output from kernel', 210 197 action='store_true') 211 - 198 + parser.add_argument('--json', 199 + nargs='?', 200 + help='Stores test results in a JSON, and either ' 201 + 'prints to stdout or saves to file if a ' 202 + 'filename is specified', 203 + type=str, const='stdout', default=None) 212 204 213 205 def main(argv, linux=None): 214 206 parser = argparse.ArgumentParser( ··· 255 237 256 238 cli_args = parser.parse_args(argv) 257 239 240 + if get_kernel_root_path(): 241 + os.chdir(get_kernel_root_path()) 242 + 258 243 if cli_args.subcommand == 'run': 259 244 if not os.path.exists(cli_args.build_dir): 260 245 os.mkdir(cli_args.build_dir) 246 + 247 + if not os.path.exists(kunit_kernel.kunitconfig_path): 248 + create_default_kunitconfig() 261 249 262 250 if not linux: 263 251 linux = kunit_kernel.LinuxSourceTree() ··· 273 249 cli_args.jobs, 274 250 cli_args.build_dir, 275 251 cli_args.alltests, 252 + cli_args.json, 276 253 cli_args.make_options) 277 254 result = run_tests(linux, request) 278 255 if result.status != KunitStatus.SUCCESS: 279 256 sys.exit(1) 280 257 elif cli_args.subcommand == 'config': 281 - if cli_args.build_dir: 282 - if not os.path.exists(cli_args.build_dir): 283 - os.mkdir(cli_args.build_dir) 258 + if cli_args.build_dir and ( 259 + not os.path.exists(cli_args.build_dir)): 260 + os.mkdir(cli_args.build_dir) 261 + 262 + if not os.path.exists(kunit_kernel.kunitconfig_path): 263 + create_default_kunitconfig() 284 264 285 265 if not linux: 286 266 linux = kunit_kernel.LinuxSourceTree() ··· 298 270 if result.status != KunitStatus.SUCCESS: 299 271 sys.exit(1) 300 272 elif cli_args.subcommand == 'build': 301 - if cli_args.build_dir: 302 - if not os.path.exists(cli_args.build_dir): 303 - os.mkdir(cli_args.build_dir) 304 - 305 273 if not linux: 306 274 linux = kunit_kernel.LinuxSourceTree() 307 275 ··· 312 288 if result.status != KunitStatus.SUCCESS: 313 289 sys.exit(1) 314 290 elif cli_args.subcommand == 'exec': 315 - if cli_args.build_dir: 316 - if not os.path.exists(cli_args.build_dir): 317 - os.mkdir(cli_args.build_dir) 318 - 319 291 if not linux: 320 292 linux = kunit_kernel.LinuxSourceTree() 321 293 ··· 320 300 cli_args.alltests) 321 301 exec_result = exec_tests(linux, exec_request) 322 302 parse_request = KunitParseRequest(cli_args.raw_output, 323 - exec_result.result) 303 + exec_result.result, 304 + cli_args.build_dir, 305 + cli_args.json) 324 306 result = parse_tests(parse_request) 325 307 kunit_parser.print_with_timestamp(( 326 308 'Elapsed time: %.3fs\n') % ( ··· 336 314 with open(cli_args.file, 'r') as f: 337 315 kunit_output = f.read().splitlines() 338 316 request = KunitParseRequest(cli_args.raw_output, 339 - kunit_output) 317 + kunit_output, 318 + cli_args.build_dir, 319 + cli_args.json) 340 320 result = parse_tests(request) 341 321 if result.status != KunitStatus.SUCCESS: 342 322 sys.exit(1)
+63
tools/testing/kunit/kunit_json.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Generates JSON from KUnit results according to 4 + # KernelCI spec: https://github.com/kernelci/kernelci-doc/wiki/Test-API 5 + # 6 + # Copyright (C) 2020, Google LLC. 7 + # Author: Heidi Fahim <heidifahim@google.com> 8 + 9 + import json 10 + import os 11 + 12 + import kunit_parser 13 + 14 + from kunit_parser import TestStatus 15 + 16 + def get_json_result(test_result, def_config, build_dir, json_path): 17 + sub_groups = [] 18 + 19 + # Each test suite is mapped to a KernelCI sub_group 20 + for test_suite in test_result.suites: 21 + sub_group = { 22 + "name": test_suite.name, 23 + "arch": "UM", 24 + "defconfig": def_config, 25 + "build_environment": build_dir, 26 + "test_cases": [], 27 + "lab_name": None, 28 + "kernel": None, 29 + "job": None, 30 + "git_branch": "kselftest", 31 + } 32 + test_cases = [] 33 + # TODO: Add attachments attribute in test_case with detailed 34 + # failure message, see https://api.kernelci.org/schema-test-case.html#get 35 + for case in test_suite.cases: 36 + test_case = {"name": case.name, "status": "FAIL"} 37 + if case.status == TestStatus.SUCCESS: 38 + test_case["status"] = "PASS" 39 + elif case.status == TestStatus.TEST_CRASHED: 40 + test_case["status"] = "ERROR" 41 + test_cases.append(test_case) 42 + sub_group["test_cases"] = test_cases 43 + sub_groups.append(sub_group) 44 + test_group = { 45 + "name": "KUnit Test Group", 46 + "arch": "UM", 47 + "defconfig": def_config, 48 + "build_environment": build_dir, 49 + "sub_groups": sub_groups, 50 + "lab_name": None, 51 + "kernel": None, 52 + "job": None, 53 + "git_branch": "kselftest", 54 + } 55 + json_obj = json.dumps(test_group, indent=4) 56 + if json_path != 'stdout': 57 + with open(json_path, 'w') as result_path: 58 + result_path.write(json_obj) 59 + root = __file__.split('tools/testing/kunit/')[0] 60 + kunit_parser.print_with_timestamp( 61 + "Test results stored in %s" % 62 + os.path.join(root, result_path.name)) 63 + return json_obj
+16 -11
tools/testing/kunit/kunit_kernel.py
··· 36 36 try: 37 37 subprocess.check_output(['make', 'mrproper'], stderr=subprocess.STDOUT) 38 38 except OSError as e: 39 - raise ConfigError('Could not call make command: ' + e) 39 + raise ConfigError('Could not call make command: ' + str(e)) 40 40 except subprocess.CalledProcessError as e: 41 - raise ConfigError(e.output) 41 + raise ConfigError(e.output.decode()) 42 42 43 43 def make_olddefconfig(self, build_dir, make_options): 44 44 command = ['make', 'ARCH=um', 'olddefconfig'] ··· 49 49 try: 50 50 subprocess.check_output(command, stderr=subprocess.STDOUT) 51 51 except OSError as e: 52 - raise ConfigError('Could not call make command: ' + e) 52 + raise ConfigError('Could not call make command: ' + str(e)) 53 53 except subprocess.CalledProcessError as e: 54 - raise ConfigError(e.output) 54 + raise ConfigError(e.output.decode()) 55 55 56 - def make_allyesconfig(self): 56 + def make_allyesconfig(self, build_dir, make_options): 57 57 kunit_parser.print_with_timestamp( 58 58 'Enabling all CONFIGs for UML...') 59 + command = ['make', 'ARCH=um', 'allyesconfig'] 60 + if make_options: 61 + command.extend(make_options) 62 + if build_dir: 63 + command += ['O=' + build_dir] 59 64 process = subprocess.Popen( 60 - ['make', 'ARCH=um', 'allyesconfig'], 65 + command, 61 66 stdout=subprocess.DEVNULL, 62 67 stderr=subprocess.STDOUT) 63 68 process.wait() 64 69 kunit_parser.print_with_timestamp( 65 70 'Disabling broken configs to run KUnit tests...') 66 71 with ExitStack() as es: 67 - config = open(KCONFIG_PATH, 'a') 72 + config = open(get_kconfig_path(build_dir), 'a') 68 73 disable = open(BROKEN_ALLCONFIG_PATH, 'r').read() 69 74 config.write(disable) 70 75 kunit_parser.print_with_timestamp( ··· 84 79 try: 85 80 subprocess.check_output(command, stderr=subprocess.STDOUT) 86 81 except OSError as e: 87 - raise BuildError('Could not call execute make: ' + e) 82 + raise BuildError('Could not call execute make: ' + str(e)) 88 83 except subprocess.CalledProcessError as e: 89 - raise BuildError(e.output) 84 + raise BuildError(e.output.decode()) 90 85 91 86 def linux_bin(self, params, timeout, build_dir, outfile): 92 87 """Runs the Linux UML binary. Must be named 'linux'.""" ··· 166 161 return self.build_config(build_dir, make_options) 167 162 168 163 def build_um_kernel(self, alltests, jobs, build_dir, make_options): 169 - if alltests: 170 - self._ops.make_allyesconfig() 171 164 try: 165 + if alltests: 166 + self._ops.make_allyesconfig(build_dir, make_options) 172 167 self._ops.make_olddefconfig(build_dir, make_options) 173 168 self._ops.make(jobs, build_dir, make_options) 174 169 except (ConfigError, BuildError) as e:
+33
tools/testing/kunit/kunit_tool_test.py
··· 11 11 12 12 import tempfile, shutil # Handling test_tmpdir 13 13 14 + import json 14 15 import os 15 16 16 17 import kunit_config 17 18 import kunit_parser 18 19 import kunit_kernel 20 + import kunit_json 19 21 import kunit 20 22 21 23 test_tmpdir = '' ··· 231 229 with open(pound_log) as file: 232 230 result = kunit_parser.parse_run_tests(file.readlines()) 233 231 self.assertEqual('kunit-resource-test', result.suites[0].name) 232 + 233 + class KUnitJsonTest(unittest.TestCase): 234 + 235 + def _json_for(self, log_file): 236 + with(open(get_absolute_path(log_file))) as file: 237 + test_result = kunit_parser.parse_run_tests(file) 238 + json_obj = kunit_json.get_json_result( 239 + test_result=test_result, 240 + def_config='kunit_defconfig', 241 + build_dir=None, 242 + json_path='stdout') 243 + return json.loads(json_obj) 244 + 245 + def test_failed_test_json(self): 246 + result = self._json_for( 247 + 'test_data/test_is_test_passed-failure.log') 248 + self.assertEqual( 249 + {'name': 'example_simple_test', 'status': 'FAIL'}, 250 + result["sub_groups"][1]["test_cases"][0]) 251 + 252 + def test_crashed_test_json(self): 253 + result = self._json_for( 254 + 'test_data/test_is_test_passed-crash.log') 255 + self.assertEqual( 256 + {'name': 'example_simple_test', 'status': 'ERROR'}, 257 + result["sub_groups"][1]["test_cases"][0]) 258 + 259 + def test_no_tests_json(self): 260 + result = self._json_for( 261 + 'test_data/test_is_test_passed-no_tests_run.log') 262 + self.assertEqual(0, len(result['sub_groups'])) 234 263 235 264 class StrContains(str): 236 265 def __eq__(self, other):