118 lines
4.6 KiB
Bash
Executable File
118 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
API_BASE="${API_BASE:-http://127.0.0.1:5084}"
|
|
ADMIN_SESSION_TOKEN="${ADMIN_SESSION_TOKEN:-}"
|
|
|
|
fail() {
|
|
printf 'smoke failed: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_command() {
|
|
command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
|
|
}
|
|
|
|
http_json() {
|
|
local url="$1"
|
|
shift || true
|
|
curl -fsS "$@" "$url"
|
|
}
|
|
|
|
json_value() {
|
|
local expression="$1"
|
|
node -e "
|
|
let data = '';
|
|
process.stdin.on('data', chunk => data += chunk);
|
|
process.stdin.on('end', () => {
|
|
const root = JSON.parse(data);
|
|
const value = (${expression})(root);
|
|
if (typeof value === 'object') {
|
|
console.log(JSON.stringify(value));
|
|
} else {
|
|
console.log(value ?? '');
|
|
}
|
|
});
|
|
"
|
|
}
|
|
|
|
require_command curl
|
|
require_command node
|
|
|
|
printf '== VTuber Awards local smoke ==\n'
|
|
printf 'API: %s\n' "$API_BASE"
|
|
|
|
printf '\n[1/6] health\n'
|
|
http_json "$API_BASE/api/health" >/tmp/vtsa-smoke-health.json
|
|
cat /tmp/vtsa-smoke-health.json
|
|
printf '\n'
|
|
|
|
printf '\n[2/6] database health\n'
|
|
http_json "$API_BASE/api/health/database" >/tmp/vtsa-smoke-db.json
|
|
cat /tmp/vtsa-smoke-db.json
|
|
printf '\n'
|
|
can_connect="$(json_value 'root => root.canConnect' </tmp/vtsa-smoke-db.json)"
|
|
if [[ "$can_connect" != "true" ]]; then
|
|
fail "database cannot connect"
|
|
fi
|
|
|
|
printf '\n[3/6] public overview\n'
|
|
http_json "$API_BASE/api/public/overview" >/tmp/vtsa-smoke-overview.json
|
|
year="$(json_value 'root => root.year' </tmp/vtsa-smoke-overview.json)"
|
|
season_id="$(json_value 'root => root.seasonId' </tmp/vtsa-smoke-overview.json)"
|
|
printf 'current season: year=%s seasonId=%s\n' "$year" "$season_id"
|
|
if [[ -z "$year" || -z "$season_id" ]]; then
|
|
fail "public overview did not expose current season"
|
|
fi
|
|
|
|
printf '\n[4/6] public category structure\n'
|
|
http_json "$API_BASE/api/public/seasons/$year/categories" >/tmp/vtsa-smoke-categories.json
|
|
category_count="$(json_value 'root => root.categories?.length ?? 0' </tmp/vtsa-smoke-categories.json)"
|
|
legacy_count="$(json_value 'root => (root.categories ?? []).filter(c => ["Main Awards", "Discovery", "Gaming", "Creative", "Performance", "Entertainment", "Community", "Collab"].includes(c.groupName)).length' </tmp/vtsa-smoke-categories.json)"
|
|
main_group_count="$(json_value 'root => new Set((root.categories ?? []).map(c => c.groupName)).size' </tmp/vtsa-smoke-categories.json)"
|
|
printf 'categories=%s mainGroups=%s legacyParents=%s\n' "$category_count" "$main_group_count" "$legacy_count"
|
|
if [[ "$category_count" == "0" ]]; then
|
|
fail "public categories are empty"
|
|
fi
|
|
if [[ "$legacy_count" != "0" ]]; then
|
|
fail "legacy parent labels are still exposed publicly"
|
|
fi
|
|
|
|
printf '\n[5/6] admin endpoints (optional)\n'
|
|
if [[ -z "$ADMIN_SESSION_TOKEN" ]]; then
|
|
printf 'skipped: set ADMIN_SESSION_TOKEN to check admin season/team endpoints\n'
|
|
else
|
|
auth_header=( -H "Authorization: Bearer $ADMIN_SESSION_TOKEN" )
|
|
http_json "$API_BASE/api/admin/seasons" "${auth_header[@]}" >/tmp/vtsa-smoke-admin-seasons.json
|
|
admin_season_count="$(json_value 'root => Array.isArray(root) ? root.length : (root.seasons?.length ?? 0)' </tmp/vtsa-smoke-admin-seasons.json)"
|
|
printf 'admin seasons=%s\n' "$admin_season_count"
|
|
if [[ "$admin_season_count" == "0" ]]; then
|
|
fail "admin seasons endpoint returned no seasons"
|
|
fi
|
|
|
|
http_json "$API_BASE/api/admin/seasons/$season_id" "${auth_header[@]}" >/tmp/vtsa-smoke-admin-detail.json
|
|
voting_groups="$(json_value 'root => root.votingWorkspace?.categories?.length ?? 0' </tmp/vtsa-smoke-admin-detail.json)"
|
|
subcategory_templates="$(json_value 'root => root.subcategoryTemplates?.length ?? 0' </tmp/vtsa-smoke-admin-detail.json)"
|
|
printf 'admin detail: votingCategories=%s subcategoryTemplates=%s\n' "$voting_groups" "$subcategory_templates"
|
|
if [[ "$voting_groups" == "0" || "$subcategory_templates" == "0" ]]; then
|
|
fail "admin detail is missing voting workspace or subcategory templates"
|
|
fi
|
|
|
|
http_json "$API_BASE/api/admin/team" "${auth_header[@]}" >/tmp/vtsa-smoke-admin-team.json
|
|
permissions="$(json_value 'root => (root.permissions ?? []).map(p => p.key).sort().join(",")' </tmp/vtsa-smoke-admin-team.json)"
|
|
printf 'permission keys=%s\n' "$permissions"
|
|
node -e '
|
|
const fs = require("fs");
|
|
const root = JSON.parse(fs.readFileSync("/tmp/vtsa-smoke-admin-team.json", "utf8"));
|
|
const keys = new Set((root.permissions ?? []).map(item => item.key));
|
|
const required = ["dashboard","years","nominations","categories","candidates","clips","content","risk","audit","analytics","voting","winners","settings","team"];
|
|
const missing = required.filter(key => !keys.has(key));
|
|
if (missing.length) {
|
|
console.error(`missing permission keys: ${missing.join(", ")}`);
|
|
process.exit(1);
|
|
}
|
|
'
|
|
fi
|
|
|
|
printf '\n[6/6] smoke complete\n'
|