Files
matrix-screen-controller/测试相关资料/如何测试/核桃派点阵屏控制服务测试流程.md
T

364 lines
68 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.
# 核桃派点阵屏控制服务测试流程
## 手机会话取消 WiFi 开机提示(TEST-WIFI-MOBILE-DISMISS)
对应 `DISPLAY-WIFI-INDICATOR`、`CONFIG-WIFI` 和 `DEVICE-MOBILE-SESSION`。直接影响设备会话入口、WiFi 覆盖取消与后台刷新;协议、App 和原生驱动不变。以本机 mock 覆盖延迟到期前连接、联网 IP/断网提示活动时连接、失败握手与无效参数、断开及网络变化、迟到查询并发、同 boot 重建和新 boot 重新计时;验证恢复用户帧,亮度、方向、模式和修订不变。
部署后只读 `/api/status` 和帧接口,**不得访问首页**,因为首页本身会取消提示而掩盖手机入口缺陷。先核对提示未取消,再用登记手机的 `run_ble_test.py --scenario connection` 完成会话及断开重连,不发送改屏命令;应为 `dismissed_for_boot=true`、`wifi_indicator_active=false`。真实 `systemctl restart` 后保持取消;整机软件重启后,在手机尚未连接时应重新计时,等待提示延迟到期,再连接手机复验。网络断开/恢复分支优先 mock,当前任务不为此切换真实网络。
取消路径和提示提交点使用同一独立锁;NetworkManager 查询在锁外,返回后在提交前复查取消状态,避免慢查询阻塞连接或重新显示提示。现有 boot 标记保存在 `/run/matrix-screen-controller`,不得改成跨整机重启的持久设置。板端核对真实驱动与 fault 统计,无驱动改动时按影响跳过无负载基准、实屏图案、摄像头、ADC 和无关 Android 页面;必要但未完成的手机或生命周期验证记“未验证”。
本机 WiFi API 测试应先等待 mock 的开机网络激活完成,再记录激活次数基线,避免后台线程调度影响“下次开机”和“立即生效”的次数断言。文案目录校验失败时用 `scripts/build_ui_copy_catalog.py` 重建并核对实际差异,不绕过校验。中文路径下把 Python 子进程输出重定向为 UTF-8 日志时,仅对本次进程显式设置编码,避免父进程使用 UTF-8 而子进程仍输出本机代码页导致日志混合编码。
比较部署和重启前后持久文件时分别记录两个阶段:普通部署应保持原有内容;既有 `kernel-recovery.json` 在整机重启后可由 `finalize_after_boot()` 更新成功 boot ID 与记录时间。只允许核验为成功且对应当前 boot 的这项预期变化,其余文件继续逐项比较,不把用户配置或资源变化一并忽略,也不恢复过期健康记录。
TEST-MOBILE-WIFI-TRANSPORT 对应 DEVICE-MOBILE-WIFI-TRANSPORT/LIFECYCLE 与 WEB-MOBILE-PRESENCE,步骤见 `移动端相关内容/安卓app/如何安卓测试/WiFi传输测试.md`。合格标准:BLE 为会话前提、实际直连身份验证、独立密钥、无重复写入、WiFi 回退恢复、BLE 断开撤销、真实重启后新会话,以及网页/App 实际链路显示一致;模拟与实机分别记录。
本文件只维护可重复步骤、分层边界和合格标准,不记录某一次已经通过的结果。任何物理操作都按 `AGENTS.md` 的人工停顿规则执行。
## 视觉检查的适用范围与启动门禁
普通网页前端、手机界面、BLE 控制入口开发未改变驱动或显示输出实现时,不新增实屏视觉验收,优先协议、状态、逻辑帧与驱动统计。不需要视觉检查记“不适用”,不阻塞交付。只有驱动、扫描时序、底层输出改变或具体异常确需视觉证据时才提出。
**任何视觉检查开始前必须停止相关步骤、说明原因、询问用户下一步如何启动,并等待本次明确指示。** 不自动启动 DroidCam、摄像头、采集或视觉测试程序,也不主动切换实屏测试图案。专用测试手机的一般授权不替代此门禁。下文已有实屏/摄像头步骤仅在适用且取得本次启动指示后执行;“画面清晰由 Codex 判断”不是提前启动授权。接线、断电和调压仍另行逐阶段等待。
## 移动端接入测试
NetworkManager DNS 往返:`tests/test_wifi.py::test_nmcli_multiple_dns_can_roundtrip_without_password` 覆盖逗号、换行和混合重复 DNS 返回,要求读回独立地址数组、保持密码即可通过配置校验。实机按移动端运行器的 `--reapply-current-wifi` 显式步骤验证原网络立即应用;不得将该项写成不同网络、密码替换或 DHCP/静态切换全部通过。
`TEST-MOBILE-INTEGRATION` 覆盖 `整体开发需求/03_移动端接入需求.md`,详细矩阵见 `移动端相关内容/安卓app/如何安卓测试/README.md`。分别验证公共业务回归、加密与分片、手机单会话、网页顶栏连接提示、WiFi 扫描/切换、资源与刷新统计、真实 systemd 恢复及私有登记门禁。BLE 软件接入本身不默认触发实屏视觉检查。双手机首次由用户安装 APK 辅助,之后相关连接逻辑变动才重测;未实测不得写成通过。
## 0. 测试映射
| 测试编号 | 主要覆盖 | 执行位置 | 人工停顿 |
|---|---|---|---|
| `TEST-WORKSPACE-LAYOUT` | `DEPLOY-WORKSPACE-LAYOUT`、测试与发布路径、隔离和清理 | 本机中文及空格路径 | 否 |
| `TEST-REPOSITORY-HYGIENE` | `DEPLOY-REPOSITORY-HYGIENE`、凭据门禁、Git ignore、秘密与主机路径扫描 | 本机 Git 工作区 | 仅等待用户填写私有凭据时 |
| `TEST-LOCAL-MOCK` | `WEB-*`、`DISPLAY-MOCK`、`CONFIG-*` | Windows 或隔离 Linux | 否 |
| `TEST-NATIVE-UNIT` | `DISPLAY-DRIVER`、bitplane、映射、亮度、双缓冲 | 本机,不访问 `/dev/mem` | 否 |
| `TEST-REMOTE-HEALTH` | `DEPLOY-*`、系统、网络、磁盘、工具 | 核桃派,无屏 | 否 |
| `TEST-MANUAL-UPDATE` | `DEPLOY-UPDATE`、数据副本迁移、程序/数据原子切换、失败回滚和清理 | 核桃派,无屏 | 否 |
| `TEST-MOBILE-LIBRARY-CACHE` | `DEVICE-MOBILE-LIBRARY-CACHE`、两档 PNG、目录修订与预览孤儿清理、旧接口兼容 | 本机 mock + 核桃派 BLE 只读 | 否 |
| `TEST-NATIVE-NOLOAD` | H618 寄存器映射、线程、刷新率、统计、安全关闭 | 核桃派,HUB75 未连接 | 否 |
| `TEST-API-CONFIG` | REST、schema v10、工作区顺序、性能模式、动图并发、持久化、字体、模板、动图 | mock / 核桃派 | 否 |
| `TEST-FRP-MAINTENANCE` | `WEB-FRP-MAINTENANCE`、`CONFIG-FRP`、`DEPLOY-FRP`、多配置、systemd 持久与真实 SSH 穿透 | Windows mock + 核桃派 | 否 |
| `TEST-NETWORK-DIAGNOSTICS` | `WEB-NETWORK-DIAGNOSTICS`、接口、路由、DNS、TCP/TLS 和 ICMP 分类 | Windows mock + 核桃派 | 否 |
| `TEST-WS-CANVAS` | RGB888、最新帧覆盖、正常断开 | mock / 核桃派 | 否 |
| `TEST-CANVAS-EDIT` | `WEB-CANVAS-EDIT`、`WEB-CANVAS-COORDINATES` 默认只读、全屏编辑、悬浮菜单、撤销、平移缩放和自适应坐标系 | Windows / 本机浏览器 | 否 |
| `TEST-TEMPLATE-MANAGEMENT` | `WEB-PREVIEW`、`WEB-TEMPLATES`、静态/动图播放编辑解耦、保存选择与未保存守卫 | Windows / mock / 核桃派 | 否 |
| `TEST-CURRENT-PLAYBACK` | `WEB-CURRENT-DISPLAY`、当前帧弹层、动图跳转、暂停/继续、倍速和会话失效 | Windows / mock + 核桃派软件接口 | 用户最终交互确认 |
| `TEST-ANIMATION-THUMBNAIL-PERF` | 动图长名称、完整动态缩略图、浏览器/HTTP 资源与 H618 GPIO 刷新隔离 | Windows / mock + 核桃派/HUB75 | 仅摄像头歧义时确认 |
| `TEST-CPUFREQ-RECOVERY` | `HW-CPUFREQ-AXP313A`、v9 性能模式事务、原 governor 恢复 | Windows fake sysfs + 核桃派 | 否 |
| `TEST-KERNEL-ROLLBACK` | `DEPLOY-KERNEL-ROLLBACK`、离线内核载荷、候选健康标记、失败回原内核 | 隔离脚本 + 核桃派 | 仅早期硬锁时断电一次 |
| `TEST-WORKSPACE-ORDER` | 单层侧栏、内存排序、关闭拦截与设备共享持久化 | Windows / 本机浏览器 + mock | 否 |
| `TEST-MEDIA-CONVERSION` | `WEB-MEDIA-IMPORT`、格式探测、裁切、透明合成、队列、清理和内容库提交 | Windows / mock / 核桃派 | 否 |
| `TEST-MEDIA-PERF` | 转换 unit 资源隔离、显示刷新统计、API 响应和当前逻辑帧不变 | 核桃派 + 运行中 HUB75 | 否 |
| `TEST-RESTART-PERSISTENCE` | systemd 重启、默认内容、用户资源 | 核桃派 | 服务重启否;整机断电是 |
| `TEST-OTA-LOCAL` | 包协议、正式版本与功能时间、版本拒绝、迁移、回滚、进度和前端交互 | Windows / mock | 否 |
| `TEST-SYSTEM-INDICATOR-PIXELS` | `DISPLAY-OTA-INDICATOR`、`DISPLAY-WIFI-INDICATOR` 的 OTA、联网 IP 与断网提示像素完整性 | Windows / mock + 核桃派/HUB75 | 用户逐画面确认 |
| `TEST-OTA-REAL` | 浏览器上传、40% 更新覆盖、90% 居中画面、真实切换、数据保全和清理 | 核桃派 + HUB75 | 只在画面无法由摄像头判断时确认 |
| `TEST-OTA-KERNEL-RECOVERY` | `DEPLOY-OTA-KERNEL-RECOVERY`、能力退化回滚、候选材料校验、一次重启和结果持久化 | 本机 fake sysfs + 核桃派真实 systemd | 仅候选早期硬锁时断电一次 |
| `TEST-RELEASE-VERSION` | OTA/镜像共用版本、IMG 候选/实卡晋升、失败回滚、并发和发布记录 | Windows / mock + Linux | 否 |
| `TEST-IMAGE-LOCAL` | FAT16、离线载荷、双槽配置、编辑器和秘密排除 | Windows | 否 |
| `TEST-IMAGE-FIRSTBOOT` | 写卡、无外设自动安装、重启、联网、SSH 和网页 | 核桃派,无屏 | 写卡与插卡通电 |
| `TEST-REAL-SCREEN` | `HW-MATRIX`、颜色、行址、方向、内容与稳定性 | 核桃派 + HUB75 | 每个失败项停顿 |
| `TEST-ADC-HARDWARE` | `HW-SCREEN-VOLTAGE`、校准、故障恢复 | 核桃派 + ADC | 接线/万用表停顿 |
| `TEST-LOW-VOLTAGE` | 限亮、图标、恢复 | 实屏 + ADC + 可调电源 | 每一档停顿 |
| `TEST-CLEANUP` | 临时项、持久数据、GPIO 安全状态 | 本机和核桃派 | 否 |
| `TEST-LAYERS` | WEB-LAYERS、扩展画布、图层复制与跨端输出 | Node/Python/浏览器/核桃派 | 否 |
| `TEST-LAYER-OVERFLOW` | 黑色笔迹、背景、候选确认/取消、文字裁切与撤销 | Node/Python/浏览器 | 否 |
| `TEST-SCENE-V2-MIGRATION` | 草稿/模板/动图迁移、摘要、原子批量提交 | Node/Python及持久副本 | 否 |
| `TEST-INDEPENDENCE` | 单目录可拿走、无外部依赖 | 隔离临时副本 | 否 |
| `TEST-LOCAL-ENV` | `DEPLOY-WORKSPACE-LAYOUT` 项目专用环境、路径刷新和 Git 边界 | Windows 本机及中文/空格隔离副本 | 否 |
## 1. 本机 mock 与自动化
### 默认画面保存绑定(TEST-TEMPLATE-MANAGEMENT / TEST-DEFAULT-CONTENT)
- 覆盖 `WEB-DEFAULT-DISPLAY`、`WEB-TEMPLATES`:新设备开机会话载入默认静态模板并绑定 ID、修订及基线;覆盖保留 ID、名称、创建时间和默认引用,另存绑定新模板,取消不发写请求。同次开机刷新保留未保存草稿及原修订;新开机会话载入最新默认模板。服务 restart 不作为设备重新开机。
- 演示静态图和演示动图第一帧均显示保存弹窗;“保存到当前模板”须为黑色受限态,点击只解释原因且不关闭弹窗、不发覆盖请求;另存生成可写静态模板。演示动图绑定类型仍是只读 animation。用户动图保持原逐帧编辑、保存和普通草稿恢复流程。
- 定向反例:过期修订返回 `409`、删除目标返回 `404`、默认读取失败、损坏/未来版本草稿、初始化响应期间新增图层;都保留当前草稿,不误绑定或自动重写。多标签选择载入外部草稿时仅恢复与该草稿精确匹配的绑定。
- Node 行为用例在 `tests/test_template_management_ui.mjs`,首页开机会话标记及 HTML 属性转义在 `tests/test_api.py`。浏览器验证覆盖桌面与手机弹窗、真实保存请求及刷新,不以代码文本匹配替代交互验收。
- 已验证经验:场景持久化不等于模板来源持久化;绑定须单独保存原修订与基线,并核对草稿对应关系。仅设置 `aria-disabled` 不会把主按钮变黑,保存弹窗也须应用演示受限样式。另存弹窗关闭后请求仍可能在途,自动化必须等待写请求成功及绑定更新后再刷新。DELETE 同样要求 `If-Match`,不能把缺少请求头的 `428` 当成删除成功。
- 本项不改驱动、扫描或输出实现,实屏视觉验收不适用;板端验收检查服务、静态资源和临时模板保存,不改写用户原件,不启动摄像头或切换测试图案。
从独立项目根执行:
```powershell
python ".\测试相关资料\如何测试\本机测试环境\local_test.py" setup
python ".\测试相关资料\如何测试\本机测试环境\local_test.py" test
```
前端测试:
```powershell
$tests = Get-ChildItem -LiteralPath ".\核桃派软件源代码\tests" -Filter "*.mjs" -File
node --test @($tests.FullName)
```
合格标准:Python、Node、静态资源和原生 fake-register 全部通过;条件跳过项必须与当前主机缺少真实硬件相符;没有读取真实凭据、生产数据或 `/dev/mem`。
`TEST-SYSTEM-INDICATOR-PIXELS` 在 mock 中逐像素验证 OTA 的 `OTA`、百分比和进度条缩小后无断笔、百分比未被底边裁切、四边仍各有 3 像素黑边;联网 IP 与断网提示的字体覆盖像素只能是全白或全灭,禁止抗锯齿灰阶造成低亮度缺块。部署后依次只显示 OTA、联网 IP、断网提示三个画面;每次只显示一个并停止,由用户回复内容无误后再进入下一个,不使用摄像头代替本轮人工确认,三个画面均确认前不得写成通过。
`TEST-CANVAS-EDIT` 使用本机 mock 服务,在约 `320px`、`390px`、平板和桌面视口逐项检查:像素工作区默认滑动画板不落笔且页面可滚动;点击“开始编辑”后才进入全屏绘画;悬浮按钮点击与拖动不产生像素;移动模式支持单指平移、双指缩放和桌面滚轮缩放,切回绘画后落点准确;画笔、橡皮、填充和清空可连续撤销。悬浮菜单的坐标系按钮使用 `aria-pressed`,默认关闭并按浏览器记忆;坐标层无指针事件,只在全屏像素编辑中显示。分别在 `1x/2x/4x/8x` 缩放和不同平移位置检查上、左 `0..63` 标尺、主刻度与贯穿线对齐,间隔从 `1/2/4/8/16/32` 中自适应;普通与单像素模式均可使用,单像素网格可同时显示。切换坐标系前后重复绘画、吸管、撤销、平移和缩放,并逐字节比较场景、导出 PNG 与 WebSocket RGB888 不变。退出编辑回到颜色工具区,离开工作区强制退出;文字工作区保持原有选择、拖动和缩放。成功应用画板、保存或更新模板、保存或新建动图帧后撤销历史清空,失败请求保留历史。该测试不连接 HUB75、ADC,也不进行实屏目测。
`TEST-TEMPLATE-MANAGEMENT` 使用 mock 和前端自动化验证:模板管理顶部为与系统设置相同的 `160 CSS px` 当前帧监视器且没有应用、导出或画板交互;静态模板和动图卡片均按“播放/编辑、复制/重命名、删除、上移/下移”两列四行排列,演示案例显示相同布局并对受限项提供原因。静态与动图播放只改变设备输出,不替换普通画布或动图编辑上下文,也不修改默认内容;静态编辑进入像素画布,未绑定草稿或保存后又修改的模板在被替换前提示“当前内容将会丢失”,干净模板直接切换,取消及读取失败保持原状态。普通模板保存覆盖当前或另存后都更新绑定基线,冲突保留未保存内容;演示静态图只能另存。板端只用故意过期的静态播放修订验证 `409` 且当前帧字节不变,不要求摄像头、实屏目测或物理操作。
`TEST-CURRENT-PLAYBACK` 使用 mock 服务和前端自动化验证:非动图顶栏按钮打开当前逻辑帧,点击任意预览区域、遮罩和 `Escape` 均关闭;动图对话框展示完整时长、当前位置、播放/暂停和 `0.5x/1x/1.5x/2x`,控件点击不关闭。服务测试覆盖暂停位置冻结、继续、跳转目标帧、四档倍速、循环边界、关闭线程,以及新静态内容、新动图和同一动图重新播放均重置到 `0ms/播放/1x` 并拒绝旧会话。拖动最多每 `100ms` 一个请求、在途请求不并发、松手提交最终位置,状态轮询不得抢动滑块。部署后只检查服务、接口和新静态资源,由用户实际拉动进度、暂停后关闭重开继续、切换新内容及四档倍速;该软件逻辑验收不要求 GPIO、摄像头、ADC 或其他实屏测试,用户确认前不得写成完成。
`TEST-ANIMATION-THUMBNAIL-PERF` 先在隔离 mock 数据根生成 100 个动图、每个 100 张不同的 `64x64` 帧、每帧 `50ms`。自动化验证已有动图名称单行尾部省略,细指针鼠标只在截断时显示完整名称,触摸/点击/长按不展开,重命名仍取得完整值;动图管理和模板管理都按完整帧顺序及原时长循环,页面隐藏、离开视口、切换工作区、减少动态效果、缩略图失败和分页间修订变化均停止或安全回退。配置 v9→v10 必须默认加入 `animation_preview_max_concurrent=2`,接口只接受 `1..50` 的严格整数;设置页在性能模式正下方显示“模板界面同时播放的动图数量”和固定风险提示,启动加载及保存成功后立即让两个管理界面共享新上限,保存失败恢复最近有效值。自动化分别以 `1`、`2`、`50` 验证首帧加载、完整时间表读取和实际播放并发,降低上限时必须释放超额预载并取消可取消请求。服务重启后的首次动图列表必须直接使用启动期严格校验形成的缓存,测试用替身禁止再次读取全量持久帧;100×100 板端首次列表不得触发前端超时。四类视口不得横向溢出;两轮完整滚动和反复切换期间操作响应不超过 `200ms`、单个主线程长任务不超过 `200ms`、`/api/status` p95 不超过 `500ms`,预热后服务 CPU 相对静态首帧基线平均增幅不超过 10 个百分点、RSS 增幅不超过 `64MiB`,浏览器 JS 堆增幅不超过 `100MiB` 且第二轮不再单调增长。设备默认值 `2` 仍执行全部网页、HTTP 与 GPIO 门槛;隔离数据下把 50 张卡片同时置于视口并持续 60 秒时,网页变慢只记录为已提示风险,但 GPIO 仍必须达到刷新率、miss、连续完成帧、fault 和当前 RGB 帧一致性门槛。该小逻辑部署验收免除摄像头和肉眼实屏判断。
本机门槛通过后,先独立完成 `TEST-CPUFREQ-RECOVERY` 和 `TEST-KERNEL-ROLLBACK`,再在核桃派上用候选程序、独立临时数据根和临时 systemd unit 运行真实驱动,生产持久数据不得参与压力数据生成。100Hz 档依次采集:性能模式关闭的 60 秒空闲基线;性能模式开启后以 5% 亮度浏览动图管理 60 秒;保持开启并以 40% 亮度浏览模板管理 60 秒;最后关闭性能模式并用生产数据冒烟 60 秒。每阶段用 `scripts/measure_gpio_status.py` 每秒读取 `/api/status` 并保存 JSON 结果:逻辑实际刷新和面板扫描均不低于 95Hz;完成帧与完成扫描持续增长且区间增量相等,`scans_per_frame=1`;截止丢失增量不高于完成帧增量的 0.1%,不得连续两秒无完成帧;OE pulse fault、forced blank 和其他 fault 不增长,驱动/PWM/安全关闭错误为空,CPU3 绑定、实时优先级和内存锁定保持生效,性能阶段全部 policy 必须实际为 `performance`,关闭后必须恢复启动前 governor;`/api/display/current-frame` RGB 字节不变。实屏不得出现同步黑场、局部高亮块、坏行、错色或可见卡顿;只剩拍频/曝光歧义时等待用户确认。
如果最多 2 张视口内动态缩略图未通过网页、服务或 GPIO 任一门槛,候选应用先改为只播放距视口中心最近的 1 张并完整重测;最多 1 张仍失败则撤销动态缩略图、保留静态首帧。两种应用失败都不得撤销已经独立通过的 AXP313A/cpufreq、性能模式、CPU3 绑定、实时优先级和内存锁定成果。候选应用失败时恢复生产应用并在聊天中报告瓶颈和互斥方案;全部通过后才使用原子更新脚本部署并在重启后复测 60 秒,最终 `performance_mode_enabled` 必须为 `false`。
`TEST-CPUFREQ-RECOVERY` 在 fake sysfs 注入多 policy、缺失 policy、单 policy 写失败和配置保存失败,要求已写 governor 全部回滚;所有 mock/fake-register 应用默认使用运行根下不可用的隔离 cpufreq 路径,只有该专项测试可通过工厂注入 fake sysfs,任何 mock 测试不得读取或改写宿主机真实 governor。保留运行根记录后模拟异常重启,不得把遗留 `performance` 当作原 governor。板端候选内核必须识别 `x-powers,axp313a`、注册 `vdd-cpu` DCDC2、消除 `cpufreq-dt` deferred,`policy0` 覆盖 CPU0-3且包含 `performance`;DCDC2 始终处于 `810000..1080000µV`,ALDO1 保持 1.8V、DLDO1 保持常开 3.3V、DCDC3 保持引导器实际设置的 1.10V,修复前后的其他 PMIC 寄存器、GPU 状态和持久数据清单不得有非预期变化。
`TEST-OTA-KERNEL-RECOVERY` 先在本机 fake sysfs 和隔离 boot/module 树覆盖:健康候选更新前后 policy、标记或 governor 丢失必须令 OTA 回滚;既有原内核回退可完成应用更新,但核对候选 Image、两份 DTB、全部 `.ko` 摘要、原内核备份、受管启动脚本及已启用健康服务后才可安排一次独立重启。缺件、摘要不符或已失败记录不得自动重试;旧 worker 首次升级也须在新服务观察到成功结果后进入同一恢复判断。板端运行 `scripts/test_kernel_recovery_systemd.py`,验证临时主服务停止后独立任务仍可使用受保护运行目录;只清理本次随机命名的临时服务和目录。真实恢复后分别检查 `uname -r`、AXP313A、`vdd-cpu`、`policy0`、健康标记和 `/api/status`,短暂开启性能模式确认 `performance` 后关闭并恢复原 governor;候选失败则检查回退记录并停止再次重启。该逻辑不改变显示输出,视觉检查不适用。
`TEST-KERNEL-ROLLBACK` 先在隔离目录验证 boot 脚本只出现一个候选管理块、原文件路径保持可达、健康标记在候选启动前删除。板端保留原 `Image`、DTB、模块和 `boot.scr`,候选使用独立名称;健康服务只有在内核版本、AXP313A、cpufreq、服务和 GPIO 全部通过后才重建标记。注入健康失败后必须自动重启到原内核;若候选在健康服务前早期硬锁且硬件看门狗没有重启,停止自动操作并请用户只断电重启一次,随后确认无标记路径进入原内核。
`TEST-WORKSPACE-ORDER` 在相同四类视口检查:侧栏六个项目无“设备/内容”分类标题;叉号下方提供“自定义项目位置”;进入编辑后按钮变为“保存”且项目只显示上下移动操作。首末边界不可用,项目点击不导航,叉号、遮罩和 `Escape` 只提示保存并保持侧栏打开。保存成功后侧栏保持打开,刷新页面、另一浏览器和服务重启均恢复新顺序;请求失败保留内存草稿,未保存时刷新、关闭页面或模拟崩溃后恢复上一次已保存顺序。该测试不连接 HUB75 或 ADC。
`TEST-MEDIA-CONVERSION` 使用确定性合成素材覆盖静态 PNG/JPEG/WebP/AVIF、透明 PNG/GIF/APNG/WebP、HEIC 和 MP4/MOV/WebM/MKV/AVI。逐项验证三种适配;“自由取景”在 `zoom=1` 时必须先完整显示方向及 SAR 归一后的横图或竖图,不得预先居中裁成正方形,缩放后可选择非中心区域并由整段媒体共用同一组焦点/缩放。素材可从四边拖出固定 1:1 视窗直至只剩一个输出像素,再拖到全空必须拒绝;素材自身透明像素使用透明填充色,素材外虚空使用留白色。继续验证 20fps 上限、相邻最终 RGB 帧合并和静态/动图分类。流式上传必须覆盖 4 GiB 上限、长度不符、中断 `.part` 清理、伪扩展名、音频/播放列表/网络协议/异常尺寸拒绝、2 GiB 空间保留和 30,000 帧门槛;自动化必须注入确定性的充足/不足空间结果,不能因本机磁盘很大而漏测不足,也不能因板端 `/run` 容量小于生产持久盘而误报正常上传失败。同一文件名和相同字节连续上传必须产生不同 UUID 与独立源文件,分别改名和取景后均可转换。上传区域不得要求保存名称,分析完成后按文件名预填;已有静态模板、已有动图及其他排队/转换任务的同名、大小写变体或首尾空白变体必须在保存设置或排队时返回 `409`,被拒任务保持可编辑,取消、失败、完成和重启恢复后按规则释放或保留名称占用。任务成功或取消立即清理,失败与待设置保留 24 小时;重启恢复队列,任何失败不留下部分模板或动图。浏览器在约 `320px`、`390px`、平板和桌面验证上传区单列文件选择、上传进度、最多五张代表帧、自由取景拖动缩放、双颜色、名称冲突提示、排队/重试/取消、隐藏页暂停轮询、成功卡片消失和对应内容库刷新。动图列表必须先在主服务中预热缓存,再由独立转换进程提交 GIF,并确认不重启主服务即可从 `/api/animations` 和模板管理看到新动图。等待设置卡片还必须在自动轮询至少两个周期及手动刷新后保持同一 DOM 节点、输入焦点、未提交名称、适配模式、取景焦点、缩放、颜色和代表帧选择;服务端状态转换后则立即退出本地编辑并显示新状态。
`TEST-MEDIA-PERF` 在当前用户画面保持不变时分别转换静态图、透明动图、1080p 和 4K 视频。转换 unit 必须只运行在 CPU0-1、`CPUQuota=150%`、`MemoryMax=384M`、无 swap 和网络;CPU3 绑定、实时优先级、内存锁定、OE/PWM 状态保持真实正常。100Hz 档实际刷新和物理扫描满足既有门槛,转换窗口截止丢失率不高于 0.1%,无 OOM、fault 或 `last_error`,普通状态和模板 API 持续可响应。转换前后 `/api/display/current-frame` RGB 字节完全相同;主动播放结果后与软件期望帧逐像素比较,动态时间误差不超过 50ms。重启项还要确认 `/proc/sys/kernel/sched_rt_runtime_us` 在显示服务运行时为 `-1`、服务停止时恢复启动前数值,并在整机重启后再次确认 `realtime_priority_active=true`。本测试只读逻辑帧和统计,不要求用户或摄像头判断。
`TEST-MANUAL-UPDATE` 使用 `scripts/update_walnutpi.sh`:更新前记录服务状态、当前 release 和持久根清单;脚本必须在停服后克隆持久根,在副本上运行 `scripts.prepare_data_root`,确认配置 v8→v9 默认加入并关闭性能模式后再原子切换程序和数据。源码轻量更新包不携带预编译内核、固定内核源码或镜像;仅当更新器明确设置源码轻量测试标记且两类大型材料均不存在时,登记材料完整性用例可跳过,其他设备端 Python 测试必须全部运行,任一材料只缺一类仍失败,本机完整项目仍强制校验两类材料。板端测试的应用数据、运行数据、pytest basetemp 和通用临时目录必须全部位于本次 `/run/matrix-screen-controller-update.<release>` 命名空间,禁用 pytest cache,结束后精确清理且不得使用默认 `/tmp`。首次健康检查成功后必须再次 `systemctl restart` 并重新轮询真实 `/api/status`。成功时原用户文件完整保留,只允许登记的 schema 迁移改变内容,并删除旧 release、本次 staging、迁移副本和回滚副本;注入迁移或健康检查失败时必须恢复旧程序、旧 unit 和未修改的旧持久根。本测试不连接或操作 HUB75、ADC。
`TEST-OTA-LOCAL` 还必须覆盖:严格版本比较、严格 `+08:00` 分钟级功能时间、两个状态 API 返回同一固定值、完整包携带该文件、载荷排除、摘要损坏、路径穿越、压缩膨胀、超限和中断上传清理;并发任务拒绝、写冻结、进度恢复、配置新增预设、退休字段/文件定向删除、未知用户文件保留、切换失败精确回滚、事务恢复和旧 release 清理。模拟 1.0.3 旧 worker 只传三个旧环境变量时,新包 conftest 必须仍把应用/运行数据、`tmp_path` 和 Python 临时文件放入事务目录,并实际执行测试;故意失败用例必须返回非零。当前源码及临时候选载荷不得包含 1.0.6 诊断标记、`pytest.exit` 成功早退或其他测试绕过入口。日志测试覆盖各阶段、命令退出码、pytest 短 traceback、非 UTF-8、安全主机摘要、`1 MiB` 头尾截断、单份原子覆盖、成功删除和日志写入失败降级;不得出现凭据、网络配置、用户内容或完整环境。状态 API 与纯文本日志 API 覆盖可用/缺失、字节数、`404` 和 `no-store`。前端必须覆盖软件版本与功能时间、上传进度、处理进度、预期断线、恢复刷新、失败自动弹窗、纯文本安全、长日志滚动、重新查看以及 Clipboard/textarea 两条复制路径;常态页面不得显示最近 OTA 结果,完成任务后不得继续显示 100% 进度条或完成提示。普通开发部署必须保持 `VERSION` 不变并按功能变更更新 `FEATURE_UPDATED_AT`,只有明确的 OTA 或镜像导出成功才推进共用版本,单纯导出不得改写功能时间。
`TEST-RELEASE-VERSION` 交替模拟 OTA、镜像、同一代码连续导出两种产物、构建失败、已有目录、并发锁和历史导出 IMG 被删除。OTA 按已登记节点推进;IMG 不使用 OTA 跳转门禁,但新候选必须严格高于当前版本。`image --candidate-output` 只能写正式目录外且不得改变 `VERSION`、发布记录或正式目录;`image --validated-candidate --validation-report` 只接受下一补丁、摘要一致、字段严格且全部门槛为真的无秘密实卡报告,重建期望 bundle 并复核真实 IMG 后才原字节晋升。候选后源码变化、报告多余字段、摘要错误、已有版本、并发、复制或记录写入失败均须保持版本、记录和正式目录字节不变。另行覆盖用户明确授权的 `image --repair-current` 原有同版本修复语义。
`TEST-OTA-LOCAL`/`TEST-RELEASE-VERSION` 增加 `DEPLOY-OTA-OFFLINE-CLOSURE` 与 `DEPLOY-OTA-CANDIDATE`:缺少直接依赖、固定版本不符、wheel 未列入摘要清单时,候选导出须在发布前拒绝;从候选包实际载荷解出软件与 wheelhouse,用目标 Python/AArch64 标签执行 `pip --no-index --dry-run --ignore-installed --only-binary=:all:`,并在板端隔离 venv 完成无网络安装。新 OTA 候选不占版本;晋升仅接受下一补丁、包字节与报告摘要相同、源码与离线材料未变化、真实安装及恢复均通过的报告。拒绝篡改包、过期源码、报告字段错误和发布中断,核对正式包与试装候选逐字节一致。1.1.1 可直接升级到 1.1.3,1.1.2 标记不可用但原包保留。
隔离复制验收须从候选包的 `software/` 单独运行完整 pytest;设备侧共享协议黄金向量应在 `tests/fixtures/` 随包携带。本机有移动工程时再对照其向量逐字节核验,OTA/板端不得因移动工程目录缺席而跳过设备端协议测试。
历史排障经验:电脑端测试工具的依赖只写入其独立环境,不写入设备 `requirements-dev.txt`;发布前从候选包实际载荷在板端隔离 venv 执行 `pip install --no-index`,并确认完整 pytest 通过。实机 OTA 后 `kernel-recovery.json` 的启动时间和启动标识可能更新,用户配置与资源应分别核对;恢复原版本时程序、持久数据和组件文件按备份字节复核。旧失败留下的 OTA 一次性 unit 可由 `failed` 变为禁用的 `inactive`,主服务及 FRP、蓝牙的启停状态仍须与备份一致。
`TEST-IMAGE-LOCAL` 校验官方 IMG 摘要在导出前后不变;独立读取 MBR、FAT16、rootfs 离线 bundle、软件版本和全部 SHA-256。镜像元数据必须严格为 v3,记录应用载荷 rootfs 路径、压缩字节数和摘要,以及已登记内核 release、压缩/展开字节数、摘要、FAT 安装预算和 `32 MiB` 安全余量;FAT 必须不存在 `MSCBOOT.TGZ`。预编译载荷逐项覆盖外层/内部摘要、3,048 个模块普通文件、五个 boot 文件、固定 release/commit、确定性 gzip、路径穿越、符号链接、特殊文件和损坏元数据。隔离假根验证应用与内核载荷共同写入、读回、既有目标拒绝及“两类压缩载荷 + 256 MiB”空间门槛;合成 FAT 分别覆盖空间通过、边界和不足,预算按簇计入五个 boot 文件、受管/原始/临时启动脚本与状态文件,并确认不足发生在任何候选 boot 文件写入前。Linux 上再只读挂载真实复制件根分区,逐字节比对两类载荷和 FAT 元数据,并确认 `matrix-image-firstboot.service` 与 `ssh.service` 均已启用、受管 sshd 配置逐字匹配、一次性程序指向 FAT 分区且排序早于 SSH 和普通启动脚本。根分区还必须包含 `sshd`、`sudo` 和 `visudo`,SSH 不得被 mask。以 `BASE_IMAGE_PACKAGES.tsv` 为基准解析 FFmpeg、libheif 和 Python venv 的全部直接/传递 Debian 依赖;删除任意仅由闭包提供的包、根包、基准清单、内核依赖或摘要条目时,构建必须在复制正式镜像前失败。导出入口必须在 `python3 -S` 下完成参数解析,不得因 Pillow 或 FontTools 未安装而在发布锁前退出。静态回归必须确认首启写入网络配置并重启 NetworkManager 后直接进入部署,不得循环调用 `nmcli connection up`、等待 SSID/DHCP 或以默认路由缺失退出;`DEFER_SERVICE_START=1` 的全新安装和同版本恢复均使用不要求默认路由的 `dedicated_host.py check --service`,普通部署的严格检查仍要求默认路由。离线完成状态必须固定、无凭据并明确安装成功和 WiFi 未连接。首启只启用控制服务,SSH 也只能 `enable`、不能在具有 `Before=` 排序的 oneshot 内 `start` 或 `enable --now`;账户必须显式加入 `sudo` 组,sudoers 临时文件先经 `visudo` 校验再原子安装,实际 sshd 策略必须经 `sshd -t/-T` 校验。同版本中断恢复必须拒绝版本或安装文件不完整的 `/opt`。破坏活动配置槽必须回退旧槽,两个槽都损坏、产品错误、未知 schema、非法账户/WiFi/IPv4 均拒绝。编辑器覆盖打开、密码遮挡、修改原包确认、另存为不改原包和另存后自动重开;中文、空格及长路径必须生成无 BOM UTF-8 规范摘要并由独立 `Get-FileHash` 复核,摘要长度、十六进制、分隔符、多行、文件名或内容错误以及旧版中文名变成 `?` 的摘要均拒绝。保留名、错误扩展名、同路径、既有 IMG、孤立同名摘要和不可写目录必须在修改前拒绝且不留半成品。主窗口、密码输入框和全部应用内提示在 100%、150%、200% 缩放及约 1280×720、1920×1080、4K 工作区完整可达,跨不同 DPI 显示器或改变分辨率后不得裁切;低分辨率允许滚动。镜像扫描不得包含项目凭据、当前设备数据、SSH 主机密钥、NetworkManager 连接、缓存或编译输出。
`TEST-IMAGE-LOCAL` 的编辑器回归必须直接运行 Python/PySide6 源码单元测试,并将最终 Windows 10/11 x64 单 EXE 单独复制到隔离临时目录,在不依赖源码目录、Python、.NET、Qt 或外部 DLL 的环境中重复 `--validate` 与 `--apply`。同一合成 FAT16 镜像还必须由主工程 `image_config.py` 交叉读取,并覆盖非活动槽更新、活动槽损坏回退和失败不留新 IMG/摘要/临时文件。GUI 人工验收继续覆盖单 IMG 拖放、密码遮挡、确认流程、另存后自动重开、进度响应以及 100%/150%/200% DPI、1280×720、1080p、4K 和跨显示器变化。macOS 只验证源码和构建说明完整,未在 macOS 实际构建时不得写成 macOS 产物通过。
`TEST-IMAGE-LOCAL` 还必须确认 IMG README 使用镜像专用模板,逐字匹配 FAT 配置中的默认账户、密码、Wi-Fi SSID、Wi-Fi 密码和 DHCP,并包含公开默认值修改警告;不得出现 OTA 包类型、前置节点或上传说明。除该 README 与 IMG 配置外,manifest、发布记录、日志和验收报告均不得包含这些默认值,当前开发机凭据任何位置都不得出现。
`TEST-IMAGE-LOCAL` 的 SSH 静态回归还必须确认:直接运行 `sshd -t/-T` 前创建模式 `0755` 的 `/run/sshd`,不得依赖尚未启动的 `ssh.service` 创建其易失运行目录。
`TEST-IMAGE-FIRSTBOOT` 写卡前重新按可移动总线、容量及非系统/非启动属性锁定目标并确认会清空。核桃派与外设全部断开时插卡通电;先让预设 SSID 完全不存在,设备仍应自行扩容、从 rootfs 离线载荷安装、配置网络、生成唯一身份和 SSH 主机密钥、校验并安装预编译内核后重启一次。FAT 必须显示无凭据的“安装成功但 WiFi 未连接”状态,不得出现 `FAILED: stage=network`;断电取卡只读确认控制程序、服务、账户、主机密钥和候选内核均已安装且明文配置已清理。认证失败和认证成功但 DHCP 失败分别执行同一门槛,均不得阻断安装;NetworkManager、载荷、空间、硬件、权限、SSH 或内核故障仍必须失败。内核阶段要求根分区剩余空间不低于“两倍展开大小 + 256 MiB”,并在写入 `/boot` 前重新满足 v3 元数据登记的实际 boot 预算和 `32 MiB` 余量;成功必须删除 rootfs 两类压缩载荷和 `/var/tmp` 展开目录,失败必须保留压缩载荷供完整重试。候选启动后确认 `6.1.31-matrix-axp313a1`、AXP313A、cpufreq 和应用健康标记;注入安装失败必须保持原 boot 文件且不重启,注入候选健康失败必须自动回原内核。首启 unit 必须使用无限启动时限;FAT 成功状态只能在秘密、rootfs 载荷和临时文件清理、首启 unit 禁用及全盘同步之后出现。随后恢复原热点且不重刷、不重新部署,最多等待 20 分钟,确认设备由正常运行服务自动联网、屏幕断网提示按既有逻辑恢复,并用镜像编辑器写入的账户和密码完成 SSH 登录;`systemctl is-enabled/is-active ssh.service` 必须均成功,root 密码登录必须拒绝。先清除 sudo 时间戳并确认 `sudo -n` 被拒绝,再输入同一账户密码执行任意 root 命令;检查 `/etc/sudoers` 不含 `Defaults rootpw` 或旧 `pi` 的 `NOPASSWD`,且当前主机名可由 `/etc/hosts` 立即解析。随后确认 `/api/status` 版本正确、真实 H618 映射就绪、浏览器控制界面可加载;再次重启后 SSH、sudo 和网页仍通过。SSH 未监听、未实际登录、内核健康或权限策略不符都不得作为正式镜像通过。失败且网络不可达时断电取卡读取 FAT 状态文件;Debian 安装失败还必须读取不含配置凭据的 `MSCPKG.TXT` 和 `MSCPKGS.TSV`,不得连接屏幕绕过或把结果写成通过。成功时两个诊断文件必须删除。
候选晋升的最低真实硬件门槛是同一摘要 IMG 在默认热点从上电起可用时完成一次完整正向首启、自动重启、SSH/sudo/root 拒绝、服务、内核、H618、网页和再次重启复验。SSID 不存在、认证失败和 DHCP 失败分支仍须通过自动化;没有另行执行真实故障网络矩阵时,在验收记录中明确写为“本次未重复实卡验证”,不得写成实卡通过。
工作区 OTA 今后长期保留。1.0.1 缺失已由用户接受,原 `1.0.0 → 1.0.1` 组合仅保留为历史用例,不再要求补齐或执行,不提示验收材料缺失,不影响开发、常规测试和使用。新的真实 OTA 验收使用本次任务明确的源/目标版本及实际包,并遵守安装节点门禁;不得为重跑历史用例自动导出或替换版本。
`TEST-OTA-REAL` 按本次任务明确的源/目标版本执行:先部署源版本,再从系统设置选择 `发布更新相关/OTA数据包/<目标版本>/` 中的真实包。更新前后对持久根做文件清单,除 schema 迁移和单条 OTA 状态外保持一致;确认版本、实例 ID、真实驱动、硬件映射、PWM4 OE 后端和 fault 计数。再次上传同一包必须在停服前拒绝。成功后不得残留旧 release、上传包、staging、数据备份或活动 OTA unit。另用受控失败包确认 1.0.5 及后续旧版本服务恢复后自动弹出最近失败日志,日志包含失败用例与回滚结论且可在局域网 HTTP 页面完整复制;成功更新清除旧日志。1.0.6 是发布记录中唯一经授权跳过旧 worker pytest 的历史诊断引导包,只用于先安装日志能力,其成品不得覆盖、实现不得复制到当前源码或任何后续包;1.0.7 及以后全部恢复严格 pytest 门槛。实屏应在更新期间以 40% 亮度显示整体缩放为 58×58、位于 `(3,3)` 的居中 OTA 进度,四边均有黑色空白,并在成功后恢复默认内容;摄像头画面不清晰时必须等待用户肉眼确认。
## 2. 原生驱动单元测试
`TEST-FRP-MAINTENANCE` 在 Windows mock 覆盖默认无配置且关闭、多格式创建/上传/读取/编辑/选择/删除、重名、UTF-8 与 `1 MiB` 上限、UUID 路径隔离、官方校验失败不落盘、活动编辑重启失败回滚、运行配置删除冲突、目录损坏保全、状态脱敏和设置页操作。板端校验官方 `frpc` 摘要/版本、普通维护账户、单实例、关闭时 disabled、开启后整机重启自动恢复。最后导入一次性 22 端口样例,从外部端点 SSH 登录并核对同一主机密钥;通过后关闭 FRP 并删除样例,不在源码、日志或归档保留其密密值。
`TEST-NETWORK-DIAGNOSTICS` 用可注入结果分别验证网卡/WiFi 未连接、默认网关缺失、DNS 失败、TCP 不可达、TLS/时间异常、单站点失败与 ICMP 被屏蔽但 TLS 成功。板端使用当前 NetworkManager 连接运行一次,返回中国大陆可访问多站点证据,单个目标临时异常不写成本机 DNS 或网关已确认故障。
`TEST-NATIVE-UNIT` 必须使用内存中的 fake register block,不打开真实设备:
- 物理脚到 `PI0..PI16` 和 HUB75 信号映射精确,`OE=PI14/PWM4`、`LAT=PI15/GPIO`,PI7/PI8/PI16 永不出现在显示输出 mask;映射标识固定为 `walnutpi-pi-bank-pwm-oe-v2`。
- PIO 基址 `0x0300B000`、PWM 基址 `0x0300A000`、PI bank offset `0x120`、data offset `0x10`、mux 寄存器分组与 bit 位置正确。
- 64×64 RGB888 与 `1..100` 亮度经 CIE1931 映射到 11-bit 通道值,再转换为内部位 `4..10` 的七个输出 bitplane;覆盖上下半屏六个颜色位、ABCDE 行地址、亮度非递减和白色 100% 映射到 `2047`。
- 双缓冲仅在完整帧边界交换;覆盖未展示 back buffer 不产生队列和撕裂。
- 亮度 `1..100` 和刷新挡位 `15/20/30/45/60/80/100` 校验、CIE 映射和状态更新正确;所有亮度每逻辑帧只做一次完整扫描,累计帧数与累计扫描数保持 `1:1`,亮度变化只改变 bitplane 数据。
- fake PWM4 寄存器测试覆盖:低有效极性、通道 4 启停、`PWM_MODE=1` 单脉冲、`PWM_PUL_START` 触发/自动清零模拟、PPR 可写忙状态、总周期等于有效周期、`125ns` tick 和固定 `2..128us` 位权、活动 PWM5 的兼容共享时钟被接受且 enable/bypass/PCR5/PPR5 不被覆盖、不兼容共享时钟被拒绝、LAT/OE 新 mux、帧边界切换和寄存器回读失败时强制黑屏。
- 初始化失败、PWM4/PWM5 占用冲突、线程失败、提交长度错误、关闭、析构和 `hub75_safeoff` 都先禁用 PWM4、强制 OE 高并清零占用位。
## 3. 核桃派远端健康
SSH 后先执行远端工具检查:
```sh
command -v git python3 curl wget gcc g++ make
python3 --version
gcc --version | head -n 1
uname -a
systemctl is-system-running
df -h /
free -h
nmcli -t -f GENERAL.STATE,IP4.ADDRESS,IP4.GATEWAY device show wlan0
```
要求系统为 Debian 12 / AArch64,地址、网关、时间、磁盘和内存正常。核桃派无 VPN;依赖安装只能使用已验证国内源或电脑准备的带 SHA-256 清单离线包。
冷启动时 `ExecStartPre` 使用 `dedicated_host.py check --service`,该模式不得因 NetworkManager 尚未生成默认路由而失败;服务进入就绪后,本节健康检查仍必须确认默认路由。检查当次 boot 的 journal,不得依靠一次 `default network route` 失败和 `Restart=on-failure` 重试才启动成功。
## 4. 无负载 H618 基准
开始前确认:HUB75、屏幕 5V 和 ADC 全部未连接。该阶段允许软件切换空载 GPIO,不要求用户接线。
1. 编译项目自带原生共享库和 benchmark。
2. 用 fake-register 模式先跑全部功能测试。
3. 读取板端 device tree,必须得到 `allwinner,sun50i-h616-pinctrl`、PIO `0x0300B000` 和 PWM `0x0300A000`;确认 `PI14` mux `0x5` 为 PWM4。若 PWM5 已启用,必须确认共享字段为兼容的 `24MHz/div1`,并记录 PWM5 enable、bypass、PCR5、PPR5 前值供停止后逐项比对;不兼容则停止。
4. 真实 `/dev/mem` 基准启动时先把 `PI14` 作为 GPIO 拉高 OE、数据/地址/CLK/LAT 低,再配置 PWM4 单脉冲模式并切换复用;确认 `PCR4.PWM_MODE=1`、`PWM_PUL_START` 每次脉冲后由硬件清零,禁止用 `PER` 反复启停连续 PWM;PI7、PI8、PI16 及 PWM5 前后值保持不变。
5. 以 64×64、7 个输出 bitplane、逻辑上限 100 Hz 分别在亮度 5 和 40 连续运行至少 60 秒;100 Hz 档包含固定 `0.25ms` 调度保护间隔,预期逻辑和物理扫描均约 97.56 Hz、`scans_per_frame=1`;并逐档检查 15/20/30/45/60/80/100 Hz,确认亮度不再改变 OE 时序或扫描次数。
6. 连续提交不同帧验证 buffer swap 只发生在帧边界;同时读取状态。
7. 正常停止和强制异常路径都检查 PWM4 禁用、OE 强制高、占用 data bit 清零、mux 恢复安全输入、PWM5 不变、映射与线程释放;再分别直接执行 `hub75_safeoff` 和经 systemd `ExecStopPost` 执行,结果相同。
接屏门槛:100 Hz 逻辑档实际值和面板物理扫描率均至少 95 Hz,`completed_scans = completed_frames`、`scans_per_frame=1`、`max_programmed_oe_ns=128000`。亮度 5 和 40 的 60 秒截止丢失率均不高于 0.1%,`oe_timing_backend=h618-pwm4`、`oe_pulse_faults=0`、PWM 错误为空,统计单调、RSS 不持续增长;CPU3 绑定、实时优先级、内存锁定和 governor 分项报告真实结果。任何安全关闭失败、PWM5 改动或非保留 GPIO 被改动都直接失败。
## 5. 实时服务与重启
先用 `MATRIX_DRIVER=mock` 验证:首页、`/api/status`、配置更新、字体导入与文字 PNG、模板和缩略图、两帧动图、默认内容、WebSocket RGB888。正常关闭 WebSocket 后 journal 不得出现 close 后再次发送。
再用真实驱动但仍不接屏启动服务,`/api/status` 必须返回:
- `driver=walnutpi-h618-hub75`;
- 逻辑实际刷新率、面板物理扫描率、完成帧、完成扫描、每帧扫描数、deadline miss、buffer swap;
- CPU 绑定、实时优先级、内存锁定、governor 和最后错误;
- `oe_timing_backend=h618-pwm4`、OE pulse fault/forced blank、最大编程脉宽和 PWM 错误;
- 不得把 mock 回退报告为真实成功。
执行 `systemctl restart matrix-screen-controller`,等待 `/api/status` 真正就绪后复核配置 schema v7、工作区顺序、字体、模板 schema v1、动图 schema v1、默认内容和新进程 instance ID。不得用固定 2 秒代替就绪轮询。
冷启动与服务重启都应在第一次 `ExecStartPre` 通过;若默认路由尚未出现,`--service` 预检仍允许应用启动并由后台网络流程接管。最终必须同时确认服务启动后默认路由、固定地址和网关正常。
## 6. HUB75 接线与实屏顺序
只有 `TEST-NATIVE-NOLOAD` 达标后才生成并使用接线资料。开始前明确要求核桃派和屏幕全部断电;旧接线只互换两根线为 `OE→物理脚40/PI14/PWM4`、`LAT→物理脚36/PI15/GPIO`,其余信号、共地和屏幕独立 5V 不变。用户完成并回复确认前不得启动新驱动,本阶段不连接 ADC。
上电后严格逐项:
1. 低亮度全黑:确认无随机亮点和异常发热。
2. 全红、全绿、全蓝:确认 R/G/B 线组和上下半屏。
3. 同帧混合色带与 `#FF4FA3` 粉色:确认红/橙/黄/绿/青/蓝/紫/白顺序正确,粉色不偏黄,排除 G/B 互换和 8-bit→7-bit 回绕。
4. 全白:确认组合颜色与稳定供电,不长时间高亮。
5. 四角与 `y=0/31/32/63`:确认上下半屏、CLK/LAT/OE。
6. 行带与 address check:确认 A/B/C/D/E,无半屏、重复行或乱序。
7. 0/90/180/270 方向。
8. `OK123`、中文和多语言文字。
9. 模板、图片、两帧动图和持续刷新。
上一项失败就停止。全黑有随机点只检查 CLK/LAT/OE/共地;单色错只检查六根 RGB;半屏或 32 行重复只检查 E;行序错误只检查 ABCDE。用户修正后只复测失败项,不跨项宣布通过。
亮度稳定性必须额外用 DroidCam 或等价摄像头验证。在 `1/5/20/50/60/100%` 各连续录制至少 30 秒,固定只含屏幕中央的裁剪区并舍弃前 5 秒自动曝光收敛段;比较稳定段逐帧整屏均值、每秒峰峰差和极值帧,检查局部高亮块、同步黑场、固定坏行和错色。随后锁定曝光扫过 `1..100`,要求测得亮度单调。只有复现异常或房间人员进入裁剪区时才增加独立录像,不得把重连后的曝光重置样本混合统计。
以下任一项都判为刷新失败:稳定段出现可重复的局部高亮块、整屏同步黑场或大幅周期性亮度跳变;出现固定坏行、固定错色;亮度扫描不单调;100 Hz 档 `panel_scan_rate_hz < 95` 或 `scans_per_frame != 1`;截止丢失或 OE/PWM fault 持续增长。滚动快门把面板扫描拍成随帧移动的窄亮带或暗带时,若条带数量随物理扫描率变化、整屏均值稳定且驱动统计正常,只记录为摄像头拍频,不能单独判失败;房间人员、整体曝光缓慢变化和 DroidCam 水印也不得误判为屏幕故障。若只剩拍频歧义,暂停请用户直接观察一次是否仍有肉眼可见闪烁。最终必须请用户对 5% 与 20% 各做一次肉眼确认。
若用户在已经取得驱动统计、连续录像和肉眼结论后明确决定把单一稳定性问题延期,可以继续验证与该问题相互独立的颜色、行地址和内容功能,但必须同时满足:在可单独拿走的项目 README 中登记当前症状、已做缓解、未通过项和后续调查方向;一次性证据写入移植记录;最终验收把该项列为未通过而不是跳过或通过。延期不豁免新增黑场、固定坏行、固定错色、截止丢失或异常发热的立即停止规则。
## 7. ADC 和校准
实屏通过后再次整机断电,用户只连接物理脚 3/5 的 SDA/SCL、5V、GND 和屏幕输入测量点。上电后顺序固定:
1. `/dev/i2c-1` 存在;
2. 总线发现地址 `0x48`;
3. 原始值稳定且不是伪造 `0V`;
4. 断开/权限/短读状态明确,网页与显示继续;
5. 暂停请用户把万用表接到同一屏幕输入点,只提供当前稳定读数;
6. 预览校准、确认提案、再读软件值与万用表复核;
7. 重启服务后校准保留;断开再接后自动恢复。
一次只处理一个万用表读数,不能提前假设校准通过。
## 8. 低电压保护
仅在 ADC 校准可靠后执行。每档开始前暂停,让用户调到一个指定安全电压并确认稳定;Codex 读取软件状态和实屏结果后才给下一档。
- 正常档:高于 4.8V,用户亮度与画面不变。
- 单个限亮档:4.5..4.8V,检查线性亮度上限,不改用户保存亮度。
- 临界档:严格低于 4.5V,检查 35% 黑底红图标和方向。
- 恢复档:严格高于 4.8V,满足两组确认后恢复最新用户输出。
故障、过期读数和恢复中的任何歧义都暂停,不一次要求整条电压阶梯。
## 9. 清理与最终独立性
`TEST-LOCAL-ENV` 按 [本机环境说明](本机测试环境/README.md) 的 setup/check、主机单元测试与隔离复建命令验证:锁定 wheel 安装及依赖检查通过,迁移保护和场景选择测试通过;项目 AVD 包登记有效,settings/baseline 冒烟通过并恢复环境;中文及空格的新位置不复制 venv/私有登记也能复建;`.local/` 被 Git 忽略,卫生检查通过。缺少实际验证时记“未验证”。此项不触发真机、SSH、切网、摄像头或实屏测试。迁移结束按明确路径移除旧项目专用目录和工具登记,通用工具保留。
- 停止所有临时 unit,按已验证的明确绝对路径删除临时源码、venv、wheelhouse、构建和测试数据;保留 `/var/lib/matrix-screen-controller`。
- 复核 GPIO 安全状态、系统 `running`、生产服务健康、无临时端口和无残留诊断环境变量。
- 独立目录不得含 `.venv`、缓存、运行数据、旧设备配置、旧凭据、主机密钥或外层绝对路径。
- 把整个 `奇妙小屏幕控制器-核桃派` 复制到一个隔离临时目录,只按本目录 README/测试文档重新编译和测试;任何目录外依赖都失败。
### TEST-OTA-CHECKPOINT:软件安装节点与组件事务
映射 `DEPLOY-OTA-CHECKPOINT`、`DEPLOY-OTA-COMPONENT-TRANSACTION`、`DEPLOY-FRP`、`WEB-OTA`。运行完整本机套件,并执行 `tests/test_ota_checkpoints.py`。
- 允许 `1.0.3/1.0.6 → 1.1.0`、`1.1.0 → 1.1.3`、`1.1.x → 1.2.0`;拒绝 `1.0.x → 1.1.1/1.2.0`、`1.1.x → 1.2.1`,提示首个缺失节点;同版和降级仍拒绝。
- 用真实旧更新器检验 1.1.0 v1 包解包、测试、迁移桥接,确认旧解析器拒绝后续 v2 包。旧材料只作一次性验收输入,不能成为日后构建和常规测试的依赖。
- 软件安装节点携带登记的系统组件;普通补丁不含这些二进制,篡改依赖摘要或已发布节点必须阻止导出。导出失败不推进版本,不覆盖历史产物;删除旧导出 IMG 后仍能构建;不得为测试删除长期保留的正式 OTA。
- 在隔离 AArch64 文件系统检查无 frp、完整已有 frp、二进制损坏/不同版本、缺 unit/drop-in;匹配二进制不重写,不必要时不重启,缺失部分修复。正常配置和启停状态保持,首次关闭。检查维护账户不依赖 SUDO_USER。
- 注入安装、pytest、迁移、服务启动、健康检查故障以及程序/数据切换中断;必须恢复原文件、权限、启停状态、用户内容和旧版本。模拟组件恢复失败时保留 journal,不能报告恢复成功。
- 本机或隔离环境模拟的 systemd/HTTP/显示结果不能写为真实设备 OTA、重启或实屏通过。真实调试设备只修正必要的旧 worker 兼容性时,版本保持 1.0.6,不提前安装 1.1.0。
### TEST-OTA-RUNTIME-LIFECYCLE:真实 systemd 停启与日志降级
映射 `DEPLOY-OTA-RUNTIME-LIFECYCLE`、`TEST-OTA-LOG-RESILIENCE`。本机运行 `tests/test_ota_runtime_lifecycle.py` 及 OTA/发布回归,覆盖日志降级、保护核验失败时拒绝停服、不覆盖用户 drop-in,以及组件校验允许本次事务持有的保护文件。板端运行 `sudo python3 scripts/test_runtime_directory_systemd.py`:脚本创建随机命名专用 unit,先证明 restart 策略在独立 stop 时删除目录,再实际调用生产保护函数,验证 stop、restart、启动失败期间请求/进度/日志字节不变,并清理测试 unit 和目录。两类证据分别记录。
完整包仍执行全部 pytest。涉及主服务停启的 OTA 修复必须走真实设备 OTA,核对磁盘与 API 版本、成功状态、持久数据、frp 启停和事务清理。systemctl 替身仅能验证业务分支,不能作为真实目录生命周期或 OTA 通过证据。显示效果与软件验收分开记录,缺少人工/摄像头证据时不能记为实屏通过。
同版本修复覆盖验证报告不匹配、候选源码不匹配、历史摘要损坏、提交失败回退及原始包完整归档;正式产物必须与实机验收候选包摘要一致,不得在实机成功后重新构建替换。
## 工作区目录适配验收(`TEST-WORKSPACE-LAYOUT`)
从工作区根目录及其他调用目录分别通过测试入口绝对路径执行测试;复制源码、测试入口、当前需求和必要离线材料到含中文及空格的隔离目录,按本文件命令运行 Python、前端与 mock 健康检查。复制件不得依赖原工作区或历史导出产物。发布定位用临时夹具测试,确认依赖来自 `发布更新相关/其他依赖/`,OTA 与 IMG 输出分别位于 `发布更新相关/` 下的 `OTA数据包/`、`导出包/`;不为路径验证推进正式版本。
在隔离目录执行 `clean`,确认 `.venv`、依赖指纹和人工持久数据保持不变,仅删除登记的临时目标;越界路径必须拒绝。核对现存文档链接和发布记录中的路径格式;历史导出 IMG 不做齐全性门槛,缺失默认视为用户正常清理,不列故障、不追补、不阻塞开发。OTA 今后长期保留,1.0.1 缺失为已接受例外,不再提示或要求重跑该历史组合;保留原发布记录,不重新生成。镜像内部 `project/离线依赖/` 属于载荷协议,构建器与首启脚本应继续保持一致。
## Git 仓库安全验收(`TEST-REPOSITORY-HYGIENE`)
先运行 `python "核桃派软件源代码/scripts/check_repository_hygiene.py"`。确认 Git 候选集合不包含 `测试相关资料/核桃派的用户名和密码和ip/用户名密码ip.txt` 和任何 `*.img`,但包含同目录 `.example.txt`、镜像发布说明与摘要、OTA、离线依赖、编辑器程序和历史归档;`.gitattributes` 可以为大体积二进制配置 LFS filter,卫生检查不得因此失败。检查输出只能包含文件路径和问题类型,不得包含命中的秘密或凭据值。
在含中文和空格的隔离目录测试 `prepare_credentials.py`:私有文件缺失时逐字复制示例、返回非零并要求用户填写;占位符、空值和缺字段继续失败;填写完整后成功;已有文件在所有路径均保持字节不变。随后检查文本中的 Windows/macOS/Linux 开发者主目录、当前用户名和主机名、私钥头、高可信秘密及非测试归档中的私有 IPv4;对大文件流式检查 ASCII、UTF-8 和 UTF-16LE 主机标识。测试假值、回环地址、硬件地址、设备固定部署路径和正式 IMG README 的公开默认值不得误报。
执行 `git diff --check`、`python -m pytest -q tests/test_repository_hygiene.py tests/test_workspace_layout.py` 和本机 `all` 套件。最终用 `git check-ignore -v` 复核私有文件由根规则命中,并确认 `git status --short --ignored` 把秘密、本机状态、运行数据、可再生缓存和仓库外发行的 IMG 列为忽略项;使用 `git lfs track` 与 `git lfs ls-files` 核对已配置和已暂存的 LFS 对象。本测试不执行 commit 或 push。
### Git / LFS 本地空间维护
本节仅在需要清理 Git 本地空间时执行,不属于每轮业务测试。先保存 HEAD、暂存区、工作区状态以及本地 LFS 对象的 OID 与大小清单。`git count-objects -vH` 只统计普通 Git 对象,不包含 `.git/lfs/objects`;无引用对象和中断操作的临时残留可用 `git gc` 按默认保留期限清理,执行期间避免其他 Git 写操作。
`*.img` 加入忽略并停止跟踪后,旧提交的 LFS 指针和本地缓存仍可能存在;`git gc` 不清理 LFS 缓存。先用 `git lfs ls-files --all --long --size` 将历史文件映射到 OID,再执行 `git lfs prune --dry-run --verbose --verify-remote --verify-unreachable`。必须核对完整候选 OID 集合及全部候选的远端副本,包括已无引用的对象;候选变化或远端验证失败时停止。非交互输出可能只显示最后一个候选,不能把最后一行当作完整清单;检查候选数、经验证的 OID 集合和本地对象清单。
确认候选都属于可回收的历史本地副本后,执行 `git lfs prune --verify-remote --verify-unreachable`。不使用 `--force`、`--when-unverified=continue`、`git gc --prune=now`,不直接删除 `.git/objects` 或整个 `.git/lfs`。此操作只回收本地副本,不删除工作区文件、远端 LFS 数据或历史指针,也不需要重写历史或强制推送。仍在使用的 OTA、离线依赖与镜像基线文件保持原样。
完成后比对对象清单,确认只有预先核对的候选消失,其余对象大小保持不变;核对 HEAD、已有引用、暂存区和工作区状态,运行 `git fsck --connectivity-only --no-dangling`,统计 `.git` 总体积。连接检查不替代全部内容校验或完整历史恢复测试。一次性清理对象、远端验证结果、前后清单和回收量写入 `各种归档/`,不把具体历史版本当作以后必须删除的固定目标。按影响选测:纯缓存维护与说明修订只做上述 Git 检查、仓库卫生检查和文档差异检查,不触发设备、Android 或全量业务测试。
## Android 0.2.1 界面专项映射
TEST-MOBILE-INTEGRATION 增补 MOBILE-STATUS/DISCOVERY/PREVIEW 对应的 ANDROID-TEST-STATE/UI:顶栏溢出循环配置和完整语义、认证连接后的条目断开及扫描保留、两处预览按卡片居中且刷新不重叠。共享逻辑及登记手机root验收入口和合格标准维护在 `移动端相关内容/安卓app/如何安卓测试/README.md`。手机界面及会话显示状态变化没有修改设备服务或驱动,实屏视觉检查不适用,不增加接线、显示图案切换、网络切换或真实systemd停启步骤。
## Android 选测入口
遵循 [按影响选测](../../移动端相关内容/安卓app/如何安卓测试/按影响选测.md)。日常变更不自动执行模拟器或 root 真机全量矩阵;独立 uiTest 使用真实 Compose 界面与 Controller、测试专用假平台,不替代物理 BLE。历史版本专项不作为每轮门槛。
## 多图层与扩展画布(TEST-LAYERS / TEST-LAYER-OVERFLOW / TEST-SCENE-V2-MIGRATION)
直接影响画图工具、文字编辑、草稿、模板/动图存储和共享库渲染。运行完整 `local_test.py test --suite all`、全部Node `tests/*.mjs`;定向文件为 `test_scene_layers.py`、`test_scene_layers.mjs`、场景/画笔模型、模板、动图、配置、媒体导入和手机业务契约测试。驱动、BLE线格式和App未改:不选Android真机、摄像头、实屏图案或ADC。
浏览器使用隔离mock数据及新context,按以下状态核验:
1. 清空按钮下图层面板可达;新建/复制置顶并选中,命名和排序互不干扰;至少一个画笔层,文字层可删空。每个文字层可有多段文字,切层工具和选中元素隔离。
2. 空白透出下层,黑色遮挡;背景各层独立且随层位移,擦除/清空只删笔迹。导入每帧仅一个画笔层。
3. 扩展开关默认关闭、刷新记忆,开关往返不改内容;192外围可编辑,实际64边框清晰。普通预览、保存后缩略图、播放、导出/应用只取中央区域。
4. 图层移动输入只在回车/失焦提交,各轴±1/±10逐次提交,±64限位提示;拖动预览不写草稿,松手确认。切到视线模式仍可操作移动面板,平移/捏合/滚轮不改偏移或草稿。
5. 背景越界不报警、黑色笔迹报警、移出中央不报警;越界取消保留原稿,确认只清越界内容。文字部分裁切、整段删除、移回不恢复,字号/编辑/保存重载保留裁切,撤销完整恢复。切层后撤销对象正确,成功保存按既有检查点规则清空历史。
6. 复制当前板、静态模板、动图单帧/多帧/全帧,副本独立置顶;未选帧/原层/帧序/时长不变。脏目标先保存/放弃/取消;过期If-Match冲突,模拟场景/缩略图/索引写入失败后重启检查原帧均不变。
7. 桌面、390px和320px窄屏分别检查工具、文字字段、复制对话框、悬浮菜单滚动及触摸输入;菜单不能溢出视口,所有按钮通过滚动可达。PNG及叠层像素由Node/Pillow逐字节对比;迁移前后64输出相同。
部署使用凭据门禁、远端工具检查及 `update_walnutpi.sh`。在持久数据副本迁移后才切换,健康失败恢复原程序/数据;比对所有既有内容中央输出、帧序和时长。部署后只用接口/网页逻辑验证,读取真实驱动统计,不发送诊断图案。测试创建内容仅用独立ID,验证后删除并核验;临时载荷精确清理。保持VERSION,不导出OTA/IMG。
排障经验:合并文字工作区后文案选择器会改变,重建目录并更新测试中实际迁移的选择器,不能绕过目录校验。文字位置输入必须与字号/文本的input即时更新分开,位置仅change/回车提交。复制控件遵守 `runControlAction(control, options, action)`,目标修订号在选择时捕获,不能在提交前重新读取而悄悄接受并发修改。浏览器原生确认测试使用单一dialog处理器,每步后移除或切换策略;未触发的一次性监听器会残留,不得让两个处理器同时确认同一弹窗。Windows曾出现一次无关WiFi原子替换PermissionError,单测及完整重测通过,根因未证实,不改业务逻辑。
浏览器自动化入口:`核桃派软件源代码/scripts/check_layers_browser.mjs` 导出 `checkLayersBrowser(page, baseUrl)`。在Playwright交互REPL中使用已有浏览器的新context及隔离mock服务,动态导入该文件并调用;不安装或固定开发机浏览器路径。该入口覆盖图层增删/复制/排序/命名、多文字隔离、背景、位置输入提交、部分裁切/整段删除/撤销、笔迹越界确认/取消、视线不改草稿、扩展开关记忆及重载。触摸和320/390布局另用已有Playwright context验证。
独立副本验证:复制源码、需求及本机harness到隔离中文/空格目录,不复制venv/缓存/数据或凭据;以现有解释器运行复制目录中的pytest和全部Node测试,设置 `MATRIX_SOURCE_ONLY_UPDATE_TESTS=1` 仅表示不含发行载荷,跳过项逐项记录。隔离环境不可作为便携venv复用。出现Windows原子替换/目录rename的偶发WinError5时保留首轮证据,排除并发和进程占用后重测;仅在完整重测通过后签收,不把未证实原因固化成根因。
scene迁移比对经验:内容摘要/修订改变会让手机 `mobile/previews/<64位SHA256>.png` 缓存过期,既有 `PreviewCache.reconcile` 在新内容列表建立后清理。比对时先逐帧核验64×64像素、名称、顺序/时长、业务配置和其余持久文件,缓存例外只允许严格命名且不属于当前有效修订的旧PNG;不能泛化忽略整个mobile目录或把用户数据丢失视为缓存变化。
HTML验证经验:服务启动时读取首页模板;修改HTML后重启隔离mock再检查实际DOM,避免把旧服务缓存误判成布局失败。旧导航仅含文字入口、旧草稿未知字段及越界数字均纳入迁移边界测试。
### TEST-LAYERS-UI:颜色区、复制弹窗与移动退出
对应WEB-LAYERS、WEB-EXTENDED-CANVAS。桌面及390/320px分别检查颜色标题与按钮对齐、背景开关20px且整标签可点;复制帧复选框20px、合法长名称换行、弹窗不透明,帧列表独立滚动、操作按钮可达且不横向溢出。复制当前板/独立模板/独立动图多帧,并在脏目标“保存后复制”提示中检查背景与操作。
画笔及文字层移动后分别点击“退出图层移动”,检查仍处于全屏编辑、扩展显示和视线位置不变、面板隐藏、已提交偏移保留且撤销仍能恢复。切到视线后退出同样成立;拖动尚未松手时用键盘激活退出,候选取消且不增加历史。原来的“继续编辑”在移动图层时也应可用。可复用scripts/check_layers_browser.mjs;有持久化目标的UI操作只能针对独立测试ID,设备已有目标仅打开检查并取消,不能修改用户内容。
经验:全局input的width/min-height会作用于原生checkbox,必须以局部高优先级样式指定尺寸、padding及margin;不要改全局表单样式。CSS未定义变量且无fallback会使dialog背景声明失效,应复用已定义的surface变量。DOM颜色区新增子项需显式行列结构,不能依赖原两列grid自动排放。文案目录同时更新并执行--check。截图需避开固定顶栏遮挡,先将颜色标题滚动到顶栏下再裁取颜色区域。独立测试长名称遵守现有长度上限,测试数据创建后立即记录ID,以便后续失败也可精确清理。