# -*- coding: utf-8 -*- """terminal_tasks / terminal_execute 后台挂起 + 资源边界 验证脚本(独立运行,非 pytest)。 覆盖: 1. 后台挂起 → terminal_info 运行中/尾部输出 → wait 超时返回运行中 → kill → wait 返回已终止 2. 后台任务自然完成 → wait 返回最终输出 + 退出码 0 3. 异常退出(exit 3)→ wait 返回"异常退出(退出码: 3)" 4. 前台命令超时 → 杀进程树(含 Start-Process 后代),端口不再监听(资源边界) 5. 前台命令正常回归(python --version) """ import os import socket import sys import time sys.path.insert(0, r"C:\Users\86166\Desktop\Agent_Learning_minor\Agent\src") from agent.tools import terminal_tasks as tt # noqa: E402 from agent.tools.terminal_execute import TerminalExecute # noqa: E402 FAILS = [] def check(name, cond, extra=""): status = "PASS" if cond else "FAIL" print(f"[{status}] {name} {extra}") if not cond: FAILS.append(name) def port_open(port, timeout=1.0): try: with socket.create_connection(("127.0.0.1", port), timeout=timeout): return True except OSError: return False def main(): cwd = r"C:\Users\86166\Desktop\Agent_Learning_minor\Agent" sid = "verify_session" # ---- 1) 挂起 2s 打印脚本:info → wait 超时 → 完成 wait ---- print("=== 测试1: 后台挂起 + terminal_info + wait ===") pid = tt.start_background_task( sid, 'python -c "import time;time.sleep(2);print(\'TASK_DONE_MARK\')"', cwd, use_venv=False, ) check("启动返回正数PID", pid > 0, f"pid={pid}") time.sleep(1.2) info = tt.task_info_text(pid, max_chars=1000) check("terminal_info 运行中+头部提示", "仍在运行" in info or "运行中" in info, info[:80].replace("\n", " ")) wait_short = tt.wait_task(pid, 1) check("wait 超时返回运行中摘要", "仍在运行" in wait_short, wait_short[:60].replace("\n", " ")) wait_final = tt.wait_task(pid, 15) check("wait 等到完成+最终输出", "TASK_DONE_MARK" in wait_final and "退出码: 0" in wait_final, wait_final[:80].replace("\n", " ")) # ---- 2) kill 路径:先挂起长驻 http 服务,kill 后 wait 返回已终止 ---- print("=== 测试2: kill 杀树(http.server 依赖端口) ===") pid2 = tt.start_background_task(sid, "python -m http.server 8090", cwd, use_venv=False) check("挂起http服务", pid2 > 0) time.sleep(2) check("端口8090已监听", port_open(8090)) ok = tt.kill_task(pid2) check("kill_task 成功", ok) time.sleep(1.5) check("kill后端口8090不再监听", not port_open(8090)) after = tt.wait_task(pid2, 3) check("kill后wait返回已终止", "已终止" in after, after[:60].replace("\n", " ")) # ---- 3) 异常退出 ---- print("=== 测试3: 异常退出(exit 3) ===") pid3 = tt.start_background_task(sid, 'python -c "print(\'before boom\'); raise SystemExit(3)"', cwd, use_venv=False) res3 = tt.wait_task(pid3, 15) check("异常退出识别", "异常退出(退出码: 3)" in res3 and "before boom" in res3, res3[:100].replace("\n", " ")) # ---- 4) 前台工具超时 → 杀进程树(Start-Process 后代) ---- print("=== 测试4: 前台超时杀进程树 ===") tool = TerminalExecute() out = tool._run( "Start-Process python.exe -m http.server 8092; Start-Sleep 30", working_dir=cwd, timeout=2, use_venv=False, ) check("前台超时返回错误文本", "命令执行超时" in out, out[:80].replace("\n", " ")) time.sleep(2.5) check("超时后端口8092不再监听(进程树已清)", not port_open(8092)) # ---- 5) 前台回归 ---- print("=== 测试5: 前台正常执行 ===") out5 = tool._run("python --version", working_dir=cwd, use_venv=False) check("前台python --version", "退出码: 0" in out5 and "Python" in out5, out5[:80].replace("\n", " ")) # ---- 6) 多任务并行 ---- print("=== 测试6: 多开两个后台任务 ===") a = tt.start_background_task(sid, "python -m http.server 8093", cwd, use_venv=False) b = tt.start_background_task(sid, "python -m http.server 8094", cwd, use_venv=False) time.sleep(2) check("双端口同时监听", port_open(8093) and port_open(8094)) tt.kill_all_session(sid) time.sleep(1.5) check("kill_all_session 后均未监听", (not port_open(8093)) and (not port_open(8094))) check("运行中计数归零", tt.get_running_count() == 0, f"count={tt.get_running_count()}") print() if FAILS: print("FAILED:", FAILS) sys.exit(1) print("ALL PASS") if __name__ == "__main__": main()