test(timeout): use clock-free unit tests per AGENTS.md

Signed-off-by: agustin18 <agustinsaiz02@gmail.com>
This commit is contained in:
agustin18 2026-09-27 23:06:30 +00:00
parent a8aff17f30
commit 06f400e4e9

View file

@ -1,7 +1,6 @@
"""Unit tests for litellm.timeout decorator."""
import asyncio
import time
from typing import Final
import pytest
@ -12,65 +11,87 @@ from litellm.timeout import timeout
@pytest.mark.asyncio
@pytest.mark.parametrize("timeout_arg", ["request_timeout", "force_timeout"])
async def test_async_timeout_decorator_respects_per_call_timeout(timeout_arg: str):
"""An async function decorated with a large timeout must respect a shorter per-call timeout."""
async def test_async_timeout_decorator_passes_per_call_timeout(
monkeypatch: pytest.MonkeyPatch, timeout_arg: str
) -> None:
captured_timeout: Final[list[float | None]] = []
async def fake_wait_for(fut, timeout):
captured_timeout.append(timeout)
return await fut
monkeypatch.setattr("litellm.timeout.asyncio.wait_for", fake_wait_for)
@timeout(timeout_duration=5.0)
async def slow_async_func(**kwargs):
await asyncio.sleep(0.5)
async def sample_func(**kwargs):
return "ok"
start_time: Final = time.monotonic()
kwargs = {timeout_arg: 0.05, "model": "test-model"}
result: Final = await sample_func(**{timeout_arg: 0.05, "model": "test-model"})
assert result == "ok"
assert captured_timeout == [0.05]
@pytest.mark.asyncio
@pytest.mark.parametrize("timeout_arg", ["request_timeout", "force_timeout"])
async def test_async_timeout_decorator_raises_with_per_call_timeout_message(
monkeypatch: pytest.MonkeyPatch, timeout_arg: str
) -> None:
async def fake_wait_for_timeout(fut, timeout):
fut.close()
raise asyncio.TimeoutError()
monkeypatch.setattr("litellm.timeout.asyncio.wait_for", fake_wait_for_timeout)
@timeout(timeout_duration=5.0)
async def sample_func(**kwargs):
return "ok"
with pytest.raises(Timeout) as exc_info:
await slow_async_func(**kwargs)
await sample_func(**{timeout_arg: 0.05, "model": "test-model"})
elapsed: Final = time.monotonic() - start_time
assert elapsed < 0.3, f"Call waited {elapsed}s instead of respecting {timeout_arg}=0.05"
assert "0.05 second(s)" in str(exc_info.value)
@pytest.mark.asyncio
async def test_async_timeout_decorator_extends_duration_with_per_call_timeout():
"""An async function with a small default timeout must not time out if request_timeout gives more time."""
async def test_async_timeout_decorator_handles_none_force_timeout(monkeypatch: pytest.MonkeyPatch) -> None:
captured_timeout: Final[list[float | None]] = []
@timeout(timeout_duration=0.05)
async def moderately_slow_async_func(**kwargs):
await asyncio.sleep(0.1)
return "completed"
async def fake_wait_for(fut, timeout):
captured_timeout.append(timeout)
return await fut
result = await moderately_slow_async_func(request_timeout=1.0, model="test-model")
assert result == "completed"
monkeypatch.setattr("litellm.timeout.asyncio.wait_for", fake_wait_for)
@timeout(timeout_duration=5.0)
async def sample_func(**kwargs):
return "ok"
await sample_func(force_timeout=None, model="test-model")
assert captured_timeout == [5.0]
@pytest.mark.asyncio
async def test_async_timeout_decorator_handles_none_force_timeout():
"""Passing force_timeout=None should not break timeout_duration fallback."""
async def test_async_timeout_decorator_uses_default_timeout(monkeypatch: pytest.MonkeyPatch) -> None:
captured_timeout: Final[list[float | None]] = []
@timeout(timeout_duration=0.05)
async def slow_async_func(**kwargs):
await asyncio.sleep(0.2)
async def fake_wait_for(fut, timeout):
captured_timeout.append(timeout)
return await fut
monkeypatch.setattr("litellm.timeout.asyncio.wait_for", fake_wait_for)
@timeout(timeout_duration=42.0)
async def sample_func(**kwargs):
return "ok"
with pytest.raises(Timeout) as exc_info:
await slow_async_func(force_timeout=None, model="test-model")
assert "0.05 second(s)" in str(exc_info.value)
await sample_func(model="test-model")
assert captured_timeout == [42.0]
def test_sync_timeout_decorator_respects_per_call_timeout():
"""A sync function decorated with a large timeout must respect a shorter per-call timeout."""
def test_sync_timeout_decorator_runs_without_clock() -> None:
@timeout(timeout_duration=5.0)
def slow_sync_func(**kwargs):
time.sleep(0.5)
return "ok"
def sample_sync_func(**kwargs):
return "sync_ok"
start_time: Final = time.monotonic()
with pytest.raises(Timeout) as exc_info:
slow_sync_func(request_timeout=0.05, model="test-model")
elapsed: Final = time.monotonic() - start_time
assert elapsed < 0.3, f"Call waited {elapsed}s instead of respecting request_timeout=0.05"
assert "0.05 second(s)" in str(exc_info.value)
result: Final = sample_sync_func(request_timeout=0.05, model="test-model")
assert result == "sync_ok"