feat: harden runtime import and frontend verification workflows
This commit is contained in:
109
scripts/acceptance/verify_accounts_admin_ui.sh
Normal file
109
scripts/acceptance/verify_accounts_admin_ui.sh
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
# shellcheck disable=SC1091
|
||||
source "$ROOT_DIR/scripts/acceptance/route_acceptance_lib.sh"
|
||||
|
||||
ACCOUNTS_ACCEPTANCE_ROOT="${ACCOUNTS_ACCEPTANCE_ROOT:-$ROOT_DIR/artifacts/frontend-acceptance-matrix}"
|
||||
TS="${TS:-$(timestamp_token)}"
|
||||
ARTIFACT_DIR="${ARTIFACT_DIR:-$ACCOUNTS_ACCEPTANCE_ROOT/${TS}_accounts_admin_ui}"
|
||||
|
||||
ACCOUNTS_PAGE_URL="${ACCOUNTS_PAGE_URL:-https://sub.tksea.top/portal/admin/accounts.html}"
|
||||
ACCOUNT_ID="${ACCOUNT_ID:-}"
|
||||
HOST_ID_FILTER="${HOST_ID_FILTER:-}"
|
||||
PROVIDER_ID_FILTER="${PROVIDER_ID_FILTER:-}"
|
||||
BINDING_STATE_FILTER="${BINDING_STATE_FILTER:-}"
|
||||
LIMIT="${LIMIT:-50}"
|
||||
ALLOW_EMPTY_ACCOUNTS="${ALLOW_EMPTY_ACCOUNTS:-0}"
|
||||
|
||||
require_var CRM_BASE
|
||||
crm_auth_init
|
||||
ensure_artifact_dir
|
||||
curl_status_to_file "$ACCOUNTS_PAGE_URL" "$ARTIFACT_DIR/00-accounts-admin.html"
|
||||
|
||||
query="$(
|
||||
python3 - "$HOST_ID_FILTER" "$PROVIDER_ID_FILTER" "$BINDING_STATE_FILTER" "$LIMIT" <<'PY'
|
||||
import sys
|
||||
from urllib.parse import urlencode
|
||||
|
||||
host_id, provider_id, binding_state, limit = sys.argv[1:5]
|
||||
params = {}
|
||||
if host_id:
|
||||
params["host_id"] = host_id
|
||||
if provider_id:
|
||||
params["provider_id"] = provider_id
|
||||
if binding_state:
|
||||
params["binding_state"] = binding_state
|
||||
if limit:
|
||||
params["limit"] = limit
|
||||
print(urlencode(params))
|
||||
PY
|
||||
)"
|
||||
|
||||
list_path="/api/provider-accounts"
|
||||
if [[ -n "$query" ]]; then
|
||||
list_path="$list_path?$query"
|
||||
fi
|
||||
|
||||
save_json 01-provider-accounts "$(crm_curl_json GET "$list_path")"
|
||||
|
||||
if [[ -z "$ACCOUNT_ID" ]]; then
|
||||
ACCOUNT_ID="$(
|
||||
python3 - "$ARTIFACT_DIR/01-provider-accounts.json" "$ALLOW_EMPTY_ACCOUNTS" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
payload = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
allow_empty = sys.argv[2] == "1"
|
||||
items = payload.get("provider_accounts") or []
|
||||
if not items:
|
||||
if allow_empty:
|
||||
raise SystemExit(3)
|
||||
raise SystemExit(2)
|
||||
first = items[0]
|
||||
print(first.get("id") or "")
|
||||
PY
|
||||
)" || ACCOUNT_ID=""
|
||||
fi
|
||||
|
||||
if [[ -n "$ACCOUNT_ID" ]]; then
|
||||
save_json 02-binding-candidates "$(crm_curl_json GET "/api/provider-accounts/$ACCOUNT_ID/binding-candidates")"
|
||||
fi
|
||||
|
||||
python3 - "$ARTIFACT_DIR" "$ACCOUNT_ID" "$ALLOW_EMPTY_ACCOUNTS" >"$ARTIFACT_DIR/99-summary.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
art_dir = Path(sys.argv[1])
|
||||
account_id = sys.argv[2]
|
||||
allow_empty = sys.argv[3] == "1"
|
||||
|
||||
page = (art_dir / "00-accounts-admin.html").read_text(encoding="utf-8")
|
||||
accounts = json.loads((art_dir / "01-provider-accounts.json").read_text(encoding="utf-8")).get("provider_accounts") or []
|
||||
|
||||
assert "Provider Accounts Admin" in page
|
||||
if not accounts and not allow_empty:
|
||||
raise AssertionError("provider_accounts list is empty")
|
||||
|
||||
summary = {
|
||||
"page_title_seen": "Provider Accounts Admin" in page,
|
||||
"account_count": len(accounts),
|
||||
"selected_account_id": account_id or "",
|
||||
}
|
||||
|
||||
if accounts:
|
||||
first = accounts[0]
|
||||
summary["first_account_provider_id"] = first.get("provider_id")
|
||||
summary["first_account_status"] = first.get("status") or first.get("account_status")
|
||||
summary["first_account_binding_state"] = first.get("binding_state")
|
||||
|
||||
if account_id:
|
||||
candidates = json.loads((art_dir / "02-binding-candidates.json").read_text(encoding="utf-8")).get("binding_candidates") or []
|
||||
summary["binding_candidate_count"] = len(candidates)
|
||||
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
cat "$ARTIFACT_DIR/99-summary.json"
|
||||
112
scripts/acceptance/verify_frontend_acceptance_matrix.sh
Normal file
112
scripts/acceptance/verify_frontend_acceptance_matrix.sh
Normal file
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
MATRIX_ROOT="${FRONTEND_MATRIX_ROOT:-$ROOT_DIR/artifacts/frontend-acceptance-matrix}"
|
||||
TS="${TS:-$(date +%s)}"
|
||||
MATRIX_DIR="${MATRIX_DIR:-$MATRIX_ROOT/${TS}_frontend_matrix}"
|
||||
|
||||
BROWSER_SMOKE_SCRIPT="${BROWSER_SMOKE_SCRIPT:-$ROOT_DIR/scripts/test/verify_frontend_smoke.sh}"
|
||||
PORTAL_ACCEPTANCE_SCRIPT="${PORTAL_ACCEPTANCE_SCRIPT:-$ROOT_DIR/scripts/acceptance/verify_portal_catalog_ui.sh}"
|
||||
PUBLIC_PORTAL_BROWSER_SCRIPT="${PUBLIC_PORTAL_BROWSER_SCRIPT:-$ROOT_DIR/scripts/acceptance/verify_public_portal_browser.sh}"
|
||||
ACCOUNTS_ACCEPTANCE_SCRIPT="${ACCOUNTS_ACCEPTANCE_SCRIPT:-$ROOT_DIR/scripts/acceptance/verify_accounts_admin_ui.sh}"
|
||||
ROUTE_MATRIX_SCRIPT="${ROUTE_MATRIX_SCRIPT:-$ROOT_DIR/scripts/acceptance/verify_route_acceptance_matrix.sh}"
|
||||
PROVIDER_ADMIN_SCRIPT="${PROVIDER_ADMIN_SCRIPT:-$ROOT_DIR/scripts/acceptance/verify_provider_admin_actions.sh}"
|
||||
RUN_PUBLIC_PORTAL_BROWSER="${RUN_PUBLIC_PORTAL_BROWSER:-0}"
|
||||
|
||||
mkdir -p "$MATRIX_DIR"
|
||||
|
||||
run_step() {
|
||||
local name="$1"
|
||||
shift
|
||||
echo "==> $name"
|
||||
ARTIFACT_DIR="$MATRIX_DIR/$name" "$@" >"$MATRIX_DIR/$name.stdout.txt" 2>"$MATRIX_DIR/$name.stderr.txt"
|
||||
}
|
||||
|
||||
mark_skip() {
|
||||
local name="$1"
|
||||
local reason="$2"
|
||||
printf '%s\n' "$reason" >"$MATRIX_DIR/$name.skip.txt"
|
||||
}
|
||||
|
||||
has_crm_auth() {
|
||||
[[ -n "${CRM_ADMIN_TOKEN:-}" ]] || { [[ -n "${CRM_ADMIN_USERNAME:-}" ]] && [[ -n "${CRM_ADMIN_PASSWORD:-}" ]]; }
|
||||
}
|
||||
|
||||
run_step browser_smoke bash "$BROWSER_SMOKE_SCRIPT"
|
||||
run_step portal_catalog bash "$PORTAL_ACCEPTANCE_SCRIPT"
|
||||
|
||||
if [[ "$RUN_PUBLIC_PORTAL_BROWSER" == "1" ]]; then
|
||||
run_step portal_public_browser bash "$PUBLIC_PORTAL_BROWSER_SCRIPT"
|
||||
else
|
||||
mark_skip portal_public_browser "set RUN_PUBLIC_PORTAL_BROWSER=1 to execute public portal browser verification"
|
||||
fi
|
||||
|
||||
if [[ -n "${CRM_BASE:-}" ]] && has_crm_auth; then
|
||||
run_step accounts_admin bash "$ACCOUNTS_ACCEPTANCE_SCRIPT"
|
||||
else
|
||||
mark_skip accounts_admin "missing CRM_BASE or CRM auth; set CRM_BASE with CRM_ADMIN_TOKEN or CRM_ADMIN_USERNAME/CRM_ADMIN_PASSWORD"
|
||||
fi
|
||||
|
||||
if [[ -n "${CRM_BASE:-}" ]] && has_crm_auth && [[ -n "${SHADOW_HOST_ID:-}" ]] && [[ -n "${SHADOW_GROUP_ID:-}" ]] && { [[ -n "${SUBSCRIPTION_USER_ID:-}" ]] || [[ -n "${GATEWAY_API_KEY:-}" ]]; }; then
|
||||
run_step route_matrix bash "$ROUTE_MATRIX_SCRIPT"
|
||||
else
|
||||
mark_skip route_matrix "missing CRM auth or route data-plane env; require CRM_BASE, auth, SHADOW_HOST_ID, SHADOW_GROUP_ID, and SUBSCRIPTION_USER_ID or GATEWAY_API_KEY"
|
||||
fi
|
||||
|
||||
if [[ -n "${CRM_BASE:-}" ]] && has_crm_auth && [[ -n "${ACCESS_API_KEY:-}" ]] && [[ -n "${PROVIDER_KEYS:-}" ]]; then
|
||||
run_step provider_admin bash "$PROVIDER_ADMIN_SCRIPT"
|
||||
else
|
||||
mark_skip provider_admin "missing provider admin env; require CRM_BASE, auth, ACCESS_API_KEY, and PROVIDER_KEYS"
|
||||
fi
|
||||
|
||||
python3 - "$MATRIX_DIR" >"$MATRIX_DIR/summary.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
matrix_dir = Path(sys.argv[1])
|
||||
|
||||
def load_json(path):
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
def step_result(name, summary_file):
|
||||
step_dir = matrix_dir / name
|
||||
if step_dir.exists():
|
||||
return {"status": "ok", "artifact_dir": str(step_dir), "summary": load_json(step_dir / summary_file)}
|
||||
skip_file = matrix_dir / f"{name}.skip.txt"
|
||||
if skip_file.exists():
|
||||
return {"status": "skipped", "reason": skip_file.read_text(encoding="utf-8").strip()}
|
||||
return {"status": "missing"}
|
||||
|
||||
browser = step_result("browser_smoke", "99-summary.json")
|
||||
portal = step_result("portal_catalog", "99-summary.json")
|
||||
portal_public_browser = step_result("portal_public_browser", "99-summary.json")
|
||||
accounts = step_result("accounts_admin", "99-summary.json")
|
||||
route = step_result("route_matrix", "summary.json")
|
||||
provider = step_result("provider_admin", "99-summary.json")
|
||||
|
||||
summary = {
|
||||
"matrix_dir": str(matrix_dir),
|
||||
"steps": {
|
||||
"browser_smoke": browser,
|
||||
"portal_catalog": portal,
|
||||
"portal_public_browser": portal_public_browser,
|
||||
"accounts_admin": accounts,
|
||||
"route_matrix": route,
|
||||
"provider_admin": provider,
|
||||
},
|
||||
"page_mapping": {
|
||||
"portal": ["browser_smoke", "portal_catalog", "portal_public_browser"],
|
||||
"admin_index": ["browser_smoke"],
|
||||
"logical_groups": ["browser_smoke", "route_matrix"],
|
||||
"route_health": ["browser_smoke", "route_matrix"],
|
||||
"accounts": ["browser_smoke", "accounts_admin"],
|
||||
"providers": ["browser_smoke", "provider_admin"],
|
||||
"batch_import": ["browser_smoke"],
|
||||
},
|
||||
}
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
cat "$MATRIX_DIR/summary.json"
|
||||
94
scripts/acceptance/verify_portal_catalog_ui.sh
Normal file
94
scripts/acceptance/verify_portal_catalog_ui.sh
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
# shellcheck disable=SC1091
|
||||
source "$ROOT_DIR/scripts/acceptance/route_acceptance_lib.sh"
|
||||
|
||||
PORTAL_ACCEPTANCE_ROOT="${PORTAL_ACCEPTANCE_ROOT:-$ROOT_DIR/artifacts/frontend-acceptance-matrix}"
|
||||
TS="${TS:-$(timestamp_token)}"
|
||||
ARTIFACT_DIR="${ARTIFACT_DIR:-$PORTAL_ACCEPTANCE_ROOT/${TS}_portal_catalog_ui}"
|
||||
|
||||
PORTAL_PAGE_URL="${PORTAL_PAGE_URL:-https://sub.tksea.top/portal/}"
|
||||
PORTAL_CATALOG_BASE="${PORTAL_CATALOG_BASE:-https://sub.tksea.top/portal-admin-api/api/portal}"
|
||||
PORTAL_PROXY_BASE="${PORTAL_PROXY_BASE:-https://sub.tksea.top/portal-proxy/api/v1}"
|
||||
PORTAL_ACCESS_TOKEN="${PORTAL_ACCESS_TOKEN:-}"
|
||||
|
||||
ensure_artifact_dir
|
||||
curl_status_to_file "$PORTAL_PAGE_URL" "$ARTIFACT_DIR/00-portal.html"
|
||||
|
||||
curl -fsS "${PORTAL_CATALOG_BASE%/}/logical-groups" >"$ARTIFACT_DIR/01-logical-groups.json"
|
||||
|
||||
first_group_id="$(
|
||||
python3 - "$ARTIFACT_DIR/01-logical-groups.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
payload = json.load(open(sys.argv[1], "r", encoding="utf-8"))
|
||||
items = payload.get("logical_groups") or []
|
||||
if not items:
|
||||
raise SystemExit(2)
|
||||
first = items[0]
|
||||
print(first.get("logical_group_id") or "")
|
||||
PY
|
||||
)" || first_group_id=""
|
||||
|
||||
if [[ -n "$first_group_id" ]]; then
|
||||
curl -fsS "${PORTAL_CATALOG_BASE%/}/logical-groups/${first_group_id}/models" >"$ARTIFACT_DIR/02-group-models.json"
|
||||
fi
|
||||
|
||||
if [[ -n "$PORTAL_ACCESS_TOKEN" ]]; then
|
||||
curl -fsS -H "Authorization: Bearer $PORTAL_ACCESS_TOKEN" "${PORTAL_PROXY_BASE%/}/auth/me" >"$ARTIFACT_DIR/03-auth-me.json"
|
||||
curl -fsS -H "Authorization: Bearer $PORTAL_ACCESS_TOKEN" "${PORTAL_PROXY_BASE%/}/groups/available" >"$ARTIFACT_DIR/04-groups-available.json"
|
||||
curl -fsS -H "Authorization: Bearer $PORTAL_ACCESS_TOKEN" "${PORTAL_PROXY_BASE%/}/subscriptions" >"$ARTIFACT_DIR/05-subscriptions.json"
|
||||
curl -fsS -H "Authorization: Bearer $PORTAL_ACCESS_TOKEN" "${PORTAL_PROXY_BASE%/}/keys?page=1&page_size=20" >"$ARTIFACT_DIR/06-keys.json"
|
||||
fi
|
||||
|
||||
python3 - "$ARTIFACT_DIR" "$PORTAL_ACCESS_TOKEN" >"$ARTIFACT_DIR/99-summary.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
art_dir = Path(sys.argv[1])
|
||||
access_token = sys.argv[2]
|
||||
|
||||
page = (art_dir / "00-portal.html").read_text(encoding="utf-8")
|
||||
catalog = json.loads((art_dir / "01-logical-groups.json").read_text(encoding="utf-8"))
|
||||
groups = catalog.get("logical_groups") or []
|
||||
|
||||
assert "Sub2API 多模型接入中心" in page
|
||||
assert "逻辑分组目录" in page
|
||||
assert groups, groups
|
||||
|
||||
summary = {
|
||||
"page_url": "portal",
|
||||
"page_title_seen": "Sub2API 多模型接入中心" in page,
|
||||
"logical_group_count": len(groups),
|
||||
"first_logical_group_id": groups[0].get("logical_group_id"),
|
||||
"first_logical_group_display_name": groups[0].get("display_name"),
|
||||
"user_projection_checked": bool(access_token),
|
||||
}
|
||||
|
||||
models_file = art_dir / "02-group-models.json"
|
||||
if models_file.exists():
|
||||
models_payload = json.loads(models_file.read_text(encoding="utf-8"))
|
||||
public_models = models_payload.get("public_models") or []
|
||||
summary["first_group_models_count"] = len(public_models)
|
||||
if public_models:
|
||||
summary["first_group_first_model"] = public_models[0].get("public_model")
|
||||
|
||||
if access_token:
|
||||
auth_me = json.loads((art_dir / "03-auth-me.json").read_text(encoding="utf-8"))
|
||||
groups_available = json.loads((art_dir / "04-groups-available.json").read_text(encoding="utf-8"))
|
||||
subscriptions = json.loads((art_dir / "05-subscriptions.json").read_text(encoding="utf-8"))
|
||||
keys_page = json.loads((art_dir / "06-keys.json").read_text(encoding="utf-8"))
|
||||
summary["auth_me_present"] = bool(auth_me.get("data") or auth_me)
|
||||
summary["available_group_count"] = len((groups_available.get("data") if isinstance(groups_available, dict) else groups_available) or [])
|
||||
summary["subscription_count"] = len((subscriptions.get("data") if isinstance(subscriptions, dict) else subscriptions) or [])
|
||||
key_data = keys_page.get("data") if isinstance(keys_page, dict) else keys_page
|
||||
summary["key_count"] = len((key_data or {}).get("items") or [])
|
||||
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
cat "$ARTIFACT_DIR/99-summary.json"
|
||||
120
scripts/acceptance/verify_public_portal_browser.sh
Normal file
120
scripts/acceptance/verify_public_portal_browser.sh
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
# shellcheck disable=SC1091
|
||||
source "$ROOT_DIR/scripts/acceptance/route_acceptance_lib.sh"
|
||||
|
||||
PORTAL_ACCEPTANCE_ROOT="${PORTAL_ACCEPTANCE_ROOT:-$ROOT_DIR/artifacts/frontend-acceptance-matrix}"
|
||||
TS="${TS:-$(timestamp_token)}"
|
||||
ARTIFACT_DIR="${ARTIFACT_DIR:-$PORTAL_ACCEPTANCE_ROOT/${TS}_portal_public_browser}"
|
||||
|
||||
PUBLIC_PORTAL_PAGE_URL="${PUBLIC_PORTAL_PAGE_URL:-https://sub.tksea.top/portal/}"
|
||||
PUBLIC_PORTAL_CATALOG_BASE="${PUBLIC_PORTAL_CATALOG_BASE:-https://sub.tksea.top/portal-admin-api/api/portal}"
|
||||
PUBLIC_PORTAL_PROXY_BASE="${PUBLIC_PORTAL_PROXY_BASE:-https://sub.tksea.top/portal-proxy/api/v1}"
|
||||
PORTAL_ACCESS_TOKEN="${PORTAL_ACCESS_TOKEN:-}"
|
||||
CHROMIUM_BIN="${CHROMIUM_BIN:-}"
|
||||
VIRTUAL_TIME_BUDGET="${VIRTUAL_TIME_BUDGET:-5000}"
|
||||
USER_DATA_DIR="$ARTIFACT_DIR/chromium-profile"
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_contains_file() {
|
||||
local file="$1"
|
||||
local needle="$2"
|
||||
if ! grep -Fq "$needle" "$file"; then
|
||||
fail "expected [$needle] in $file"
|
||||
fi
|
||||
}
|
||||
|
||||
find_chromium() {
|
||||
if [[ -n "$CHROMIUM_BIN" ]]; then
|
||||
printf '%s\n' "$CHROMIUM_BIN"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local candidate
|
||||
for candidate in chromium chromium-browser google-chrome google-chrome-stable; do
|
||||
if command -v "$candidate" >/dev/null 2>&1; then
|
||||
command -v "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
dump_dom() {
|
||||
local label="$1"
|
||||
local url="$2"
|
||||
local output="$ARTIFACT_DIR/${label}.dom.html"
|
||||
"$CHROMIUM_BIN" \
|
||||
--headless \
|
||||
--disable-gpu \
|
||||
--no-sandbox \
|
||||
--no-proxy-server \
|
||||
--user-data-dir="$USER_DATA_DIR/$label" \
|
||||
--virtual-time-budget="$VIRTUAL_TIME_BUDGET" \
|
||||
--dump-dom \
|
||||
"$url" >"$output" 2>"$ARTIFACT_DIR/${label}.stderr.txt"
|
||||
printf '%s\n' "$output"
|
||||
}
|
||||
|
||||
CHROMIUM_BIN="$(find_chromium)" || fail "missing chromium-compatible browser; set CHROMIUM_BIN explicitly"
|
||||
[[ -x "$CHROMIUM_BIN" ]] || fail "chromium binary is not executable: $CHROMIUM_BIN"
|
||||
ensure_artifact_dir
|
||||
mkdir -p "$USER_DATA_DIR"
|
||||
|
||||
portal_dom="$(dump_dom "00-portal" "$PUBLIC_PORTAL_PAGE_URL")"
|
||||
assert_contains_file "$portal_dom" "Sub2API 多模型接入中心"
|
||||
assert_contains_file "$portal_dom" "逻辑分组目录"
|
||||
assert_contains_file "$portal_dom" "申请 Key 依赖状态"
|
||||
assert_contains_file "$portal_dom" "可直接申请"
|
||||
assert_contains_file "$portal_dom" "可申请,调用前需确认状态"
|
||||
assert_contains_file "$portal_dom" "待补开通"
|
||||
assert_contains_file "$portal_dom" "待人工整理"
|
||||
assert_contains_file "$portal_dom" "仅目录可见"
|
||||
|
||||
PORTAL_PAGE_URL="$PUBLIC_PORTAL_PAGE_URL" \
|
||||
PORTAL_CATALOG_BASE="$PUBLIC_PORTAL_CATALOG_BASE" \
|
||||
PORTAL_PROXY_BASE="$PUBLIC_PORTAL_PROXY_BASE" \
|
||||
PORTAL_ACCESS_TOKEN="$PORTAL_ACCESS_TOKEN" \
|
||||
ARTIFACT_DIR="$ARTIFACT_DIR/catalog_api" \
|
||||
bash "$ROOT_DIR/scripts/acceptance/verify_portal_catalog_ui.sh" >"$ARTIFACT_DIR/portal_catalog.stdout.txt"
|
||||
|
||||
python3 - "$ARTIFACT_DIR" "$PUBLIC_PORTAL_PAGE_URL" "$PORTAL_ACCESS_TOKEN" >"$ARTIFACT_DIR/99-summary.json" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
art_dir = Path(sys.argv[1])
|
||||
page_url = sys.argv[2]
|
||||
access_token = sys.argv[3]
|
||||
|
||||
page = (art_dir / "00-portal.dom.html").read_text(encoding="utf-8")
|
||||
catalog_summary = json.loads((art_dir / "catalog_api" / "99-summary.json").read_text(encoding="utf-8"))
|
||||
|
||||
summary = {
|
||||
"page_url": page_url,
|
||||
"page_title_seen": "Sub2API 多模型接入中心" in page,
|
||||
"logical_group_catalog_seen": "逻辑分组目录" in page,
|
||||
"dependency_panel_seen": "申请 Key 依赖状态" in page,
|
||||
"dependency_state_copy_seen": {
|
||||
"ready": "可直接申请" in page,
|
||||
"granted": "可申请,调用前需确认状态" in page,
|
||||
"pending": "待补开通" in page,
|
||||
"ambiguous": "待人工整理" in page,
|
||||
"catalog_only": "仅目录可见" in page,
|
||||
},
|
||||
"user_projection_checked": bool(access_token),
|
||||
"catalog_api_summary": catalog_summary,
|
||||
"result": "pass",
|
||||
}
|
||||
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
PY
|
||||
|
||||
cat "$ARTIFACT_DIR/99-summary.json"
|
||||
Reference in New Issue
Block a user