Files
2026-07-13 13:12:00 +08:00

131 lines
4.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Backend-only local smoke test.
#
# Validates the Python backend and local API server from THIS checkout without
# building the web UI, configuring provider credentials, creating sessions, or
# running agents. Useful for a quick server/API smoke check on your working
# copy or current `main`.
#
# Everything (toolchain, project venv, config, data, database, artifacts, logs,
# caches) lives under one disposable runtime directory that is removed on exit,
# so the run never touches your real ~/.omnigent, ~/.config / ~/Library, or
# package caches.
#
# Usage:
# scripts/backend-smoke.sh # uses port 18080
# PORT=18090 scripts/backend-smoke.sh # override the port if 18080 is busy
#
# Requires: bash, python3 (3.12+), git, curl, and network access to PyPI. No
# provider credentials needed. Works on Linux and macOS.
set -euo pipefail
PORT="${PORT:-18080}"
repo_root="$(git -C "$(dirname "$0")" rev-parse --show-toplevel)"
runtime_root="$(mktemp -d "${TMPDIR:-/tmp}/omnigent_backend_XXXXXX")"
toolchain_venv="$runtime_root/toolchain_venv"
project_venv="$runtime_root/project_venv"
runtime_home="$runtime_root/home"
runtime_tmp="$runtime_root/tmp"
runtime_config="$runtime_root/config"
runtime_data="$runtime_root/data"
runtime_cache="$runtime_root/cache"
runtime_logs="$runtime_root/logs"
runtime_artifacts="$runtime_root/artifacts"
runtime_db="$runtime_data/omnigent/chat.db"
server_pid=""
cleanup() {
if [ -n "$server_pid" ]; then
kill -TERM "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
fi
rm -rf "$runtime_root"
}
trap cleanup EXIT
mkdir -p \
"$runtime_home" "$runtime_tmp" \
"$runtime_config/xdg" "$runtime_data/xdg" "$runtime_cache/xdg" \
"$runtime_cache/pip" "$runtime_cache/uv" \
"$runtime_logs" "$runtime_artifacts" \
"$(dirname "$runtime_db")" \
"$runtime_config/omnigent" "$runtime_data/omnigent"
# Isolated environment shared by every step. HOME is the primary isolation
# lever (it covers ~/.config on Linux and ~/Library on macOS); the explicit
# UV_/PIP_/OMNIGENT_ overrides pin the toolchain and app state regardless of
# OS. XDG_* are set so an XDG var already exported in the caller's shell can't
# redirect state back to the real home. OMNIGENT_SKIP_WEB_UI leaves the server
# in API-only mode (no web UI build); UV_PROJECT_ENVIRONMENT points uv at the
# throwaway project venv; UV_PYTHON_DOWNLOAD=never keeps uv from fetching
# interpreters.
env_vars=(
"HOME=$runtime_home"
"TMPDIR=$runtime_tmp"
"XDG_CONFIG_HOME=$runtime_config/xdg"
"XDG_DATA_HOME=$runtime_data/xdg"
"XDG_CACHE_HOME=$runtime_cache/xdg"
"PIP_CACHE_DIR=$runtime_cache/pip"
"UV_CACHE_DIR=$runtime_cache/uv"
"UV_PROJECT_ENVIRONMENT=$project_venv"
"UV_PYTHON_DOWNLOAD=never"
"OMNIGENT_CONFIG_HOME=$runtime_config/omnigent"
"OMNIGENT_DATA_DIR=$runtime_data/omnigent"
"OMNIGENT_DATABASE_URI=sqlite:///$runtime_db"
"OMNIGENT_SKIP_WEB_UI=true"
)
echo "Runtime dir: $runtime_root"
echo "Checkout: $repo_root"
echo "Installing uv into a throwaway toolchain venv..."
python3 -m venv "$toolchain_venv"
python3 -m venv "$project_venv"
env "${env_vars[@]}" "$toolchain_venv/bin/python" -m pip install --quiet "uv>=0.11.8"
echo "Syncing project dependencies (uv sync --frozen)..."
( cd "$repo_root" && env "${env_vars[@]}" "$toolchain_venv/bin/uv" sync --frozen )
echo "Starting backend server on 127.0.0.1:$PORT (API-only)..."
nohup env "${env_vars[@]}" \
"$project_venv/bin/omnigent" server \
--host 127.0.0.1 \
--port "$PORT" \
--database-uri "sqlite:///$runtime_db" \
--artifact-location "$runtime_artifacts" \
< /dev/null > "$runtime_logs/omnigent_server.log" 2>&1 &
server_pid="$!"
echo "Waiting for /health..."
ready=""
for _ in {1..60}; do
code="$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 \
"http://127.0.0.1:${PORT}/health" || true)"
if [ "$code" = "200" ]; then ready=1; break; fi
sleep 0.5
done
if [ -z "$ready" ]; then
echo "ERROR: server did not become healthy in time; last log lines:" >&2
tail -n 40 "$runtime_logs/omnigent_server.log" >&2 || true
exit 1
fi
echo "Smoke-testing API endpoints (expect 200):"
status=0
for path in / /health /docs /v1/agents /v1/sessions; do
code="$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 \
"http://127.0.0.1:${PORT}${path}")"
printf " %-14s %s\n" "$path" "$code"
[ "$code" = "200" ] || status=1
done
if [ "$status" -eq 0 ]; then
echo "OK: all endpoints returned 200."
else
echo "FAIL: one or more endpoints did not return 200." >&2
fi
exit "$status"