summaryrefslogtreecommitdiff
path: root/9player/test/adv_bridge_hostile.sh
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-19 23:28:22 -0300
committerGabriel Schneider <[email protected]>2026-09-19 23:28:22 -0300
commitba996acfcad1698adbf4a1834fe50e73b1c6cab9 (patch)
tree282ba00ce5b10d7416aecb9f2f0f0a439340a57d /9player/test/adv_bridge_hostile.sh
parentb05abcba3ea09ea106ad28364c6e40a3ec31b890 (diff)
downloadcloud9-ba996acfcad1698adbf4a1834fe50e73b1c6cab9.tar.gz
cloud9-ba996acfcad1698adbf4a1834fe50e73b1c6cab9.zip
Rename programs: 9player -> 9ns, introspect -> 9proc, app -> web (9web)
Directories, binaries, build options (-D9ns, -D9proc), step names, module name (9proc), thread and fs names, env var NINEPLAYER_MOUNT -> NINE_MOUNT, docs and test scripts. Browser assets move to web/static. Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to '9player/test/adv_bridge_hostile.sh')
-rwxr-xr-x9player/test/adv_bridge_hostile.sh181
1 files changed, 0 insertions, 181 deletions
diff --git a/9player/test/adv_bridge_hostile.sh b/9player/test/adv_bridge_hostile.sh
deleted file mode 100755
index f1ee292..0000000
--- a/9player/test/adv_bridge_hostile.sh
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/usr/bin/env bash
-# Hostile-server tests: 9player against 9player/test/adv_bridge_hostile.py in every
-# misbehaviour mode. 9player must never crash (panic/segfault) and must turn
-# each misbehaviour into an errno for the child.
-# Usage: bash 9player/test/adv_bridge_hostile.sh <9player> <introspect> (introspect unused; part of zig build 9player-adv)
-set -u
-PLAYER=$(realpath "${1:?path to 9player}")
-HERE=$(cd "$(dirname "$0")" && pwd)
-SRV=$HERE/adv_bridge_hostile.py
-TMP=$(mktemp -d "${TMPDIR:-/tmp}/9player-adv.XXXXXX")
-M=/mnt/9p
-FAILED=0
-PASSED=0
-SRVPID=
-
-cleanup() { [ -n "$SRVPID" ] && kill "$SRVPID" 2>/dev/null; pkill -f "adv_bridge_hostile.py $TMP" 2>/dev/null; rm -rf "$TMP"; }
-trap cleanup EXIT
-
-if ! unshare -Urm true 2>/dev/null || [ ! -c /dev/fuse ]; then echo "SKIP: no user namespaces or /dev/fuse"; exit 0; fi
-
-pass() { PASSED=$((PASSED + 1)); echo "ok - $1"; }
-fail() { FAILED=$((FAILED + 1)); echo "FAIL - $1"; shift; [ $# -gt 0 ] && printf ' %s\n' "$@"; }
-expect_eq() { if [ "$2" = "$3" ]; then pass "$1"; else fail "$1" "expected: $(printf %q "$2")" "actual: $(printf %q "$3")"; fi; }
-expect_contains() { case "$3" in *"$2"*) pass "$1" ;; *) fail "$1" "missing: $(printf %q "$2")" "in: $(printf %q "$3")" ;; esac; }
-
-start_server() { # mode
- [ -n "$SRVPID" ] && { kill "$SRVPID" 2>/dev/null; wait "$SRVPID" 2>/dev/null; }
- SOCK=$TMP/$1.sock
- rm -f "$SOCK"
- python3 "$SRV" "$SOCK" "$1" >"$TMP/$1.srv.out" 2>&1 </dev/null &
- SRVPID=$!
- for _ in $(seq 1 100); do [ -S "$SOCK" ] && return 0; sleep 0.02; done
- echo "server for $1 did not start"; cat "$TMP/$1.srv.out"; exit 1
-}
-
-# run MODE SCRIPT [extra 9player args...]: starts the server, runs 9player; sets OUT, RC, STDERR.
-run() {
- local mode=$1 script=$2; shift 2
- start_server "$mode"
- OUT=$(timeout 30 "$PLAYER" --unix "$SOCK" "$@" -- sh -c "$script" 2>"$TMP/stderr")
- RC=$?
- STDERR=$(cat "$TMP/stderr")
-}
-
-# 9player must not die of a signal or panic. RC 124 = timeout(1) fired.
-no_crash() { # name
- if [ "$RC" -ge 128 ] || [ "$RC" -eq 124 ]; then fail "$1: 9player exit $RC" "$STDERR"; return; fi
- case "$STDERR" in *panic*|*"Segmentation"*|*"integer overflow"*|*"reached unreachable"*|*"index out of bounds"*) fail "$1: crash text in stderr" "$STDERR";; *) pass "$1: no crash (exit $RC)";; esac
-}
-
-echo "# sanity: the hostile server behaves in 'ok' mode"
-run ok "cat $M/f"; expect_eq "ok: cat f" "hello world" "$OUT"
-run ok "cat $M/d/g"; expect_eq "ok: nested" "in d" "$OUT"
-run ok "cat $M/nope 2>&1 | sed 's/.*: //'"; expect_eq "ok: ENOENT" "No such file or directory" "$OUT"
-run ok "head -c 1048576 $M/big | wc -c | grep -q 1048576 && echo yes"; expect_eq "ok: 1 MiB read matches" "yes" "$OUT"
-
-echo "# unlink + recreate with a recycled qid.path"
-run ok "echo 1 > $M/a; rm $M/a; echo 2 > $M/a; cat $M/a; rm $M/a"; expect_eq "qid reuse: new content, not stale" "2" "$OUT"
-run ok "echo 1 > $M/x; rm $M/x; mkdir $M/x; stat -c %F $M/x; rmdir $M/x"; expect_eq "qid reuse: file→dir on the same path" "directory" "$OUT"
-
-echo "# fids do not grow with the number of operations"
-loop='i=0; while [ $i -lt N ]; do echo hi > M/t; cat M/t >/dev/null; mkdir M/dd; rmdir M/dd; rm M/t; i=$((i+1)); done; cat M/fids'
-run ok "$(echo "$loop" | sed "s|N|20|; s|M/|$M/|g")"; a=$OUT
-run ok "$(echo "$loop" | sed "s|N|200|; s|M/|$M/|g")"; b=$OUT
-expect_eq "fids after 20 == after 200 iterations ($a)" "$a" "$b"
-floop='i=0; while [ $i -lt N ]; do cat M/nope 2>/dev/null; echo x > M/fids 2>/dev/null; mkdir M/f 2>/dev/null; rm M/d 2>/dev/null; mv M/f M/d 2>/dev/null; i=$((i+1)); done; cat M/fids'
-run ok "$(echo "$floop" | sed "s|N|20|; s|M/|$M/|g")"; a=$OUT
-run ok "$(echo "$floop" | sed "s|N|200|; s|M/|$M/|g")"; b=$OUT
-expect_eq "fids after 20 == after 200 failing iterations ($a)" "$a" "$b"
-
-echo "# rename over an existing file must not lose the target when the rename fails"
-run rename_fail "echo A > $M/a; echo B > $M/b; mv $M/a $M/b 2>/dev/null; echo mv=\$?; cat $M/b; cat $M/a"
-expect_contains "rename_fail: mv reports failure" "mv=1" "$OUT"
-expect_contains "rename_fail: target b still has its content" "B" "$OUT"
-expect_contains "rename_fail: source a still has its content" "A" "$OUT"
-
-echo "# protocol violations on a data read must yield an error, not a crash"
-for mode in trunc short_frame huge_frame wrong_tag rread_big extra_reply close_mid renegotiate rwrite_big; do
- if [ "$mode" = rwrite_big ]; then script="dd if=/dev/zero of=$M/f bs=10 count=1 2>&1; echo status=\$?"; else script="cat $M/f 2>&1; echo status=\$?"; fi
- run "$mode" "$script"
- no_crash "$mode"
- expect_contains "$mode: child sees an error" "status=1" "$OUT"
- case "$OUT" in *"Input/output error"*|*"not connected"*) pass "$mode: EIO/ENOTCONN";; *) fail "$mode: errno text" "$OUT";; esac
-done
-
-echo "# protocol violations on lookup/stat"
-for mode in wrong_type rwalk_many rstat_garbage rstat_overlong; do
- run "$mode" "stat -c %s $M/f 2>&1; echo status=\$?"
- no_crash "$mode"
- expect_contains "$mode: child sees an error" "status=1" "$OUT"
-done
-run rwalk_zero "cat $M/nope 2>&1; echo status=\$?; cat $M/f 2>&1"
-no_crash "rwalk_zero"
-expect_contains "rwalk_zero: child sees an error" "status=1" "$OUT"
-run rerror_big "cat $M/nope 2>&1; echo status=\$?; cat $M/f"
-no_crash "rerror_big"
-expect_contains "rerror_big: child sees an error" "status=1" "$OUT"
-expect_contains "rerror_big: session survives a 64 KiB Rerror" "hello world" "$OUT"
-
-echo "# hostile stat contents"
-run length_max "stat -c '%s %b' $M/f 2>&1; echo status=\$?"
-no_crash "length_max"
-expect_contains "length_max: stat succeeds with a saturated block count" "status=0" "$OUT"
-run iounit_one "cat $M/f; head -c 3000 $M/big | wc -c"
-no_crash "iounit_one"
-expect_contains "iounit_one: read still complete" "hello world" "$OUT"
-expect_contains "iounit_one: 3000 bytes" "3000" "$OUT"
-
-echo "# hostile directory listings"
-run dir_split "ls $M 2>&1; echo status=\$?; cat $M/f"
-no_crash "dir_split"
-expect_contains "dir_split: readdir fails with EIO" "Input/output error" "$OUT"
-expect_contains "dir_split: session survives" "hello world" "$OUT"
-run dir_forever "ls $M 2>&1 | tail -c 200; echo status=\$?; cat $M/f; grep VmRSS /proc/\$PPID/status"
-no_crash "dir_forever"
-expect_contains "dir_forever: infinite directory is cut off with EIO" "Input/output error" "$OUT"
-expect_contains "dir_forever: session survives" "hello world" "$OUT"
-for mode in name_slash name_empty name_huge name_dots; do
- run "$mode" "ls -a $M | tr '\n' ' '; echo; cat $M/f"
- no_crash "$mode"
- expect_contains "$mode: listing still works" "big d f fids" "$OUT"
- expect_contains "$mode: file readable" "hello world" "$OUT"
- case "$mode" in
- name_slash) expect_eq "$mode: slash entry dropped" "" "$(printf '%s' "$OUT" | grep -o 'a/b')";;
- name_dots) expect_eq "$mode: exactly one . and one .." "1 1" "$(printf '%s %s' "$(printf '%s\n' "$OUT" | head -1 | tr ' ' '\n' | grep -c '^\.$')" "$(printf '%s\n' "$OUT" | head -1 | tr ' ' '\n' | grep -c '^\.\.$')")";;
- esac
-done
-
-echo "# qid collisions"
-run qid_collide "cat $M/f; cat $M/d/g; ls $M/d; stat -c %i $M/f $M/d 2>&1; echo status=\$?"
-no_crash "qid_collide"
-expect_contains "qid_collide: reads work" "hello world" "$OUT"
-run qid_zero "cat $M/f; ls $M | tr '\n' ' '; echo; cat $M/d/g; echo status=\$?"
-no_crash "qid_zero"
-expect_contains "qid_zero: file with root's qid.path is still a readable file" "hello world" "$OUT"
-expect_contains "qid_zero: root still lists" "big d f fids" "$OUT"
-expect_contains "qid_zero: nested file readable" "in d" "$OUT"
-
-echo "# version negotiation"
-run version_unknown "echo ran"
-expect_eq "version_unknown: 9player refuses (125)" "125" "$RC"
-run msize_tiny "cat $M/f 2>&1; echo status=\$?"
-no_crash "msize_tiny"
-
-echo "# a server that never replies"
-start_server never
-# SIGTERM is forwarded to the child; once the child is gone 9player must leave the
-# pending 9P reply behind and exit even though the server stays silent.
-timeout -s TERM 3 "$PLAYER" --unix "$SOCK" -- sh -c "cat $M/f; echo unreachable" >"$TMP/never.out" 2>"$TMP/never.err" &
-TPID=$!
-sleep 4
-if kill -0 "$TPID" 2>/dev/null; then
- fail "never: SIGTERM did not end 9player while a reply was outstanding"; kill -9 "$TPID"
-else
- pass "never: SIGTERM ends 9player even while the server is silent"
-fi
-wait "$TPID" 2>/dev/null
-# Without a signal the mount hangs (documented v1 limitation) until the server dies.
-timeout 30 "$PLAYER" --unix "$SOCK" -- sh -c "cat $M/f; echo unreachable" >"$TMP/never.out" 2>"$TMP/never.err" &
-TPID=$!
-sleep 1.5
-if kill -0 "$TPID" 2>/dev/null; then
- pass "never: mount hangs while the server is silent (documented v1 limitation)"
- kill "$SRVPID"; wait "$SRVPID" 2>/dev/null; SRVPID=
- for _ in $(seq 1 50); do kill -0 "$TPID" 2>/dev/null || break; sleep 0.1; done
- if kill -0 "$TPID" 2>/dev/null; then fail "never: 9player still alive after its server died"; kill -9 "$TPID"; else pass "never: killing the server unblocks 9player"; fi
-else
- wait "$TPID"; fail "never: 9player exited early ($?)" "$(cat "$TMP/never.err")"
-fi
-
-echo "# interrupting a slow read (INTERRUPT must not confuse reply matching)"
-run slow "cat $M/big > /dev/null; cat $M/f; cat $M/fids" --msize 8192
-base=$(printf '%s\n' "$OUT" | tail -1)
-run slow "(cat $M/big > /dev/null & sleep 0.3; kill -INT \$!; wait \$!) 2>/dev/null; cat $M/f; cat $M/fids" --msize 8192
-no_crash "slow"
-expect_contains "slow: read after interrupted read works" "hello world" "$OUT"
-expect_eq "slow: fids after an interrupted read == after a complete one ($base)" "$base" "$(printf '%s\n' "$OUT" | tail -1)"
-
-echo
-echo "passed=$PASSED failed=$FAILED"
-[ "$FAILED" -eq 0 ]