S7:@test闭环增加自检结论联合判定(selftest.log缺失或空=PASS、有64B记录=FAIL;FTP匿名抓取+本地副本两种来源)
This commit is contained in:
+43
-3
@@ -9,6 +9,7 @@
|
||||
[--required 'marker1;marker2']
|
||||
[--forbidden 'FAIL;ERROR;HardFault;assert;[ERR]']
|
||||
[--require-suite-summary 'Storage Tests;GD5F2GQ5UE Tests']
|
||||
[--require-selftest-pass] [--selftest-log <selftest.log 本地副本>]
|
||||
[--show-tail-lines 40]
|
||||
|
||||
退出码(与旧版一致):
|
||||
@@ -36,6 +37,11 @@
|
||||
命中即判 PASS,**套件是否跑到汇总行、断言数是否为 0 完全不可见**(套件中途
|
||||
挂死/复位、或 Phase 宏全关时会被误判为通过)。`--require-suite-summary`
|
||||
要求日志中出现 `=== <名称>: N/M PASSED (failed=0) ===` 且 **N > 0**。
|
||||
- 自检记录联合判定(S7,2026-10 实机窗口):`--require-selftest-pass` 对 /log/selftest.log
|
||||
的本地副本(定长 64B 记录,格式见 App/log/sys_log.h)判定。自检仅故障写盘(v1 不记
|
||||
通过项):**文件缺失 / 0 字节 = 无故障 → PASS**;存在任何一条记录 = 有故障 → FAIL
|
||||
(退出码 1),并逐条打印时间戳 + 描述。抓取失败(设备不可达 / FTP 错误等)由调用方
|
||||
(run_boot_test.py)先打 WARN,本地文件按缺失处理 → 按上述规则不判整体 FAIL。
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@@ -72,11 +78,15 @@ def _read_lines(path):
|
||||
|
||||
|
||||
def verify(log_path, required=REQUIRED_DEFAULT, forbidden=FORBIDDEN_DEFAULT,
|
||||
show_tail=40, out=print, suite_summary=""):
|
||||
show_tail=40, out=print, suite_summary="",
|
||||
selftest_pass=False, selftest_log=""):
|
||||
"""标记校验核心(可被 run_boot_test.py 复用)。返回退出码 0/1/2。
|
||||
|
||||
suite_summary: ';' 分隔的套件名列表。非空时,要求日志中每个套件都出现
|
||||
`=== <名称>: N/M PASSED (failed=0) ===` 且 **N > 0**。
|
||||
selftest_pass: True 时对 selftest_log(/log/selftest.log 本地副本)联合判定:
|
||||
文件缺失 / 0 字节 = 无故障(PASS);存在任何 64B 记录 = FAIL(S7)。
|
||||
selftest_log: 自检记录文件本地路径(空串 = 按文件缺失处理)。
|
||||
"""
|
||||
p = Path(log_path)
|
||||
if not p.is_file():
|
||||
@@ -149,6 +159,29 @@ def verify(log_path, required=REQUIRED_DEFAULT, forbidden=FORBIDDEN_DEFAULT,
|
||||
if not ok:
|
||||
bad_summary.append(name)
|
||||
|
||||
# 自检记录联合判定(S7):/log/selftest.log 定长 64B 记录(格式见 App/log/sys_log.h),
|
||||
# 仅故障写盘:文件缺失 / 0 字节 = 无故障 → PASS;存在任何一条记录 → FAIL
|
||||
selftest_fail = False
|
||||
if selftest_pass:
|
||||
sp = Path(selftest_log) if selftest_log else None
|
||||
if sp is None or not sp.is_file() or sp.stat().st_size == 0:
|
||||
out("[OK] selftest: no fault record (file missing or empty)")
|
||||
else:
|
||||
raw = sp.read_bytes()
|
||||
n = len(raw) // 64
|
||||
if len(raw) % 64:
|
||||
out("[WARN] selftest log has {} trailing incomplete bytes (ignored)".format(len(raw) % 64))
|
||||
if n > 0:
|
||||
selftest_fail = True
|
||||
out("[FAIL] selftest: {} fault record(s) in {}".format(n, selftest_log))
|
||||
for i in range(n):
|
||||
rec = raw[i * 64:(i + 1) * 64]
|
||||
ts = rec[0:19].decode("ascii", errors="replace")
|
||||
desc = rec[31:59].split(b"\0", 1)[0].decode("utf-8", errors="replace")
|
||||
out(" #{}: {} {}".format(i, ts, desc))
|
||||
else:
|
||||
out("[OK] selftest: no fault record (0 complete records)")
|
||||
|
||||
if show_tail > 0 and lines:
|
||||
out("")
|
||||
out("=== Last {} line(s) of log ===".format(show_tail))
|
||||
@@ -156,7 +189,7 @@ def verify(log_path, required=REQUIRED_DEFAULT, forbidden=FORBIDDEN_DEFAULT,
|
||||
out(ln)
|
||||
|
||||
out("")
|
||||
if missing or hits or bad_summary:
|
||||
if missing or hits or bad_summary or selftest_fail:
|
||||
out("VERDICT: FAIL")
|
||||
return 1
|
||||
out("VERDICT: PASS")
|
||||
@@ -182,10 +215,17 @@ def main(argv=None):
|
||||
"with N>0, ';' separated (T-2). Empty = off")
|
||||
ap.add_argument("--show-tail-lines", type=int, default=40,
|
||||
help="show last N log lines (0 = off)")
|
||||
ap.add_argument("--require-selftest-pass", action="store_true",
|
||||
help="judge /log/selftest.log local copy (S7): "
|
||||
"missing/empty = PASS, any 64B record = FAIL")
|
||||
ap.add_argument("--selftest-log", default="",
|
||||
help="local copy path of /log/selftest.log (with --require-selftest-pass)")
|
||||
args = ap.parse_args(argv)
|
||||
|
||||
return verify(args.log_path, args.required, args.forbidden,
|
||||
args.show_tail_lines, suite_summary=args.require_suite_summary)
|
||||
args.show_tail_lines, suite_summary=args.require_suite_summary,
|
||||
selftest_pass=args.require_selftest_pass,
|
||||
selftest_log=args.selftest_log)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user