mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-12 03:48:56 +00:00
* test: move the unit half of 126 mixed legacy files into tests/unit * test: restore litellm globals that moved tests set * test: finalize migration test cleanup * test: restore original bodies of moved legacy tests The move into tests/unit had rewritten 612 test bodies, and some of the rewrites dropped assertions. Each moved test now carries its original body from the legacy file, with only the imports, helpers, fake provider credentials and monkeypatched env it needs to run under tests/unit test_timeout_streaming goes back to tests/local_testing because it needs the fake OpenAI endpoint server. The image payload fixture moves with its only user, and two tests that leaked global state (a registered model cost entry and queued logging tasks) are now isolated * test: drop module imports shadowed by restored local imports * test: assert on LiteLLM output in no-assertion moved tests and isolate leaks Twenty no-assertion candidates get one assertion on the value LiteLLM returns, with the original lines unchanged. Four tests go back to their legacy files because they only check types or imports, write into the working directory, or cannot assert without a body change Two moved tests leaked globals into later tests in the same worker, so monkeypatch fixtures now restore the retry-after header parser and the end user cost tracking flags * test: drain queued logging tasks before the Phoenix span test The moved Phoenix test counted spans from logging tasks that earlier tests had queued, so the drain fixture moves to tests/unit/conftest.py and both it and the Datadog batch test use it. test_factory_function goes back to its legacy file because its returned wrapper calls the real Assistants API and cannot be asserted on without a body change --------- Co-authored-by: yuneng <yuneng@berri.ai>
251 lines
7.7 KiB
Python
251 lines
7.7 KiB
Python
#### What this tests ####
|
|
# This tests the timeout decorator
|
|
|
|
import os
|
|
|
|
import httpx
|
|
import openai
|
|
import pytest
|
|
|
|
import litellm
|
|
from litellm._uuid import uuid
|
|
from tests.fake_openai_endpoint import FAKE_OPENAI_API_BASE
|
|
|
|
|
|
def test_timeout():
|
|
# this Will Raise a timeout
|
|
litellm.set_verbose = False
|
|
try:
|
|
response = litellm.completion(
|
|
model="gpt-3.5-turbo",
|
|
timeout=0.01,
|
|
messages=[{"role": "user", "content": "hello, write a 20 pg essay"}],
|
|
)
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|
|
except Exception as e:
|
|
pytest.fail(
|
|
f"Did not raise error `openai.APITimeoutError`. Instead raised error type: {type(e)}, Error: {e}"
|
|
)
|
|
|
|
|
|
# test_timeout()
|
|
|
|
|
|
def test_bedrock_timeout():
|
|
# this Will Raise a timeout
|
|
litellm.set_verbose = True
|
|
try:
|
|
response = litellm.completion(
|
|
model="bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
|
timeout=0.01,
|
|
messages=[{"role": "user", "content": "hello, write a 20 pg essay"}],
|
|
)
|
|
pytest.fail("Did not raise error `openai.APITimeoutError`")
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|
|
except Exception as e:
|
|
pytest.fail(
|
|
f"Did not raise error `openai.APITimeoutError`. Instead raised error type: {type(e)}, Error: {e}"
|
|
)
|
|
|
|
|
|
def test_hanging_request_azure():
|
|
"""
|
|
Test that a slow Azure request properly raises APITimeoutError via the Router.
|
|
|
|
Uses a mock to simulate a slow HTTP response so the timeout fires reliably,
|
|
rather than racing against real network latency.
|
|
"""
|
|
litellm.set_verbose = True
|
|
import asyncio
|
|
from unittest.mock import patch
|
|
|
|
try:
|
|
router = litellm.Router(
|
|
model_list=[
|
|
{
|
|
"model_name": "azure-gpt",
|
|
"litellm_params": {
|
|
"model": "azure/gpt-4.1-mini",
|
|
"api_base": os.environ["AZURE_AI_API_BASE"],
|
|
"api_key": os.environ["AZURE_AI_API_KEY"],
|
|
},
|
|
},
|
|
{
|
|
"model_name": "openai-gpt",
|
|
"litellm_params": {"model": "gpt-3.5-turbo"},
|
|
},
|
|
],
|
|
num_retries=0,
|
|
)
|
|
|
|
encoded = litellm.utils.encode(model="gpt-3.5-turbo", text="blue")[0]
|
|
|
|
original_send = httpx.AsyncClient.send
|
|
|
|
async def _slow_send(self, request, *args, **kwargs):
|
|
await asyncio.sleep(5)
|
|
return await original_send(self, request, *args, **kwargs)
|
|
|
|
async def _test():
|
|
with patch.object(httpx.AsyncClient, "send", new=_slow_send):
|
|
response = await router.acompletion(
|
|
model="azure-gpt",
|
|
messages=[
|
|
{
|
|
"role": "user",
|
|
"content": f"what color is red {uuid.uuid4()}",
|
|
}
|
|
],
|
|
logit_bias={encoded: 100},
|
|
timeout=0.01,
|
|
)
|
|
print(response)
|
|
return response
|
|
|
|
response = asyncio.run(_test())
|
|
|
|
if response.choices[0].message.content is not None:
|
|
pytest.fail("Got a response, expected a timeout")
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|
|
except Exception as e:
|
|
pytest.fail(
|
|
f"Did not raise error `openai.APITimeoutError`. Instead raised error type: {type(e)}, Error: {e}"
|
|
)
|
|
|
|
|
|
# test_hanging_request_azure()
|
|
|
|
|
|
def test_hanging_request_openai():
|
|
litellm.set_verbose = True
|
|
try:
|
|
router = litellm.Router(
|
|
model_list=[
|
|
{
|
|
"model_name": "azure-gpt",
|
|
"litellm_params": {
|
|
"model": "azure/gpt-4.1-mini",
|
|
"api_base": os.environ["AZURE_AI_API_BASE"],
|
|
"api_key": os.environ["AZURE_AI_API_KEY"],
|
|
},
|
|
},
|
|
{
|
|
"model_name": "openai-gpt",
|
|
"litellm_params": {"model": "gpt-3.5-turbo"},
|
|
},
|
|
],
|
|
num_retries=0,
|
|
)
|
|
|
|
encoded = litellm.utils.encode(model="gpt-3.5-turbo", text="blue")[0]
|
|
response = router.completion(
|
|
model="openai-gpt",
|
|
messages=[{"role": "user", "content": "what color is red"}],
|
|
logit_bias={encoded: 100},
|
|
timeout=0.01,
|
|
)
|
|
print(response)
|
|
|
|
if response.choices[0].message.content is not None:
|
|
pytest.fail("Got a response, expected a timeout")
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|
|
except Exception as e:
|
|
pytest.fail(
|
|
f"Did not raise error `openai.APITimeoutError`. Instead raised error type: {type(e)}, Error: {e}"
|
|
)
|
|
|
|
|
|
# test_hanging_request_openai()
|
|
|
|
# test_timeout()
|
|
|
|
|
|
def test_timeout_streaming():
|
|
# this Will Raise a timeout
|
|
litellm.set_verbose = False
|
|
try:
|
|
response = litellm.completion(
|
|
model="openai/slow-endpoint",
|
|
messages=[{"role": "user", "content": "hello, write a 20 pg essay"}],
|
|
api_base=FAKE_OPENAI_API_BASE,
|
|
api_key="fake-key",
|
|
timeout=0.5,
|
|
stream=True,
|
|
)
|
|
for chunk in response:
|
|
print(chunk)
|
|
pytest.fail("Did not raise error `openai.APITimeoutError`. The stream completed instead")
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|
|
except Exception as e:
|
|
pytest.fail(
|
|
f"Did not raise error `openai.APITimeoutError`. Instead raised error type: {type(e)}, Error: {e}"
|
|
)
|
|
|
|
|
|
# test_timeout_streaming()
|
|
|
|
|
|
|
|
|
|
# test_timeout_ollama()
|
|
|
|
|
|
@pytest.mark.parametrize("streaming", [True, False])
|
|
@pytest.mark.parametrize("sync_mode", [True, False])
|
|
@pytest.mark.asyncio
|
|
async def test_anthropic_timeout(streaming, sync_mode):
|
|
litellm.set_verbose = False
|
|
|
|
try:
|
|
if sync_mode:
|
|
response = litellm.completion(
|
|
model="claude-sonnet-4-5-20250929",
|
|
timeout=0.01,
|
|
messages=[{"role": "user", "content": "hello, write a 20 pg essay"}],
|
|
stream=streaming,
|
|
)
|
|
if isinstance(response, litellm.CustomStreamWrapper):
|
|
for chunk in response:
|
|
pass
|
|
else:
|
|
response = await litellm.acompletion(
|
|
model="claude-sonnet-4-5-20250929",
|
|
timeout=0.01,
|
|
messages=[{"role": "user", "content": "hello, write a 20 pg essay"}],
|
|
stream=streaming,
|
|
)
|
|
if isinstance(response, litellm.CustomStreamWrapper):
|
|
async for chunk in response:
|
|
pass
|
|
pytest.fail("Did not raise error `openai.APITimeoutError`")
|
|
except openai.APITimeoutError as e:
|
|
print(
|
|
"Passed: Raised correct exception. Got openai.APITimeoutError\nGood Job", e
|
|
)
|
|
print(type(e))
|
|
pass
|