xref: /linux/tools/testing/kunit/kunit.py (revision 87c9c16317882dd6dbbc07e349bc3223e14f3244)
1c25ce589SFinn Behrens#!/usr/bin/env 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
146ebf5866SFelix Guo
156ebf5866SFelix Guofrom collections import namedtuple
166ebf5866SFelix Guofrom enum import Enum, auto
176ebf5866SFelix Guo
186ebf5866SFelix Guoimport kunit_config
1921a6d178SHeidi Fahimimport kunit_json
206ebf5866SFelix Guoimport kunit_kernel
216ebf5866SFelix Guoimport kunit_parser
226ebf5866SFelix Guo
2345ba7a89SDavid GowKunitResult = namedtuple('KunitResult', ['status','result','elapsed_time'])
246ebf5866SFelix Guo
2545ba7a89SDavid GowKunitConfigRequest = namedtuple('KunitConfigRequest',
2601397e82SVitor Massaru Iha				['build_dir', 'make_options'])
2745ba7a89SDavid GowKunitBuildRequest = namedtuple('KunitBuildRequest',
2845ba7a89SDavid Gow			       ['jobs', 'build_dir', 'alltests',
2945ba7a89SDavid Gow				'make_options'])
3045ba7a89SDavid GowKunitExecRequest = namedtuple('KunitExecRequest',
31d992880bSDaniel Latypov			      ['timeout', 'build_dir', 'alltests', 'filter_glob'])
3245ba7a89SDavid GowKunitParseRequest = namedtuple('KunitParseRequest',
3321a6d178SHeidi Fahim			       ['raw_output', 'input_data', 'build_dir', 'json'])
34021ed9f5SHeidi FahimKunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs',
35d992880bSDaniel Latypov					   'build_dir', 'alltests', 'filter_glob',
36d992880bSDaniel Latypov					   'json', 'make_options'])
376ebf5866SFelix Guo
38be886ba9SHeidi FahimKernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
39be886ba9SHeidi Fahim
406ebf5866SFelix Guoclass KunitStatus(Enum):
416ebf5866SFelix Guo	SUCCESS = auto()
426ebf5866SFelix Guo	CONFIG_FAILURE = auto()
436ebf5866SFelix Guo	BUILD_FAILURE = auto()
446ebf5866SFelix Guo	TEST_FAILURE = auto()
456ebf5866SFelix Guo
4609641f7cSDaniel Latypovdef get_kernel_root_path() -> str:
4709641f7cSDaniel Latypov	path = sys.argv[0] if not __file__ else __file__
4809641f7cSDaniel Latypov	parts = os.path.realpath(path).split('tools/testing/kunit')
49be886ba9SHeidi Fahim	if len(parts) != 2:
50be886ba9SHeidi Fahim		sys.exit(1)
51be886ba9SHeidi Fahim	return parts[0]
52be886ba9SHeidi Fahim
5345ba7a89SDavid Gowdef config_tests(linux: kunit_kernel.LinuxSourceTree,
5445ba7a89SDavid Gow		 request: KunitConfigRequest) -> KunitResult:
5545ba7a89SDavid Gow	kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...')
5645ba7a89SDavid Gow
576ebf5866SFelix Guo	config_start = time.time()
580476e69fSGreg Thelen	success = linux.build_reconfig(request.build_dir, request.make_options)
596ebf5866SFelix Guo	config_end = time.time()
606ebf5866SFelix Guo	if not success:
6145ba7a89SDavid Gow		return KunitResult(KunitStatus.CONFIG_FAILURE,
6245ba7a89SDavid Gow				   'could not configure kernel',
6345ba7a89SDavid Gow				   config_end - config_start)
6445ba7a89SDavid Gow	return KunitResult(KunitStatus.SUCCESS,
6545ba7a89SDavid Gow			   'configured kernel successfully',
6645ba7a89SDavid Gow			   config_end - config_start)
676ebf5866SFelix Guo
6845ba7a89SDavid Gowdef build_tests(linux: kunit_kernel.LinuxSourceTree,
6945ba7a89SDavid Gow		request: KunitBuildRequest) -> KunitResult:
706ebf5866SFelix Guo	kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
716ebf5866SFelix Guo
726ebf5866SFelix Guo	build_start = time.time()
73*87c9c163SBrendan Higgins	success = linux.build_kernel(request.alltests,
74021ed9f5SHeidi Fahim				     request.jobs,
750476e69fSGreg Thelen				     request.build_dir,
760476e69fSGreg Thelen				     request.make_options)
776ebf5866SFelix Guo	build_end = time.time()
786ebf5866SFelix Guo	if not success:
79ee61492aSDavid Gow		return KunitResult(KunitStatus.BUILD_FAILURE,
80ee61492aSDavid Gow				   'could not build kernel',
81ee61492aSDavid Gow				   build_end - build_start)
8245ba7a89SDavid Gow	if not success:
8345ba7a89SDavid Gow		return KunitResult(KunitStatus.BUILD_FAILURE,
8445ba7a89SDavid Gow				   'could not build kernel',
8545ba7a89SDavid Gow				   build_end - build_start)
8645ba7a89SDavid Gow	return KunitResult(KunitStatus.SUCCESS,
8745ba7a89SDavid Gow			   'built kernel successfully',
8845ba7a89SDavid Gow			   build_end - build_start)
896ebf5866SFelix Guo
9045ba7a89SDavid Gowdef exec_tests(linux: kunit_kernel.LinuxSourceTree,
9145ba7a89SDavid Gow	       request: KunitExecRequest) -> KunitResult:
926ebf5866SFelix Guo	kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
936ebf5866SFelix Guo	test_start = time.time()
9445ba7a89SDavid Gow	result = linux.run_kernel(
95021ed9f5SHeidi Fahim		timeout=None if request.alltests else request.timeout,
96d992880bSDaniel Latypov                filter_glob=request.filter_glob,
976ec1b81dSSeongJae Park		build_dir=request.build_dir)
9845ba7a89SDavid Gow
996ebf5866SFelix Guo	test_end = time.time()
1006ebf5866SFelix Guo
10145ba7a89SDavid Gow	return KunitResult(KunitStatus.SUCCESS,
10245ba7a89SDavid Gow			   result,
10345ba7a89SDavid Gow			   test_end - test_start)
10445ba7a89SDavid Gow
10545ba7a89SDavid Gowdef parse_tests(request: KunitParseRequest) -> KunitResult:
10645ba7a89SDavid Gow	parse_start = time.time()
10745ba7a89SDavid Gow
10845ba7a89SDavid Gow	test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS,
10945ba7a89SDavid Gow					      [],
11045ba7a89SDavid Gow					      'Tests not Parsed.')
11121a6d178SHeidi Fahim
11245ba7a89SDavid Gow	if request.raw_output:
11345ba7a89SDavid Gow		kunit_parser.raw_output(request.input_data)
11445ba7a89SDavid Gow	else:
11545ba7a89SDavid Gow		test_result = kunit_parser.parse_run_tests(request.input_data)
11645ba7a89SDavid Gow	parse_end = time.time()
11745ba7a89SDavid Gow
11821a6d178SHeidi Fahim	if request.json:
11921a6d178SHeidi Fahim		json_obj = kunit_json.get_json_result(
12021a6d178SHeidi Fahim					test_result=test_result,
12121a6d178SHeidi Fahim					def_config='kunit_defconfig',
12221a6d178SHeidi Fahim					build_dir=request.build_dir,
12321a6d178SHeidi Fahim					json_path=request.json)
12421a6d178SHeidi Fahim		if request.json == 'stdout':
12521a6d178SHeidi Fahim			print(json_obj)
12621a6d178SHeidi Fahim
12745ba7a89SDavid Gow	if test_result.status != kunit_parser.TestStatus.SUCCESS:
12845ba7a89SDavid Gow		return KunitResult(KunitStatus.TEST_FAILURE, test_result,
12945ba7a89SDavid Gow				   parse_end - parse_start)
13045ba7a89SDavid Gow
13145ba7a89SDavid Gow	return KunitResult(KunitStatus.SUCCESS, test_result,
13245ba7a89SDavid Gow				parse_end - parse_start)
13345ba7a89SDavid Gow
13445ba7a89SDavid Gow
13545ba7a89SDavid Gowdef run_tests(linux: kunit_kernel.LinuxSourceTree,
13645ba7a89SDavid Gow	      request: KunitRequest) -> KunitResult:
13745ba7a89SDavid Gow	run_start = time.time()
13845ba7a89SDavid Gow
13945ba7a89SDavid Gow	config_request = KunitConfigRequest(request.build_dir,
14045ba7a89SDavid Gow					    request.make_options)
14145ba7a89SDavid Gow	config_result = config_tests(linux, config_request)
14245ba7a89SDavid Gow	if config_result.status != KunitStatus.SUCCESS:
14345ba7a89SDavid Gow		return config_result
14445ba7a89SDavid Gow
14545ba7a89SDavid Gow	build_request = KunitBuildRequest(request.jobs, request.build_dir,
14645ba7a89SDavid Gow					  request.alltests,
14745ba7a89SDavid Gow					  request.make_options)
14845ba7a89SDavid Gow	build_result = build_tests(linux, build_request)
14945ba7a89SDavid Gow	if build_result.status != KunitStatus.SUCCESS:
15045ba7a89SDavid Gow		return build_result
15145ba7a89SDavid Gow
15245ba7a89SDavid Gow	exec_request = KunitExecRequest(request.timeout, request.build_dir,
153d992880bSDaniel Latypov					request.alltests, request.filter_glob)
15445ba7a89SDavid Gow	exec_result = exec_tests(linux, exec_request)
15545ba7a89SDavid Gow	if exec_result.status != KunitStatus.SUCCESS:
15645ba7a89SDavid Gow		return exec_result
15745ba7a89SDavid Gow
15845ba7a89SDavid Gow	parse_request = KunitParseRequest(request.raw_output,
15921a6d178SHeidi Fahim					  exec_result.result,
16021a6d178SHeidi Fahim					  request.build_dir,
16121a6d178SHeidi Fahim					  request.json)
16245ba7a89SDavid Gow	parse_result = parse_tests(parse_request)
16345ba7a89SDavid Gow
16445ba7a89SDavid Gow	run_end = time.time()
16545ba7a89SDavid Gow
1666ebf5866SFelix Guo	kunit_parser.print_with_timestamp((
1676ebf5866SFelix Guo		'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
1686ebf5866SFelix Guo		'building, %.3fs running\n') % (
16945ba7a89SDavid Gow				run_end - run_start,
17045ba7a89SDavid Gow				config_result.elapsed_time,
17145ba7a89SDavid Gow				build_result.elapsed_time,
17245ba7a89SDavid Gow				exec_result.elapsed_time))
17345ba7a89SDavid Gow	return parse_result
1746ebf5866SFelix Guo
17509641f7cSDaniel Latypovdef add_common_opts(parser) -> None:
17645ba7a89SDavid Gow	parser.add_argument('--build_dir',
17745ba7a89SDavid Gow			    help='As in the make command, it specifies the build '
17845ba7a89SDavid Gow			    'directory.',
179ddbd60c7SVitor Massaru Iha                            type=str, default='.kunit', metavar='build_dir')
18045ba7a89SDavid Gow	parser.add_argument('--make_options',
18145ba7a89SDavid Gow			    help='X=Y make option, can be repeated.',
18245ba7a89SDavid Gow			    action='append')
18345ba7a89SDavid Gow	parser.add_argument('--alltests',
18445ba7a89SDavid Gow			    help='Run all KUnit tests through allyesconfig',
1856ebf5866SFelix Guo			    action='store_true')
186243180f5SDaniel Latypov	parser.add_argument('--kunitconfig',
1879854781dSDaniel Latypov			     help='Path to Kconfig fragment that enables KUnit tests.'
1889854781dSDaniel Latypov			     ' If given a directory, (e.g. lib/kunit), "/.kunitconfig" '
1899854781dSDaniel Latypov			     'will get  automatically appended.',
190243180f5SDaniel Latypov			     metavar='kunitconfig')
1916ebf5866SFelix Guo
192*87c9c163SBrendan Higgins	parser.add_argument('--arch',
193*87c9c163SBrendan Higgins			    help=('Specifies the architecture to run tests under. '
194*87c9c163SBrendan Higgins				  'The architecture specified here must match the '
195*87c9c163SBrendan Higgins				  'string passed to the ARCH make param, '
196*87c9c163SBrendan Higgins				  'e.g. i386, x86_64, arm, um, etc. Non-UML '
197*87c9c163SBrendan Higgins				  'architectures run on QEMU.'),
198*87c9c163SBrendan Higgins			    type=str, default='um', metavar='arch')
199*87c9c163SBrendan Higgins
200*87c9c163SBrendan Higgins	parser.add_argument('--cross_compile',
201*87c9c163SBrendan Higgins			    help=('Sets make\'s CROSS_COMPILE variable; it should '
202*87c9c163SBrendan Higgins				  'be set to a toolchain path prefix (the prefix '
203*87c9c163SBrendan Higgins				  'of gcc and other tools in your toolchain, for '
204*87c9c163SBrendan Higgins				  'example `sparc64-linux-gnu-` if you have the '
205*87c9c163SBrendan Higgins				  'sparc toolchain installed on your system, or '
206*87c9c163SBrendan Higgins				  '`$HOME/toolchains/microblaze/gcc-9.2.0-nolibc/microblaze-linux/bin/microblaze-linux-` '
207*87c9c163SBrendan Higgins				  'if you have downloaded the microblaze toolchain '
208*87c9c163SBrendan Higgins				  'from the 0-day website to a directory in your '
209*87c9c163SBrendan Higgins				  'home directory called `toolchains`).'),
210*87c9c163SBrendan Higgins			    metavar='cross_compile')
211*87c9c163SBrendan Higgins
212*87c9c163SBrendan Higgins	parser.add_argument('--qemu_config',
213*87c9c163SBrendan Higgins			    help=('Takes a path to a path to a file containing '
214*87c9c163SBrendan Higgins				  'a QemuArchParams object.'),
215*87c9c163SBrendan Higgins			    type=str, metavar='qemu_config')
216*87c9c163SBrendan Higgins
21709641f7cSDaniel Latypovdef add_build_opts(parser) -> None:
21845ba7a89SDavid Gow	parser.add_argument('--jobs',
21945ba7a89SDavid Gow			    help='As in the make command, "Specifies  the number of '
22045ba7a89SDavid Gow			    'jobs (commands) to run simultaneously."',
22145ba7a89SDavid Gow			    type=int, default=8, metavar='jobs')
22245ba7a89SDavid Gow
22309641f7cSDaniel Latypovdef add_exec_opts(parser) -> None:
22445ba7a89SDavid Gow	parser.add_argument('--timeout',
2256ebf5866SFelix Guo			    help='maximum number of seconds to allow for all tests '
2266ebf5866SFelix Guo			    'to run. This does not include time taken to build the '
2276ebf5866SFelix Guo			    'tests.',
2286ebf5866SFelix Guo			    type=int,
2296ebf5866SFelix Guo			    default=300,
2306ebf5866SFelix Guo			    metavar='timeout')
231d992880bSDaniel Latypov	parser.add_argument('filter_glob',
232d992880bSDaniel Latypov			    help='maximum number of seconds to allow for all tests '
233d992880bSDaniel Latypov			    'to run. This does not include time taken to build the '
234d992880bSDaniel Latypov			    'tests.',
235d992880bSDaniel Latypov			    type=str,
236d992880bSDaniel Latypov			    nargs='?',
237d992880bSDaniel Latypov			    default='',
238d992880bSDaniel Latypov			    metavar='filter_glob')
2396ebf5866SFelix Guo
24009641f7cSDaniel Latypovdef add_parse_opts(parser) -> None:
24145ba7a89SDavid Gow	parser.add_argument('--raw_output', help='don\'t format output from kernel',
242ff7b437fSBrendan Higgins			    action='store_true')
24321a6d178SHeidi Fahim	parser.add_argument('--json',
24421a6d178SHeidi Fahim			    nargs='?',
24521a6d178SHeidi Fahim			    help='Stores test results in a JSON, and either '
24621a6d178SHeidi Fahim			    'prints to stdout or saves to file if a '
24721a6d178SHeidi Fahim			    'filename is specified',
24821a6d178SHeidi Fahim			    type=str, const='stdout', default=None)
249021ed9f5SHeidi Fahim
25045ba7a89SDavid Gowdef main(argv, linux=None):
25145ba7a89SDavid Gow	parser = argparse.ArgumentParser(
25245ba7a89SDavid Gow			description='Helps writing and running KUnit tests.')
25345ba7a89SDavid Gow	subparser = parser.add_subparsers(dest='subcommand')
25445ba7a89SDavid Gow
25545ba7a89SDavid Gow	# The 'run' command will config, build, exec, and parse in one go.
25645ba7a89SDavid Gow	run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
25745ba7a89SDavid Gow	add_common_opts(run_parser)
25845ba7a89SDavid Gow	add_build_opts(run_parser)
25945ba7a89SDavid Gow	add_exec_opts(run_parser)
26045ba7a89SDavid Gow	add_parse_opts(run_parser)
26145ba7a89SDavid Gow
26245ba7a89SDavid Gow	config_parser = subparser.add_parser('config',
26345ba7a89SDavid Gow						help='Ensures that .config contains all of '
26445ba7a89SDavid Gow						'the options in .kunitconfig')
26545ba7a89SDavid Gow	add_common_opts(config_parser)
26645ba7a89SDavid Gow
26745ba7a89SDavid Gow	build_parser = subparser.add_parser('build', help='Builds a kernel with KUnit tests')
26845ba7a89SDavid Gow	add_common_opts(build_parser)
26945ba7a89SDavid Gow	add_build_opts(build_parser)
27045ba7a89SDavid Gow
27145ba7a89SDavid Gow	exec_parser = subparser.add_parser('exec', help='Run a kernel with KUnit tests')
27245ba7a89SDavid Gow	add_common_opts(exec_parser)
27345ba7a89SDavid Gow	add_exec_opts(exec_parser)
27445ba7a89SDavid Gow	add_parse_opts(exec_parser)
27545ba7a89SDavid Gow
27645ba7a89SDavid Gow	# The 'parse' option is special, as it doesn't need the kernel source
27745ba7a89SDavid Gow	# (therefore there is no need for a build_dir, hence no add_common_opts)
27845ba7a89SDavid Gow	# and the '--file' argument is not relevant to 'run', so isn't in
27945ba7a89SDavid Gow	# add_parse_opts()
28045ba7a89SDavid Gow	parse_parser = subparser.add_parser('parse',
28145ba7a89SDavid Gow					    help='Parses KUnit results from a file, '
28245ba7a89SDavid Gow					    'and parses formatted results.')
28345ba7a89SDavid Gow	add_parse_opts(parse_parser)
28445ba7a89SDavid Gow	parse_parser.add_argument('file',
28545ba7a89SDavid Gow				  help='Specifies the file to read results from.',
28645ba7a89SDavid Gow				  type=str, nargs='?', metavar='input_file')
2870476e69fSGreg Thelen
2886ebf5866SFelix Guo	cli_args = parser.parse_args(argv)
2896ebf5866SFelix Guo
2905578d008SBrendan Higgins	if get_kernel_root_path():
2915578d008SBrendan Higgins		os.chdir(get_kernel_root_path())
2925578d008SBrendan Higgins
2936ebf5866SFelix Guo	if cli_args.subcommand == 'run':
294e3212513SSeongJae Park		if not os.path.exists(cli_args.build_dir):
295e3212513SSeongJae Park			os.mkdir(cli_args.build_dir)
29682206a0cSBrendan Higgins
297ff7b437fSBrendan Higgins		if not linux:
298*87c9c163SBrendan Higgins			linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
299*87c9c163SBrendan Higgins					kunitconfig_path=cli_args.kunitconfig,
300*87c9c163SBrendan Higgins					arch=cli_args.arch,
301*87c9c163SBrendan Higgins					cross_compile=cli_args.cross_compile,
302*87c9c163SBrendan Higgins					qemu_config_path=cli_args.qemu_config)
303fcdb0bc0SAndy Shevchenko
3046ebf5866SFelix Guo		request = KunitRequest(cli_args.raw_output,
3056ebf5866SFelix Guo				       cli_args.timeout,
3066ebf5866SFelix Guo				       cli_args.jobs,
307ff7b437fSBrendan Higgins				       cli_args.build_dir,
3080476e69fSGreg Thelen				       cli_args.alltests,
309d992880bSDaniel Latypov				       cli_args.filter_glob,
31021a6d178SHeidi Fahim				       cli_args.json,
3110476e69fSGreg Thelen				       cli_args.make_options)
3126ebf5866SFelix Guo		result = run_tests(linux, request)
3136ebf5866SFelix Guo		if result.status != KunitStatus.SUCCESS:
3146ebf5866SFelix Guo			sys.exit(1)
31545ba7a89SDavid Gow	elif cli_args.subcommand == 'config':
31682206a0cSBrendan Higgins		if cli_args.build_dir and (
31782206a0cSBrendan Higgins				not os.path.exists(cli_args.build_dir)):
31845ba7a89SDavid Gow			os.mkdir(cli_args.build_dir)
31982206a0cSBrendan Higgins
32045ba7a89SDavid Gow		if not linux:
321*87c9c163SBrendan Higgins			linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
322*87c9c163SBrendan Higgins					kunitconfig_path=cli_args.kunitconfig,
323*87c9c163SBrendan Higgins					arch=cli_args.arch,
324*87c9c163SBrendan Higgins					cross_compile=cli_args.cross_compile,
325*87c9c163SBrendan Higgins					qemu_config_path=cli_args.qemu_config)
326fcdb0bc0SAndy Shevchenko
32745ba7a89SDavid Gow		request = KunitConfigRequest(cli_args.build_dir,
32845ba7a89SDavid Gow					     cli_args.make_options)
32945ba7a89SDavid Gow		result = config_tests(linux, request)
33045ba7a89SDavid Gow		kunit_parser.print_with_timestamp((
33145ba7a89SDavid Gow			'Elapsed time: %.3fs\n') % (
33245ba7a89SDavid Gow				result.elapsed_time))
33345ba7a89SDavid Gow		if result.status != KunitStatus.SUCCESS:
33445ba7a89SDavid Gow			sys.exit(1)
33545ba7a89SDavid Gow	elif cli_args.subcommand == 'build':
33645ba7a89SDavid Gow		if not linux:
337*87c9c163SBrendan Higgins			linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
338*87c9c163SBrendan Higgins					kunitconfig_path=cli_args.kunitconfig,
339*87c9c163SBrendan Higgins					arch=cli_args.arch,
340*87c9c163SBrendan Higgins					cross_compile=cli_args.cross_compile,
341*87c9c163SBrendan Higgins					qemu_config_path=cli_args.qemu_config)
342fcdb0bc0SAndy Shevchenko
34345ba7a89SDavid Gow		request = KunitBuildRequest(cli_args.jobs,
34445ba7a89SDavid Gow					    cli_args.build_dir,
34545ba7a89SDavid Gow					    cli_args.alltests,
34645ba7a89SDavid Gow					    cli_args.make_options)
34745ba7a89SDavid Gow		result = build_tests(linux, request)
34845ba7a89SDavid Gow		kunit_parser.print_with_timestamp((
34945ba7a89SDavid Gow			'Elapsed time: %.3fs\n') % (
35045ba7a89SDavid Gow				result.elapsed_time))
35145ba7a89SDavid Gow		if result.status != KunitStatus.SUCCESS:
35245ba7a89SDavid Gow			sys.exit(1)
35345ba7a89SDavid Gow	elif cli_args.subcommand == 'exec':
35445ba7a89SDavid Gow		if not linux:
355*87c9c163SBrendan Higgins			linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir,
356*87c9c163SBrendan Higgins					kunitconfig_path=cli_args.kunitconfig,
357*87c9c163SBrendan Higgins					arch=cli_args.arch,
358*87c9c163SBrendan Higgins					cross_compile=cli_args.cross_compile,
359*87c9c163SBrendan Higgins					qemu_config_path=cli_args.qemu_config)
360fcdb0bc0SAndy Shevchenko
36145ba7a89SDavid Gow		exec_request = KunitExecRequest(cli_args.timeout,
36245ba7a89SDavid Gow						cli_args.build_dir,
363d992880bSDaniel Latypov						cli_args.alltests,
364d992880bSDaniel Latypov						cli_args.filter_glob)
36545ba7a89SDavid Gow		exec_result = exec_tests(linux, exec_request)
36645ba7a89SDavid Gow		parse_request = KunitParseRequest(cli_args.raw_output,
36721a6d178SHeidi Fahim						  exec_result.result,
36821a6d178SHeidi Fahim						  cli_args.build_dir,
36921a6d178SHeidi Fahim						  cli_args.json)
37045ba7a89SDavid Gow		result = parse_tests(parse_request)
37145ba7a89SDavid Gow		kunit_parser.print_with_timestamp((
37245ba7a89SDavid Gow			'Elapsed time: %.3fs\n') % (
37345ba7a89SDavid Gow				exec_result.elapsed_time))
37445ba7a89SDavid Gow		if result.status != KunitStatus.SUCCESS:
37545ba7a89SDavid Gow			sys.exit(1)
37645ba7a89SDavid Gow	elif cli_args.subcommand == 'parse':
37745ba7a89SDavid Gow		if cli_args.file == None:
37845ba7a89SDavid Gow			kunit_output = sys.stdin
37945ba7a89SDavid Gow		else:
38045ba7a89SDavid Gow			with open(cli_args.file, 'r') as f:
38145ba7a89SDavid Gow				kunit_output = f.read().splitlines()
38245ba7a89SDavid Gow		request = KunitParseRequest(cli_args.raw_output,
38321a6d178SHeidi Fahim					    kunit_output,
3843959d0a6SDavid Gow					    None,
38521a6d178SHeidi Fahim					    cli_args.json)
38645ba7a89SDavid Gow		result = parse_tests(request)
38745ba7a89SDavid Gow		if result.status != KunitStatus.SUCCESS:
38845ba7a89SDavid Gow			sys.exit(1)
3896ebf5866SFelix Guo	else:
3906ebf5866SFelix Guo		parser.print_help()
3916ebf5866SFelix Guo
3926ebf5866SFelix Guoif __name__ == '__main__':
393ff7b437fSBrendan Higgins	main(sys.argv[1:])
394