litellm_fix_mapped_tests_core: fix test isolation and mock injection issues

## Problem
Four tests in litellm_mapped_tests_core were failing:
1. test_register_model_with_scientific_notation - KeyError due to test isolation issues
2. test_search_uses_registry_credentials - Mock not being called due to incorrect patch path
3. test_send_email_missing_api_key - Real API calls despite mocking
4. test_stream_transformation_error_sync - Mock not effective, real API called

## Solution

### test_register_model_with_scientific_notation
- Use unique model name to avoid conflicts with other tests
- Clear LRU caches before test to prevent stale data
- Clean up model_cost entry after test

### test_search_uses_registry_credentials
- Use patch.object() on the actual base_llm_http_handler instance
- String-based patching for instance methods can fail; direct object patching is more reliable

### test_send_email_missing_api_key
- Directly inject mock HTTP client into logger instance
- This bypasses any caching issues that could cause the fixture mock to be ineffective

### test_stream_transformation_error_sync
- Patch litellm.completion directly instead of the handler module's litellm reference
- This ensures the mock is effective regardless of import order

## Regression
These tests were affected by LRU caching added in #19606 and HTTP client caching.
This commit is contained in:
shin-bot-litellm 2026-02-01 00:28:24 +00:00
parent ecb725f189
commit 9ddcdbcaf7
4 changed files with 37 additions and 14 deletions

View file

@ -98,7 +98,7 @@ async def test_send_email_success(mock_env_vars, mock_httpx_client):
@pytest.mark.asyncio
@respx.mock
async def test_send_email_missing_api_key(mock_httpx_client):
async def test_send_email_missing_api_key():
# Block all HTTP requests at network level to prevent real API calls
respx.post("https://api.resend.com/emails").mock(
return_value=httpx.Response(200, json={"id": "test_email_id"})
@ -117,13 +117,18 @@ async def test_send_email_missing_api_key(mock_httpx_client):
subject = "Test Subject"
html_body = "<p>Test email body</p>"
# Mock the response to avoid making real HTTP requests
# Create mock HTTP client and inject it directly into the logger
# This ensures the mock is used regardless of any caching issues
mock_response = mock.Mock(spec=Response)
mock_response.raise_for_status.return_value = None
mock_response.status_code = 200
mock_response.json.return_value = {"id": "test_email_id"}
mock_httpx_client.post.return_value = mock_response
mock_async_client = mock.AsyncMock()
mock_async_client.post.return_value = mock_response
# Directly inject the mock client to bypass any caching
logger.async_httpx_client = mock_async_client
# Send email
await logger.send_email(
@ -131,8 +136,8 @@ async def test_send_email_missing_api_key(mock_httpx_client):
)
# Verify the HTTP client was called with None as the API key
mock_httpx_client.post.assert_called_once()
call_args = mock_httpx_client.post.call_args
mock_async_client.post.assert_called_once()
call_args = mock_async_client.post.call_args
assert call_args[1]["headers"] == {"Authorization": "Bearer None"}
finally:
# Restore the original key if it existed

View file

@ -183,10 +183,8 @@ def test_stream_transformation_error_sync():
"translate_completion_output_params_streaming",
return_value=None
):
# Mock litellm.completion at the module level where it's imported
# We need to patch it in the handler module, not in litellm itself
with patch("litellm.google_genai.adapters.handler.litellm") as mock_litellm:
mock_litellm.completion.return_value = mock_stream
# Patch litellm.completion directly to prevent real API calls
with patch("litellm.completion", return_value=mock_stream):
# Call the handler with stream=True and expect a ValueError
with pytest.raises(ValueError, match="Failed to transform streaming response"):
GenerateContentToCompletionHandler.generate_content_handler(

View file

@ -2282,8 +2282,19 @@ def test_register_model_with_scientific_notation():
"""
Test that the register_model function can handle scientific notation in the model name.
"""
# Use a unique model name to avoid conflicts with other tests
test_model_name = "test-scientific-notation-model-unique-12345"
# Clean up any pre-existing entry and clear caches
if test_model_name in litellm.model_cost:
del litellm.model_cost[test_model_name]
# Clear LRU caches that might have stale data
from litellm.utils import get_model_info, _cached_get_model_info_helper, _invalidate_model_cost_lowercase_map
_invalidate_model_cost_lowercase_map()
model_cost_dict = {
"my-custom-model": {
test_model_name: {
"max_tokens": 8192,
"input_cost_per_token": "3e-07",
"output_cost_per_token": "6e-07",
@ -2294,12 +2305,17 @@ def test_register_model_with_scientific_notation():
litellm.register_model(model_cost_dict)
registered_model = litellm.model_cost["my-custom-model"]
registered_model = litellm.model_cost[test_model_name]
print(registered_model)
assert registered_model["input_cost_per_token"] == 3e-07
assert registered_model["output_cost_per_token"] == 6e-07
assert registered_model["litellm_provider"] == "openai"
assert registered_model["mode"] == "chat"
# Clean up after test
if test_model_name in litellm.model_cost:
del litellm.model_cost[test_model_name]
_invalidate_model_cost_lowercase_map()
def test_reasoning_content_preserved_in_text_completion_wrapper():

View file

@ -136,6 +136,9 @@ def test_add_vector_store_to_registry():
@respx.mock
def test_search_uses_registry_credentials():
"""search() should pull credentials from vector_store_registry when available"""
# Import the actual instance to patch it correctly
from litellm.vector_stores.main import base_llm_http_handler
# Block all HTTP requests at the network level to prevent real API calls
respx.route().mock(return_value=httpx.Response(200, json={"object": "list", "data": []}))
@ -168,8 +171,9 @@ def test_search_uses_registry_credentials():
) as mock_get_creds, patch(
"litellm.vector_stores.main.ProviderConfigManager.get_provider_vector_stores_config",
return_value=MagicMock(),
), patch(
"litellm.vector_stores.main.base_llm_http_handler.vector_store_search_handler",
), patch.object(
base_llm_http_handler,
"vector_store_search_handler",
return_value=mock_search_response,
) as mock_handler:
search(vector_store_id="vs1", query="test", litellm_logging_obj=logger)