Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp1438229pxb; Fri, 22 Jan 2021 16:19:58 -0800 (PST) X-Google-Smtp-Source: ABdhPJyP6VIeXQVPSgC2JRvshuUOj2hMYtoMtu9ZgG6/DLZOkTN25y96gt9HDAy0ceuh9BtvkBB3 X-Received: by 2002:a05:6402:2346:: with SMTP id r6mr5283069eda.8.1611361198558; Fri, 22 Jan 2021 16:19:58 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1611361198; cv=none; d=google.com; s=arc-20160816; b=fgloUCvzoIvLykD+/r5ltzL6dsLrfYrY0lPkVFZ7LfvIRhd+F2+gQd7/OObjYTxT/P lmNkdCaq4EGhEndxMLRpvLHJiubzJEW7Vt8rGWy8Z04no2WLSwgcjHDFzty++qmITbeI a6QsXcQ+tKDH0t2d2VBp9yR21Y6f+1Zq2dZp334/bQ/YxyUhIqeZ3PzzzXO9r4QbiYN3 fDwvhNCPn1MkFH1Xs8xfsSts20g01zIY6U8iBjAO+VPFrO5HnU1EgUHD9DUs2j0FT3cX bXpV+/HyIs/PW2aQ+3JwNIej0LqkJKTKedd10RCr5EobUT/fnc1HVAJSlkTSM1Ot1Vo7 Pklg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:mime-version:message-id:date :sender:dkim-signature; bh=j2yVLSeKVflthIG8vtivuEcuH5FNLO2jKklVbyIHSEo=; b=fuyyXjD8Nu1XcJ6aF3dwk0/9mqRzSG3NdNVfDkg0HV2ReXKZLJrPVhvN+ro88ftNrT bnbU4IfpJVZm0ySzzujd8VrOsWr/L5yjorVJk2L5pzgAQzJ1GdiDhmZmTuBMaoqrEync kcPY3bTbj9x1N62wAUQJkeMUbn7RaqwQMABhMZNErOfyql8+4PjOt42U+Py2ervWs2EL Vjqqvew/rIGzJxWyGvMKDIw5Hzbai3I4WzM13BmCZ2PWf+BGCAM0BuMP76mEZWwO6PhX U0B4q93Vlgyt0wTQ6BZMEbxbH2PQxjKdGg2u9qg6c2FbTbVkCJUQwWNrVvWms9t1bbTH qn8w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=RQKykWkf; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id n10si3573281eja.493.2021.01.22.16.19.34; Fri, 22 Jan 2021 16:19:58 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=RQKykWkf; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726529AbhAWAS4 (ORCPT + 99 others); Fri, 22 Jan 2021 19:18:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726754AbhAWASk (ORCPT ); Fri, 22 Jan 2021 19:18:40 -0500 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DA772C0613D6 for ; Fri, 22 Jan 2021 16:17:56 -0800 (PST) Received: by mail-yb1-xb49.google.com with SMTP id s7so7189152ybj.0 for ; Fri, 22 Jan 2021 16:17:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:message-id:mime-version:subject:from:to:cc; bh=j2yVLSeKVflthIG8vtivuEcuH5FNLO2jKklVbyIHSEo=; b=RQKykWkfNrzebKlEf7vc0c2jTc87fR03Qa7ac2jOOXolc7+hOLWIc2n0BYqjXSvns8 Bcik0sPBVZO8G7Pgy6WelJSbnUhx5+/MITfj10+rvFRTJgRJY8gwi7m1a8T1c4tJdWQS Ihe+BXo3bpr4vpXKvy5vOrE+wKBfhcZK4JDxTrwaFsrAyYQq/sM+WPLGDfCLP6kZiytv oACsgVJySnR7sRfz+oGjhHLBNTO3HXSz0SwBxUUEkixTLNey89HgFQqiIr/pBd+BcLO5 XWKX78CpIkb9qbzYmwKt9sKMNXUKKh60Hk5U8wGdyk+Gl8KR2si2NlAS+agdJUovw9NC QpDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:message-id:mime-version:subject:from :to:cc; bh=j2yVLSeKVflthIG8vtivuEcuH5FNLO2jKklVbyIHSEo=; b=Ye20qM8MBgZtHge7XlsW0XbkrE8cl/TRnkKY8Lj9di435+4eA/Lp5NEK4OTEjqETUG OllJiHvUJS1E3D8bNB8muZjQYVIeYETRUz8pOxST2Y29W2roncJIWWSGeCqcLBC3mDVz TLhMLPcckMGO8xKdQ4d7SplDoTSIkfCXSKcigEAJ47zUjrRbMZ2kVKIQ9ZqkL1WaGZSG oSQyD3YsFFpg2Sq2Hit1biWqi5go1gszkORWc0BRf0w0Z7v9QUhEZGpDdVSJAXkDNLBx 7Zbcwby28oYykkqNIea7YRVU6C5x9z/i/zd5AqBYoJYpj4P2kP8b3Pd+kYGdQeDxQyAj 8Xcw== X-Gm-Message-State: AOAM532kBVZEq4uW5IZ0sdhoAAGWbT9Ptf+V21RyV6FeL5Cf4X8gsKBX 1hwj46IOtpu585YAanA9MRr8PCKdDaFcow== Sender: "dlatypov via sendgmr" X-Received: from dlatypov.svl.corp.google.com ([2620:15c:2cd:202:a28c:fdff:fee3:28c6]) (user=dlatypov job=sendgmr) by 2002:a25:2941:: with SMTP id p62mr5891729ybp.26.1611361076091; Fri, 22 Jan 2021 16:17:56 -0800 (PST) Date: Fri, 22 Jan 2021 16:17:43 -0800 Message-Id: <20210123001743.1379894-1-dlatypov@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.30.0.280.ga3ce27912f-goog Subject: [PATCH] kunit: make kunit_tool accept optional path to .kunitconfig fragment From: Daniel Latypov To: brendanhiggins@google.com, davidgow@google.com Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, skhan@linuxfoundation.org, Daniel Latypov Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 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 --- tools/testing/kunit/kunit.py | 9 ++++++--- tools/testing/kunit/kunit_kernel.py | 12 ++++++++---- tools/testing/kunit/kunit_tool_test.py | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py index e808a47c839b..3204a23bd16e 100755 --- a/tools/testing/kunit/kunit.py +++ b/tools/testing/kunit/kunit.py @@ -188,6 +188,9 @@ def add_build_opts(parser) -> None: help='As in the make command, "Specifies the number of ' 'jobs (commands) to run simultaneously."', type=int, default=8, metavar='jobs') + parser.add_argument('kunitconfig', + help='Path to Kconfig fragment that enables KUnit tests', + type=str, nargs='?', metavar='kunitconfig') def add_exec_opts(parser) -> None: parser.add_argument('--timeout', @@ -256,7 +259,7 @@ def main(argv, linux=None): os.mkdir(cli_args.build_dir) if not linux: - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir) + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) request = KunitRequest(cli_args.raw_output, cli_args.timeout, @@ -274,7 +277,7 @@ def main(argv, linux=None): os.mkdir(cli_args.build_dir) if not linux: - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir) + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) request = KunitConfigRequest(cli_args.build_dir, cli_args.make_options) @@ -286,7 +289,7 @@ def main(argv, linux=None): sys.exit(1) elif cli_args.subcommand == 'build': if not linux: - linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir) + linux = kunit_kernel.LinuxSourceTree(cli_args.build_dir, kunitconfig_path=cli_args.kunitconfig) request = KunitBuildRequest(cli_args.jobs, cli_args.build_dir, diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py index 2076a5a2d060..0b461663e7d9 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -123,7 +123,7 @@ def get_outfile_path(build_dir) -> str: class LinuxSourceTree(object): """Represents a Linux kernel source tree with KUnit tests.""" - def __init__(self, build_dir: str, load_config=True, defconfig=DEFAULT_KUNITCONFIG_PATH) -> None: + def __init__(self, build_dir: str, load_config=True, kunitconfig_path='') -> None: signal.signal(signal.SIGINT, self.signal_handler) self._ops = LinuxSourceTreeOperations() @@ -131,9 +131,13 @@ class LinuxSourceTree(object): if not load_config: return - kunitconfig_path = get_kunitconfig_path(build_dir) - if not os.path.exists(kunitconfig_path): - shutil.copyfile(defconfig, kunitconfig_path) + if kunitconfig_path: + if not os.path.exists(kunitconfig_path): + raise ConfigError(f'Specified kunitconfig ({kunitconfig_path}) does not exist') + else: + kunitconfig_path = get_kunitconfig_path(build_dir) + if not os.path.exists(kunitconfig_path): + shutil.copyfile(DEFAULT_KUNITCONFIG_PATH, kunitconfig_path) self._kconfig = kunit_config.Kconfig() self._kconfig.read_from_file(kunitconfig_path) diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py index b593f4448e83..533fe41b5123 100755 --- a/tools/testing/kunit/kunit_tool_test.py +++ b/tools/testing/kunit/kunit_tool_test.py @@ -12,6 +12,7 @@ from unittest import mock import tempfile, shutil # Handling test_tmpdir import json +import signal import os import kunit_config @@ -250,6 +251,23 @@ class KUnitParserTest(unittest.TestCase): result.status) self.assertEqual('kunit-resource-test', result.suites[0].name) +class LinuxSourceTreeTest(unittest.TestCase): + + def setUp(self): + mock.patch.object(signal, 'signal').start() + self.addCleanup(mock.patch.stopall) + + def test_invalid_kunitconfig(self): + with self.assertRaisesRegex(kunit_kernel.ConfigError, 'nonexistent.* does not exist'): + kunit_kernel.LinuxSourceTree('', kunitconfig_path='/nonexistent_file') + + def test_valid_kunitconfig(self): + with tempfile.NamedTemporaryFile('wt') as kunitconfig: + tree = kunit_kernel.LinuxSourceTree('', kunitconfig_path=kunitconfig.name) + + # TODO: add more test cases. + + class KUnitJsonTest(unittest.TestCase): def _json_for(self, log_file): @@ -399,5 +417,12 @@ class KUnitMainTest(unittest.TestCase): self.linux_source_mock.run_kernel.assert_called_once_with(build_dir=build_dir, timeout=300) self.print_mock.assert_any_call(StrContains('Testing complete.')) + @mock.patch.object(kunit_kernel, 'LinuxSourceTree') + def test_run_kunitconfig(self, mock_linux_init): + mock_linux_init.return_value = self.linux_source_mock + kunit.main(['run', 'mykunitconfig']) + # Just verify that we parsed and initialized it correctly here. + mock_linux_init.assert_called_once_with('.kunit', kunitconfig_path='mykunitconfig') + if __name__ == '__main__': unittest.main() base-commit: 2b8fdbbf1c616300312f71fe5b21fe8f03129950 -- 2.30.0.280.ga3ce27912f-goog