fix fresh-host acceptance and document real-host debugging learnings
This commit is contained in:
@@ -41,6 +41,20 @@ if [[ -z "$upstream_key" ]]; then
|
||||
exit 2
|
||||
fi
|
||||
|
||||
upstream_base_url="$(python3 - "$PACK_PATH" "$provider_id" <<'PY'
|
||||
import json, pathlib, sys
|
||||
pack_path = pathlib.Path(sys.argv[1])
|
||||
provider_id = sys.argv[2]
|
||||
provider_file = pack_path / "providers" / f"{provider_id}.json"
|
||||
provider = json.loads(provider_file.read_text(encoding='utf-8'))
|
||||
print(str(provider.get("base_url", "")).strip())
|
||||
PY
|
||||
)"
|
||||
if [[ -z "$upstream_base_url" ]]; then
|
||||
echo "missing provider base_url for $provider_id in $PACK_PATH" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
ssh_cmd() {
|
||||
local cmd="$1"
|
||||
ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$cmd"
|
||||
@@ -454,6 +468,14 @@ ssh_cmd "curl -sS -D /tmp/chat_headers.txt -o /tmp/chat_body.json -H 'Authorizat
|
||||
ssh_cmd "cat /tmp/chat_headers.txt" > "$ART/11-chat.headers.txt"
|
||||
ssh_cmd "cat /tmp/chat_body.json" > "$ART/12-chat.body.json"
|
||||
|
||||
ssh_cmd "curl -sS -D /tmp/upstream_models_headers.txt -o /tmp/upstream_models_body.json -H 'Authorization: Bearer $upstream_key' ${upstream_base_url%/}/models"
|
||||
ssh_cmd "cat /tmp/upstream_models_headers.txt" > "$ART/17-upstream-models.headers.txt"
|
||||
ssh_cmd "cat /tmp/upstream_models_body.json" > "$ART/18-upstream-models.body.json"
|
||||
|
||||
ssh_cmd "curl -sS -D /tmp/upstream_chat_headers.txt -o /tmp/upstream_chat_body.txt -H 'Authorization: Bearer $upstream_key' -H 'Content-Type: application/json' ${upstream_base_url%/}/chat/completions -d $(printf %q "$probe_payload")"
|
||||
ssh_cmd "cat /tmp/upstream_chat_headers.txt" > "$ART/19-upstream-chat.headers.txt"
|
||||
ssh_cmd "cat /tmp/upstream_chat_body.txt" > "$ART/20-upstream-chat.body.txt"
|
||||
|
||||
crm_curl_json GET "/api/providers/$provider_id/status" > "$ART/13-provider-status.json"
|
||||
crm_curl_json GET "/api/providers/$provider_id/access/status" > "$ART/14-access-status.json"
|
||||
preview_payload="$(python3 - "$provider_id" <<'PY'
|
||||
@@ -472,17 +494,67 @@ provider_id=sys.argv[2]
|
||||
batch_id=int(sys.argv[3])
|
||||
subscription_group_id=sys.argv[4]
|
||||
expected_model=sys.argv[5]
|
||||
|
||||
def normalize_model_id(model_id: str) -> str:
|
||||
value = str(model_id or '').strip().lower()
|
||||
if not value:
|
||||
return ''
|
||||
if '/' in value:
|
||||
value = value.split('/')[-1]
|
||||
return value
|
||||
|
||||
def has_expected_model(models, expected: str) -> bool:
|
||||
normalized_expected = normalize_model_id(expected)
|
||||
if not normalized_expected:
|
||||
return False
|
||||
return any(normalize_model_id(model_id) == normalized_expected for model_id in models)
|
||||
|
||||
def status_from_headers(path: pathlib.Path) -> int:
|
||||
if not path.exists():
|
||||
return 0
|
||||
for line in path.read_text(encoding='utf-8').splitlines():
|
||||
parts = line.strip().split()
|
||||
if len(parts) >= 2 and parts[0].startswith('HTTP/'):
|
||||
try:
|
||||
return int(parts[1])
|
||||
except ValueError:
|
||||
return 0
|
||||
return 0
|
||||
|
||||
def load_json(path: pathlib.Path):
|
||||
try:
|
||||
return json.loads(path.read_text(encoding='utf-8'))
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
import_obj=json.loads((art/'03-import.body.json').read_text())
|
||||
models_obj=json.loads((art/'10-models.body.json').read_text())
|
||||
access_status=json.loads((art/'14-access-status.json').read_text())
|
||||
preview=json.loads((art/'15-access-preview.json').read_text())
|
||||
models_obj=load_json(art/'10-models.body.json')
|
||||
access_status=load_json(art/'14-access-status.json')
|
||||
preview=load_json(art/'15-access-preview.json')
|
||||
models_headers=(art/'09-models.headers.txt').read_text()
|
||||
chat_headers=(art/'11-chat.headers.txt').read_text()
|
||||
upstream_models_obj=load_json(art/'18-upstream-models.body.json')
|
||||
upstream_chat_headers=(art/'19-upstream-chat.headers.txt')
|
||||
upstream_chat_body=(art/'20-upstream-chat.body.txt').read_text(encoding='utf-8')
|
||||
models=[]
|
||||
for item in models_obj.get('data') or []:
|
||||
model_id = item.get('id')
|
||||
if isinstance(model_id, str) and model_id:
|
||||
models.append(model_id)
|
||||
upstream_models=[]
|
||||
for item in upstream_models_obj.get('data') or []:
|
||||
model_id = item.get('id')
|
||||
if isinstance(model_id, str) and model_id:
|
||||
upstream_models.append(model_id)
|
||||
host_chat_status = status_from_headers(art/'11-chat.headers.txt')
|
||||
upstream_chat_status = status_from_headers(upstream_chat_headers)
|
||||
classification = 'unknown'
|
||||
direct_has_expected_model = has_expected_model(models, expected_model)
|
||||
upstream_has_expected_model = has_expected_model(upstream_models, expected_model)
|
||||
if direct_has_expected_model and host_chat_status >= 500 and upstream_chat_status == 200:
|
||||
classification = 'host_compatibility_gap'
|
||||
elif direct_has_expected_model and upstream_chat_status == 403 and 'insufficient_user_quota' in upstream_chat_body:
|
||||
classification = 'upstream_key_quota_issue'
|
||||
summary={
|
||||
'artifact_dir': str(art),
|
||||
'provider_id': provider_id,
|
||||
@@ -491,14 +563,21 @@ summary={
|
||||
'access_status_from_import': import_obj.get('access_status'),
|
||||
'provider_status_from_import': import_obj.get('provider_status'),
|
||||
'direct_models_http200': '200 OK' in models_headers,
|
||||
'direct_models_has_expected_model': expected_model in models,
|
||||
'direct_models_has_expected_model': direct_has_expected_model,
|
||||
'direct_models': models,
|
||||
'direct_chat_http200': '200 OK' in chat_headers,
|
||||
'direct_chat_status': host_chat_status,
|
||||
'upstream_models': upstream_models,
|
||||
'upstream_models_has_expected_model': upstream_has_expected_model,
|
||||
'upstream_chat_status': upstream_chat_status,
|
||||
'completion_classification': classification,
|
||||
'latest_access_status': access_status.get('latest_access_status') or access_status.get('batch_access_status'),
|
||||
'preview_available': preview.get('available'),
|
||||
'accepted_keys_count': import_obj.get('accepted_keys_count'),
|
||||
'subscription_group_id': subscription_group_id,
|
||||
'import_group_id': (import_obj.get('group') or {}).get('id'),
|
||||
}
|
||||
print(json.dumps(summary, ensure_ascii=False))
|
||||
summary_json = json.dumps(summary, ensure_ascii=False)
|
||||
(art / '21-summary.json').write_text(summary_json, encoding='utf-8')
|
||||
print(summary_json)
|
||||
PY
|
||||
|
||||
@@ -243,14 +243,17 @@ EOF
|
||||
}
|
||||
|
||||
run_test_import_remote43_provider_subscription_prep() {
|
||||
local tmpdir fakebin artifact_dir ssh_log psql_sql
|
||||
local tmpdir fakebin artifact_dir ssh_log psql_sql pack_dir
|
||||
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"
|
||||
pack_dir="$tmpdir/pack"
|
||||
mkdir -p "$fakebin"
|
||||
mkdir -p "$pack_dir/providers"
|
||||
printf '%s\n' '{"provider_id":"deepseek","base_url":"https://upstream.example.com/v1"}' > "$pack_dir/providers/deepseek.json"
|
||||
|
||||
cat > "$fakebin/curl" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
@@ -338,7 +341,7 @@ if [[ "$cmd" == *'***'* ]]; then
|
||||
echo "unexpected redacted auth placeholder in ssh command: $cmd" >&2
|
||||
exit 1
|
||||
fi
|
||||
case "$cmd" in
|
||||
case "$cmd" in
|
||||
*"/api/v1/auth/login"*)
|
||||
printf '%s\n' 'host-bearer-token'
|
||||
;;
|
||||
@@ -390,6 +393,26 @@ case "$cmd" in
|
||||
"cat /tmp/chat_body.json")
|
||||
cat /tmp/chat_body.json
|
||||
;;
|
||||
*"curl -sS -D /tmp/upstream_models_headers.txt"*)
|
||||
printf '%s\n' 'HTTP/1.1 200 OK' > /tmp/upstream_models_headers.txt
|
||||
printf '%s\n' '{"data":[{"id":"openai/gpt-4"},{"id":"openai/gpt-4.1"}]}' > /tmp/upstream_models_body.json
|
||||
;;
|
||||
"cat /tmp/upstream_models_headers.txt")
|
||||
cat /tmp/upstream_models_headers.txt
|
||||
;;
|
||||
"cat /tmp/upstream_models_body.json")
|
||||
cat /tmp/upstream_models_body.json
|
||||
;;
|
||||
*"curl -sS -D /tmp/upstream_chat_headers.txt"*)
|
||||
printf '%s\n' 'HTTP/1.1 200 OK' > /tmp/upstream_chat_headers.txt
|
||||
printf '%s\n' '{"choices":[{"message":{"content":"upstream-pong"}}]}' > /tmp/upstream_chat_body.txt
|
||||
;;
|
||||
"cat /tmp/upstream_chat_headers.txt")
|
||||
cat /tmp/upstream_chat_headers.txt
|
||||
;;
|
||||
"cat /tmp/upstream_chat_body.txt")
|
||||
cat /tmp/upstream_chat_body.txt
|
||||
;;
|
||||
*"/api/providers/deepseek/status"*)
|
||||
printf '%s\n' '{"status":"ready"}'
|
||||
;;
|
||||
@@ -451,7 +474,7 @@ EOF
|
||||
CRM_HOST_BASE="http://127.0.0.1:18093" \
|
||||
ROOT="$artifact_dir/root" \
|
||||
ART="$artifact_dir/run" \
|
||||
PACK_PATH="/tmp/openai-pack" \
|
||||
PACK_PATH="$pack_dir" \
|
||||
REMOTE_PG_CONTAINER="fresh-pg" \
|
||||
REMOTE_REDIS_CONTAINER="fresh-redis" \
|
||||
UPSTREAM_KEY="upstream-test-key" \
|
||||
@@ -474,14 +497,21 @@ EOF
|
||||
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
|
||||
local subscription_state models_body chat_body upstream_models upstream_chat summary_json
|
||||
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")"
|
||||
upstream_models="$(cat "$artifact_dir/run/18-upstream-models.body.json")"
|
||||
upstream_chat="$(cat "$artifact_dir/run/20-upstream-chat.body.txt")"
|
||||
summary_json="$(cat "$artifact_dir/run/21-summary.json" 2>/dev/null || true)"
|
||||
assert_contains "$models_body" '"id":"gpt-4"'
|
||||
assert_contains "$chat_body" '"content":"pong"'
|
||||
assert_contains "$upstream_models" '"id":"openai/gpt-4"'
|
||||
assert_contains "$upstream_chat" '"content":"upstream-pong"'
|
||||
assert_contains "$summary_json" '"upstream_models_has_expected_model": true'
|
||||
assert_contains "$summary_json" '"completion_classification": "unknown"'
|
||||
[[ -s "$ssh_log" ]] || fail "ssh log was empty"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user