docs: camera_code改造测试报告

添加完整的测试报告文档,包括:
- 测试概述与环境要求
- 数据库迁移验证步骤
- 功能测试用例(摄像头创建、ROI截图、配置推送)
- 数据一致性测试
- 异常测试场景
- 性能测试
- 集成测试场景
- 回归测试
- 测试清单与风险评估

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-13 11:49:39 +08:00
parent 450afb8112
commit 87c75608f1

View File

@@ -0,0 +1,546 @@
# camera_code 改造测试报告
## 一、测试概述
**测试目标**: 验证 camera_code 全链路改造的功能完整性和数据一致性
**测试时间**: 2026-02-13
**改造范围**:
- 后端数据库、StreamProxy模块、AIoT模块
- 前端摄像头管理、ROI配置、API调用
**测试环境要求**:
- MySQL 5.7+
- Redis 6.0+
- ZLMediaKit 流媒体服务器
- 前端开发环境Node.js 18+
- 后端 Java 环境JDK 17+
---
## 二、测试准备
### 2.1 数据库迁移验证
**脚本位置**: `C:\workspace\wvp-platform\数据库\aiot\迁移-添加camera_code字段.sql`
**执行步骤**:
```bash
# 1. 进入SQL脚本目录
cd C:\workspace\wvp-platform\数据库\aiot
# 2. 执行迁移脚本需要MySQL客户端
mysql -h localhost -u root -p your_database < 迁移-添加camera_code字段.sql
```
**预期结果**:
1.`wvp_stream_proxy` 表新增 `camera_code` 字段
2. ✅ 现有数据自动生成 `camera_code`(格式:`cam_xxxxxxxxxxxx`
3.`camera_code` 字段设置为 NOT NULL 和 UNIQUE 约束
4.`wvp_ai_roi` 表的 `camera_id` 字段更新为对应的 `camera_code`
5. ✅ 验证查询显示无重复、无格式错误
**验证SQL**:
```sql
-- 检查字段是否添加成功
SHOW COLUMNS FROM wvp_stream_proxy LIKE 'camera_code';
-- 检查唯一索引
SHOW INDEX FROM wvp_stream_proxy WHERE Key_name = 'uk_camera_code';
-- 检查数据完整性应返回0
SELECT COUNT(*) FROM wvp_stream_proxy WHERE camera_code IS NULL;
-- 检查格式正确性应返回0
SELECT COUNT(*) FROM wvp_stream_proxy
WHERE camera_code NOT REGEXP '^cam_[a-f0-9]{12}$';
-- 检查ROI表迁移情况
SELECT COUNT(*) FROM wvp_ai_roi r
LEFT JOIN wvp_stream_proxy sp ON r.camera_id = sp.camera_code
WHERE sp.camera_code IS NULL;
```
---
## 三、功能测试用例
### 3.1 新增摄像头 - camera_code 自动生成
**测试目的**: 验证创建摄像头时 camera_code 自动生成逻辑
**前置条件**:
- 系统正常运行
- 流媒体服务器在线
**测试步骤**:
1. 访问前端摄像头管理页面
2. 点击"新增摄像头"按钮
3. 填写摄像头信息:
- 名称测试摄像头001
- 拉流地址rtsp://example.com/test/stream1
- 超时时间:默认
- 注意:**不需要手动填写 app 字段**(系统自动生成)
4. 提交保存
**预期结果**:
1. ✅ 摄像头创建成功
2. ✅ 系统自动生成 `camera_code`(格式:`cam_xxxxxxxxxxxx`
3.`app` 字段自动设置为与 `camera_code` 相同
4.`stream` 字段为系统生成的唯一标识
5. ✅ 数据库 `wvp_stream_proxy` 表中插入新记录
**验证SQL**:
```sql
SELECT id, camera_code, app, stream, name, src_url
FROM wvp_stream_proxy
WHERE name = '测试摄像头001';
```
**重点检查**:
- `camera_code` 格式符合 `^cam_[a-f0-9]{12}$`
- `app` = `camera_code`
- `camera_code` 在全表唯一
---
### 3.2 ROI 截图功能 - cameraCode 参数
**测试目的**: 验证 ROI 截图接口改用 cameraCode 参数
**前置条件**:
- 摄像头已创建并在线推流
- 流媒体服务器正常
**测试步骤**:
1. 访问 ROI 配置页面
2. 选择已创建的摄像头
3. 点击"获取截图"按钮
4. 观察网络请求F12开发者工具
**预期结果**:
1. ✅ 请求 URL`/api/ai/roi/snap?cameraCode=cam_xxxxxxxxxxxx`
2. ✅ 使用 `cameraCode` 参数(而非旧的 `app`/`stream`
3. ✅ 后端通过 `cameraCode` 查询 `StreamProxy` 对象
4. ✅ 获取到正确的 `app``stream`
5. ✅ 调用 ZLM 截图接口成功,返回图片数据
**验证方法**:
```javascript
// 浏览器控制台查看请求
// Network > Headers > Request URL
// 应包含 cameraCode=cam_xxxxxxxxxxxx
```
**错误处理测试**:
- 使用不存在的 `cameraCode` → 返回 404 Not Found
- 流媒体服务器离线 → 返回 503 Service Unavailable
---
### 3.3 配置推送到 Redis - camera_code 字段
**测试目的**: 验证配置推送使用 camera_code 查询和生成配置
**前置条件**:
- Redis 服务正常
- ROI 已配置并绑定算法
- Edge 设备在线
**测试步骤**:
1. 访问配置管理页面
2. 创建或更新 ROI 配置
3. 绑定算法模板
4. 执行"配置推送"操作
5. 检查 Redis 中的配置数据
**预期结果**:
1. ✅ 配置构建时使用 `camera_code` 查询 `StreamProxy`
2. ✅ 优先使用 `StreamProxy.srcUrl` 作为 `rtsp_url`
3. ✅ Redis 配置中包含 `camera_code` 字段
4. ✅ 保留 `camera_id` 字段向后兼容(值为 `app/stream`
5. ✅ StreamProxy 不存在时降级使用 MediaServer 构建 URL
**验证命令**:
```bash
# 连接 Redis 检查配置
redis-cli
# 查看配置 key
KEYS aiot:edge:config:*
# 查看具体配置内容
GET aiot:edge:config:{edge_device_id}
# 检查配置 JSON 中的字段
# 应包含:
# - camera_code: "cam_xxxxxxxxxxxx"
# - camera_id: "app/stream" (向后兼容)
# - rtsp_url: 优先来自 StreamProxy.srcUrl
```
**配置示例**:
```json
{
"cameras": [
{
"camera_code": "cam_a1b2c3d4e5f6",
"camera_id": "cam_a1b2c3d4e5f6/stream_12345",
"rtsp_url": "rtsp://example.com/test/stream1",
"rois": [
{
"roi_id": "roi_001",
"coordinates": [...],
"algorithms": [...]
}
]
}
]
}
```
---
### 3.4 前端展示和交互
**测试目的**: 验证前端页面正确使用 camera_code
**测试用例 3.4.1 - 摄像头管理页面**:
**测试步骤**:
1. 访问摄像头管理页面
2. 查看摄像头列表
3. 新增/编辑摄像头
**预期结果**:
1. ✅ 列表正确显示 `cameraCode` 字段
2. ✅ 新增表单**隐藏** `app` 输入框(自动生成)
3. ✅ API 调用使用新的 `cameraCode` 字段
4. ✅ 数据保存后正确回显
**测试用例 3.4.2 - ROI 配置页面**:
**测试步骤**:
1. 访问 ROI 配置页面
2. 选择摄像头
3. 获取截图
4. 配置 ROI 区域
**预期结果**:
1. ✅ 摄像头选择器显示 `cameraCode` 和名称
2. ✅ 截图请求使用 `cameraCode` 参数
3. ✅ ROI 保存时关联正确的 `cameraCode`
4. ✅ 配置查询使用 `cameraCode` 匹配
---
## 四、数据一致性测试
### 4.1 迁移数据验证
**测试目的**: 确保历史数据正确迁移
**验证SQL**:
```sql
-- 1. 检查所有 camera_code 都已生成
SELECT COUNT(*) AS total,
COUNT(camera_code) AS has_code
FROM wvp_stream_proxy;
-- total 应等于 has_code
-- 2. 检查 camera_code 格式
SELECT id, camera_code
FROM wvp_stream_proxy
WHERE camera_code NOT REGEXP '^cam_[a-f0-9]{12}$';
-- 应返回空
-- 3. 检查唯一性
SELECT camera_code, COUNT(*) AS cnt
FROM wvp_stream_proxy
GROUP BY camera_code
HAVING cnt > 1;
-- 应返回空
-- 4. 检查 ROI 表关联
SELECT r.roi_id, r.camera_id, r.name
FROM wvp_ai_roi r
LEFT JOIN wvp_stream_proxy sp ON r.camera_id = sp.camera_code
WHERE sp.camera_code IS NULL;
-- 应返回空(所有 ROI 都能找到对应的 camera_code
```
### 4.2 新旧数据兼容性
**测试场景**: 系统同时存在迁移的旧数据和新创建的数据
**验证点**:
1. ✅ 旧数据的 `camera_code` 格式正确
2. ✅ 新数据的 `camera_code` 与旧数据不冲突
3. ✅ ROI 查询同时支持新旧数据
4. ✅ 配置推送对新旧数据处理一致
---
## 五、异常测试
### 5.1 camera_code 重复冲突
**测试目的**: 验证重试机制
**模拟方法**:
- 理论上 UUID 生成的12位哈希极低概率重复
- 系统已实现最多3次重试机制
**预期结果**:
- ✅ 第一次冲突时自动重试
- ✅ 3次都冲突则抛出异常
- ✅ 错误日志记录详细信息
### 5.2 StreamProxy 不存在
**测试场景**: 使用无效的 cameraCode 调用接口
**测试步骤**:
1. 调用截图接口:`/api/ai/roi/snap?cameraCode=cam_invalid123`
2. 调用配置推送时 ROI 关联了不存在的 camera_code
**预期结果**:
- ✅ 截图接口返回 404 Not Found
- ✅ 配置推送时跳过该摄像头或使用降级逻辑
- ✅ 错误日志记录
### 5.3 数据库迁移失败回滚
**测试场景**: 迁移脚本执行失败
**可能原因**:
- 数据库权限不足
- 表不存在
- 字段已存在
**验证方法**:
```sql
-- 检查迁移是否完成
SHOW COLUMNS FROM wvp_stream_proxy LIKE 'camera_code';
-- 如果失败,检查错误日志
SHOW ENGINE INNODB STATUS;
```
---
## 六、性能测试
### 6.1 camera_code 生成性能
**测试方法**: 批量创建摄像头
**测试步骤**:
1. 使用脚本批量调用新增摄像头接口
2. 创建 100 个摄像头
3. 记录平均响应时间
**预期结果**:
- ✅ 单次生成 camera_code 耗时 < 5ms
- 数据库唯一索引查询性能正常
- 重试机制不影响整体性能
### 6.2 查询性能
**测试SQL**:
```sql
-- 1. 按 camera_code 查询(应使用唯一索引)
EXPLAIN SELECT * FROM wvp_stream_proxy WHERE camera_code = 'cam_a1b2c3d4e5f6';
-- type: const 或 eq_ref
-- 2. ROI 关联查询
EXPLAIN SELECT r.*, sp.name, sp.src_url
FROM wvp_ai_roi r
INNER JOIN wvp_stream_proxy sp ON r.camera_id = sp.camera_code
WHERE sp.camera_code = 'cam_a1b2c3d4e5f6';
-- 应使用索引
```
---
## 七、集成测试场景
### 场景1: 完整业务流程
**流程步骤**:
1. 新增摄像头自动生成 camera_code
2. 创建 ROI 区域关联 camera_code
3. 绑定算法模板
4. 获取截图验证使用 cameraCode 参数
5. 推送配置到 Redis包含 camera_code
6. Edge 设备消费配置
**验证点**:
- 每个步骤数据传递正确
- camera_code 作为全局唯一标识贯穿全流程
- 前后端数据一致
### 场景2: 多摄像头配置
**测试步骤**:
1. 创建 5 个摄像头
2. 为每个摄像头配置 2-3 ROI
3. 绑定不同算法
4. 批量推送配置
**验证点**:
- 所有 camera_code 唯一
- ROI 正确关联到对应摄像头
- Redis 配置结构正确
- 无数据混乱
---
## 八、回归测试
### 8.1 旧功能验证
**测试项**:
- 摄像头列表查询
- 摄像头编辑/删除
- 流媒体代理功能
- 国标设备对接
- 录像管理
**预期**: 所有旧功能正常工作不受 camera_code 改造影响
### 8.2 API 兼容性
**验证点**:
- 新接口正确处理 cameraCode
- 旧接口如果有仍可用或有明确废弃提示
- 响应数据结构兼容
---
## 九、测试总结
### 9.1 测试清单
| 测试项 | 优先级 | 状态 | 备注 |
|--------|--------|------|------|
| 数据库迁移脚本执行 | P0 | 待测 | 需要MySQL环境 |
| camera_code 自动生成 | P0 | 待测 | 核心功能 |
| camera_code 唯一性 | P0 | 待测 | 数据完整性 |
| ROI 截图接口 cameraCode 参数 | P0 | 待测 | API改造 |
| 配置推送 camera_code 字段 | P0 | 待测 | Redis配置 |
| 前端摄像头管理页面 | P1 | 待测 | UI交互 |
| 前端 ROI 配置页面 | P1 | 待测 | UI交互 |
| 数据一致性验证 | P0 | 待测 | 迁移验证 |
| 异常处理测试 | P1 | 待测 | 容错机制 |
| 性能测试 | P2 | 待测 | 非阻塞 |
### 9.2 风险评估
**高风险项**:
1. 数据库迁移失败 **建议先备份数据库**
2. 历史数据 camera_code 生成冲突 已有重试机制
3. ROI camera_id 更新不完整 迁移脚本有验证SQL
**缓解措施**:
- 在测试环境先完整执行一遍
- 准备回滚方案
- 监控生产环境日志
### 9.3 建议测试顺序
1. **第一阶段(核心功能)**:
- 数据库迁移
- camera_code 自动生成
- 数据一致性验证
2. **第二阶段(接口改造)**:
- ROI 截图接口
- 配置推送功能
- API 调用验证
3. **第三阶段(前端集成)**:
- 摄像头管理页面
- ROI 配置页面
- 端到端流程测试
4. **第四阶段(回归测试)**:
- 旧功能验证
- 性能测试
- 异常场景
### 9.4 部署前检查项
- [ ] 数据库迁移脚本在测试环境验证通过
- [ ] 所有 P0 测试用例通过
- [ ] 前后端代码已同步部署
- [ ] Redis 配置结构兼容旧版本向后兼容
- [ ] 回滚方案准备就绪
- [ ] 监控告警配置完成
---
## 十、附录
### 附录A: 相关代码文件清单
**后端文件**:
- `StreamProxy.java` - 新增 cameraCode 字段
- `StreamProxyMapper.java` - 新增 selectByCameraCode 查询
- `StreamProxyProvider.java` - SQL 生成逻辑
- `StreamProxyServiceImpl.java` - 自动生成和查询实现
- `IStreamProxyService.java` - 接口声明
- `AiRoiController.java` - snap 接口改造
- `AiRedisConfigServiceImpl.java` - 配置推送改造
**前端文件**:
- `apps/web-antd/src/api/aiot/device/index.ts` - API 类型定义
- `apps/web-antd/src/views/aiot/device/camera/index.vue` - 摄像头管理页面
- `apps/web-antd/src/views/aiot/device/roi/index.vue` - ROI 配置页面
- `apps/web-antd/src/views/aiot/device/roi/components/*.vue` - ROI 子组件
**数据库文件**:
- `数据库/aiot/迁移-添加camera_code字段.sql` - 迁移脚本
### 附录B: Git 提交记录
```
450afb811 feat(aiot): 配置推送使用camera_code查询StreamProxy
6d1e1d0bc feat(aiot): snap接口改用cameraCode参数查询StreamProxy
3792a3061 feat(streamProxy): 实现camera_code自动生成和查询逻辑
754677e11 feat(streamProxy): Service接口新增getStreamProxyByCameraCode方法
2b61113ba feat(streamProxy): Provider增加camera_code的SQL处理
2e89c2a62 feat(streamProxy): Mapper新增selectByCameraCode查询方法
b542432dc feat(streamProxy): StreamProxy增加cameraCode字段
0c8037726 fix(aiot): 迁移脚本增加camera_code格式验证
731291217 feat(aiot): 添加camera_code字段迁移脚本
ac345a472 feat(aiot): ROI配置页面改用cameraCode参数和截图调用
4bbc4b16d feat(aiot): 摄像头管理页面改用cameraCode隐藏app输入
2583ed533 feat(aiot): Camera接口增加cameraCode字段,getSnapUrl改用cameraCode
```
### 附录C: 测试数据示例
**摄像头测试数据**:
```sql
INSERT INTO wvp_stream_proxy (camera_code, app, stream, name, src_url, timeout, enable)
VALUES
('cam_test1234567', 'cam_test1234567', 'stream_001', '测试摄像头001', 'rtsp://example.com/test1', 30, 1),
('cam_test7654321', 'cam_test7654321', 'stream_002', '测试摄像头002', 'rtsp://example.com/test2', 30, 1);
```
**ROI 测试数据**:
```sql
INSERT INTO wvp_ai_roi (roi_id, camera_id, name, points)
VALUES
('roi_001', 'cam_test1234567', 'ROI区域1', '[[0,0],[100,0],[100,100],[0,100]]'),
('roi_002', 'cam_test1234567', 'ROI区域2', '[[200,200],[300,200],[300,300],[200,300]]');
```
---
**文档版本**: v1.0
**创建时间**: 2026-02-13
**创建人**: AI开发团队
**审核状态**: 待审核