Files
compose-anything/builds/cube-sandbox/smoke-test.sh
T
2026-04-28 10:05:39 +08:00

105 lines
4.7 KiB
Bash

#!/usr/bin/env bash
# Smoke test for a running CubeSandbox stack.
#
# Run from the WSL2 host or from inside the cube-sandbox container - both work
# because the container uses network_mode: host.
#
# Steps:
# 1. Health-check all CubeSandbox services
# 2. (Optional, slow) Build a code-interpreter template from a public image
# 3. Create a sandbox via the E2B-compatible REST API, run a tiny payload,
# then destroy it
#
# Skip the slow template-build step with: SKIP_TEMPLATE_BUILD=1 ./smoke-test.sh
set -euo pipefail
# cubemastercli is installed to a non-standard prefix; add it to PATH so this
# script works both when run inside the container and from the WSL2 host.
export PATH="/usr/local/services/cubetoolbox/CubeMaster/bin:${PATH:-}"
CUBE_API="${CUBE_API:-http://127.0.0.1:3000}"
CUBE_MASTER="${CUBE_MASTER:-http://127.0.0.1:8089}"
CUBE_NETAGENT="${CUBE_NETAGENT:-http://127.0.0.1:19090}"
ok() { printf '\033[1;32m[ OK ]\033[0m %s\n' "$*"; }
fail() { printf '\033[1;31m[FAIL]\033[0m %s\n' "$*" >&2; exit 1; }
info() { printf '\033[1;36m[INFO]\033[0m %s\n' "$*"; }
#-------------------------------------------------------------------
# 1. Health checks (matches what install.sh's quickcheck.sh verifies)
#-------------------------------------------------------------------
info "Health: CubeAPI"
curl -fsS "${CUBE_API}/health" >/dev/null && ok "CubeAPI /health" || fail "CubeAPI /health"
echo
info "Health: CubeMaster"
curl -fsS "${CUBE_MASTER}/notify/health" >/dev/null && ok "CubeMaster /notify/health" || fail "CubeMaster /notify/health"
info "Health: network-agent"
curl -fsS "${CUBE_NETAGENT}/healthz" >/dev/null && ok "network-agent /healthz" || fail "network-agent /healthz"
curl -fsS "${CUBE_NETAGENT}/readyz" >/dev/null && ok "network-agent /readyz" || fail "network-agent /readyz"
#-------------------------------------------------------------------
# 2. Optional: build a sandbox template
#-------------------------------------------------------------------
TEMPLATE_ID="${CUBE_TEMPLATE_ID:-}"
if [ -z "$TEMPLATE_ID" ] && [ "${SKIP_TEMPLATE_BUILD:-0}" != "1" ]; then
info "No CUBE_TEMPLATE_ID provided; building one from ccr.ccs.tencentyun.com/ags-image/sandbox-code:latest"
info "(this can take 5-15 minutes; set SKIP_TEMPLATE_BUILD=1 to skip and only run health checks)"
if ! command -v cubemastercli >/dev/null 2>&1; then
# cubemastercli lives inside the container; exec into it
CUBE_CTR="$(docker compose ps -q cube-sandbox 2>/dev/null || true)"
[ -z "$CUBE_CTR" ] && fail "cube-sandbox container not running and cubemastercli not on PATH"
CMC="docker exec -i $CUBE_CTR cubemastercli"
else
CMC="cubemastercli"
fi
JOB_OUT="$($CMC tpl create-from-image \
--image ccr.ccs.tencentyun.com/ags-image/sandbox-code:latest \
--writable-layer-size 1G \
--expose-port 49999 \
--expose-port 49983 \
--probe 49999 2>&1)"
echo "$JOB_OUT"
JOB_ID="$(echo "$JOB_OUT" | grep -oE 'job_id[=: ]+[A-Za-z0-9_-]+' | head -1 | awk '{print $NF}')"
[ -z "$JOB_ID" ] && fail "could not parse job_id from output"
info "Watching job $JOB_ID ..."
$CMC tpl watch --job-id "$JOB_ID"
# Extract template_id from the create-from-image output (it's on the first few
# lines) rather than re-querying the list — list ordering is not guaranteed and
# could return a FAILED entry as the last line.
TEMPLATE_ID="$(echo "$JOB_OUT" | grep -E '\btemplate_id\b' | head -1 | awk '{print $NF}')"
[ -z "$TEMPLATE_ID" ] && fail "could not determine template id after build"
ok "Template built: $TEMPLATE_ID"
elif [ -z "$TEMPLATE_ID" ]; then
info "Skipping sandbox lifecycle test (no CUBE_TEMPLATE_ID and SKIP_TEMPLATE_BUILD=1)"
ok "Health checks passed - CubeSandbox stack is up"
exit 0
fi
#-------------------------------------------------------------------
# 3. Create -> inspect -> destroy a sandbox via REST
#-------------------------------------------------------------------
info "Creating sandbox from template $TEMPLATE_ID ..."
RESP="$(curl -fsS -X POST "${CUBE_API}/sandboxes" \
-H 'Authorization: Bearer dummy' \
-H 'Content-Type: application/json' \
-d "{\"templateID\":\"${TEMPLATE_ID}\"}")"
SANDBOX_ID="$(echo "$RESP" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("sandboxID",""))')"
[ -z "$SANDBOX_ID" ] && fail "no sandboxID in response: $RESP"
ok "Created sandbox $SANDBOX_ID"
info "Inspecting sandbox ..."
curl -fsS "${CUBE_API}/sandboxes/${SANDBOX_ID}" -H 'Authorization: Bearer dummy' \
| python3 -m json.tool
ok "Sandbox is queryable"
info "Destroying sandbox ..."
curl -fsS -X DELETE "${CUBE_API}/sandboxes/${SANDBOX_ID}" -H 'Authorization: Bearer dummy' >/dev/null
ok "Sandbox destroyed"
ok "All smoke tests passed"