Add samsung specific changes

This commit is contained in:
2025-08-11 14:29:00 +02:00
parent c66122e619
commit 4d134a1294
2688 changed files with 1127995 additions and 11475 deletions

View File

@@ -1,3 +1,3 @@
CONFIG_KUNIT=y
CONFIG_KUNIT_EXAMPLE_TEST=y
CONFIG_KUNIT_ALL_TESTS=y
CONFIG_SEC_KUNIT=y
CONFIG_OF=y

View 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()

View 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()

View 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)

View 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.

View File

@@ -0,0 +1 @@
obj-$(CONFIG_${caps_test_prefix}) += ${test_object_file}

View 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");

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)