113 lines
4.6 KiB
Python
113 lines
4.6 KiB
Python
# -*- 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()
|