Files
gplan-2/tools/run_system_test.py
T

85 lines
4.1 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
r"""run_system_test.py — 系统测试运行器(脚本错误外部门禁)
用法:
python tools/run_system_test.py # 跑系统测试(过渡期宿主 res://smoke/smoke_all.gd)
python tools/run_system_test.py --script res://tests/system_test.gd
python tools/run_system_test.py --godot <引擎路径> --path <切片目录> --timeout 300
系统测试 = 启动真实工程走真实玩法路径的断言面(标准四级测试层之一)。
宿主过渡态:断言现全部住在 res://smoke/smoke_all.gd,按「只剪切禁改写」纪律迁往
res://tests/system_test.gd(宿主薄壳已在位)——迁移完成后本件缺省 --script 改指新宿主,
闸 01 系统测试随迁。
背景: GDScript 运行时脚本错误(SCRIPT ERROR)不改变进程退出码、不计入失败数,
且会静默中断所在断言函数的剩余断言——摘要零失败也可能断言未跑全。
进程内无脚本错误陷阱 API(GDScript 无 try/catch),故闸设在外部:本包装除退出码与摘要行外,
另扫输出中的 SCRIPT ERROR / Parse Error,命中即判失败。
三闸: ① 进程退出码 = 0;② 摘要行(「冒烟完成:N 项检查,0 项失败」或
「[system_test] 摘要:N 项检查,0 项失败」)在案且失败数为 0;
③ 输出无「SCRIPT ERROR」「Parse Error」标记行(标记清单经 tools/error_scan.py 复用,禁另写一份)。
"""
import argparse
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
DEFAULT_GODOT = r"D:\code\godot\Godot_v4.7.2-stable_win64_console.exe"
DEFAULT_SLICE = ROOT / "game"
DEFAULT_SCRIPT = "res://smoke/smoke_all.gd" # 过渡期宿主;断言迁移批后改 res://tests/system_test.gd
SUMMARY_RE = re.compile(r"(?:冒烟完成|\[system_test\] 摘要):(\d+) 项检查,(\d+) 项失败")
ERROR_MARKERS = ("SCRIPT ERROR", "Parse Error")
def main():
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
ap = argparse.ArgumentParser(description="系统测试运行器(脚本错误外部门禁)")
ap.add_argument("--godot", default=DEFAULT_GODOT)
ap.add_argument("--path", default=str(DEFAULT_SLICE), help="切片项目目录(含 project.godot)")
ap.add_argument("--script", default=DEFAULT_SCRIPT, help="系统测试宿主脚本")
ap.add_argument("--timeout", type=int, default=300, help="外部超时秒数(硬性要求)")
args = ap.parse_args()
cmd = [args.godot, "--headless", "--path", args.path, "--script", args.script]
try:
proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8",
errors="replace", timeout=args.timeout)
except subprocess.TimeoutExpired:
print(f"[run_system_test] FAIL:外部超时(>{args.timeout}s——硬性要求)")
return 1
out = (proc.stdout or "") + (proc.stderr or "")
sys.stdout.write(out)
if out and not out.endswith("\n"):
print()
gates = []
if proc.returncode != 0:
gates.append(f"退出码 = {proc.returncode}(≠0)")
m = SUMMARY_RE.search(out)
if m is None:
gates.append("摘要行缺失(未检出「冒烟完成:N 项检查,M 项失败」——宿主跑完前中断?)")
elif int(m.group(2)) != 0:
gates.append(f"系统测试失败 {m.group(2)} 项 / 共 {m.group(1)} 项")
hits = [ln.strip() for ln in out.splitlines() if any(k in ln for k in ERROR_MARKERS)]
if hits:
gates.append(f"脚本错误标记命中 {len(hits)} 行(首行: {hits[0][:140]}——脚本错误不计失败数,"
"且中断所在函数的剩余断言,必须人工排查)")
if m is not None:
print(f"[run_system_test] 摘要: {m.group(0)}")
if gates:
print("[run_system_test] FAIL——")
for g in gates:
print(f" - {g}")
return 1
print("[run_system_test] PASS(退出码 / 摘要失败数 / 脚本错误扫描 三闸全过)")
return 0
if __name__ == "__main__":
sys.exit(main())