From 78111e5371f50f42d3999b2e475953d9c8a30c27 Mon Sep 17 00:00:00 2001 From: David Balatero Date: Tue, 5 May 2026 11:45:41 -0400 Subject: [PATCH] test: flaky terminal channel exitcode check #39580 Problem: The `nvim_get_chan_info()` terminal channel test used `shell-test INTERACT` to verify that `jobstop()` reports an unhandled `SIGHUP` as exit code `129`. `INTERACT` reads from stdin with `fgets()`, so closing the PTY could race with `SIGHUP` delivery. If `fgets()` observed EOF first, `shell-test` exited normally with code `0`, causing intermittent failures on slower sanitizer builds. Solution: Add a `shell-test HOLD` mode that prints a readiness prompt and then waits without reading stdin. Use it for the `SIGHUP` assertion so PTY EOF cannot make the helper exit normally before the signal path is observed. --- test/functional/api/vim_spec.lua | 5 +++-- test/functional/fixtures/shell-test.c | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index c27ce68773..6ae2e5be47 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -2977,9 +2977,10 @@ describe('API', function() -- :terminal with args + stopped process (shell-test). command('enew') - argv = { n.testprg('shell-test'), 'INTERACT' } + -- Use a process that doesn't read stdin, so PTY EOF can't race SIGHUP. + argv = { n.testprg('shell-test'), 'HOLD' } fn.jobstart(argv, { term = true }) - screen:expect({ any = { vim.pesc('interact $') } }) + screen:expect({ any = { vim.pesc('holding $') } }) eq(1, eval('jobstop(&channel)')) eval('jobwait([&channel], 1000)') -- Wait. local expected3 = term_channel_info(5, 3, argv) diff --git a/test/functional/fixtures/shell-test.c b/test/functional/fixtures/shell-test.c index 85de51f2b4..56b9e5c56b 100644 --- a/test/functional/fixtures/shell-test.c +++ b/test/functional/fixtures/shell-test.c @@ -46,6 +46,8 @@ static void help(void) puts(" Like REP, but print as fast as possible and then exit immediately."); puts(" shell-test INTERACT"); puts(" Prints \"interact $ \" to stderr, and waits for \"exit\" input."); + puts(" shell-test HOLD"); + puts(" Prints \"holding $ \" to stderr, and waits indefinitely."); puts(" shell-test EXIT {code}"); puts(" Exits immediately with exit code \"{code}\"."); } @@ -151,6 +153,16 @@ int main(int argc, char **argv) fprintf(stderr, "command not found: %s\n", cmd); } } + } else if (strcmp(argv[1], "HOLD") == 0) { + fprintf(stderr, "holding $ "); + fflush(NULL); + while (true) { +#ifdef MSWIN + Sleep(1000); +#else + pause(); +#endif + } } else if (strcmp(argv[1], "EXIT") == 0) { int code = 1; if (argc >= 3) {