16ebf5866SFelix Guo#!/usr/bin/python3 26ebf5866SFelix Guo# SPDX-License-Identifier: GPL-2.0 36ebf5866SFelix Guo# 46ebf5866SFelix Guo# A thin wrapper on top of the KUnit Kernel 56ebf5866SFelix Guo# 66ebf5866SFelix Guo# Copyright (C) 2019, Google LLC. 76ebf5866SFelix Guo# Author: Felix Guo <felixguoxiuping@gmail.com> 86ebf5866SFelix Guo# Author: Brendan Higgins <brendanhiggins@google.com> 96ebf5866SFelix Guo 106ebf5866SFelix Guoimport argparse 116ebf5866SFelix Guoimport sys 126ebf5866SFelix Guoimport os 136ebf5866SFelix Guoimport time 14ff7b437fSBrendan Higginsimport shutil 156ebf5866SFelix Guo 166ebf5866SFelix Guofrom collections import namedtuple 176ebf5866SFelix Guofrom enum import Enum, auto 186ebf5866SFelix Guo 196ebf5866SFelix Guoimport kunit_config 206ebf5866SFelix Guoimport kunit_kernel 216ebf5866SFelix Guoimport kunit_parser 226ebf5866SFelix Guo 236ebf5866SFelix GuoKunitResult = namedtuple('KunitResult', ['status','result']) 246ebf5866SFelix Guo 25021ed9f5SHeidi FahimKunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 26021ed9f5SHeidi Fahim 'build_dir', 'defconfig', 27*0476e69fSGreg Thelen 'alltests', 'make_options']) 286ebf5866SFelix Guo 29be886ba9SHeidi FahimKernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0] 30be886ba9SHeidi Fahim 316ebf5866SFelix Guoclass KunitStatus(Enum): 326ebf5866SFelix Guo SUCCESS = auto() 336ebf5866SFelix Guo CONFIG_FAILURE = auto() 346ebf5866SFelix Guo BUILD_FAILURE = auto() 356ebf5866SFelix Guo TEST_FAILURE = auto() 366ebf5866SFelix Guo 37ff7b437fSBrendan Higginsdef create_default_kunitconfig(): 38e3212513SSeongJae Park if not os.path.exists(kunit_kernel.kunitconfig_path): 39ff7b437fSBrendan Higgins shutil.copyfile('arch/um/configs/kunit_defconfig', 40e3212513SSeongJae Park kunit_kernel.kunitconfig_path) 41ff7b437fSBrendan Higgins 42be886ba9SHeidi Fahimdef get_kernel_root_path(): 43be886ba9SHeidi Fahim parts = sys.argv[0] if not __file__ else __file__ 44be886ba9SHeidi Fahim parts = os.path.realpath(parts).split('tools/testing/kunit') 45be886ba9SHeidi Fahim if len(parts) != 2: 46be886ba9SHeidi Fahim sys.exit(1) 47be886ba9SHeidi Fahim return parts[0] 48be886ba9SHeidi Fahim 496ebf5866SFelix Guodef run_tests(linux: kunit_kernel.LinuxSourceTree, 506ebf5866SFelix Guo request: KunitRequest) -> KunitResult: 516ebf5866SFelix Guo config_start = time.time() 52*0476e69fSGreg Thelen success = linux.build_reconfig(request.build_dir, request.make_options) 536ebf5866SFelix Guo config_end = time.time() 546ebf5866SFelix Guo if not success: 556ebf5866SFelix Guo return KunitResult(KunitStatus.CONFIG_FAILURE, 'could not configure kernel') 566ebf5866SFelix Guo 576ebf5866SFelix Guo kunit_parser.print_with_timestamp('Building KUnit Kernel ...') 586ebf5866SFelix Guo 596ebf5866SFelix Guo build_start = time.time() 60021ed9f5SHeidi Fahim success = linux.build_um_kernel(request.alltests, 61021ed9f5SHeidi Fahim request.jobs, 62*0476e69fSGreg Thelen request.build_dir, 63*0476e69fSGreg Thelen request.make_options) 646ebf5866SFelix Guo build_end = time.time() 656ebf5866SFelix Guo if not success: 666ebf5866SFelix Guo return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel') 676ebf5866SFelix Guo 686ebf5866SFelix Guo kunit_parser.print_with_timestamp('Starting KUnit Kernel ...') 696ebf5866SFelix Guo test_start = time.time() 70021ed9f5SHeidi Fahim kunit_output = linux.run_kernel( 71021ed9f5SHeidi Fahim timeout=None if request.alltests else request.timeout, 726ec1b81dSSeongJae Park build_dir=request.build_dir) 73021ed9f5SHeidi Fahim if request.raw_output: 74021ed9f5SHeidi Fahim raw_output = kunit_parser.raw_output(kunit_output) 75021ed9f5SHeidi Fahim isolated = list(kunit_parser.isolate_kunit_output(raw_output)) 76021ed9f5SHeidi Fahim test_result = kunit_parser.parse_test_result(isolated) 77021ed9f5SHeidi Fahim else: 786ebf5866SFelix Guo test_result = kunit_parser.parse_run_tests(kunit_output) 796ebf5866SFelix Guo test_end = time.time() 806ebf5866SFelix Guo 816ebf5866SFelix Guo kunit_parser.print_with_timestamp(( 826ebf5866SFelix Guo 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' + 836ebf5866SFelix Guo 'building, %.3fs running\n') % ( 846ebf5866SFelix Guo test_end - config_start, 856ebf5866SFelix Guo config_end - config_start, 866ebf5866SFelix Guo build_end - build_start, 876ebf5866SFelix Guo test_end - test_start)) 886ebf5866SFelix Guo 896ebf5866SFelix Guo if test_result.status != kunit_parser.TestStatus.SUCCESS: 906ebf5866SFelix Guo return KunitResult(KunitStatus.TEST_FAILURE, test_result) 916ebf5866SFelix Guo else: 926ebf5866SFelix Guo return KunitResult(KunitStatus.SUCCESS, test_result) 936ebf5866SFelix Guo 94ff7b437fSBrendan Higginsdef main(argv, linux=None): 956ebf5866SFelix Guo parser = argparse.ArgumentParser( 966ebf5866SFelix Guo description='Helps writing and running KUnit tests.') 976ebf5866SFelix Guo subparser = parser.add_subparsers(dest='subcommand') 986ebf5866SFelix Guo 996ebf5866SFelix Guo run_parser = subparser.add_parser('run', help='Runs KUnit tests.') 1006ebf5866SFelix Guo run_parser.add_argument('--raw_output', help='don\'t format output from kernel', 1016ebf5866SFelix Guo action='store_true') 1026ebf5866SFelix Guo 1036ebf5866SFelix Guo run_parser.add_argument('--timeout', 1046ebf5866SFelix Guo help='maximum number of seconds to allow for all tests ' 1056ebf5866SFelix Guo 'to run. This does not include time taken to build the ' 1066ebf5866SFelix Guo 'tests.', 1076ebf5866SFelix Guo type=int, 1086ebf5866SFelix Guo default=300, 1096ebf5866SFelix Guo metavar='timeout') 1106ebf5866SFelix Guo 1116ebf5866SFelix Guo run_parser.add_argument('--jobs', 1126ebf5866SFelix Guo help='As in the make command, "Specifies the number of ' 1136ebf5866SFelix Guo 'jobs (commands) to run simultaneously."', 1146ebf5866SFelix Guo type=int, default=8, metavar='jobs') 1156ebf5866SFelix Guo 1166ebf5866SFelix Guo run_parser.add_argument('--build_dir', 1176ebf5866SFelix Guo help='As in the make command, it specifies the build ' 1186ebf5866SFelix Guo 'directory.', 119609952c2SSeongJae Park type=str, default='', metavar='build_dir') 1206ebf5866SFelix Guo 121ff7b437fSBrendan Higgins run_parser.add_argument('--defconfig', 12214ee5cfdSSeongJae Park help='Uses a default .kunitconfig.', 123ff7b437fSBrendan Higgins action='store_true') 124ff7b437fSBrendan Higgins 125021ed9f5SHeidi Fahim run_parser.add_argument('--alltests', 126021ed9f5SHeidi Fahim help='Run all KUnit tests through allyesconfig', 127021ed9f5SHeidi Fahim action='store_true') 128021ed9f5SHeidi Fahim 129*0476e69fSGreg Thelen run_parser.add_argument('--make_options', 130*0476e69fSGreg Thelen help='X=Y make option, can be repeated.', 131*0476e69fSGreg Thelen action='append') 132*0476e69fSGreg Thelen 1336ebf5866SFelix Guo cli_args = parser.parse_args(argv) 1346ebf5866SFelix Guo 1356ebf5866SFelix Guo if cli_args.subcommand == 'run': 136be886ba9SHeidi Fahim if get_kernel_root_path(): 137be886ba9SHeidi Fahim os.chdir(get_kernel_root_path()) 138be886ba9SHeidi Fahim 139e3212513SSeongJae Park if cli_args.build_dir: 140e3212513SSeongJae Park if not os.path.exists(cli_args.build_dir): 141e3212513SSeongJae Park os.mkdir(cli_args.build_dir) 142e3212513SSeongJae Park kunit_kernel.kunitconfig_path = os.path.join( 143e3212513SSeongJae Park cli_args.build_dir, 144e3212513SSeongJae Park kunit_kernel.kunitconfig_path) 145e3212513SSeongJae Park 146ff7b437fSBrendan Higgins if cli_args.defconfig: 147ff7b437fSBrendan Higgins create_default_kunitconfig() 148ff7b437fSBrendan Higgins 149ff7b437fSBrendan Higgins if not linux: 150ff7b437fSBrendan Higgins linux = kunit_kernel.LinuxSourceTree() 151ff7b437fSBrendan Higgins 1526ebf5866SFelix Guo request = KunitRequest(cli_args.raw_output, 1536ebf5866SFelix Guo cli_args.timeout, 1546ebf5866SFelix Guo cli_args.jobs, 155ff7b437fSBrendan Higgins cli_args.build_dir, 156021ed9f5SHeidi Fahim cli_args.defconfig, 157*0476e69fSGreg Thelen cli_args.alltests, 158*0476e69fSGreg Thelen cli_args.make_options) 1596ebf5866SFelix Guo result = run_tests(linux, request) 1606ebf5866SFelix Guo if result.status != KunitStatus.SUCCESS: 1616ebf5866SFelix Guo sys.exit(1) 1626ebf5866SFelix Guo else: 1636ebf5866SFelix Guo parser.print_help() 1646ebf5866SFelix Guo 1656ebf5866SFelix Guoif __name__ == '__main__': 166ff7b437fSBrendan Higgins main(sys.argv[1:]) 167