kunit.py (d053cf0d771f6547cb0537759a9af63cf402908d) kunit.py (01397e822af42f8485e876ba9d1309b63646d886)
1#!/usr/bin/python3
2# SPDX-License-Identifier: GPL-2.0
3#
4# A thin wrapper on top of the KUnit Kernel
5#
6# Copyright (C) 2019, Google LLC.
7# Author: Felix Guo <felixguoxiuping@gmail.com>
8# Author: Brendan Higgins <brendanhiggins@google.com>

--- 6 unchanged lines hidden (view full) ---

15
16from collections import namedtuple
17from enum import Enum, auto
18
19import kunit_config
20import kunit_kernel
21import kunit_parser
22
1#!/usr/bin/python3
2# SPDX-License-Identifier: GPL-2.0
3#
4# A thin wrapper on top of the KUnit Kernel
5#
6# Copyright (C) 2019, Google LLC.
7# Author: Felix Guo <felixguoxiuping@gmail.com>
8# Author: Brendan Higgins <brendanhiggins@google.com>

--- 6 unchanged lines hidden (view full) ---

15
16from collections import namedtuple
17from enum import Enum, auto
18
19import kunit_config
20import kunit_kernel
21import kunit_parser
22
23KunitResult = namedtuple('KunitResult', ['status','result'])
23KunitResult = namedtuple('KunitResult', ['status','result','elapsed_time'])
24
24
25KunitConfigRequest = namedtuple('KunitConfigRequest',
26 ['build_dir', 'make_options'])
27KunitBuildRequest = namedtuple('KunitBuildRequest',
28 ['jobs', 'build_dir', 'alltests',
29 'make_options'])
30KunitExecRequest = namedtuple('KunitExecRequest',
31 ['timeout', 'build_dir', 'alltests'])
32KunitParseRequest = namedtuple('KunitParseRequest',
33 ['raw_output', 'input_data'])
25KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs',
34KunitRequest = namedtuple('KunitRequest', ['raw_output','timeout', 'jobs',
26 'build_dir', 'defconfig',
27 'alltests', 'make_options'])
35 'build_dir', 'alltests',
36 'make_options'])
28
29KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
30
31class KunitStatus(Enum):
32 SUCCESS = auto()
33 CONFIG_FAILURE = auto()
34 BUILD_FAILURE = auto()
35 TEST_FAILURE = auto()

--- 5 unchanged lines hidden (view full) ---

41
42def get_kernel_root_path():
43 parts = sys.argv[0] if not __file__ else __file__
44 parts = os.path.realpath(parts).split('tools/testing/kunit')
45 if len(parts) != 2:
46 sys.exit(1)
47 return parts[0]
48
37
38KernelDirectoryPath = sys.argv[0].split('tools/testing/kunit/')[0]
39
40class KunitStatus(Enum):
41 SUCCESS = auto()
42 CONFIG_FAILURE = auto()
43 BUILD_FAILURE = auto()
44 TEST_FAILURE = auto()

--- 5 unchanged lines hidden (view full) ---

50
51def get_kernel_root_path():
52 parts = sys.argv[0] if not __file__ else __file__
53 parts = os.path.realpath(parts).split('tools/testing/kunit')
54 if len(parts) != 2:
55 sys.exit(1)
56 return parts[0]
57
49def run_tests(linux: kunit_kernel.LinuxSourceTree,
50 request: KunitRequest) -> KunitResult:
58def config_tests(linux: kunit_kernel.LinuxSourceTree,
59 request: KunitConfigRequest) -> KunitResult:
60 kunit_parser.print_with_timestamp('Configuring KUnit Kernel ...')
61
51 config_start = time.time()
62 config_start = time.time()
63 create_default_kunitconfig()
52 success = linux.build_reconfig(request.build_dir, request.make_options)
53 config_end = time.time()
54 if not success:
64 success = linux.build_reconfig(request.build_dir, request.make_options)
65 config_end = time.time()
66 if not success:
55 return KunitResult(KunitStatus.CONFIG_FAILURE, 'could not configure kernel')
67 return KunitResult(KunitStatus.CONFIG_FAILURE,
68 'could not configure kernel',
69 config_end - config_start)
70 return KunitResult(KunitStatus.SUCCESS,
71 'configured kernel successfully',
72 config_end - config_start)
56
73
74def build_tests(linux: kunit_kernel.LinuxSourceTree,
75 request: KunitBuildRequest) -> KunitResult:
57 kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
58
59 build_start = time.time()
60 success = linux.build_um_kernel(request.alltests,
61 request.jobs,
62 request.build_dir,
63 request.make_options)
64 build_end = time.time()
65 if not success:
66 return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel')
76 kunit_parser.print_with_timestamp('Building KUnit Kernel ...')
77
78 build_start = time.time()
79 success = linux.build_um_kernel(request.alltests,
80 request.jobs,
81 request.build_dir,
82 request.make_options)
83 build_end = time.time()
84 if not success:
85 return KunitResult(KunitStatus.BUILD_FAILURE, 'could not build kernel')
86 if not success:
87 return KunitResult(KunitStatus.BUILD_FAILURE,
88 'could not build kernel',
89 build_end - build_start)
90 return KunitResult(KunitStatus.SUCCESS,
91 'built kernel successfully',
92 build_end - build_start)
67
93
94def exec_tests(linux: kunit_kernel.LinuxSourceTree,
95 request: KunitExecRequest) -> KunitResult:
68 kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
69 test_start = time.time()
96 kunit_parser.print_with_timestamp('Starting KUnit Kernel ...')
97 test_start = time.time()
70 kunit_output = linux.run_kernel(
98 result = linux.run_kernel(
71 timeout=None if request.alltests else request.timeout,
72 build_dir=request.build_dir)
99 timeout=None if request.alltests else request.timeout,
100 build_dir=request.build_dir)
101
102 test_end = time.time()
103
104 return KunitResult(KunitStatus.SUCCESS,
105 result,
106 test_end - test_start)
107
108def parse_tests(request: KunitParseRequest) -> KunitResult:
109 parse_start = time.time()
110
111 test_result = kunit_parser.TestResult(kunit_parser.TestStatus.SUCCESS,
112 [],
113 'Tests not Parsed.')
73 if request.raw_output:
114 if request.raw_output:
74 raw_output = kunit_parser.raw_output(kunit_output)
75 isolated = list(kunit_parser.isolate_kunit_output(raw_output))
76 test_result = kunit_parser.parse_test_result(isolated)
115 kunit_parser.raw_output(request.input_data)
77 else:
116 else:
78 test_result = kunit_parser.parse_run_tests(kunit_output)
79 test_end = time.time()
117 test_result = kunit_parser.parse_run_tests(request.input_data)
118 parse_end = time.time()
80
119
120 if test_result.status != kunit_parser.TestStatus.SUCCESS:
121 return KunitResult(KunitStatus.TEST_FAILURE, test_result,
122 parse_end - parse_start)
123
124 return KunitResult(KunitStatus.SUCCESS, test_result,
125 parse_end - parse_start)
126
127
128def run_tests(linux: kunit_kernel.LinuxSourceTree,
129 request: KunitRequest) -> KunitResult:
130 run_start = time.time()
131
132 config_request = KunitConfigRequest(request.build_dir,
133 request.make_options)
134 config_result = config_tests(linux, config_request)
135 if config_result.status != KunitStatus.SUCCESS:
136 return config_result
137
138 build_request = KunitBuildRequest(request.jobs, request.build_dir,
139 request.alltests,
140 request.make_options)
141 build_result = build_tests(linux, build_request)
142 if build_result.status != KunitStatus.SUCCESS:
143 return build_result
144
145 exec_request = KunitExecRequest(request.timeout, request.build_dir,
146 request.alltests)
147 exec_result = exec_tests(linux, exec_request)
148 if exec_result.status != KunitStatus.SUCCESS:
149 return exec_result
150
151 parse_request = KunitParseRequest(request.raw_output,
152 exec_result.result)
153 parse_result = parse_tests(parse_request)
154
155 run_end = time.time()
156
81 kunit_parser.print_with_timestamp((
82 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
83 'building, %.3fs running\n') % (
157 kunit_parser.print_with_timestamp((
158 'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
159 'building, %.3fs running\n') % (
84 test_end - config_start,
85 config_end - config_start,
86 build_end - build_start,
87 test_end - test_start))
160 run_end - run_start,
161 config_result.elapsed_time,
162 build_result.elapsed_time,
163 exec_result.elapsed_time))
164 return parse_result
88
165
89 if test_result.status != kunit_parser.TestStatus.SUCCESS:
90 return KunitResult(KunitStatus.TEST_FAILURE, test_result)
91 else:
92 return KunitResult(KunitStatus.SUCCESS, test_result)
166def add_common_opts(parser):
167 parser.add_argument('--build_dir',
168 help='As in the make command, it specifies the build '
169 'directory.',
170 type=str, default='.kunit', metavar='build_dir')
171 parser.add_argument('--make_options',
172 help='X=Y make option, can be repeated.',
173 action='append')
174 parser.add_argument('--alltests',
175 help='Run all KUnit tests through allyesconfig',
176 action='store_true')
93
177
178def add_build_opts(parser):
179 parser.add_argument('--jobs',
180 help='As in the make command, "Specifies the number of '
181 'jobs (commands) to run simultaneously."',
182 type=int, default=8, metavar='jobs')
183
184def add_exec_opts(parser):
185 parser.add_argument('--timeout',
186 help='maximum number of seconds to allow for all tests '
187 'to run. This does not include time taken to build the '
188 'tests.',
189 type=int,
190 default=300,
191 metavar='timeout')
192
193def add_parse_opts(parser):
194 parser.add_argument('--raw_output', help='don\'t format output from kernel',
195 action='store_true')
196
197
94def main(argv, linux=None):
95 parser = argparse.ArgumentParser(
96 description='Helps writing and running KUnit tests.')
97 subparser = parser.add_subparsers(dest='subcommand')
98
198def main(argv, linux=None):
199 parser = argparse.ArgumentParser(
200 description='Helps writing and running KUnit tests.')
201 subparser = parser.add_subparsers(dest='subcommand')
202
203 # The 'run' command will config, build, exec, and parse in one go.
99 run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
204 run_parser = subparser.add_parser('run', help='Runs KUnit tests.')
100 run_parser.add_argument('--raw_output', help='don\'t format output from kernel',
101 action='store_true')
205 add_common_opts(run_parser)
206 add_build_opts(run_parser)
207 add_exec_opts(run_parser)
208 add_parse_opts(run_parser)
102
209
103 run_parser.add_argument('--timeout',
104 help='maximum number of seconds to allow for all tests '
105 'to run. This does not include time taken to build the '
106 'tests.',
107 type=int,
108 default=300,
109 metavar='timeout')
210 config_parser = subparser.add_parser('config',
211 help='Ensures that .config contains all of '
212 'the options in .kunitconfig')
213 add_common_opts(config_parser)
110
214
111 run_parser.add_argument('--jobs',
112 help='As in the make command, "Specifies the number of '
113 'jobs (commands) to run simultaneously."',
114 type=int, default=8, metavar='jobs')
215 build_parser = subparser.add_parser('build', help='Builds a kernel with KUnit tests')
216 add_common_opts(build_parser)
217 add_build_opts(build_parser)
115
218
116 run_parser.add_argument('--build_dir',
117 help='As in the make command, it specifies the build '
118 'directory.',
119 type=str, default='', metavar='build_dir')
219 exec_parser = subparser.add_parser('exec', help='Run a kernel with KUnit tests')
220 add_common_opts(exec_parser)
221 add_exec_opts(exec_parser)
222 add_parse_opts(exec_parser)
120
223
121 run_parser.add_argument('--defconfig',
122 help='Uses a default .kunitconfig.',
123 action='store_true')
224 # The 'parse' option is special, as it doesn't need the kernel source
225 # (therefore there is no need for a build_dir, hence no add_common_opts)
226 # and the '--file' argument is not relevant to 'run', so isn't in
227 # add_parse_opts()
228 parse_parser = subparser.add_parser('parse',
229 help='Parses KUnit results from a file, '
230 'and parses formatted results.')
231 add_parse_opts(parse_parser)
232 parse_parser.add_argument('file',
233 help='Specifies the file to read results from.',
234 type=str, nargs='?', metavar='input_file')
124
235
125 run_parser.add_argument('--alltests',
126 help='Run all KUnit tests through allyesconfig',
127 action='store_true')
128
129 run_parser.add_argument('--make_options',
130 help='X=Y make option, can be repeated.',
131 action='append')
132
133 cli_args = parser.parse_args(argv)
134
135 if cli_args.subcommand == 'run':
236 cli_args = parser.parse_args(argv)
237
238 if cli_args.subcommand == 'run':
136 if get_kernel_root_path():
137 os.chdir(get_kernel_root_path())
239 if not os.path.exists(cli_args.build_dir):
240 os.mkdir(cli_args.build_dir)
241 kunit_kernel.kunitconfig_path = os.path.join(
242 cli_args.build_dir,
243 kunit_kernel.kunitconfig_path)
138
244
139 if cli_args.build_dir:
140 if not os.path.exists(cli_args.build_dir):
141 os.mkdir(cli_args.build_dir)
142 kunit_kernel.kunitconfig_path = os.path.join(
143 cli_args.build_dir,
144 kunit_kernel.kunitconfig_path)
145
146 if cli_args.defconfig:
245 if not os.path.exists(kunit_kernel.kunitconfig_path):
147 create_default_kunitconfig()
148
149 if not linux:
150 linux = kunit_kernel.LinuxSourceTree()
151
152 request = KunitRequest(cli_args.raw_output,
153 cli_args.timeout,
154 cli_args.jobs,
155 cli_args.build_dir,
246 create_default_kunitconfig()
247
248 if not linux:
249 linux = kunit_kernel.LinuxSourceTree()
250
251 request = KunitRequest(cli_args.raw_output,
252 cli_args.timeout,
253 cli_args.jobs,
254 cli_args.build_dir,
156 cli_args.defconfig,
157 cli_args.alltests,
158 cli_args.make_options)
159 result = run_tests(linux, request)
160 if result.status != KunitStatus.SUCCESS:
161 sys.exit(1)
255 cli_args.alltests,
256 cli_args.make_options)
257 result = run_tests(linux, request)
258 if result.status != KunitStatus.SUCCESS:
259 sys.exit(1)
260 elif cli_args.subcommand == 'config':
261 if cli_args.build_dir:
262 if not os.path.exists(cli_args.build_dir):
263 os.mkdir(cli_args.build_dir)
264 kunit_kernel.kunitconfig_path = os.path.join(
265 cli_args.build_dir,
266 kunit_kernel.kunitconfig_path)
267
268 if not os.path.exists(kunit_kernel.kunitconfig_path):
269 create_default_kunitconfig()
270
271 if not linux:
272 linux = kunit_kernel.LinuxSourceTree()
273
274 request = KunitConfigRequest(cli_args.build_dir,
275 cli_args.make_options)
276 result = config_tests(linux, request)
277 kunit_parser.print_with_timestamp((
278 'Elapsed time: %.3fs\n') % (
279 result.elapsed_time))
280 if result.status != KunitStatus.SUCCESS:
281 sys.exit(1)
282 elif cli_args.subcommand == 'build':
283 if cli_args.build_dir:
284 if not os.path.exists(cli_args.build_dir):
285 os.mkdir(cli_args.build_dir)
286 kunit_kernel.kunitconfig_path = os.path.join(
287 cli_args.build_dir,
288 kunit_kernel.kunitconfig_path)
289
290 if not os.path.exists(kunit_kernel.kunitconfig_path):
291 create_default_kunitconfig()
292
293 if not linux:
294 linux = kunit_kernel.LinuxSourceTree()
295
296 request = KunitBuildRequest(cli_args.jobs,
297 cli_args.build_dir,
298 cli_args.alltests,
299 cli_args.make_options)
300 result = build_tests(linux, request)
301 kunit_parser.print_with_timestamp((
302 'Elapsed time: %.3fs\n') % (
303 result.elapsed_time))
304 if result.status != KunitStatus.SUCCESS:
305 sys.exit(1)
306 elif cli_args.subcommand == 'exec':
307 if cli_args.build_dir:
308 if not os.path.exists(cli_args.build_dir):
309 os.mkdir(cli_args.build_dir)
310 kunit_kernel.kunitconfig_path = os.path.join(
311 cli_args.build_dir,
312 kunit_kernel.kunitconfig_path)
313
314 if not os.path.exists(kunit_kernel.kunitconfig_path):
315 create_default_kunitconfig()
316
317 if not linux:
318 linux = kunit_kernel.LinuxSourceTree()
319
320 exec_request = KunitExecRequest(cli_args.timeout,
321 cli_args.build_dir,
322 cli_args.alltests)
323 exec_result = exec_tests(linux, exec_request)
324 parse_request = KunitParseRequest(cli_args.raw_output,
325 exec_result.result)
326 result = parse_tests(parse_request)
327 kunit_parser.print_with_timestamp((
328 'Elapsed time: %.3fs\n') % (
329 exec_result.elapsed_time))
330 if result.status != KunitStatus.SUCCESS:
331 sys.exit(1)
332 elif cli_args.subcommand == 'parse':
333 if cli_args.file == None:
334 kunit_output = sys.stdin
335 else:
336 with open(cli_args.file, 'r') as f:
337 kunit_output = f.read().splitlines()
338 request = KunitParseRequest(cli_args.raw_output,
339 kunit_output)
340 result = parse_tests(request)
341 if result.status != KunitStatus.SUCCESS:
342 sys.exit(1)
162 else:
163 parser.print_help()
164
165if __name__ == '__main__':
166 main(sys.argv[1:])
343 else:
344 parser.print_help()
345
346if __name__ == '__main__':
347 main(sys.argv[1:])