测试与验证
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_keys | JWK数组,每个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个状态的转换路径是否正确:| 测试场景 | 起始状态 | 操作 | 期望结果 |
|---|---|---|---|
| 创建空会话 | - | Create | incomplete |
| 补充完整信息 | incomplete | Update | ready_for_complete |
| 提交完成 | ready_for_complete | Complete | complete_in_progress |
| 取消进行中的会话 | incomplete | Cancel | canceled |
| 对已完成会话调用Cancel | completed | Cancel | 400错误 |
| 对已取消会话调用Update | canceled | Update | 400错误 |
| 触发人工介入 | 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 Profile | 100ms以内 | 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代理无法发现Profile | 3xx重定向或非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和集成实战路径