mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-02 02:11:58 +00:00
* test(ci): repair stale request fakes, spend-log golden, auto-router labels, and Interactions spec lookups Request fakes now carry the scope a real Starlette request has, the GCS pub/sub spend-log golden gains the agent identity keys from #43722, the auto-router session tests follow the baseline_models contract from #43348, and the Interactions spec checks resolve the create body and resource paths from the live spec instead of hardcoded names * test(ci): move retired OpenAI text-completion fixtures to live vehicles OpenAI still serves native /v1/completions on the gpt-5.4 family, so the single-prompt cases move to text-completion-openai/gpt-5.4-nano. Multi-prompt batches and echo with logprobs now 500 on every OpenAI model, so those cases keep the same text-completion-openai transport pointed at Fireworks, which documents both. The optional-params test asserts the request body actually sent instead of a success callback whose assertions were swallowed * test(ci): use a serverless Fireworks model for the text-completion batch and echo cases gpt-oss-20b is on-demand only on Fireworks, so the CI key got 404 model not deployed; glm-5p3-flash is listed as serverless * test(ci): skip the ROI calculator repository listing in the security route sweep GET /roi-calculator/repositories (#43669) lists repositories from the configured GitHub API, api.github.com by default, so the S2 sweep's GET of every route made the owned proxy reach an external host and failed the egress check in 31 integration-security tests. It joins /get/latest_release_info in the deny list
61 lines
1.7 KiB
Python
61 lines
1.7 KiB
Python
from collections.abc import Awaitable, Callable
|
|
|
|
import pytest
|
|
from fastapi import Request
|
|
from starlette.types import Message
|
|
|
|
from litellm.proxy._types import ProxyException
|
|
from litellm.proxy.common_utils.http_parsing_utils import _read_request_body
|
|
|
|
|
|
def _request(receive: Callable[[], Awaitable[Message]]) -> Request:
|
|
return Request(
|
|
{
|
|
"type": "http",
|
|
"method": "POST",
|
|
"path": "/v1/chat/completions",
|
|
"headers": [(b"content-type", b"application/json")],
|
|
},
|
|
receive,
|
|
)
|
|
|
|
|
|
def _request_with_body(body: bytes) -> Request:
|
|
async def receive() -> Message:
|
|
return {"type": "http.request", "body": body, "more_body": False}
|
|
|
|
return _request(receive)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_request_body_valid_json():
|
|
result = await _read_request_body(_request_with_body(b'{"key": "value"}'))
|
|
assert result == {"key": "value"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_request_body_empty_body():
|
|
result = await _read_request_body(_request_with_body(b""))
|
|
assert result == {}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_request_body_invalid_json():
|
|
with pytest.raises(ProxyException):
|
|
await _read_request_body(_request_with_body(b'{"key": value}'))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_request_body_large_payload():
|
|
large_payload = '{"key":' + '"a"' * 10**6 + "}"
|
|
with pytest.raises(ProxyException):
|
|
await _read_request_body(_request_with_body(large_payload.encode()))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_read_request_body_unexpected_error():
|
|
async def receive() -> Message:
|
|
raise ValueError("Unexpected error")
|
|
|
|
result = await _read_request_body(_request(receive))
|
|
assert result == {}
|