Compare commits

..

2 Commits

Author SHA1 Message Date
Xavier Roche
cc69161ffc probe v2: dirty controls + harness capture
Signed-off-by: Xavier Roche <xroche@gmail.com>
2026-07-27 09:58:47 +02:00
Xavier Roche
42eadb8516 probe: windows rm -rf after taskkill
Signed-off-by: Xavier Roche <xroche@gmail.com>
2026-07-27 09:52:47 +02:00
2 changed files with 156 additions and 0 deletions

134
.github/probe.sh vendored Normal file
View File

@@ -0,0 +1,134 @@
#!/bin/bash
# Throwaway probe v2.
set -u
cd "$(dirname "$0")/../tests"
. ./testlib.sh
python=$(find_python)
echo "python=$python uname=$(uname -s) bash=$BASH_VERSION rm=$(rm --version | head -1)"
# ---- D: can rm -rf fail AT ALL here, and does it say so? (dirty controls) ----
hold() { # hold <dir> <mode>: a live python.exe pinning something in <dir>
local d=$1 m=$2
"$python" -c "
import os,sys,time
d,m=sys.argv[1],sys.argv[2]
if m=='file':
h=open(os.path.join(d,'held.log'),'w'); h.write('x'*100)
elif m=='cwd':
os.chdir(d)
elif m=='mmap':
import mmap
h=open(os.path.join(d,'held.bin'),'w+b'); h.write(b'x'*4096); h.flush()
mm=mmap.mmap(h.fileno(),0)
sys.stdout.write('ready\n'); sys.stdout.flush()
time.sleep(120)
" "$d" "$m" &
local p=$!
for _ in $(seq 1 100); do
kill -0 "$p" 2>/dev/null || break
sleep 0.1
done
echo "$p"
}
for m in file cwd mmap; do
d="$TMPDIR/dirty.$m"
mkdir -p "$d"
p=$(hold "$d" "$m")
sleep 1
err=$(rm -rf "$d" 2>&1) && rc=0 || rc=$?
printf 'D-%s: rc=%s stderr=<%s> still-there=%s\n' \
"$m" "$rc" "$err" "$(test -e "$d" && echo yes || echo no)"
kill -9 "$p" 2>/dev/null || true
wait "$p" 2>/dev/null || true
rm -rf "$d" 2>/dev/null || true
done
# ---- E5b: 57's exact cleanup shape, with the REAL server, run through
# run_with_timeout exactly like the Windows workflow does. 60 iterations.
cat >"$TMPDIR/shape.sh" <<'EOF'
set -euo pipefail
. ./testlib.sh
python=$(find_python)
server=$(nativepath "./proxy-connect-server.py")
tmpdir=$(mktemp -d)
pids=
cleanup() {
for pid in $pids; do stop_server "$pid"; done
rm -rf "$tmpdir"
}
trap cleanup EXIT
start() {
local dir="$1" mode="$2" ports
mkdir -p "$dir"
ports="$dir/ports.txt"
: >"$ports"
"$python" "$server" "$(nativepath "$dir")" "$mode" >"$ports" 2>"$dir/server.err" &
pids="$pids $!"
for _ in $(seq 1 100); do
grep -q "^ready" "$ports" 2>/dev/null && break
sleep 0.1
done
proxy_port=$(awk '/^PROXY/{print $2}' "$ports")
origin_port=$(awk '/^ORIGIN/{print $2}' "$ports")
}
start "$tmpdir/ok" ok
# poke the proxy so its handler threads open proxy.log, and the origin so it
# opens origin-headers.log -- that is what has handles out at kill time.
for _ in 1 2 3; do
"$python" -c "
import socket,sys
p=int(sys.argv[1]); o=int(sys.argv[2])
s=socket.create_connection(('127.0.0.1',p)); s.sendall(b'CONNECT 127.0.0.1:%d HTTP/1.1\r\n\r\n'%o)
s.recv(100); s.sendall(b'GET / HTTP/1.1\r\nHost: x\r\n\r\n'); s.recv(100)
" "$proxy_port" "$origin_port" >/dev/null 2>&1 || true
done
start "$tmpdir/flood" flood
# a mirror-sized tree, freshly written, like httrack leaves behind
mkdir -p "$tmpdir/ok/out/hts-cache"
i=0
while test "$i" -lt 300; do
printf 'ORIGIN-PAGE-564 %s' "$i" >"$tmpdir/ok/out/f$i.html"
i=$((i + 1))
done
echo "OK: shape ran"
EOF
bad=0 codes=
for i in $(seq 1 60); do
out=$(run_with_timeout 120 bash "$TMPDIR/shape.sh" 2>&1) && rc=0 || rc=$?
if test "$rc" -ne 0; then
bad=$((bad + 1))
codes="$codes $rc"
test "$bad" -gt 6 || printf ' [shape #%s] rc=%s out=<%s>\n' "$i" "$rc" "$out"
fi
done
echo "E5b full-shape via run_with_timeout: $bad/60 nonzero, codes:$codes"
# ---- F1: does the harness's own exit capture ever invent a nonzero? ----
bad=0 codes=
for i in $(seq 1 300); do
run_with_timeout 60 bash -c 'trap "rm -rf /tmp/nonexistent.$$" EXIT; exit 0' && rc=0 || rc=$?
test "$rc" -eq 0 || {
bad=$((bad + 1))
codes="$codes $rc"
}
done
echo "F1 run_with_timeout over a trivially-zero child: $bad/300 nonzero, codes:$codes"
# ---- F2: same, but the child also backgrounds and reaps children ----
bad=0 codes=
for i in $(seq 1 150); do
run_with_timeout 60 bash -c '
set -euo pipefail
d=$(mktemp -d); pids=
for _ in 1 2; do sleep 5 & pids="$pids $!"; done
cleanup() { for p in $pids; do kill "$p" 2>/dev/null || true; wait "$p" 2>/dev/null || true; done; rm -rf "$d"; }
trap cleanup EXIT
: >"$d/x"' && rc=0 || rc=$?
test "$rc" -eq 0 || {
bad=$((bad + 1))
codes="$codes $rc"
}
done
echo "F2 trap-with-background-reaps: $bad/150 nonzero, codes:$codes"

22
.github/workflows/zz-probe.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: zz-probe
on:
push:
branches: [fix/test57-windows-cleanup]
jobs:
probe:
runs-on: windows-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v5
- name: probe
shell: bash
working-directory: tests
run: |
set -u
export MSYS_NO_PATHCONV=1
export MSYS2_ARG_CONV_EXCL='*'
TMPDIR="$(cygpath -m "$RUNNER_TEMP")"
export TMPDIR
. ./testlib.sh
bash ../.github/probe.sh