Files
STM32F4-Base/test/host/sys_log_mcu/run_unit_test.py
T
wandering1 794906cdc8 test(host): P2 覆盖率批次,5 套主机单测与共享假 FatFs
P2 五个文件全部进分母(三名队友并行,写范围互斥、零越界):
  net_socket 420 条 / 881-883=99.8%、52-52 函数(S1~S6 分片)
  sys_log_mcu 75 条 / 310-313=99.0%、12-12
  console_log 104 条 / 188-189=99.5%、15-15
  cfg_file_store_mcu 34 条 / 97-97=100%、10-10
  soe_store 26 条 / 78-79=98.7%、4-4
合计 659 条断言,P2 本体 1554-1561=99.6%、93-93 函数。

账:套件 28→33 全绿;files_tested 32→37;未触及 112→107(.c 34→29,
恒等式 29 = 0(P1剩) + 0(P2) + 29(P3) 咬合,§9 终点判据达成);分母
4684→6245 插桩行;line 85.8%→89.3%;func 90.1%→92.2%(这批 5 个文件
全都以 ≥98.7% 进分母,故未摊薄)。--update-baseline 前后逐文件比对:
下降 0 个文件。

基建:新建 test/host/common/fatfs_fake.{h,c}(以真实 ff.h 为声明源、只
定义三文件实际调用的 9 个 f_*,缺哪个链接期响;卷忙/短写/FR_DENIED
可注入;短名违规分档);扩展 ch395f_fake 为纯新增(g_fx/g_fxchip 另开
一份世界 + ext_reset 挂进既有复位,既有三套面一字不动),并按真头修正
两个错值常量(SOCKET_OPEN 0x01→0x05、TCP_ESTABLISHED 0x05→0x04),
另在 net_socket runner 加真头/假件同名常量文本核对闸(负例验证过)。
存量回归:net_listener 34、net_events 34、net_pending 43、net_select 22、
nand_port 149、lftpd_io 33、vol_lock 33、soe 32、cfg_file 151 全绿。

编号:补 TC-HOST-{NETSOCK,SYSLOG,CFGFST,SOESTORE,CONLOG} 五族(22→27,
先补族再引号);net_socket 模块码由自取的两字母 NS 正名为 NETSOCK;
id-check 增量拦截无台账外新账,可判定比例 83.27%(基线 82.6%)。

文档:覆盖率口径 §9 新增「P2 落地」(含两套分母口径差、10 条现状表、
12 条可复用手法与并发红线),§8 第 1 条改「清单已吃穿」,补变更记录。
本提交未改任何生产代码(App/Drivers/Src/Lib/MDK-ARM 零触碰)。

10 条现状已逐条登记在 §9(含 sys_log_mcu.c:509~537 卷忙整批丢日志、
net_socket.c 同文件两套 IP 字节序、UDP 两 API 绕过 netTask),已获指示
全部修复,另开一轮(含测试字面量统一纯 ASCII)。

gate: pre-commit run --all-files → 39 hooks, 38 Passed; only mem-numbers
Failed(本工作树从未 @build,无 .map 事实源,属分支期已知陷阱);
mem-budget Passed;test-coverage 与 id-check Passed。RAM/Flash 增量 = 0
(纯测试批次)。按仓内分支约定走 --no-verify,台账回填留待主树合并后。
2026-10-24 17:54:02 +08:00

73 lines
3.9 KiB
Python
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.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
r"""运行/自检记录落盘后端(sys_log_mcu)的主机侧单元测试运行器(L0.5,纯标准库)。
做什么:
用本机 MSVC 编译 test/host/sys_log_mcu/sys_log_mcu_test.c(以 #include 纳入**生产源**
App/log/sys_log_mcu.c,并纳入共享假卷 test/host/common/fatfs_fake.c),在 PC 上离线
跑 64B 定长记录格式、单条/批量两条写路径、syslog_drain 的 preboot+队列排空与
"失败回投不丢条目"、N-24 的 8 条滑动读窗口 + 写者代数失效、挂载幂等与
上电/重启分类、sys_log_evidence 的 wdev.log 取证通道,失败即非 0 退出。
工具链与判定委托 test/host/common/unit_test_harness.py。
为什么要主机侧单测(而不是只用台架):
1. **FA_OPEN_APPEND 不含 FA_WRITE**(存储架构 §10.1 第 11 条):漏写位时 f_open
会成功、文件甚至被创建出来,只有 f_write 恒返 FR_DENIED —— 真机表现是
"/log 写失败 x5/开机",2026-09-20 才定位到根因。假卷按真实 ff.c 判 fp->flag
就能把这条做成必然失败的断言。
2. **f_write 簇分配失败 = FR_OK + 短写**(同一页第 11 条后半):只判 fr != FR_OK
等于把丢记录当写成功;短写注入只有假卷给得出。
3. **挂载幂等**:syslog_mcu_mounted 曾在建 /log 失败后永久 no-op(运行期日志与自检
全部滞留),改成幂等 + 重试后又必须防"每 2s 刷一条同样错误" → 要注入 mkdir
失败才测得到,且必须能数出"到底留痕几次"。
4. **读窗口 try 语义 / N-24 读侧**:窗口"命中即零 I/O"与"写者一落地就失效"是一枚硬币两面,
只做前者会把陈旧读当正确、只做后者会退回逐条 open/seek/close 的旧实现。
桩的边界:ff.h / sys_log.h / soe_store.h / sys_clock.h / vol_lock.h 用**真实头**;
main.h 是桩,只为截断 sys_clock.h -> sd2506.h -> main.h -> stm32f4xx_hal.h;
cmsis_os.h / dbg_log.h 本目录桩。soe_store_drain() 用**计数桩**(本套只断言
"每次 drain 各调一次"这个 B9 挂接点,SOE 落盘本身归 test/host/soe_store/)。
FatFs 由 test/host/common/fatfs_fake.c 给 RAM 实现(**显式纳入,不用目录通配**)。
sys_clock_* / vol_lock_* / osMessageQueue* 强符号桩写在本测试单元里。
用法(仓库根目录):
& '.venv\\Scripts\\python.exe' test/host/sys_log_mcu/run_unit_test.py
退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。
设计依据:docs/子系统设计/运行与自检记录设计说明.md §4.4/§4.5/§5.3、
docs/架构设计/STM32F4-Base存储架构说明.md §10.1 第 10/11 条、
docs/测试说明/主机单测覆盖率口径.md §9 P2 第 2 项
创建日期:2026-10-24
"""
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
sys.path.insert(0, os.path.join(ROOT, "test", "host", "common"))
from unit_test_harness import TestBuild, run_host_unit_test # noqa: E402
# 顺序敏感:stub 必须最先(覆盖 cmsis_os.h / dbg_log.h / main.h),其余全用真实头。
# 假卷 fatfs_fake.c 由测试单元 #include 纳入(同 ch395f_fake.c 惯例,显式列文件、不通配)。
BUILD = TestBuild(
name="Sys Log Mcu Tests",
src=os.path.join(HERE, "sys_log_mcu_test.c"),
include_dirs=[
os.path.join(HERE, "stub"),
os.path.join(ROOT, "test", "host", "common"),
os.path.join(ROOT, "App", "log"),
os.path.join(ROOT, "App", "util"),
os.path.join(ROOT, "App", "fs"),
os.path.join(ROOT, "Drivers", "BSP"),
os.path.join(ROOT, "Drivers", "BSP", "SD2506"),
os.path.join(ROOT, "Lib", "FatFs"),
HERE,
],
summary_marker="=== Sys Log Mcu Tests:",
)
if __name__ == "__main__":
sys.exit(run_host_unit_test(BUILD))