litellm/tests/unit/proxy/test_chat_completion_metadata.py
Mateo Wang 58258409c9
refactor(proxy): expose public names for private proxy helpers (#45170)
* refactor(proxy): expose public names for private proxy helpers

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep original class names behind public aliases

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): preserve internal callback filtering

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep _PROXY_ class names for managed files hooks

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep old private names in package exports

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): preserve recursive auth helper name

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): align MCP limiter tests with server enforcement

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): match main's MCP limiter tests

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep old private names bound in importing modules

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): preserve compatibility imports through strict lint

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): use exact pyright suppression in password helper test

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* style(proxy): add reasons to compatibility import noqa comments

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(proxy): update IN-list baseline for renamed helpers

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-07 18:59:27 -07:00

128 lines
5.5 KiB
Python

import pytest
from unittest.mock import MagicMock, AsyncMock, patch
from litellm.proxy.proxy_server import chat_completion, completion, embeddings
from litellm.proxy._types import UserAPIKeyAuth
from fastapi import Request, Response
@pytest.mark.asyncio
async def test_chat_completion_metadata_population():
# Setup
request = MagicMock(spec=Request)
# Mock _read_request_body to return a dict
with patch("litellm.proxy.proxy_server.read_request_body", new_callable=AsyncMock) as mock_read_body:
mock_read_body.return_value = {"model": "gpt-3.5-turbo", "messages": []}
user_api_key_dict = UserAPIKeyAuth(user_id="test_user_id", team_id="test_team_id", org_id="test_org_id")
fastapi_response = MagicMock(spec=Response)
# Mock ProxyBaseLLMRequestProcessing
with patch("litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing") as MockProcessor:
mock_instance = MockProcessor.return_value
mock_instance.base_process_llm_request = AsyncMock(return_value={"choices": []})
# Execute
await chat_completion(
request=request,
fastapi_response=fastapi_response,
user_api_key_dict=user_api_key_dict,
)
# Verify
# Check if ProxyBaseLLMRequestProcessing was initialized with data containing metadata
call_args = MockProcessor.call_args
assert call_args is not None
data_arg = call_args.kwargs.get("data")
assert data_arg is not None
assert "metadata" in data_arg
assert data_arg["metadata"]["user_api_key_user_id"] == "test_user_id"
assert data_arg["metadata"]["user_api_key_team_id"] == "test_team_id"
assert data_arg["metadata"]["user_api_key_org_id"] == "test_org_id"
@pytest.mark.asyncio
async def test_embedding_metadata_population():
"""
Test that the embedding endpoint correctly populates metadata
from UserAPIKeyAuth.
"""
# Setup
with patch("litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing.base_process_llm_request"):
with patch(
"litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing.__init__",
return_value=None,
) as mock_base_process_init:
# Create a mock UserAPIKeyAuth object
mock_user_auth = MagicMock(spec=UserAPIKeyAuth)
mock_user_auth.user_id = "test_user_id_emb"
mock_user_auth.team_id = "test_team_id_emb"
mock_user_auth.org_id = "test_org_id_emb"
# Create a mock Request object
mock_request = MagicMock(spec=Request)
mock_request.json = AsyncMock(return_value={"model": "gpt-3.5-turbo", "input": "hello"})
# Mock _read_request_body to return our data
with patch(
"litellm.proxy.proxy_server.read_request_body",
new=AsyncMock(return_value={"model": "gpt-3.5-turbo", "input": "hello"}),
):
# Call the endpoint function directly
await embeddings(
request=mock_request,
fastapi_response=MagicMock(spec=Response),
user_api_key_dict=mock_user_auth,
)
# Check if ProxyBaseLLMRequestProcessing was initialized with the correct metadata
mock_base_process_init.assert_called_once()
call_args = mock_base_process_init.call_args
# handle both positional and keyword args for data
if "data" in call_args.kwargs:
data_arg = call_args.kwargs["data"]
else:
data_arg = call_args.args[0]
assert data_arg["metadata"]["user_api_key_user_id"] == "test_user_id_emb"
assert data_arg["metadata"]["user_api_key_team_id"] == "test_team_id_emb"
assert data_arg["metadata"]["user_api_key_org_id"] == "test_org_id_emb"
@pytest.mark.asyncio
async def test_completion_metadata_population():
# Setup
request = MagicMock(spec=Request)
# Mock _read_request_body to return a dict
with patch("litellm.proxy.proxy_server.read_request_body", new_callable=AsyncMock) as mock_read_body:
mock_read_body.return_value = {
"model": "gpt-3.5-turbo-instruct",
"prompt": "test",
}
user_api_key_dict = UserAPIKeyAuth(user_id="test_user_id_2", team_id="test_team_id_2", org_id="test_org_id_2")
fastapi_response = MagicMock(spec=Response)
# Mock ProxyBaseLLMRequestProcessing
with patch("litellm.proxy.proxy_server.ProxyBaseLLMRequestProcessing") as MockProcessor:
mock_instance = MockProcessor.return_value
mock_instance.base_process_llm_request = AsyncMock(return_value={"choices": []})
# Execute
await completion(
request=request,
fastapi_response=fastapi_response,
user_api_key_dict=user_api_key_dict,
)
# Verify
call_args = MockProcessor.call_args
assert call_args is not None
data_arg = call_args.kwargs.get("data")
assert data_arg is not None
assert "metadata" in data_arg
assert data_arg["metadata"]["user_api_key_user_id"] == "test_user_id_2"
assert data_arg["metadata"]["user_api_key_team_id"] == "test_team_id_2"
assert data_arg["metadata"]["user_api_key_org_id"] == "test_org_id_2"