Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

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



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 <noreply@xxxxxxxxxxxxx>
---
 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





Messages sorted by: Reverse Date, Date, Thread, Author