litellm/tests/local_testing/test_http_parsing_utils.py
yuneng-jiang c168199e33
test(ci): repair stale tests and move retired OpenAI text-completion fixtures (#43958)
* 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
2026-09-30 19:19:59 -07:00

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 == {}