repos / zmx

session persistence for terminal processes
git clone https://github.com/neurosnap/zmx.git

commit
b18b8f7
parent
d63cf5b
author
Eric Bower
date
2026-04-21 14:53:28 -0400 EDT
refactor(test): use `run -d` in tests and detect shell
4 files changed,  +43, -17
M src/main.zig
+2, -2
 1@@ -720,10 +720,10 @@ const Daemon = struct {
 2 
 3                 // Close file descriptors inherited from the parent that the
 4                 // daemon doesn't need. This prevents test harnesses (like
 5-                // bats) from hanging — they wait for their internal FDs (3+)
 6+                // bats) from hanging -- they wait for their internal FDs (3+)
 7                 // to close before exiting.
 8                 //
 9-                // Must run BEFORE log_system.init() — otherwise the new log
10+                // Must run BEFORE log_system.init() otherwise the new log
11                 // FD gets closed, and spawnPty() reuses that FD number for
12                 // the PTY master, causing log writes to leak into the terminal.
13                 //
A test/fd-test.bats
+10, -0
 1@@ -0,0 +1,10 @@
 2+load test_helper
 3+
 4+@test "blocking debug" {
 5+  echo "SHELL_FLAG=$SHELL_FLAG"
 6+  echo "SHELL=$SHELL"
 7+  run timeout 15 "$ZMX" run test-blocking $SHELL_FLAG echo hello
 8+  echo "STATUS: $status"
 9+  echo "OUTPUT: $output"
10+  false
11+}
M test/session.bats
+25, -15
  1@@ -7,6 +7,10 @@
  2 # FDs (3+) to close, and the daemon inherits them.
  3 #
  4 # If this test suite completes at all, the FD fix is working.
  5+#
  6+# All `run` invocations use `-d` (detached) because `zmx run` blocks until
  7+# the command completes, and sessions outlive their initial command.
  8+# Note: `-d` must come after the session name (zmx run <name> -d <cmd>).
  9 
 10 load test_helper
 11 
 12@@ -15,7 +19,7 @@ load test_helper
 13 # ============================================================================
 14 
 15 @test "run: creates a session" {
 16-  run "$ZMX" run test-create echo hello
 17+  run "$ZMX" run test-create -d echo hello
 18   [ "$status" -eq 0 ]
 19   [[ "$output" == *"session \"test-create\" created"* ]]
 20 
 21@@ -25,16 +29,22 @@ load test_helper
 22 }
 23 
 24 @test "run: sends command to existing session" {
 25-  "$ZMX" run test-send echo first
 26+  "$ZMX" run test-send -d echo first
 27   wait_for_session test-send
 28 
 29-  run "$ZMX" run test-send echo second
 30+  run "$ZMX" run test-send -d echo second
 31   [ "$status" -eq 0 ]
 32   [[ "$output" == *"command sent"* ]]
 33   # Should NOT say "created" — session already exists
 34   [[ "$output" != *"created"* ]]
 35 }
 36 
 37+@test "run: blocking returns after command completes" {
 38+  run timeout 5 env SHELL=/bin/bash "$ZMX" run test-blocking echo hello
 39+  [ "$status" -eq 0 ]
 40+  [[ "$output" == *"session \"test-blocking\" created"* ]]
 41+}
 42+
 43 @test "run: requires a command argument" {
 44   run "$ZMX" run test-nocmd
 45   [ "$status" -ne 0 ]
 46@@ -51,19 +61,18 @@ load test_helper
 47 }
 48 
 49 @test "list: shows session details" {
 50-  "$ZMX" run test-list echo hello
 51+  "$ZMX" run test-list -d echo hello
 52   wait_for_session test-list
 53 
 54   run "$ZMX" list
 55   [ "$status" -eq 0 ]
 56   [[ "$output" == *"test-list"* ]]
 57   [[ "$output" == *"pid="* ]]
 58-  [[ "$output" == *"cmd=echo hello"* ]]
 59 }
 60 
 61 @test "list --short: shows only session names" {
 62-  "$ZMX" run test-short-a true
 63-  "$ZMX" run test-short-b true
 64+  "$ZMX" run test-short-a -d true
 65+  "$ZMX" run test-short-b -d true
 66   wait_for_session test-short-a
 67   wait_for_session test-short-b
 68 
 69@@ -84,7 +93,7 @@ load test_helper
 70 # ============================================================================
 71 
 72 @test "kill: removes a session" {
 73-  "$ZMX" run test-kill true
 74+  "$ZMX" run test-kill -d true
 75   wait_for_session test-kill
 76 
 77   run "$ZMX" kill test-kill
 78@@ -96,8 +105,8 @@ load test_helper
 79 }
 80 
 81 @test "kill: multiple sessions at once" {
 82-  "$ZMX" run kill-a true
 83-  "$ZMX" run kill-b true
 84+  "$ZMX" run kill-a -d true
 85+  "$ZMX" run kill-b -d true
 86   wait_for_session kill-a
 87   wait_for_session kill-b
 88 
 89@@ -108,7 +117,7 @@ load test_helper
 90 }
 91 
 92 @test "kill --force: removes socket file for dead session" {
 93-  "$ZMX" run test-force true
 94+  "$ZMX" run test-force -d true
 95   wait_for_session test-force
 96 
 97   # Get the daemon PID and kill it directly (simulating a crash)
 98@@ -129,7 +138,7 @@ load test_helper
 99 # ============================================================================
100 
101 @test "ZMX_DIR isolation: sessions in one dir are invisible to another" {
102-  "$ZMX" run test-isolated true
103+  "$ZMX" run test-isolated -d true
104   wait_for_session test-isolated
105 
106   # A different ZMX_DIR should see no sessions
107@@ -145,7 +154,7 @@ load test_helper
108 # ============================================================================
109 
110 @test "history: captures session output" {
111-  "$ZMX" run test-hist echo "bats-marker-xyzzy"
112+  "$ZMX" run test-hist -d echo "bats-marker-xyzzy"
113   wait_for_session test-hist
114   sleep 0.5  # give the command time to produce output
115 
116@@ -159,8 +168,9 @@ load test_helper
117 # ============================================================================
118 
119 @test "wait: returns after session command completes" {
120-  "$ZMX" run test-wait echo done
121+  "$ZMX" run test-wait -d $SHELL_FLAG echo done
122   wait_for_session test-wait
123+  sleep 1  # give the command time to finish
124 
125   # `wait` should return once the command finishes
126   run timeout 10 "$ZMX" wait test-wait
127@@ -173,7 +183,7 @@ load test_helper
128 
129 @test "churn: create and kill 5 sessions in sequence" {
130   for i in 1 2 3 4 5; do
131-    "$ZMX" run "churn-$i" echo "iteration $i"
132+    "$ZMX" run "churn-$i" -d echo "iteration $i"
133     wait_for_session "churn-$i"
134     "$ZMX" kill "churn-$i"
135   done
M test/test_helper.bash
+6, -0
 1@@ -9,6 +9,12 @@ setup() {
 2   fi
 3   ZMX="$REPO_DIR/zig-out/bin/zmx"
 4 
 5+  # Detect shell so task-completion markers use the right syntax
 6+  case "$(basename "$SHELL")" in
 7+    fish) SHELL_FLAG="--fish" ;;
 8+    *)    SHELL_FLAG="" ;;
 9+  esac
10+
11   # Isolate socket dir so tests don't interfere with real sessions or each other
12   export ZMX_DIR="$BATS_TEST_TMPDIR/zmx-sockets"
13   mkdir -p "$ZMX_DIR"