142 lines
8.0 KiB
Bash
Executable File
142 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
cd "$(dirname "$0")/.."
|
|
|
|
raw_calls=$(grep -En -- '(->|\.)call\(' src/wasm/worker.cpp)
|
|
if [[ $(wc -l <<<"$raw_calls") -ne 1 || "$raw_calls" != *'return(func.call(context, args));'* ]]; then
|
|
echo "raw Wasmtime call bypasses call_guest(): $raw_calls" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "${1:-}" == "--static-only" ]]; then
|
|
echo "wasm invocation timeout static call gate passed"
|
|
exit 0
|
|
fi
|
|
|
|
settings_file="${UCE_SETTINGS_FILE:-/etc/uce/settings.cfg}"
|
|
site_directory="${UCE_TEST_SITE_DIRECTORY:-site}"
|
|
socket_path="${UCE_CLI_SOCKET:-/run/uce/cli.sock}"
|
|
bin_directory="${BIN_DIRECTORY:-/tmp/uce/work}"
|
|
if [[ -r "$settings_file" ]]; then
|
|
[[ -n "${UCE_TEST_SITE_DIRECTORY:-}" ]] || site_directory=$(awk -F= '/^[[:space:]]*SITE_DIRECTORY[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' "$settings_file")
|
|
[[ -n "${UCE_CLI_SOCKET:-}" ]] || socket_path=$(awk -F= '/^[[:space:]]*CLI_SOCKET_PATH[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' "$settings_file")
|
|
[[ -n "${BIN_DIRECTORY:-}" ]] || bin_directory=$(awk -F= '/^[[:space:]]*BIN_DIRECTORY[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' "$settings_file")
|
|
invocation_ms=$(awk -F= '/^[[:space:]]*WASM_INVOCATION_TIMEOUT_MS[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' "$settings_file")
|
|
cli_worker_count=$(awk -F= '/^[[:space:]]*CLI_WORKER_COUNT[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); value=$2} END{print value}' "$settings_file")
|
|
fi
|
|
site_directory="${site_directory:-site}"
|
|
socket_path="${socket_path:-/run/uce/cli.sock}"
|
|
bin_directory="${bin_directory:-/tmp/uce/work}"
|
|
invocation_ms="${invocation_ms:-30000}"
|
|
cli_worker_count="${cli_worker_count:-0}"
|
|
curl_transport=(--unix-socket "$socket_path")
|
|
test_base_url="http://localhost"
|
|
if (( cli_worker_count > 0 )); then
|
|
test_http_host="${UCE_TEST_HTTP_HOST:-uce.openfu.com}"
|
|
curl_transport=(--resolve "$test_http_host:80:127.0.0.1")
|
|
test_base_url="http://$test_http_host"
|
|
fi
|
|
test_name="invocation-timeout-test-$$"
|
|
source_dir="$site_directory/$test_name"
|
|
pid_file="/tmp/uce-$test_name-worker"
|
|
cache_dir=""
|
|
body_file="/tmp/uce-$test_name-body"
|
|
|
|
cleanup() {
|
|
rm -rf "$source_dir"
|
|
[[ -z "$cache_dir" ]] || rm -rf "$cache_dir"
|
|
rm -f "$pid_file" "$body_file"
|
|
}
|
|
trap cleanup EXIT
|
|
mkdir -p "$source_dir"
|
|
cache_dir="$(scripts/unit_cache_directory "$bin_directory")$(realpath "$source_dir")"
|
|
|
|
printf '%s\n' \
|
|
'void timeout_test_run(Request& context) {' \
|
|
' if(context.get["warm"] == "1") { print("warm"); return; }' \
|
|
" file_put_contents(\"$pid_file\", std::to_string(request_perf()[\"worker_pid\"].to_u64()));" \
|
|
' while(true) time_precise();' \
|
|
'}' \
|
|
'CLI(Request& context) { timeout_test_run(context); }' \
|
|
'RENDER(Request& context) { timeout_test_run(context); }' >"$source_dir/hostcall-loop.uce"
|
|
printf '%s\n' \
|
|
'void timeout_test_run(Request& context) {' \
|
|
' if(context.get["warm"] == "1") { print("warm"); return; }' \
|
|
' if(context.get["quick"] == "1") { print(shell_exec("printf quick")); return; }' \
|
|
' if(context.get["status"] == "1") { DValue spec; spec["cmd"] = "exit 7"; spec["timeout_ms"] = (f64)500; print(shell_exec(spec)["exit_code"].to_u64()); return; }' \
|
|
' if(context.get["zero"] == "1") { DValue spec; spec["cmd"] = "printf zero"; spec["timeout_ms"] = (f64)0; print(shell_exec(spec)["stdout"].to_string()); return; }' \
|
|
' if(context.get["job"] == "1") { DValue spec; spec["cmd"] = "sleep 2"; spec["timeout_ms"] = (f64)5000; u64 job = shell_spawn(spec); f64 started = time_precise(); job_await(job, 300); u64 elapsed = (u64)((time_precise() - started) * 1000); job_cancel(job); print(elapsed); return; }' \
|
|
" file_put_contents(\"$pid_file\", std::to_string(request_perf()[\"worker_pid\"].to_u64()));" \
|
|
' print(shell_exec("printf shell-start; sleep 60 & printf shell-end"));' \
|
|
'}' \
|
|
'CLI(Request& context) { timeout_test_run(context); }' \
|
|
'RENDER(Request& context) { timeout_test_run(context); }' >"$source_dir/legacy-shell.uce"
|
|
printf '%s\n' \
|
|
'void timeout_test_run(Request& context) {' \
|
|
' if(context.get["warm"] == "1") { print("warm"); return; }' \
|
|
" file_put_contents(\"$pid_file\", std::to_string(request_perf()[\"worker_pid\"].to_u64()));" \
|
|
' while(true) sleep(60);' \
|
|
' print("sleep-end");' \
|
|
'}' \
|
|
'CLI(Request& context) { timeout_test_run(context); }' \
|
|
'RENDER(Request& context) { timeout_test_run(context); }' >"$source_dir/sleep.uce"
|
|
printf '%s\n' \
|
|
'void timeout_test_run(Request& context) { print(request_perf()["worker_pid"].to_u64(), "|health"); }' \
|
|
'CLI(Request& context) { timeout_test_run(context); }' \
|
|
'RENDER(Request& context) { timeout_test_run(context); }' >"$source_dir/health.uce"
|
|
|
|
max_seconds=$(( (invocation_ms + 15000) / 1000 ))
|
|
(( max_seconds >= 10 )) || max_seconds=10
|
|
|
|
request() {
|
|
local unit="$1"
|
|
curl -sS --max-time "$max_seconds" -o "$body_file" -w '%{http_code}' "${curl_transport[@]}" "$test_base_url/$test_name/$unit"
|
|
}
|
|
|
|
same_worker_health() {
|
|
local expected_pid="$1"
|
|
kill -0 "$expected_pid" 2>/dev/null || return 1
|
|
local health
|
|
health=$(curl -sS --max-time 5 --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/health.uce")
|
|
[[ "$health" =~ ^[0-9]+\|health$ ]]
|
|
}
|
|
|
|
curl -sS --max-time "$max_seconds" --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/hostcall-loop.uce?warm=1" >/dev/null
|
|
curl -sS --max-time "$max_seconds" --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/legacy-shell.uce?warm=1" >/dev/null
|
|
curl -sS --max-time "$max_seconds" --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/sleep.uce?warm=1" >/dev/null
|
|
curl -sS --max-time "$max_seconds" --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/health.uce" >/dev/null
|
|
quick=$(curl -sS --max-time 5 --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/legacy-shell.uce?quick=1")
|
|
[[ "$quick" == quick ]] || { echo "quick legacy shell returned: $quick" >&2; exit 1; }
|
|
exit_status=$(curl -sS --max-time 5 --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/legacy-shell.uce?status=1")
|
|
[[ "$exit_status" == 7 ]] || { echo "structured shell lost exit status: $exit_status" >&2; exit 1; }
|
|
zero_timeout=$(curl -sS --max-time 5 --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/legacy-shell.uce?zero=1")
|
|
[[ "$zero_timeout" == zero ]] || { echo "structured shell zero-timeout default changed: $zero_timeout" >&2; exit 1; }
|
|
job_elapsed=$(curl -sS --max-time 5 --fail-with-body "${curl_transport[@]}" "$test_base_url/$test_name/legacy-shell.uce?job=1")
|
|
[[ "$job_elapsed" =~ ^[0-9]+$ && "$job_elapsed" -ge 200 && "$job_elapsed" -lt 500 ]] || { echo "job_await two-call duration was ${job_elapsed}ms" >&2; exit 1; }
|
|
|
|
for unit in hostcall-loop.uce legacy-shell.uce sleep.uce; do
|
|
rm -f "$pid_file"
|
|
started_ns=$(date +%s%N)
|
|
status=$(request "$unit")
|
|
elapsed_ms=$(( ($(date +%s%N) - started_ns) / 1000000 ))
|
|
[[ "$status" == "500" ]] || { echo "$unit returned HTTP $status" >&2; exit 1; }
|
|
if [[ "$unit" == legacy-shell.uce ]]; then
|
|
if (( invocation_ms <= 5000 )); then
|
|
grep -q 'UCE_INVOCATION_TIMEOUT:' "$body_file" || { echo "$unit lacked invocation-timeout classification" >&2; exit 1; }
|
|
expected_ms=$invocation_ms
|
|
else
|
|
grep -q 'UCE_HOSTCALL_TIMEOUT:' "$body_file" || { echo "$unit lacked hostcall-timeout classification" >&2; exit 1; }
|
|
expected_ms=5000
|
|
fi
|
|
else
|
|
grep -q 'UCE_INVOCATION_TIMEOUT:' "$body_file" || { echo "$unit lacked invocation-timeout classification: $(cat "$body_file")" >&2; exit 1; }
|
|
expected_ms=$invocation_ms
|
|
fi
|
|
(( elapsed_ms >= expected_ms - 1000 && elapsed_ms <= expected_ms + 3000 )) || { echo "$unit completed in ${elapsed_ms}ms; expected about ${expected_ms}ms" >&2; exit 1; }
|
|
grep -q "$unit" "$body_file" || { echo "$unit lacked a source-mapped trace" >&2; exit 1; }
|
|
[[ -s "$pid_file" ]] || { echo "$unit did not record its worker" >&2; exit 1; }
|
|
worker_pid=$(<"$pid_file")
|
|
same_worker_health "$worker_pid" || { echo "worker $worker_pid did not survive $unit" >&2; exit 1; }
|
|
done
|
|
|
|
echo "wasm invocation timeout passed (absolute ${invocation_ms}ms; sleep and process hostcalls bounded)"
|