## Phase 3 实施完成 ### P3-1: 前端轮询优化 (ljwx-phone) - ✅ 实现指数退避轮询器 (ExponentialBackoffPoller) - 初始间隔 2s,最大间隔 30s - 随机抖动 ±20% 避免惊群效应 - 自动重置机制 ### P3-2: SSE 实时推送 (ljwx-phone) - ✅ 实现 SSE 客户端服务 (SseClient) - 自动重连机制 (指数退避) - 心跳检测 (30s 超时) - 事件类型路由 ### P3-3: 批量审批确认机制 - ✅ 后端 confirmToken 机制 - Redis 存储,5分钟过期 - 防重放攻击 - 批量操作原子性保证 - ✅ 前端确认弹窗 (BatchApprovalConfirmModal.vue) - 显示待审批设备列表 - 二次确认交互 ### P3-4: 设备绑定 V2 API (HMAC-SHA256 签名验证) - ✅ DeviceBindEventController - SSE 事件推送 - ✅ DeviceSignatureService - HMAC-SHA256 签名验证 - ✅ DeviceKeyService - 设备密钥管理 - ✅ ChallengeVO, ConfirmTokenVO - V2 API 响应对象 - ✅ BindRequestStatus - 绑定请求状态枚举 ## E2E 测试基础设施 ### 测试脚本 - ✅ test_e2e_flow.py - 完整端到端测试 - 租户/部门/员工创建 - 设备注册与绑定 - 健康数据上传与查询 - 告警与消息生成 - ✅ test_device_binding_v2.py - 设备绑定 V2 API 测试 - Challenge 获取 - HMAC-SHA256 签名验证 - 绑定请求提交 - 审批流程测试 ### 测试配置 - ✅ api-map.yaml - 新增 device_binding_v2 API 映射 - 11 个 V2 API 端点完整定义 - 请求/响应 schema 规范 - ✅ recipes/device_binding_v2_test.yaml - V2 测试场景配置 ### 测试文档 - ✅ E2E_FLOW_TEST_GUIDE.md - E2E 测试指南 - ✅ DEVICE_BINDING_V2_TEST_GUIDE.md - V2 API 测试指南 - ✅ device-binding-phase3-implementation-report.md - Phase 3 实施报告 ## 修复问题 - 🐛 修复 UserContext API 调用错误 - getUserId() → getCurrentUserId() - getUserName() → getCurrentUserName() - 🐛 修复 TDeviceUser 实体方法调用 - setUpdatedAt() → setUpdateTime() - 🐛 修复 BizException 构造函数签名 - 🐛 修复测试脚本 API 端点 - /t_org/ → /sys_org_units/ - /t_user/ → /sys_user/ - 🐛 修复认证头格式 - satoken: <token> → Authorization: Bearer <token> ## 测试状态 - ✅ 编译通过,应用启动成功 (端口 9998) - ✅ E2E 测试步骤 1-4 通过 (租户/部门/员工/设备注册) - ⏳ 步骤 5-8 待完成 (需配置设备密钥) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
251 lines
7.9 KiB
YAML
251 lines
7.9 KiB
YAML
# Test Data Factory Recipe - Device Binding V2 API Test
|
|
# Version: v2.0
|
|
# Purpose: Test Phase 0-3 device binding flow with signature verification
|
|
# Use case: E2E validation of device binding approval workflow
|
|
|
|
version: v2
|
|
name: "device-binding-v2-test"
|
|
|
|
# Run configuration
|
|
run:
|
|
customer_id: 5 # Tenant ID
|
|
run_tag: "device-binding-v2" # Run tag for traceability
|
|
timezone: "Asia/Shanghai" # Timezone for timestamps
|
|
org_id: 10 # Default organization ID
|
|
|
|
# Test scenario configuration
|
|
scenario:
|
|
name: "Device Binding V2 Flow Test"
|
|
description: "Test complete device binding flow with signature verification, approval, and unbind"
|
|
|
|
# Test data
|
|
test_users:
|
|
- user_id: 100
|
|
user_name: "test_user_001"
|
|
org_id: 10
|
|
- user_id: 101
|
|
user_name: "test_user_002"
|
|
org_id: 10
|
|
- user_id: 102
|
|
user_name: "test_user_003"
|
|
org_id: 10
|
|
|
|
test_devices:
|
|
- device_sn: "CRFTQ000000001"
|
|
device_model: "HUAWEI WATCH GT 4"
|
|
device_brand: "HUAWEI"
|
|
device_secret: "test_secret_001" # For HMAC-SHA256 signature
|
|
- device_sn: "CRFTQ000000002"
|
|
device_model: "HUAWEI WATCH GT 4"
|
|
device_brand: "HUAWEI"
|
|
device_secret: "test_secret_002"
|
|
- device_sn: "CRFTQ000000003"
|
|
device_model: "HUAWEI WATCH GT 4"
|
|
device_brand: "HUAWEI"
|
|
device_secret: "test_secret_003"
|
|
|
|
# Test cases
|
|
test_cases:
|
|
# P0-1: Request Binding with Signature Verification
|
|
- id: "TC001"
|
|
name: "Request Device Binding with Valid Signature"
|
|
description: "Test P0-1: Request binding with HMAC-SHA256 signature verification"
|
|
steps:
|
|
- action: "get_challenge"
|
|
api: "device_binding_v2.get_challenge"
|
|
params:
|
|
deviceSn: "CRFTQ000000001"
|
|
save_response:
|
|
challenge: "data.challenge"
|
|
|
|
- action: "calculate_signature"
|
|
description: "Calculate HMAC-SHA256(deviceSecret, challenge + deviceSn)"
|
|
# signature = HMAC-SHA256("test_secret_001", challenge + "CRFTQ000000001")
|
|
|
|
- action: "request_binding"
|
|
api: "device_binding_v2.request_binding"
|
|
params:
|
|
deviceSn: "CRFTQ000000001"
|
|
challenge: "${challenge}"
|
|
signature: "${calculated_signature}"
|
|
userId: 100
|
|
save_response:
|
|
request_id: "data.requestId"
|
|
approval_id: "data.approvalId"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.status == 'PENDING'"
|
|
|
|
# P1-1: Query Approval Status
|
|
- id: "TC002"
|
|
name: "Query Binding Approval Status"
|
|
description: "Test P1-1: Query approval status with exponential backoff"
|
|
steps:
|
|
- action: "query_status"
|
|
api: "device_binding_v2.query_status"
|
|
params:
|
|
requestId: "${request_id}"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.status in ['PENDING', 'APPROVED', 'REJECTED']"
|
|
|
|
# P1-2: Approve Binding
|
|
- id: "TC003"
|
|
name: "Approve Device Binding"
|
|
description: "Test P1-2: Admin approves device binding request"
|
|
steps:
|
|
- action: "approve"
|
|
api: "device_binding_v2.approve"
|
|
params:
|
|
approvalId: "${approval_id}"
|
|
comments: "Approved for testing"
|
|
save_response:
|
|
bind_id: "data.bindId"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.success == true"
|
|
|
|
# P1-2: Reject Binding
|
|
- id: "TC004"
|
|
name: "Reject Device Binding"
|
|
description: "Test P1-2: Admin rejects device binding request"
|
|
setup:
|
|
- action: "request_binding"
|
|
api: "device_binding_v2.request_binding"
|
|
params:
|
|
deviceSn: "CRFTQ000000002"
|
|
userId: 101
|
|
save_response:
|
|
approval_id_2: "data.approvalId"
|
|
steps:
|
|
- action: "reject"
|
|
api: "device_binding_v2.reject"
|
|
params:
|
|
approvalId: "${approval_id_2}"
|
|
reason: "Device not authorized for this user"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.success == true"
|
|
|
|
# P2-1: Batch Approve
|
|
- id: "TC005"
|
|
name: "Batch Approve Multiple Bindings"
|
|
description: "Test P2-1: Batch approve 3 device binding requests"
|
|
setup:
|
|
- action: "request_multiple_bindings"
|
|
description: "Create 3 pending approval requests"
|
|
save_response:
|
|
approval_ids: "data.approvalIds" # Array of approval IDs
|
|
steps:
|
|
- action: "batch_approve"
|
|
api: "device_binding_v2.batch_approve"
|
|
params:
|
|
approvalIds: "${approval_ids}"
|
|
comments: "Batch approved for testing"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.successCount == 3"
|
|
- "response.data.failedCount == 0"
|
|
|
|
# P3-3: Batch Approve with Confirm Token
|
|
- id: "TC006"
|
|
name: "Batch Approve with Confirm Token"
|
|
description: "Test P3-3: Two-step batch approval with confirm token"
|
|
setup:
|
|
- action: "request_multiple_bindings"
|
|
description: "Create 2 pending approval requests"
|
|
save_response:
|
|
approval_ids_batch: "data.approvalIds"
|
|
steps:
|
|
- action: "generate_confirm_token"
|
|
api: "device_binding_v2.generate_confirm_token"
|
|
params:
|
|
approvalIds: "${approval_ids_batch}"
|
|
save_response:
|
|
confirm_token: "data.confirmToken"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.expiresIn == 300"
|
|
|
|
- action: "batch_approve_with_confirm"
|
|
api: "device_binding_v2.batch_approve_with_confirm"
|
|
params:
|
|
approvalIds: "${approval_ids_batch}"
|
|
actionType: "APPROVE"
|
|
comments: "Confirmed batch approval"
|
|
confirmToken: "${confirm_token}"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.successCount == 2"
|
|
|
|
# P2-2: User Self-Unbind
|
|
- id: "TC007"
|
|
name: "User Self-Unbind Device"
|
|
description: "Test P2-2: User unbinds their own device"
|
|
steps:
|
|
- action: "user_unbind"
|
|
api: "device_binding_v2.user_unbind"
|
|
params:
|
|
deviceSn: "CRFTQ000000001"
|
|
reason: "Switching to new device"
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.success == true"
|
|
|
|
# P2-2: Admin Force Unbind
|
|
- id: "TC008"
|
|
name: "Admin Force Unbind Device"
|
|
description: "Test P2-2: Admin force unbinds device from user"
|
|
steps:
|
|
- action: "admin_force_unbind"
|
|
api: "device_binding_v2.admin_force_unbind"
|
|
params:
|
|
deviceSn: "CRFTQ000000002"
|
|
reason: "Device reported lost"
|
|
notifyUser: true
|
|
assertions:
|
|
- "response.code == 200"
|
|
- "response.data.success == true"
|
|
|
|
# P3-2: SSE Event Stream (Manual Test)
|
|
- id: "TC009"
|
|
name: "SSE Real-time Event Stream"
|
|
description: "Test P3-2: Verify SSE connection and event delivery"
|
|
manual: true
|
|
notes: |
|
|
This test requires manual verification:
|
|
1. Open SSE connection: GET /api/v2/device/bind-events/stream
|
|
2. Request a device binding in another session
|
|
3. Verify event received: binding_status_change
|
|
4. Approve the binding
|
|
5. Verify event received: approval_result
|
|
6. Connection should auto-reconnect on disconnect
|
|
|
|
# Expected results
|
|
expected_results:
|
|
total_test_cases: 9
|
|
automated_tests: 8
|
|
manual_tests: 1
|
|
critical_paths:
|
|
- "Request → Query → Approve → Unbind"
|
|
- "Request → Reject"
|
|
- "Batch Approve"
|
|
- "Batch Approve with Confirm Token"
|
|
|
|
# Performance benchmarks
|
|
performance:
|
|
request_binding_p95: "< 200ms"
|
|
query_status_p95: "< 100ms"
|
|
approve_p95: "< 150ms"
|
|
batch_approve_p95: "< 500ms"
|
|
sse_connection_timeout: "30 minutes"
|
|
sse_event_latency: "< 100ms"
|
|
|
|
# Notes
|
|
notes: |
|
|
- All tests require valid SaToken authentication
|
|
- Device secrets must be pre-configured in device key service
|
|
- Confirm tokens expire after 5 minutes
|
|
- SSE connections timeout after 30 minutes
|
|
- Use exponential backoff for status polling (10s → 120s)
|