Add samsung specific changes
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_KUNIT_EXAMPLE_TEST=y
|
||||
CONFIG_KUNIT_ALL_TESTS=y
|
||||
CONFIG_SEC_KUNIT=y
|
||||
CONFIG_OF=y
|
||||
|
212
tools/testing/kunit/insert_kunit/insert_kunit.py
Executable file
212
tools/testing/kunit/insert_kunit/insert_kunit.py
Executable file
@@ -0,0 +1,212 @@
|
||||
#! /usr/bin/env python3
|
||||
__author__ = 'Ji-Hun Kim'
|
||||
__version__ = '0.1.0'
|
||||
__maintainer__ = 'Ji-Hun Kim'
|
||||
__email__ = 'ji_hun.kim@samsung.com'
|
||||
|
||||
'''
|
||||
Insert a default KUnit unit test templete in the directory
|
||||
The result will be:
|
||||
mydir$ tree
|
||||
.
|
||||
├── my_driver.c
|
||||
├── Kconfig
|
||||
├── Makefile
|
||||
└── kunit_test
|
||||
├── Makefile
|
||||
└── my_driver_test.c
|
||||
'''
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from kunit_new_template import create_skeletons, Skeletons
|
||||
|
||||
TEST_PATH='kunit_test'
|
||||
|
||||
class ConfigNameExtractor():
|
||||
def __init__(self, path):
|
||||
dir_name, file_name = os.path.split(path)
|
||||
mkfile = os.path.join(dir_name, 'Makefile')
|
||||
file_prefix, _ = os.path.splitext(file_name)
|
||||
obj_name = file_prefix + '.o'
|
||||
self.result = None
|
||||
self.__search_file(obj_name, mkfile)
|
||||
|
||||
def __search_file(self, string, target_file):
|
||||
if not os.path.exists(target_file):
|
||||
print(f'The file is not exist: {target_file}')
|
||||
sys.exit(1)
|
||||
with open(target_file, 'rt') as fp:
|
||||
for line in fp:
|
||||
ret = self.__search_line(string, line)
|
||||
|
||||
def __search_line(self, string, line):
|
||||
if string in line:
|
||||
self.__extract_config(line)
|
||||
|
||||
def __extract_config(self, line):
|
||||
# FIXME: is there another cases?
|
||||
search = 'obj-\$\((.*?)\)' # get inside of obj-$()
|
||||
rgx = re.compile(search)
|
||||
srch = rgx.search(line)
|
||||
if srch:
|
||||
self.result = srch.group(1)
|
||||
|
||||
class TemplateGenerator():
|
||||
def __init__(self, path, postfix='-test'):
|
||||
self.__create_path(path, postfix)
|
||||
|
||||
def __create_path(self, path, postfix):
|
||||
self.dir_name, self.file_name = os.path.split(path)
|
||||
self.file_prefix, _ = os.path.splitext(self.file_name)
|
||||
self.testfile_name = os.path.join(self.dir_name, self.file_prefix + postfix + '.c')
|
||||
self.test_object_file = self.file_prefix + postfix + '.o'
|
||||
# FIXME: change to CONFIG_KUNIT_<file name upper case>_TEST
|
||||
# from CONFIG_<file name upper case>_TEST
|
||||
# it is generated by class create_skeletons
|
||||
namespace_prefix = self.file_prefix.replace('-', '_')
|
||||
self.kconfig_name = 'CONFIG_' + namespace_prefix.upper() + '_TEST'
|
||||
self.skeletons = create_skeletons(self.file_name, namespace_prefix, self.test_object_file)
|
||||
|
||||
def get_kconfig(self):
|
||||
return self.skeletons.kconfig_skeleton
|
||||
|
||||
def get_makefile(self):
|
||||
return self.skeletons.makefile_skeleton
|
||||
|
||||
def get_testfile(self):
|
||||
return self.skeletons.test_skeleton
|
||||
|
||||
class TestConstructor():
|
||||
'''
|
||||
modify path/Makefile
|
||||
modify path/Kconfig
|
||||
mkdir path/kunit_test
|
||||
gen path/kunit_test/Makefile
|
||||
gen path/kunit_test/testfile.c
|
||||
'''
|
||||
def __init__(self, path):
|
||||
self.tmplts = TemplateGenerator(path)
|
||||
self.dir_name = self.tmplts.dir_name
|
||||
self.file_prefix = self.tmplts.file_prefix
|
||||
self.test_path = os.path.join(self.dir_name, TEST_PATH)
|
||||
self.test_driver_name = self.file_prefix + '_test'
|
||||
self.tgt_config_name = ConfigNameExtractor(path).result
|
||||
if os.path.exists(self.test_path):
|
||||
self.additional = True
|
||||
else:
|
||||
os.mkdir(self.test_path)
|
||||
self.additional = False
|
||||
|
||||
def __print_result(self):
|
||||
pass
|
||||
|
||||
def __search_str(self, content, target):
|
||||
with open(target, 'r') as fp:
|
||||
ret = False
|
||||
if content in fp.read():
|
||||
ret = True
|
||||
return ret
|
||||
|
||||
def __is_contain(self, string, fpath):
|
||||
def strip(orig):
|
||||
return ' '.join(orig.split())
|
||||
with open(fpath, 'r') as fp:
|
||||
if strip(string) in strip(fp.read()):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __cat_file(self, f):
|
||||
with open(f, 'r') as fp:
|
||||
print(fp.read())
|
||||
|
||||
def __append_content(self, content, target, debug=False):
|
||||
if not os.path.exists(target):
|
||||
print(f'not exist: {target}')
|
||||
sys.exit(1)
|
||||
if self.__is_contain(content, target):
|
||||
return
|
||||
|
||||
with open(target, 'a') as fp:
|
||||
#if not self.__search_str(content, target):
|
||||
fp.write(content)
|
||||
if debug:
|
||||
print(f'appended: {target}')
|
||||
self.__cat_file(target)
|
||||
|
||||
def __write_content(self, content, target, debug=False):
|
||||
if os.path.exists(target):
|
||||
if self.__is_contain(content, target):
|
||||
return
|
||||
with open(target, 'a') as fp:
|
||||
fp.write(content)
|
||||
else:
|
||||
with open(target, 'w') as fp:
|
||||
fp.write(content)
|
||||
|
||||
if debug:
|
||||
print(f'generated: {target}')
|
||||
self.__cat_file(target)
|
||||
|
||||
def append_makefile(self):
|
||||
mk_path = os.path.join(self.dir_name, 'Makefile')
|
||||
mk_content = f'\nobj-$(CONFIG_SEC_KUNIT)\t\t\t+= {TEST_PATH}/\n'
|
||||
gcov_content = 'GCOV_PROFILE_' + self.file_prefix + '.o\t\t:= $(CONFIG_SEC_KUNIT)\n'
|
||||
|
||||
self.__append_content(mk_content, mk_path)
|
||||
self.__append_content(gcov_content, mk_path)
|
||||
|
||||
def append_kconfig(self):
|
||||
mk_path = os.path.join(self.dir_name, 'Kconfig')
|
||||
test_kconfig = self.tmplts.kconfig_name.replace('CONFIG_', '')
|
||||
# FIXME: the config name should be a real config + _TEST ?
|
||||
if self.__is_contain(f'config {test_kconfig}', mk_path):
|
||||
return
|
||||
self.__append_content('\n' + self.tmplts.get_kconfig() + '\n', mk_path)
|
||||
|
||||
def write_test_makefile(self):
|
||||
mk_path = os.path.join(self.test_path, 'Makefile')
|
||||
obj_name = self.test_driver_name + '.o'
|
||||
test_config = self.tmplts.kconfig_name
|
||||
if self.tgt_config_name:
|
||||
tgt_config = f'{self.tgt_config_name}'
|
||||
else:
|
||||
tgt_config = 'y'
|
||||
mk_contents = [
|
||||
'\nifneq ($(CONFIG_UML), y)',
|
||||
' # Test file for on-device',
|
||||
f' obj-$({tgt_config}) += {obj_name}',
|
||||
'else',
|
||||
' # Test file for UML',
|
||||
f' obj-$({test_config}_FOR_ONLY_UML) += {obj_name}',
|
||||
'endif\n',
|
||||
]
|
||||
self.__write_content('\n'.join(mk_contents), mk_path)
|
||||
|
||||
def write_test_driver(self):
|
||||
drv_path = os.path.join(self.test_path, self.test_driver_name + '.c')
|
||||
drv_cont = self.tmplts.get_testfile()
|
||||
self.__write_content(drv_cont, drv_path)
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Generate a KUnit test template')
|
||||
parser.add_argument('-f', '--filepath', dest='file_path', help='unit testing target file path')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
def main():
|
||||
arg = parse_args()
|
||||
a = TestConstructor(os.path.abspath(arg.file_path))
|
||||
a.append_makefile()
|
||||
a.append_kconfig()
|
||||
a.write_test_makefile()
|
||||
a.write_test_driver()
|
||||
result = os.path.join(os.path.split(arg.file_path)[0], TEST_PATH, a.test_driver_name + '.c')
|
||||
print(f'Done! You can write test cases on the {result}')
|
||||
print(f'Please check KUnit-wiki for more details: https://mobilerndhub.sec.samsung.net/wiki/x/sjFaU')
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
213
tools/testing/kunit/insert_kunit/insert_kunit_test.py
Executable file
213
tools/testing/kunit/insert_kunit/insert_kunit_test.py
Executable file
@@ -0,0 +1,213 @@
|
||||
#! /usr/bin/env python3
|
||||
__author__ = 'Ji-Hun Kim'
|
||||
__version__ = '0.1.0'
|
||||
__maintainer__ = 'Ji-Hun Kim'
|
||||
__email__ = 'ji_hun.kim@samsung.com'
|
||||
|
||||
'''
|
||||
Unit Test for insert_kunit.py
|
||||
'''
|
||||
|
||||
import unittest
|
||||
import shutil
|
||||
import os
|
||||
from insert_kunit import *
|
||||
|
||||
script_path, _ = os.path.split(os.path.realpath(__file__))
|
||||
|
||||
test_list = [
|
||||
'test_data/bsp_kernel/drivers/fingerprint',
|
||||
'test_data/bsp_kernel/drivers/muic'
|
||||
]
|
||||
|
||||
def generate_test_data(path_name):
|
||||
test_orig=os.path.join(script_path, path_name)
|
||||
test_target = os.path.join(script_path, 'temp', path_name)
|
||||
|
||||
try:
|
||||
shutil.copytree(test_orig, test_target)
|
||||
except FileExistsError as e:
|
||||
print(e)
|
||||
shutil.rmtree(test_target)
|
||||
shutil.copytree(test_orig, test_target)
|
||||
|
||||
test_path = os.path.join(test_target, 'qbt2000_common.c')
|
||||
|
||||
return test_path, test_target
|
||||
|
||||
def remove_temp_test_data():
|
||||
try:
|
||||
generated_path = os.path.join(script_path, 'temp')
|
||||
shutil.rmtree(generated_path)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def is_contain(string, fpath):
|
||||
with open(fpath, 'r') as fp:
|
||||
if string in fp.read():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def how_many_contains(string, fpath):
|
||||
cnt = 0
|
||||
with open(fpath, 'r') as fp:
|
||||
for line in fp.readlines():
|
||||
if string in line:
|
||||
cnt = cnt + 1
|
||||
return cnt
|
||||
|
||||
class TestAdditionalInsertionSameDirectory(unittest.TestCase):
|
||||
'''
|
||||
If inserting test template to the same directory where is another templete
|
||||
has been generated previously.
|
||||
'''
|
||||
def setUp(self):
|
||||
self.test_path, self.test_tgt = generate_test_data(test_list[0])
|
||||
|
||||
# 1. generate first test template for 'fingerprint/qbt2000_common.c'
|
||||
self.tgt_driver = os.path.join(self.test_tgt, 'qbt2000_common.c')
|
||||
self.af = TestConstructor(self.tgt_driver)
|
||||
self.af.append_makefile()
|
||||
self.af.append_kconfig()
|
||||
self.af.write_test_makefile()
|
||||
self.af.write_test_driver()
|
||||
|
||||
# 2. generate second test template for 'fingerprint/fingerprint_sysfs.c'
|
||||
self.tgt_driver = os.path.join(self.test_tgt, 'fingerprint_sysfs.c')
|
||||
self.af2 = TestConstructor(self.tgt_driver)
|
||||
self.af2.append_makefile()
|
||||
self.af2.append_kconfig()
|
||||
self.af2.write_test_makefile()
|
||||
self.af2.write_test_driver()
|
||||
|
||||
# these are target for check
|
||||
self.mkfile = os.path.join(self.test_tgt, 'Makefile')
|
||||
self.kconf = os.path.join(self.test_tgt, 'Kconfig')
|
||||
self.test = os.path.join(self.test_tgt, 'kunit_test')
|
||||
self.test_mkfile = os.path.join(self.test, 'Makefile')
|
||||
self.test_driver = os.path.join(self.test, 'qbt2000_common_test.c')
|
||||
self.test_driver2 = os.path.join(self.test, 'fingerprint_sysfs_test.c')
|
||||
|
||||
def tearDown(self):
|
||||
remove_temp_test_data()
|
||||
|
||||
# 1. Test cases for 'fingerprint/qbt2000_common.c'
|
||||
def test_append_makefile_qbt2000_common(self):
|
||||
self.assertTrue(os.path.exists(self.mkfile))
|
||||
self.assertTrue(is_contain('obj-$(CONFIG_SEC_KUNIT)', self.mkfile))
|
||||
self.assertTrue(is_contain('kunit_test/', self.mkfile))
|
||||
self.assertTrue(is_contain('GCOV_PROFILE_qbt2000_common', self.mkfile))
|
||||
|
||||
def test_append_kconfig_qbt2000_common(self):
|
||||
self.assertTrue(os.path.exists(self.kconf))
|
||||
self.assertTrue(is_contain('config QBT2000_COMMON_TEST', self.kconf))
|
||||
|
||||
def test_mkdir_test(self):
|
||||
self.assertTrue(os.path.exists(self.test))
|
||||
|
||||
def test_gen_test_makefile_qbt2000_common(self):
|
||||
self.assertTrue(os.path.exists(self.test_mkfile))
|
||||
self.assertTrue(is_contain('CONFIG_SENSORS_QBT2000', self.test_mkfile))
|
||||
# CONFIG_SENSORS_QBT2000 should be in Makefile as well
|
||||
self.assertTrue(is_contain('CONFIG_SENSORS_QBT2000', self.mkfile))
|
||||
self.assertTrue(is_contain('CONFIG_QBT2000_COMMON_TEST', self.test_mkfile))
|
||||
self.assertTrue(is_contain('qbt2000_common_test.o', self.test_mkfile))
|
||||
|
||||
def test_gen_test_driver_qbt2000_common(self):
|
||||
self.assertTrue(os.path.exists(self.test_driver))
|
||||
self.assertTrue(is_contain('module_test(qbt2000_common_test_module)', self.test_driver))
|
||||
|
||||
# 2. Test cases for additional inserted 'fingerprint/fingerprint_sysfs.c'
|
||||
def test_append_makefile_fingerprint_sysfs(self):
|
||||
check_str = 'GCOV_PROFILE_fingerprint_sysfs'
|
||||
check_str_test = '+= kunit_test/'
|
||||
self.assertTrue(os.path.exists(self.mkfile))
|
||||
self.assertTrue(is_contain(check_str, self.mkfile))
|
||||
# Must have only one '+= kunit_test/' in Makefile
|
||||
self.assertEqual(how_many_contains(check_str, self.mkfile), 1)
|
||||
self.assertEqual(how_many_contains(check_str_test, self.mkfile), 1)
|
||||
|
||||
def test_append_kconfig_fingerprint_sysfs(self):
|
||||
self.assertTrue(is_contain('config FINGERPRINT_SYSFS_TEST', self.kconf))
|
||||
|
||||
def test_gen_test_makefile_fingerprint_sysfs(self):
|
||||
self.assertTrue(is_contain('CONFIG_FINGERPRINT_SYSFS_TEST', self.test_mkfile))
|
||||
self.assertTrue(is_contain('fingerprint_sysfs_test.o', self.test_mkfile))
|
||||
|
||||
def test_gen_test_driver_fingerprint_sysfs(self):
|
||||
self.assertTrue(os.path.exists(self.test_driver2))
|
||||
self.assertTrue(is_contain('module_test(fingerprint_sysfs_test_module)', self.test_driver2))
|
||||
|
||||
|
||||
class TestConstruntionTemplate(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.test_path, self.test_tgt = generate_test_data(test_list[0])
|
||||
self.tgt_driver = os.path.join(self.test_tgt, 'qbt2000_common.c')
|
||||
self.mkfile = os.path.join(self.test_tgt, 'Makefile')
|
||||
self.kconf = os.path.join(self.test_tgt, 'Kconfig')
|
||||
self.test = os.path.join(self.test_tgt, 'kunit_test')
|
||||
self.test_mkfile = os.path.join(self.test, 'Makefile')
|
||||
self.test_driver = os.path.join(self.test, 'qbt2000_common_test.c')
|
||||
self.af = TestConstructor(self.tgt_driver)
|
||||
|
||||
def tearDown(self):
|
||||
remove_temp_test_data()
|
||||
|
||||
def test_append_makefile(self):
|
||||
self.af.append_makefile()
|
||||
self.assertTrue(os.path.exists(self.mkfile))
|
||||
self.assertTrue(is_contain('obj-$(CONFIG_SEC_KUNIT)', self.mkfile))
|
||||
self.assertTrue(is_contain('kunit_test/', self.mkfile))
|
||||
self.assertTrue(is_contain('GCOV_PROFILE_qbt2000_common', self.mkfile))
|
||||
|
||||
def test_append_kconfig(self):
|
||||
self.af.append_kconfig()
|
||||
self.assertTrue(os.path.exists(self.kconf))
|
||||
self.assertTrue(is_contain('config QBT2000_COMMON_TEST', self.kconf))
|
||||
self.assertTrue(is_contain('depends on SEC_KUNIT', self.kconf))
|
||||
|
||||
def test_mkdir_test(self):
|
||||
self.assertTrue(os.path.exists(self.test))
|
||||
|
||||
def test_gen_test_makefile(self):
|
||||
self.af.write_test_makefile()
|
||||
self.assertTrue(os.path.exists(self.test_mkfile))
|
||||
self.assertTrue(is_contain('CONFIG_SENSORS_QBT2000', self.test_mkfile))
|
||||
# CONFIG_SENSORS_QBT2000 should be in Makefile as well
|
||||
self.assertTrue(is_contain('CONFIG_SENSORS_QBT2000', self.mkfile))
|
||||
self.assertTrue(is_contain('CONFIG_QBT2000_COMMON_TEST', self.test_mkfile))
|
||||
self.assertTrue(is_contain('qbt2000_common_test.o', self.test_mkfile))
|
||||
|
||||
def test_gen_test_driver(self):
|
||||
self.af.write_test_driver()
|
||||
self.assertTrue(os.path.exists(self.test_driver))
|
||||
self.assertTrue(is_contain('module_test(qbt2000_common_test_module)', self.test_driver))
|
||||
self.assertTrue(is_contain('include <kunit/test.h>', self.test_driver))
|
||||
|
||||
class TestConfigExtractor(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.test_path, self.test_tgt = generate_test_data(test_list[0])
|
||||
self.tgt_driver1 = os.path.join(self.test_tgt, 'qbt2000_common.c')
|
||||
self.tgt_driver2 = os.path.join(self.test_tgt, 'fingerprint_sysfs.c')
|
||||
|
||||
def tearDown(self):
|
||||
remove_temp_test_data()
|
||||
|
||||
def test_gen_tmplt(self):
|
||||
tmplt = TemplateGenerator(self.test_path)
|
||||
#print(tmplt.get_testfile())
|
||||
#print(tmplt.get_kconfig())
|
||||
#print(tmplt.get_makefile())
|
||||
|
||||
def test_get_config(self):
|
||||
c = ConfigNameExtractor(self.tgt_driver1)
|
||||
self.assertEqual('CONFIG_SENSORS_QBT2000', c.result)
|
||||
|
||||
def test_get_config2(self):
|
||||
c = ConfigNameExtractor(self.tgt_driver2)
|
||||
self.assertEqual('CONFIG_SENSORS_FINGERPRINT', c.result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
73
tools/testing/kunit/insert_kunit/kunit_new_template.py
Normal file
73
tools/testing/kunit/insert_kunit/kunit_new_template.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
import os
|
||||
import string
|
||||
|
||||
TEMPLATE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
TEST_TEMPLATE_PATH = os.path.join(TEMPLATE_DIR, 'test_template.c')
|
||||
KCONFIG_TEMPLATE_PATH = os.path.join(TEMPLATE_DIR, 'test_template.Kconfig')
|
||||
MAKEFILE_TEMPLATE_PATH = os.path.join(TEMPLATE_DIR, 'test_template.Makefile')
|
||||
|
||||
def create_skeleton_from_template(template_path, test_prefix, test_object_file):
|
||||
with open(template_path, 'r') as f:
|
||||
return string.Template(f.read()).safe_substitute(
|
||||
test_prefix=test_prefix,
|
||||
caps_test_prefix=test_prefix.upper(),
|
||||
test_object_file=test_object_file)
|
||||
|
||||
def create_kconfig_from_template(template_path, file_name, test_prefix):
|
||||
with open(template_path, 'r') as f:
|
||||
return string.Template(f.read()).safe_substitute(
|
||||
file_name=file_name,
|
||||
test_prefix=test_prefix,
|
||||
caps_test_prefix=test_prefix.upper())
|
||||
|
||||
class Skeletons(object):
|
||||
"""
|
||||
Represents the KUnit skeletons for a test, Kconfig entry, and Makefile
|
||||
entry.
|
||||
"""
|
||||
def __init__(self, test_skeleton, kconfig_skeleton, makefile_skeleton):
|
||||
self.test_skeleton = test_skeleton
|
||||
self.kconfig_skeleton = kconfig_skeleton
|
||||
self.makefile_skeleton = makefile_skeleton
|
||||
|
||||
|
||||
def create_skeletons(file_name, namespace_prefix, test_object_file):
|
||||
test_prefix = namespace_prefix + '_test'
|
||||
return Skeletons(
|
||||
test_skeleton=create_skeleton_from_template(
|
||||
TEST_TEMPLATE_PATH,
|
||||
test_prefix,
|
||||
test_object_file),
|
||||
kconfig_skeleton=create_kconfig_from_template(
|
||||
KCONFIG_TEMPLATE_PATH,
|
||||
file_name,
|
||||
test_prefix),
|
||||
makefile_skeleton=create_skeleton_from_template(
|
||||
MAKEFILE_TEMPLATE_PATH,
|
||||
test_prefix,
|
||||
test_object_file)
|
||||
)
|
||||
|
||||
def namespace_prefix_from_path(path):
|
||||
file_name = os.path.basename(path)
|
||||
return os.path.splitext(file_name)
|
||||
|
||||
def create_skeletons_from_path(path, namespace_prefix=None, print_test_only=False):
|
||||
dir_name, file_name = os.path.split(path)
|
||||
file_prefix, _ = os.path.splitext(file_name)
|
||||
test_path = os.path.join(dir_name, file_prefix + '-test.c')
|
||||
test_object_file = file_prefix + '-test.o'
|
||||
if not namespace_prefix:
|
||||
namespace_prefix = file_prefix.replace('-', '_')
|
||||
skeletons = create_skeletons(file_name, namespace_prefix, test_object_file)
|
||||
print('### In ' + test_path)
|
||||
print(skeletons.test_skeleton)
|
||||
if print_test_only:
|
||||
return
|
||||
print('### In Kconfig')
|
||||
print(skeletons.kconfig_skeleton)
|
||||
print('### In Makefile')
|
||||
print(skeletons.makefile_skeleton)
|
||||
|
16
tools/testing/kunit/insert_kunit/test_template.Kconfig
Executable file
16
tools/testing/kunit/insert_kunit/test_template.Kconfig
Executable file
@@ -0,0 +1,16 @@
|
||||
config ${caps_test_prefix}_FOR_ON_DEVICE
|
||||
tristate "KUnit test for ${test_prefix}"
|
||||
depends on SEC_KUNIT
|
||||
depends on <write CONFIG for building target driver, ${file_name}>
|
||||
help
|
||||
TODO: Describe config fully.
|
||||
If you run this test driver on device, SHOULD set this config as 'm' to build test driver modulraly.
|
||||
|
||||
config ${caps_test_prefix}_FOR_ONLY_UML
|
||||
tristate "KUnit test for ${test_prefix}"
|
||||
depends on SEC_KUNIT
|
||||
depends on UML
|
||||
depends on <write CONFIG for building target driver, ${file_name}>
|
||||
help
|
||||
TODO: Describe config fully.
|
||||
This CONFIG is recommended to set to y.
|
1
tools/testing/kunit/insert_kunit/test_template.Makefile
Normal file
1
tools/testing/kunit/insert_kunit/test_template.Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_${caps_test_prefix}) += ${test_object_file}
|
113
tools/testing/kunit/insert_kunit/test_template.c
Executable file
113
tools/testing/kunit/insert_kunit/test_template.c
Executable file
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* TODO: Add test description.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/mock.h>
|
||||
|
||||
/*
|
||||
* This is the most fundamental element of KUnit, the test case. A test case
|
||||
* makes a set EXPECTATIONs and ASSERTIONs about the behavior of some code; if
|
||||
* any expectations or assertions are not met, the test fails; otherwise, the
|
||||
* test passes.
|
||||
*
|
||||
* In KUnit, a test case is just a function with the signature
|
||||
* `void (*)(struct kunit *)`. `struct kunit` is a context object that stores
|
||||
* information about the current test.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_UML
|
||||
/* NOTE: UML TC */
|
||||
static void ${test_prefix}_bar(struct kunit *test)
|
||||
{
|
||||
/* Test cases for UML */
|
||||
KUNIT_EXPECT_EQ(test, 1, 1); // Pass
|
||||
}
|
||||
#else
|
||||
/* NOTE: Target running TC must be in the #ifndef CONFIG_UML */
|
||||
static void ${test_prefix}_foo(struct kunit *test)
|
||||
{
|
||||
/*
|
||||
* This is an EXPECTATION; it is how KUnit tests things. When you want
|
||||
* to test a piece of code, you set some expectations about what the
|
||||
* code should do. KUnit then runs the test and verifies that the code's
|
||||
* behavior matched what was expected.
|
||||
*/
|
||||
KUNIT_EXPECT_EQ(test, 1, 2); // Obvious failure.
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is run once before each test case, see the comment on
|
||||
* example_test_module for more information.
|
||||
*/
|
||||
static int ${test_prefix}_init(struct kunit *test)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is run once after each test case, see the comment on example_test_module
|
||||
* for more information.
|
||||
*/
|
||||
static void ${test_prefix}_exit(struct kunit *test)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we make a list of all the test cases we want to add to the test module
|
||||
* below.
|
||||
*/
|
||||
static struct kunit_case ${test_prefix}_cases[] = {
|
||||
/*
|
||||
* This is a helper to create a test case object from a test case
|
||||
* function; its exact function is not important to understand how to
|
||||
* use KUnit, just know that this is how you associate test cases with a
|
||||
* test module.
|
||||
*/
|
||||
#ifdef CONFIG_UML
|
||||
/* NOTE: UML TC */
|
||||
KUNIT_CASE(${test_prefix}_bar),
|
||||
#else
|
||||
/* NOTE: Target running TC */
|
||||
KUNIT_CASE(${test_prefix}_foo),
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
||||
/*
|
||||
* This defines a suite or grouping of tests.
|
||||
*
|
||||
* Test cases are defined as belonging to the suite by adding them to
|
||||
* `test_cases`.
|
||||
*
|
||||
* Often it is desirable to run some function which will set up things which
|
||||
* will be used by every test; this is accomplished with an `init` function
|
||||
* which runs before each test case is invoked. Similarly, an `exit` function
|
||||
* may be specified which runs after every test case and can be used to for
|
||||
* cleanup. For clarity, running tests in a test module would behave as follows:
|
||||
*
|
||||
* module.init(test);
|
||||
* module.test_case[0](test);
|
||||
* module.exit(test);
|
||||
* module.init(test);
|
||||
* module.test_case[1](test);
|
||||
* module.exit(test);
|
||||
* ...;
|
||||
*/
|
||||
struct kunit_suite ${test_prefix}_module = {
|
||||
.name = "${test_prefix}",
|
||||
.init = ${test_prefix}_init,
|
||||
.exit = ${test_prefix}_exit,
|
||||
.test_cases = ${test_prefix}_cases,
|
||||
};
|
||||
EXPORT_SYMBOL_KUNIT(${test_prefix}_module);
|
||||
|
||||
/*
|
||||
* This registers the above test module telling KUnit that this is a suite of
|
||||
* tests that need to be run.
|
||||
*/
|
||||
kunit_test_suites(&${test_prefix}_module);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -258,13 +258,16 @@ def parse_tests(request: KunitParseRequest, metadata: kunit_json.Metadata, input
|
||||
return KunitResult(KunitStatus.SUCCESS, parse_time), test
|
||||
|
||||
def run_tests(linux: kunit_kernel.LinuxSourceTree,
|
||||
request: KunitRequest) -> KunitResult:
|
||||
request: KunitRequest, cli_args) -> KunitResult:
|
||||
run_start = time.time()
|
||||
|
||||
config_result = config_tests(linux, request)
|
||||
if config_result.status != KunitStatus.SUCCESS:
|
||||
return config_result
|
||||
|
||||
linux.add_external_config(cli_args.external_config)
|
||||
linux.update_config(cli_args.build_dir, cli_args.make_options)
|
||||
|
||||
build_result = build_tests(linux, request)
|
||||
if build_result.status != KunitStatus.SUCCESS:
|
||||
return build_result
|
||||
@@ -413,7 +416,9 @@ def add_parse_opts(parser: argparse.ArgumentParser) -> None:
|
||||
help='Prints parsed test results as JSON to stdout or a file if '
|
||||
'a filename is specified. Does nothing if --raw_output is set.',
|
||||
type=str, const='stdout', default=None, metavar='FILE')
|
||||
|
||||
parser.add_argument('-t', '--external_config', nargs='+',
|
||||
help='run kunit with a specific target kunitconfig',
|
||||
type=str)
|
||||
|
||||
def tree_from_args(cli_args: argparse.Namespace) -> kunit_kernel.LinuxSourceTree:
|
||||
"""Returns a LinuxSourceTree based on the user's arguments."""
|
||||
@@ -456,7 +461,7 @@ def run_handler(cli_args: argparse.Namespace) -> None:
|
||||
run_isolated=cli_args.run_isolated,
|
||||
list_tests=cli_args.list_tests,
|
||||
list_tests_attr=cli_args.list_tests_attr)
|
||||
result = run_tests(linux, request)
|
||||
result = run_tests(linux, request, cli_args)
|
||||
if result.status != KunitStatus.SUCCESS:
|
||||
sys.exit(1)
|
||||
|
||||
|
@@ -49,6 +49,11 @@ class Kconfig:
|
||||
def add_entry(self, name: str, value: str) -> None:
|
||||
self._entries[name] = value
|
||||
|
||||
def remove_entry(self, entry_set) -> None:
|
||||
for entry in entry_set:
|
||||
print(f"Remove invalid config: {str(entry)}")
|
||||
self._entries.pop(entry.name, None)
|
||||
|
||||
def is_subset_of(self, other: 'Kconfig') -> bool:
|
||||
for name, value in self._entries.items():
|
||||
b = other._entries.get(name)
|
||||
|
@@ -11,6 +11,7 @@ import importlib.util
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
import glob
|
||||
import shlex
|
||||
import shutil
|
||||
import signal
|
||||
@@ -31,6 +32,8 @@ OUTFILE_PATH = 'test.log'
|
||||
ABS_TOOL_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
QEMU_CONFIGS_DIR = os.path.join(ABS_TOOL_PATH, 'qemu_configs')
|
||||
|
||||
DEFAULT_SUBMODULE_KUNITCONFIG_PATH = 'kunitconfigs'
|
||||
PREFIX_SUBMODULE_FILE = 'kunitconfig.'
|
||||
class ConfigError(Exception):
|
||||
"""Represents an error trying to configure the Linux kernel."""
|
||||
|
||||
@@ -223,6 +226,18 @@ def _get_qemu_ops(config_path: str,
|
||||
return params.linux_arch, LinuxSourceTreeOperationsQemu(
|
||||
params, cross_compile=cross_compile)
|
||||
|
||||
def get_submodule_kunitconfig_path(name):
|
||||
return os.path.join(DEFAULT_SUBMODULE_KUNITCONFIG_PATH, PREFIX_SUBMODULE_FILE + '%s' %name)
|
||||
|
||||
def get_sub_config(name):
|
||||
submodule_kunitconfig = get_submodule_kunitconfig_path(name)
|
||||
group_submodule_kunitconfig = glob.glob(submodule_kunitconfig + '*')
|
||||
|
||||
if not group_submodule_kunitconfig:
|
||||
return [os.path.join('.', name)]
|
||||
else:
|
||||
return group_submodule_kunitconfig
|
||||
|
||||
class LinuxSourceTree:
|
||||
"""Represents a Linux kernel source tree with KUnit tests."""
|
||||
|
||||
@@ -277,7 +292,45 @@ class LinuxSourceTree:
|
||||
logging.error(message)
|
||||
return False
|
||||
|
||||
def build_config(self, build_dir: str, make_options: Optional[List[str]]) -> bool:
|
||||
def add_external_config(self, ex_config):
|
||||
print("-------- Add External configs ----------")
|
||||
if not ex_config:
|
||||
logging.warning("No external config!")
|
||||
return
|
||||
for module in ex_config:
|
||||
module_configs = get_sub_config(module)
|
||||
for config in module_configs:
|
||||
if not os.path.exists(config):
|
||||
logging.error("Couldn't find kunitconfigs/kunitconfig.%s file" %module)
|
||||
continue;
|
||||
additional_config = kunit_config.parse_file(config)
|
||||
print(additional_config)
|
||||
self._kconfig.merge_in_entries(additional_config)
|
||||
print("-------- External configs are added ----------")
|
||||
|
||||
def update_config(self, build_dir, make_options):
|
||||
kconfig_path = get_kconfig_path(build_dir)
|
||||
if build_dir and not os.path.exists(build_dir):
|
||||
os.mkdir(build_dir)
|
||||
try:
|
||||
self._kconfig.write_to_file(kconfig_path)
|
||||
self._ops.make_olddefconfig(build_dir, make_options)
|
||||
except ConfigError as e:
|
||||
logging.error(e)
|
||||
return False
|
||||
|
||||
validated_kconfig = kunit_config.parse_file(kconfig_path)
|
||||
if self._kconfig.is_subset_of(validated_kconfig):
|
||||
return True
|
||||
missing = set(self._kconfig.as_entries()) - set(validated_kconfig.as_entries())
|
||||
message = 'Not all Kconfig options selected in kunitconfig were in the generated .config.\n' \
|
||||
'This is probably due to unsatisfied dependencies. Please double check dependencies of below configs.\n' \
|
||||
'Missing: ' + ', '.join(str(e) for e in missing)
|
||||
logging.warning(message)
|
||||
self._kconfig.remove_entry(missing)
|
||||
return True
|
||||
|
||||
def build_config(self, build_dir: str, make_options) -> bool:
|
||||
kconfig_path = get_kconfig_path(build_dir)
|
||||
if build_dir and not os.path.exists(build_dir):
|
||||
os.mkdir(build_dir)
|
||||
|
Reference in New Issue
Block a user