Fix broken mocks in 6 flaky tests to prevent real API calls (#19829)

* Fix broken mocks in 6 flaky tests to prevent real API calls

Added network-level HTTP blocking using respx to prevent tests from making real API calls when Python-level mocks fail. This makes tests more reliable and retryable in CI.

Changes:

- Azure OIDC test: Added Azure Identity SDK mock to prevent real Azure calls

- Vector store test: Added @respx.mock decorator to block HTTP requests

- Resend email tests (3): Added @respx.mock decorator for all 3 test functions

- SendGrid email test: Added @respx.mock decorator

All test assertions and verification logic remain unchanged - only added safety nets to catch leaked API calls.

* Fix failing OIDC secret manager tests

Fixed two test failures in test_secret_managers_main.py:

1. test_oidc_azure_ad_token_success: Corrected the patch path for get_bearer_token_provider from 'litellm.secret_managers.get_azure_ad_token_provider.get_bearer_token_provider' to 'azure.identity.get_bearer_token_provider' since the function is imported from azure.identity.

2. test_oidc_google_success: Added @patch('httpx.Client') decorator to prevent any real HTTP connections during test execution, resolving httpx.ConnectError issues.

Both tests now pass successfully.
This commit is contained in:
Alexsander Hamir 2026-01-26 17:39:40 -08:00 • committed by GitHub
parent c442fcd922
commit f95572e3ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 9 deletions

View file

@ -2,7 +2,9 @@ import os
import sys import sys
import unittest.mock as mock import unittest.mock as mock
import httpx
import pytest import pytest
import respx
from httpx import Response from httpx import Response
sys.path.insert(0, os.path.abspath("../../..")) sys.path.insert(0, os.path.abspath("../../.."))
@ -39,7 +41,13 @@ def mock_httpx_client():
@pytest.mark.asyncio @pytest.mark.asyncio
@respx.mock
async def test_send_email_success(mock_env_vars, mock_httpx_client): async def test_send_email_success(mock_env_vars, mock_httpx_client):
# 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"})
)
# Initialize the logger # Initialize the logger
logger = ResendEmailLogger() logger = ResendEmailLogger()
@ -73,7 +81,13 @@ async def test_send_email_success(mock_env_vars, mock_httpx_client):
@pytest.mark.asyncio @pytest.mark.asyncio
@respx.mock
async def test_send_email_missing_api_key(mock_httpx_client): async def test_send_email_missing_api_key(mock_httpx_client):
# 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"})
)
# Remove the API key from environment before initializing logger # Remove the API key from environment before initializing logger
original_key = os.environ.pop("RESEND_API_KEY", None) original_key = os.environ.pop("RESEND_API_KEY", None)
@ -111,7 +125,13 @@ async def test_send_email_missing_api_key(mock_httpx_client):
@pytest.mark.asyncio @pytest.mark.asyncio
@respx.mock
async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client): async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client):
# 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"})
)
# Initialize the logger # Initialize the logger
logger = ResendEmailLogger() logger = ResendEmailLogger()

View file

@ -2,7 +2,9 @@ import os
import sys import sys
import unittest.mock as mock import unittest.mock as mock
import httpx
import pytest import pytest
import respx
from httpx import Response from httpx import Response
sys.path.insert(0, os.path.abspath("../../..")) sys.path.insert(0, os.path.abspath("../../.."))
@ -101,7 +103,13 @@ async def test_send_email_missing_api_key():
@pytest.mark.asyncio @pytest.mark.asyncio
@respx.mock
async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client): async def test_send_email_multiple_recipients(mock_env_vars, mock_httpx_client):
# Block all HTTP requests at network level to prevent real API calls
respx.post("https://api.sendgrid.com/v3/mail/send").mock(
return_value=httpx.Response(202, text="accepted")
)
logger = SendGridEmailLogger() logger = SendGridEmailLogger()
from_email = "test@example.com" from_email = "test@example.com"

View file

@ -48,7 +48,8 @@ def mock_env():
@patch("litellm.secret_managers.main.oidc_cache") @patch("litellm.secret_managers.main.oidc_cache")
@patch("litellm.secret_managers.main._get_oidc_http_handler") @patch("litellm.secret_managers.main._get_oidc_http_handler")
def test_oidc_google_success(mock_get_http_handler, mock_oidc_cache): @patch("httpx.Client") # Prevent any real HTTP connections
def test_oidc_google_success(mock_httpx_client, mock_get_http_handler, mock_oidc_cache):
mock_oidc_cache.get_cache.return_value = None mock_oidc_cache.get_cache.return_value = None
mock_handler = MockHTTPHandler(timeout=600.0) mock_handler = MockHTTPHandler(timeout=600.0)
mock_get_http_handler.return_value = mock_handler mock_get_http_handler.return_value = mock_handler
@ -156,8 +157,14 @@ def test_oidc_azure_ad_token_success(mock_get_azure_ad_token_provider):
if "AZURE_FEDERATED_TOKEN_FILE" in os.environ: if "AZURE_FEDERATED_TOKEN_FILE" in os.environ:
del os.environ["AZURE_FEDERATED_TOKEN_FILE"] del os.environ["AZURE_FEDERATED_TOKEN_FILE"]
# Mock the token provider function that gets returned and called
mock_token_provider = Mock(return_value="azure_ad_token") mock_token_provider = Mock(return_value="azure_ad_token")
mock_get_azure_ad_token_provider.return_value = mock_token_provider mock_get_azure_ad_token_provider.return_value = mock_token_provider
# Also mock the Azure Identity SDK to prevent any real Azure calls
with patch("azure.identity.get_bearer_token_provider") as mock_bearer:
mock_bearer.return_value = mock_token_provider
secret_name = "oidc/azure/api://azure-audience" secret_name = "oidc/azure/api://azure-audience"
result = get_secret(secret_name) result = get_secret(secret_name)

View file

@ -119,8 +119,12 @@ def test_add_vector_store_to_registry():
@respx.mock
def test_search_uses_registry_credentials(): def test_search_uses_registry_credentials():
"""search() should pull credentials from vector_store_registry when available""" """search() should pull credentials from vector_store_registry when available"""
# 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": []}))
vector_store = LiteLLM_ManagedVectorStore( vector_store = LiteLLM_ManagedVectorStore(
vector_store_id="vs1", vector_store_id="vs1",
custom_llm_provider="bedrock", custom_llm_provider="bedrock",