xref: /linux/tools/testing/kunit/kunit.py (revision 14ee5cfd4512ee3d1e0047d8751450dcc6544070)
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
25ff7b437fSBrendan HigginsKunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs', 'build_dir', 'defconfig'])
266ebf5866SFelix Guo
276ebf5866SFelix Guoclass KunitStatus(Enum):
286ebf5866SFelix Guo	SUCCESS = auto()
296ebf5866SFelix Guo	CONFIG_FAILURE = auto()
306ebf5866SFelix Guo	BUILD_FAILURE = auto()
316ebf5866SFelix Guo	TEST_FAILURE = auto()
326ebf5866SFelix Guo
33ff7b437fSBrendan Higginsdef create_default_kunitconfig():
34e3212513SSeongJae Park	if not os.path.exists(kunit_kernel.kunitconfig_path):
35ff7b437fSBrendan Higgins		shutil.copyfile('arch/um/configs/kunit_defconfig',
36e3212513SSeongJae Park				kunit_kernel.kunitconfig_path)
37ff7b437fSBrendan Higgins
386ebf5866SFelix Guodef run_tests(linux: kunit_kernel.LinuxSourceTree,
396ebf5866SFelix Guo	      request: KunitRequest) -> KunitResult:
406ebf5866SFelix Guo	config_start = time.time()
416ebf5866SFelix Guo	success = linux.build_reconfig(request.build_dir)
426ebf5866SFelix Guo	config_end = time.time()
436ebf5866SFelix Guo	if not success:
446ebf5866SFelix Guo		return KunitResult(KunitStatus.CONFIG_FAILURE, 'could not configure kernel')
456ebf5866SFelix Guo
466ebf5866SFelix Guo	kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
476ebf5866SFelix Guo
486ebf5866SFelix Guo	build_start = time.time()
496ebf5866SFelix Guo	success = linux.build_um_kernel(request.jobs, request.build_dir)
506ebf5866SFelix Guo	build_end = time.time()
516ebf5866SFelix Guo	if not success:
526ebf5866SFelix Guo		return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel')
536ebf5866SFelix Guo
546ebf5866SFelix Guo	kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
556ebf5866SFelix Guo	test_start = time.time()
566ebf5866SFelix Guo
576ebf5866SFelix Guo	test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS,
586ebf5866SFelix Guo					      [],
596ebf5866SFelix Guo					      'Tests not Parsed.')
606ebf5866SFelix Guo	if request.raw_output:
616ebf5866SFelix Guo		kunit_parser.raw_output(
626ec1b81dSSeongJae Park			linux.run_kernel(timeout=request.timeout,
636ec1b81dSSeongJae Park					 build_dir=request.build_dir))
646ebf5866SFelix Guo	else:
656ec1b81dSSeongJae Park		kunit_output = linux.run_kernel(timeout=request.timeout,
666ec1b81dSSeongJae Park						build_dir=request.build_dir)
676ebf5866SFelix Guo		test_result = kunit_parser.parse_run_tests(kunit_output)
686ebf5866SFelix Guo	test_end = time.time()
696ebf5866SFelix Guo
706ebf5866SFelix Guo	kunit_parser.print_with_timestamp((
716ebf5866SFelix Guo		'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
726ebf5866SFelix Guo		'building, %.3fs running\n') % (
736ebf5866SFelix Guo				test_end - config_start,
746ebf5866SFelix Guo				config_end - config_start,
756ebf5866SFelix Guo				build_end - build_start,
766ebf5866SFelix Guo				test_end - test_start))
776ebf5866SFelix Guo
786ebf5866SFelix Guo	if test_result.status != kunit_parser.TestStatus.SUCCESS:
796ebf5866SFelix Guo		return KunitResult(KunitStatus.TEST_FAILURE, test_result)
806ebf5866SFelix Guo	else:
816ebf5866SFelix Guo		return KunitResult(KunitStatus.SUCCESS, test_result)
826ebf5866SFelix Guo
83ff7b437fSBrendan Higginsdef main(argv, linux=None):
846ebf5866SFelix Guo	parser = argparse.ArgumentParser(
856ebf5866SFelix Guo			description='Helps writing and running KUnit tests.')
866ebf5866SFelix Guo	subparser = parser.add_subparsers(dest='subcommand')
876ebf5866SFelix Guo
886ebf5866SFelix Guo	run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
896ebf5866SFelix Guo	run_parser.add_argument('--raw_output', help='don\'t format output from kernel',
906ebf5866SFelix Guo				action='store_true')
916ebf5866SFelix Guo
926ebf5866SFelix Guo	run_parser.add_argument('--timeout',
936ebf5866SFelix Guo				help='maximum number of seconds to allow for all tests '
946ebf5866SFelix Guo				'to run. This does not include time taken to build the '
956ebf5866SFelix Guo				'tests.',
966ebf5866SFelix Guo				type=int,
976ebf5866SFelix Guo				default=300,
986ebf5866SFelix Guo				metavar='timeout')
996ebf5866SFelix Guo
1006ebf5866SFelix Guo	run_parser.add_argument('--jobs',
1016ebf5866SFelix Guo				help='As in the make command, "Specifies  the number of '
1026ebf5866SFelix Guo				'jobs (commands) to run simultaneously."',
1036ebf5866SFelix Guo				type=int, default=8, metavar='jobs')
1046ebf5866SFelix Guo
1056ebf5866SFelix Guo	run_parser.add_argument('--build_dir',
1066ebf5866SFelix Guo				help='As in the make command, it specifies the build '
1076ebf5866SFelix Guo				'directory.',
108609952c2SSeongJae Park				type=str, default='', metavar='build_dir')
1096ebf5866SFelix Guo
110ff7b437fSBrendan Higgins	run_parser.add_argument('--defconfig',
111*14ee5cfdSSeongJae Park				help='Uses a default .kunitconfig.',
112ff7b437fSBrendan Higgins				action='store_true')
113ff7b437fSBrendan Higgins
1146ebf5866SFelix Guo	cli_args = parser.parse_args(argv)
1156ebf5866SFelix Guo
1166ebf5866SFelix Guo	if cli_args.subcommand == 'run':
117e3212513SSeongJae Park		if cli_args.build_dir:
118e3212513SSeongJae Park			if not os.path.exists(cli_args.build_dir):
119e3212513SSeongJae Park				os.mkdir(cli_args.build_dir)
120e3212513SSeongJae Park			kunit_kernel.kunitconfig_path = os.path.join(
121e3212513SSeongJae Park				cli_args.build_dir,
122e3212513SSeongJae Park				kunit_kernel.kunitconfig_path)
123e3212513SSeongJae Park
124ff7b437fSBrendan Higgins		if cli_args.defconfig:
125ff7b437fSBrendan Higgins			create_default_kunitconfig()
126ff7b437fSBrendan Higgins
127ff7b437fSBrendan Higgins		if not linux:
128ff7b437fSBrendan Higgins			linux = kunit_kernel.LinuxSourceTree()
129ff7b437fSBrendan Higgins
1306ebf5866SFelix Guo		request = KunitRequest(cli_args.raw_output,
1316ebf5866SFelix Guo				       cli_args.timeout,
1326ebf5866SFelix Guo				       cli_args.jobs,
133ff7b437fSBrendan Higgins				       cli_args.build_dir,
134ff7b437fSBrendan Higgins				       cli_args.defconfig)
1356ebf5866SFelix Guo		result = run_tests(linux, request)
1366ebf5866SFelix Guo		if result.status != KunitStatus.SUCCESS:
1376ebf5866SFelix Guo			sys.exit(1)
1386ebf5866SFelix Guo	else:
1396ebf5866SFelix Guo		parser.print_help()
1406ebf5866SFelix Guo
1416ebf5866SFelix Guoif __name__ == '__main__':
142ff7b437fSBrendan Higgins	main(sys.argv[1:])
143