Linux Documentation
 help / color / mirror / Atom feed
From: Mark Brown <broonie@kernel.org>
To: Brendan Higgins <brendan.higgins@linux.dev>,
	 David Gow <david@davidgow.net>, Rae Moar <raemoar63@gmail.com>,
	 Shuah Khan <skhan@linuxfoundation.org>,
	 Daniel Latypov <dlatypov@google.com>,
	Jonathan Corbet <corbet@lwn.net>,
	 Randy Dunlap <rdunlap@infradead.org>
Cc: linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com,
	 linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
	 Mark Brown <broonie@kernel.org>
Subject: [PATCH 4/7] kunit: tool: Add an outfile argument to run_kernel()
Date: Tue, 13 Oct 2026 16:43:23 +0100	[thread overview]
Message-ID: <20261013-kunit-parallel-v1-4-f4be28c895e5@kernel.org> (raw)
In-Reply-To: <20261013-kunit-parallel-v1-0-f4be28c895e5@kernel.org>

run_kernel() always tees the kernel's console output to test.log in the
build directory. If more than one kernel were to be run at a time they
would all write to the same file, so allow the caller to choose where
the log goes with a new optional outfile argument.

Also teach get_outfile_path() to generate per-kernel log names of the
form test.<name>.log when given a name, for callers that need to keep
the logs of several kernels apart. Characters that are awkward in file
names, such as the '*' in a filter glob, are replaced with '_'.

Add a unit test covering the new argument.

Signed-off-by: Mark Brown <broonie@kernel.org>
---
 tools/testing/kunit/kunit_kernel.py    | 28 ++++++++++++++++++++++++----
 tools/testing/kunit/kunit_tool_test.py | 17 +++++++++++++++++
 2 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
index 58557c47d85f..2641db9eddba 100644
--- a/tools/testing/kunit/kunit_kernel.py
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -11,6 +11,7 @@ import importlib.util
 import logging
 import subprocess
 import os
+import re
 import shlex
 import shutil
 import signal
@@ -193,8 +194,19 @@ def get_parsed_kunitconfig(build_dir: str,
 		merged.merge_in_entries(partial)
 	return merged
 
-def get_outfile_path(build_dir: str) -> str:
-	return os.path.join(build_dir, OUTFILE_PATH)
+def get_outfile_path(build_dir: str, name: Optional[str]=None) -> str:
+	"""Returns the path of the kernel console log.
+
+	When several kernels are run each needs its own log, so `name` is
+	used to tell them apart, giving test.<name>.log. Characters that are
+	awkward in file names (anything other than letters, digits, '_', '-'
+	and '.') are replaced with '_'.
+	"""
+	if name is None:
+		return os.path.join(build_dir, OUTFILE_PATH)
+	base, ext = os.path.splitext(OUTFILE_PATH)
+	name = re.sub(r'[^\w.-]', '_', name)
+	return os.path.join(build_dir, f'{base}.{name}{ext}')
 
 def _default_qemu_config_path(arch: str) -> str:
 	config_path = os.path.join(QEMU_CONFIGS_DIR, arch + '.py')
@@ -352,7 +364,12 @@ class LinuxSourceTree:
 			return
 		subprocess.call(['stty', 'sane'])
 
-	def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]:
+	def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None, outfile: Optional[str]=None) -> Iterator[str]:
+		"""Boots the kernel and yields its console output line by line.
+
+		The output is also written to `outfile`, which defaults to
+		test.log in the build directory.
+		"""
 		# Copy to avoid mutating the caller-supplied list. exec_tests() reuses
 		# the same args across repeated run_kernel() calls (e.g. --run_isolated),
 		# so appending to the original would accumulate stale flags on each call.
@@ -365,6 +382,9 @@ class LinuxSourceTree:
 			args.append('kunit.filter_action=' + filter_action)
 		args.append('kunit.enable=1')
 
+		if outfile is None:
+			outfile = get_outfile_path(build_dir)
+
 		self._process = self._ops.start(args, build_dir)
 		assert self._process is not None # tell mypy it's set
 		assert self._process.stdout is not None  # tell mypy it's set
@@ -382,7 +402,7 @@ class LinuxSourceTree:
 		waiter = threading.Thread(target=_wait_proc)
 		waiter.start()
 
-		output = open(get_outfile_path(build_dir), 'w')
+		output = open(outfile, 'w')
 		try:
 			# Tee the output to the file and to our caller in real time.
 			for line in self._process.stdout:
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index 17f926ef2820..4e8068dce918 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -522,6 +522,23 @@ class LinuxSourceTreeTest(unittest.TestCase):
 			with open(kunit_kernel.get_outfile_path(build_dir), 'rt') as outfile:
 				self.assertEqual(outfile.read(), 'hi\nbye\n', msg='Missing some output')
 
+	def test_run_kernel_outfile(self):
+		"""Verify run_kernel() logs to the given outfile instead of test.log."""
+		def fake_start(unused_args, unused_build_dir):
+			return subprocess.Popen(['printf', 'hi\n'], text=True, stdout=subprocess.PIPE)
+
+		with tempfile.TemporaryDirectory('') as build_dir:
+			tree = kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=[os.devnull])
+			mock.patch.object(tree._ops, 'start', side_effect=fake_start).start()
+
+			# Awkward characters in the name are sanitised.
+			outfile = kunit_kernel.get_outfile_path(build_dir, 'my suite.test*')
+			self.assertEqual(outfile, os.path.join(build_dir, 'test.my_suite.test_.log'))
+			self.assertEqual(list(tree.run_kernel(build_dir=build_dir, outfile=outfile)), ['hi\n'])
+			with open(outfile, 'rt') as f:
+				self.assertEqual(f.read(), 'hi\n')
+			self.assertFalse(os.path.exists(kunit_kernel.get_outfile_path(build_dir)))
+
 	def test_run_kernel_args_not_mutated(self):
 		"""Verify run_kernel() copies args so callers can reuse them."""
 		start_calls = []

-- 
2.47.3


  parent reply	other threads:[~2026-10-13 15:51 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13 15:43 [PATCH 0/7] kunit: tool: Support parallel test execution Mark Brown
2026-10-13 15:43 ` [PATCH 1/7] kunit: tool: Preserve failures from kernels without test results Mark Brown
2026-10-13 15:43 ` [PATCH 2/7] kunit: tool: Combine reports from isolated kernels Mark Brown
2026-10-13 15:43 ` [PATCH 3/7] kunit: tool: Boot with a larger log buffer when listing tests Mark Brown
2026-10-13 15:43 ` Mark Brown [this message]
2026-10-13 15:43 ` [PATCH 5/7] kunit: tool: Allow several run_kernel() calls to be in flight at once Mark Brown
2026-10-13 15:43 ` [PATCH 6/7] kunit: tool: Serialise output written from multiple threads Mark Brown
2026-10-13 15:43 ` [PATCH 7/7] kunit: tool: Add --parallel to run suites in concurrent kernels Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261013-kunit-parallel-v1-4-f4be28c895e5@kernel.org \
    --to=broonie@kernel.org \
    --cc=brendan.higgins@linux.dev \
    --cc=corbet@lwn.net \
    --cc=david@davidgow.net \
    --cc=dlatypov@google.com \
    --cc=kunit-dev@googlegroups.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=raemoar63@gmail.com \
    --cc=rdunlap@infradead.org \
    --cc=skhan@linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox