| 1 | #!/bin/sh |
| 2 | TEST_PREFIX="[int-job-control]" |
| 3 | SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) |
| 4 | FORTSH_BIN="${FORTSH_BIN:-$SCRIPT_DIR/../../../bin/fortsh}" |
| 5 | export FORTSH_BIN |
| 6 | . "$SCRIPT_DIR/../test_harness.sh" |
| 7 | |
| 8 | # Integration tests: job control, background processes, wait, kill |
| 9 | # TTY-dependent tests are skipped when not connected to a terminal |
| 10 | |
| 11 | HAS_TTY=false |
| 12 | [ -t 0 ] && HAS_TTY=true |
| 13 | |
| 14 | section "1. background execution" |
| 15 | compare_output "background and wait" 'echo bg & wait; echo done' |
| 16 | compare_output "background exit status via wait" 'true & wait $!; echo $?' |
| 17 | compare_output "background false status" 'false & wait $!; echo $?' |
| 18 | # Output order of concurrent background jobs is non-deterministic — sort to normalize |
| 19 | TEST_NUM=$((TEST_NUM + 1)) |
| 20 | _jc_expected=$(run_with_timeout "$TEST_TIMEOUT" "$BASH_REF" -c 'echo a & echo b & wait; echo done' 2>&1 | sort) |
| 21 | _jc_actual=$(run_with_timeout "$TEST_TIMEOUT" "$FORTSH_BIN" -c 'echo a & echo b & wait; echo done' 2>&1 | sort) |
| 22 | if [ "$_jc_expected" = "$_jc_actual" ]; then pass "multiple background wait all" |
| 23 | else fail "multiple background wait all" "$_jc_expected" "$_jc_actual"; fi |
| 24 | compare_output "background dollar-bang" 'sleep 0.01 & [ -n "$!" ] && echo has_pid' |
| 25 | compare_output "background preserves parent" 'X=before; (X=after) & wait; echo $X' |
| 26 | |
| 27 | section "2. wait" |
| 28 | compare_output "wait specific pid" 'sleep 0.01 & PID=$!; wait $PID; echo $?' |
| 29 | compare_output "wait captures exit" 'false & wait $!; echo $?' |
| 30 | compare_output "wait for true" 'true & wait $!; echo $?' |
| 31 | compare_output "wait no children" 'wait 2>/dev/null; echo $?' |
| 32 | compare_output "wait nonexistent pid" 'wait 99999 2>/dev/null; echo $?' |
| 33 | compare_output "wait all children" 'sleep 0.01 & sleep 0.01 & wait; echo $?' |
| 34 | |
| 35 | section "3. kill" |
| 36 | compare_output "kill background process" 'sleep 10 & PID=$!; kill $PID 2>/dev/null; wait $PID 2>/dev/null; echo done' |
| 37 | compare_output "kill -0 checks existence" 'sleep 10 & PID=$!; kill -0 $PID 2>/dev/null && echo alive; kill $PID 2>/dev/null; wait $PID 2>/dev/null' |
| 38 | compare_output "kill nonexistent pid" 'kill 99999 2>/dev/null; echo $?' |
| 39 | compare_output "kill -l lists signals" 'kill -l | head -1 | grep -q "[A-Z]" && echo has_signals' |
| 40 | |
| 41 | section "4. job control (TTY-dependent)" |
| 42 | if $HAS_TTY; then |
| 43 | compare_output "jobs empty" 'jobs 2>/dev/null; echo $?' |
| 44 | else |
| 45 | skip "jobs empty" "no TTY" |
| 46 | skip "fg no jobs" "no TTY" |
| 47 | skip "bg no jobs" "no TTY" |
| 48 | fi |
| 49 | |
| 50 | section "5. coproc" |
| 51 | compare_output "coproc with brace group" 'coproc { cat; }; echo hello >&${COPROC[1]}; sleep 0.1; read line <&${COPROC[0]}; echo $line' |
| 52 | compare_output "named coproc" 'coproc MYCAT { cat; }; echo test >&${MYCAT[1]}; sleep 0.1; read line <&${MYCAT[0]}; echo $line' |
| 53 | compare_output "coproc output" 'coproc { echo from_coproc; sleep 10; }; sleep 0.1; read line <&${COPROC[0]}; echo $line; kill $COPROC_PID 2>/dev/null; wait $COPROC_PID 2>/dev/null' |
| 54 | |
| 55 | print_summary |