Skip to content

Commit 243180f

Browse files
dlatypovshuahkh
authored andcommitted
kunit: make kunit_tool accept optional path to .kunitconfig fragment
Currently running tests via KUnit tool means tweaking a .kunitconfig file, which you'd keep around locally and never commit. This changes makes it so users can pass in a path to a kunitconfig. One of the imagined use cases is having kunitconfig fragments in-tree to formalize interesting sets of tests for features/subsystems, e.g. $ ./tools/testing/kunit/kunit.py run --kunticonfig=fs/ext4/kunitconfig For now, this hypothetical fs/ext4/kunitconfig would contain CONFIG_KUNIT=y CONFIG_EXT4_FS=y CONFIG_EXT4_KUNIT_TESTS=y At the moment, it's not hard to manually whip up this file, but as more and more tests get added, this will get tedious. It also opens the door to documenting how to run all the tests relevant to a specific subsystem or feature as a simple one-liner. This can be seen as an analogue to tools/testing/selftests/*/config But in the case of KUnit, the tests live in the same directory as the code-under-test, so it feels more natural to allow the kunitconfig fragments to live anywhere. (Though, people could create a separate directory if wanted; this patch imposes no restrictions on the path). Signed-off-by: Daniel Latypov <[email protected]> Reviewed-by: Brendan Higgins <[email protected]> Tested-by: Brendan Higgins <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent 7c2b108 commit 243180f

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

tools/testing/kunit/kunit.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ def add_common_opts(parser) -> None:
182182
parser.add_argument('--alltests',
183183
help='Run all KUnit tests through allyesconfig',
184184
action='store_true')
185+
parser.add_argument('--kunitconfig',
186+
help='Path to Kconfig fragment that enables KUnit tests',
187+
metavar='kunitconfig')
185188

186189
def add_build_opts(parser) -> None:
187190
parser.add_argument('--jobs',
@@ -256,7 +259,7 @@ def main(argv, linux=None):
256259
os.mkdir(cli_args.build_dir)
257260

258261
if not linux:
259-
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
262+
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig)
260263

261264
request = KunitRequest(cli_args.raw_output,
262265
cli_args.timeout,
@@ -274,7 +277,7 @@ def main(argv, linux=None):
274277
os.mkdir(cli_args.build_dir)
275278

276279
if not linux:
277-
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
280+
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig)
278281

279282
request = KunitConfigRequest(cli_args.build_dir,
280283
cli_args.make_options)
@@ -286,7 +289,7 @@ def main(argv, linux=None):
286289
sys.exit(1)
287290
elif cli_args.subcommand == 'build':
288291
if not linux:
289-
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir)
292+
linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig)
290293

291294
request = KunitBuildRequest(cli_args.jobs,
292295
cli_args.build_dir,

tools/testing/kunit/kunit_kernel.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,21 @@ def get_outfile_path(build_dir) -> str:
123123
class LinuxSourceTree(object):
124124
"""Represents a Linux kernel source tree with KUnit tests."""
125125

126-
def __init__(self, build_dir: str, load_config=True, defconfig=DEFAULT_KUNITCONFIG_PATH) -> None:
126+
def __init__(self, build_dir: str, load_config=True, kunitconfig_path='') -> None:
127127
signal.signal(signal.SIGINT, self.signal_handler)
128128

129129
self._ops = LinuxSourceTreeOperations()
130130

131131
if not load_config:
132132
return
133133

134-
kunitconfig_path = get_kunitconfig_path(build_dir)
135-
if not os.path.exists(kunitconfig_path):
136-
shutil.copyfile(defconfig, kunitconfig_path)
134+
if kunitconfig_path:
135+
if not os.path.exists(kunitconfig_path):
136+
raise ConfigError(f'Specified kunitconfig ({kunitconfig_path}) does not exist')
137+
else:
138+
kunitconfig_path = get_kunitconfig_path(build_dir)
139+
if not os.path.exists(kunitconfig_path):
140+
shutil.copyfile(DEFAULT_KUNITCONFIG_PATH, kunitconfig_path)
137141

138142
self._kconfig = kunit_config.Kconfig()
139143
self._kconfig.read_from_file(kunitconfig_path)

tools/testing/kunit/kunit_tool_test.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import tempfile, shutil # Handling test_tmpdir
1313

1414
import json
15+
import signal
1516
import os
1617

1718
import kunit_config
@@ -236,6 +237,23 @@ def test_pound_no_prefix(self):
236237
result.status)
237238
self.assertEqual('kunit-resource-test', result.suites[0].name)
238239

240+
class LinuxSourceTreeTest(unittest.TestCase):
241+
242+
def setUp(self):
243+
mock.patch.object(signal, 'signal').start()
244+
self.addCleanup(mock.patch.stopall)
245+
246+
def test_invalid_kunitconfig(self):
247+
with self.assertRaisesRegex(kunit_kernel.ConfigError, 'nonexistent.* does not exist'):
248+
kunit_kernel.LinuxSourceTree('', kunitconfig_path='/nonexistent_file')
249+
250+
def test_valid_kunitconfig(self):
251+
with tempfile.NamedTemporaryFile('wt') as kunitconfig:
252+
tree = kunit_kernel.LinuxSourceTree('', kunitconfig_path=kunitconfig.name)
253+
254+
# TODO: add more test cases.
255+
256+
239257
class KUnitJsonTest(unittest.TestCase):
240258

241259
def _json_for(self, log_file):
@@ -378,5 +396,19 @@ def test_exec_builddir(self):
378396
self.linux_source_mock.run_kernel.assert_called_once_with(build_dir=build_dir, timeout=300)
379397
self.print_mock.assert_any_call(StrContains('Testing complete.'))
380398

399+
@mock.patch.object(kunit_kernel, 'LinuxSourceTree')
400+
def test_run_kunitconfig(self, mock_linux_init):
401+
mock_linux_init.return_value = self.linux_source_mock
402+
kunit.main(['run', '--kunitconfig=mykunitconfig'])
403+
# Just verify that we parsed and initialized it correctly here.
404+
mock_linux_init.assert_called_once_with('.kunit', kunitconfig_path='mykunitconfig')
405+
406+
@mock.patch.object(kunit_kernel, 'LinuxSourceTree')
407+
def test_config_kunitconfig(self, mock_linux_init):
408+
mock_linux_init.return_value = self.linux_source_mock
409+
kunit.main(['config', '--kunitconfig=mykunitconfig'])
410+
# Just verify that we parsed and initialized it correctly here.
411+
mock_linux_init.assert_called_once_with('.kunit', kunitconfig_path='mykunitconfig')
412+
381413
if __name__ == '__main__':
382414
unittest.main()

0 commit comments

Comments
 (0)