[PATCH] Re-enable job suspension tests in W02jobs.ztst

Mikel Ward <[email protected]>
Newsgroups gmane.comp.shells.zsh.devel
Message-ID <[email protected]>
The three suspended-job tests were disabled in workers/43426 (2018)
because they used a fixed `sleep 0.1` to wait for the foreground
job to start before sending Ctrl-Z, which raced on slower systems.

This patch re-enables them with two changes:

1. Readiness synchronization
   Replace the racy `sleep 0.1` with an output-based causal barrier:
   the foreground command prints a sentinel ("ready") before it
   blocks, and the test reads the sentinel back via `zpty_line`
   before sending Ctrl-Z.  This is the same pattern the existing
   `kill` tests at the end of the file already use, and it
   guarantees the foreground process group is established before
   the signal is sent.

2. Fast teardown via a new zpty_stop_suspended helper
   The default zpty_stop's final `zpty -r` blocks waiting for pty
   EOF.  A stopped `sleep` keeps the pty slave open, so without
   explicit cleanup the test would hang for the full sleep duration
   per suspended-job test.  An earlier version of this patch used
   `sleep 100` and called the regular zpty_stop, which caused each
   test to block for up to 100 seconds.  zpty_stop_suspended sends
   `kill -KILL %1; wait; exit` (all on one command line, to keep
   zsh from flushing a "[1] + killed ..." notification into the
   test output) so the stopped child is gone by the time the
   inner shell exits and the pty slave closes.

Tests 1 and 2 also send their own `exit` before calling the helper,
to verify the "you have suspended jobs" exit warning.  Test 3
inspects the job with `jobs -r`/`jobs -s` first; that marks the
job as "reported", which suppresses the exit warning, so test 3
skips the explicit `exit` and just calls the helper.

Uses `sleep 3` instead of `sleep 100` so that even if the cleanup
regresses, the hang is caught in seconds rather than minutes.

Co-Authored-By: Claude <[email protected]>
---
 Test/W02jobs.ztst | 91 ++++++++++++++++++++++++++++-------------------
 1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index f38e90dcd..97359e4ca 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -27,6 +27,22 @@
       zpty -d
       :
     }
+    # Drop-in replacement for zpty_stop when the inner shell is left with
+    # a suspended foreground job.  Without explicit cleanup, the stopped
+    # child keeps the pty slave open and { zpty -r } blocks waiting for
+    # EOF until the child eventually exits on its own.  Tests that want
+    # to verify the "you have suspended jobs" exit warning should send
+    # their own `exit` before calling this helper.
+    zpty_stop_suspended() {
+      # SIGKILL works even on stopped processes; `wait` reaps; `exit`
+      # exits.  All on one command line so zsh doesn't return to a
+      # prompt between steps and flush a "[1] + killed ..." job-state
+      # notification into the test output.
+      zpty -w zsh $'kill -KILL %1; wait; exit\n'
+      { zpty -r zsh } | sed $'/[^[:space:]]/!d; s/\r$//;'
+      zpty -d
+      :
+    }
   else
     ZTST_unimplemented='the zsh/zpty module is not available'
   fi
@@ -83,29 +99,31 @@
 *>zsh:*running jobs*
 *>zsh:*SIGHUPed*
 
-#### Races presumed to be associated with zpty mean that
-#### tests involving suspending jobs are not safe.
-##   zpty_start
-##   zpty_input 'setopt check_jobs no_check_running_jobs'
-##   zpty_input 'sleep 3'
-##   sleep 0.1
-##   zpty_input $'\C-z'
-##   zpty_stop
-## 0:suspended job with check_jobs + no_check_running_jobs
-## *>zsh:*(stopped|suspended)*sleep*
-## *>zsh:*(stopped|suspended) jobs*
-## # no 'SIGHUPed' message for suspended jobs
-## 
-##   zpty_start
-##   zpty_input 'setopt check_jobs check_running_jobs'
-##   zpty_input 'sleep 3'
-##   sleep 0.1
-##   zpty_input $'\C-z'
-##   zpty_stop
-## 0:suspended job with check_jobs + check_running_jobs
-## *>zsh:*(stopped|suspended)*sleep*
-## *>zsh:*(stopped|suspended) jobs*
-## # no 'SIGHUPed' message for suspended jobs
+  zpty_start
+  zpty_input 'setopt check_jobs no_check_running_jobs'
+  zpty_input '(print ready; sleep 3)'
+  zpty_line
+  zpty_input $'\C-z'
+  zpty_input 'exit'
+  zpty_stop_suspended
+0:suspended job with check_jobs + no_check_running_jobs
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>zsh:*(stopped|suspended) jobs*
+# no 'SIGHUPed' message for suspended jobs
+
+  zpty_start
+  zpty_input 'setopt check_jobs check_running_jobs'
+  zpty_input '(print ready; sleep 3)'
+  zpty_line
+  zpty_input $'\C-z'
+  zpty_input 'exit'
+  zpty_stop_suspended
+0:suspended job with check_jobs + check_running_jobs
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>zsh:*(stopped|suspended) jobs*
+# no 'SIGHUPed' message for suspended jobs
 
   zpty_start
   zpty_input 'sleep 5 & sleep 4 & sleep 3 &'
@@ -155,19 +173,20 @@
 *>-
 *>zsh:*SIGHUPed*
 
-##   zpty_start
-##   zpty_input 'sleep 5'
-##   sleep 0.1
-##   zpty_input $'\C-z'
-##   zpty_input 'jobs -r'
-##   zpty_input 'print -- -'
-##   zpty_input 'jobs -s'
-##   zpty_stop
-## 0:`jobs -r` and `jobs -s` with suspended job
-## *>zsh:*(stopped|suspended)*sleep*
-## *>-
-## *>\[1]  + (stopped|suspended)*sleep*
-## # no 'SIGHUPed' message for suspended jobs
+  zpty_start
+  zpty_input '(print ready; sleep 3)'
+  zpty_line
+  zpty_input $'\C-z'
+  zpty_input 'jobs -r'
+  zpty_input 'print -- -'
+  zpty_input 'jobs -s'
+  zpty_stop_suspended
+0:`jobs -r` and `jobs -s` with suspended job
+*>ready
+*>zsh:*(stopped|suspended)*sleep*
+*>-
+*>\[1]  + (stopped|suspended)*sleep*
+# no 'SIGHUPed' message for suspended jobs
 
   zpty_start
   zpty_input 'sleep 10 & sleep 9 & sleep 8 & sleep 7 &'
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.