mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-01 07:03:02 +00:00
* refactor(rust-bridge): detect Python-only features in the catalog instead of Rust declines * refactor(rust-bridge): split and document route-specific detectors --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
58 lines
2.2 KiB
Python
58 lines
2.2 KiB
Python
from typing import Final
|
|
|
|
import pytest
|
|
from pydantic import TypeAdapter
|
|
|
|
import litellm
|
|
from litellm import RateLimitError
|
|
from tests.test_litellm_rust.responses.data import RATE_LIMITED, call
|
|
from tests.test_litellm_rust.support.callback_recorder import RecordingLogger
|
|
from tests.test_litellm_rust.support.recording_server import RecordingServer, ResponseSpec
|
|
|
|
pytestmark = pytest.mark.requires_rust_extension
|
|
|
|
_OBJECT: Final = TypeAdapter(dict[str, object])
|
|
|
|
|
|
def failure_signal(asynchronous: bool) -> str:
|
|
return "async_log_failure_event" if asynchronous else "log_failure_event"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("asynchronous", (False, True))
|
|
async def test_sdk_policy_rejection_precedes_resource_setup_and_is_logged_once(
|
|
server: RecordingServer, monkeypatch: pytest.MonkeyPatch, asynchronous: bool
|
|
) -> None:
|
|
monkeypatch.setattr(litellm, "max_budget", 1.0)
|
|
monkeypatch.setattr(litellm, "_current_cost", 2.0)
|
|
monkeypatch.setattr(litellm, "ssl_verify", object())
|
|
recorder: Final = RecordingLogger()
|
|
server.expected_requests = 0
|
|
|
|
with pytest.raises(litellm.BudgetExceededError) as caught:
|
|
await call(server, asynchronous=asynchronous, callbacks=[recorder])
|
|
|
|
failure: Final = await recorder.wait_for_async(failure_signal(asynchronous))
|
|
assert len(failure) == 1
|
|
assert _OBJECT.validate_python(failure[0].kwargs)["exception"] is caught.value
|
|
assert not server.requests
|
|
assert not any("success" in name for name in recorder.names)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("asynchronous", (False, True))
|
|
async def test_provider_failure_is_terminal_and_shared_with_callbacks(
|
|
server: RecordingServer, asynchronous: bool
|
|
) -> None:
|
|
recorder: Final = RecordingLogger()
|
|
server.enqueue(ResponseSpec(body=RATE_LIMITED, status=429))
|
|
|
|
with pytest.raises(RateLimitError) as caught:
|
|
await call(server, asynchronous=asynchronous, callbacks=[recorder])
|
|
|
|
assert caught.value.status_code == 429
|
|
assert len(server.requests) == 1
|
|
failure: Final = await recorder.wait_for_async(failure_signal(asynchronous))
|
|
assert len(failure) == 1
|
|
assert _OBJECT.validate_python(failure[0].kwargs)["exception"] is caught.value
|
|
assert not any("success" in name for name in recorder.names)
|