Files
NeoTachyon/tests/ui_sing_box_probe.sh
T

121 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib"
UI_UC="$TACHYON_LIB/service/ui.uc"
WORK_DIR="$(mktemp -d)"
PROBE_BIN="$WORK_DIR/sing-box"
PROBE_COUNT="$WORK_DIR/probe-count"
PROBE_PIDS="$WORK_DIR/probe-pids"
CACHE_FILE="$WORK_DIR/sing-box-version-cache"
cleanup() {
if [ -f "$PROBE_PIDS" ]; then
while IFS= read -r pid; do
kill -9 "$pid" 2>/dev/null || true
done <"$PROBE_PIDS"
fi
rm -rf "$WORK_DIR"
}
trap cleanup EXIT
fail() {
printf 'FAIL: %s\n' "$1" >&2
exit 1
}
cat >"$PROBE_BIN" <<'SH'
#!/bin/sh
printf '%s\n' "$$" >>"$TACHYON_TEST_SING_BOX_PROBE_PIDS"
printf 'probe\n' >>"$TACHYON_TEST_SING_BOX_PROBE_COUNT"
if [ "${TACHYON_TEST_SING_BOX_PROBE_MODE:-fast}" = "slow" ]; then
exec sleep 30
fi
printf 'sing-box version 1.13.14\n\n'
printf 'Tags: with_quic,with_tailscale\n'
SH
chmod 755 "$PROBE_BIN"
cat >"$WORK_DIR/opkg" <<'SH'
#!/bin/sh
exit 0
SH
chmod 755 "$WORK_DIR/opkg"
ui_capabilities() {
PATH="$WORK_DIR:$PATH" \
TACHYON_CONFIG_NAME=tachyon-ui-probe-test \
TACHYON_UI_STATE_DIR="$WORK_DIR/state" \
TACHYON_UI_COMPONENT_ACTION_DIR="$WORK_DIR/components" \
TACHYON_UI_SING_BOX_VERSION_CACHE_FILE="$CACHE_FILE" \
TACHYON_UI_SING_BOX_VARIANT_STATE_FILE="$WORK_DIR/missing-variant" \
TACHYON_UI_SING_BOX_BIN_PATH="$PROBE_BIN" \
TACHYON_UI_SING_BOX_VERSION_PROBE_TIMEOUT_SECONDS=1 \
TACHYON_UI_SING_BOX_VERSION_PROBE_FAILURE_TTL_SECONDS=30 \
ZAPRET_PROVIDER_NFQWS_BIN="$WORK_DIR/missing-nfqws" \
ZAPRET2_PROVIDER_NFQWS2_BIN="$WORK_DIR/missing-nfqws2" \
BYEDPI_BIN="$WORK_DIR/missing-ciadpi" \
TACHYON_TEST_SING_BOX_PROBE_COUNT="$PROBE_COUNT" \
TACHYON_TEST_SING_BOX_PROBE_PIDS="$PROBE_PIDS" \
ucode -L "$TACHYON_LIB" "$UI_UC" get-ui-capabilities
}
fast_first="$(TACHYON_TEST_SING_BOX_PROBE_MODE=fast ui_capabilities)"
fast_second="$(TACHYON_TEST_SING_BOX_PROBE_MODE=fast ui_capabilities)"
[ "$(wc -l <"$PROBE_COUNT")" -eq 1 ] ||
fail "successful sing-box capability detection must be cached by binary signature"
JSON_VALUE="$fast_first" node - <<'NODE'
const value = JSON.parse(process.env.JSON_VALUE);
if (value.sing_box_extended !== 0 || value.sing_box_tiny !== 0 || value.sing_box_tailscale !== 1) {
console.error('cached sing-box capability flags mismatch');
process.exit(1);
}
NODE
[ "$fast_first" = "$fast_second" ] ||
fail "cached sing-box capabilities must match the initial detection"
: >"$PROBE_COUNT"
: >"$PROBE_PIDS"
rm -rf "$CACHE_FILE" "$CACHE_FILE.lock"
start_seconds=$SECONDS
workers=""
for index in 1 2 3 4 5; do
TACHYON_TEST_SING_BOX_PROBE_MODE=slow ui_capabilities >"$WORK_DIR/slow-$index.json" &
workers="$workers $!"
done
for worker in $workers; do
wait "$worker"
done
elapsed_seconds=$((SECONDS - start_seconds))
[ "$elapsed_seconds" -le 4 ] ||
fail "bounded sing-box probes took ${elapsed_seconds}s"
[ "$(wc -l <"$PROBE_COUNT")" -eq 1 ] ||
fail "parallel UI requests must share one sing-box probe"
for output in "$WORK_DIR"/slow-*.json; do
JSON_FILE="$output" node - <<'NODE'
const fs = require('fs');
const value = JSON.parse(fs.readFileSync(process.env.JSON_FILE, 'utf8'));
if (value.sing_box_extended !== 0 || value.sing_box_tiny !== 0 || value.sing_box_tailscale !== 0) {
console.error('failed sing-box probe must produce conservative capability flags');
process.exit(1);
}
NODE
done
TACHYON_TEST_SING_BOX_PROBE_MODE=slow ui_capabilities >/dev/null
[ "$(wc -l <"$PROBE_COUNT")" -eq 1 ] ||
fail "failed sing-box probe must be cached during the retry cooldown"
while IFS= read -r pid; do
if kill -0 "$pid" 2>/dev/null; then
fail "timed-out sing-box probe process $pid is still running"
fi
done <"$PROBE_PIDS"
: >"$PROBE_PIDS"
printf 'UI sing-box probe checks passed\n'