diff --git a/game/tests/run_all.gd b/game/tests/run_all.gd index 308c0e0b..4e803b0a 100644 --- a/game/tests/run_all.gd +++ b/game/tests/run_all.gd @@ -279,9 +279,18 @@ func _run_suite(suite: Dictionary, idx: int, filtered: bool = false) -> Dictiona DirAccess.make_dir_recursive_absolute(proj + "/tests/.gates") # /V:ON=延迟展开:!ERRORLEVEL! 到 echo 执行时(套件已退出)才取值; # 延迟展开会吞字面 !,命令串各段(引擎路径/工程路径/套件路径/日志路径)不得含 !。 - var cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1 & echo !ERRORLEVEL! > "%s"' % [bin, proj, path, log, codefile] + var pid: int = -1 var out := PackedStringArray() - var pid: int = OS.create_process("cmd.exe", PackedStringArray(["/V:ON", "/C", cmd])) + if OS.get_name() == "Windows": + # Windows 形态(原实现逐位保留):/V:ON 延迟展开,!ERRORLEVEL! 到 echo 时(套件已退出)才取值; + # 延迟展开会吞字面 !,命令串各段(引擎路径/工程路径/套件路径/日志路径)不得含 !。 + var cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1 & echo !ERRORLEVEL! > "%s"' % [bin, proj, path, log, codefile] + pid = OS.create_process("cmd.exe", PackedStringArray(["/V:ON", "/C", cmd])) + else: + # POSIX 形态(mac/Linux runner):/bin/sh -c 同步串行——sh 前台等引擎退出再落 $?, + # 无延迟展开问题;create_process 拿 sh 的 pid(存活轮询=sh 前台等待期),截止杀走 kill 树。 + var sh_cmd := '"%s" --headless --path "%s" --script "%s" > "%s" 2>&1; echo $? > "%s"' % [bin, proj, path, log, codefile] + pid = OS.create_process("/bin/sh", PackedStringArray(["-c", sh_cmd])) if pid < 0: push_error("[run_all] FAIL %s — cmd 子进程启动失败(pid=%d)" % [path, pid]) return {"fail": 1, "timed_out": false} @@ -299,7 +308,12 @@ func _run_suite(suite: Dictionary, idx: int, filtered: bool = false) -> Dictiona var negative := bool(suite.get("negative", false)) if timed_out: var kill_out := PackedStringArray() - OS.execute("taskkill", PackedStringArray(["/F", "/T", "/PID", str(pid)]), kill_out, true) + if OS.get_name() == "Windows": + OS.execute("taskkill", PackedStringArray(["/F", "/T", "/PID", str(pid)]), kill_out, true) + else: + # POSIX:先杀 sh 的直接子进程(引擎),再杀 sh 自身(顺序要紧——先杀父会让子成孤儿续跑) + OS.execute("pkill", PackedStringArray(["-9", "-P", str(pid)]), kill_out, true) + OS.execute("kill", PackedStringArray(["-9", str(pid)]), kill_out, true) # taskkill 落刀到进程对象消失有间隔:等死确认再放行下一套件(10s 宽限), # 确认不了也如实报红留 PID 供手工清杀,不静默放行。 var reap_deadline := Time.get_ticks_msec() + 10000