import os import subprocess import sys from types import SimpleNamespace import pytest PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if PROJECT_ROOT not in sys.path: sys.path.insert(0, PROJECT_ROOT) import tools.command_tools as command_tools_module from tools.command_tools import EXECUTE_COMMAND_TIMEOUT_SECONDS, execute_command @pytest.mark.asyncio async def test_execute_command_uses_600_second_timeout(monkeypatch): captured = {} async def fake_to_thread(func, *args, **kwargs): captured["func"] = func captured["args"] = args captured["kwargs"] = kwargs return SimpleNamespace(returncode=0, stdout="ok\n", stderr="") monkeypatch.setattr(command_tools_module.asyncio, "to_thread", fake_to_thread) result = await execute_command("uv run python demo.py") assert result == "ok" assert captured["args"][0] == "uv run python demo.py" assert captured["kwargs"]["timeout"] == EXECUTE_COMMAND_TIMEOUT_SECONDS == 600 @pytest.mark.asyncio async def test_execute_command_returns_english_failure_message(monkeypatch): async def fake_to_thread(func, *args, **kwargs): return SimpleNamespace(returncode=1, stdout="trace line\n", stderr="boom\n") monkeypatch.setattr(command_tools_module.asyncio, "to_thread", fake_to_thread) result = await execute_command("uv run python broken.py") assert "Command failed with exit code 1." in result assert "STDOUT:\ntrace line" in result assert "STDERR:\nboom" in result assert "Timeout may be caused by the program waiting for input" not in result @pytest.mark.asyncio async def test_execute_command_returns_english_timeout_message(monkeypatch): async def fake_to_thread(func, *args, **kwargs): raise subprocess.TimeoutExpired( cmd="uv run python slow.py", timeout=EXECUTE_COMMAND_TIMEOUT_SECONDS, output="still running\n", stderr="waiting\n", ) monkeypatch.setattr(command_tools_module.asyncio, "to_thread", fake_to_thread) result = await execute_command("uv run python slow.py") assert ( f"Command timed out after {EXECUTE_COMMAND_TIMEOUT_SECONDS} seconds." in result ) assert ( "The process may be stuck, waiting for input, or simply taking too long." in result ) assert "Partial STDOUT:\nstill running" in result assert "Partial STDERR:\nwaiting" in result