AtlatestRepositorysigil-http

sigil-http / tree / test / integrationrun-starvation-test.sh

1#!/usr/bin/env bash
2# Integration test for the server-loop drain starvation fix.
3#
4# Proves that a sibling socket io-waiter is serviced promptly while the HTTP
5# server has a connected (half-open) client. Before the fix, the server-loop
6# `drain` busy-spins process-connections while >=1 client is connected; the
7# async scheduler only polls socket io-waiters when its run-queue is empty,
8# so the sibling's first read starves (observed as multi-second to
9# multi-minute first-event delays for outbound sockets in real apps). After
10# the fix the drain suspends on the scheduler (await-readable-any), the run
11# queue empties, and the sibling io-waiter is serviced within milliseconds.
13# Same ceremony as run-streaming-tests.sh: a loose `sigil <file>` run would
14# resolve imports from the RELEASED sigil-http (and the interpreter's async
15# path is not faithful to compiled scheduling anyway), so we build an
16# ephemeral bundle and run the compiled binary. The probe is self-contained
17# (exit 0 = serviced promptly, 1 = starved/degraded, 2 = harness failure).
19# Unlike run-streaming-tests.sh, this repo's http modules are VENDORED into
20# the bundle (copied verbatim from src/) instead of pulled as a `from-path`
21# package: combining a from-path sigil-http with a from-path/redirected
22# sigil monorepo (needed while the `await-readable-any` scheduler primitive
23# is unreleased) makes the from-path package build silently produce nothing.
24# Vendoring sidesteps that while still compiling this repo's actual
25# server.sgl bytes.
27# SIGIL_MONOREPO_PATH: when set, sigil-run/sigil-stdlib resolve from that
28# local sigil checkout (for testing against an unreleased runtime); when
29# unset, they resolve from the released monorepo (from-git).
31# Requires: a working `sigil` toolchain, network on first run (dep fetch).
32# Run from anywhere:
33# test/integration/run-starvation-test.sh
35set -u
37SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
38REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
39PROBE_SRC="$SCRIPT_DIR/starvation-probe-main.sgl"
41APP_DIR="$(mktemp -d /tmp/starvation-probe-app.XXXXXX)"
42BIN="$APP_DIR/build/dev/bin/starvation-probe"
44cleanup() {
45 rm -rf "$APP_DIR"
47trap cleanup EXIT
49echo "=== server-loop drain starvation probe ==="
51mkdir -p "$APP_DIR/src/starvation-probe" "$APP_DIR/src/sigil/http"
52cp "$PROBE_SRC" "$APP_DIR/src/starvation-probe/main.sgl"
53# Vendor this repo's http modules (the code under test) into the bundle.
54for m in server request response mime; do
55 cp "$REPO_ROOT/src/sigil/http/$m.sgl" "$APP_DIR/src/sigil/http/$m.sgl"
56done
58if [ -n "${SIGIL_MONOREPO_PATH:-}" ]; then
59 MONOREPO_DEPS="(from-path dir: \"$SIGIL_MONOREPO_PATH\" package: \"sigil-run\")
60 (from-path dir: \"$SIGIL_MONOREPO_PATH\" package: \"sigil-stdlib\")"
61else
62 MONOREPO_DEPS="(from-git url: \"codeberg:sigil/sigil\" package: \"sigil-run\" version: \"^0.17\")
63 (from-git url: \"codeberg:sigil/sigil\" package: \"sigil-stdlib\" version: \"^0.17\")"
64fi
66cat > "$APP_DIR/package.sgl" <<EOF
67(package
68 name: "starvation-probe"
69 version: "0.1.0"
70 sigil: "^0.17"
71 description: "Ephemeral integration bundle for the drain starvation fix"
72 entry: '(starvation-probe main)
73 bundle-name: "starvation-probe"
74 configs: (list
75 (config name: 'dev output-dir: "build/dev" static?: #f debug?: #t optimize: 0 bundle?: #t))
76 dependencies: (list
77 $MONOREPO_DEPS
78 (from-git url: "codeberg:sigil/sigil-json" version: "^0.16"))
80 tasks: (list
81 (task
82 name: 'build
83 description: "Compile probe + vendored http modules"
84 steps: (list
85 (compile-sigil-modules sources: "src/**/*.sgl")))))
86EOF
88echo "--- building probe bundle ($APP_DIR) ---"
89(cd "$APP_DIR" \
90 && sigil deps install >"$APP_DIR/deps.log" 2>&1 \
91 && sigil build starvation-probe) || {
92 echo "FAIL: probe build failed; deps log:"
93 tail -20 "$APP_DIR/deps.log" 2>/dev/null
94 exit 2
96if [ ! -x "$BIN" ]; then
97 echo "FAIL: probe binary missing after build"
98 exit 2
99fi
101echo "--- running probe (watchdog-bounded; ~10-20s) ---"
102"$BIN"
103RC=$?
105if [ "$RC" -eq 0 ]; then
106 echo "PASS: sibling io-waiter serviced promptly while a client was connected"
107else
108 echo "FAIL: probe exit $RC (1 = starved/degraded, 2 = harness failure)"
109fi
110exit "$RC"