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

20 KiB
Raw Permalink Blame History

M1.2 集成测试计划

1. 目标与范围

  • 目标:完成 ShowenV2 在 M1.2 阶段的端到端集成测试、旧功能对齐验证、边界条件验证、错误处理验证与回归基线建立。
  • 范围覆盖:devicescreenwifivideoblehttp 六个内置插件动态插件系统Flutter App 通过 HTTP/WebSocket/BLE 的交互链路。
  • 重点链路插件注册与启动、消息路由、配置热重载、视频控制、WiFi 配网、BLE 配网、文件管理、动态插件生命周期。
  • 验收对齐:覆盖 docs/MILESTONES.md 中 M1.2 的全部任务项,并为 M1.3 性能优化提供可重复的基准输入。

2. 当前实现观察与 M1.2 风险

  • src/main.rsdevice -> 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_enableplugin_disableplugin_rollbackplugin_switchplugin_installplugin_check_updates
  • 风险 2/api/plugins 依赖 plugin_states 自定义消息更新状态,但当前源码中未看到 Manager 侧生产该消息,插件列表接口可能返回空状态。
  • 风险 3WifiProvisionedDeviceEvent、部分 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 使用 curlwebsocat、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:验证 videohttpble 的 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_updateconfig_updateble_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;若状态变化则广播 StateChangedHTTP/WebSocket 观察到 state_update

场景 5配置热重载

  • 前置条件:当前配置文件合法,可修改显示或播放参数。
  • 操作步骤:POST /api/config 提交合法 JSON观察日志与 /ws;再次调用 /api/config
  • 预期结果配置文件落盘Manager 处理 ConfigReloadRequest 并广播 ConfigReloadedVideoPlugin 与 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::ConnectWifiPlugin 返回结果后 BLE 状态特征更新HttpPlugin 反映 ble_updatewifi_update

场景 13WebSocket 实时控制链路

  • 前置条件WebSocket 已连接。
  • 操作步骤:发送 playpausegototriggerconnectap_start 命令 JSON。
  • 预期结果:合法命令被解析为内部消息并入队;响应 {"ok":true};状态更新推送到客户端。

场景 14动态插件挂载与自测通过

  • 前置条件:plugin_store/registry.json 指向一个合法动态插件版本manifest 声明 capability 且自测通过。
  • 操作步骤:启动程序;查看日志与插件状态接口。
  • 预期结果:动态插件被加载、initself_teststart;必需能力通过;插件状态显示 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_updatestate_updatewifi_updateUI 与设备状态一致。

场景 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 快照均不崩溃。
    1. goto 越界:返回 400,不改变当前播放状态。
    1. 上传 100MB 边界:恰好上限通过,超过上限返回 413
    1. 文件名包含 ../\\:上传、下载、删除、配置切换均拒绝。
    1. WiFi SSID/密码包含空格、引号、反斜杠、冒号:命令参数保真。
    1. BLE 写入空 SSID 或空命令:状态特征返回错误,不向核心发送无效命令。
    1. 动态插件 manifest id/version 与目录不匹配:加载应失败且不污染注册表。
    1. 动态插件 required capability 缺失于自测结果:视为失败并按策略处理。
    1. ConfigReloadRequest 指向损坏 JSONManager 记录失败,保留旧配置。
    1. WebSocket 收到非法 JSON 或缺少 cmd:返回结构化错误字符串,不影响连接。
    1. remote_control.enabled=falseHTTP 插件不启动监听,但系统其他插件正常工作。
    1. 关闭中的广播消息:Shutdown 广播后所有启用插件按逆序停止。

9. 错误处理场景清单

    1. HTTP 发送到关闭的消息通道:播放/WiFi/插件管理 API 返回 500
    1. WiFi 10 秒无响应:/api/wifi/* 返回 504
    1. WiFi 返回非 JSONHTTP 层返回 502
    1. WiFi 返回 {ok:false}HTTP 层透传为 500 业务错误。
    1. 配置更新请求体非 UTF-8返回 400
    1. 配置切换目标文件不存在:返回 404
    1. 文件下载缺少 path 参数:返回 400
    1. 文件移动目标已存在:返回 409
    1. 静态插件 init/start 失败:启动整体失败并退出。
    1. 动态插件 init/start 失败:仅该插件禁用,其他插件继续运行。
    1. 动态插件错误阈值达到上限:disable_and_log 时禁用;auto_rollback 时回退。
    1. 热替换新插件启动失败:恢复旧插件;若恢复失败则明确标记 disabled。
    1. BLE worker 崩溃3 秒重试;停止信号下应及时退出。
    1. /api/plugins* 命令当前无 Manager 闭环:应在 M1.2 先作为已知功能对齐缺陷立项验证并修复。

10. 性能基准定义

M1.2 不做深度优化,但必须建立可重复基准,供 M1.3 追踪。

  • 启动时间:从进程启动到 httpvideo 均发出 PluginReady,目标 <= 3s(无动态插件时)。
  • HTTP 控制延迟:POST /api/play 到首个 status_updateP95 <= 200ms
  • WebSocket 状态推送延迟内部消息到客户端收到事件P95 <= 150ms
  • 配置热重载耗时:POST /api/configconfig_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 运行时、websocatcurl
  • 具备显示输出、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.rsregistry、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 三条交互链路联调。
  • 所有关键用户场景、边界条件、错误处理场景均有执行记录。
  • 已知阻断性问题清零,或被明确降级并获负责人确认。