summaryrefslogtreecommitdiff
path: root/tools/testing
diff options
context:
space:
mode:
authorShuvam Pandey <shuvampandey1@gmail.com>2026-02-27 15:31:36 +0300
committerShuah Khan <skhan@linuxfoundation.org>2026-04-06 23:07:29 +0300
commite42c349f4cdfa43cb39a68c8f764f8cafc23a9a9 (patch)
tree7cb029c906448e2666515e12e7b740548bb3561c /tools/testing
parentb73f50ffd4bddcd42b312a6c2b3d990f2cde7bf7 (diff)
downloadlinux-e42c349f4cdfa43cb39a68c8f764f8cafc23a9a9.tar.xz
kunit: tool: skip stty when stdin is not a tty
run_kernel() cleanup and signal_handler() invoke stty unconditionally. When stdin is not a tty (for example in CI or unit tests), this writes noise to stderr. Call stty only when stdin is a tty. Add regression tests for these paths: - run_kernel() with non-tty stdin - signal_handler() with non-tty stdin - signal_handler() with tty stdin Signed-off-by: Shuvam Pandey <shuvampandey1@gmail.com> Reviewed-by: David Gow <david@davidgow.net> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/kunit/kunit_kernel.py10
-rwxr-xr-xtools/testing/kunit/kunit_tool_test.py42
2 files changed, 50 insertions, 2 deletions
diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
index 2998e1bc088b..b610fcf0715a 100644
--- a/tools/testing/kunit/kunit_kernel.py
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -345,6 +345,12 @@ class LinuxSourceTree:
return False
return self.validate_config(build_dir)
+ def _restore_terminal_if_tty(self) -> None:
+ # stty requires a controlling terminal; skip headless runs.
+ if sys.stdin is None or not sys.stdin.isatty():
+ 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]:
# Copy to avoid mutating the caller-supplied list. exec_tests() reuses
# the same args across repeated run_kernel() calls (e.g. --run_isolated),
@@ -386,8 +392,8 @@ class LinuxSourceTree:
process.stdout.close()
waiter.join()
- subprocess.call(['stty', 'sane'])
+ self._restore_terminal_if_tty()
def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None:
logging.error('Build interruption occurred. Cleaning console.')
- subprocess.call(['stty', 'sane'])
+ self._restore_terminal_if_tty()
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index db4370032e97..267c33cecf87 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -529,6 +529,48 @@ class LinuxSourceTreeTest(unittest.TestCase):
self.assertIn('kunit.filter_glob=suite.test1', start_calls[0])
self.assertIn('kunit.filter_glob=suite.test2', start_calls[1])
+ def test_run_kernel_skips_terminal_reset_without_tty(self):
+ def fake_start(unused_args, unused_build_dir):
+ return subprocess.Popen(['printf', 'KTAP version 1\n'],
+ text=True, stdout=subprocess.PIPE)
+
+ non_tty_stdin = mock.Mock()
+ non_tty_stdin.isatty.return_value = False
+
+ with tempfile.TemporaryDirectory('') as build_dir:
+ tree = kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=[os.devnull])
+ with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \
+ mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \
+ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call:
+ for _ in tree.run_kernel(build_dir=build_dir):
+ pass
+
+ mock_call.assert_not_called()
+
+ def test_signal_handler_skips_terminal_reset_without_tty(self):
+ non_tty_stdin = mock.Mock()
+ non_tty_stdin.isatty.return_value = False
+ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull])
+
+ with mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \
+ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \
+ mock.patch.object(kunit_kernel.logging, 'error') as mock_error:
+ tree.signal_handler(signal.SIGINT, None)
+ mock_error.assert_called_once()
+ mock_call.assert_not_called()
+
+ def test_signal_handler_resets_terminal_with_tty(self):
+ tty_stdin = mock.Mock()
+ tty_stdin.isatty.return_value = True
+ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull])
+
+ with mock.patch.object(kunit_kernel.sys, 'stdin', tty_stdin), \
+ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \
+ mock.patch.object(kunit_kernel.logging, 'error') as mock_error:
+ tree.signal_handler(signal.SIGINT, None)
+ mock_error.assert_called_once()
+ mock_call.assert_called_once_with(['stty', 'sane'])
+
def test_build_reconfig_no_config(self):
with tempfile.TemporaryDirectory('') as build_dir:
with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f: