跳转到主要内容

测试与验证

9.1 UCP Profile验证

Profile是所有AI代理对接的入口,必须通过严格验证。

基础检查

# 1. 检查HTTPS和无重定向
curl -sI "https://mystore.com/.well-known/ucp" | head -5
# 期望: HTTP/2 200 (不能是3xx)

# 2. 检查Cache-Control
curl -sI "https://mystore.com/.well-known/ucp" | grep -i cache-control
# 期望: cache-control: public, max-age=N (N >= 60)

# 3. 检查Content-Type
curl -sI "https://mystore.com/.well-known/ucp" | grep -i content-type
# 期望: content-type: application/json

# 4. 获取并验证JSON
curl -s "https://mystore.com/.well-known/ucp" | jq .

Profile字段验证清单

字段验证规则必须
supported_versions非空数组,包含有效日期格式版本号
services至少一个服务,base_url 必须是HTTPS
capabilities至少一个能力,命名空间格式正确
capabilities.*.version有效日期格式,在 supported_versions 范围内
payment_handlers数组,反向DNS命名格式
signing_keysJWK数组,每个key有 kid, kty, crv, x, y, use, alg

Profile自动化验证脚本

#!/bin/bash
URL="https://mystore.com/.well-known/ucp"

echo "=== UCP Profile Validation ==="

# 检查HTTP状态码(不跟随重定向)
STATUS=$(curl -so /dev/null -w "%{http_code}" --max-redirs 0 "$URL")
if [ "$STATUS" = "200" ]; then
  echo "PASS: HTTP 200 (no redirect)"
else
  echo "FAIL: HTTP $STATUS (expected 200, no redirects allowed)"
fi

# 检查HTTPS
if [[ "$URL" == https://* ]]; then
  echo "PASS: HTTPS"
else
  echo "FAIL: Must be HTTPS"
fi

# 检查Cache-Control
CACHE=$(curl -sI "$URL" | grep -i "cache-control" | tr -d '\r')
if echo "$CACHE" | grep -qi "public"; then
  echo "PASS: Cache-Control includes public"
else
  echo "FAIL: Cache-Control must include 'public'"
fi

# 检查JSON有效性
BODY=$(curl -s "$URL")
if echo "$BODY" | jq . > /dev/null 2>&1; then
  echo "PASS: Valid JSON"
else
  echo "FAIL: Invalid JSON"
fi

# 检查必须字段
if echo "$BODY" | jq -e '.supported_versions | length > 0' > /dev/null 2>&1; then
  echo "PASS: supported_versions present"
else
  echo "FAIL: supported_versions missing or empty"
fi

if echo "$BODY" | jq -e '.services | keys | length > 0' > /dev/null 2>&1; then
  echo "PASS: services present"
else
  echo "FAIL: services missing or empty"
fi

if echo "$BODY" | jq -e '.capabilities | keys | length > 0' > /dev/null 2>&1; then
  echo "PASS: capabilities present"
else
  echo "FAIL: capabilities missing or empty"
fi

# 检查签名密钥格式
KEYS=$(echo "$BODY" | jq -r '.signing_keys | length')
if [ "$KEYS" -gt 0 ]; then
  echo "INFO: $KEYS signing key(s) found"
  echo "$BODY" | jq -r '.signing_keys[] | "  kid=\(.kid) alg=\(.alg) crv=\(.crv)"'
else
  echo "INFO: No signing keys (Webhook signing not configured)"
fi

echo "=== Validation Complete ==="

9.2 结账流程测试

完整结账流程

BASE="https://mystore.com/ucp"
TOKEN="Bearer ucp_pk_test_xxxx"

# 步骤1: 创建结账会话
SESSION=$(curl -s -X POST "$BASE/checkout/sessions" \
  -H "Content-Type: application/json" \
  -H "Authorization: $TOKEN" \
  -d '{
    "line_items": [{"product_id": "prod_001", "quantity": 1}],
    "buyer": {"email": "test@example.com"}
  }')
echo "Create: $(echo $SESSION | jq -r '.checkout_session.status')"
# 期望: incomplete

SESSION_ID=$(echo $SESSION | jq -r '.checkout_session.id')

# 步骤2: 更新买家信息和配送
curl -s -X PATCH "$BASE/checkout/sessions/$SESSION_ID" \
  -H "Content-Type: application/json" \
  -H "Authorization: $TOKEN" \
  -d '{
    "buyer": {
      "name": "Test User",
      "shipping_address": {
        "line1": "123 Test St",
        "city": "Beijing",
        "state": "Beijing",
        "postal_code": "100000",
        "country_code": "CN"
      }
    },
    "fulfillment": {"method": "standard_shipping"}
  }' | jq '.checkout_session.status'

# 步骤3: 查询会话状态
STATUS=$(curl -s "$BASE/checkout/sessions/$SESSION_ID" \
  -H "Authorization: $TOKEN" | jq -r '.checkout_session.status')
echo "After update: $STATUS"
# 期望: incomplete 或 ready_for_complete

# 步骤4: 取消会话(测试环境建议取消而非完成)
curl -s -X POST "$BASE/checkout/sessions/$SESSION_ID/cancel" \
  -H "Content-Type: application/json" \
  -H "Authorization: $TOKEN" \
  -d '{"reason": "test_cancellation"}' | jq '.checkout_session.status'
# 期望: canceled

状态机验证

测试所有6个状态的转换路径是否正确:
测试场景起始状态操作期望结果
创建空会话-Createincomplete
补充完整信息incompleteUpdateready_for_complete
提交完成ready_for_completeCompletecomplete_in_progress
取消进行中的会话incompleteCancelcanceled
对已完成会话调用CancelcompletedCancel400错误
对已取消会话调用UpdatecanceledUpdate400错误
触发人工介入incomplete特定条件requires_escalation

9.3 商品数据验证

每个商品记录必须通过以下验证:
必填字段检查:
  [x] id: 非空且唯一
  [x] name: 非空字符串
  [x] price.amount: 正整数(最小货币单位)
  [x] price.currency_code: 有效的ISO 4217代码(如CNY, USD, JPY)
  [x] availability: in_stock / out_of_stock / preorder 之一
  [x] images: 至少一项,URL可通过HTTPS访问

可选字段格式检查:
  [x] variants[].sku: 如存在则唯一
  [x] variants[].price.amount: 正整数
  [x] gtin: 如存在则符合GTIN-13或GTIN-14格式
  [x] compare_at_price.amount: 如存在则大于price.amount(划线价高于实际价)

金额一致性:
  [x] 所有price对象使用相同的currency_code
  [x] 金额值与货币的最小单位一致(CNY用分,JPY用円)

9.4 签名验证测试

如果配置了Webhook签名,测试签名的创建和验证:
# 模拟商家发送带签名的Webhook
# 1. 创建测试请求体
BODY='{"event_type":"order.created","order_id":"ord_test_001"}'

# 2. 计算Content-Digest
DIGEST=$(echo -n "$BODY" | openssl dgst -sha256 -binary | base64)
echo "Content-Digest: sha-256=:$DIGEST:"

# 3. 验证商家Profile中的签名密钥
curl -s "https://mystore.com/.well-known/ucp" | jq '.signing_keys'
# 确认kid、alg(ES256)、crv(P-256)等字段正确

9.5 OAuth流程测试

# 1. 验证授权服务器发现
curl -s "https://mystore.com/.well-known/oauth-authorization-server" | jq .
# 检查: authorization_endpoint, token_endpoint, revocation_endpoint

# 2. 验证授权端点支持PKCE
# 检查 code_challenge_methods_supported 包含 "S256"

# 3. 验证scope支持
# 检查 scopes_supported 包含 "ucp:scopes:checkout_session"

# 4. 测试令牌撤销端点 (RFC 7009)
curl -s -X POST "https://mystore.com/oauth/revoke" \
  -d "token=expired_test_token&token_type_hint=access_token&client_id=test" \
  -w "\nHTTP Status: %{http_code}\n"
# 期望: 200 (即使token无效也应返回200)

9.6 性能基准

UCP端点需要在合理的时间内响应:
端点类型响应时间目标并发要求
/.well-known/ucp Profile100ms以内100+ QPS
商品搜索500ms以内50+ QPS
商品详情200ms以内100+ QPS
结账操作1s以内20+ QPS
OAuth令牌端点300ms以内50+ QPS
# 简单性能测试
# Profile端点延迟
for i in $(seq 1 10); do
  curl -so /dev/null -w "%{time_total}\n" "https://mystore.com/.well-known/ucp"
done

# 商品搜索并发测试 (需要安装ab或wrk)
ab -n 100 -c 10 "https://mystore.com/ucp/catalog/products?query=test&limit=10"

9.7 常见问题排查

问题原因解决方案
AI代理无法发现Profile3xx重定向或非HTTPS确保直接返回200,不经过重定向
Cache-Control验证失败max-age不足60秒设置 public, max-age=3600
价格显示异常未使用最小货币单位确认amount是整数(分/美分),不是小数
签名验证失败kid不匹配或密钥过期检查Profile中signing_keys的kid是否一致
OAuth流程中断缺少PKCE支持实现S256 code_challenge验证
能力协商结果为空版本号不匹配确保双方supported_versions有交集
Webhook未收到签名验证失败被拒检查Content-Digest和Signature是否正确

下一章: 实战案例与扩展 — Buyer Consent扩展、AP2 Mandate和集成实战路径