2020-11-23 15:15:33 +01:00
#!/usr/bin/env python3
2019-09-23 02:02:43 -07:00
# SPDX-License-Identifier: GPL-2.0
#
# A thin wrapper on top of the KUnit Kernel
#
# Copyright (C) 2019, Google LLC.
# Author: Felix Guo <felixguoxiuping@gmail.com>
# Author: Brendan Higgins <brendanhiggins@google.com>
import argparse
import sys
import os
import time
from collections import namedtuple
from enum import Enum , auto
import kunit_config
2020-08-11 14:27:56 -07:00
import kunit_json
2019-09-23 02:02:43 -07:00
import kunit_kernel
import kunit_parser
2020-04-30 21:27:01 -07:00
KunitResult = namedtuple ( ' KunitResult ' , [ ' status ' , ' result ' , ' elapsed_time ' ] )
2019-09-23 02:02:43 -07:00
2020-04-30 21:27:01 -07:00
KunitConfigRequest = namedtuple ( ' KunitConfigRequest ' ,
kunit: Fix TabError, remove defconfig code and handle when there is no kunitconfig
The identation before this code
(`if not os.path.exists(cli_args.build_dir):``)
was with spaces instead of tabs after fixed up merge conflits,
this commit revert spaces to tabs:
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
File "tools/testing/kunit/kunit.py", line 247
if not linux:
^
TabError: inconsistent use of tabs and spaces in indentation
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 338, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 215, in main
add_config_opts(config_parser)
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 337, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 255, in main
result = run_tests(linux, request)
File "tools/testing/kunit/kunit.py", line 133, in run_tests
request.defconfig,
AttributeError: 'KunitRequest' object has no attribute 'defconfig'
Handles when there is no .kunitconfig, the error due to merge conflicts
between the following:
commit 9bdf64b35117 ("kunit: use KUnit defconfig by default")
commit 45ba7a893ad8 ("kunit: kunit_tool: Separate out
config/build/exec/parse")
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 335, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 246, in main
linux = kunit_kernel.LinuxSourceTree()
File "../tools/testing/kunit/kunit_kernel.py", line 109, in __init__
self._kconfig.read_from_file(kunitconfig_path)
File "t../ools/testing/kunit/kunit_config.py", line 88, in read_from_file
with open(path, 'r') as f:
FileNotFoundError: [Errno 2] No such file or directory: '.kunit/.kunitconfig'
Signed-off-by: Vitor Massaru Iha <vitor@massaru.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2020-05-29 16:28:45 -03:00
[ ' build_dir ' , ' make_options ' ] )
2020-04-30 21:27:01 -07:00
KunitBuildRequest = namedtuple ( ' KunitBuildRequest ' ,
[ ' jobs ' , ' build_dir ' , ' alltests ' ,
' make_options ' ] )
KunitExecRequest = namedtuple ( ' KunitExecRequest ' ,
[ ' timeout ' , ' build_dir ' , ' alltests ' ] )
KunitParseRequest = namedtuple ( ' KunitParseRequest ' ,
2020-08-11 14:27:56 -07:00
[ ' raw_output ' , ' input_data ' , ' build_dir ' , ' json ' ] )
2020-03-16 13:21:25 -07:00
KunitRequest = namedtuple ( ' KunitRequest ' , [ ' raw_output ' , ' timeout ' , ' jobs ' ,
2020-08-11 14:27:56 -07:00
' build_dir ' , ' alltests ' , ' json ' ,
2020-04-14 20:37:53 -03:00
' make_options ' ] )
2019-09-23 02:02:43 -07:00
2020-02-18 14:19:16 -08:00
KernelDirectoryPath = sys . argv [ 0 ] . split ( ' tools/testing/kunit/ ' ) [ 0 ]
2019-09-23 02:02:43 -07:00
class KunitStatus ( Enum ) :
SUCCESS = auto ( )
CONFIG_FAILURE = auto ( )
BUILD_FAILURE = auto ( )
TEST_FAILURE = auto ( )
2020-02-18 14:19:16 -08:00
def get_kernel_root_path ( ) :
parts = sys . argv [ 0 ] if not __file__ else __file__
parts = os . path . realpath ( parts ) . split ( ' tools/testing/kunit ' )
if len ( parts ) != 2 :
sys . exit ( 1 )
return parts [ 0 ]
2020-04-30 21:27:01 -07:00
def config_tests ( linux : kunit_kernel . LinuxSourceTree ,
request : KunitConfigRequest ) - > KunitResult :
kunit_parser . print_with_timestamp ( ' Configuring KUnit Kernel ... ' )
2019-09-23 02:02:43 -07:00
config_start = time . time ( )
2020-03-23 12:04:59 -07:00
success = linux . build_reconfig ( request . build_dir , request . make_options )
2019-09-23 02:02:43 -07:00
config_end = time . time ( )
if not success :
2020-04-30 21:27:01 -07:00
return KunitResult ( KunitStatus . CONFIG_FAILURE ,
' could not configure kernel ' ,
config_end - config_start )
return KunitResult ( KunitStatus . SUCCESS ,
' configured kernel successfully ' ,
config_end - config_start )
2019-09-23 02:02:43 -07:00
2020-04-30 21:27:01 -07:00
def build_tests ( linux : kunit_kernel . LinuxSourceTree ,
request : KunitBuildRequest ) - > KunitResult :
2019-09-23 02:02:43 -07:00
kunit_parser . print_with_timestamp ( ' Building KUnit Kernel ... ' )
build_start = time . time ( )
2020-03-16 13:21:25 -07:00
success = linux . build_um_kernel ( request . alltests ,
request . jobs ,
2020-03-23 12:04:59 -07:00
request . build_dir ,
request . make_options )
2019-09-23 02:02:43 -07:00
build_end = time . time ( )
if not success :
2020-06-15 23:47:30 -07:00
return KunitResult ( KunitStatus . BUILD_FAILURE ,
' could not build kernel ' ,
build_end - build_start )
2020-04-30 21:27:01 -07:00
if not success :
return KunitResult ( KunitStatus . BUILD_FAILURE ,
' could not build kernel ' ,
build_end - build_start )
return KunitResult ( KunitStatus . SUCCESS ,
' built kernel successfully ' ,
build_end - build_start )
2019-09-23 02:02:43 -07:00
2020-04-30 21:27:01 -07:00
def exec_tests ( linux : kunit_kernel . LinuxSourceTree ,
request : KunitExecRequest ) - > KunitResult :
2019-09-23 02:02:43 -07:00
kunit_parser . print_with_timestamp ( ' Starting KUnit Kernel ... ' )
test_start = time . time ( )
2020-04-30 21:27:01 -07:00
result = linux . run_kernel (
2020-03-16 13:21:25 -07:00
timeout = None if request . alltests else request . timeout ,
build_dir = request . build_dir )
2020-04-30 21:27:01 -07:00
test_end = time . time ( )
return KunitResult ( KunitStatus . SUCCESS ,
result ,
test_end - test_start )
def parse_tests ( request : KunitParseRequest ) - > KunitResult :
parse_start = time . time ( )
test_result = kunit_parser . TestResult ( kunit_parser . TestStatus . SUCCESS ,
[ ] ,
' Tests not Parsed. ' )
2020-08-11 14:27:56 -07:00
2019-09-23 02:02:43 -07:00
if request . raw_output :
2020-04-30 21:27:01 -07:00
kunit_parser . raw_output ( request . input_data )
2019-09-23 02:02:43 -07:00
else :
2020-04-30 21:27:01 -07:00
test_result = kunit_parser . parse_run_tests ( request . input_data )
parse_end = time . time ( )
2020-08-11 14:27:56 -07:00
if request . json :
json_obj = kunit_json . get_json_result (
test_result = test_result ,
def_config = ' kunit_defconfig ' ,
build_dir = request . build_dir ,
json_path = request . json )
if request . json == ' stdout ' :
print ( json_obj )
2020-04-30 21:27:01 -07:00
if test_result . status != kunit_parser . TestStatus . SUCCESS :
return KunitResult ( KunitStatus . TEST_FAILURE , test_result ,
parse_end - parse_start )
return KunitResult ( KunitStatus . SUCCESS , test_result ,
parse_end - parse_start )
def run_tests ( linux : kunit_kernel . LinuxSourceTree ,
request : KunitRequest ) - > KunitResult :
run_start = time . time ( )
config_request = KunitConfigRequest ( request . build_dir ,
request . make_options )
config_result = config_tests ( linux , config_request )
if config_result . status != KunitStatus . SUCCESS :
return config_result
build_request = KunitBuildRequest ( request . jobs , request . build_dir ,
request . alltests ,
request . make_options )
build_result = build_tests ( linux , build_request )
if build_result . status != KunitStatus . SUCCESS :
return build_result
exec_request = KunitExecRequest ( request . timeout , request . build_dir ,
request . alltests )
exec_result = exec_tests ( linux , exec_request )
if exec_result . status != KunitStatus . SUCCESS :
return exec_result
parse_request = KunitParseRequest ( request . raw_output ,
2020-08-11 14:27:56 -07:00
exec_result . result ,
request . build_dir ,
request . json )
2020-04-30 21:27:01 -07:00
parse_result = parse_tests ( parse_request )
run_end = time . time ( )
2019-09-23 02:02:43 -07:00
kunit_parser . print_with_timestamp ( (
' Elapsed time: %.3f s total, %.3f s configuring, %.3f s ' +
' building, %.3f s running \n ' ) % (
2020-04-30 21:27:01 -07:00
run_end - run_start ,
config_result . elapsed_time ,
build_result . elapsed_time ,
exec_result . elapsed_time ) )
return parse_result
def add_common_opts ( parser ) :
parser . add_argument ( ' --build_dir ' ,
help = ' As in the make command, it specifies the build '
' directory. ' ,
2020-04-14 20:09:50 -03:00
type = str , default = ' .kunit ' , metavar = ' build_dir ' )
2020-04-30 21:27:01 -07:00
parser . add_argument ( ' --make_options ' ,
help = ' X=Y make option, can be repeated. ' ,
action = ' append ' )
parser . add_argument ( ' --alltests ' ,
help = ' Run all KUnit tests through allyesconfig ' ,
action = ' store_true ' )
def add_build_opts ( parser ) :
parser . add_argument ( ' --jobs ' ,
help = ' As in the make command, " Specifies the number of '
' jobs (commands) to run simultaneously. " ' ,
type = int , default = 8 , metavar = ' jobs ' )
def add_exec_opts ( parser ) :
parser . add_argument ( ' --timeout ' ,
help = ' maximum number of seconds to allow for all tests '
' to run. This does not include time taken to build the '
' tests. ' ,
type = int ,
default = 300 ,
metavar = ' timeout ' )
def add_parse_opts ( parser ) :
parser . add_argument ( ' --raw_output ' , help = ' don \' t format output from kernel ' ,
action = ' store_true ' )
2020-08-11 14:27:56 -07:00
parser . add_argument ( ' --json ' ,
nargs = ' ? ' ,
help = ' Stores test results in a JSON, and either '
' prints to stdout or saves to file if a '
' filename is specified ' ,
type = str , const = ' stdout ' , default = None )
2019-09-23 02:02:43 -07:00
2019-09-23 02:02:44 -07:00
def main ( argv , linux = None ) :
2019-09-23 02:02:43 -07:00
parser = argparse . ArgumentParser (
description = ' Helps writing and running KUnit tests. ' )
subparser = parser . add_subparsers ( dest = ' subcommand ' )
2020-04-30 21:27:01 -07:00
# The 'run' command will config, build, exec, and parse in one go.
2019-09-23 02:02:43 -07:00
run_parser = subparser . add_parser ( ' run ' , help = ' Runs KUnit tests. ' )
2020-04-30 21:27:01 -07:00
add_common_opts ( run_parser )
add_build_opts ( run_parser )
add_exec_opts ( run_parser )
add_parse_opts ( run_parser )
config_parser = subparser . add_parser ( ' config ' ,
help = ' Ensures that .config contains all of '
' the options in .kunitconfig ' )
add_common_opts ( config_parser )
build_parser = subparser . add_parser ( ' build ' , help = ' Builds a kernel with KUnit tests ' )
add_common_opts ( build_parser )
add_build_opts ( build_parser )
exec_parser = subparser . add_parser ( ' exec ' , help = ' Run a kernel with KUnit tests ' )
add_common_opts ( exec_parser )
add_exec_opts ( exec_parser )
add_parse_opts ( exec_parser )
# The 'parse' option is special, as it doesn't need the kernel source
# (therefore there is no need for a build_dir, hence no add_common_opts)
# and the '--file' argument is not relevant to 'run', so isn't in
# add_parse_opts()
parse_parser = subparser . add_parser ( ' parse ' ,
help = ' Parses KUnit results from a file, '
' and parses formatted results. ' )
add_parse_opts ( parse_parser )
parse_parser . add_argument ( ' file ' ,
help = ' Specifies the file to read results from. ' ,
type = str , nargs = ' ? ' , metavar = ' input_file ' )
2020-03-23 12:04:59 -07:00
2019-09-23 02:02:43 -07:00
cli_args = parser . parse_args ( argv )
2020-08-11 14:27:55 -07:00
if get_kernel_root_path ( ) :
os . chdir ( get_kernel_root_path ( ) )
2019-09-23 02:02:43 -07:00
if cli_args . subcommand == ' run ' :
kunit: Fix TabError, remove defconfig code and handle when there is no kunitconfig
The identation before this code
(`if not os.path.exists(cli_args.build_dir):``)
was with spaces instead of tabs after fixed up merge conflits,
this commit revert spaces to tabs:
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
File "tools/testing/kunit/kunit.py", line 247
if not linux:
^
TabError: inconsistent use of tabs and spaces in indentation
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 338, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 215, in main
add_config_opts(config_parser)
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 337, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 255, in main
result = run_tests(linux, request)
File "tools/testing/kunit/kunit.py", line 133, in run_tests
request.defconfig,
AttributeError: 'KunitRequest' object has no attribute 'defconfig'
Handles when there is no .kunitconfig, the error due to merge conflicts
between the following:
commit 9bdf64b35117 ("kunit: use KUnit defconfig by default")
commit 45ba7a893ad8 ("kunit: kunit_tool: Separate out
config/build/exec/parse")
[iha@bbking linux]$ tools/testing/kunit/kunit.py run
Traceback (most recent call last):
File "tools/testing/kunit/kunit.py", line 335, in <module>
main(sys.argv[1:])
File "tools/testing/kunit/kunit.py", line 246, in main
linux = kunit_kernel.LinuxSourceTree()
File "../tools/testing/kunit/kunit_kernel.py", line 109, in __init__
self._kconfig.read_from_file(kunitconfig_path)
File "t../ools/testing/kunit/kunit_config.py", line 88, in read_from_file
with open(path, 'r') as f:
FileNotFoundError: [Errno 2] No such file or directory: '.kunit/.kunitconfig'
Signed-off-by: Vitor Massaru Iha <vitor@massaru.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2020-05-29 16:28:45 -03:00
if not os . path . exists ( cli_args . build_dir ) :
os . mkdir ( cli_args . build_dir )
2020-09-28 13:02:27 -07:00
2019-09-23 02:02:44 -07:00
if not linux :
linux = kunit_kernel . LinuxSourceTree ( )
2020-10-26 18:59:25 +02:00
linux . create_kunitconfig ( cli_args . build_dir )
linux . read_kunitconfig ( cli_args . build_dir )
2019-09-23 02:02:43 -07:00
request = KunitRequest ( cli_args . raw_output ,
cli_args . timeout ,
cli_args . jobs ,
2019-09-23 02:02:44 -07:00
cli_args . build_dir ,
2020-03-23 12:04:59 -07:00
cli_args . alltests ,
2020-08-11 14:27:56 -07:00
cli_args . json ,
2020-03-23 12:04:59 -07:00
cli_args . make_options )
2019-09-23 02:02:43 -07:00
result = run_tests ( linux , request )
if result . status != KunitStatus . SUCCESS :
sys . exit ( 1 )
2020-04-30 21:27:01 -07:00
elif cli_args . subcommand == ' config ' :
2020-09-28 13:02:27 -07:00
if cli_args . build_dir and (
not os . path . exists ( cli_args . build_dir ) ) :
os . mkdir ( cli_args . build_dir )
2020-04-30 21:27:01 -07:00
if not linux :
linux = kunit_kernel . LinuxSourceTree ( )
2020-10-26 18:59:25 +02:00
linux . create_kunitconfig ( cli_args . build_dir )
linux . read_kunitconfig ( cli_args . build_dir )
2020-04-30 21:27:01 -07:00
request = KunitConfigRequest ( cli_args . build_dir ,
cli_args . make_options )
result = config_tests ( linux , request )
kunit_parser . print_with_timestamp ( (
' Elapsed time: %.3f s \n ' ) % (
result . elapsed_time ) )
if result . status != KunitStatus . SUCCESS :
sys . exit ( 1 )
elif cli_args . subcommand == ' build ' :
if not linux :
linux = kunit_kernel . LinuxSourceTree ( )
2020-10-26 18:59:25 +02:00
linux . create_kunitconfig ( cli_args . build_dir )
linux . read_kunitconfig ( cli_args . build_dir )
2020-04-30 21:27:01 -07:00
request = KunitBuildRequest ( cli_args . jobs ,
cli_args . build_dir ,
cli_args . alltests ,
cli_args . make_options )
result = build_tests ( linux , request )
kunit_parser . print_with_timestamp ( (
' Elapsed time: %.3f s \n ' ) % (
result . elapsed_time ) )
if result . status != KunitStatus . SUCCESS :
sys . exit ( 1 )
elif cli_args . subcommand == ' exec ' :
if not linux :
linux = kunit_kernel . LinuxSourceTree ( )
2020-10-26 18:59:25 +02:00
linux . create_kunitconfig ( cli_args . build_dir )
linux . read_kunitconfig ( cli_args . build_dir )
2020-04-30 21:27:01 -07:00
exec_request = KunitExecRequest ( cli_args . timeout ,
cli_args . build_dir ,
cli_args . alltests )
exec_result = exec_tests ( linux , exec_request )
parse_request = KunitParseRequest ( cli_args . raw_output ,
2020-08-11 14:27:56 -07:00
exec_result . result ,
cli_args . build_dir ,
cli_args . json )
2020-04-30 21:27:01 -07:00
result = parse_tests ( parse_request )
kunit_parser . print_with_timestamp ( (
' Elapsed time: %.3f s \n ' ) % (
exec_result . elapsed_time ) )
if result . status != KunitStatus . SUCCESS :
sys . exit ( 1 )
elif cli_args . subcommand == ' parse ' :
if cli_args . file == None :
kunit_output = sys . stdin
else :
with open ( cli_args . file , ' r ' ) as f :
kunit_output = f . read ( ) . splitlines ( )
request = KunitParseRequest ( cli_args . raw_output ,
2020-08-11 14:27:56 -07:00
kunit_output ,
2020-10-21 00:16:03 -07:00
None ,
2020-08-11 14:27:56 -07:00
cli_args . json )
2020-04-30 21:27:01 -07:00
result = parse_tests ( request )
if result . status != KunitStatus . SUCCESS :
sys . exit ( 1 )
2019-09-23 02:02:43 -07:00
else :
parser . print_help ( )
if __name__ == ' __main__ ' :
2019-09-23 02:02:44 -07:00
main ( sys . argv [ 1 : ] )