fix(test): replace live httpbin.org call with mocked transport in test_pass_through_with_httpbin_redirect

Root cause of OOM: the test made a real HTTP request to https://httpbin.org
inside a pytest-xdist worker. Under memory pressure the worker's httpx client
and redirect-following logic allocated enough virtual memory to trip the OOM
killer (confirmed by ulimit -v 16GB reproducing the crash with 'node down: Not
properly terminated' on this exact test).

Fix: replace the real network call with a custom httpx.AsyncBaseTransport that
returns a pre-built 302 -> 200 response sequence in-memory. The test now runs
hermetically with no network dependency and no excess memory allocation.

ulimit -v 16GB: 24,284 passed (0 crashes) after this fix.
This commit is contained in:
Yaniv Israel 2026-06-21 17:02:18 +03:00
parent 3cdb964e21
commit add0ff19d3

View file

@ -2198,10 +2198,11 @@ async def test_pass_through_request_query_params_forwarding():
@pytest.mark.asyncio
async def test_pass_through_with_httpbin_redirect():
"""
Integration test using httpbin.org redirect endpoint to test real redirect handling.
This tests the actual redirect handling capability end-to-end using the full pass_through_request function.
Tests redirect handling in pass_through_request using a mocked HTTP transport.
The mock simulates: GET /redirect/1 -> 302 Location: /get -> 200 {url: ...}
No real network calls are made.
"""
from unittest.mock import MagicMock
import json
from fastapi import Request
from starlette.datastructures import Headers, QueryParams
@ -2210,24 +2211,50 @@ async def test_pass_through_with_httpbin_redirect():
pass_through_request,
)
# Create mock request
# Build the two responses the mock transport will return in order:
# 1. 302 redirect from /redirect/1 -> /get
redirect_response = httpx.Response(
status_code=302,
headers={"location": "https://httpbin.org/get"},
content=b"",
request=httpx.Request("GET", "https://httpbin.org/redirect/1"),
)
# 2. 200 final response from /get
final_body = json.dumps({"url": "https://httpbin.org/get"}).encode()
final_response = httpx.Response(
status_code=200,
headers={"content-type": "application/json"},
content=final_body,
request=httpx.Request("GET", "https://httpbin.org/get"),
)
responses = iter([redirect_response, final_response])
class _MockTransport(httpx.AsyncBaseTransport):
async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
return next(responses)
# pass_through_request accesses get_async_httpx_client(...).client, so the
# mock must expose a .client attribute wrapping our transport.
mock_handler = MagicMock()
mock_handler.client = httpx.AsyncClient(transport=_MockTransport(), follow_redirects=True)
# Create mock FastAPI request
mock_request = MagicMock(spec=Request)
mock_request.method = "GET"
mock_request.headers = Headers({})
mock_request.query_params = QueryParams("")
# Mock the body method to return empty bytes for GET request
async def mock_body():
return b""
mock_request.body = mock_body
# Mock user API key dict
mock_user_api_key_dict = MagicMock()
try:
# Test with httpbin.org redirect endpoint
# This will redirect to httpbin.org/get
with patch(
"litellm.proxy.pass_through_endpoints.pass_through_endpoints.get_async_httpx_client",
return_value=mock_handler,
):
response = await pass_through_request(
request=mock_request,
target="https://httpbin.org/redirect/1",
@ -2235,19 +2262,9 @@ async def test_pass_through_with_httpbin_redirect():
user_api_key_dict=mock_user_api_key_dict,
)
# Should get the final response (200) from /get endpoint, not the redirect (302)
assert response.status_code == 200
# The response should be from the /get endpoint
response_content = bytes(response.body).decode("utf-8")
# httpbin.org/get returns JSON with info about the request
assert '"url": "https://httpbin.org/get"' in response_content
except Exception as e:
# If httpbin.org is not accessible, skip the test
import pytest
pytest.skip(f"Could not reach httpbin.org for integration test: {e}")
assert response.status_code == 200
response_content = bytes(response.body).decode("utf-8")
assert '"url": "https://httpbin.org/get"' in response_content
@pytest.mark.asyncio