96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""bg proc host 模式手工验证(ASCII-only 输出,GBK console 安全)。
|
|
|
|
场景:
|
|
1. shell background 启动一个 ~6s 的命令 -> 立即返回
|
|
2. 期间 status = running
|
|
3. 结束后 status = finished, exit_code=0, 日志内容对
|
|
4. inline python background + kill
|
|
5. count_running / list_procs / sweep 冒烟
|
|
"""
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
|
|
|
from core import procs # noqa: E402
|
|
|
|
anchor = Path(tempfile.mkdtemp(prefix="zcbot_bgproc_test_"))
|
|
task_id = "11111111-1111-1111-1111-111111111111"
|
|
fails = []
|
|
|
|
|
|
def check(name, cond):
|
|
print(("[ok] " if cond else "[FAIL] ") + name)
|
|
if not cond:
|
|
fails.append(name)
|
|
|
|
|
|
# 1. python inline bg: 3s 后打印再退出
|
|
code = "import time\nprint('phase1', flush=True)\ntime.sleep(3)\nprint('phase2 done', flush=True)\n"
|
|
t0 = time.time()
|
|
pid1, d1 = procs.launch_host(
|
|
anchor, task_id, kind="python", command_display="python <inline>",
|
|
cwd=anchor, timeout_s=120, env=None, inline_code=code,
|
|
argv=None, shell_cmd=None,
|
|
)
|
|
launch_elapsed = time.time() - t0
|
|
check("launch returns fast (<2s), got %.2fs" % launch_elapsed, launch_elapsed < 2)
|
|
|
|
time.sleep(1.5)
|
|
meta1 = procs.read_meta(d1)
|
|
st, ec = procs.status_of(meta1, d1)
|
|
check("running mid-flight (got %s)" % st, st == "running")
|
|
check("count_running == 1 (got %d)" % procs.count_running(anchor), procs.count_running(anchor) == 1)
|
|
|
|
for _ in range(20):
|
|
time.sleep(0.5)
|
|
st, ec = procs.status_of(procs.read_meta(d1), d1)
|
|
if st == "finished":
|
|
break
|
|
check("finished with exit 0 (got %s/%s)" % (st, ec), st == "finished" and ec == 0)
|
|
log = procs.tail_log(d1)
|
|
check("log has phase2 output", "phase2 done" in log)
|
|
|
|
# 2. timeout kill: sleep 60 but timeout_s=61 clamp floor -> use argv sleep via python
|
|
code2 = "import time\ntime.sleep(600)\n"
|
|
pid2, d2 = procs.launch_host(
|
|
anchor, task_id, kind="python", command_display="python <sleeper>",
|
|
cwd=anchor, timeout_s=120, env=None, inline_code=code2,
|
|
argv=None, shell_cmd=None,
|
|
)
|
|
time.sleep(1.5)
|
|
meta2 = procs.read_meta(d2)
|
|
st2, _ = procs.status_of(meta2, d2)
|
|
check("sleeper running", st2 == "running")
|
|
msg = procs.kill_proc(meta2, d2)
|
|
time.sleep(1.0)
|
|
st2b, ec2 = procs.status_of(procs.read_meta(d2), d2)
|
|
check("killed -> finished 137 (got %s/%s, msg=%s)" % (st2b, ec2, msg),
|
|
st2b == "finished" and ec2 == 137)
|
|
|
|
# 3. list + format
|
|
items = procs.list_procs(anchor, task_id)
|
|
check("list_procs sees 2 (got %d)" % len(items), len(items) == 2)
|
|
for m in items:
|
|
print(" " + procs.format_proc_line(m))
|
|
|
|
# 4. sweep: nothing removed (fresh), then with ttl=0 removes finished dirs
|
|
stats = procs.sweep(anchor.parent / "_nonexistent_users")
|
|
stats2 = procs.sweep(anchor.parent, ttl_s=10 ** 9) # anchor.parent as users base: anchor is one 'user'
|
|
# note: sweep expects user_root_base -> iterates children; anchor.parent contains anchor
|
|
check("sweep noop keeps dirs", (anchor / procs.PROCS_SUBDIR / task_id).is_dir())
|
|
stats3 = procs.sweep(anchor.parent, ttl_s=0)
|
|
remaining = list((anchor / procs.PROCS_SUBDIR / task_id).glob("*")) if (anchor / procs.PROCS_SUBDIR / task_id).is_dir() else []
|
|
check("sweep ttl=0 removed finished dirs (left %d)" % len(remaining), len(remaining) == 0)
|
|
|
|
shutil.rmtree(anchor, ignore_errors=True)
|
|
print()
|
|
if fails:
|
|
print("RESULT: %d FAILURE(S): %s" % (len(fails), "; ".join(fails)))
|
|
sys.exit(1)
|
|
print("RESULT: ALL PASS")
|