Files
uce/scripts/test_dynamic_compile_failures.sh
T
2026-07-19 23:15:39 +00:00

168 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")/.."
if [[ "${1:-}" != "--inside" ]]; then
exec timeout --signal=TERM --kill-after=5s 240s unshare --mount --net --fork --kill-child=TERM "$0" --inside
fi
ip link set lo up
root="/tmp/uce-dynamic-compile-failures-$$"
site="$root/site"
work="$root/work"
settings="$root/settings.cfg"
log="$root/service.log"
port=18080
server_pid=""
cleanup() {
status=$?
if [[ -n "$server_pid" ]] && kill -0 "$server_pid" 2>/dev/null; then
kill -TERM "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
fi
if (( status != 0 )) && [[ -r "$log" ]]; then cat "$log" >&2; fi
while umount /etc/uce/settings.cfg 2>/dev/null; do :; done
rm -rf "$root"
return "$status"
}
trap cleanup EXIT
mkdir -p "$site" "$work" "$root/run" "$root/session" "$root/upload"
cat >"$site/driver.uce" <<'UCE'
RENDER(Request& context) {
print("driver:");
if(context.get["mode"] == "render") unit_render("broken-render", context);
else if(context.get["mode"] == "call") unit_call("broken-call", "COMPONENT");
else print(component("child", context));
}
UCE
printf '%s\n' 'COMPONENT(Request& context) { print("good-v1"); }' >"$site/child.uce"
printf '%s\n' 'RENDER(Request& context) { print("render-ok"); }' >"$site/broken-render.uce"
printf '%s\n' 'COMPONENT(Request& context) { print("call-ok"); }' >"$site/broken-call.uce"
write_settings() {
local show_errors="$1" serve_good="$2" proactive="$3"
sed -E '/^[[:space:]]*(BIN_DIRECTORY|PRECOMPILE_FILES_IN|SITE_DIRECTORY|FCGI_SOCKET_PATH|FCGI_PORT|CLI_SOCKET_PATH|WS_BROKER_SOCKET_PATH|HTTP_PORT|HTTP_DOCUMENT_ROOT|SESSION_PATH|TMP_UPLOAD_PATH|WASM_CORE_PATH|PROACTIVE_COMPILE_ENABLED|PROACTIVE_COMPILE_CHECK_INTERVAL|PROACTIVE_COMPILE_JOBS|WORKER_COUNT|SHOW_DYNAMIC_COMPILE_ERRORS|SERVE_LAST_KNOWN_GOOD)[[:space:]]*=/d' \
/etc/uce/settings.cfg >"$settings"
cat >>"$settings" <<CFG
BIN_DIRECTORY=$work
PRECOMPILE_FILES_IN=$site
SITE_DIRECTORY=$site
FCGI_SOCKET_PATH=$root/run/fastcgi.sock
FCGI_PORT=
CLI_SOCKET_PATH=$root/run/cli.sock
WS_BROKER_SOCKET_PATH=$root/run/ws.sock
HTTP_PORT=$port
HTTP_DOCUMENT_ROOT=$site
SESSION_PATH=$root/session
TMP_UPLOAD_PATH=$root/upload
WASM_CORE_PATH=$(pwd)/bin/wasm/core.wasm
PROACTIVE_COMPILE_ENABLED=$proactive
PROACTIVE_COMPILE_CHECK_INTERVAL=1
PROACTIVE_COMPILE_JOBS=1
WORKER_COUNT=1
SHOW_DYNAMIC_COMPILE_ERRORS=$show_errors
SERVE_LAST_KNOWN_GOOD=$serve_good
CFG
mount --bind "$settings" /etc/uce/settings.cfg
}
start_server() {
: >"$log"
bin/uce_fastcgi.linux.bin >"$log" 2>&1 &
server_pid=$!
for _ in $(seq 1 500); do
curl -sS --max-time 1 "http://127.0.0.1:$port/driver.uce" >/dev/null 2>&1 && return
kill -0 "$server_pid" 2>/dev/null || break
sleep 0.02
done
cat "$log" >&2
return 1
}
stop_server() {
kill -TERM "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
server_pid=""
}
request() {
local method="${1:-GET}" query="${2:-}"
if [[ "$method" == POST ]]; then
curl -sS --max-time 30 -w $'\n%{http_code}' -X POST --data '' "http://127.0.0.1:$port/driver.uce?$query"
else
curl -sS --max-time 30 -w $'\n%{http_code}' "http://127.0.0.1:$port/driver.uce?$query"
fi
}
body_of() { printf '%s' "${1%$'\n'*}"; }
status_of() { printf '%s' "${1##*$'\n'}"; }
write_settings 1 0 0
start_server
printf '%s\n' 'COMPONENT(Request& context) { UCE_DYNAMIC_COMPILE_MARKER }' >"$site/child.uce"
response=$(request GET)
body=$(body_of "$response")
[[ "$(status_of "$response")" == 500 ]]
[[ "$body" == *UCE_DYNAMIC_COMPILE_MARKER* ]]
[[ "$body" != *"component not found"* ]]
printf '%s\n' 'RENDER(Request& context) { UCE_RENDER_COMPILE_MARKER }' >"$site/broken-render.uce"
response=$(request GET mode=render)
[[ "$(status_of "$response")" == 500 && "$(body_of "$response")" == *UCE_RENDER_COMPILE_MARKER* ]]
printf '%s\n' 'COMPONENT(Request& context) { UCE_CALL_COMPILE_MARKER }' >"$site/broken-call.uce"
response=$(request GET mode=call)
[[ "$(body_of "$response")" == *UCE_CALL_COMPILE_MARKER* ]]
[[ "$(body_of "$response")" != *"function 'COMPONENT' not found"* ]]
printf '%s\n' 'COMPONENT(Request& context) { print("recovered"); }' >"$site/child.uce"
response=$(request GET)
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:recovered" ]]
stop_server
write_settings 0 0 0
start_server
printf '%s\n' 'COMPONENT(Request& context) { UCE_HIDDEN_COMPILE_MARKER }' >"$site/child.uce"
response=$(request GET)
body=$(body_of "$response")
[[ "$(status_of "$response")" == 500 ]]
[[ "$body" == *"component not found: child"* ]]
[[ "$body" != *UCE_HIDDEN_COMPILE_MARKER* ]]
stop_server
printf '%s\n' 'COMPONENT(Request& context) { print("good-v1"); }' >"$site/child.uce"
write_settings 1 1 1
start_server
for _ in $(seq 1 100); do
response=$(request GET)
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v1" ]] && break
sleep 0.1
done
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v1" ]]
cache="$(scripts/unit_cache_directory "$work")$(realpath "$site")"
for artifact in "$cache/child.uce.wasm" "$cache/child.uce.cwasm" "$cache/child.uce.wasm.source-map"; do [[ -s "$artifact" ]]; done
before_hashes=$(sha256sum "$cache/child.uce.wasm" "$cache/child.uce.cwasm" "$cache/child.uce.wasm.source-map")
printf '%s\n' 'COMPONENT(Request& context) { UCE_STALE_COMPILE_MARKER }' >"$site/child.uce"
for _ in $(seq 1 30); do
response=$(request GET)
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v1" ]]
sleep 0.1
done
[[ -s "$cache/child.uce.compile.txt" ]]
[[ "$(sha256sum "$cache/child.uce.wasm" "$cache/child.uce.cwasm" "$cache/child.uce.wasm.source-map")" == "$before_hashes" ]]
stop_server
start_server
response=$(request GET)
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v1" ]] || { echo "last-known-good artifact did not survive worker restart: $response" >&2; exit 1; }
printf '%s\n' 'COMPONENT(Request& context) { print("permission-repair"); }' >"$site/child.uce"
chmod 000 "$site/child.uce"
for _ in $(seq 1 100); do
grep -q "source file is not readable" "$cache/child.uce.compile.txt" 2>/dev/null && break
sleep 0.05
done
[[ "$(sha256sum "$cache/child.uce.wasm" "$cache/child.uce.cwasm" "$cache/child.uce.wasm.source-map")" == "$before_hashes" ]]
response=$(request GET)
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v1" ]] || { echo "unreadable source removed last-known-good service: $response" >&2; exit 1; }
chmod 644 "$site/child.uce"
printf '%s\n' 'COMPONENT(Request& context) { print("good-v2"); }' >"$site/child.uce"
for _ in $(seq 1 200); do
response=$(request GET)
if [[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v2" ]]; then break; fi
sleep 0.1
done
[[ "$(status_of "$response")" == 200 && "$(body_of "$response")" == "driver:good-v2" ]] || { echo "repaired unit was not published: $response" >&2; exit 1; }
echo "dynamic compile failure handling passed"