18c2ecf20Sopenharmony_ci#!/usr/bin/env python3
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
38c2ecf20Sopenharmony_ci#
48c2ecf20Sopenharmony_ci# A thin wrapper on top of the KUnit Kernel
58c2ecf20Sopenharmony_ci#
68c2ecf20Sopenharmony_ci# Copyright (C) 2019, Google LLC.
78c2ecf20Sopenharmony_ci# Author: Felix Guo <felixguoxiuping@gmail.com>
88c2ecf20Sopenharmony_ci# Author: Brendan Higgins <brendanhiggins@google.com>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciimport argparse
118c2ecf20Sopenharmony_ciimport sys
128c2ecf20Sopenharmony_ciimport os
138c2ecf20Sopenharmony_ciimport time
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_cifrom collections import namedtuple
168c2ecf20Sopenharmony_cifrom enum import Enum, auto
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciimport kunit_config
198c2ecf20Sopenharmony_ciimport kunit_json
208c2ecf20Sopenharmony_ciimport kunit_kernel
218c2ecf20Sopenharmony_ciimport kunit_parser
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciKunitResult = namedtuple('KunitResult', ['status','result','elapsed_time'])
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciKunitConfigRequest = namedtuple('KunitConfigRequest',
268c2ecf20Sopenharmony_ci				['build_dir', 'make_options'])
278c2ecf20Sopenharmony_ciKunitBuildRequest = namedtuple('KunitBuildRequest',
288c2ecf20Sopenharmony_ci			       ['jobs', 'build_dir', 'alltests',
298c2ecf20Sopenharmony_ci				'make_options'])
308c2ecf20Sopenharmony_ciKunitExecRequest = namedtuple('KunitExecRequest',
318c2ecf20Sopenharmony_ci			      ['timeout', 'build_dir', 'alltests'])
328c2ecf20Sopenharmony_ciKunitParseRequest = namedtuple('KunitParseRequest',
338c2ecf20Sopenharmony_ci			       ['raw_output', 'input_data', 'build_dir', 'json'])
348c2ecf20Sopenharmony_ciKunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs',
358c2ecf20Sopenharmony_ci					   'build_dir', 'alltests', 'json',
368c2ecf20Sopenharmony_ci					   'make_options'])
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ciKernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciclass KunitStatus(Enum):
418c2ecf20Sopenharmony_ci	SUCCESS = auto()
428c2ecf20Sopenharmony_ci	CONFIG_FAILURE = auto()
438c2ecf20Sopenharmony_ci	BUILD_FAILURE = auto()
448c2ecf20Sopenharmony_ci	TEST_FAILURE = auto()
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cidef get_kernel_root_path():
478c2ecf20Sopenharmony_ci	parts = sys.argv[0] if not __file__ else __file__
488c2ecf20Sopenharmony_ci	parts = os.path.realpath(parts).split('tools/testing/kunit')
498c2ecf20Sopenharmony_ci	if len(parts) != 2:
508c2ecf20Sopenharmony_ci		sys.exit(1)
518c2ecf20Sopenharmony_ci	return parts[0]
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cidef config_tests(linux: kunit_kernel.LinuxSourceTree,
548c2ecf20Sopenharmony_ci		 request: KunitConfigRequest) -> KunitResult:
558c2ecf20Sopenharmony_ci	kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...')
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	config_start = time.time()
588c2ecf20Sopenharmony_ci	success = linux.build_reconfig(request.build_dir, request.make_options)
598c2ecf20Sopenharmony_ci	config_end = time.time()
608c2ecf20Sopenharmony_ci	if not success:
618c2ecf20Sopenharmony_ci		return KunitResult(KunitStatus.CONFIG_FAILURE,
628c2ecf20Sopenharmony_ci				   'could not configure kernel',
638c2ecf20Sopenharmony_ci				   config_end - config_start)
648c2ecf20Sopenharmony_ci	return KunitResult(KunitStatus.SUCCESS,
658c2ecf20Sopenharmony_ci			   'configured kernel successfully',
668c2ecf20Sopenharmony_ci			   config_end - config_start)
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cidef build_tests(linux: kunit_kernel.LinuxSourceTree,
698c2ecf20Sopenharmony_ci		request: KunitBuildRequest) -> KunitResult:
708c2ecf20Sopenharmony_ci	kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	build_start = time.time()
738c2ecf20Sopenharmony_ci	success = linux.build_um_kernel(request.alltests,
748c2ecf20Sopenharmony_ci					request.jobs,
758c2ecf20Sopenharmony_ci					request.build_dir,
768c2ecf20Sopenharmony_ci					request.make_options)
778c2ecf20Sopenharmony_ci	build_end = time.time()
788c2ecf20Sopenharmony_ci	if not success:
798c2ecf20Sopenharmony_ci		return KunitResult(KunitStatus.BUILD_FAILURE,
808c2ecf20Sopenharmony_ci				   'could not build kernel',
818c2ecf20Sopenharmony_ci				   build_end - build_start)
828c2ecf20Sopenharmony_ci	if not success:
838c2ecf20Sopenharmony_ci		return KunitResult(KunitStatus.BUILD_FAILURE,
848c2ecf20Sopenharmony_ci				   'could not build kernel',
858c2ecf20Sopenharmony_ci				   build_end - build_start)
868c2ecf20Sopenharmony_ci	return KunitResult(KunitStatus.SUCCESS,
878c2ecf20Sopenharmony_ci			   'built kernel successfully',
888c2ecf20Sopenharmony_ci			   build_end - build_start)
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cidef exec_tests(linux: kunit_kernel.LinuxSourceTree,
918c2ecf20Sopenharmony_ci	       request: KunitExecRequest) -> KunitResult:
928c2ecf20Sopenharmony_ci	kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
938c2ecf20Sopenharmony_ci	test_start = time.time()
948c2ecf20Sopenharmony_ci	result = linux.run_kernel(
958c2ecf20Sopenharmony_ci		timeout=None if request.alltests else request.timeout,
968c2ecf20Sopenharmony_ci		build_dir=request.build_dir)
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	test_end = time.time()
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return KunitResult(KunitStatus.SUCCESS,
1018c2ecf20Sopenharmony_ci			   result,
1028c2ecf20Sopenharmony_ci			   test_end - test_start)
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cidef parse_tests(request: KunitParseRequest) -> KunitResult:
1058c2ecf20Sopenharmony_ci	parse_start = time.time()
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS,
1088c2ecf20Sopenharmony_ci					      [],
1098c2ecf20Sopenharmony_ci					      'Tests not Parsed.')
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if request.raw_output:
1128c2ecf20Sopenharmony_ci		kunit_parser.raw_output(request.input_data)
1138c2ecf20Sopenharmony_ci	else:
1148c2ecf20Sopenharmony_ci		test_result = kunit_parser.parse_run_tests(request.input_data)
1158c2ecf20Sopenharmony_ci	parse_end = time.time()
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	if request.json:
1188c2ecf20Sopenharmony_ci		json_obj = kunit_json.get_json_result(
1198c2ecf20Sopenharmony_ci					test_result=test_result,
1208c2ecf20Sopenharmony_ci					def_config='kunit_defconfig',
1218c2ecf20Sopenharmony_ci					build_dir=request.build_dir,
1228c2ecf20Sopenharmony_ci					json_path=request.json)
1238c2ecf20Sopenharmony_ci		if request.json == 'stdout':
1248c2ecf20Sopenharmony_ci			print(json_obj)
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if test_result.status != kunit_parser.TestStatus.SUCCESS:
1278c2ecf20Sopenharmony_ci		return KunitResult(KunitStatus.TEST_FAILURE, test_result,
1288c2ecf20Sopenharmony_ci				   parse_end - parse_start)
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	return KunitResult(KunitStatus.SUCCESS, test_result,
1318c2ecf20Sopenharmony_ci				parse_end - parse_start)
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cidef run_tests(linux: kunit_kernel.LinuxSourceTree,
1358c2ecf20Sopenharmony_ci	      request: KunitRequest) -> KunitResult:
1368c2ecf20Sopenharmony_ci	run_start = time.time()
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	config_request = KunitConfigRequest(request.build_dir,
1398c2ecf20Sopenharmony_ci					    request.make_options)
1408c2ecf20Sopenharmony_ci	config_result = config_tests(linux, config_request)
1418c2ecf20Sopenharmony_ci	if config_result.status != KunitStatus.SUCCESS:
1428c2ecf20Sopenharmony_ci		return config_result
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	build_request = KunitBuildRequest(request.jobs, request.build_dir,
1458c2ecf20Sopenharmony_ci					  request.alltests,
1468c2ecf20Sopenharmony_ci					  request.make_options)
1478c2ecf20Sopenharmony_ci	build_result = build_tests(linux, build_request)
1488c2ecf20Sopenharmony_ci	if build_result.status != KunitStatus.SUCCESS:
1498c2ecf20Sopenharmony_ci		return build_result
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	exec_request = KunitExecRequest(request.timeout, request.build_dir,
1528c2ecf20Sopenharmony_ci					request.alltests)
1538c2ecf20Sopenharmony_ci	exec_result = exec_tests(linux, exec_request)
1548c2ecf20Sopenharmony_ci	if exec_result.status != KunitStatus.SUCCESS:
1558c2ecf20Sopenharmony_ci		return exec_result
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	parse_request = KunitParseRequest(request.raw_output,
1588c2ecf20Sopenharmony_ci					  exec_result.result,
1598c2ecf20Sopenharmony_ci					  request.build_dir,
1608c2ecf20Sopenharmony_ci					  request.json)
1618c2ecf20Sopenharmony_ci	parse_result = parse_tests(parse_request)
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	run_end = time.time()
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	kunit_parser.print_with_timestamp((
1668c2ecf20Sopenharmony_ci		'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
1678c2ecf20Sopenharmony_ci		'building, %.3fs running\n') % (
1688c2ecf20Sopenharmony_ci				run_end - run_start,
1698c2ecf20Sopenharmony_ci				config_result.elapsed_time,
1708c2ecf20Sopenharmony_ci				build_result.elapsed_time,
1718c2ecf20Sopenharmony_ci				exec_result.elapsed_time))
1728c2ecf20Sopenharmony_ci	return parse_result
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cidef add_common_opts(parser):
1758c2ecf20Sopenharmony_ci	parser.add_argument('--build_dir',
1768c2ecf20Sopenharmony_ci			    help='As in the make command, it specifies the build '
1778c2ecf20Sopenharmony_ci			    'directory.',
1788c2ecf20Sopenharmony_ci                            type=str, default='.kunit', metavar='build_dir')
1798c2ecf20Sopenharmony_ci	parser.add_argument('--make_options',
1808c2ecf20Sopenharmony_ci			    help='X=Y make option, can be repeated.',
1818c2ecf20Sopenharmony_ci			    action='append')
1828c2ecf20Sopenharmony_ci	parser.add_argument('--alltests',
1838c2ecf20Sopenharmony_ci			    help='Run all KUnit tests through allyesconfig',
1848c2ecf20Sopenharmony_ci			    action='store_true')
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cidef add_build_opts(parser):
1878c2ecf20Sopenharmony_ci	parser.add_argument('--jobs',
1888c2ecf20Sopenharmony_ci			    help='As in the make command, "Specifies  the number of '
1898c2ecf20Sopenharmony_ci			    'jobs (commands) to run simultaneously."',
1908c2ecf20Sopenharmony_ci			    type=int, default=8, metavar='jobs')
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cidef add_exec_opts(parser):
1938c2ecf20Sopenharmony_ci	parser.add_argument('--timeout',
1948c2ecf20Sopenharmony_ci			    help='maximum number of seconds to allow for all tests '
1958c2ecf20Sopenharmony_ci			    'to run. This does not include time taken to build the '
1968c2ecf20Sopenharmony_ci			    'tests.',
1978c2ecf20Sopenharmony_ci			    type=int,
1988c2ecf20Sopenharmony_ci			    default=300,
1998c2ecf20Sopenharmony_ci			    metavar='timeout')
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cidef add_parse_opts(parser):
2028c2ecf20Sopenharmony_ci	parser.add_argument('--raw_output', help='don\'t format output from kernel',
2038c2ecf20Sopenharmony_ci			    action='store_true')
2048c2ecf20Sopenharmony_ci	parser.add_argument('--json',
2058c2ecf20Sopenharmony_ci			    nargs='?',
2068c2ecf20Sopenharmony_ci			    help='Stores test results in a JSON, and either '
2078c2ecf20Sopenharmony_ci			    'prints to stdout or saves to file if a '
2088c2ecf20Sopenharmony_ci			    'filename is specified',
2098c2ecf20Sopenharmony_ci			    type=str, const='stdout', default=None)
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cidef main(argv, linux=None):
2128c2ecf20Sopenharmony_ci	parser = argparse.ArgumentParser(
2138c2ecf20Sopenharmony_ci			description='Helps writing and running KUnit tests.')
2148c2ecf20Sopenharmony_ci	subparser = parser.add_subparsers(dest='subcommand')
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	# The 'run' command will config, build, exec, and parse in one go.
2178c2ecf20Sopenharmony_ci	run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
2188c2ecf20Sopenharmony_ci	add_common_opts(run_parser)
2198c2ecf20Sopenharmony_ci	add_build_opts(run_parser)
2208c2ecf20Sopenharmony_ci	add_exec_opts(run_parser)
2218c2ecf20Sopenharmony_ci	add_parse_opts(run_parser)
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	config_parser = subparser.add_parser('config',
2248c2ecf20Sopenharmony_ci						help='Ensures that .config contains all of '
2258c2ecf20Sopenharmony_ci						'the options in .kunitconfig')
2268c2ecf20Sopenharmony_ci	add_common_opts(config_parser)
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	build_parser = subparser.add_parser('build', help='Builds a kernel with KUnit tests')
2298c2ecf20Sopenharmony_ci	add_common_opts(build_parser)
2308c2ecf20Sopenharmony_ci	add_build_opts(build_parser)
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	exec_parser = subparser.add_parser('exec', help='Run a kernel with KUnit tests')
2338c2ecf20Sopenharmony_ci	add_common_opts(exec_parser)
2348c2ecf20Sopenharmony_ci	add_exec_opts(exec_parser)
2358c2ecf20Sopenharmony_ci	add_parse_opts(exec_parser)
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	# The 'parse' option is special, as it doesn't need the kernel source
2388c2ecf20Sopenharmony_ci	# (therefore there is no need for a build_dir, hence no add_common_opts)
2398c2ecf20Sopenharmony_ci	# and the '--file' argument is not relevant to 'run', so isn't in
2408c2ecf20Sopenharmony_ci	# add_parse_opts()
2418c2ecf20Sopenharmony_ci	parse_parser = subparser.add_parser('parse',
2428c2ecf20Sopenharmony_ci					    help='Parses KUnit results from a file, '
2438c2ecf20Sopenharmony_ci					    'and parses formatted results.')
2448c2ecf20Sopenharmony_ci	add_parse_opts(parse_parser)
2458c2ecf20Sopenharmony_ci	parse_parser.add_argument('file',
2468c2ecf20Sopenharmony_ci				  help='Specifies the file to read results from.',
2478c2ecf20Sopenharmony_ci				  type=str, nargs='?', metavar='input_file')
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	cli_args = parser.parse_args(argv)
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if get_kernel_root_path():
2528c2ecf20Sopenharmony_ci		os.chdir(get_kernel_root_path())
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if cli_args.subcommand == 'run':
2558c2ecf20Sopenharmony_ci		if not os.path.exists(cli_args.build_dir):
2568c2ecf20Sopenharmony_ci			os.mkdir(cli_args.build_dir)
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		if not linux:
2598c2ecf20Sopenharmony_ci			linux = kunit_kernel.LinuxSourceTree()
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		linux.create_kunitconfig(cli_args.build_dir)
2628c2ecf20Sopenharmony_ci		linux.read_kunitconfig(cli_args.build_dir)
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		request = KunitRequest(cli_args.raw_output,
2658c2ecf20Sopenharmony_ci				       cli_args.timeout,
2668c2ecf20Sopenharmony_ci				       cli_args.jobs,
2678c2ecf20Sopenharmony_ci				       cli_args.build_dir,
2688c2ecf20Sopenharmony_ci				       cli_args.alltests,
2698c2ecf20Sopenharmony_ci				       cli_args.json,
2708c2ecf20Sopenharmony_ci				       cli_args.make_options)
2718c2ecf20Sopenharmony_ci		result = run_tests(linux, request)
2728c2ecf20Sopenharmony_ci		if result.status != KunitStatus.SUCCESS:
2738c2ecf20Sopenharmony_ci			sys.exit(1)
2748c2ecf20Sopenharmony_ci	elif cli_args.subcommand == 'config':
2758c2ecf20Sopenharmony_ci		if cli_args.build_dir and (
2768c2ecf20Sopenharmony_ci				not os.path.exists(cli_args.build_dir)):
2778c2ecf20Sopenharmony_ci			os.mkdir(cli_args.build_dir)
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci		if not linux:
2808c2ecf20Sopenharmony_ci			linux = kunit_kernel.LinuxSourceTree()
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		linux.create_kunitconfig(cli_args.build_dir)
2838c2ecf20Sopenharmony_ci		linux.read_kunitconfig(cli_args.build_dir)
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		request = KunitConfigRequest(cli_args.build_dir,
2868c2ecf20Sopenharmony_ci					     cli_args.make_options)
2878c2ecf20Sopenharmony_ci		result = config_tests(linux, request)
2888c2ecf20Sopenharmony_ci		kunit_parser.print_with_timestamp((
2898c2ecf20Sopenharmony_ci			'Elapsed time: %.3fs\n') % (
2908c2ecf20Sopenharmony_ci				result.elapsed_time))
2918c2ecf20Sopenharmony_ci		if result.status != KunitStatus.SUCCESS:
2928c2ecf20Sopenharmony_ci			sys.exit(1)
2938c2ecf20Sopenharmony_ci	elif cli_args.subcommand == 'build':
2948c2ecf20Sopenharmony_ci		if not linux:
2958c2ecf20Sopenharmony_ci			linux = kunit_kernel.LinuxSourceTree()
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		linux.create_kunitconfig(cli_args.build_dir)
2988c2ecf20Sopenharmony_ci		linux.read_kunitconfig(cli_args.build_dir)
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		request = KunitBuildRequest(cli_args.jobs,
3018c2ecf20Sopenharmony_ci					    cli_args.build_dir,
3028c2ecf20Sopenharmony_ci					    cli_args.alltests,
3038c2ecf20Sopenharmony_ci					    cli_args.make_options)
3048c2ecf20Sopenharmony_ci		result = build_tests(linux, request)
3058c2ecf20Sopenharmony_ci		kunit_parser.print_with_timestamp((
3068c2ecf20Sopenharmony_ci			'Elapsed time: %.3fs\n') % (
3078c2ecf20Sopenharmony_ci				result.elapsed_time))
3088c2ecf20Sopenharmony_ci		if result.status != KunitStatus.SUCCESS:
3098c2ecf20Sopenharmony_ci			sys.exit(1)
3108c2ecf20Sopenharmony_ci	elif cli_args.subcommand == 'exec':
3118c2ecf20Sopenharmony_ci		if not linux:
3128c2ecf20Sopenharmony_ci			linux = kunit_kernel.LinuxSourceTree()
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		linux.create_kunitconfig(cli_args.build_dir)
3158c2ecf20Sopenharmony_ci		linux.read_kunitconfig(cli_args.build_dir)
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		exec_request = KunitExecRequest(cli_args.timeout,
3188c2ecf20Sopenharmony_ci						cli_args.build_dir,
3198c2ecf20Sopenharmony_ci						cli_args.alltests)
3208c2ecf20Sopenharmony_ci		exec_result = exec_tests(linux, exec_request)
3218c2ecf20Sopenharmony_ci		parse_request = KunitParseRequest(cli_args.raw_output,
3228c2ecf20Sopenharmony_ci						  exec_result.result,
3238c2ecf20Sopenharmony_ci						  cli_args.build_dir,
3248c2ecf20Sopenharmony_ci						  cli_args.json)
3258c2ecf20Sopenharmony_ci		result = parse_tests(parse_request)
3268c2ecf20Sopenharmony_ci		kunit_parser.print_with_timestamp((
3278c2ecf20Sopenharmony_ci			'Elapsed time: %.3fs\n') % (
3288c2ecf20Sopenharmony_ci				exec_result.elapsed_time))
3298c2ecf20Sopenharmony_ci		if result.status != KunitStatus.SUCCESS:
3308c2ecf20Sopenharmony_ci			sys.exit(1)
3318c2ecf20Sopenharmony_ci	elif cli_args.subcommand == 'parse':
3328c2ecf20Sopenharmony_ci		if cli_args.file == None:
3338c2ecf20Sopenharmony_ci			kunit_output = sys.stdin
3348c2ecf20Sopenharmony_ci		else:
3358c2ecf20Sopenharmony_ci			with open(cli_args.file, 'r') as f:
3368c2ecf20Sopenharmony_ci				kunit_output = f.read().splitlines()
3378c2ecf20Sopenharmony_ci		request = KunitParseRequest(cli_args.raw_output,
3388c2ecf20Sopenharmony_ci					    kunit_output,
3398c2ecf20Sopenharmony_ci					    None,
3408c2ecf20Sopenharmony_ci					    cli_args.json)
3418c2ecf20Sopenharmony_ci		result = parse_tests(request)
3428c2ecf20Sopenharmony_ci		if result.status != KunitStatus.SUCCESS:
3438c2ecf20Sopenharmony_ci			sys.exit(1)
3448c2ecf20Sopenharmony_ci	else:
3458c2ecf20Sopenharmony_ci		parser.print_help()
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciif __name__ == '__main__':
3488c2ecf20Sopenharmony_ci	main(sys.argv[1:])
349