Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Shuvam Pandey and committed by
Shuah Khan
e42c349f b73f50ff

+50 -2
+8 -2
tools/testing/kunit/kunit_kernel.py
··· 345 345 return False 346 346 return self.validate_config(build_dir) 347 347 348 + def _restore_terminal_if_tty(self) -> None: 349 + # stty requires a controlling terminal; skip headless runs. 350 + if sys.stdin is None or not sys.stdin.isatty(): 351 + return 352 + subprocess.call(['stty', 'sane']) 353 + 348 354 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]: 349 355 # Copy to avoid mutating the caller-supplied list. exec_tests() reuses 350 356 # the same args across repeated run_kernel() calls (e.g. --run_isolated), ··· 392 386 process.stdout.close() 393 387 394 388 waiter.join() 395 - subprocess.call(['stty', 'sane']) 389 + self._restore_terminal_if_tty() 396 390 397 391 def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: 398 392 logging.error('Build interruption occurred. Cleaning console.') 399 - subprocess.call(['stty', 'sane']) 393 + self._restore_terminal_if_tty()
+42
tools/testing/kunit/kunit_tool_test.py
··· 529 529 self.assertIn('kunit.filter_glob=suite.test1', start_calls[0]) 530 530 self.assertIn('kunit.filter_glob=suite.test2', start_calls[1]) 531 531 532 + def test_run_kernel_skips_terminal_reset_without_tty(self): 533 + def fake_start(unused_args, unused_build_dir): 534 + return subprocess.Popen(['printf', 'KTAP version 1\n'], 535 + text=True, stdout=subprocess.PIPE) 536 + 537 + non_tty_stdin = mock.Mock() 538 + non_tty_stdin.isatty.return_value = False 539 + 540 + with tempfile.TemporaryDirectory('') as build_dir: 541 + tree = kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=[os.devnull]) 542 + with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \ 543 + mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ 544 + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call: 545 + for _ in tree.run_kernel(build_dir=build_dir): 546 + pass 547 + 548 + mock_call.assert_not_called() 549 + 550 + def test_signal_handler_skips_terminal_reset_without_tty(self): 551 + non_tty_stdin = mock.Mock() 552 + non_tty_stdin.isatty.return_value = False 553 + tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) 554 + 555 + with mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ 556 + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ 557 + mock.patch.object(kunit_kernel.logging, 'error') as mock_error: 558 + tree.signal_handler(signal.SIGINT, None) 559 + mock_error.assert_called_once() 560 + mock_call.assert_not_called() 561 + 562 + def test_signal_handler_resets_terminal_with_tty(self): 563 + tty_stdin = mock.Mock() 564 + tty_stdin.isatty.return_value = True 565 + tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) 566 + 567 + with mock.patch.object(kunit_kernel.sys, 'stdin', tty_stdin), \ 568 + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ 569 + mock.patch.object(kunit_kernel.logging, 'error') as mock_error: 570 + tree.signal_handler(signal.SIGINT, None) 571 + mock_error.assert_called_once() 572 + mock_call.assert_called_once_with(['stty', 'sane']) 573 + 532 574 def test_build_reconfig_no_config(self): 533 575 with tempfile.TemporaryDirectory('') as build_dir: 534 576 with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f: