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 25*021ed9f5SHeidi FahimKunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 26*021ed9f5SHeidi Fahim 'build_dir', 'defconfig', 27*021ed9f5SHeidi Fahim 'alltests']) 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() 526ebf5866SFelix Guo success = linux.build_reconfig(request.build_dir) 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() 60*021ed9f5SHeidi Fahim success = linux.build_um_kernel(request.alltests, 61*021ed9f5SHeidi Fahim request.jobs, 62*021ed9f5SHeidi Fahim request.build_dir) 636ebf5866SFelix Guo build_end = time.time() 646ebf5866SFelix Guo if not success: 656ebf5866SFelix Guo return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel') 666ebf5866SFelix Guo 676ebf5866SFelix Guo kunit_parser.print_with_timestamp('Starting KUnit Kernel ...') 686ebf5866SFelix Guo test_start = time.time() 69*021ed9f5SHeidi Fahim kunit_output = linux.run_kernel( 70*021ed9f5SHeidi Fahim timeout=None if request.alltests else request.timeout, 716ec1b81dSSeongJae Park build_dir=request.build_dir) 72*021ed9f5SHeidi Fahim if request.raw_output: 73*021ed9f5SHeidi Fahim raw_output = kunit_parser.raw_output(kunit_output) 74*021ed9f5SHeidi Fahim isolated = list(kunit_parser.isolate_kunit_output(raw_output)) 75*021ed9f5SHeidi Fahim test_result = kunit_parser.parse_test_result(isolated) 76*021ed9f5SHeidi Fahim else: 776ebf5866SFelix Guo test_result = kunit_parser.parse_run_tests(kunit_output) 786ebf5866SFelix Guo test_end = time.time() 796ebf5866SFelix Guo 806ebf5866SFelix Guo kunit_parser.print_with_timestamp(( 816ebf5866SFelix Guo 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' + 826ebf5866SFelix Guo 'building, %.3fs running\n') % ( 836ebf5866SFelix Guo test_end - config_start, 846ebf5866SFelix Guo config_end - config_start, 856ebf5866SFelix Guo build_end - build_start, 866ebf5866SFelix Guo test_end - test_start)) 876ebf5866SFelix Guo 886ebf5866SFelix Guo if test_result.status != kunit_parser.TestStatus.SUCCESS: 896ebf5866SFelix Guo return KunitResult(KunitStatus.TEST_FAILURE, test_result) 906ebf5866SFelix Guo else: 916ebf5866SFelix Guo return KunitResult(KunitStatus.SUCCESS, test_result) 926ebf5866SFelix Guo 93ff7b437fSBrendan Higginsdef main(argv, linux=None): 946ebf5866SFelix Guo parser = argparse.ArgumentParser( 956ebf5866SFelix Guo description='Helps writing and running KUnit tests.') 966ebf5866SFelix Guo subparser = parser.add_subparsers(dest='subcommand') 976ebf5866SFelix Guo 986ebf5866SFelix Guo run_parser = subparser.add_parser('run', help='Runs KUnit tests.') 996ebf5866SFelix Guo run_parser.add_argument('--raw_output', help='don\'t format output from kernel', 1006ebf5866SFelix Guo action='store_true') 1016ebf5866SFelix Guo 1026ebf5866SFelix Guo run_parser.add_argument('--timeout', 1036ebf5866SFelix Guo help='maximum number of seconds to allow for all tests ' 1046ebf5866SFelix Guo 'to run. This does not include time taken to build the ' 1056ebf5866SFelix Guo 'tests.', 1066ebf5866SFelix Guo type=int, 1076ebf5866SFelix Guo default=300, 1086ebf5866SFelix Guo metavar='timeout') 1096ebf5866SFelix Guo 1106ebf5866SFelix Guo run_parser.add_argument('--jobs', 1116ebf5866SFelix Guo help='As in the make command, "Specifies the number of ' 1126ebf5866SFelix Guo 'jobs (commands) to run simultaneously."', 1136ebf5866SFelix Guo type=int, default=8, metavar='jobs') 1146ebf5866SFelix Guo 1156ebf5866SFelix Guo run_parser.add_argument('--build_dir', 1166ebf5866SFelix Guo help='As in the make command, it specifies the build ' 1176ebf5866SFelix Guo 'directory.', 118609952c2SSeongJae Park type=str, default='', metavar='build_dir') 1196ebf5866SFelix Guo 120ff7b437fSBrendan Higgins run_parser.add_argument('--defconfig', 12114ee5cfdSSeongJae Park help='Uses a default .kunitconfig.', 122ff7b437fSBrendan Higgins action='store_true') 123ff7b437fSBrendan Higgins 124*021ed9f5SHeidi Fahim run_parser.add_argument('--alltests', 125*021ed9f5SHeidi Fahim help='Run all KUnit tests through allyesconfig', 126*021ed9f5SHeidi Fahim action='store_true') 127*021ed9f5SHeidi Fahim 1286ebf5866SFelix Guo cli_args = parser.parse_args(argv) 1296ebf5866SFelix Guo 1306ebf5866SFelix Guo if cli_args.subcommand == 'run': 131be886ba9SHeidi Fahim if get_kernel_root_path(): 132be886ba9SHeidi Fahim os.chdir(get_kernel_root_path()) 133be886ba9SHeidi Fahim 134e3212513SSeongJae Park if cli_args.build_dir: 135e3212513SSeongJae Park if not os.path.exists(cli_args.build_dir): 136e3212513SSeongJae Park os.mkdir(cli_args.build_dir) 137e3212513SSeongJae Park kunit_kernel.kunitconfig_path = os.path.join( 138e3212513SSeongJae Park cli_args.build_dir, 139e3212513SSeongJae Park kunit_kernel.kunitconfig_path) 140e3212513SSeongJae Park 141ff7b437fSBrendan Higgins if cli_args.defconfig: 142ff7b437fSBrendan Higgins create_default_kunitconfig() 143ff7b437fSBrendan Higgins 144ff7b437fSBrendan Higgins if not linux: 145ff7b437fSBrendan Higgins linux = kunit_kernel.LinuxSourceTree() 146ff7b437fSBrendan Higgins 1476ebf5866SFelix Guo request = KunitRequest(cli_args.raw_output, 1486ebf5866SFelix Guo cli_args.timeout, 1496ebf5866SFelix Guo cli_args.jobs, 150ff7b437fSBrendan Higgins cli_args.build_dir, 151*021ed9f5SHeidi Fahim cli_args.defconfig, 152*021ed9f5SHeidi Fahim cli_args.alltests) 1536ebf5866SFelix Guo result = run_tests(linux, request) 1546ebf5866SFelix Guo if result.status != KunitStatus.SUCCESS: 1556ebf5866SFelix Guo sys.exit(1) 1566ebf5866SFelix Guo else: 1576ebf5866SFelix Guo parser.print_help() 1586ebf5866SFelix Guo 1596ebf5866SFelix Guoif __name__ == '__main__': 160ff7b437fSBrendan Higgins main(sys.argv[1:]) 161