Spaces:
Runtime error
Runtime error
| """OpenAI client concurrency gate and 429 retry behaviour.""" | |
| from __future__ import annotations | |
| import asyncio | |
| from unittest.mock import MagicMock, patch | |
| import pytest | |
| from backend.config import settings | |
| from backend.llm import openai_client | |
| class _RateLimitError(Exception): | |
| status_code = 429 | |
| def test_max_concurrent_llm_calls_respects_settings(monkeypatch): | |
| monkeypatch.setattr(settings, "max_concurrent_llm_calls", 7) | |
| openai_client.reset_client() | |
| assert openai_client.max_concurrent_llm_calls() == 7 | |
| def test_chat_text_retries_on_429(monkeypatch): | |
| monkeypatch.setattr(settings, "openai_rate_limit_max_retries", 2) | |
| monkeypatch.setattr(settings, "openai_rate_limit_backoff_base_seconds", 0.01) | |
| monkeypatch.setattr(settings, "openai_rate_limit_backoff_max_seconds", 0.05) | |
| openai_client.reset_client() | |
| mock_client = MagicMock() | |
| mock_client.chat.completions.create.side_effect = [ | |
| _RateLimitError("rate limited"), | |
| MagicMock(choices=[MagicMock(message=MagicMock(content="ok"))]), | |
| ] | |
| sleeps: list[float] = [] | |
| monkeypatch.setattr(openai_client.time, "sleep", lambda s: sleeps.append(s)) | |
| with patch.object(openai_client, "_get_client", return_value=mock_client), patch.object( | |
| openai_client, "_is_rate_limit_error", return_value=True | |
| ): | |
| out = openai_client.chat_text([{"role": "user", "content": "hi"}]) | |
| assert out == "ok" | |
| assert mock_client.chat.completions.create.call_count == 2 | |
| assert sleeps | |
| def test_chat_text_raises_after_retry_budget_exhausted(monkeypatch): | |
| monkeypatch.setattr(settings, "openai_rate_limit_max_retries", 1) | |
| monkeypatch.setattr(settings, "openai_rate_limit_backoff_base_seconds", 0.01) | |
| openai_client.reset_client() | |
| mock_client = MagicMock() | |
| mock_client.chat.completions.create.side_effect = _RateLimitError("rate limited") | |
| monkeypatch.setattr(openai_client.time, "sleep", lambda _s: None) | |
| with patch.object(openai_client, "_get_client", return_value=mock_client), patch.object( | |
| openai_client, "_is_rate_limit_error", return_value=True | |
| ): | |
| with pytest.raises(_RateLimitError): | |
| openai_client.chat_text([{"role": "user", "content": "hi"}]) | |
| assert mock_client.chat.completions.create.call_count == 2 | |
| def test_thread_semaphore_capacity(monkeypatch): | |
| monkeypatch.setattr(settings, "max_concurrent_llm_calls", 2) | |
| openai_client.reset_client() | |
| sem = openai_client._get_thread_semaphore() | |
| assert sem.acquire(blocking=False) is True | |
| assert sem.acquire(blocking=False) is True | |
| assert sem.acquire(blocking=False) is False | |
| sem.release() | |
| sem.release() | |
| async def test_chat_json_async_sets_gate_held(monkeypatch): | |
| monkeypatch.setattr(settings, "max_concurrent_llm_calls", 3) | |
| openai_client.reset_client() | |
| held: list[bool] = [] | |
| def fake_chat_json(*args, **kwargs): | |
| held.append(bool(kwargs.get("_gate_held"))) | |
| return {"passed": True} | |
| monkeypatch.setattr(openai_client, "chat_json", fake_chat_json) | |
| out = await openai_client.chat_json_async([{"role": "user", "content": "audit"}]) | |
| assert out == {"passed": True} | |
| assert held == [True] | |