测试闭环补 [ERR] 禁项:DBG_ERROR 前缀为 [ERR] 且不匹配 ERROR 子串,此前错误日志漏检

This commit is contained in:
2026-09-21 03:03:37 +08:00
parent 5d386cedfb
commit 4114416bf4
3 changed files with 21 additions and 5 deletions
@@ -47,6 +47,12 @@
| `SD2506 ID:` / `time:` / `temp:` / `battery:` | `App/app_main.c` | | `SD2506 ID:` / `time:` / `temp:` / `battery:` | `App/app_main.c` |
| `Network Init` / `net init: OK` / `MAC:` / `PHY:` | `App/task/net_task.c` | | `Network Init` / `net init: OK` / `MAC:` / `PHY:` | `App/task/net_task.c` |
**默认 Forbidden 模式**:`FAIL;ERROR;HardFault;[ERR]`
> ⚠ 固件错误级日志前缀是 `[ERR]`(`DBG_ERROR` → `[时间][ERR][TAG] 消息`),与 `ERROR`
> 子串**并不匹配**。2026-09-21 起默认列表显式加入 `[ERR]`——此前驱动/模块的错误行
> 不会被自动闭环拦截(历史日志中的 `[ERR]` 全是漏检)。产品构建正常开机应为零 `[ERR]`。
### 失败模式应对 ### 失败模式应对
| 现象 | 处理 | | 现象 | 处理 |
@@ -57,6 +63,7 @@
| 烧录后无数据(`no_data`) | 开串口 + clear 必须在烧录**前**完成(`run_boot_test.py` 已保证);核对 COM 号、板子供电,看 `state/serial.log` 有无 SYS 异常行 | | 烧录后无数据(`no_data`) | 开串口 + clear 必须在烧录**前**完成(`run_boot_test.py` 已保证);核对 COM 号、板子供电,看 `state/serial.log` 有无 SYS 异常行 |
| 端口被占用(`port busy`) | 先 `serial_tool.py close` 或 `restart`;检查其他程序占用;Keil ST-Link 不占 COM | | 端口被占用(`port busy`) | 先 `serial_tool.py close` 或 `restart`;检查其他程序占用;Keil ST-Link 不占 COM |
| 日志中无 UI 相关输出 | 见下节「UI 自动化」 | | 日志中无 UI 相关输出 | 见下节「UI 自动化」 |
| 日志出现 `[ERR]` 行 | 固件错误级日志(`DBG_ERROR`),默认 Forbidden 会判 FAIL:按 TAG 查对应模块的 `docs/问题记录/*_Trap_Records.md`;若属测试套件的**预期**错误(守卫负路径、非法名校验等),用 `--forbidden` 放宽 |
## UI 屏幕自动化 ## UI 屏幕自动化
@@ -71,6 +78,10 @@
`-Required "App init OK;Network Init;net init: OK;PHY: 100M FULL"`。 `-Required "App init OK;Network Init;net init: OK;PHY: 100M FULL"`。
- **测试套件构建**:`test/test_config.h` 开启某个 `TEST_SUITE_*` 后,把套件打印的 - **测试套件构建**:`test/test_config.h` 开启某个 `TEST_SUITE_*` 后,把套件打印的
`=== ... Test:` 标题作为 Required 标记,配合 `test/` 下各用例输出判断。 `=== ... Test:` 标题作为 Required 标记,配合 `test/` 下各用例输出判断。
**注意**:套件内**预期**的错误日志会打印 `[ERR]`(GD5F 的 `TC-GD5F-704/705` DMA 守卫
负路径与 FTL 运行期坏块、FatFs 非法名校验等),与默认 Forbidden 冲突,须显式放宽:
`--forbidden "FAIL;HardFault"`(`[FAIL]` 仍会拦截真实断言失败);
例:GD5F 套件 `--required "=== GD5F2GQ5UE Tests: 68/68 PASSED"`。
- **长时间采集**:daemon 全量持续写入 `state/serial.log`(20MB 上限自动截头保尾 10MB),直接读文件即可;或用 `log --tail 0 --grep <标记>` 过滤。 - **长时间采集**:daemon 全量持续写入 `state/serial.log`(20MB 上限自动截头保尾 10MB),直接读文件即可;或用 `log --tail 0 --grep <标记>` 过滤。
## 变更记录 ## 变更记录
@@ -79,3 +90,4 @@
|---|---| |---|---|
| 2026-09-13 | 「UI 屏幕自动化(当前缺口)」更新:UI 初始化 DBG 打印已实现(`ui_task.c`),屏幕内容已纳入模拟器像素回归;测试分层与门禁见 `测试开发标准流程.md` | | 2026-09-13 | 「UI 屏幕自动化(当前缺口)」更新:UI 初始化 DBG 打印已实现(`ui_task.c`),屏幕内容已纳入模拟器像素回归;测试分层与门禁见 `测试开发标准流程.md` |
| 2026-09-15 | 采集机制整体切换:serial-mcp-server(采集窗口/first-byte/EOF 重试)→ 仓库内置 Python 串口助手(daemon 常驻全量日志 + `wait-idle` 静默判据 `-SettleMs`/`-MaxWaitMs`);`serial_capture.ps1` 删除,流程/脚本清单/失败模式表同步 | | 2026-09-15 | 采集机制整体切换:serial-mcp-server(采集窗口/first-byte/EOF 重试)→ 仓库内置 Python 串口助手(daemon 常驻全量日志 + `wait-idle` 静默判据 `-SettleMs`/`-MaxWaitMs`);`serial_capture.ps1` 删除,流程/脚本清单/失败模式表同步 |
| 2026-09-21 | 默认 Forbidden 增补 `[ERR]`:固件 `DBG_ERROR` 前缀是 `[ERR]`(≠ `ERROR` 子串),此前驱动/模块错误日志不会被自动闭环拦截;`verify_log.py` / `run_boot_test.py` 默认值同步,测试套件运行需显式放宽 |
+2 -2
View File
@@ -23,7 +23,7 @@
[--port COM7] [--baud-rate 115200] [--settle-ms 8000] [--max-wait-ms 30000] [--port COM7] [--baud-rate 115200] [--settle-ms 8000] [--max-wait-ms 30000]
[--flash-cmd MDK-ARM\\download.bat] [--flash-timeout 180] [--flash-cmd MDK-ARM\\download.bat] [--flash-timeout 180]
[--required "App init OK;Network Init;net init: OK"] [--required "App init OK;Network Init;net init: OK"]
[--forbidden "FAIL;ERROR;HardFault"] [--forbidden "FAIL;ERROR;HardFault;[ERR]"]
[--out-dir <目录>] [--show-tail-lines 15] [--out-dir <目录>] [--show-tail-lines 15]
--port 缺省取 .opencode/serial_config.json 的 portName(单一配置源) --port 缺省取 .opencode/serial_config.json 的 portName(单一配置源)
@@ -51,7 +51,7 @@ CFG_FILE = REPO_ROOT / ".opencode" / "serial_config.json"
DEFAULT_FLASH = REPO_ROOT / "MDK-ARM" / "download.bat" DEFAULT_FLASH = REPO_ROOT / "MDK-ARM" / "download.bat"
REQUIRED_DEFAULT = "App init OK;Network Init;net init: OK" REQUIRED_DEFAULT = "App init OK;Network Init;net init: OK"
FORBIDDEN_DEFAULT = "FAIL;ERROR;HardFault" FORBIDDEN_DEFAULT = "FAIL;ERROR;HardFault;[ERR]"
def _cli(cmd_args, timeout): def _cli(cmd_args, timeout):
+7 -3
View File
@@ -7,7 +7,7 @@
用法: 用法:
& '.venv\\Scripts\\python.exe' test/verify_log.py --log-path <file> & '.venv\\Scripts\\python.exe' test/verify_log.py --log-path <file>
[--required 'marker1;marker2'] [--required 'marker1;marker2']
[--forbidden 'FAIL;ERROR;HardFault;assert'] [--forbidden 'FAIL;ERROR;HardFault;assert;[ERR]']
[--show-tail-lines 40] [--show-tail-lines 40]
退出码(与旧版一致): 退出码(与旧版一致):
@@ -18,12 +18,16 @@
默认 Required 标记对应 STM32F4-Base 启动序列(见 App/app_main.c + App/task/net_task.c), 默认 Required 标记对应 STM32F4-Base 启动序列(见 App/app_main.c + App/task/net_task.c),
按测试用例覆盖,例如: 按测试用例覆盖,例如:
--required 'App init OK;net init: OK;PHY: 100M FULL' --required 'App init OK;net init: OK;PHY: 100M FULL'
--forbidden 'FAIL;ERROR;HardFault;assert' --forbidden 'FAIL;ERROR;HardFault;assert;[ERR]'
语义约定(与旧 PowerShell 版对齐): 语义约定(与旧 PowerShell 版对齐):
- Required:大小写敏感子串匹配(全文) - Required:大小写敏感子串匹配(全文)
- Forbidden:大小写**不敏感**子串匹配、逐行计数(旧版 -like 语义; - Forbidden:大小写**不敏感**子串匹配、逐行计数(旧版 -like 语义;
如 Forbidden 'FAIL' 会命中 "write /log/run.log fail (7)" 这类行) 如 Forbidden 'FAIL' 会命中 "write /log/run.log fail (7)" 这类行)
- 固件错误级日志前缀是 `[ERR]`(`DBG_ERROR`,形如 `[时间][ERR][TAG] 消息`),
与 `ERROR` 子串**不匹配**——默认 Forbidden 因此显式包含 `[ERR]`,驱动/模块
错误行不再漏检(2026-09-21 修复)。测试套件中**预期**出现 `[ERR]` 的用例
(如 GD5F DMA 守卫负路径、FatFs 非法名校验)须用 --forbidden 覆盖默认值。
- 读取编码:先按 UTF-8,解码失败回退系统 locale 编码(旧版 Get-Content 行为) - 读取编码:先按 UTF-8,解码失败回退系统 locale 编码(旧版 Get-Content 行为)
- 控制台输出重配置为 UTF-8(errors=replace):任何 Windows 控制台代码页 - 控制台输出重配置为 UTF-8(errors=replace):任何 Windows 控制台代码页
都只影响终端显示,不会导致本脚本崩溃 都只影响终端显示,不会导致本脚本崩溃
@@ -35,7 +39,7 @@ import sys
from pathlib import Path from pathlib import Path
REQUIRED_DEFAULT = "App init OK;Network Init;net init: OK" REQUIRED_DEFAULT = "App init OK;Network Init;net init: OK"
FORBIDDEN_DEFAULT = "FAIL;ERROR;HardFault;assert" FORBIDDEN_DEFAULT = "FAIL;ERROR;HardFault;assert;[ERR]"
def _split_list(spec): def _split_list(spec):