"""Tests for the async dolt subprocess wrapper's failure handling. Uses the Python interpreter as a stand-in subprocess (cross-platform, no dolt needed) to prove a non-zero exit and a hung command both raise DoltError — the latter is what stops a hung pull from pinning the import connection + advisory lock forever. """ from __future__ import annotations import sys import time from pathlib import Path import pytest from app.services import dolt_client from app.services.dolt_client import DoltError async def test_run_raises_on_nonzero_exit(): with pytest.raises(DoltError) as exc: await dolt_client._run( sys.executable, ["-c", "import sys; sys.exit(3)"], cwd=Path.cwd(), timeout=30 ) assert "3" in str(exc.value) async def test_run_times_out_and_kills(): start = time.monotonic() with pytest.raises(DoltError) as exc: await dolt_client._run( sys.executable, ["-c", "import time; time.sleep(30)"], cwd=Path.cwd(), timeout=0.5, ) elapsed = time.monotonic() - start assert "timed out" in str(exc.value) assert elapsed < 10 # killed promptly, not waited out async def test_run_returns_stdout_on_success(): out = await dolt_client._run( sys.executable, ["-c", "print('hello')"], cwd=Path.cwd(), timeout=30 ) assert out.strip() == "hello"