Files
sub2api-cn-relay-manager/scripts/test_real_host_scripts.sh

393 lines
12 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
fail() {
echo "FAIL: $*" >&2
exit 1
}
assert_contains() {
local haystack="$1"
local needle="$2"
if [[ "$haystack" != *"$needle"* ]]; then
fail "expected to find [$needle] in [$haystack]"
fi
}
run_test_build_subscription_access_prep_sql() {
# shellcheck disable=SC1091
source "$ROOT_DIR/scripts/host_access_prep_lib.sh"
local sql
sql="$(build_subscription_access_prep_sql 42 'sk-test-123' 7 10 30 1 'hermes remote subscription validation')"
assert_contains "$sql" "UPDATE users"
assert_contains "$sql" "balance < 10"
assert_contains "$sql" "UPDATE api_keys"
assert_contains "$sql" "group_id = 7"
assert_contains "$sql" "key = 'sk-test-123'"
assert_contains "$sql" "INSERT INTO user_subscriptions"
assert_contains "$sql" "ON CONFLICT (user_id, group_id) WHERE deleted_at IS NULL"
assert_contains "$sql" "now() + interval '30 days'"
local quoted_sql
quoted_sql="$(build_bind_api_key_group_sql "sk-o'reilly" 7)"
assert_contains "$quoted_sql" "WHERE key = 'sk-o''reilly'"
local auth_cache_key balance_cache_key subscription_cache_key
auth_cache_key="$(build_api_key_auth_cache_key 'user-key')"
balance_cache_key="$(build_user_balance_cache_key 42)"
subscription_cache_key="$(build_subscription_billing_cache_key 42 7)"
assert_contains "$auth_cache_key" "apikey:auth:"
assert_contains "$balance_cache_key" "billing:balance:42"
assert_contains "$subscription_cache_key" "billing:sub:42:7"
}
run_test_real_host_acceptance_after_import_hook() {
local tmpdir fakebin artifact_dir hook_file
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' RETURN
fakebin="$tmpdir/bin"
artifact_dir="$tmpdir/artifacts"
hook_file="$artifact_dir/hook.txt"
mkdir -p "$fakebin"
cat > "$fakebin/curl" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
url=""
for arg in "$@"; do
if [[ "$arg" == *'***'* ]]; then
echo "unexpected redacted auth placeholder in curl args: $*" >&2
exit 1
fi
if [[ "$arg" == http://* || "$arg" == https://* ]]; then
url="$arg"
fi
done
[[ -n "$url" ]] || {
echo "missing url in curl args: $*" >&2
exit 1
}
case "$url" in
*/api/hosts)
printf '%s\n' '{"host_id":"test-host"}'
;;
*/api/hosts/test-host)
printf '%s\n' '{"host_id":"test-host"}'
;;
*/api/hosts/test-host/probe)
printf '%s\n' '{"ok":true}'
;;
*/api/packs/install)
printf '%s\n' '{"pack_id":1}'
;;
*/api/providers/deepseek/preview-import)
printf '%s\n' '{"available":true}'
;;
*/api/providers/deepseek/import)
printf '%s\n' '{"batch_id":123,"batch_status":"partially_succeeded","access_status":"broken"}'
;;
*/api/import-batches/123)
printf '%s\n' '{"managed_resources":[{"ResourceType":"group","HostResourceID":"7","ResourceName":"DeepSeek 默认分组"}]}'
;;
*/api/providers/deepseek/access/preview)
printf '%s\n' '{"available":true}'
;;
*/api/providers/deepseek/access/status)
printf '%s\n' '{"latest_access_status":"subscription_ready"}'
;;
*/api/providers/deepseek/status)
printf '%s\n' '{"status":"ready"}'
;;
*/api/providers/deepseek/reconcile)
printf '%s\n' '{"status":"in_sync"}'
;;
*/api/import-batches/123/rollback)
printf '%s\n' '{"status":"rolled_back"}'
;;
*)
echo "unexpected curl url: $url" >&2
exit 1
;;
esac
EOF
chmod +x "$fakebin/curl"
PATH="$fakebin:$PATH" \
ARTIFACT_DIR="$artifact_dir" \
CRM_BASE_URL="http://crm.example.com" \
CRM_ADMIN_TOKEN="token" \
HOST_NAME="test-host" \
HOST_BASE_URL="http://host.example.com" \
PACK_PATH="/tmp/openai-pack" \
PROVIDER_ID="deepseek" \
HOST_API_KEY="host-key" \
REMOTE_PG_CONTAINER="fresh-pg" \
REMOTE_REDIS_CONTAINER="fresh-redis" \
MODE="partial" \
ACCESS_MODE="subscription" \
ACCESS_API_KEY="user-key" \
SUBSCRIPTION_USERS="42" \
SKIP_ROLLBACK="1" \
AFTER_IMPORT_HOOK_COMMAND='printf "%s\n" "$BATCH_ID:$BATCH_DETAIL_FILE:$ACCESS_MODE" > "$ARTIFACT_DIR/hook.txt"' \
"$ROOT_DIR/scripts/real_host_acceptance.sh" >/dev/null
[[ -f "$hook_file" ]] || fail "after-import hook did not create $hook_file"
local hook_contents
hook_contents="$(cat "$hook_file")"
assert_contains "$hook_contents" "123:"
assert_contains "$hook_contents" "05a-batch-detail-pre-access.json:subscription"
}
run_test_import_remote43_provider_subscription_prep() {
local tmpdir fakebin artifact_dir ssh_log psql_sql
tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' RETURN
fakebin="$tmpdir/bin"
artifact_dir="$tmpdir/artifacts"
ssh_log="$artifact_dir/ssh-log.txt"
psql_sql="$artifact_dir/prep.sql"
mkdir -p "$fakebin"
cat > "$fakebin/curl" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
headers_file=""
body_file=""
url=""
prev=""
for arg in "$@"; do
if [[ "$arg" == *'***'* ]]; then
echo "unexpected redacted auth placeholder in curl args: $*" >&2
exit 1
fi
case "$prev" in
-D)
headers_file="$arg"
prev=""
continue
;;
-o)
body_file="$arg"
prev=""
continue
;;
esac
case "$arg" in
-D|-o)
prev="$arg"
continue
;;
http://*|https://*)
url="$arg"
;;
esac
done
write_headers() {
[[ -n "$headers_file" ]] && printf '%s\n' 'HTTP/1.1 200 OK' > "$headers_file"
}
write_body() {
local body="$1"
if [[ -n "$body_file" ]]; then
printf '%s\n' "$body" > "$body_file"
else
printf '%s\n' "$body"
fi
}
case "$url" in
*/api/hosts)
write_body '{"host_id":"remote43-current-host"}'
;;
*/api/providers/deepseek/import)
write_headers
write_body '{"batch_id":123,"batch_status":"partially_succeeded","access_status":"broken","provider_status":"ready","accepted_keys_count":1,"group":{"id":"7","name":"DeepSeek 默认分组"}}'
;;
*/api/import-batches/123)
write_body '{"managed_resources":[{"ResourceType":"group","HostResourceID":"7","ResourceName":"DeepSeek 默认分组"}]}'
;;
*/api/providers/deepseek/status)
write_body '{"status":"ready"}'
;;
*/api/providers/deepseek/access/status)
write_body '{"latest_access_status":"subscription_ready"}'
;;
*/api/providers/deepseek/access/preview)
write_body '{"available":true}'
;;
*)
echo "unexpected curl url: $url" >&2
exit 1
;;
esac
EOF
chmod +x "$fakebin/curl"
cat > "$fakebin/ssh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
log_dir="${FAKE_REMOTE_LOG_DIR:?missing FAKE_REMOTE_LOG_DIR}"
cmd="${*: -1}"
printf '%s\n' "$cmd" >> "$log_dir/ssh-log.txt"
if [[ "$cmd" == *'***'* ]]; then
echo "unexpected redacted auth placeholder in ssh command: $cmd" >&2
exit 1
fi
case "$cmd" in
*"/api/v1/auth/login"*)
printf '%s\n' 'host-bearer-token'
;;
*"grep ^SUB2API_CRM_ADMIN_TOKEN="*)
printf '%s\n' 'crm-token'
;;
*"select value from settings where key='admin_api_key'"*)
printf '%s\n' 'admin-key'
;;
*"select id from users where role='admin'"*)
printf '%s\n' '1'
;;
*"select id from users where email like 'relay-sub-%@sub2api.local'"*)
printf '%s\n' '42'
;;
*"select k.key from users u join api_keys k on k.user_id=u.id"*)
printf '%s\n' 'user-key'
;;
*"/api/providers/deepseek/import"*)
printf '%s\n' '{"batch_id":123,"batch_status":"partially_succeeded","access_status":"broken","group":{"id":"7","name":"DeepSeek 默认分组"}}' > /tmp/import_body.json
printf '%s\n' 'HTTP/1.1 200 OK' > /tmp/import_headers.txt
;;
"cat /tmp/import_headers.txt")
cat /tmp/import_headers.txt
;;
"cat /tmp/import_body.json")
cat /tmp/import_body.json
;;
*"/api/import-batches/123"*)
printf '%s\n' '{"managed_resources":[{"ResourceType":"account","HostResourceID":"8","ResourceName":"deepseek-01"}]}'
;;
*"curl -sS -D /tmp/models_headers.txt"*)
printf '%s\n' 'HTTP/1.1 200 OK' > /tmp/models_headers.txt
printf '%s\n' '{"data":[{"id":"gpt-4"},{"id":"gpt-4.1"}]}' > /tmp/models_body.json
;;
"cat /tmp/models_headers.txt")
cat /tmp/models_headers.txt
;;
"cat /tmp/models_body.json")
cat /tmp/models_body.json
;;
*"curl -sS -D /tmp/chat_headers.txt"*)
printf '%s\n' 'HTTP/1.1 200 OK' > /tmp/chat_headers.txt
printf '%s\n' '{"choices":[{"message":{"content":"pong"}}]}' > /tmp/chat_body.json
;;
"cat /tmp/chat_headers.txt")
cat /tmp/chat_headers.txt
;;
"cat /tmp/chat_body.json")
cat /tmp/chat_body.json
;;
*"/api/providers/deepseek/status"*)
printf '%s\n' '{"status":"ready"}'
;;
*"/api/providers/deepseek/access/status"*)
printf '%s\n' '{"latest_access_status":"subscription_ready"}'
;;
*"/api/providers/deepseek/access/preview"*)
printf '%s\n' '{"available":true}'
;;
*"/api/providers/deepseek/reconcile"*)
printf '%s\n' '{"status":"in_sync"}'
;;
*"sudo -n docker exec -i fresh-pg psql -U sub2api -d sub2api -At -F ''"*)
printf '%s\n' '{"group_id":7,"subscription":{"status":"active"},"key":{"group_id":7}}'
;;
*"sudo -n docker exec -i fresh-pg psql -U sub2api -d sub2api"*)
CMD="$cmd" LOG_DIR="$log_dir" python3 - <<'PY'
import base64, os, re, pathlib, sys
cmd = os.environ['CMD']
log_dir = pathlib.Path(os.environ['LOG_DIR'])
match = re.search(r"printf '%s' '([^']+)' \| base64 -d", cmd)
if not match:
raise SystemExit(f'failed to extract base64 payload from: {cmd}')
sql = base64.b64decode(match.group(1)).decode()
if "select id from users where email like 'relay-sub-%@sub2api.local' and not exists" in sql:
print('')
elif "select k.key from users u join api_keys k on k.user_id=u.id" in sql and "not exists" in sql:
print('')
elif "UPDATE users" in sql and "INSERT INTO user_subscriptions" in sql:
log_dir.joinpath('prep.sql').write_text(sql, encoding='utf-8')
print('')
elif "INSERT INTO users" in sql and "INSERT INTO api_keys" in sql:
log_dir.joinpath('create-user.sql').write_text(sql, encoding='utf-8')
print('84\tuser-key-fresh')
elif "SELECT json_build_object(" in sql:
log_dir.joinpath('group-state.sql').write_text(sql, encoding='utf-8')
print('{"group_id":7,"subscription":{"status":"active"},"key":{"group_id":7}}')
else:
print('')
PY
;;
*"sudo -n docker exec fresh-redis redis-cli DEL apikey:auth:"*" billing:balance:"*" billing:sub:"*":7"*)
printf '%s\n' '3'
;;
*)
echo "unexpected ssh command: $cmd" >&2
exit 1
;;
esac
EOF
chmod +x "$fakebin/ssh"
PATH="$fakebin:$PATH" \
FAKE_REMOTE_LOG_DIR="$artifact_dir" \
KEY="/does/not/matter" \
REMOTE="fake@host" \
CRM_BASE="http://127.0.0.1:18088" \
HOST_BASE="http://127.0.0.1:18087" \
CRM_HOST_BASE="http://127.0.0.1:18093" \
ROOT="$artifact_dir/root" \
ART="$artifact_dir/run" \
PACK_PATH="/tmp/openai-pack" \
REMOTE_PG_CONTAINER="fresh-pg" \
REMOTE_REDIS_CONTAINER="fresh-redis" \
UPSTREAM_KEY="upstream-test-key" \
SUBSCRIPTION_DAYS=30 \
MIN_BALANCE=10 \
SKIP_ROLLBACK=1 \
bash "$ROOT_DIR/scripts/import_remote43_provider.sh" deepseek gpt-4 UPSTREAM_KEY >/dev/null
[[ -f "$psql_sql" ]] || fail "prep sql was not captured"
local prep_sql
prep_sql="$(cat "$psql_sql")"
assert_contains "$prep_sql" "UPDATE users"
assert_contains "$prep_sql" "UPDATE api_keys"
assert_contains "$prep_sql" "INSERT INTO user_subscriptions"
assert_contains "$prep_sql" "group_id = 7"
local runtime_context invalidation_log
runtime_context="$(cat "$artifact_dir/run/01-runtime-context.json")"
assert_contains "$runtime_context" '"crm_host_base": "http://127.0.0.1:18093"'
invalidation_log="$(cat "$artifact_dir/run/07-redis-targeted-invalidation.txt")"
assert_contains "$invalidation_log" "auth_cache_key=apikey:auth:"
assert_contains "$invalidation_log" "balance_cache_key=billing:balance:84"
assert_contains "$invalidation_log" "subscription_cache_key=billing:sub:84:7"
local subscription_state models_body chat_body
subscription_state="$(cat "$artifact_dir/run/08-subscription-group-state.json")"
assert_contains "$subscription_state" '"group_id":7'
assert_contains "$subscription_state" '"status":"active"'
models_body="$(cat "$artifact_dir/run/10-models.body.json")"
chat_body="$(cat "$artifact_dir/run/12-chat.body.json")"
assert_contains "$models_body" '"id":"gpt-4"'
assert_contains "$chat_body" '"content":"pong"'
[[ -s "$ssh_log" ]] || fail "ssh log was empty"
}
run_test_build_subscription_access_prep_sql
run_test_real_host_acceptance_after_import_hook
run_test_import_remote43_provider_subscription_prep
echo "PASS: real host script regression checks"