Files
ShowenV2/docs/M1.2_TEST_PLAN.md
showen d30c111c71 feat: M1.1 完成 + M1.2 启动 — 全量更新
M1.1 收尾:
- 24项 P0/P1/P2 bug 修复 (Rust 107 tests + Flutter 15 tests)
- Flutter App v0.3: cupertino_icons 修复, 单元测试, 调试面板, APK 52.6MB
- 示例插件完善: manifest.json + 请求/响应示范 + 7个测试
- API 文档重写 (以 routes.rs 为唯一权威)
- MILESTONES.md 更新至 100%

M1.2 启动:
- P0: 插件管理 API 闭环 (handle_manager_message Custom 分支 + broadcast_plugin_states)
- ServiceManager 集成测试 8/8 (tests/m1_2_service_manager.rs)
- M1.2 测试计划 (docs/M1.2_TEST_PLAN.md, 18个E2E场景)
- 动态插件系统: auto_rollback + version_manager GC + 路径穿越防护

总计: Rust 115/115 测试, Flutter 15/15 测试, 零 warning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:12:42 +08:00

348 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M1.2 集成测试计划
## 1. 目标与范围
- 目标:完成 ShowenV2 在 M1.2 阶段的端到端集成测试、旧功能对齐验证、边界条件验证、错误处理验证与回归基线建立。
- 范围覆盖:`device``screen``wifi``video``ble``http` 六个内置插件动态插件系统Flutter App 通过 HTTP/WebSocket/BLE 的交互链路。
- 重点链路插件注册与启动、消息路由、配置热重载、视频控制、WiFi 配网、BLE 配网、文件管理、动态插件生命周期。
- 验收对齐:覆盖 `docs/MILESTONES.md` 中 M1.2 的全部任务项,并为 M1.3 性能优化提供可重复的基准输入。
## 2. 当前实现观察与 M1.2 风险
- `src/main.rs``device -> screen -> wifi -> video -> ble -> http` 注册静态插件,再扫描 `plugin_store/` 挂载动态插件。
- `src/core/service_manager.rs` 负责依赖排序、`init -> self_test -> start` 生命周期、消息路由、动态插件错误阈值、自动回退、启停与热替换。
- `src/plugins/http/routes.rs` 已暴露播放、配置、视频、文件、WiFi、BLE、插件管理、App 下载等 API。
- 风险 1HTTP 插件管理 API 通过 `Message::Custom` 向 Manager 发命令,但 `ServiceManager::handle_manager_message()` 当前未处理 `plugin_enable``plugin_disable``plugin_rollback``plugin_switch``plugin_install``plugin_check_updates`
- 风险 2`/api/plugins` 依赖 `plugin_states` 自定义消息更新状态,但当前源码中未看到 Manager 侧生产该消息,插件列表接口可能返回空状态。
- 风险 3`WifiProvisioned``DeviceEvent`、部分 `Custom` 消息在当前主链路中无明确生产者/消费者,测试时应区分“未实现”与“回归缺陷”。
- 风险 4BLE、WiFi、显示、OpenCV、动态插件 `.so` 装载均依赖 ARM64 实机环境CI 只能承担部分替身测试。
## 3. 测试策略
### 3.1 分层策略
- 单元测试验证纯逻辑、解析、状态转换、命令拼装、路径校验、manifest 校验、消息序列化。
- 集成测试:验证 `ServiceManager` 与插件间消息流、配置重载、插件生命周期、HTTP 路由到消息总线的桥接。
- 端到端测试:以真实进程启动 `showen_v2`,通过 HTTP/WebSocket/BLE/文件系统操作驱动系统,校验插件协同与用户可见结果。
### 3.2 层级分工
- 单元:优先放在 `src/core/*``src/plugins/*` 内部测试,补齐未覆盖的解析和错误分支。
- 集成:新增 `tests/m1_2_*.rs`使用临时目录、测试配置、fake backend、fake dynamic plugin store 驱动系统。
- E2E以 ARM64 实机为主CI 仅跑“无硬件替身版”流程WebSocket/HTTP 使用 `curl``websocat`、Flutter 测试桩执行。
### 3.3 覆盖原则
- 所有非 `-` 消息交互单元至少有 1 条自动化验证。
- 所有用户入口 API 至少有 1 条成功场景和 1 条失败场景。
- 所有动态插件生命周期动作至少覆盖:加载、必需能力自测失败、错误阈值禁用、自动回退、热替换恢复。
- Flutter 侧至少覆盖首次连接、实时状态、WiFi 配网、配置读取/保存、APK 下载入口。
## 4. src 模块视图
- `src/main.rs`:程序入口、配置加载、静态/动态插件注册、主循环。
- `src/core/`:消息模型、插件 trait、ServiceManager、PluginLoader、VersionManager。
- `src/plugins/device/`:统一设备能力入口,响应 `DeviceCommand` 并广播 `DeviceResponse`
- `src/plugins/screen/`DevicePlugin thin wrapper负责防息屏与光标隐藏。
- `src/plugins/wifi/`nmcli 驱动的 WiFi 扫描/连接/AP 管理。
- `src/plugins/video/`OpenCV 播放器、状态机、状态广播。
- `src/plugins/ble/`BlueZ GATT 配网服务,接收 WiFi 结果并向核心转发 WiFi 指令。
- `src/plugins/http/`REST/WebSocket/Web UI/App 下载与文件管理桥接层。
## 5. 插件 × Message 覆盖矩阵
说明:`Rx`=直接处理,`Tx`=直接发送/广播,`Bridge`=对外桥接或间接映射,`Gap`=已有入口但当前实现未闭环,`-`=无直接关系。
| 插件/系统 | PlayerCommand | PlayerStatus | Trigger | StateChanged | ScreenLockRequest | CursorVisibility | WifiCommand | WifiResult | WifiProvisioned | ConfigReloaded | ConfigReloadRequest | Shutdown | PluginReady | DeviceCommand | DeviceResponse | DeviceEvent | Custom |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DevicePlugin | - | - | - | - | - | - | - | - | - | - | - | Rx | Rx | Rx | Tx | - | - |
| ScreenPlugin | - | - | - | - | Rx/Tx | Rx/Tx | - | - | - | - | - | Rx | - | Tx | - | - | - |
| WifiPlugin | - | - | - | - | - | - | Rx | Tx | - | - | - | - | - | - | - | - | - |
| VideoPlugin | Rx | Tx | Rx | Tx | Tx | - | - | - | - | Rx | - | Rx | Tx | - | - | - | - |
| BlePlugin | - | - | - | - | - | - | Tx(经 GATT) | Rx | - | - | - | Rx | Tx | - | - | - | - |
| HttpPlugin | Bridge | Rx/Bridge | Bridge | Rx/Bridge | - | - | Bridge | Rx/Bridge | - | Rx/Bridge | Tx/Bridge | Rx | Rx(ble) | - | - | - | Rx(`plugin_states`) |
| 动态插件系统 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | - | Rx | 视插件而定 | 视插件而定 | 视插件而定 | 视插件而定 | Rx/Tx |
| Flutter App | Bridge | Bridge | Bridge | Bridge | - | - | Bridge | Bridge | Bridge(BLE 配网结果) | Bridge | Bridge | - | Bridge(状态映射) | - | - | - | Bridge(插件管理入口) |
### 5.1 重点补测项
- `DeviceResponse`:补足 DevicePlugin 与 ScreenPlugin/业务插件的联动验证,确认 thin wrapper 没有只发不收的问题。
- `PluginReady`:验证 `video``http``ble` 的 ready 事件被 Manager 广播后HTTP/Flutter 状态同步是否准确。
- `Custom`动态插件自定义消息已有基础HTTP 插件管理类 `Custom` 当前缺少 Manager 闭环,应作为 M1.2 对齐缺陷优先验证。
## 6. HTTP API 覆盖范围
### 6.1 播放与状态
- `GET /api/status`
- `POST /api/play`
- `POST /api/pause`
- `POST /api/next`
- `POST /api/previous`
- `POST /api/goto/:index`
- `GET /api/playlist`
- `POST /api/scene/:name`
- `POST /api/trigger/:name`
- `POST /api/trigger/:name/:value`
### 6.2 配置管理
- `GET /api/config`
- `GET /api/config/display`
- `POST /api/config`
- `GET /api/config/available`
- `POST /api/config/switch`
### 6.3 视频/文件/App
- `GET /api/videos`
- `POST /api/videos/upload`
- `DELETE /api/videos/:filename`
- `GET /api/app/info`
- `GET /download/:filename`
- `GET /api/files/:dir`
- `POST /api/files/:dir/upload`
- `GET /api/files/:dir/download`
- `POST /api/files/:dir/delete`
- `POST /api/files/move`
- `POST /api/files/:dir/mkdir`
### 6.4 WiFi / BLE / WebSocket / 插件管理
- `GET|POST /api/wifi/scan`
- `GET /api/wifi/status`
- `POST /api/wifi/connect`
- `POST /api/wifi/ap/start`
- `POST /api/wifi/ap/stop`
- `POST /api/wifi/hotspot/start`
- `POST /api/wifi/hotspot/stop`
- `POST /api/ble/start`
- `POST /api/ble/stop`
- `GET /api/ble/status`
- `GET /ws`
- `GET /api/plugins`
- `GET /api/plugins/:id`
- `POST /api/plugins/:id/enable`
- `POST /api/plugins/:id/disable`
- `POST /api/plugins/:id/rollback`
- `POST /api/plugins/:id/switch`
- `POST /api/plugins/install`
- `POST /api/plugins/check-updates`
## 7. 端到端场景清单
每个场景均要求记录日志、HTTP 响应、WebSocket 事件、关键文件变化、插件状态快照。
### 场景 1系统冷启动与插件注册
- 前置条件ARM64 实机;有效配置文件;`plugin_store/` 为空或仅含稳定动态插件。
- 操作步骤:启动主程序;观察启动日志;调用 `GET /api/status`;建立 `/ws` 连接。
- 预期结果6 个内置插件按依赖顺序启动;若动态插件存在则完成自测;`/api/status` 可返回WebSocket 首包包含 `status_update``config_update``ble_update`
### 场景 2播放控制主链路
- 前置条件:播放列表至少 2 个有效视频HTTP 服务启用。
- 操作步骤:依次调用 `/api/play``/api/pause``/api/play``/api/next``/api/previous`
- 预期结果VideoPlugin 正确切换状态WebSocket 推送 `status_update`;暂停时触发 ScreenPlugin 释放防息屏,恢复播放时重新加锁。
### 场景 3按索引跳转视频
- 前置条件:播放列表长度 >= 3。
- 操作步骤:调用 `POST /api/goto/2`,随后调用 `GET /api/status`
- 预期结果:当前索引变为 2当前视频与目标条目一致无越界异常。
### 场景 4状态机触发器切换场景
- 前置条件:配置内存在多个 state/trigger 规则。
- 操作步骤:调用 `POST /api/trigger/voice/name` 或 WebSocket `{"cmd":"trigger","name":"voice","value":"name"}`
- 预期结果VideoPlugin 接收 `Trigger`;若状态变化则广播 `StateChanged`HTTP/WebSocket 观察到 `state_update`
### 场景 5配置热重载
- 前置条件:当前配置文件合法,可修改显示或播放参数。
- 操作步骤:`POST /api/config` 提交合法 JSON观察日志与 `/ws`;再次调用 `/api/config`
- 预期结果配置文件落盘Manager 处理 `ConfigReloadRequest` 并广播 `ConfigReloaded`VideoPlugin 与 HttpPlugin 更新内部状态;新配置立即可见。
### 场景 6切换配置文件
- 前置条件:`configs/` 下至少 2 个合法配置文件。
- 操作步骤:调用 `GET /api/config/available`,选择另一个配置后调用 `POST /api/config/switch`
- 预期结果:目标配置通过校验后覆盖当前活动配置;系统广播配置重载;`active` 配置更新。
### 场景 7视频文件上传与删除
- 前置条件:视频目录可写;准备 1 个小视频文件。
- 操作步骤:调用 `/api/videos/upload` 上传;调用 `/api/videos` 检查列表;随后调用 `DELETE /api/videos/:filename`
- 预期结果:上传成功且文件可见;删除后列表消失;不会因文件名注入逃逸目录。
### 场景 8文件管理器跨目录操作
- 前置条件:`videos/``configs/``plugin_store/` 可访问;创建测试子目录。
- 操作步骤:调用 `/api/files/:dir` 浏览、`mkdir` 新建目录、`upload` 上传、`move` 移动、`download` 下载、`delete` 删除。
- 预期结果:仅允许受管目录;子路径校验生效;跨文件系统移动可回退到 copy+delete非法路径返回拒绝。
### 场景 9WiFi 扫描与状态查询
- 前置条件:实机具备 WiFi 网卡与 `nmcli`;附近存在可扫描网络。
- 操作步骤:调用 `GET /api/wifi/scan`;随后调用 `GET /api/wifi/status`
- 预期结果WiFiPlugin 返回去重后的网络列表状态接口返回连接状态、SSID、IPWebSocket 有 `wifi_update`
### 场景 10WiFi 连接成功
- 前置条件:准备可连接的测试 WiFi账号密码正确。
- 操作步骤:调用 `POST /api/wifi/connect`;等待 1~10 秒后查询 `/api/wifi/status`
- 预期结果:连接命令进入 WifiPlugin返回成功消息状态转为 connectedIP 地址可读。
### 场景 11AP 热点启停
- 前置条件:设备支持热点模式。
- 操作步骤:调用 `POST /api/wifi/ap/start`;确认热点启动;随后调用 `POST /api/wifi/ap/stop`
- 预期结果:热点名称和密码按请求生效;停止成功;兼容别名 `/api/wifi/hotspot/*`
### 场景 12BLE 配网成功链路
- 前置条件BLE 在配置中启用;手机或测试脚本可写 GATT 特征;目标 WiFi 可用。
- 操作步骤:启动程序;通过 BLE 写入 SSID、密码、`connect` 命令;观察 BLE 状态特征、日志、WiFi 状态。
- 预期结果BLE 将凭据转发为 `WifiCommand::Connect`WifiPlugin 返回结果后 BLE 状态特征更新HttpPlugin 反映 `ble_update``wifi_update`
### 场景 13WebSocket 实时控制链路
- 前置条件WebSocket 已连接。
- 操作步骤:发送 `play``pause``goto``trigger``connect``ap_start` 命令 JSON。
- 预期结果:合法命令被解析为内部消息并入队;响应 `{"ok":true}`;状态更新推送到客户端。
### 场景 14动态插件挂载与自测通过
- 前置条件:`plugin_store/registry.json` 指向一个合法动态插件版本manifest 声明 capability 且自测通过。
- 操作步骤:启动程序;查看日志与插件状态接口。
- 预期结果:动态插件被加载、`init``self_test``start`;必需能力通过;插件状态显示 enabled。
### 场景 15动态插件必需能力失败并自动回退
- 前置条件:准备 active 版本失败、stable 版本可回退的动态插件仓库;错误策略为 `auto_rollback`
- 操作步骤:启动程序或发送触发失败的消息直至达到错误阈值。
- 预期结果:当前版本被禁用并触发回退;若稳定版本可重载则恢复运行;否则 `needs_rollback=true` 并记录日志。
### 场景 16动态插件热替换恢复旧版本
- 前置条件:已加载动态插件;准备一个启动失败的新版本。
- 操作步骤:通过测试钩子或后续管理命令触发热替换。
- 预期结果:旧插件先 stop新插件 init/start 失败后恢复旧插件;资源无双开窗口。
### 场景 17Flutter App 首次连接与实时状态
- 前置条件Flutter App 安装完成;手机与设备网络可达。
- 操作步骤Flutter App 输入设备地址并连接;进入主控页;触发播放/暂停;保持 WebSocket 连接。
- 预期结果App 能读取 `/api/status``/api/playlist``/api/ble/status`;能接收 `status_update``state_update``wifi_update`UI 与设备状态一致。
### 场景 18Flutter App 配网与 APK 下载入口
- 前置条件HTTP 服务与下载目录启用;存在 `downloads/showen-app.apk`
- 操作步骤Flutter 通过 BLE 或 HTTP 执行配网;访问 App 下载信息接口;点击下载 APK。
- 预期结果:`/api/app/info` 返回正确版本、大小、下载地址APK 下载成功Flutter 侧配网链路完成且错误可回显。
## 8. 边界条件清单
- 1. 空 `playlist` 启动:`/api/status``/api/videos`、WebSocket 快照均不崩溃。
- 2. `goto` 越界:返回 `400`,不改变当前播放状态。
- 3. 上传 100MB 边界:恰好上限通过,超过上限返回 `413`
- 4. 文件名包含 `..``/``\\`:上传、下载、删除、配置切换均拒绝。
- 5. WiFi SSID/密码包含空格、引号、反斜杠、冒号:命令参数保真。
- 6. BLE 写入空 SSID 或空命令:状态特征返回错误,不向核心发送无效命令。
- 7. 动态插件 manifest `id/version` 与目录不匹配:加载应失败且不污染注册表。
- 8. 动态插件 required capability 缺失于自测结果:视为失败并按策略处理。
- 9. `ConfigReloadRequest` 指向损坏 JSONManager 记录失败,保留旧配置。
- 10. WebSocket 收到非法 JSON 或缺少 `cmd`:返回结构化错误字符串,不影响连接。
- 11. `remote_control.enabled=false`HTTP 插件不启动监听,但系统其他插件正常工作。
- 12. 关闭中的广播消息:`Shutdown` 广播后所有启用插件按逆序停止。
## 9. 错误处理场景清单
- 1. HTTP 发送到关闭的消息通道:播放/WiFi/插件管理 API 返回 `500`
- 2. WiFi 10 秒无响应:`/api/wifi/*` 返回 `504`
- 3. WiFi 返回非 JSONHTTP 层返回 `502`
- 4. WiFi 返回 `{ok:false}`HTTP 层透传为 `500` 业务错误。
- 5. 配置更新请求体非 UTF-8返回 `400`
- 6. 配置切换目标文件不存在:返回 `404`
- 7. 文件下载缺少 `path` 参数:返回 `400`
- 8. 文件移动目标已存在:返回 `409`
- 9. 静态插件 init/start 失败:启动整体失败并退出。
- 10. 动态插件 init/start 失败:仅该插件禁用,其他插件继续运行。
- 11. 动态插件错误阈值达到上限:`disable_and_log` 时禁用;`auto_rollback` 时回退。
- 12. 热替换新插件启动失败:恢复旧插件;若恢复失败则明确标记 disabled。
- 13. BLE worker 崩溃3 秒重试;停止信号下应及时退出。
- 14. `/api/plugins*` 命令当前无 Manager 闭环:应在 M1.2 先作为已知功能对齐缺陷立项验证并修复。
## 10. 性能基准定义
M1.2 不做深度优化,但必须建立可重复基准,供 M1.3 追踪。
- 启动时间:从进程启动到 `http``video` 均发出 `PluginReady`,目标 `<= 3s`(无动态插件时)。
- HTTP 控制延迟:`POST /api/play` 到首个 `status_update`P95 `<= 200ms`
- WebSocket 状态推送延迟内部消息到客户端收到事件P95 `<= 150ms`
- 配置热重载耗时:`POST /api/config``config_update` 推送完成P95 `<= 500ms`
- WiFi 状态查询:单次 `/api/wifi/status` 完成时间 P95 `<= 3s`,超时阈值 10s。
- 视频上传100MB 文件上传不出现进程 OOM峰值 RSS 不超过基线版本 120%。
- 长稳冒烟:连续 4 小时播放 + WebSocket 连接 + 周期性 WiFi 状态查询,无崩溃、无句柄泄漏迹象。
- 动态插件回退:达到错误阈值到完成禁用/回退标记P95 `<= 1s`(不含磁盘 I/O 抖动)。
## 11. 测试环境要求
### 11.1 ARM64 实机
- Linux ARM64。
- 安装 `nmcli`、BlueZ、OpenCV 运行时、`websocat``curl`
- 具备显示输出、WiFi 网卡、BLE 适配器。
- 可访问测试路由器,并可创建 AP 热点。
- 支持动态插件 `.so` 装载与回退仓库读写。
### 11.2 CI 环境
- 运行 Rust 单元/集成测试。
- 使用 fake backend/fake plugin store 替代硬件。
- 执行 HTTP 路由级测试、消息序列化测试、ServiceManager 生命周期测试。
- 不承担真实 OpenCV 显示、真实 WiFi/BLE、真实动态 `.so` 装载回归。
### 11.3 Flutter 联调环境
- Android 真机优先,至少 1 台;若支持则补 1 台 iOS 设备做网络连通冒烟。
- Flutter App 使用与服务端同版本 API 模型。
- 同时验证 HTTP 轮询回退与 WebSocket 实时模式。
## 12. 自动化落地建议
- 新增 `tests/m1_2_service_manager.rs`:启动顺序、关闭顺序、广播、配置重载、动态插件错误策略。
- 新增 `tests/m1_2_http.rs`:播放/配置/文件/WiFi/BLE/插件管理 API 路由级验证。
- 新增 `tests/m1_2_dynamic_plugin.rs`registry、manifest、热替换、回退、必需能力失败。
- 新增 `scripts/e2e/`:实机冒烟脚本,串联 `curl + websocat + 日志断言`
- 新增 `clients/flutter/integration_test/`设备发现、状态同步、WiFi 配网、配置保存。
## 13. 预估工作量与排期建议
### 13.1 工作量
- 测试基建与 fake fixture2 人日。
- HTTP/ServiceManager 集成测试补齐3 人日。
- 动态插件系统回退/热替换测试2 人日。
- ARM64 实机 WiFi/BLE/视频链路验证3 人日。
- Flutter 联调与回归2 人日。
- 缺陷修复回归缓冲2~4 人日。
- 合计12~16 人日。
### 13.2 两周建议排期
- 第 1-2 天:补齐测试基建,冻结 M1.2 测试配置与样本数据。
- 第 3-5 天:完成 ServiceManager、HTTP、文件管理、配置热重载自动化测试。
- 第 6-7 天:完成动态插件系统自动化测试,并确认插件管理 API 闭环缺陷。
- 第 8-10 天ARM64 实机执行视频/WiFi/BLE/Flutter E2E集中提单。
- 第 11-12 天:修复缺陷并回归,补齐性能基线数据。
- 第 13-14 天:做旧版本功能对齐复盘、输出测试报告与遗留风险清单。
## 14. M1.2 完成判定
- 六个内置插件均有成功链路与失败链路验证证据。
- 动态插件系统完成加载、自测、禁用、回退、热替换验证。
- Flutter App 完成 HTTP/WebSocket/BLE 三条交互链路联调。
- 所有关键用户场景、边界条件、错误处理场景均有执行记录。
- 已知阻断性问题清零,或被明确降级并获负责人确认。