S7:@test闭环增加自检结论联合判定(selftest.log缺失或空=PASS、有64B记录=FAIL;FTP匿名抓取+本地副本两种来源)
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
3. wait-idle:RX 静默 >= settle-ms,或 max-wait-ms 超时
|
||||
4. 从日志提取 [RX] 载荷行(剥掉 "[RX] <ISO时间戳> " 前缀)
|
||||
5. verify_log.py 标记校验
|
||||
6. (仅当 --require-selftest-pass)自检记录联合判定(S7):
|
||||
--selftest-log 提供本地副本则直接用它,否则从设备 FTP 抓取 /log/selftest.log
|
||||
(lftpd :21 匿名);判定:文件缺失 / 0 字节 = 无故障 → PASS,有 64B 记录 = FAIL
|
||||
|
||||
采集在烧录**之前**武装(open + clear 先于烧录),daemon 常驻全量日志兜底,
|
||||
无采集窗口/首字节等待仪式(与旧 PowerShell 版行为一致)。
|
||||
@@ -25,7 +28,8 @@
|
||||
[--required "App init OK;Network Init;net init: OK"]
|
||||
[--forbidden "FAIL;ERROR;HardFault;[ERR]"]
|
||||
[--require-suite-summary "Storage Tests"]
|
||||
[--out-dir <目录>] [--show-tail-lines 15]
|
||||
[--require-selftest-pass] [--selftest-log <本地副本>]
|
||||
[--device-ip 192.168.1.100] [--out-dir <目录>] [--show-tail-lines 15]
|
||||
|
||||
--port 缺省取 .opencode/serial_config.json 的 portName(单一配置源)
|
||||
|
||||
@@ -37,6 +41,7 @@
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import ftplib
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -79,6 +84,32 @@ def _tool_cmd(py, cmd, *rest, timeout=15):
|
||||
return data, out
|
||||
|
||||
|
||||
def _fetch_selftest_log(device_ip, out_dir, stamp):
|
||||
"""从设备 FTP 抓取 /log/selftest.log(lftpd :21 匿名,根目录 = 卷根)。
|
||||
|
||||
成功返回本地路径字符串;失败(网络不可达 / FTP 错误 / 设备侧文件缺失)返回 ""
|
||||
(按 S7 语义视为无故障记录;此处打 WARN,调用方不判整体 FAIL)。
|
||||
"""
|
||||
local = Path(out_dir) / "selftest_log_{}.log".format(stamp)
|
||||
try:
|
||||
ftp = ftplib.FTP()
|
||||
ftp.connect(device_ip, 21, timeout=10)
|
||||
ftp.login() # 匿名(lftpd 接受 USER anonymous / 空 PASS)
|
||||
buf = bytearray()
|
||||
ftp.retrbinary("RETR /log/selftest.log", buf.extend)
|
||||
try:
|
||||
ftp.quit()
|
||||
except OSError:
|
||||
pass
|
||||
local.write_bytes(bytes(buf))
|
||||
print("SELFTEST_FETCH: {} -> {} ({} bytes)".format(device_ip, local, len(buf)))
|
||||
return str(local)
|
||||
except OSError as e:
|
||||
print("RUN_TEST_WARN: selftest fetch failed: {} "
|
||||
"(按 S7 语义视为无记录;设备网络/FTP 需另行排查)".format(e))
|
||||
return ""
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
# 控制台输出固定 UTF-8:Windows 代码页只影响显示,不会让脚本崩溃
|
||||
for stream in (sys.stdout, sys.stderr):
|
||||
@@ -106,6 +137,13 @@ def main(argv=None):
|
||||
ap.add_argument("--require-suite-summary", default="",
|
||||
help="suite names that MUST appear as '=== <name>: N/M PASSED (failed=0) ===' "
|
||||
"with N>0, ';' separated (T-2). Empty = off")
|
||||
ap.add_argument("--require-selftest-pass", action="store_true",
|
||||
help="jointly judge /log/selftest.log (S7): missing/empty = PASS, "
|
||||
"any 64B record = FAIL")
|
||||
ap.add_argument("--selftest-log", default="",
|
||||
help="local copy of /log/selftest.log (skips device-side fetch when given)")
|
||||
ap.add_argument("--device-ip", default="192.168.1.100",
|
||||
help="device IP for fetching /log/selftest.log via FTP (lftpd anonymous)")
|
||||
ap.add_argument("--out-dir", default=str(Path(tempfile.gettempdir()) / "opencode"))
|
||||
ap.add_argument("--show-tail-lines", type=int, default=15)
|
||||
args = ap.parse_args(argv)
|
||||
@@ -211,10 +249,17 @@ def main(argv=None):
|
||||
boot_txt.write_bytes(("\r\n".join(rx) + "\r\n").encode("utf-8"))
|
||||
print("Boot log: {} (lines={} gen={})".format(boot_txt, len(rx), data.get("gen")))
|
||||
|
||||
# 6. 标记校验
|
||||
# 5.5 自检记录抓取(S7):启用且未提供本地副本时才走 FTP
|
||||
selftest_local = args.selftest_log
|
||||
if args.require_selftest_pass and not selftest_local:
|
||||
selftest_local = _fetch_selftest_log(args.device_ip, out_dir, stamp)
|
||||
|
||||
# 6. 标记校验(含可选的自检记录联合判定)
|
||||
from verify_log import verify
|
||||
rc = verify(str(boot_txt), args.required, args.forbidden, args.show_tail_lines,
|
||||
suite_summary=args.require_suite_summary)
|
||||
suite_summary=args.require_suite_summary,
|
||||
selftest_pass=args.require_selftest_pass,
|
||||
selftest_log=selftest_local)
|
||||
print("RUN_TEST_RC={}".format(rc))
|
||||
return rc
|
||||
|
||||
|
||||
Reference in New Issue
Block a user