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>
20 KiB
20 KiB
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。- 风险 1:HTTP 插件管理 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消息在当前主链路中无明确生产者/消费者,测试时应区分“未实现”与“回归缺陷”。 - 风险 4:BLE、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/statusPOST /api/playPOST /api/pausePOST /api/nextPOST /api/previousPOST /api/goto/:indexGET /api/playlistPOST /api/scene/:namePOST /api/trigger/:namePOST /api/trigger/:name/:value
6.2 配置管理
GET /api/configGET /api/config/displayPOST /api/configGET /api/config/availablePOST /api/config/switch
6.3 视频/文件/App
GET /api/videosPOST /api/videos/uploadDELETE /api/videos/:filenameGET /api/app/infoGET /download/:filenameGET /api/files/:dirPOST /api/files/:dir/uploadGET /api/files/:dir/downloadPOST /api/files/:dir/deletePOST /api/files/movePOST /api/files/:dir/mkdir
6.4 WiFi / BLE / WebSocket / 插件管理
GET|POST /api/wifi/scanGET /api/wifi/statusPOST /api/wifi/connectPOST /api/wifi/ap/startPOST /api/wifi/ap/stopPOST /api/wifi/hotspot/startPOST /api/wifi/hotspot/stopPOST /api/ble/startPOST /api/ble/stopGET /api/ble/statusGET /wsGET /api/pluginsGET /api/plugins/:idPOST /api/plugins/:id/enablePOST /api/plugins/:id/disablePOST /api/plugins/:id/rollbackPOST /api/plugins/:id/switchPOST /api/plugins/installPOST /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;非法路径返回拒绝。
场景 9:WiFi 扫描与状态查询
- 前置条件:实机具备 WiFi 网卡与
nmcli;附近存在可扫描网络。 - 操作步骤:调用
GET /api/wifi/scan;随后调用GET /api/wifi/status。 - 预期结果:WiFiPlugin 返回去重后的网络列表;状态接口返回连接状态、SSID、IP;WebSocket 有
wifi_update。
场景 10:WiFi 连接成功
- 前置条件:准备可连接的测试 WiFi;账号密码正确。
- 操作步骤:调用
POST /api/wifi/connect;等待 1~10 秒后查询/api/wifi/status。 - 预期结果:连接命令进入 WifiPlugin;返回成功消息;状态转为 connected;IP 地址可读。
场景 11:AP 热点启停
- 前置条件:设备支持热点模式。
- 操作步骤:调用
POST /api/wifi/ap/start;确认热点启动;随后调用POST /api/wifi/ap/stop。 - 预期结果:热点名称和密码按请求生效;停止成功;兼容别名
/api/wifi/hotspot/*。
场景 12:BLE 配网成功链路
- 前置条件:BLE 在配置中启用;手机或测试脚本可写 GATT 特征;目标 WiFi 可用。
- 操作步骤:启动程序;通过 BLE 写入 SSID、密码、
connect命令;观察 BLE 状态特征、日志、WiFi 状态。 - 预期结果:BLE 将凭据转发为
WifiCommand::Connect;WifiPlugin 返回结果后 BLE 状态特征更新;HttpPlugin 反映ble_update与wifi_update。
场景 13:WebSocket 实时控制链路
- 前置条件: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 失败后恢复旧插件;资源无双开窗口。
场景 17:Flutter App 首次连接与实时状态
- 前置条件:Flutter App 安装完成;手机与设备网络可达。
- 操作步骤:Flutter App 输入设备地址并连接;进入主控页;触发播放/暂停;保持 WebSocket 连接。
- 预期结果:App 能读取
/api/status、/api/playlist、/api/ble/status;能接收status_update、state_update、wifi_update;UI 与设备状态一致。
场景 18:Flutter App 配网与 APK 下载入口
- 前置条件:HTTP 服务与下载目录启用;存在
downloads/showen-app.apk。 - 操作步骤:Flutter 通过 BLE 或 HTTP 执行配网;访问 App 下载信息接口;点击下载 APK。
- 预期结果:
/api/app/info返回正确版本、大小、下载地址;APK 下载成功;Flutter 侧配网链路完成且错误可回显。
8. 边界条件清单
-
- 空
playlist启动:/api/status、/api/videos、WebSocket 快照均不崩溃。
- 空
-
goto越界:返回400,不改变当前播放状态。
-
- 上传 100MB 边界:恰好上限通过,超过上限返回
413。
- 上传 100MB 边界:恰好上限通过,超过上限返回
-
- 文件名包含
..、/、\\:上传、下载、删除、配置切换均拒绝。
- 文件名包含
-
- WiFi SSID/密码包含空格、引号、反斜杠、冒号:命令参数保真。
-
- BLE 写入空 SSID 或空命令:状态特征返回错误,不向核心发送无效命令。
-
- 动态插件 manifest
id/version与目录不匹配:加载应失败且不污染注册表。
- 动态插件 manifest
-
- 动态插件 required capability 缺失于自测结果:视为失败并按策略处理。
-
ConfigReloadRequest指向损坏 JSON:Manager 记录失败,保留旧配置。
-
- WebSocket 收到非法 JSON 或缺少
cmd:返回结构化错误字符串,不影响连接。
- WebSocket 收到非法 JSON 或缺少
-
remote_control.enabled=false:HTTP 插件不启动监听,但系统其他插件正常工作。
-
- 关闭中的广播消息:
Shutdown广播后所有启用插件按逆序停止。
- 关闭中的广播消息:
9. 错误处理场景清单
-
- HTTP 发送到关闭的消息通道:播放/WiFi/插件管理 API 返回
500。
- HTTP 发送到关闭的消息通道:播放/WiFi/插件管理 API 返回
-
- WiFi 10 秒无响应:
/api/wifi/*返回504。
- WiFi 10 秒无响应:
-
- WiFi 返回非 JSON:HTTP 层返回
502。
- WiFi 返回非 JSON:HTTP 层返回
-
- WiFi 返回
{ok:false}:HTTP 层透传为500业务错误。
- WiFi 返回
-
- 配置更新请求体非 UTF-8:返回
400。
- 配置更新请求体非 UTF-8:返回
-
- 配置切换目标文件不存在:返回
404。
- 配置切换目标文件不存在:返回
-
- 文件下载缺少
path参数:返回400。
- 文件下载缺少
-
- 文件移动目标已存在:返回
409。
- 文件移动目标已存在:返回
-
- 静态插件 init/start 失败:启动整体失败并退出。
-
- 动态插件 init/start 失败:仅该插件禁用,其他插件继续运行。
-
- 动态插件错误阈值达到上限:
disable_and_log时禁用;auto_rollback时回退。
- 动态插件错误阈值达到上限:
-
- 热替换新插件启动失败:恢复旧插件;若恢复失败则明确标记 disabled。
-
- BLE worker 崩溃:3 秒重试;停止信号下应及时退出。
-
/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 fixture:2 人日。
- 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 三条交互链路联调。
- 所有关键用户场景、边界条件、错误处理场景均有执行记录。
- 已知阻断性问题清零,或被明确降级并获负责人确认。