mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-29 01:42:19 +00:00
test: expose replica_db on remaining PrismaClient test doubles
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
ebf89e4ae6
commit
0ae887c1e7
113 changed files with 781 additions and 9 deletions
|
|
@ -340,6 +340,7 @@ async def test_get_invitation_link(base_email_logger):
|
|||
return [mock_invitation_row]
|
||||
|
||||
mock_prisma.db.litellm_invitationlink.find_many = mock_find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
with mock.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma):
|
||||
# Test with valid user_id
|
||||
|
|
@ -361,6 +362,7 @@ async def test_get_invitation_link(base_email_logger):
|
|||
return []
|
||||
|
||||
mock_prisma.db.litellm_invitationlink.find_many = mock_find_many_empty
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
result = await base_email_logger._get_invitation_link(
|
||||
user_id="test-user", base_url="http://test.com"
|
||||
)
|
||||
|
|
@ -386,6 +388,7 @@ async def test_get_invitation_link_creates_new_when_none_exist(base_email_logger
|
|||
return []
|
||||
|
||||
mock_prisma.db.litellm_invitationlink.find_many = mock_find_many_empty
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock the create_invitation_for_user function
|
||||
mock_created_invitation = mock.MagicMock()
|
||||
|
|
@ -428,6 +431,7 @@ async def test_get_invitation_link_uses_existing_when_available(base_email_logge
|
|||
return [mock_invitation_row]
|
||||
|
||||
mock_prisma.db.litellm_invitationlink.find_many = mock_find_many_existing
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
with mock.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma):
|
||||
with mock.patch(
|
||||
|
|
@ -459,6 +463,7 @@ async def test_get_invitation_link_creates_new_when_list_is_none(base_email_logg
|
|||
return None
|
||||
|
||||
mock_prisma.db.litellm_invitationlink.find_many = mock_find_many_none
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock the create_invitation_for_user function
|
||||
mock_created_invitation = mock.MagicMock()
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ def mock_prisma_client():
|
|||
|
||||
mock_db.litellm_config = mock_config
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
|
||||
return mock_client
|
||||
|
||||
|
|
@ -65,6 +66,7 @@ async def test_get_email_settings_empty_db(mock_prisma_client):
|
|||
return None
|
||||
|
||||
mock_prisma_client.db.litellm_config.find_unique = mock_find_unique
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Call the function
|
||||
result = await _get_email_settings(mock_prisma_client)
|
||||
|
|
@ -91,6 +93,7 @@ async def test_get_email_settings_with_existing_settings(mock_prisma_client):
|
|||
return mock_entry
|
||||
|
||||
mock_prisma_client.db.litellm_config.find_unique = mock_find_unique
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Call the function
|
||||
result = await _get_email_settings(mock_prisma_client)
|
||||
|
|
@ -109,12 +112,14 @@ async def test_save_email_settings_new_entry(mock_prisma_client):
|
|||
return None
|
||||
|
||||
mock_prisma_client.db.litellm_config.find_unique = mock_find_unique
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Setup mock upsert to return None
|
||||
async def mock_upsert(*args, **kwargs):
|
||||
return None
|
||||
|
||||
mock_prisma_client.db.litellm_config.upsert = mock_upsert
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Settings to save
|
||||
settings = {
|
||||
|
|
@ -273,6 +278,7 @@ def _prisma_recording_upserts(upserts):
|
|||
return None
|
||||
|
||||
client.db.litellm_config.find_unique = find_unique
|
||||
client.replica_db = client.db
|
||||
client.db.litellm_config.upsert = upsert
|
||||
return client
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ async def test_should_resolve_raw_input_file_id_to_unified():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_managedobjecttable.find_first = AsyncMock(return_value=mock_db_object)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(return_value=mock_managed_file)
|
||||
|
||||
from litellm.proxy.openai_files_endpoints.common_utils import get_batch_from_database
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ def _build_managed_files_mock(unified_id: str = "file-bWFuYWdlZF9vdXRwdXRfaWQ=")
|
|||
def _build_prisma_mock():
|
||||
mock = MagicMock()
|
||||
mock.db.litellm_managedfiletable.find_first = AsyncMock(return_value=None)
|
||||
mock.replica_db = mock.db
|
||||
return mock
|
||||
|
||||
|
||||
|
|
@ -134,6 +135,7 @@ async def test_get_batch_from_database_registers_missing_output_file_id():
|
|||
prisma.db.litellm_managedobjecttable.find_first = AsyncMock(
|
||||
return_value=batch_db_record
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_managedfiletable.find_first = AsyncMock(return_value=None)
|
||||
|
||||
mock_managed_files = _build_managed_files_mock(unified_id=unified_output_file_id)
|
||||
|
|
@ -188,6 +190,7 @@ async def test_registered_output_file_row_denies_cross_user_access():
|
|||
raw_output_file_id = "file-raw-output"
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_managedfiletable.upsert = AsyncMock()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_managedfiletable.find_first = AsyncMock(return_value=None)
|
||||
managed_files = _PROXY_LiteLLMManagedFiles(
|
||||
internal_usage_cache=MagicMock(),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ def _mock_prisma(batch_json: str, managed_file_record=None):
|
|||
prisma.db.litellm_managedobjecttable.find_first = AsyncMock(
|
||||
return_value=batch_db_record
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
prisma.db.litellm_managedfiletable.find_first = AsyncMock(
|
||||
return_value=managed_file_record
|
||||
|
|
@ -81,6 +82,7 @@ async def test_should_resolve_raw_input_file_id_to_unified_id():
|
|||
prisma.db.litellm_managedfiletable.find_first.assert_any_call(
|
||||
where={"flat_model_file_ids": {"has": raw_input_file_id}}
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_managedfiletable.find_first.assert_any_call(
|
||||
where={"flat_model_file_ids": {"has": "file-output-raw"}}
|
||||
)
|
||||
|
|
@ -125,3 +127,4 @@ async def test_should_preserve_already_managed_input_file_id():
|
|||
)
|
||||
|
||||
prisma.db.litellm_managedfiletable.find_first.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ def _make_managed_files_with_no_db_record():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
return _PROXY_LiteLLMManagedFiles(
|
||||
internal_usage_cache=MagicMock(),
|
||||
|
|
@ -76,6 +77,7 @@ async def test_should_allow_owner_access_when_record_exists():
|
|||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
managed_files = _PROXY_LiteLLMManagedFiles(
|
||||
internal_usage_cache=MagicMock(),
|
||||
|
|
@ -105,6 +107,7 @@ async def test_should_block_different_user_when_record_exists():
|
|||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
managed_files = _PROXY_LiteLLMManagedFiles(
|
||||
internal_usage_cache=MagicMock(),
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ def _make_managed_files_instance_with_batches(
|
|||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(
|
||||
return_value=mock_file_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_managedfiletable.delete = AsyncMock(
|
||||
return_value=mock_file_record
|
||||
)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ def _make_managed_files_instance(
|
|||
mock_prisma.db.litellm_managedfiletable.find_first = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
instance = _PROXY_LiteLLMManagedFiles(
|
||||
internal_usage_cache=MagicMock(),
|
||||
|
|
@ -189,6 +190,7 @@ def _make_managed_files_instance_with_object_store():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_managedobjecttable.upsert = AsyncMock(side_effect=upsert)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_managedobjecttable.find_first = AsyncMock(
|
||||
side_effect=find_first
|
||||
)
|
||||
|
|
@ -296,6 +298,7 @@ async def test_check_batch_cost_should_call_afile_content_directly_with_credenti
|
|||
mock_prisma.db.litellm_managedobjecttable.find_many = AsyncMock(
|
||||
return_value=[mock_job]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_managedobjecttable.update = AsyncMock()
|
||||
mock_prisma.db.litellm_managedobjecttable.update_many = AsyncMock(return_value=1)
|
||||
|
||||
|
|
|
|||
|
|
@ -993,6 +993,7 @@ class TestMCPRequestHandler:
|
|||
# Test case: None values in database
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique.return_value = None
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_teamtable.find_unique.return_value = None
|
||||
|
||||
user_api_key_auth = UserAPIKeyAuth(
|
||||
|
|
@ -4589,6 +4590,7 @@ class TestAgentMCPPermissions:
|
|||
agent_row.object_permission_id = "perm-xyz"
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(return_value=agent_row)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
user_api_key_auth = UserAPIKeyAuth(
|
||||
api_key="test-key",
|
||||
user_id="test-user",
|
||||
|
|
@ -4627,6 +4629,7 @@ class TestAgentMCPPermissions:
|
|||
agent_row.object_permission_id = None
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(return_value=agent_row)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
user_api_key_auth = UserAPIKeyAuth(
|
||||
api_key="test-key",
|
||||
user_id="test-user",
|
||||
|
|
@ -9421,6 +9424,7 @@ class TestGetUserObjectPermission:
|
|||
def _prisma_with_user(self, user_row):
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_usertable.find_unique = AsyncMock(return_value=user_row)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
return prisma_client
|
||||
|
||||
async def test_resolves_through_the_shared_permission_cache(self):
|
||||
|
|
@ -9447,6 +9451,7 @@ class TestGetUserObjectPermission:
|
|||
|
||||
# The user_id -> object_permission_id link is cached, so the user row is read once.
|
||||
prisma_client.db.litellm_usertable.find_unique.reset_mock()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
await MCPRequestHandler._get_user_object_permission(auth)
|
||||
prisma_client.db.litellm_usertable.find_unique.assert_not_called()
|
||||
|
||||
|
|
@ -9469,6 +9474,7 @@ class TestGetUserObjectPermission:
|
|||
assert await MCPRequestHandler._get_user_object_permission(auth) is None
|
||||
mock_get_perm.assert_not_awaited()
|
||||
prisma_client.db.litellm_usertable.find_unique.assert_awaited_once()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
async def test_missing_user_row_places_no_ceiling(self):
|
||||
"""Whether this human is entitled at all is unknown when their row is absent, which is the
|
||||
|
|
@ -9490,6 +9496,7 @@ class TestGetUserObjectPermission:
|
|||
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_usertable.find_unique = AsyncMock(side_effect=Exception("db down"))
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
auth = UserAPIKeyAuth(api_key="sk-test", user_id="human-db-down")
|
||||
|
||||
with (
|
||||
|
|
@ -9551,6 +9558,7 @@ def _agent_prisma(object_permission_id=None, side_effect=None):
|
|||
return_value=MagicMock(object_permission_id=object_permission_id),
|
||||
side_effect=side_effect,
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
return prisma_client
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -633,6 +633,7 @@ async def test_execute_byok_tool_missing_credential_advertises_api_key_flow(monk
|
|||
server = MCPServer(server_id="byok-discovery", name="byok-discovery", transport=MCPTransport.http, is_byok=True)
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_mcpusercredentials.find_unique = AsyncMock(return_value=None)
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma)
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await mcp_operations.execute_mcp_tool(
|
||||
|
|
|
|||
|
|
@ -790,6 +790,7 @@ async def test_load_user_env_vars_force_refresh_bypasses_cache(
|
|||
prisma.db.litellm_mcpuserenvvars.find_unique = AsyncMock(
|
||||
side_effect=[old_row, new_row]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma)
|
||||
|
||||
manager = MCPServerManager()
|
||||
|
|
@ -836,6 +837,7 @@ async def test_load_user_env_vars_invalidation_forces_refetch(
|
|||
prisma.db.litellm_mcpuserenvvars.find_unique = AsyncMock(
|
||||
side_effect=[old_row, new_row]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma)
|
||||
|
||||
manager = MCPServerManager()
|
||||
|
|
@ -870,6 +872,7 @@ def _mock_env_vars_prisma(row=None):
|
|||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_mcpuserenvvars.find_unique = AsyncMock(return_value=row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_mcpuserenvvars.find_many = AsyncMock(return_value=[])
|
||||
prisma.db.litellm_mcpuserenvvars.upsert = AsyncMock()
|
||||
prisma.db.litellm_mcpuserenvvars.delete_many = AsyncMock()
|
||||
|
|
@ -965,6 +968,7 @@ def _transactional_env_vars_prisma(read_delay: float = 0.0):
|
|||
class _Prisma:
|
||||
def __init__(self, delay):
|
||||
self.db = _DB(_Store(), delay)
|
||||
self.replica_db = self.db
|
||||
|
||||
return _Prisma(read_delay)
|
||||
|
||||
|
|
@ -1057,6 +1061,7 @@ async def test_get_user_env_vars_bulk_distributes_results(env_vars_salt_key):
|
|||
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpuserenvvars.find_many = AsyncMock(return_value=[row1, row2])
|
||||
prisma.replica_db = prisma.db
|
||||
result = await get_user_env_vars_bulk(prisma, "alice", ["srv-1", "srv-2", "srv-3"])
|
||||
assert result == {"srv-1": {"A": "1"}, "srv-2": {"B": "2"}}
|
||||
|
||||
|
|
@ -1080,6 +1085,7 @@ async def test_delete_user_env_vars_is_idempotent_delete_many():
|
|||
prisma = _mock_env_vars_prisma()
|
||||
await delete_user_env_vars(prisma, "alice", "srv-1")
|
||||
prisma.db.litellm_mcpuserenvvars.delete_many.assert_awaited_once()
|
||||
prisma.replica_db = prisma.db
|
||||
call = prisma.db.litellm_mcpuserenvvars.delete_many.call_args
|
||||
assert call.kwargs["where"] == {"user_id": "alice", "server_id": "srv-1"}
|
||||
|
||||
|
|
@ -1187,6 +1193,7 @@ async def test_merge_user_env_vars_acquires_lock_without_deserializing_void(
|
|||
tx = _Tx()
|
||||
prisma = MagicMock()
|
||||
prisma.db.tx = MagicMock(return_value=tx)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
values = {"CORP_TOKEN": "t0ken"}
|
||||
merged = await merge_user_env_vars(
|
||||
|
|
@ -1207,6 +1214,7 @@ async def test_delete_mcp_server_removes_orphaned_user_env_vars():
|
|||
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=object())
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
await delete_mcp_server(prisma, "srv-1")
|
||||
|
||||
|
|
@ -1224,6 +1232,7 @@ async def test_delete_mcp_server_skips_env_var_cleanup_when_server_missing():
|
|||
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=None)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await delete_mcp_server(prisma, "srv-1")
|
||||
|
||||
|
|
@ -1244,6 +1253,7 @@ async def test_delete_mcp_server_succeeds_when_orphan_cleanup_fails():
|
|||
deleted = object()
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=deleted)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_mcpuserenvvars.delete_many = AsyncMock(
|
||||
side_effect=Exception("connection pool exhausted")
|
||||
)
|
||||
|
|
@ -1265,6 +1275,7 @@ async def test_delete_mcp_server_removes_orphaned_user_credentials():
|
|||
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=object())
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
await delete_mcp_server(prisma, "srv-1")
|
||||
|
||||
|
|
@ -1282,6 +1293,7 @@ async def test_delete_mcp_server_skips_credential_cleanup_when_server_missing():
|
|||
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=None)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await delete_mcp_server(prisma, "srv-1")
|
||||
|
||||
|
|
@ -1301,6 +1313,7 @@ async def test_delete_mcp_server_credential_cleanup_failure_still_cleans_env_var
|
|||
deleted = object()
|
||||
prisma = _mock_env_vars_prisma()
|
||||
prisma.db.litellm_mcpservertable.delete = AsyncMock(return_value=deleted)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_mcpusercredentials.delete_many = AsyncMock(
|
||||
side_effect=Exception("connection pool exhausted")
|
||||
)
|
||||
|
|
@ -1534,6 +1547,7 @@ async def test_create_mcp_server_decrypts_env_vars_when_prisma_returns_json_stri
|
|||
mock_prisma.db.litellm_mcpservertable.create = AsyncMock(
|
||||
return_value=_prisma_row_with_json_string_env_vars()
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
created = await create_mcp_server(
|
||||
mock_prisma,
|
||||
|
|
@ -1553,6 +1567,7 @@ async def test_create_mcp_server_decrypts_env_vars_when_prisma_returns_json_stri
|
|||
mock_prisma_upd.db.litellm_mcpservertable.update = AsyncMock(
|
||||
return_value=_prisma_row_with_json_string_env_vars()
|
||||
)
|
||||
mock_prisma_upd.replica_db = mock_prisma_upd.db
|
||||
updated = await update_mcp_server(
|
||||
mock_prisma_upd,
|
||||
UpdateMCPServerRequest(server_id="srv-update"),
|
||||
|
|
@ -1630,6 +1645,7 @@ async def test_rotate_mcp_user_env_vars_logs_rotated_and_skipped_counts(
|
|||
prisma.db.litellm_mcpuserenvvars.find_many = AsyncMock(
|
||||
return_value=[good_one, good_two, bad]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_mcpuserenvvars.update = AsyncMock()
|
||||
|
||||
logger = MagicMock()
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ def _credentials_cleared(value) -> bool:
|
|||
def _mock_prisma():
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
row = models.LiteLLM_MCPServerTable.model_construct(server_id="test-server", transport="http", env={}, env_vars=[])
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=row)
|
||||
mock_prisma.db.litellm_mcpservertable.create = AsyncMock(return_value=row)
|
||||
|
|
@ -198,6 +199,7 @@ async def _run_update_with_existing(data: UpdateMCPServerRequest, existing_auth_
|
|||
existing.auth_type = existing_auth_type
|
||||
existing.credentials = None
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
return mock_prisma.db.litellm_mcpservertable.update.call_args[1]["data"]
|
||||
|
||||
|
|
@ -240,6 +242,7 @@ async def test_explicit_null_clears_upstream_resource_and_keeps_the_rest_of_the_
|
|||
existing.url = "https://up.example.com/mcp"
|
||||
existing.credentials = json.dumps({"client_secret": "csec", "upstream_resource": "api://audience"})
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="my-test-server", credentials={"upstream_resource": None})
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -261,6 +264,7 @@ async def test_url_change_clears_stale_oauth_fields():
|
|||
existing.url = "https://old.example.com/mcp"
|
||||
existing.credentials = None
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="my-test-server", url="https://new.example.com/mcp")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -286,6 +290,7 @@ async def test_url_change_clears_stale_oauth_fields_even_when_resubmitted_unchan
|
|||
existing.token_url = "https://old-idp.example.com/token"
|
||||
existing.authorization_url = "https://old-idp.example.com/authorize"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="my-test-server",
|
||||
|
|
@ -318,6 +323,7 @@ async def test_clearing_pinned_issuer_clears_stale_oauth_endpoints():
|
|||
existing.token_url = "https://pinned-idp.example.com/token"
|
||||
existing.authorization_url = "https://pinned-idp.example.com/authorize"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="my-test-server",
|
||||
|
|
@ -345,6 +351,7 @@ async def test_repointing_pinned_issuer_clears_stale_endpoints_keeps_new_issuer(
|
|||
existing.token_url = "https://old-idp.example.com/token"
|
||||
existing.authorization_url = "https://old-idp.example.com/authorize"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="my-test-server",
|
||||
|
|
@ -375,6 +382,7 @@ async def test_establishing_issuer_first_time_preserves_endpoints_set_in_the_sam
|
|||
existing.credentials = None
|
||||
existing.issuer = None
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="my-test-server",
|
||||
|
|
@ -402,6 +410,7 @@ async def test_unchanged_url_does_not_clear_oauth_fields():
|
|||
existing.url = "https://same.example.com/mcp"
|
||||
existing.credentials = None
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="my-test-server", url="https://same.example.com/mcp")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -600,6 +609,7 @@ async def test_credentials_merge_migrates_legacy_blob_te_settings():
|
|||
},
|
||||
)
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="te-server",
|
||||
|
|
@ -629,6 +639,7 @@ async def test_cleared_column_is_not_resurrected_by_legacy_blob_value():
|
|||
credentials={"client_id": "enc-old-cid", "token_exchange_endpoint": "https://dead-idp.example.com/token"},
|
||||
)
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="te-server",
|
||||
|
|
@ -654,6 +665,7 @@ async def test_merge_strips_blob_te_copy_when_column_already_set():
|
|||
)
|
||||
existing.token_exchange_endpoint = "https://column.example.com/token"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="te-server",
|
||||
|
|
@ -676,6 +688,7 @@ async def test_auth_type_switch_clears_flow_fields_with_external_fields_set():
|
|||
mock_prisma = _mock_prisma()
|
||||
existing = _existing_row("oauth2")
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="te-server", auth_type="oauth2_token_exchange")
|
||||
await update_mcp_server(mock_prisma, data, "test-user", fields_set=set(data.fields_set()))
|
||||
|
|
@ -705,6 +718,7 @@ async def test_explicit_clear_without_credentials_purges_legacy_blob_copy():
|
|||
credentials={"client_id": "enc-old-cid", "token_exchange_endpoint": "https://dead-idp.example.com/token"},
|
||||
)
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="te-server", token_exchange_endpoint=None)
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -732,6 +746,7 @@ async def test_explicit_te_write_without_credentials_migrates_other_legacy_field
|
|||
},
|
||||
)
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="te-server", audience="api://new")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -751,6 +766,7 @@ async def test_te_update_without_blob_te_keys_leaves_credentials_untouched():
|
|||
mock_prisma = _mock_prisma()
|
||||
existing = _existing_row("oauth2_token_exchange", credentials={"client_id": "enc-old-cid"})
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="te-server", token_exchange_endpoint="https://new.example.com/token")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -774,6 +790,7 @@ async def test_cf_pair_switch_without_credentials_keeps_stored_app_and_endpoints
|
|||
existing.token_url = "https://provider.example/token"
|
||||
existing.registration_url = "https://provider.example/register"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="cf-server", auth_type="oauth_delegate")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -791,6 +808,7 @@ async def test_cf_pair_switch_with_partial_credentials_merges_not_replaces():
|
|||
mock_prisma = _mock_prisma()
|
||||
existing = _existing_row("true_passthrough", credentials={"client_id": "enc-A", "client_secret": "enc-B"})
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="cf-server", auth_type="oauth_delegate", credentials={"client_id": "B"})
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -808,6 +826,7 @@ async def test_null_existing_auth_type_to_cf_counts_as_changed_and_clears_blob()
|
|||
mock_prisma = _mock_prisma()
|
||||
existing = _existing_row(None, credentials={"client_id": "enc-old"})
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(server_id="cf-server", auth_type="true_passthrough")
|
||||
await update_mcp_server(mock_prisma, data, "test-user")
|
||||
|
|
@ -827,6 +846,7 @@ async def test_client_rotation_strips_legacy_minted_token_keys():
|
|||
"oauth2", credentials={"client_id": "A", "access_token": "T", "refresh_token": "R", "expires_in": 3600}
|
||||
)
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="oauth2-server", auth_type="oauth2", credentials={"client_id": "B", "client_secret": "S"}
|
||||
|
|
@ -872,6 +892,7 @@ def _mock_toolset_prisma():
|
|||
}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcptoolsettable = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcptoolsettable.update = AsyncMock(return_value=updated_row)
|
||||
return mock_prisma
|
||||
|
||||
|
|
@ -945,6 +966,7 @@ async def test_find_identifier_conflict_reports_alias_hit():
|
|||
|
||||
mock_prisma = _mock_prisma()
|
||||
mock_prisma.db.litellm_mcpservertable.find_first = AsyncMock(return_value=_conflict_row())
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
conflict = await find_mcp_server_identifier_conflict(
|
||||
mock_prisma, server_name="new-name", alias="taken", exclude_server_id="my-server"
|
||||
|
|
@ -966,6 +988,7 @@ async def test_find_identifier_conflict_reports_server_name_when_alias_is_free()
|
|||
|
||||
mock_prisma = _mock_prisma()
|
||||
mock_prisma.db.litellm_mcpservertable.find_first = AsyncMock(side_effect=[None, _conflict_row()])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
conflict = await find_mcp_server_identifier_conflict(
|
||||
mock_prisma, server_name="taken", alias="free", exclude_server_id=None
|
||||
|
|
@ -994,6 +1017,7 @@ async def test_update_writing_alias_returns_conflict_instead_of_row():
|
|||
|
||||
mock_prisma = _mock_prisma()
|
||||
mock_prisma.db.litellm_mcpservertable.find_first = AsyncMock(return_value=_conflict_row())
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result = await update_mcp_server(
|
||||
mock_prisma,
|
||||
|
|
@ -1040,6 +1064,7 @@ async def test_clearing_alias_conflicts_on_the_fallback_server_name():
|
|||
existing = MagicMock()
|
||||
existing.server_name = "taken"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.find_first = AsyncMock(return_value=_conflict_row())
|
||||
|
||||
result = await update_mcp_server(
|
||||
|
|
@ -1063,6 +1088,7 @@ async def test_clearing_alias_to_empty_string_conflicts_on_the_fallback_server_n
|
|||
existing = MagicMock()
|
||||
existing.server_name = "taken"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.find_first = AsyncMock(return_value=_conflict_row())
|
||||
|
||||
result = await update_mcp_server(
|
||||
|
|
@ -1082,6 +1108,7 @@ async def test_clearing_alias_with_free_server_name_returns_the_row():
|
|||
existing = MagicMock()
|
||||
existing.server_name = "free-name"
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result = await update_mcp_server(
|
||||
mock_prisma,
|
||||
|
|
|
|||
|
|
@ -5390,6 +5390,7 @@ class TestMCPServerManagerReload:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[db_row])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy.management_endpoints.mcp_management_endpoints.get_prisma_client_or_throw",
|
||||
|
|
@ -5432,6 +5433,7 @@ class TestMCPServerManagerReload:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[db_row])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy.management_endpoints.mcp_management_endpoints.get_prisma_client_or_throw",
|
||||
|
|
@ -5487,6 +5489,7 @@ class TestMCPServerManagerReload:
|
|||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(
|
||||
return_value=[healthy_row, bad_row, another_healthy_row]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy.management_endpoints.mcp_management_endpoints.get_prisma_client_or_throw",
|
||||
|
|
@ -5557,6 +5560,7 @@ class TestMCPServerManagerReload:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[healthy_row, bad_openapi_row])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
with (
|
||||
patch(
|
||||
"litellm.proxy.management_endpoints.mcp_management_endpoints.get_prisma_client_or_throw",
|
||||
|
|
@ -8718,6 +8722,7 @@ async def test_get_active_submitted_mcp_server_ids_for_user_queries_active_rows(
|
|||
row.server_id = "submitted-1"
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[row])
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
result = await get_active_submitted_mcp_server_ids_for_user(prisma_client, "submitter-user")
|
||||
|
||||
|
|
@ -8738,6 +8743,7 @@ async def test_get_active_submitted_mcp_server_ids_for_user_empty_user_id_skips_
|
|||
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_mcpservertable.find_many = AsyncMock()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
assert await get_active_submitted_mcp_server_ids_for_user(prisma_client, "") == []
|
||||
prisma_client.db.litellm_mcpservertable.find_many.assert_not_awaited()
|
||||
|
|
|
|||
|
|
@ -605,6 +605,7 @@ class TestCredentialMergeOnUpdate:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
|
|
@ -645,6 +646,7 @@ class TestCredentialMergeOnUpdate:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
server_id="test-server",
|
||||
|
|
@ -672,6 +674,7 @@ class TestCredentialMergeOnUpdate:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
|
|
@ -714,6 +717,7 @@ class TestCredentialMergeOnUpdate:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
|
|
@ -757,6 +761,7 @@ class TestCredentialMergeOnUpdate:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
|
|
@ -993,6 +998,7 @@ class TestRotateCredentials:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[server])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock()
|
||||
mock_prisma.db.litellm_mcpserveroauthclient.find_many = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -1041,6 +1047,7 @@ class TestRotateCredentials:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[server])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock()
|
||||
mock_prisma.db.litellm_mcpserveroauthclient.find_many = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -1088,6 +1095,7 @@ class TestAuthTypeSwitchClearsCredentials:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=_updated_row())
|
||||
|
||||
data = UpdateMCPServerRequest(
|
||||
|
|
|
|||
|
|
@ -142,6 +142,7 @@ async def test_mint_reads_the_users_teams_from_the_database_not_a_stale_cached_r
|
|||
prisma.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=_user(user_id="stale-cache-user", teams=["team-a"])
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(proxy_server, "user_api_key_cache", cache)
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma)
|
||||
|
||||
|
|
@ -167,6 +168,7 @@ async def test_mint_refuses_a_user_scim_deactivated_after_the_cache_last_saw_the
|
|||
prisma.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=_user(user_id="deactivated-user", teams=["team-a"], metadata={"scim_active": False})
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(proxy_server, "user_api_key_cache", cache)
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma)
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ async def test_update_agent_in_db_clears_static_headers_and_extra_headers_when_o
|
|||
|
||||
mock_update = AsyncMock(return_value=updated_agent)
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
# Agent config WITHOUT static_headers or extra_headers (omitted)
|
||||
|
|
@ -108,6 +109,7 @@ async def test_update_agent_in_db_preserves_explicit_static_headers_and_extra_he
|
|||
|
||||
mock_update = AsyncMock(return_value=updated_agent)
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
agent_config = {
|
||||
|
|
@ -453,6 +455,7 @@ async def test_update_agent_in_db_raises_when_row_deleted_mid_update():
|
|||
mock_prisma.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
return_value=SimpleNamespace(litellm_params={}, object_permission_id=None)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.update = AsyncMock(return_value=None)
|
||||
|
||||
with pytest.raises(Exception, match="Error updating agent in DB") as exc_info:
|
||||
|
|
@ -478,6 +481,7 @@ async def test_patch_agent_in_db_raises_when_row_deleted_mid_update():
|
|||
mock_prisma.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
return_value={"agent_id": "agent-123", "agent_name": "Old Agent", "object_permission_id": None}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.update = AsyncMock(return_value=None)
|
||||
|
||||
with pytest.raises(Exception, match="Error patching agent in DB") as exc_info:
|
||||
|
|
@ -497,6 +501,7 @@ async def test_delete_agent_from_db_raises_when_row_already_gone():
|
|||
registry: Final = AgentRegistry()
|
||||
mock_prisma: Final = MagicMock()
|
||||
mock_prisma.db.litellm_agentstable.delete = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
with pytest.raises(Exception, match="Error deleting agent from DB") as exc_info:
|
||||
await registry.delete_agent_from_db(agent_id="agent-123", prisma_client=mock_prisma)
|
||||
|
|
@ -701,6 +706,7 @@ async def test_add_agent_to_db_drops_a_sentinel_value_instead_of_storing_the_pla
|
|||
created_agent.object_permission = None
|
||||
mock_create = AsyncMock(return_value=created_agent)
|
||||
mock_prisma.db.litellm_agentstable.create = mock_create
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
await registry.add_agent_to_db(
|
||||
agent={
|
||||
|
|
@ -738,6 +744,7 @@ async def test_update_agent_in_db_preserves_secret_when_echoed_back_redacted():
|
|||
object_permission_id=None,
|
||||
)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -786,6 +793,7 @@ async def test_update_agent_in_db_preserves_secret_when_key_omitted_entirely():
|
|||
object_permission_id=None,
|
||||
)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -832,6 +840,7 @@ async def test_update_agent_in_db_preserves_secret_nested_under_a_non_sensitive_
|
|||
object_permission_id=None,
|
||||
)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -880,6 +889,7 @@ async def test_update_agent_in_db_clears_secret_on_explicit_empty_value():
|
|||
object_permission_id=None,
|
||||
)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -922,6 +932,7 @@ async def test_patch_agent_in_db_preserves_secret_when_litellm_params_omitted():
|
|||
"object_permission_id": None,
|
||||
}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
patched_agent = MagicMock()
|
||||
patched_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -964,6 +975,7 @@ async def test_patch_agent_in_db_preserves_secret_when_echoed_back_redacted():
|
|||
"object_permission_id": None,
|
||||
}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
patched_agent = MagicMock()
|
||||
patched_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
|
|
@ -1013,6 +1025,7 @@ async def test_add_agent_to_db_persists_deduplicated_access_group_ids():
|
|||
mock_prisma: Final = MagicMock()
|
||||
mock_create = AsyncMock(return_value=_agent_row_mock(["ag-1", "ag-2"]))
|
||||
mock_prisma.db.litellm_agentstable.create = mock_create
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result: Final = await registry.add_agent_to_db(
|
||||
agent={
|
||||
|
|
@ -1034,6 +1047,7 @@ async def test_add_agent_to_db_without_access_group_ids_leaves_column_to_its_def
|
|||
mock_prisma: Final = MagicMock()
|
||||
mock_create = AsyncMock(return_value=_agent_row_mock([]))
|
||||
mock_prisma.db.litellm_agentstable.create = mock_create
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
await registry.add_agent_to_db(
|
||||
agent={"agent_name": "Test Agent", "agent_card_params": _sample_agent_card_params()},
|
||||
|
|
@ -1067,6 +1081,7 @@ async def test_patch_agent_in_db_replaces_access_group_ids_when_provided(
|
|||
"access_group_ids": ["ag-1"],
|
||||
}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_update = AsyncMock(return_value=_agent_row_mock(expected))
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
|
||||
|
|
@ -1090,6 +1105,7 @@ async def test_patch_agent_in_db_keeps_access_group_ids_when_omitted():
|
|||
"access_group_ids": ["ag-1"],
|
||||
}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_update = AsyncMock(return_value=_agent_row_mock(["ag-1"]))
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
|
||||
|
|
@ -1112,6 +1128,7 @@ async def test_update_agent_in_db_always_writes_access_group_ids(body_access_gro
|
|||
mock_prisma.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
return_value=SimpleNamespace(litellm_params={}, object_permission_id=None, access_group_ids=["ag-1"])
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_update = AsyncMock(return_value=_agent_row_mock(expected))
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
body: Final = {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ MODEL_ROWS = [{"model": "gpt-5.1"}]
|
|||
def build_prisma(query_raw: AsyncMock) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.query_raw = query_raw
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -137,6 +138,7 @@ async def test_rejects_malformed_dates_with_400(mock_prisma: MagicMock):
|
|||
|
||||
assert exc_info.value.status_code == 400
|
||||
mock_prisma.db.query_raw.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
def test_totals_ratio_is_zero_without_requests():
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ def _make_mock_prisma():
|
|||
mock_table.create = AsyncMock(side_effect=_create)
|
||||
mock_table.update = AsyncMock(side_effect=_update)
|
||||
mock_client.db.litellm_claudecodeplugintable = mock_table
|
||||
mock_client.replica_db = mock_client.db
|
||||
return mock_client
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ def admin_viewer_client(monkeypatch):
|
|||
litellm_config=mock_config_table,
|
||||
query_raw=mock_query_raw,
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
_override_auth(LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY)
|
||||
|
|
|
|||
|
|
@ -254,6 +254,7 @@ async def test_get_team_object_warm_cache():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_teamtable = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock()
|
||||
|
||||
|
|
@ -295,6 +296,7 @@ async def test_get_user_object_warm_cache():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_usertable = MagicMock()
|
||||
mock_prisma.db.litellm_usertable.find_unique = AsyncMock()
|
||||
|
||||
|
|
@ -347,6 +349,7 @@ async def test_get_team_membership_warm_cache():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_teammembership = MagicMock()
|
||||
mock_prisma.db.litellm_teammembership.find_unique = AsyncMock()
|
||||
|
||||
|
|
@ -533,6 +536,7 @@ async def test_get_user_object_missing_user_negative_cache():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_usertable = MagicMock()
|
||||
mock_prisma.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
|
|
@ -564,6 +568,7 @@ async def test_get_user_object_missing_user_rechecks_after_expiry():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_usertable = MagicMock()
|
||||
mock_prisma.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ async def test_custom_auth_token_budget_still_loads_and_caches_unrestricted_end_
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_endusertable.find_unique = AsyncMock(return_value=end_user_row)
|
||||
cache = UserApiKeyCache()
|
||||
|
||||
|
|
@ -241,6 +242,7 @@ async def test_custom_auth_key_default_end_user_budget_reaches_the_token_for_a_n
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_endusertable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_budgettable.find_unique = AsyncMock(side_effect=_find_budget)
|
||||
|
||||
|
|
@ -279,6 +281,7 @@ async def test_custom_auth_cap_stays_below_the_key_default_end_user_budget(monke
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_endusertable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_budgettable.find_unique = AsyncMock(side_effect=_find_budget)
|
||||
|
||||
|
|
@ -317,6 +320,7 @@ async def test_custom_auth_proxy_wide_default_end_user_budget_reaches_an_uncappe
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_endusertable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_budgettable.find_unique = AsyncMock(side_effect=_find_budget)
|
||||
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ async def test_authenticate_user_admin_login_with_ui_credentials():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -150,6 +151,7 @@ async def test_authenticate_user_admin_login_with_master_key_as_password(monkeyp
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
env_vars = {
|
||||
"UI_USERNAME": ui_username,
|
||||
|
|
@ -206,6 +208,7 @@ async def test_authenticate_user_invalid_credentials():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": ui_username, "UI_PASSWORD": "correct-password"}):
|
||||
with pytest.raises(ProxyException) as exc_info:
|
||||
|
|
@ -260,6 +263,7 @@ async def test_authenticate_user_wrong_password():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=mock_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -311,6 +315,7 @@ async def test_authenticate_user_email_case_insensitive_login():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(side_effect=mock_find_first)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -366,6 +371,7 @@ async def test_authenticate_user_database_required_for_admin(monkeypatch):
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": ui_username, "UI_PASSWORD": ui_password}):
|
||||
with patch(
|
||||
|
|
@ -405,6 +411,7 @@ async def test_authenticate_user_admin_login_with_non_ascii_characters():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -479,6 +486,7 @@ async def test_authenticate_user_multiple_logins_generate_unique_tokens():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -566,6 +574,7 @@ async def test_authenticate_user_database_login_with_non_ascii_password():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(side_effect=mock_find_first)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -1768,6 +1777,7 @@ class TestDisablePasswordLoginWhenSSOEnabled:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": ui_username, "UI_PASSWORD": master_key}):
|
||||
with ExitStack() as stack:
|
||||
|
|
@ -1801,6 +1811,7 @@ class TestDisablePasswordLoginWhenSSOEnabled:
|
|||
)
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=mock_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": "admin", "UI_PASSWORD": "unrelated"}):
|
||||
with ExitStack() as stack:
|
||||
|
|
@ -1827,6 +1838,7 @@ class TestDisablePasswordLoginWhenSSOEnabled:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -1864,6 +1876,7 @@ class TestDisablePasswordLoginWhenSSOEnabled:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -1898,6 +1911,7 @@ class TestDisablePasswordLoginWhenSSOEnabled:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -1938,6 +1952,7 @@ class TestDisableEnvCredentialLogin:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": ui_username, "UI_PASSWORD": ui_password}):
|
||||
with pytest.raises(ProxyException) as exc_info:
|
||||
|
|
@ -1963,6 +1978,7 @@ class TestDisableEnvCredentialLogin:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(os.environ, {"UI_USERNAME": "admin"}, clear=True):
|
||||
with pytest.raises(ProxyException) as exc_info:
|
||||
|
|
@ -1991,6 +2007,7 @@ class TestDisableEnvCredentialLogin:
|
|||
)
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=mock_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -2031,6 +2048,7 @@ class TestDisableEnvCredentialLogin:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch.dict(
|
||||
os.environ,
|
||||
|
|
@ -2098,6 +2116,7 @@ def _db_user_row(*, password: str, password_reset_required: bool | None = None,
|
|||
def _prisma_with_user(row) -> MagicMock:
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_usertable.find_first = AsyncMock(return_value=row)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.update = AsyncMock(return_value=row)
|
||||
return mock_prisma_client
|
||||
|
||||
|
|
@ -2288,6 +2307,7 @@ class TestScreenLoginPasswordForBreach:
|
|||
|
||||
assert breached is False
|
||||
mock_prisma_client.db.litellm_usertable.update.assert_not_called()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rechecks_when_last_check_is_older_than_24_hours(self):
|
||||
|
|
@ -2323,6 +2343,7 @@ class TestScreenLoginPasswordForBreach:
|
|||
|
||||
assert breached is False
|
||||
mock_prisma_client.db.litellm_usertable.update.assert_not_called()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_db_failure_never_raises_but_still_reports_the_breach(self):
|
||||
|
|
@ -2331,6 +2352,7 @@ class TestScreenLoginPasswordForBreach:
|
|||
password = "Password123!"
|
||||
mock_prisma_client = _prisma_with_user(None)
|
||||
mock_prisma_client.db.litellm_usertable.update = AsyncMock(side_effect=RuntimeError("db down"))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
assert (
|
||||
await screen_login_password_for_breach(
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ class _RecordingPrismaClient:
|
|||
self.rows = {row.access_group_name: row for row in rows}
|
||||
self.batches: list[list[str]] = []
|
||||
self.db = SimpleNamespace(litellm_modelaccessgroupbudgettable=SimpleNamespace(find_many=self._find_many))
|
||||
self.replica_db = self.db
|
||||
|
||||
async def _find_many(self, **kwargs):
|
||||
requested = list(kwargs["where"]["access_group_name"]["in"])
|
||||
|
|
@ -498,6 +499,7 @@ async def test_a_database_error_does_not_block_the_request():
|
|||
class _FailingPrismaClient:
|
||||
def __init__(self) -> None:
|
||||
self.db = SimpleNamespace(litellm_modelaccessgroupbudgettable=SimpleNamespace(find_many=self._boom))
|
||||
self.replica_db = self.db
|
||||
|
||||
async def _boom(self, **kwargs):
|
||||
raise RuntimeError("database unavailable")
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ _POLICY_NO_BREACH_CHECK = {"password_policy_check_breached_passwords": False}
|
|||
class _AsyncTx:
|
||||
def __init__(self, db: MagicMock):
|
||||
self.db = db
|
||||
self.replica_db = self.db
|
||||
|
||||
async def __aenter__(self) -> MagicMock:
|
||||
return self.db
|
||||
|
|
@ -63,6 +64,7 @@ def _make_user() -> MagicMock:
|
|||
def _make_prisma(invite: MagicMock, user: MagicMock | None = None) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_invitationlink.find_unique = AsyncMock(return_value=invite)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_invitationlink.update = AsyncMock()
|
||||
prisma.db.litellm_invitationlink.update_many = AsyncMock(return_value=1)
|
||||
prisma.db.litellm_usertable.find_unique = AsyncMock(return_value=user)
|
||||
|
|
@ -125,6 +127,7 @@ async def test_get_token_rejects_already_used_link():
|
|||
assert "already been used" in exc_info.value.detail["error"]
|
||||
# The user table must never have been queried
|
||||
prisma.db.litellm_usertable.find_unique.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -215,6 +218,7 @@ async def test_get_token_returns_onboarding_token_without_minting_ui_key():
|
|||
|
||||
mock_generate_key.assert_not_called()
|
||||
prisma.db.litellm_invitationlink.update_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_invitationlink.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -247,6 +251,7 @@ async def test_claim_token_rejects_already_used_link():
|
|||
assert "already been used" in exc_info.value.detail["error"]
|
||||
# Password must never have been written
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -315,6 +320,7 @@ async def test_claim_token_rejects_missing_onboarding_token():
|
|||
assert exc_info.value.status_code == 401
|
||||
assert "Missing onboarding session" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -344,6 +350,7 @@ async def test_claim_token_rejects_wrong_onboarding_session():
|
|||
assert exc_info.value.status_code == 401
|
||||
assert "Invalid onboarding session" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -371,6 +378,7 @@ async def test_claim_token_rejects_invalid_bearer_token():
|
|||
assert exc_info.value.status_code == 401
|
||||
assert "Invalid onboarding session" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -381,6 +389,7 @@ async def test_claim_token_rejects_concurrent_reuse_before_password_write():
|
|||
invite = _make_invite(is_accepted=False)
|
||||
prisma = _make_prisma(invite)
|
||||
prisma.db.litellm_invitationlink.update_many = AsyncMock(return_value=0)
|
||||
prisma.replica_db = prisma.db
|
||||
request = _make_claim_request(_make_onboarding_token())
|
||||
data = InvitationClaim(
|
||||
invitation_link="invite-abc",
|
||||
|
|
@ -456,6 +465,7 @@ async def test_claim_token_sets_accepted_at_after_password_written():
|
|||
|
||||
# Password was written
|
||||
prisma.db.litellm_invitationlink.update_many.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
reserve_kwargs = prisma.db.litellm_invitationlink.update_many.call_args.kwargs
|
||||
assert reserve_kwargs["where"] == {"id": "invite-abc", "is_accepted": False}
|
||||
assert reserve_kwargs["data"]["is_accepted"] is True
|
||||
|
|
@ -627,6 +637,7 @@ async def test_claim_token_rejects_short_password_before_consuming_invite():
|
|||
assert exc_info.value.code == "400"
|
||||
assert "at least 12 characters" in exc_info.value.message
|
||||
prisma.db.litellm_invitationlink.update_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -661,6 +672,7 @@ async def test_claim_token_rejects_breached_password_before_consuming_invite():
|
|||
assert exc_info.value.code == "400"
|
||||
assert "data breaches" in exc_info.value.message
|
||||
prisma.db.litellm_invitationlink.update_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -707,3 +719,4 @@ async def test_claim_token_fails_open_when_hibp_unreachable():
|
|||
|
||||
assert "token" in result
|
||||
prisma.db.litellm_usertable.update.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
|
|
|
|||
|
|
@ -1182,6 +1182,7 @@ def assert_ownership_registered_for_team_a(prisma_client: AsyncMock, batch_id: s
|
|||
assert created["created_by"] == "user_a"
|
||||
assert created["team_id"] == "team_a"
|
||||
prisma_client.db.litellm_managedobjecttable.update_many.assert_not_awaited()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -683,6 +683,7 @@ async def test_model_repository_write_publishes_via_live_coordination_cache() ->
|
|||
client = _RecordingRedisClient()
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_proxymodeltable.update = AsyncMock(return_value={"model_id": "m-1"})
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
repository = ModelRepository(prisma_client)
|
||||
table = repository.table
|
||||
assert isinstance(table, _PublishOnWriteActions)
|
||||
|
|
@ -711,6 +712,7 @@ async def test_ui_settings_write_publishes_via_live_coordination_cache() -> None
|
|||
client = _RecordingRedisClient()
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_uisettings.upsert = AsyncMock(return_value={"id": "ui_settings"})
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
table = UISettingsRepository(prisma_client).table
|
||||
assert isinstance(table, _PublishOnWriteActions)
|
||||
|
||||
|
|
@ -790,6 +792,7 @@ def _reload_config_prisma_client() -> MagicMock:
|
|||
prisma_client = MagicMock()
|
||||
prisma_client.get_generic_data = AsyncMock(return_value=config_record)
|
||||
prisma_client.db.litellm_config.find_unique = AsyncMock(return_value=config_record)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_config.upsert = AsyncMock(return_value=config_record)
|
||||
prisma_client.db.litellm_config.update_many = AsyncMock(return_value=1)
|
||||
return prisma_client
|
||||
|
|
@ -823,6 +826,7 @@ async def test_model_cost_map_reload_does_not_publish_config_change() -> None:
|
|||
_set_redis_usage_cache(previous_cache)
|
||||
|
||||
prisma_client.db.litellm_config.update_many.assert_awaited_once()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
assert client.published == []
|
||||
|
||||
|
||||
|
|
@ -844,6 +848,7 @@ async def test_anthropic_beta_headers_reload_does_not_publish_config_change() ->
|
|||
_set_redis_usage_cache(previous_cache)
|
||||
|
||||
prisma_client.db.litellm_config.upsert.assert_awaited_once()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
assert client.published == []
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class TestExpiredUISessionKeyCleanupManager:
|
|||
mock_prisma_client.db.litellm_verificationtoken.find_many.return_value = (
|
||||
mock_keys
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.common_utils.expired_ui_session_key_cleanup_manager.datetime"
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ class TestKeyRotationErrorResilience:
|
|||
be attempted. No key should be silently skipped.
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
key1 = LiteLLM_VerificationToken(
|
||||
|
|
@ -221,6 +222,7 @@ class TestKeyRotationErrorResilience:
|
|||
but process_rotations should catch it per-key.
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
key = LiteLLM_VerificationToken(
|
||||
|
|
@ -260,6 +262,7 @@ class TestKeyRotationErrorResilience:
|
|||
update for rotation_count should still have succeeded (it runs before the hook).
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
key = LiteLLM_VerificationToken(
|
||||
|
|
@ -359,6 +362,7 @@ class TestKeyRotationFullFlow:
|
|||
|
||||
# Mock cleanup
|
||||
mock_prisma.db.litellm_deprecatedverificationtoken.delete_many.return_value = 1
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
# Mock find keys
|
||||
mock_prisma.db.litellm_verificationtoken.find_many.return_value = [key]
|
||||
|
||||
|
|
@ -399,6 +403,7 @@ class TestKeyRotationFullFlow:
|
|||
correctly each time: 0 -> 1 -> 2 -> 3
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
rotation_counts_seen = []
|
||||
|
|
@ -445,6 +450,7 @@ class TestKeyRotationFullFlow:
|
|||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.db.litellm_deprecatedverificationtoken.delete_many.return_value = 0
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_verificationtoken.find_many.return_value = []
|
||||
|
||||
mock_lock = MagicMock()
|
||||
|
|
@ -468,6 +474,7 @@ class TestKeyRotationFullFlow:
|
|||
the DB update for rotation metadata should be skipped.
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
key = LiteLLM_VerificationToken(
|
||||
|
|
@ -525,6 +532,7 @@ class TestKeyRotationInitialization:
|
|||
When no pod_lock_manager is provided, it defaults to None.
|
||||
"""
|
||||
mock_prisma = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
manager = KeyRotationManager(mock_prisma)
|
||||
|
||||
assert manager.pod_lock_manager is None
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class TestKeyRotationManagerPassesKeyAlias:
|
|||
mock_prisma.db.litellm_verificationtoken.update = AsyncMock(
|
||||
return_value=mock_key
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Create mock response
|
||||
mock_response = GenerateKeyResponse(
|
||||
|
|
@ -114,6 +115,7 @@ class TestKeyRotationManagerPassesKeyAlias:
|
|||
mock_prisma.db.litellm_verificationtoken.update = AsyncMock(
|
||||
return_value=mock_key
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
mock_response = GenerateKeyResponse(
|
||||
key="sk-new-key-value",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class TestKeyRotationManager:
|
|||
"""
|
||||
# Setup
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
manager = KeyRotationManager(mock_prisma_client)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
|
@ -101,6 +102,7 @@ class TestKeyRotationManager:
|
|||
"""
|
||||
# Setup
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
manager = KeyRotationManager(mock_prisma_client)
|
||||
|
||||
# Use a fixed timestamp to avoid timing issues in tests
|
||||
|
|
@ -171,6 +173,7 @@ class TestKeyRotationManager:
|
|||
"""
|
||||
# Setup
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
manager = KeyRotationManager(mock_prisma_client)
|
||||
|
||||
# Mock key to rotate
|
||||
|
|
@ -231,6 +234,7 @@ class TestKeyRotationManager:
|
|||
Test that _cleanup_expired_deprecated_keys deletes expired deprecated keys.
|
||||
"""
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_deprecatedverificationtoken.delete_many.return_value = (
|
||||
3
|
||||
)
|
||||
|
|
@ -251,6 +255,7 @@ class TestKeyRotationManager:
|
|||
Test that _rotate_key passes grace_period in RegenerateKeyRequest.
|
||||
"""
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
manager = KeyRotationManager(mock_prisma_client)
|
||||
|
||||
key_to_rotate = LiteLLM_VerificationToken(
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ def _row(param_value=None, reload_revision=0, last_run_at=None):
|
|||
def _mock_prisma(row=None, upserted_revision=1):
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_config.find_unique = AsyncMock(return_value=row)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_config.upsert = AsyncMock(return_value=_row(reload_revision=upserted_revision))
|
||||
prisma_client.db.litellm_config.update_many = AsyncMock(return_value=1)
|
||||
return prisma_client
|
||||
|
|
@ -85,6 +86,7 @@ class _FakeConfigTable:
|
|||
def _fake_prisma(table):
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_config = table
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
return prisma_client
|
||||
|
||||
|
||||
|
|
@ -291,6 +293,7 @@ async def test_record_reload_run_updates_last_run_without_creating_or_bumping():
|
|||
kwargs = prisma_client.db.litellm_config.update_many.await_args.kwargs
|
||||
assert kwargs == {"data": {"last_run_at": LAST_RUN}, "where": {"param_name": "model_cost_map_reload_config"}}
|
||||
prisma_client.db.litellm_config.upsert.assert_not_called()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -167,6 +167,7 @@ async def test_get_agent_with_read_through_recovers_agent_created_on_sibling_rep
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
return_value=FakeAgentRow(agent_id, "read-through-db-agent")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -193,6 +194,7 @@ async def test_get_agent_with_read_through_recovers_agent_by_name(clean_agent_re
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
side_effect=[None, FakeAgentRow("read-through-name-lookup-id", agent_name)]
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -217,6 +219,7 @@ async def test_get_agent_with_read_through_returns_none_for_unknown_agent(
|
|||
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -236,6 +239,7 @@ async def test_resync_agents_already_registered_skips_db(clean_agent_registry, m
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
return_value=FakeAgentRow(agent_id, "read-through-dedup-agent")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -283,6 +287,7 @@ async def test_get_guardrail_with_read_through_recovers_guardrail_created_on_sib
|
|||
prisma_client.db.litellm_guardrailstable.find_first = AsyncMock(
|
||||
return_value=FakeGuardrailRow(guardrail_id, guardrail_name)
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(
|
||||
side_effect=AssertionError("full-table guardrail scan on read-through miss")
|
||||
)
|
||||
|
|
@ -311,6 +316,7 @@ async def test_get_guardrail_with_read_through_returns_none_for_unknown_guardrai
|
|||
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db.litellm_guardrailstable.find_first = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -327,6 +333,7 @@ async def test_resync_guardrails_never_loads_non_active_rows(monkeypatch):
|
|||
pending_name: Final = "pending-review-guardrail"
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db.litellm_guardrailstable.find_first = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
@ -353,6 +360,7 @@ async def test_resync_guardrails_syncs_under_guardrail_reconcile_lock(monkeypatc
|
|||
prisma_client.db.litellm_guardrailstable.find_first = AsyncMock(
|
||||
return_value=FakeGuardrailRow("lock-scope-guardrail-id", guardrail_name)
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
lock_states: list[bool] = []
|
||||
|
||||
def record_sync(guardrail) -> None:
|
||||
|
|
@ -377,6 +385,7 @@ async def test_resync_model_deployments_mutates_router_under_model_reconcile_loc
|
|||
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[MagicMock()])
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
router: Final = MagicMock()
|
||||
router.get_model_list.return_value = []
|
||||
lock_states: list[bool] = []
|
||||
|
|
@ -410,6 +419,7 @@ async def test_resync_model_deployments_loads_db_credentials_before_reconciling_
|
|||
rows: Final = [MagicMock()]
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=rows)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
router: Final = MagicMock()
|
||||
router.get_model_list.return_value = []
|
||||
installed: Final = MagicMock()
|
||||
|
|
@ -451,6 +461,7 @@ async def test_resync_model_deployments_respects_supported_db_objects(monkeypatc
|
|||
prisma_client.db.litellm_proxymodeltable.find_many = AsyncMock(
|
||||
side_effect=AssertionError("db hit for an object type this replica does not load")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
monkeypatch.setattr(proxy_server, "general_settings", {"supported_db_objects": ["guardrails"]})
|
||||
|
|
@ -469,6 +480,7 @@ async def test_resync_guardrails_respects_supported_db_objects(monkeypatch):
|
|||
prisma_client.db.litellm_guardrailstable.find_unique = AsyncMock(
|
||||
side_effect=AssertionError("db hit for an object type this replica does not load")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
monkeypatch.setattr(proxy_server, "general_settings", {"supported_db_objects": ["models"]})
|
||||
|
|
@ -487,6 +499,7 @@ async def test_resync_agents_respects_supported_db_objects(clean_agent_registry,
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
side_effect=AssertionError("db hit for an object type this replica does not load")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
monkeypatch.setattr(proxy_server, "general_settings", {"supported_db_objects": ["models"]})
|
||||
|
|
@ -508,6 +521,7 @@ async def test_resync_agents_waits_for_agent_reload_and_skips_duplicate_registra
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
side_effect=AssertionError("db hit while the agent reload held the reconcile lock")
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from litellm.proxy._experimental.mcp_server.db import (
|
|||
def _prisma_client_returning(team_record: object) -> MagicMock:
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_record)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
return prisma_client
|
||||
|
||||
|
||||
|
|
@ -42,11 +43,13 @@ async def test_fetch_mcp_servers_by_team(team_record, expected):
|
|||
where={"team_id": "team-123"},
|
||||
include={"object_permission": True},
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
|
||||
def _prisma_client_with_missing_mcp_server_row() -> MagicMock:
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_mcpservertable.update = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
return prisma_client
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ class _FakePrismaClient:
|
|||
litellm_verificationtoken=_InFlightCountingTable(),
|
||||
litellm_projecttable=_FakeFindUniqueTable(row=project_row),
|
||||
)
|
||||
self.replica_db = self.db
|
||||
|
||||
|
||||
def _row(window_start: datetime, spend: float) -> SimpleNamespace:
|
||||
|
|
@ -97,7 +98,8 @@ class _PausedSpendTable:
|
|||
async def _reseed_with_paused_table(
|
||||
table: _PausedSpendTable, cache: DualCache, counter_key: str, window: bool
|
||||
) -> float | None:
|
||||
prisma: Final = SimpleNamespace(db=SimpleNamespace(litellm_usertable=table, litellm_budgetwindowspend=table))
|
||||
tables: Final = SimpleNamespace(litellm_usertable=table, litellm_budgetwindowspend=table)
|
||||
prisma: Final = SimpleNamespace(db=tables, replica_db=tables)
|
||||
if window:
|
||||
return await SpendCounterReseed.coalesced_window(
|
||||
prisma_client=prisma,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class _FakeBatcher:
|
|||
def _prisma(batch_: MagicMock) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.batch_ = batch_
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_spendlogtoolindex.create_many = AsyncMock()
|
||||
return prisma
|
||||
|
||||
|
|
@ -296,12 +297,14 @@ class TestFlushToolUsageTransactions:
|
|||
]
|
||||
batcher.litellm_spendlogtoolindex.create_many.assert_not_called()
|
||||
prisma.db.batch_.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
assert batcher.litellm_dailytoolspend.upsert.call_count == len(tool_names)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_index_connection_error_is_retried_before_the_rollup_is_attempted(self, monkeypatch):
|
||||
prisma, batcher = _prisma_with_batcher()
|
||||
prisma.db.litellm_spendlogtoolindex.create_many = AsyncMock(side_effect=[httpx.ConnectError("down"), None])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
async def fake_sleep(seconds: float) -> None:
|
||||
return None
|
||||
|
|
@ -310,12 +313,14 @@ class TestFlushToolUsageTransactions:
|
|||
await flush_tool_usage_transactions(prisma_client=prisma, transactions=[_transaction("r1")])
|
||||
assert prisma.db.litellm_spendlogtoolindex.create_many.await_count == 2
|
||||
prisma.db.batch_.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
batcher.litellm_dailytoolspend.upsert.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ambiguous_index_error_drops_the_batch_without_touching_the_rollup(self):
|
||||
prisma, _ = _prisma_with_batcher()
|
||||
prisma.db.litellm_spendlogtoolindex.create_many = AsyncMock(side_effect=httpx.ReadTimeout("ambiguous"))
|
||||
prisma.replica_db = prisma.db
|
||||
with pytest.raises(httpx.ReadTimeout):
|
||||
await flush_tool_usage_transactions(prisma_client=prisma, transactions=[_transaction("r1")])
|
||||
prisma.db.litellm_spendlogtoolindex.create_many.assert_awaited_once()
|
||||
|
|
@ -326,6 +331,7 @@ class TestFlushToolUsageTransactions:
|
|||
prisma, _ = _prisma_with_batcher()
|
||||
await flush_tool_usage_transactions(prisma_client=prisma, transactions=[])
|
||||
prisma.db.batch_.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_connection_errors_retry_and_succeed(self, monkeypatch):
|
||||
|
|
@ -364,6 +370,7 @@ class TestFlushToolUsageTransactions:
|
|||
with pytest.raises(ValueError, match="bad data"):
|
||||
await flush_tool_usage_transactions(prisma_client=prisma, transactions=[_transaction("r1")])
|
||||
prisma.db.batch_.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("ambiguous_error", ["ReadTimeout", "ReadError"])
|
||||
|
|
@ -377,3 +384,4 @@ class TestFlushToolUsageTransactions:
|
|||
with pytest.raises((httpx.ReadTimeout, httpx.ReadError)):
|
||||
await flush_tool_usage_transactions(prisma_client=prisma, transactions=[_transaction("r1")])
|
||||
prisma.db.batch_.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ def _make_prisma(
|
|||
"""Return a mock prisma_client with litellm_tooltable.upsert, find_many, find_unique."""
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_tooltable = MagicMock()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_tooltable.upsert = AsyncMock(return_value=upsert_return)
|
||||
prisma.db.litellm_tooltable.find_many = AsyncMock(
|
||||
return_value=find_many_rows if find_many_rows is not None else []
|
||||
|
|
@ -72,6 +73,7 @@ async def test_batch_upsert_tools_calls_upsert():
|
|||
items = [{"tool_name": "tool_a", "origin": "mcp_server", "created_by": None}]
|
||||
await batch_upsert_tools(prisma, items)
|
||||
prisma.db.litellm_tooltable.upsert.assert_awaited_once()
|
||||
prisma.replica_db = prisma.db
|
||||
call_kw = prisma.db.litellm_tooltable.upsert.call_args.kwargs
|
||||
assert call_kw["where"] == {"tool_name": "tool_a"}
|
||||
assert call_kw["data"]["create"]["tool_name"] == "tool_a"
|
||||
|
|
@ -88,6 +90,7 @@ async def test_batch_upsert_tools_empty_list():
|
|||
prisma = _make_prisma()
|
||||
await batch_upsert_tools(prisma, [])
|
||||
prisma.db.litellm_tooltable.upsert.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -96,6 +99,7 @@ async def test_batch_upsert_tools_skips_empty_names():
|
|||
items = [{"tool_name": "", "origin": None}, {"tool_name": None}] # type: ignore[list-item]
|
||||
await batch_upsert_tools(prisma, items)
|
||||
prisma.db.litellm_tooltable.upsert.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -128,6 +132,7 @@ async def test_list_tools_no_filter():
|
|||
assert result[0].tool_name == "tool_a"
|
||||
assert result[0].call_count == 5
|
||||
prisma.db.litellm_tooltable.find_many.assert_awaited_once()
|
||||
prisma.replica_db = prisma.db
|
||||
call_kw = prisma.db.litellm_tooltable.find_many.call_args.kwargs
|
||||
assert call_kw["where"] == {}
|
||||
assert call_kw["order"] == {"created_at": "desc"}
|
||||
|
|
@ -161,6 +166,7 @@ async def test_get_tool_found():
|
|||
prisma.db.litellm_tooltable.find_unique.assert_awaited_once_with(
|
||||
where={"tool_name": "my_tool"}
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -185,6 +191,7 @@ async def test_update_tool_policy_calls_upsert_then_get_tool():
|
|||
assert result is not None
|
||||
assert result.input_policy == "blocked"
|
||||
prisma.db.litellm_tooltable.upsert.assert_awaited_once()
|
||||
prisma.replica_db = prisma.db
|
||||
call_kw = prisma.db.litellm_tooltable.upsert.call_args.kwargs
|
||||
assert call_kw["where"] == {"tool_name": "my_tool"}
|
||||
assert call_kw["data"]["update"]["input_policy"] == "blocked"
|
||||
|
|
@ -213,6 +220,7 @@ async def test_get_tools_by_names_returns_policy_map():
|
|||
prisma.db.litellm_tooltable.find_many.assert_awaited_once_with(
|
||||
where={"tool_name": {"in": ["tool_a", "tool_b"]}}
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -221,6 +229,7 @@ async def test_get_tools_by_names_empty_list():
|
|||
result = await get_tools_by_names(prisma, [])
|
||||
assert result == {}
|
||||
prisma.db.litellm_tooltable.find_many.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
# --- ToolPolicyRegistry ---
|
||||
|
|
@ -256,6 +265,7 @@ async def test_tool_policy_registry_sync_and_get_effective_policies():
|
|||
_mock_tool_row("tool_c", input_policy="untrusted"),
|
||||
]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_objectpermissiontable.find_many = AsyncMock(
|
||||
return_value=[
|
||||
_mock_perm_row("op-key-1", ["tool_a"]),
|
||||
|
|
@ -310,6 +320,7 @@ async def test_sync_tool_policy_from_db_retries_on_transport_error_first_read():
|
|||
mock_prisma_client.db.litellm_tooltable.find_many = AsyncMock(
|
||||
side_effect=_flaky_find_many
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_many = AsyncMock(
|
||||
return_value=[]
|
||||
)
|
||||
|
|
@ -346,6 +357,7 @@ async def test_sync_tool_policy_from_db_retries_on_transport_error_second_read()
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_tooltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_many = AsyncMock(
|
||||
side_effect=_flaky_perms_find_many
|
||||
)
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ def mock_prisma_client(mocker):
|
|||
mock_client = mocker.Mock()
|
||||
# Create async mocks for the database methods
|
||||
mock_client.db = mocker.Mock()
|
||||
mock_client.replica_db = mock_client.db
|
||||
mock_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_client.db.litellm_guardrailstable.find_many = AsyncMock(
|
||||
return_value=[MOCK_DB_GUARDRAIL]
|
||||
|
|
@ -175,6 +176,7 @@ async def test_list_guardrails_v2_skips_stale_db_backed_in_memory_entries(mocker
|
|||
}
|
||||
mock_prisma_client = mocker.Mock()
|
||||
mock_prisma_client.db = mocker.Mock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -211,6 +213,7 @@ async def test_get_guardrail_info_404s_stale_db_backed_entry(
|
|||
mock_prisma_client.db.litellm_guardrailstable.find_unique = AsyncMock(
|
||||
return_value=None
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
# In-memory still has it, but it's tagged as 'db' (stale, awaiting reconcile)
|
||||
mock_in_memory_handler.get_source.return_value = "db"
|
||||
|
||||
|
|
@ -240,6 +243,7 @@ async def test_list_guardrails_v2_masks_sensitive_data_in_db_guardrails(mocker):
|
|||
|
||||
mock_prisma_client = mocker.Mock()
|
||||
mock_prisma_client.db = mocker.Mock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(
|
||||
return_value=[db_guardrail_with_secrets]
|
||||
|
|
@ -295,6 +299,7 @@ async def test_list_guardrails_v2_masks_sensitive_data_in_config_guardrails(mock
|
|||
|
||||
mock_prisma_client = mocker.Mock()
|
||||
mock_prisma_client.db = mocker.Mock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -354,6 +359,7 @@ async def test_list_guardrails_v2_admin_viewer_sees_guardrails_of_teams_they_are
|
|||
|
||||
mock_prisma_client = mocker.Mock()
|
||||
mock_prisma_client.db = mocker.Mock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(
|
||||
return_value=[other_team_guardrail]
|
||||
|
|
@ -403,6 +409,7 @@ async def test_list_guardrails_v2_masks_sensitive_data_for_admin_viewer(mocker):
|
|||
|
||||
mock_prisma_client = mocker.Mock()
|
||||
mock_prisma_client.db = mocker.Mock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_guardrailstable = mocker.Mock()
|
||||
mock_prisma_client.db.litellm_guardrailstable.find_many = AsyncMock(
|
||||
return_value=[other_team_guardrail_with_secrets]
|
||||
|
|
@ -465,6 +472,7 @@ async def test_get_guardrail_info_from_config(
|
|||
mock_prisma_client.db.litellm_guardrailstable.find_unique = AsyncMock(
|
||||
return_value=None
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
response = await get_guardrail_info("test-config-guardrail")
|
||||
|
||||
|
|
@ -489,6 +497,7 @@ async def test_get_guardrail_info_not_found(
|
|||
mock_prisma_client.db.litellm_guardrailstable.find_unique = AsyncMock(
|
||||
return_value=None
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_in_memory_handler.get_guardrail_by_id.return_value = None
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
|
|
@ -1903,6 +1912,7 @@ async def test_register_guardrail_success(mocker):
|
|||
"""Register creates a row with status pending_review and returns guardrail_id."""
|
||||
mock_prisma = mocker.Mock()
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
created_row = mocker.Mock(
|
||||
guardrail_id="reg-123",
|
||||
guardrail_name=MOCK_REGISTER_REQUEST.guardrail_name,
|
||||
|
|
@ -1961,6 +1971,7 @@ async def test_register_guardrail_non_admin_cross_team_allowed(mocker):
|
|||
"""Non-admin may register for a team in their user.teams list even if the key's team_id differs."""
|
||||
mock_prisma = mocker.Mock()
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
created = mocker.Mock(
|
||||
guardrail_id="g1",
|
||||
guardrail_name=MOCK_REGISTER_REQUEST.guardrail_name,
|
||||
|
|
@ -2016,6 +2027,7 @@ async def test_register_guardrail_duplicate_name(mocker):
|
|||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(
|
||||
return_value={"guardrail_name": MOCK_REGISTER_REQUEST.guardrail_name}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_id="u1", user_email="a@b.com", team_id="team-1")
|
||||
|
||||
|
|
@ -2043,6 +2055,7 @@ async def test_list_guardrail_submissions_non_admin_scoped_to_own_teams(mocker):
|
|||
)
|
||||
find_many = AsyncMock(return_value=[own_team_row])
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mocker.patch(
|
||||
"litellm.proxy.guardrails.guardrail_endpoints._get_user_team_ids",
|
||||
|
|
@ -2068,6 +2081,7 @@ async def test_list_guardrail_submissions_non_admin_no_teams(mocker):
|
|||
mock_prisma = mocker.Mock()
|
||||
find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mocker.patch(
|
||||
"litellm.proxy.guardrails.guardrail_endpoints._get_user_team_ids",
|
||||
|
|
@ -2121,6 +2135,7 @@ async def test_list_guardrail_submissions_success(mocker):
|
|||
updated_at=datetime.now(),
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = AsyncMock(return_value=[row])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2140,6 +2155,7 @@ async def test_list_guardrail_submissions_returns_only_team_guardrails(mocker):
|
|||
mock_prisma = mocker.Mock()
|
||||
find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2181,6 +2197,7 @@ async def test_list_guardrail_submissions_team_id_filter(mocker):
|
|||
)
|
||||
find_many = AsyncMock(return_value=[row_abc, row_other])
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2199,6 +2216,7 @@ async def test_get_guardrail_submission_not_found(mocker):
|
|||
"""Get submission returns 404 when guardrail_id does not exist."""
|
||||
mock_prisma = mocker.Mock()
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2224,6 +2242,7 @@ async def test_get_guardrail_submission_non_admin_own_team(mocker):
|
|||
updated_at=datetime.now(),
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mocker.patch(
|
||||
"litellm.proxy.guardrails.guardrail_endpoints._get_user_team_ids",
|
||||
|
|
@ -2254,6 +2273,7 @@ async def test_get_guardrail_submission_non_admin_other_team_forbidden(mocker):
|
|||
updated_at=datetime.now(),
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mocker.patch(
|
||||
"litellm.proxy.guardrails.guardrail_endpoints._get_user_team_ids",
|
||||
|
|
@ -2283,6 +2303,7 @@ async def test_get_guardrail_submission_admin_viewer_other_team_allowed(mocker):
|
|||
updated_at=datetime.now(),
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mock_get_user_team_ids = mocker.patch(
|
||||
"litellm.proxy.guardrails.guardrail_endpoints._get_user_team_ids",
|
||||
|
|
@ -2315,6 +2336,7 @@ async def test_approve_guardrail_submission_success(mocker):
|
|||
guardrail_info={},
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_guardrailstable.update = AsyncMock()
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
mock_handler = mocker.Mock()
|
||||
|
|
@ -2340,6 +2362,7 @@ async def test_approve_guardrail_submission_not_pending(mocker):
|
|||
mock_prisma = mocker.Mock()
|
||||
row = mocker.Mock(guardrail_id="x", guardrail_name="y", status="active")
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2354,6 +2377,7 @@ async def test_reject_guardrail_submission_success(mocker):
|
|||
mock_prisma = mocker.Mock()
|
||||
row = mocker.Mock(guardrail_id="rej-1", guardrail_name="r", status="pending_review")
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_guardrailstable.update = AsyncMock()
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
|
@ -2374,6 +2398,7 @@ async def test_reject_guardrail_submission_not_pending(mocker):
|
|||
guardrail_id="already-active", guardrail_name="g", status="active"
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2430,6 +2455,7 @@ async def test_register_guardrail_accepts_valid_https_url(mocker):
|
|||
"""Register accepts valid https api_base URLs."""
|
||||
mock_prisma = mocker.Mock()
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
created_row = mocker.Mock(
|
||||
guardrail_id="valid-url-123",
|
||||
guardrail_name="valid-guard",
|
||||
|
|
@ -2470,6 +2496,7 @@ async def test_approve_guardrail_init_failure_returns_warning(mocker):
|
|||
guardrail_info={},
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_guardrailstable.update = AsyncMock()
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -2507,6 +2534,7 @@ async def test_approve_guardrail_no_warning_on_success(mocker):
|
|||
guardrail_info={},
|
||||
)
|
||||
mock_prisma.db.litellm_guardrailstable.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_guardrailstable.update = AsyncMock()
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -2530,6 +2558,7 @@ async def test_list_submissions_single_db_query(mocker):
|
|||
mock_prisma = mocker.Mock()
|
||||
find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
@ -2568,6 +2597,7 @@ async def test_list_submissions_summary_counts_unaffected_by_filters(mocker):
|
|||
)
|
||||
all_rows = [pending_row, active_row]
|
||||
mock_prisma.db.litellm_guardrailstable.find_many = AsyncMock(return_value=all_rows)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mocker.patch("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
user = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
|
||||
|
|
|
|||
|
|
@ -934,6 +934,7 @@ class TestScanOnlyToolResultsInitRefusal:
|
|||
async def test_update_guardrail_in_db_raises_when_row_missing():
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_guardrailstable.update = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
with pytest.raises(
|
||||
Exception,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ def _prisma(
|
|||
) -> MagicMock:
|
||||
client = MagicMock()
|
||||
db = client.db
|
||||
client.replica_db = client.db
|
||||
db.litellm_guardrailstable.find_many = AsyncMock(return_value=find_many or [])
|
||||
db.litellm_guardrailstable.find_unique = AsyncMock(return_value=find_unique)
|
||||
db.litellm_dailyguardrailmetrics.find_many = AsyncMock(return_value=metrics or [])
|
||||
|
|
@ -309,6 +310,7 @@ def _units_table_missing() -> TableNotFoundError:
|
|||
async def test_overview_degrades_units_to_empty_when_units_table_is_missing():
|
||||
prisma = _prisma(metrics=[_metric("yaml-pii", requests=4, passed=3, blocked=1)])
|
||||
prisma.db.litellm_dailyguardrailusageunits.find_many = AsyncMock(side_effect=_units_table_missing())
|
||||
prisma.replica_db = prisma.db
|
||||
handler = _config_handler(_yaml_guardrail(guardrail_id="yaml-uuid", name="yaml-pii"))
|
||||
p1, p2 = _patches(prisma, handler)
|
||||
with p1, p2:
|
||||
|
|
@ -443,6 +445,7 @@ async def test_detail_breaks_cost_down_by_unit_day_team_and_key():
|
|||
async def test_detail_degrades_units_to_empty_when_units_table_is_missing():
|
||||
prisma = _prisma(metrics=[_metric("yaml-pii", requests=4, passed=3, blocked=1)])
|
||||
prisma.db.litellm_dailyguardrailusageunits.find_many = AsyncMock(side_effect=_units_table_missing())
|
||||
prisma.replica_db = prisma.db
|
||||
handler = _config_handler(_yaml_guardrail())
|
||||
p1, p2 = _patches(prisma, handler)
|
||||
with p1, p2:
|
||||
|
|
@ -526,6 +529,7 @@ async def test_logs_reports_flagged_action_for_guardrail_flagged_status():
|
|||
_spend_log("r-block", "guardrail_intervened"),
|
||||
]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
p1, p2 = _patches(prisma, _config_handler())
|
||||
with p1, p2:
|
||||
resp = await guardrails_usage_logs(
|
||||
|
|
@ -565,6 +569,7 @@ async def test_logs_reports_post_call_flag_when_pre_call_allowed():
|
|||
prisma.db.litellm_spendlogs.find_many = AsyncMock(
|
||||
return_value=[_spend_log("r-post-flag", "success", "guardrail_flagged")]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
p1, p2 = _patches(prisma, _config_handler())
|
||||
with p1, p2:
|
||||
resp = await guardrails_usage_logs(
|
||||
|
|
@ -649,6 +654,7 @@ async def test_policies_overview_returns_a_full_row_and_totals():
|
|||
metric.policy_id = "pol-1"
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[policy])
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_dailypolicymetrics.find_many = AsyncMock(return_value=[metric])
|
||||
p1, p2 = _patches(prisma, _config_handler())
|
||||
with p1, p2:
|
||||
|
|
@ -702,6 +708,7 @@ async def test_logs_report_not_run_entries_as_not_run_not_passed():
|
|||
}
|
||||
prisma = _prisma(find_unique=_db_row(), index_find_many=[index_row])
|
||||
prisma.db.litellm_spendlogs.find_many = AsyncMock(return_value=[spend_log])
|
||||
prisma.replica_db = prisma.db
|
||||
handler = _config_handler()
|
||||
p1, p2 = _patches(prisma, handler)
|
||||
with p1, p2:
|
||||
|
|
@ -732,6 +739,7 @@ async def test_logs_action_passed_filter_excludes_not_run_entries():
|
|||
spend_log.metadata = {"guardrail_information": [{"guardrail_name": "db-1", "guardrail_status": "not_run"}]}
|
||||
prisma = _prisma(find_unique=_db_row(), index_find_many=[index_row])
|
||||
prisma.db.litellm_spendlogs.find_many = AsyncMock(return_value=[spend_log])
|
||||
prisma.replica_db = prisma.db
|
||||
handler = _config_handler()
|
||||
p1, p2 = _patches(prisma, handler)
|
||||
with p1, p2:
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ from litellm.proxy.guardrails.usage_tracking import (
|
|||
def _prisma() -> MagicMock:
|
||||
client = MagicMock()
|
||||
db = client.db
|
||||
client.replica_db = client.db
|
||||
db.litellm_dailyguardrailmetrics.upsert = AsyncMock()
|
||||
db.litellm_dailyguardrailusageunits.upsert = AsyncMock()
|
||||
db.litellm_spendlogguardrailindex.create_many = AsyncMock()
|
||||
|
|
@ -142,6 +143,7 @@ async def test_one_failing_upsert_does_not_drop_remaining_writes():
|
|||
"""
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_dailyguardrailmetrics.upsert.side_effect = httpx.ConnectError("db down")
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_dailyguardrailusageunits.upsert.side_effect = [httpx.ConnectError("db down"), None, None]
|
||||
sleep, _ = _fake_sleep()
|
||||
logs = [
|
||||
|
|
@ -167,6 +169,7 @@ async def test_transient_upsert_failure_is_retried_with_backoff_for_failed_rows_
|
|||
"""
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_dailyguardrailusageunits.upsert.side_effect = [httpx.ConnectError("blip"), None, None]
|
||||
prisma.replica_db = prisma.db
|
||||
sleep, delays = _fake_sleep()
|
||||
logs = [
|
||||
_payload("r1", usage={"topicPolicyUnits": 1}),
|
||||
|
|
@ -185,6 +188,7 @@ async def test_transient_upsert_failure_is_retried_with_backoff_for_failed_rows_
|
|||
async def test_persistent_upsert_failure_stops_after_three_retries():
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_dailyguardrailmetrics.upsert.side_effect = httpx.ConnectError("db down")
|
||||
prisma.replica_db = prisma.db
|
||||
sleep, delays = _fake_sleep()
|
||||
pending = PendingRollups()
|
||||
|
||||
|
|
@ -215,6 +219,7 @@ async def test_retry_exhausted_rows_are_requeued_and_land_on_the_next_flush():
|
|||
pending = PendingRollups()
|
||||
down = _prisma()
|
||||
down.db.litellm_dailyguardrailmetrics.upsert.side_effect = httpx.ConnectError("db down")
|
||||
down.replica_db = down.db
|
||||
down.db.litellm_dailyguardrailusageunits.upsert.side_effect = httpx.ConnectError("db down")
|
||||
sleep, _ = _fake_sleep()
|
||||
|
||||
|
|
@ -249,6 +254,7 @@ async def test_ambiguous_failures_are_never_requeued():
|
|||
pending = PendingRollups()
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_dailyguardrailusageunits.upsert.side_effect = httpx.ReadTimeout("maybe committed")
|
||||
prisma.replica_db = prisma.db
|
||||
sleep, delays = _fake_sleep()
|
||||
|
||||
await process_spend_logs_guardrail_usage(
|
||||
|
|
@ -296,6 +302,7 @@ async def test_post_send_failure_is_never_retried_so_increments_cannot_double_co
|
|||
httpx.ConnectError("refused"),
|
||||
None,
|
||||
]
|
||||
prisma.replica_db = prisma.db
|
||||
sleep, delays = _fake_sleep()
|
||||
logs = [
|
||||
_payload("r1", usage={"topicPolicyUnits": 1}),
|
||||
|
|
@ -314,6 +321,7 @@ async def test_post_send_failure_is_never_retried_so_increments_cannot_double_co
|
|||
async def test_generic_upsert_exception_is_terminal_for_that_row_only():
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_dailyguardrailmetrics.upsert.side_effect = RuntimeError("constraint violation")
|
||||
prisma.replica_db = prisma.db
|
||||
sleep, delays = _fake_sleep()
|
||||
|
||||
await process_spend_logs_guardrail_usage(prisma, [_payload("r1", usage={"topicPolicyUnits": 1})], sleep=sleep)
|
||||
|
|
@ -565,6 +573,7 @@ async def test_requeued_cost_is_added_to_the_next_flush():
|
|||
pending = PendingRollups()
|
||||
down = _prisma()
|
||||
down.db.litellm_dailyguardrailmetrics.upsert.side_effect = httpx.ConnectError("db down")
|
||||
down.replica_db = down.db
|
||||
down.db.litellm_dailyguardrailusageunits.upsert.side_effect = httpx.ConnectError("db down")
|
||||
sleep, _ = _fake_sleep()
|
||||
|
||||
|
|
@ -647,6 +656,7 @@ async def test_one_failing_index_statement_does_not_drop_the_others_or_the_rollu
|
|||
monkeypatch.setattr(usage_tracking, "SPEND_LOG_WRITE_BATCH_MAX_ROWS", 100)
|
||||
prisma = _prisma()
|
||||
prisma.db.litellm_spendlogguardrailindex.create_many.side_effect = [None, httpx.ReadTimeout("ambiguous"), None]
|
||||
prisma.replica_db = prisma.db
|
||||
guardrail_ids = tuple(f"guard-{i}" for i in range(50))
|
||||
logs = [_fan_out_payload(f"r{i}", guardrail_ids) for i in range(5)]
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ class FakeUserTable:
|
|||
class FakePrismaClient:
|
||||
def __init__(self, rows: List[Dict[str, Any]]):
|
||||
self.db = SimpleNamespace(litellm_usertable=FakeUserTable(rows))
|
||||
self.replica_db = self.db
|
||||
|
||||
|
||||
async def _run_created_hook(prisma_client: FakePrismaClient, audit_log: AsyncMock) -> None:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ def _build_prisma_with_keys(user_keys, mock_user=None, updated_user=None):
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
if mock_user is not None:
|
||||
mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user)
|
||||
if updated_user is not None:
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ async def test_patch_user_updates_fields():
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user)
|
||||
mock_db.litellm_usertable.update = AsyncMock(side_effect=mock_update)
|
||||
mock_db.litellm_teamtable.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -105,6 +106,7 @@ async def test_patch_user_manages_group_memberships():
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user)
|
||||
mock_db.litellm_usertable.update = AsyncMock(side_effect=mock_update)
|
||||
mock_db.litellm_teamtable.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -196,6 +198,7 @@ async def test_patch_user_deprovision_without_path():
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user)
|
||||
mock_db.litellm_usertable.update = AsyncMock(side_effect=mock_update)
|
||||
mock_db.litellm_verificationtoken.find_many = AsyncMock(return_value=[])
|
||||
|
|
@ -275,6 +278,7 @@ async def test_patch_user_multiple_fields_without_path():
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
mock_db.litellm_usertable.find_unique = AsyncMock(return_value=mock_user)
|
||||
mock_db.litellm_usertable.update = AsyncMock(side_effect=mock_update)
|
||||
mock_db.litellm_verificationtoken.find_many = AsyncMock(return_value=[])
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ def mock_prisma_client():
|
|||
mock_client = MagicMock()
|
||||
mock_db = MagicMock()
|
||||
mock_client.db = mock_db
|
||||
mock_client.replica_db = mock_client.db
|
||||
|
||||
mock_find_unique = AsyncMock()
|
||||
mock_db.litellm_teamtable.find_unique = mock_find_unique
|
||||
|
|
|
|||
|
|
@ -629,6 +629,7 @@ async def test_get_all_search_tools_from_db_retries_on_transport_error():
|
|||
mock_prisma_client.db.litellm_searchtoolstable.find_many = AsyncMock(
|
||||
side_effect=_flaky_find_many
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.attempt_db_reconnect = AsyncMock(return_value=True)
|
||||
mock_prisma_client._db_auth_reconnect_timeout_seconds = 2.0
|
||||
mock_prisma_client._db_auth_reconnect_lock_timeout_seconds = 0.1
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ def client_and_mocks(monkeypatch):
|
|||
tx=mock_tx,
|
||||
)
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -208,6 +209,7 @@ def test_create_access_group_success(client_and_mocks, base_path, payload):
|
|||
"""Create access group with various payloads returns 201."""
|
||||
client, mock_prisma, mock_table, *_ = client_and_mocks
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[_make_team_record("team-1")])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
resp = client.post(base_path, json=payload)
|
||||
assert resp.status_code == 201
|
||||
|
|
@ -303,6 +305,7 @@ def test_list_access_groups_success_empty(client_and_mocks, base_path):
|
|||
assert resp.json() == []
|
||||
mock_table.find_many.assert_awaited_once()
|
||||
mock_prisma.db.litellm_teamtable.find_many.assert_not_awaited()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.parametrize("base_path", ACCESS_GROUP_PATHS)
|
||||
|
|
@ -454,6 +457,7 @@ def test_get_access_group_empty_column_and_no_teams_returns_empty(client_and_moc
|
|||
|
||||
mock_table.find_unique = AsyncMock(return_value=_make_access_group_record(access_group_id="ag-123"))
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
resp = client.get("/v1/access_group/ag-123")
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -1436,6 +1440,7 @@ def test_update_access_group_null_assigned_ids_treated_as_empty(client_and_mocks
|
|||
|
||||
def _mock_resource_tables(mock_prisma, *, mcp_servers=(), agents=(), teams=(), keys=()):
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=list(mcp_servers))
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=list(agents))
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=list(teams))
|
||||
mock_prisma.db.litellm_verificationtoken.find_many = AsyncMock(return_value=list(keys))
|
||||
|
|
@ -1550,6 +1555,7 @@ def test_list_access_groups_skips_lookups_when_nothing_to_resolve(client_and_moc
|
|||
assert all(group["access_mcp_servers"] == [] and group["assigned_keys"] == [] for group in resp.json())
|
||||
|
||||
mock_prisma.db.litellm_mcpservertable.find_many.assert_not_awaited()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_agentstable.find_many.assert_not_awaited()
|
||||
mock_prisma.db.litellm_verificationtoken.find_many.assert_not_awaited()
|
||||
|
||||
|
|
@ -1559,6 +1565,7 @@ def test_create_access_group_response_carries_resolved_names(client_and_mocks):
|
|||
client, mock_prisma, *_ = client_and_mocks
|
||||
team_record = _make_team_record("team-1", team_alias="Platform")
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
_mock_resource_tables(
|
||||
mock_prisma,
|
||||
mcp_servers=[_make_mcp_server_record("mcp-a", alias="GitHub")],
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ async def test_create_duplicate_access_group_fails():
|
|||
)
|
||||
]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
mock_user = UserAPIKeyAuth(
|
||||
user_id="test_admin",
|
||||
|
|
@ -103,6 +104,7 @@ async def test_create_access_group_with_model_ids_tags_only_specific_deployments
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_unique = AsyncMock(
|
||||
return_value=deploy_a
|
||||
)
|
||||
|
|
@ -172,6 +174,7 @@ async def test_create_access_group_with_model_names_tags_all_deployments():
|
|||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(
|
||||
side_effect=[[], [deploy_a, deploy_b, deploy_c]]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
|
||||
mock_user = UserAPIKeyAuth(
|
||||
|
|
@ -217,6 +220,7 @@ async def test_create_access_group_model_ids_takes_priority_over_model_names():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_unique = AsyncMock(
|
||||
return_value=deploy_a
|
||||
)
|
||||
|
|
@ -298,6 +302,7 @@ async def test_create_access_group_invalid_model_id_returns_400():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
mock_user = UserAPIKeyAuth(
|
||||
|
|
@ -342,6 +347,7 @@ async def test_create_access_group_surfaces_dropped_models():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_unique = AsyncMock(return_value=deploy_a)
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
|
||||
|
|
@ -385,6 +391,7 @@ async def test_create_access_group_trusts_reload_snapshot_over_post_lock_fresh_r
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_unique = AsyncMock(return_value=deploy_a)
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
|
||||
|
|
@ -421,6 +428,7 @@ async def test_tag_deployment_parses_string_model_info_and_refuses_corrupt():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
pair = await _tag_deployment_with_access_group(
|
||||
model_id="deploy-str",
|
||||
|
|
@ -452,6 +460,7 @@ async def test_delete_access_group_ignores_models_that_were_already_dead():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[deploy_broken])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
mock_prisma.db.litellm_modelaccessgroupbudgettable.delete = AsyncMock(return_value=None)
|
||||
|
||||
|
|
@ -514,6 +523,7 @@ async def test_create_access_group_read_through_recovers_model_created_on_siblin
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(side_effect=[[db_row], [], [db_row]])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.update = AsyncMock()
|
||||
|
||||
with (
|
||||
|
|
@ -560,6 +570,7 @@ async def test_create_access_group_model_missing_everywhere_still_400s():
|
|||
)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
with (
|
||||
patch("litellm.proxy.proxy_server.llm_router", mock_router),
|
||||
|
|
@ -714,6 +725,7 @@ class _FakePrismaClient:
|
|||
litellm_modelaccessgroupbudgettable=self.access_group_budget_table,
|
||||
litellm_proxymodeltable=self.model_table,
|
||||
)
|
||||
self.replica_db = self.db
|
||||
|
||||
def jsonify_object(self, data):
|
||||
return dict(data)
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ async def test_team_activity_requires_admin_on_every_requested_team():
|
|||
_make_team("team-B", admin_user_ids=["bob"]),
|
||||
]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
user_keys = MagicMock(token="alice-key-1")
|
||||
prisma.db.litellm_verificationtoken.find_many = AsyncMock(return_value=[user_keys])
|
||||
|
||||
|
|
@ -123,6 +124,7 @@ async def test_team_activity_full_view_when_admin_of_all_requested_teams():
|
|||
_make_team("team-B", admin_user_ids=["alice"]),
|
||||
]
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
user_info = MagicMock()
|
||||
user_info.teams = ["team-A", "team-B"]
|
||||
|
|
@ -171,6 +173,7 @@ async def test_agent_activity_admin_unscoped():
|
|||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=[])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
captured = {}
|
||||
|
||||
|
|
@ -216,6 +219,7 @@ async def test_agent_activity_non_admin_no_perms_falls_back_to_owned():
|
|||
# First call: lookup of owned agents (created_by=alice).
|
||||
# Second call: agent_metadata fetch for the resolved set.
|
||||
prisma.db.litellm_agentstable.find_many = AsyncMock(side_effect=[owned, owned])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
captured = {}
|
||||
|
||||
|
|
@ -264,6 +268,7 @@ async def test_agent_activity_non_admin_intersects_explicit_agent_ids():
|
|||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=[])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
captured = {}
|
||||
|
||||
|
|
@ -314,6 +319,7 @@ async def test_agent_activity_keyless_caller_does_not_query_created_by_null():
|
|||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=[])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
fake_get_daily = AsyncMock()
|
||||
|
||||
|
|
@ -359,6 +365,7 @@ async def test_agent_activity_non_admin_no_access_returns_empty_page():
|
|||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_agentstable.find_many = AsyncMock(return_value=[])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
fake_get_daily = AsyncMock()
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ def client_and_mocks(monkeypatch):
|
|||
litellm_budgettable=mock_table,
|
||||
litellm_dailyspend=mock_table,
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Monkeypatch Mocked Prisma client into the server module
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ async def test_update_cache_settings_persists_url_precedence(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
|
||||
proxy_config = MagicMock()
|
||||
|
|
@ -260,6 +261,7 @@ async def test_get_cache_settings_masks_password_bearing_url():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=cache_row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
|
@ -385,6 +387,7 @@ class TestCacheSettingsManager:
|
|||
mock_cache_config = MagicMock()
|
||||
mock_cache_config.cache_settings = '{"type": "redis", "host": "localhost", "port": "6379"}'
|
||||
mock_prisma_client.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=mock_cache_config)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock proxy_config
|
||||
mock_proxy_config = MagicMock()
|
||||
|
|
@ -430,6 +433,7 @@ class TestCacheSettingsManager:
|
|||
mock_cache_config = MagicMock()
|
||||
mock_cache_config.cache_settings = '{"type": "redis", "host": "localhost", "port": "6379"}'
|
||||
mock_prisma_client.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=mock_cache_config)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock proxy_config
|
||||
mock_proxy_config = MagicMock()
|
||||
|
|
@ -468,6 +472,7 @@ class TestCacheSettingsManager:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_cacheconfig.find_unique = AsyncMock(side_effect=_flaky_find_unique)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.attempt_db_reconnect = AsyncMock(return_value=True)
|
||||
mock_prisma_client._db_auth_reconnect_timeout_seconds = 2.0
|
||||
mock_prisma_client._db_auth_reconnect_lock_timeout_seconds = 0.1
|
||||
|
|
@ -502,6 +507,7 @@ async def test_update_cache_settings_emits_audit_log_when_enabled(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
|
||||
proxy_config = MagicMock()
|
||||
|
|
@ -572,6 +578,7 @@ async def test_update_cache_settings_no_audit_when_disabled(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
|
||||
proxy_config = MagicMock()
|
||||
|
|
@ -800,6 +807,7 @@ async def test_get_cache_settings_falls_back_to_redis_env(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
|
@ -828,6 +836,7 @@ async def test_get_cache_settings_redacts_password_with_marker(monkeypatch):
|
|||
)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=cache_row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
||||
|
|
@ -857,6 +866,7 @@ async def test_get_cache_settings_url_mode_hides_env_discrete_fields(monkeypatch
|
|||
cache_row.cache_settings = {"type": "redis", "url": "redis://:pw@stored-host:6379/0"}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=cache_row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
||||
|
|
@ -896,6 +906,7 @@ async def test_update_preserves_stored_password_on_redacted_resubmit(monkeypatch
|
|||
existing.cache_settings = {"type": "redis", "host": "oldhost", "password": "realpw"}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
proxy_config = _mock_proxy_config_identity_crypto()
|
||||
|
||||
|
|
@ -929,6 +940,7 @@ async def test_update_drops_env_sourced_redacted_secret(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
proxy_config = _mock_proxy_config_identity_crypto()
|
||||
|
||||
|
|
@ -958,6 +970,7 @@ async def test_update_applies_new_password(monkeypatch):
|
|||
existing.cache_settings = json.dumps({"type": "redis", "host": "h", "password": "oldpw"})
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_cacheconfig.upsert = AsyncMock()
|
||||
proxy_config = _mock_proxy_config_identity_crypto()
|
||||
|
||||
|
|
@ -1028,6 +1041,7 @@ async def test_get_cache_settings_does_not_surface_non_display_env_credentials(m
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
||||
|
|
@ -1057,6 +1071,7 @@ async def test_test_cache_connection_does_not_log_plaintext_credentials(monkeypa
|
|||
existing.cache_settings = {"type": "redis", "host": "h", "port": "6379", "password": "realredispw"}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
||||
|
|
@ -1095,6 +1110,7 @@ async def test_test_cache_connection_does_not_replay_saved_password_to_new_host(
|
|||
existing.cache_settings = {"type": "redis", "host": "real-redis", "port": "6379", "password": "realredispw"}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_cacheconfig.find_unique = AsyncMock(return_value=existing)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
proxy_config = MagicMock()
|
||||
proxy_config._decrypt_db_variables = MagicMock(side_effect=lambda variables_dict: dict(variables_dict))
|
||||
|
||||
|
|
|
|||
|
|
@ -387,6 +387,7 @@ class TestTeamAdminCanInviteUser:
|
|||
|
||||
teams = [make_team(tid, tid in user_is_admin_in) for tid in admin_teams]
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=teams)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result = await _team_admin_can_invite_user(
|
||||
user_api_key_dict=mock_auth,
|
||||
|
|
@ -1072,6 +1073,7 @@ class TestTeamAdminCanInviteUserQuery:
|
|||
|
||||
find_many = AsyncMock(return_value=[make_team("t1"), make_team("t2")])
|
||||
mock_prisma.db.litellm_teamtable.find_many = find_many
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
await _team_admin_can_invite_user(
|
||||
user_api_key_dict=mock_auth,
|
||||
|
|
@ -1281,7 +1283,8 @@ async def test_router_weights_validate_current_deployment_scope(
|
|||
}])
|
||||
rows = [SimpleNamespace(model_id="id", model_name=stored_name, model_info=info)] if stored_name else []
|
||||
table = SimpleNamespace(find_many=AsyncMock(return_value=rows))
|
||||
db = SimpleNamespace(db=SimpleNamespace(litellm_proxymodeltable=table))
|
||||
tables = SimpleNamespace(litellm_proxymodeltable=table)
|
||||
db = SimpleNamespace(db=tables, replica_db=tables)
|
||||
validation = validate_router_settings_weights(
|
||||
{"weights": {"group": {"id": 1}}}, team_id="team", prisma_client=db, llm_router=router,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ def _make_mock_db():
|
|||
mock.delete = AsyncMock(return_value=None)
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_configoverrides = mock
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma, mock
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ def _prisma_with_general_settings(general_settings: dict | None) -> MagicMock:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config.upsert = AsyncMock()
|
||||
return mock_prisma
|
||||
|
||||
|
|
@ -267,6 +268,7 @@ async def test_update_rejects_settings_without_a_connection_target(monkeypatch):
|
|||
|
||||
assert exc_info.value.status_code == 400
|
||||
mock_prisma.db.litellm_config.upsert.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -650,6 +652,7 @@ async def test_update_refuses_a_config_owned_coordination_redis_block(monkeypatc
|
|||
assert refused.value.status_code == 400
|
||||
assert refused.value.detail["keys"] == ["coordination_redis"]
|
||||
mock_prisma.db.litellm_config.upsert.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ async def test_update_customer_with_budget_id(
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=mock_existing_customer
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
mock_updated_user = MagicMock()
|
||||
mock_updated_user.model_dump.return_value = {
|
||||
|
|
@ -125,6 +126,7 @@ async def test_update_customer_creates_budget_with_proper_relations(
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=mock_existing_customer
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock budget creation
|
||||
mock_created_budget = MagicMock()
|
||||
|
|
@ -183,6 +185,7 @@ async def test_update_customer_creates_budget_with_required_fields(
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=mock_existing_customer
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock budget creation
|
||||
mock_created_budget = MagicMock()
|
||||
|
|
@ -248,6 +251,7 @@ async def test_update_customer_budget_creation_with_fallback_admin(
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=mock_existing_customer
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock budget creation
|
||||
mock_created_budget = MagicMock()
|
||||
|
|
@ -305,6 +309,7 @@ async def test_update_customer_with_budget_id_and_creation_fields(
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=mock_existing_customer
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock budget creation
|
||||
mock_created_budget = MagicMock()
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ def test_update_customer_success(mock_prisma_client, mock_user_api_key_auth):
|
|||
|
||||
# Mock the find_first response
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=mock_end_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock the update response
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=updated_mock_end_user)
|
||||
|
|
@ -88,6 +89,7 @@ def test_update_customer_unblock(mock_prisma_client, mock_user_api_key_auth):
|
|||
updated_mock_end_user = LiteLLM_EndUserTable(user_id="test-user-1", blocked=False)
|
||||
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=mock_end_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=updated_mock_end_user)
|
||||
|
||||
response = client.post(
|
||||
|
|
@ -113,6 +115,7 @@ def test_update_customer_keeps_blocked_when_omitted(mock_prisma_client, mock_use
|
|||
updated_mock_end_user = LiteLLM_EndUserTable(user_id="test-user-1", blocked=True)
|
||||
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=mock_end_user)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=updated_mock_end_user)
|
||||
|
||||
response = client.post(
|
||||
|
|
@ -133,6 +136,7 @@ def test_update_customer_not_found(mock_prisma_client, mock_user_api_key_auth):
|
|||
"""
|
||||
# Mock the database response to return None (user not found)
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Test data
|
||||
test_data = {"user_id": "non-existent-user", "alias": "Test User"}
|
||||
|
|
@ -160,6 +164,7 @@ def test_info_customer_not_found(mock_prisma_client, mock_user_api_key_auth):
|
|||
"""
|
||||
# Mock the database response to return None (user not found)
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Make the request
|
||||
response = client.get(
|
||||
|
|
@ -183,6 +188,7 @@ def test_delete_customer_not_found(mock_prisma_client, mock_user_api_key_auth):
|
|||
"""
|
||||
# Mock the database response to return empty list (no users found)
|
||||
mock_prisma_client.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Test data
|
||||
test_data = {"user_ids": ["non-existent-user-1", "non-existent-user-2"]}
|
||||
|
|
@ -225,6 +231,7 @@ def test_error_schema_consistency(mock_prisma_client, mock_user_api_key_auth):
|
|||
|
||||
# Test /customer/info - not found error
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
response = client.get(
|
||||
"/customer/info?end_user_id=non-existent",
|
||||
headers={"Authorization": "Bearer test-key"},
|
||||
|
|
@ -286,6 +293,7 @@ def test_customer_endpoints_error_schema_consistency(mock_prisma_client, mock_us
|
|||
# Scenario 1: GET /end_user/info with non-existent user
|
||||
# Should return 404 with proper error schema
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
response1 = client.get(
|
||||
"/end_user/info?end_user_id=fake-test-end-user-michaels-local-testng",
|
||||
|
|
@ -386,6 +394,7 @@ def test_update_customer_response_preserves_budget_id(mock_prisma_client, mock_u
|
|||
existing = LiteLLM_EndUserTable(user_id="cust-1", blocked=False)
|
||||
updated = LiteLLM_EndUserTable(user_id="cust-1", blocked=False, budget_id="budget-123")
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=existing)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=updated)
|
||||
|
||||
response = client.post(
|
||||
|
|
@ -444,6 +453,7 @@ def test_update_customer_budget_omission_and_null_preserve_existing_budget(
|
|||
return LiteLLM_BudgetTable(budget_id="budget-1", max_budget=budget_state.max_budget)
|
||||
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=end_user_row())
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_budgettable.update = AsyncMock(side_effect=update_budget)
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(side_effect=lambda **_: response_row())
|
||||
|
||||
|
|
@ -488,6 +498,7 @@ def test_update_customer_response_keeps_nested_budget_server_fields(mock_prisma_
|
|||
},
|
||||
}
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=existing)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=raw_row)
|
||||
|
||||
response = client.post(
|
||||
|
|
@ -512,6 +523,7 @@ def test_block_customer_success_serializes_through_response_model(mock_prisma_cl
|
|||
"""
|
||||
blocked_row = LiteLLM_EndUserTable(user_id="blocked-1", blocked=True)
|
||||
mock_prisma_client.db.litellm_endusertable.upsert = AsyncMock(return_value=blocked_row)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
response = client.post(
|
||||
"/customer/block",
|
||||
|
|
@ -535,6 +547,7 @@ def test_delete_customer_success_serializes_through_response_model(mock_prisma_c
|
|||
LiteLLM_EndUserTable(user_id="u2", blocked=False),
|
||||
]
|
||||
mock_prisma_client.db.litellm_endusertable.find_many = AsyncMock(return_value=existing)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.delete_many = AsyncMock(return_value=2)
|
||||
|
||||
response = client.post(
|
||||
|
|
@ -560,6 +573,7 @@ async def test_get_customer_daily_activity_admin_param_passing(monkeypatch):
|
|||
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.db.litellm_endusertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
mocked_response = MagicMock(name="SpendAnalyticsPaginatedResponse")
|
||||
|
|
@ -612,6 +626,7 @@ async def test_get_customer_daily_activity_with_end_user_aliases(monkeypatch):
|
|||
mock_end_user2.alias = "Customer Two"
|
||||
|
||||
mock_prisma_client.db.litellm_endusertable.find_many = AsyncMock(return_value=[mock_end_user1, mock_end_user2])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
mocked_response = MagicMock(name="SpendAnalyticsPaginatedResponse")
|
||||
|
|
@ -838,6 +853,7 @@ def _row(dump: dict) -> MagicMock:
|
|||
|
||||
def test_char_info_body(mock_prisma_client, mock_user_api_key_auth):
|
||||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
response = client.get("/customer/info?end_user_id=c1", headers={"Authorization": "Bearer k"})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == _EXPECTED_CUSTOMER
|
||||
|
|
@ -845,6 +861,7 @@ def test_char_info_body(mock_prisma_client, mock_user_api_key_auth):
|
|||
|
||||
def test_char_list_body(mock_prisma_client, mock_user_api_key_auth):
|
||||
mock_prisma_client.db.litellm_endusertable.find_many = AsyncMock(return_value=[_row(_FULL_DB_ROW)])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
response = client.get("/customer/list", headers={"Authorization": "Bearer k"})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [_EXPECTED_CUSTOMER]
|
||||
|
|
@ -852,6 +869,7 @@ def test_char_list_body(mock_prisma_client, mock_user_api_key_auth):
|
|||
|
||||
def test_char_new_body(mock_prisma_client, mock_user_api_key_auth):
|
||||
mock_prisma_client.db.litellm_endusertable.create = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
response = client.post("/customer/new", json={"user_id": "c1"}, headers={"Authorization": "Bearer k"})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == _EXPECTED_CUSTOMER
|
||||
|
|
@ -864,6 +882,7 @@ def test_customer_new_rejects_a_duration_that_never_advances(
|
|||
"""A zero-length window resets to "now", leaving the customer's budget row
|
||||
permanently due for the reset job to re-read every tick."""
|
||||
mock_prisma_client.db.litellm_endusertable.create = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
response = client.post(
|
||||
"/customer/new",
|
||||
|
|
@ -878,6 +897,7 @@ def test_customer_new_rejects_a_duration_that_never_advances(
|
|||
|
||||
def test_customer_new_accepts_a_normal_duration(mock_prisma_client, mock_user_api_key_auth):
|
||||
mock_prisma_client.db.litellm_endusertable.create = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_budgettable.create = AsyncMock(
|
||||
return_value=_row({"budget_id": "b1", "max_budget": 10.0})
|
||||
)
|
||||
|
|
@ -895,6 +915,7 @@ def test_char_update_body(mock_prisma_client, mock_user_api_key_auth):
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=_row({"user_id": "c1", "blocked": False})
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
response = client.post(
|
||||
"/customer/update",
|
||||
|
|
@ -912,6 +933,7 @@ def test_char_delete_body(mock_prisma_client, mock_user_api_key_auth):
|
|||
LiteLLM_EndUserTable(user_id="c2", blocked=False),
|
||||
]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.delete_many = AsyncMock(return_value=2)
|
||||
response = client.post(
|
||||
"/customer/delete",
|
||||
|
|
@ -963,6 +985,7 @@ def test_customer_new_invalidates_end_user_and_registry_caches(mock_prisma_clien
|
|||
budget or block goes unenforced until the TTL expires.
|
||||
"""
|
||||
mock_prisma_client.db.litellm_endusertable.create = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with _end_user_cache_doubles() as (recording_cache, mock_publish):
|
||||
response = client.post(
|
||||
|
|
@ -981,6 +1004,7 @@ def test_customer_update_invalidates_end_user_and_registry_caches(mock_prisma_cl
|
|||
mock_prisma_client.db.litellm_endusertable.find_first = AsyncMock(
|
||||
return_value=_row({"user_id": "c1", "blocked": False})
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.update = AsyncMock(return_value=_row(_FULL_DB_ROW))
|
||||
|
||||
with _end_user_cache_doubles() as (recording_cache, mock_publish):
|
||||
|
|
@ -1000,6 +1024,7 @@ def test_customer_block_invalidates_end_user_and_registry_caches(mock_prisma_cli
|
|||
mock_prisma_client.db.litellm_endusertable.upsert = AsyncMock(
|
||||
return_value=LiteLLM_EndUserTable(user_id="c1", blocked=True)
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with _end_user_cache_doubles() as (recording_cache, mock_publish):
|
||||
response = client.post(
|
||||
|
|
@ -1029,6 +1054,7 @@ def test_customer_delete_invalidates_end_user_and_registry_caches(mock_prisma_cl
|
|||
LiteLLM_EndUserTable(user_id="c2", blocked=False),
|
||||
]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_endusertable.delete_many = AsyncMock(return_value=2)
|
||||
|
||||
with _end_user_cache_doubles() as (recording_cache, mock_publish):
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ def _mock_prisma(keys, deleted_tokens):
|
|||
"""Return a minimal mock prisma_client for a given set of found keys and deleted tokens."""
|
||||
mock = AsyncMock()
|
||||
mock.db.litellm_verificationtoken.find_many = AsyncMock(return_value=keys)
|
||||
mock.replica_db = mock.db
|
||||
mock.delete_data = AsyncMock(return_value=deleted_tokens)
|
||||
mock.db.litellm_deletedverificationtoken.create_many = AsyncMock()
|
||||
return mock
|
||||
|
|
@ -176,6 +177,7 @@ async def test_delete_tokens_non_admin_token_not_in_db_returns_failed_tokens(
|
|||
mock_prisma = AsyncMock()
|
||||
# DB find_many returns only key1 — token-2 is not found
|
||||
mock_prisma.db.litellm_verificationtoken.find_many = AsyncMock(return_value=[key1])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.delete_data = AsyncMock(return_value=["hashed-token-1"])
|
||||
mock_prisma.db.litellm_deletedverificationtoken.create_many = AsyncMock()
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ def setup_mock_prisma_client(
|
|||
):
|
||||
"""Helper to set up a mock prisma client with proper async behavior"""
|
||||
mock_prisma_client.db = MagicMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_teamtable = AsyncMock()
|
||||
mock_prisma_client.db.litellm_teamtable.find_many = AsyncMock(return_value=team_records)
|
||||
mock_prisma_client.db.litellm_mcpservertable = AsyncMock()
|
||||
|
|
@ -1334,6 +1335,7 @@ class TestListMCPServers:
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=raw_prisma_model)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
mock_health_result = generate_mock_mcp_server_db_record(server_id="env-server", alias="Env Server")
|
||||
mock_health_result.status = "healthy"
|
||||
|
|
@ -3845,6 +3847,7 @@ class TestUpdateMCPServer:
|
|||
# Mock dependencies
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db = MagicMock()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_mcpservertable = AsyncMock()
|
||||
mock_prisma_client.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=existing_server)
|
||||
mock_prisma_client.db.litellm_mcpservertable.update = AsyncMock(return_value=updated_server)
|
||||
|
|
@ -4973,6 +4976,7 @@ def _make_prisma_client():
|
|||
"""Return a minimal mock PrismaClient accepted by get_prisma_client_or_throw."""
|
||||
client = MagicMock()
|
||||
client.db = MagicMock()
|
||||
client.replica_db = client.db
|
||||
return client
|
||||
|
||||
|
||||
|
|
@ -7916,6 +7920,7 @@ async def test_config_server_edit_preserves_api_contract_without_creating_rows(r
|
|||
original = server.model_dump()
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_mcpservertable.find_unique = AsyncMock(return_value=None)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_mcpservertable.update = AsyncMock(return_value=None)
|
||||
with (
|
||||
patch.object(mgmt_endpoints, "global_mcp_server_manager", manager),
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ async def test_organization_update_object_permissions_existing_permission(monkey
|
|||
}
|
||||
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(return_value=existing_object_permission)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock upsert operation
|
||||
updated_permission = MagicMock()
|
||||
|
|
@ -104,6 +105,7 @@ async def test_get_organization_daily_activity_admin_param_passing(monkeypatch):
|
|||
# Mock prisma client
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
# Admin view -> skip membership restriction
|
||||
|
|
@ -165,6 +167,7 @@ async def test_get_organization_daily_activity_non_admin_defaults_to_admin_orgs(
|
|||
# Mock prisma client and memberships
|
||||
mock_prisma_client = AsyncMock()
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_organizationmembership.find_many = AsyncMock(
|
||||
return_value=[
|
||||
SimpleNamespace(organization_id="orgA", user_role=LitellmUserRoles.ORG_ADMIN.value),
|
||||
|
|
@ -222,6 +225,7 @@ async def test_get_organization_daily_activity_non_admin_unauthorized_org_raises
|
|||
mock_prisma_client.db.litellm_organizationmembership.find_many = AsyncMock(
|
||||
return_value=[SimpleNamespace(organization_id="orgA", user_role=LitellmUserRoles.ORG_ADMIN.value)]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = AsyncMock(return_value=[])
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
|
|
@ -287,6 +291,7 @@ async def test_organization_update_object_permissions_no_existing_permission(
|
|||
|
||||
# Mock find_unique to return None (no existing permission)
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock upsert to create new record
|
||||
new_permission = MagicMock()
|
||||
|
|
@ -352,6 +357,7 @@ async def test_organization_update_object_permissions_missing_permission_record(
|
|||
|
||||
# Mock find_unique to return None (permission record not found)
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock upsert to create new record
|
||||
new_permission = MagicMock()
|
||||
|
|
@ -413,6 +419,7 @@ async def test_list_organization_filter_by_org_id(monkeypatch):
|
|||
|
||||
# Mock find_many to return filtered results
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = AsyncMock(return_value=[mock_org1])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
|
|
@ -475,6 +482,7 @@ async def test_list_organization_filter_by_org_alias(monkeypatch):
|
|||
|
||||
# Mock find_many to return filtered results
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = AsyncMock(return_value=[mock_org1, mock_org2])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
|
|
@ -570,6 +578,7 @@ def patched_org_prisma():
|
|||
patch("litellm.proxy.proxy_server.proxy_logging_obj"),
|
||||
):
|
||||
mock_prisma.db.litellm_organizationtable.find_unique = AsyncMock(return_value=victim_row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
yield mock_prisma
|
||||
|
||||
|
||||
|
|
@ -662,7 +671,7 @@ async def test_organization_member_add_budget_omission_and_null_leave_budget_uns
|
|||
litellm_usertable=SimpleNamespace(find_unique=AsyncMock(return_value=user)),
|
||||
litellm_organizationmembership=SimpleNamespace(create=create_membership),
|
||||
)
|
||||
mock_prisma = SimpleNamespace(db=mock_db)
|
||||
mock_prisma = SimpleNamespace(db=mock_db, replica_db=mock_db)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.management_endpoints.organization_endpoints._verify_org_access",
|
||||
|
|
@ -737,7 +746,7 @@ async def test_organization_member_update_budget_omission_and_null_preserve_exis
|
|||
find_unique=AsyncMock(return_value=SimpleNamespace(user_role="internal_user"))
|
||||
),
|
||||
)
|
||||
mock_prisma = SimpleNamespace(db=mock_db)
|
||||
mock_prisma = SimpleNamespace(db=mock_db, replica_db=mock_db)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
monkeypatch.setattr(organization_endpoints, "update_budget", update_budget)
|
||||
monkeypatch.setattr(
|
||||
|
|
@ -833,6 +842,7 @@ async def _run_update_organization_v2(
|
|||
existing_org.metadata = existing_metadata
|
||||
|
||||
mock_prisma_client.db.litellm_organizationtable.find_unique = AsyncMock(return_value=existing_org)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_organizationtable.update = AsyncMock(return_value=MagicMock())
|
||||
mock_prisma_client.db.litellm_budgettable.update = AsyncMock()
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(
|
||||
|
|
@ -905,6 +915,7 @@ async def test_v2_update_untouched_fields_not_written(monkeypatch):
|
|||
)
|
||||
|
||||
prisma.db.litellm_budgettable.update.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
write_data = prisma.db.litellm_organizationtable.update.await_args.kwargs["data"]
|
||||
assert write_data["organization_alias"] == "renamed"
|
||||
assert "metadata" not in write_data
|
||||
|
|
@ -982,6 +993,7 @@ async def test_v2_rejects_negative_integer_limits(monkeypatch: pytest.MonkeyPatc
|
|||
assert exc.value.status_code == 422
|
||||
assert field in str(exc.value.detail)
|
||||
prisma_mock.db.tx.assert_not_called()
|
||||
prisma_mock.replica_db = prisma_mock.db
|
||||
prisma_mock.db.litellm_budgettable.update.assert_not_awaited()
|
||||
prisma_mock.db.litellm_organizationtable.update.assert_not_awaited()
|
||||
|
||||
|
|
@ -1006,6 +1018,7 @@ async def test_v2_rejects_unparseable_budget_duration(monkeypatch: pytest.Monkey
|
|||
assert exc.value.status_code == 422
|
||||
assert "budget_duration" in str(exc.value.detail)
|
||||
prisma_mock.db.tx.assert_not_called()
|
||||
prisma_mock.replica_db = prisma_mock.db
|
||||
prisma_mock.db.litellm_budgettable.update.assert_not_awaited()
|
||||
prisma_mock.db.litellm_organizationtable.update.assert_not_awaited()
|
||||
|
||||
|
|
@ -1034,6 +1047,7 @@ async def test_v2_rejects_caller_without_org_access(monkeypatch):
|
|||
)
|
||||
assert exc.value.status_code == 403
|
||||
mock_prisma_client.db.litellm_organizationtable.update.assert_not_awaited()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1075,6 +1089,7 @@ async def test_v2_object_permission_upsert_runs_inside_transaction(monkeypatch):
|
|||
|
||||
prisma.tx.litellm_objectpermissiontable.upsert.assert_awaited_once()
|
||||
prisma.db.litellm_objectpermissiontable.upsert.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
upsert = prisma.tx.litellm_objectpermissiontable.upsert.await_args.kwargs
|
||||
linked_id = prisma.db.litellm_organizationtable.update.await_args.kwargs["data"]["object_permission_id"]
|
||||
|
|
@ -1097,6 +1112,7 @@ async def test_v2_clears_object_permission_when_sent_null(monkeypatch):
|
|||
|
||||
prisma.tx.litellm_objectpermissiontable.upsert.assert_not_awaited()
|
||||
prisma.db.litellm_objectpermissiontable.find_unique.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
write_data = prisma.db.litellm_organizationtable.update.await_args.kwargs["data"]
|
||||
assert write_data["object_permission_id"] is None
|
||||
|
||||
|
|
@ -1122,6 +1138,7 @@ async def test_v2_rejects_empty_object_permission(monkeypatch):
|
|||
assert exc.value.status_code == 422
|
||||
assert "object_permission" in str(exc.value.detail)
|
||||
mock_prisma_client.db.litellm_organizationtable.update.assert_not_awaited()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1135,6 +1152,7 @@ async def test_v2_writes_budget_and_org_in_one_transaction(monkeypatch):
|
|||
)
|
||||
|
||||
prisma.db.tx.assert_called_once()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_budgettable.update.assert_awaited_once()
|
||||
prisma.db.litellm_organizationtable.update.assert_awaited_once()
|
||||
|
||||
|
|
@ -1174,6 +1192,7 @@ async def _run_legacy_update_organization(
|
|||
existing_org.budget_id = existing_budget_id
|
||||
existing_org.metadata = {}
|
||||
mock_prisma_client.db.litellm_organizationtable.find_unique = AsyncMock(return_value=existing_org)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_organizationtable.update = AsyncMock(return_value=MagicMock())
|
||||
mock_prisma_client.db.litellm_budgettable.update = AsyncMock()
|
||||
|
||||
|
|
@ -1216,6 +1235,7 @@ async def test_legacy_update_without_budget_fields_skips_budget_write(monkeypatc
|
|||
)
|
||||
|
||||
prisma.db.litellm_budgettable.update.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
assert prisma.db.litellm_organizationtable.update.await_args.kwargs["data"]["organization_alias"] == "renamed"
|
||||
|
||||
|
||||
|
|
@ -1267,6 +1287,7 @@ async def test_get_organization_daily_activity_non_admin_without_org_admin_role_
|
|||
mock_prisma_client = AsyncMock()
|
||||
org_table_find_many = AsyncMock(return_value=[])
|
||||
mock_prisma_client.db.litellm_organizationtable.find_many = org_table_find_many
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_organizationmembership.find_many = AsyncMock(return_value=[])
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma_client)
|
||||
|
||||
|
|
@ -1308,6 +1329,7 @@ async def test_find_member_if_email_missing_row_raises_documented_400():
|
|||
|
||||
prisma_client = AsyncMock()
|
||||
prisma_client.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await find_member_if_email("missing@example.com", prisma_client)
|
||||
|
|
@ -1337,6 +1359,7 @@ async def test_new_organization_rejects_shared_alias_tool_permission_key():
|
|||
MagicMock(server_id="wiki-b-id", alias="wiki", server_name="wiki_b"),
|
||||
]
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_objectpermissiontable.create = AsyncMock()
|
||||
data = NewOrganizationRequest(
|
||||
organization_alias="org",
|
||||
|
|
@ -1367,6 +1390,7 @@ async def test_new_organization_temp_budget_fields_go_to_budget_row_not_metadata
|
|||
prisma_client = MagicMock()
|
||||
prisma_client.jsonify_object = MagicMock(side_effect=lambda data: PrismaClient.jsonify_object(prisma_client, data))
|
||||
prisma_client.db.litellm_usertable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_budgettable.create = AsyncMock(return_value=MagicMock(budget_id="budget-1"))
|
||||
prisma_client.db.litellm_organizationtable.create = AsyncMock(return_value={"organization_id": "org-1"})
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma_client)
|
||||
|
|
@ -1523,12 +1547,14 @@ async def test_delete_organization_evicts_the_cache_of_the_keys_it_deletes(monke
|
|||
prisma_client.db.litellm_verificationtoken.find_many = AsyncMock(
|
||||
return_value=[SimpleNamespace(token="hashed-org-key")]
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
async def cascading_delete_many(where):
|
||||
jwt_table.cascade(("hashed-org-key",))
|
||||
return 1
|
||||
|
||||
prisma_client.db.litellm_verificationtoken.delete_many = AsyncMock(side_effect=cascading_delete_many)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_jwtkeymapping = jwt_table
|
||||
prisma_client.db.litellm_organizationtable.delete = AsyncMock(return_value=MagicMock())
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ def _make_user_row(password: str | None) -> MagicMock:
|
|||
def _make_prisma(user: MagicMock | None) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_usertable.find_first = AsyncMock(return_value=user)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_usertable.update = AsyncMock(return_value=user)
|
||||
return prisma
|
||||
|
||||
|
|
@ -130,6 +131,7 @@ async def test_change_password_rejects_wrong_current_password():
|
|||
assert exc_info.value.status_code == 400
|
||||
assert "Current password is incorrect" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -156,6 +158,7 @@ async def test_change_password_rejects_unchanged_password():
|
|||
assert exc_info.value.status_code == 400
|
||||
assert "must be different from the current password" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -192,6 +195,7 @@ async def test_change_password_rejects_non_password_login_session(caller: UserAP
|
|||
assert exc_info.value.status_code == 403
|
||||
assert "logging in with a password" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.find_first.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -218,6 +222,7 @@ async def test_change_password_rejects_session_without_user():
|
|||
|
||||
assert exc_info.value.status_code == 400
|
||||
prisma.db.litellm_usertable.find_first.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -246,6 +251,7 @@ async def test_change_password_rejects_account_without_password():
|
|||
assert exc_info.value.status_code == 400
|
||||
assert "no password set" in exc_info.value.detail["error"]
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -274,6 +280,7 @@ async def test_change_password_enforces_min_length():
|
|||
assert exc_info.value.param == "password"
|
||||
assert "at least 12 characters" in exc_info.value.message
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -304,6 +311,7 @@ async def test_change_password_rejects_breached_password():
|
|||
assert exc_info.value.param == "password"
|
||||
assert "data breaches" in exc_info.value.message
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -335,6 +343,7 @@ async def test_change_password_verifies_current_password_before_hibp_lookup():
|
|||
assert "Current password is incorrect" in exc_info.value.detail["error"]
|
||||
assert hibp_calls == []
|
||||
prisma.db.litellm_usertable.update.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ def _make_prisma_with_team(team_id: str, admins: list, members_with_roles: tuple
|
|||
prisma = MagicMock()
|
||||
team_row = LiteLLM_TeamTable(team_id=team_id, admins=admins, members_with_roles=list(members_with_roles))
|
||||
prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_row)
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -57,6 +58,7 @@ async def test_project_perm_check_uses_current_team_not_caller_supplied():
|
|||
)
|
||||
assert has_perm is False
|
||||
prisma.db.litellm_teamtable.find_unique.assert_awaited_once()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -130,6 +132,7 @@ async def test_project_perm_check_denies_team_admin_unless_projects_permission_c
|
|||
)
|
||||
assert has_perm is False
|
||||
prisma.db.litellm_teamtable.find_unique.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -151,6 +154,7 @@ async def test_project_perm_check_require_admin_denies_team_admin_even_when_conf
|
|||
)
|
||||
assert has_perm is False
|
||||
prisma.db.litellm_teamtable.find_unique.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -172,6 +176,7 @@ async def test_project_perm_check_uses_injected_team_object_for_reassignment_tar
|
|||
)
|
||||
assert has_perm is False
|
||||
prisma.db.litellm_teamtable.find_unique.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -195,6 +200,7 @@ async def test_project_perm_check_proxy_admin_always_allowed():
|
|||
assert has_perm is True
|
||||
# Admin shortcut should not even hit the DB.
|
||||
prisma.db.litellm_teamtable.find_unique.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -209,6 +215,7 @@ def _make_prisma_with_user_orgs(user_id: str, org_ids: list):
|
|||
MagicMock(organization_id=org_id) for org_id in org_ids
|
||||
]
|
||||
prisma.db.litellm_usertable.find_unique = AsyncMock(return_value=user_row)
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -282,6 +289,7 @@ async def test_assign_key_org_blocks_caller_with_no_memberships():
|
|||
user_row = MagicMock()
|
||||
user_row.organization_memberships = None
|
||||
prisma.db.litellm_usertable.find_unique = AsyncMock(return_value=user_row)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
caller = UserAPIKeyAuth(
|
||||
user_id="alice",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ def _make_prisma(
|
|||
) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
table = prisma.db.litellm_verificationtoken
|
||||
prisma.replica_db = prisma.db
|
||||
table.find_unique = AsyncMock(return_value=find_unique_row)
|
||||
table.find_many = AsyncMock(return_value=find_many_rows or [])
|
||||
table.delete_many = AsyncMock(return_value=1)
|
||||
|
|
@ -133,6 +134,7 @@ async def test_session_logout_refuses_non_ui_session_key():
|
|||
|
||||
assert exc_info.value.status_code == 403
|
||||
prisma.db.litellm_verificationtoken.delete_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -157,6 +159,7 @@ async def test_session_logout_is_idempotent_when_row_already_gone():
|
|||
|
||||
assert response.message == "Session already revoked."
|
||||
prisma.db.litellm_verificationtoken.delete_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
# The cache entry may outlive the row; evict regardless.
|
||||
evict_mock.assert_awaited_once()
|
||||
|
||||
|
|
@ -260,6 +263,7 @@ async def test_revoke_ui_session_keys_noop_when_no_sessions():
|
|||
|
||||
assert revoked == 0
|
||||
prisma.db.litellm_verificationtoken.delete_many.assert_not_called()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -268,6 +272,7 @@ async def test_revoke_ui_session_keys_failure_is_swallowed():
|
|||
failure must not fail the caller's request."""
|
||||
prisma = _make_prisma(find_many_rows=[_session_row(token="t1")])
|
||||
prisma.db.litellm_verificationtoken.delete_many = AsyncMock(side_effect=RuntimeError("db down"))
|
||||
prisma.replica_db = prisma.db
|
||||
p1, p2, p3 = _patched_globals(prisma)
|
||||
|
||||
with (
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ async def test_create_and_get_tag():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock find_unique to return None (tag doesn't exist)
|
||||
mock_db.litellm_tagtable.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -179,6 +180,7 @@ async def test_update_tag():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock existing tag
|
||||
existing_tag = Mock()
|
||||
|
|
@ -247,7 +249,7 @@ async def test_new_tag_persists_a_budget():
|
|||
created_by="admin",
|
||||
)
|
||||
mock_db = Mock()
|
||||
mock_prisma = SimpleNamespace(db=mock_db, jsonify_object=lambda data: dict(data))
|
||||
mock_prisma = SimpleNamespace(db=mock_db, replica_db=mock_db, jsonify_object=lambda data: dict(data))
|
||||
mock_db.litellm_tagtable.find_unique = AsyncMock(return_value=None)
|
||||
mock_db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -316,7 +318,7 @@ async def test_update_tag_explicit_null_preserves_general_budget_fields(field):
|
|||
created_by="admin",
|
||||
)
|
||||
mock_db = Mock()
|
||||
mock_prisma = SimpleNamespace(db=mock_db)
|
||||
mock_prisma = SimpleNamespace(db=mock_db, replica_db=mock_db)
|
||||
mock_db.litellm_tagtable.find_unique = AsyncMock(return_value=existing_tag)
|
||||
mock_db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_db.litellm_tagtable.update = AsyncMock(return_value=updated_tag)
|
||||
|
|
@ -370,7 +372,7 @@ async def test_update_tag_explicit_null_clears_budget_duration():
|
|||
created_by="admin",
|
||||
)
|
||||
mock_db = Mock()
|
||||
mock_prisma = SimpleNamespace(db=mock_db)
|
||||
mock_prisma = SimpleNamespace(db=mock_db, replica_db=mock_db)
|
||||
mock_db.litellm_tagtable.find_unique = AsyncMock(return_value=existing_tag)
|
||||
mock_db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_db.litellm_tagtable.update = AsyncMock(return_value=updated_tag)
|
||||
|
|
@ -420,6 +422,7 @@ async def test_delete_tag():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock existing tag
|
||||
existing_tag = Mock()
|
||||
|
|
@ -516,6 +519,7 @@ async def test_new_tag_invalidates_tag_and_registry_caches():
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_db.litellm_tagtable.find_unique = AsyncMock(return_value=None)
|
||||
mock_db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
mock_get_deployments.return_value = []
|
||||
|
|
@ -568,6 +572,7 @@ async def test_update_tag_invalidates_only_the_tag_cache():
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
existing_tag = Mock()
|
||||
existing_tag.tag_name = "cache-tag"
|
||||
|
|
@ -619,6 +624,7 @@ async def test_delete_tag_invalidates_tag_and_registry_caches():
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
existing_tag = Mock()
|
||||
existing_tag.tag_name = "cache-tag"
|
||||
|
|
@ -659,6 +665,7 @@ async def test_list_tags_with_dynamic_tags():
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Setup stored tags
|
||||
stored_tag = Mock()
|
||||
|
|
@ -740,6 +747,7 @@ async def test_list_tags_no_dynamic_tags():
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
stored_tag = Mock()
|
||||
stored_tag.tag_name = "stored-tag"
|
||||
|
|
@ -790,6 +798,7 @@ async def test_internal_user_list_tags_only_returns_tags_used_by_their_keys():
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
owned_key_record = Mock()
|
||||
owned_key_record.token = "owned-key"
|
||||
|
|
@ -881,6 +890,7 @@ async def test_internal_user_list_tags_does_not_500_on_unsupported_prisma_kwarg(
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
key_record = Mock()
|
||||
key_record.token = "new-user-key"
|
||||
|
|
@ -923,6 +933,7 @@ async def test_list_tags_with_date_range_filters_dynamic_tags():
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_db.litellm_tagtable.find_many = AsyncMock(return_value=[])
|
||||
group_by_mock = AsyncMock(return_value=[])
|
||||
mock_db.litellm_dailytagspend.group_by = group_by_mock
|
||||
|
|
@ -969,6 +980,7 @@ async def test_internal_user_tag_daily_activity_is_scoped_to_their_keys():
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
owned_key_record = Mock()
|
||||
owned_key_record.token = "owned-key"
|
||||
|
|
@ -1015,6 +1027,7 @@ async def test_internal_user_tag_daily_activity_rejects_unowned_api_key_filter()
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
owned_key_record = Mock()
|
||||
owned_key_record.token = "owned-key"
|
||||
|
|
@ -1061,6 +1074,7 @@ async def test_internal_user_tag_daily_activity_scopes_to_current_key_without_us
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
fake_token_table = FakeVerificationTokenTable([])
|
||||
mock_db.litellm_verificationtoken = fake_token_table
|
||||
mock_get_daily_activity.return_value = "daily-activity-response"
|
||||
|
|
@ -1105,6 +1119,7 @@ async def test_internal_user_tag_daily_activity_without_any_scoped_keys_returns_
|
|||
):
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
fake_token_table = FakeVerificationTokenTable([])
|
||||
mock_db.litellm_verificationtoken = fake_token_table
|
||||
|
||||
|
|
@ -1165,6 +1180,7 @@ async def test_list_tags_without_date_range_omits_date_filter():
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_db.litellm_tagtable.find_many = AsyncMock(return_value=[])
|
||||
group_by_mock = AsyncMock(return_value=[])
|
||||
mock_db.litellm_dailytagspend.group_by = group_by_mock
|
||||
|
|
@ -1206,6 +1222,7 @@ async def test_list_tags_rejects_invalid_date_range(query, expected_detail_fragm
|
|||
with patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma:
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_db.litellm_tagtable.find_many = AsyncMock(return_value=[])
|
||||
mock_db.litellm_dailytagspend.group_by = AsyncMock(return_value=[])
|
||||
|
||||
|
|
@ -1325,6 +1342,7 @@ async def test_add_tag_to_deployment_preserves_encrypted_fields():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock the database model with encrypted fields
|
||||
db_model = Mock()
|
||||
|
|
@ -1391,6 +1409,7 @@ async def test_add_tag_to_deployment_with_string_params():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock the database model with litellm_params as string
|
||||
db_model = Mock()
|
||||
|
|
@ -1444,6 +1463,7 @@ async def test_add_tag_to_deployment_no_duplicate_tags():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock the database model with existing tags
|
||||
db_model = Mock()
|
||||
|
|
@ -1496,6 +1516,7 @@ async def test_add_tag_to_deployment_model_not_found():
|
|||
# Setup prisma mocks
|
||||
mock_db = Mock()
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Mock find_unique to return None (model not found)
|
||||
mock_db.litellm_proxymodeltable.find_unique = AsyncMock(return_value=None)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ def _patch_prisma(existing_team: MagicMock):
|
|||
updated_row = MagicMock()
|
||||
updated_row.team_id = existing_team.team_id
|
||||
mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=updated_row)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
return mock_prisma
|
||||
|
||||
|
||||
|
|
@ -106,6 +107,7 @@ def patched_prisma():
|
|||
):
|
||||
mock_client.get_data = AsyncMock(return_value=_team_row())
|
||||
mock_client.db.litellm_teamtable.update = AsyncMock()
|
||||
mock_client.replica_db = mock_client.db
|
||||
yield mock_client
|
||||
|
||||
|
||||
|
|
@ -128,6 +130,7 @@ async def test_add_team_callbacks_rejects_unauthorized_caller(patched_prisma, un
|
|||
)
|
||||
assert exc.value.status_code == 403
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -140,6 +143,7 @@ async def test_disable_team_logging_rejects_unauthorized_caller(patched_prisma,
|
|||
)
|
||||
assert exc.value.status_code == 403
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -170,6 +174,7 @@ async def test_proxy_admin_can_add_team_callbacks(patched_prisma):
|
|||
user_api_key_dict=_admin_auth(),
|
||||
)
|
||||
patched_prisma.db.litellm_teamtable.update.assert_awaited_once()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -196,6 +201,7 @@ async def test_team_admin_of_target_team_can_add_callbacks(patched_prisma):
|
|||
user_api_key_dict=team_admin,
|
||||
)
|
||||
patched_prisma.db.litellm_teamtable.update.assert_awaited_once()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -971,6 +977,7 @@ async def test_delete_team_callback_rejects_unauthorized_caller(patched_prisma,
|
|||
)
|
||||
assert exc.value.status_code == 403
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1109,6 +1116,7 @@ async def test_delete_team_callback_404s_for_unregistered_callback():
|
|||
assert exc.value.status_code == 404
|
||||
assert exc.value.detail == {"error": "callback_name = gcs is not registered for team_id = team-1."}
|
||||
mock_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1138,6 +1146,7 @@ async def test_delete_team_callback_404s_when_team_has_no_logging_slot():
|
|||
|
||||
assert exc.value.status_code == 404
|
||||
mock_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1145,6 +1154,7 @@ async def test_delete_team_callback_404s_for_unknown_team():
|
|||
mock_prisma = MagicMock()
|
||||
mock_prisma.get_data = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_teamtable.update = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
with patch("litellm.proxy.proxy_server.prisma_client", mock_prisma):
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
|
|
@ -1171,6 +1181,7 @@ async def test_add_team_callbacks_rejects_team_deleted_before_write():
|
|||
"""
|
||||
mock_prisma = _patch_prisma(_team_row(team_id="team-1", metadata={}))
|
||||
mock_prisma.db.litellm_teamtable.update = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
data = AddTeamCallback(
|
||||
callback_name="langfuse",
|
||||
|
|
@ -1488,6 +1499,7 @@ async def test_unknown_team_is_indistinguishable_from_no_access(call_handler, un
|
|||
): # test-quality-ok: the handler imports prisma_client from proxy_server at call time, so there is no seam to inject through
|
||||
mock_client.get_data = AsyncMock(return_value=_team_row())
|
||||
mock_client.db.litellm_teamtable.update = AsyncMock()
|
||||
mock_client.replica_db = mock_client.db
|
||||
with patch( # test-quality-ok: _verify_team_access calls this module-level helper directly, so there is no seam to inject through
|
||||
"litellm.proxy.management_endpoints.team_endpoints._is_user_org_admin_for_team",
|
||||
new_callable=AsyncMock,
|
||||
|
|
@ -1663,6 +1675,7 @@ async def test_a_second_entry_may_not_flip_the_span_scope(patched_prisma, caller
|
|||
assert exc.value.status_code == 400
|
||||
assert "langfuse_span_scope" in str(exc.value.detail) and "'full'" in str(exc.value.detail)
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
data.callback_vars["langfuse_span_scope"] = "full"
|
||||
await add_team_callbacks(
|
||||
|
|
@ -1691,6 +1704,7 @@ async def test_add_team_callbacks_rejects_out_of_range_arize_sampling_rate(patch
|
|||
assert exc.value.status_code == 400
|
||||
assert "arize_success_sampling_rate" in str(exc.value.detail)
|
||||
patched_prisma.db.litellm_teamtable.update.assert_not_called()
|
||||
patched_prisma.replica_db = patched_prisma.db
|
||||
|
||||
|
||||
def test_add_team_callback_accepts_arize_sampling_rate_vars():
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ class TestNewTeamDefaultParamsApplied:
|
|||
)
|
||||
mock_prisma.get_generic_data = AsyncMock(return_value=None)
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_teamtable = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_teamtable.count = AsyncMock(return_value=0)
|
||||
|
|
@ -682,6 +683,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[team_a, team_b])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.batch_ = MagicMock(return_value=mock_batcher)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -718,6 +720,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[team_has, team_missing])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.batch_ = MagicMock(return_value=mock_batcher)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -747,6 +750,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(side_effect=[page1, page2])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.batch_ = MagicMock(return_value=mock_batcher)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -779,6 +783,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[team_a, team_b])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.batch_ = MagicMock(return_value=mock_batcher)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -811,6 +816,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[team_has, team_missing])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.batch_ = MagicMock(return_value=mock_batcher)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -838,6 +844,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
mock_prisma = MagicMock()
|
||||
# Only team-a exists, team-b does not
|
||||
mock_prisma.db.litellm_teamtable.find_many = AsyncMock(return_value=[team_a])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
data = BulkUpdateTeamMemberPermissionsRequest(
|
||||
|
|
@ -914,6 +921,7 @@ class TestBulkUpdateTeamMemberPermissions:
|
|||
|
||||
assert result["teams_updated"] == 0
|
||||
mock_prisma.db.litellm_teamtable.find_many.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_admin_gets_403(self, monkeypatch):
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class TestTeamModelAddAtomicAppend:
|
|||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(
|
||||
return_value=existing_team
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.execute_raw = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_teamtable.update = AsyncMock(
|
||||
return_value=updated_team
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ def _team_row(object_permission_id: Optional[str]) -> MagicMock:
|
|||
def _team_policy_prisma(team_table: FakeTeamTable) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_teamtable = team_table
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_objectpermissiontable.create = AsyncMock()
|
||||
prisma.db.litellm_objectpermissiontable.delete = AsyncMock()
|
||||
return prisma
|
||||
|
|
@ -118,6 +119,7 @@ def _team_policy_prisma(team_table: FakeTeamTable) -> MagicMock:
|
|||
def _rollup_prisma(group_rows: list, daily_rows: list | None = None) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_spendlogs.find_many = AsyncMock(return_value=[])
|
||||
prisma.db.litellm_spendlogtoolindex.find_many = AsyncMock(return_value=[])
|
||||
prisma.db.litellm_dailytoolspend.group_by = AsyncMock(return_value=group_rows)
|
||||
|
|
@ -343,6 +345,7 @@ class TestToolManagementEndpoints:
|
|||
resp = self.client.get("/v1/tool/spend?start_date=2026-07-01&end_date=2026-07-02")
|
||||
assert resp.status_code == 200
|
||||
prisma.db.litellm_dailytoolspend.find_many.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
@patch("litellm.proxy.proxy_server.prisma_client", None)
|
||||
def test_tool_spend_no_db_returns_500(self):
|
||||
|
|
@ -358,6 +361,7 @@ class TestToolManagementEndpoints:
|
|||
resp = self.client.get("/v1/tool/spend?start_date=2026-07-01&end_date=2026-07-02")
|
||||
assert resp.status_code == 200
|
||||
prisma.db.query_raw.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_spendlogs.find_many.assert_not_awaited()
|
||||
prisma.db.litellm_spendlogtoolindex.find_many.assert_not_awaited()
|
||||
prisma.db.litellm_dailytoolspend.group_by.assert_awaited_once()
|
||||
|
|
@ -409,6 +413,7 @@ class TestToolManagementEndpoints:
|
|||
assert resp.status_code == 400
|
||||
assert "Invalid date format" in resp.json()["detail"]
|
||||
prisma.db.litellm_dailytoolspend.group_by.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
def test_tool_spend_non_admin_returns_403(self):
|
||||
from litellm.proxy._types import LitellmUserRoles, UserAPIKeyAuth
|
||||
|
|
@ -424,3 +429,4 @@ class TestToolManagementEndpoints:
|
|||
resp = client.get("/v1/tool/spend")
|
||||
assert resp.status_code == 403
|
||||
prisma.db.litellm_dailytoolspend.group_by.assert_not_awaited()
|
||||
prisma.replica_db = prisma.db
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ def _make_tx(event_return=None, run_return=None, msg_return=None) -> MagicMock:
|
|||
def _make_prisma_client() -> MagicMock:
|
||||
client = MagicMock()
|
||||
client.db = MagicMock()
|
||||
client.replica_db = client.db
|
||||
client.db.litellm_workflowrun = MagicMock()
|
||||
client.db.litellm_workflowevent = MagicMock()
|
||||
client.db.litellm_workflowmessage = MagicMock()
|
||||
|
|
@ -185,6 +186,7 @@ class TestCreateWorkflowRun:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_create_returns_run(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.create = AsyncMock(return_value=_make_run())
|
||||
|
||||
resp = self.client.post(
|
||||
|
|
@ -215,6 +217,7 @@ class TestListWorkflowRuns:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_returns_runs(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(
|
||||
return_value=[_make_run()]
|
||||
)
|
||||
|
|
@ -227,6 +230,7 @@ class TestListWorkflowRuns:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_filters_by_status(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(return_value=[])
|
||||
|
||||
resp = self.client.get("/v1/workflows/runs?status=running")
|
||||
|
|
@ -237,6 +241,7 @@ class TestListWorkflowRuns:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_filters_by_multiple_statuses(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(return_value=[])
|
||||
|
||||
resp = self.client.get("/v1/workflows/runs?status=running,paused")
|
||||
|
|
@ -257,6 +262,7 @@ class TestGetWorkflowRun:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_get_existing_run(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -267,6 +273,7 @@ class TestGetWorkflowRun:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_get_missing_run_returns_404(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
resp = self.client.get("/v1/workflows/runs/nonexistent")
|
||||
|
|
@ -285,6 +292,7 @@ class TestUpdateWorkflowRun:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_update_status(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -300,6 +308,7 @@ class TestUpdateWorkflowRun:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_update_no_fields_returns_400(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
resp = self.client.patch("/v1/workflows/runs/run-1", json={})
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
|
@ -316,6 +325,7 @@ class TestAppendWorkflowEvent:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_append_event_updates_run_status(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
# _require_run check
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
|
|
@ -339,6 +349,7 @@ class TestAppendWorkflowEvent:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_append_event_no_status_update_for_unknown_type(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -357,6 +368,7 @@ class TestAppendWorkflowEvent:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_sequence_number_increments(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -377,6 +389,7 @@ class TestAppendWorkflowEvent:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_unknown_run_id_returns_404(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
resp = self.client.post(
|
||||
|
|
@ -389,6 +402,7 @@ class TestAppendWorkflowEvent:
|
|||
def test_sequence_collision_retries_and_succeeds(self, mock_pc):
|
||||
"""UniqueViolationError on first attempt triggers retry; second attempt succeeds."""
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -427,6 +441,7 @@ class TestWorkflowMessages:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_append_message(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -444,6 +459,7 @@ class TestWorkflowMessages:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_append_message_unknown_run_returns_404(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
resp = self.client.post(
|
||||
|
|
@ -455,6 +471,7 @@ class TestWorkflowMessages:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_messages_ordered(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -475,6 +492,7 @@ class TestWorkflowMessages:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_messages_respects_limit(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -498,6 +516,7 @@ class TestListWorkflowEvents:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_events_ordered(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -518,6 +537,7 @@ class TestListWorkflowEvents:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_events_respects_limit(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run()
|
||||
)
|
||||
|
|
@ -531,6 +551,7 @@ class TestListWorkflowEvents:
|
|||
@patch("litellm.proxy.proxy_server.prisma_client")
|
||||
def test_list_events_unknown_run_returns_404(self, mock_pc):
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(return_value=None)
|
||||
|
||||
resp = self.client.get("/v1/workflows/runs/nonexistent/events")
|
||||
|
|
@ -553,6 +574,7 @@ class TestTenantIsolation:
|
|||
token = "tok-owner"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.create = AsyncMock(
|
||||
return_value=_make_run(created_by=token)
|
||||
)
|
||||
|
|
@ -567,6 +589,7 @@ class TestTenantIsolation:
|
|||
token = "tok-owner"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(return_value=[])
|
||||
|
||||
resp = client.get("/v1/workflows/runs")
|
||||
|
|
@ -578,6 +601,7 @@ class TestTenantIsolation:
|
|||
def test_admin_list_not_scoped(self, mock_pc):
|
||||
client = self._make_app_with_auth(_override_auth_admin)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(return_value=[])
|
||||
|
||||
resp = client.get("/v1/workflows/runs")
|
||||
|
|
@ -590,6 +614,7 @@ class TestTenantIsolation:
|
|||
token = "tok-caller"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
# Run owned by a different key
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
|
|
@ -603,6 +628,7 @@ class TestTenantIsolation:
|
|||
token = "tok-caller"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by=None)
|
||||
)
|
||||
|
|
@ -615,6 +641,7 @@ class TestTenantIsolation:
|
|||
token = "tok-caller"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by=None)
|
||||
)
|
||||
|
|
@ -631,6 +658,7 @@ class TestTenantIsolation:
|
|||
token = "tok-caller"
|
||||
client = self._make_app_with_auth(lambda: _override_auth_user_with_token(token))
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by=token)
|
||||
)
|
||||
|
|
@ -660,6 +688,7 @@ class TestAdminViewerReadParity:
|
|||
def test_admin_viewer_list_not_scoped(self, mock_pc):
|
||||
client = self._make_app_with_auth(_override_auth_admin_viewer)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_many = AsyncMock(return_value=[])
|
||||
|
||||
resp = client.get("/v1/workflows/runs")
|
||||
|
|
@ -671,6 +700,7 @@ class TestAdminViewerReadParity:
|
|||
def test_admin_viewer_get_other_owners_run_succeeds(self, mock_pc):
|
||||
client = self._make_app_with_auth(_override_auth_admin_viewer)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
)
|
||||
|
|
@ -682,6 +712,7 @@ class TestAdminViewerReadParity:
|
|||
def test_admin_viewer_lists_other_owners_events(self, mock_pc):
|
||||
client = self._make_app_with_auth(_override_auth_admin_viewer)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
)
|
||||
|
|
@ -697,6 +728,7 @@ class TestAdminViewerReadParity:
|
|||
def test_admin_viewer_lists_other_owners_messages(self, mock_pc):
|
||||
client = self._make_app_with_auth(_override_auth_admin_viewer)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
)
|
||||
|
|
@ -713,6 +745,7 @@ class TestAdminViewerReadParity:
|
|||
"""Read parity must not become write parity: PATCH still passes the caller through."""
|
||||
client = self._make_app_with_auth(_override_auth_admin_viewer)
|
||||
mock_pc.db = self._prisma.db
|
||||
mock_pc.replica_db = mock_pc.db
|
||||
self._prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
)
|
||||
|
|
@ -730,6 +763,7 @@ class TestAdminViewerReadParity:
|
|||
prisma.db.litellm_workflowrun.find_unique = AsyncMock(
|
||||
return_value=_make_run(created_by="tok-other-owner")
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
asyncio.run(_require_run(prisma, "run-1", _override_auth_admin_viewer()))
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ class TestCreateAuditLogForUpdateWithCallbacks:
|
|||
patch("litellm.proxy.proxy_server.prisma_client") as mock_prisma,
|
||||
):
|
||||
mock_prisma.db.litellm_auditlog.create = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
audit_log = _make_audit_log()
|
||||
await create_audit_log_for_update(audit_log)
|
||||
|
|
@ -219,6 +220,7 @@ class TestCreateAuditLogForUpdateWithCallbacks:
|
|||
|
||||
mock_logger.async_log_audit_log_event.assert_not_called()
|
||||
mock_prisma.db.litellm_auditlog.create.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_dispatch_when_store_audit_logs_false(self, monkeypatch: pytest.MonkeyPatch):
|
||||
|
|
@ -267,6 +269,7 @@ class TestCreateAuditLogForUpdateWithCallbacks:
|
|||
mock_prisma.db.litellm_auditlog.create = AsyncMock(
|
||||
side_effect=RuntimeError("DB connection lost")
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
audit_log = _make_audit_log()
|
||||
await create_audit_log_for_update(audit_log)
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ class _FakePrisma:
|
|||
raced_ids: frozenset[str] = frozenset(),
|
||||
) -> None:
|
||||
self.db = _Db(teams or [], fail_ids, commit_then_drop, raced_ids)
|
||||
self.replica_db = self.db
|
||||
self.tx_count = 0
|
||||
self.locks: list[str] = []
|
||||
|
||||
|
|
@ -252,6 +253,7 @@ async def test_one_insert_and_one_locked_write_per_team():
|
|||
async def test_bad_rows_fail_alone_and_good_rows_still_land():
|
||||
prisma = _FakePrisma(teams=[_team("t1")])
|
||||
prisma.db.litellm_usertable.rows["taken"] = _UserRow(user_id="taken", user_email="Taken@Example.com")
|
||||
prisma.replica_db = prisma.db
|
||||
response = await _run(
|
||||
prisma,
|
||||
[
|
||||
|
|
@ -325,6 +327,7 @@ async def test_team_write_failure_keeps_user_and_reports_it_on_the_row():
|
|||
raise RuntimeError("roster write failed")
|
||||
|
||||
prisma.db.litellm_teamtable.update = explode
|
||||
prisma.replica_db = prisma.db
|
||||
response = await _run(prisma, [{"user_id": "u1", "teams": ["t1", "t2"]}])
|
||||
|
||||
result = response.data[0]
|
||||
|
|
@ -394,6 +397,7 @@ async def test_non_admin_cannot_create_admin_users_but_other_rows_proceed():
|
|||
async def test_license_is_checked_once_against_the_whole_batch():
|
||||
prisma = _FakePrisma()
|
||||
prisma.db.litellm_usertable.rows["existing"] = _UserRow(user_id="existing")
|
||||
prisma.replica_db = prisma.db
|
||||
license = _License(max_users=3)
|
||||
|
||||
with pytest.raises(ManagementProblem) as exc:
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ class _FakePrisma:
|
|||
fail_commit: bool = False,
|
||||
) -> None:
|
||||
self.db = _Db(users, teams, memberships, tokens, invitations, org_memberships, jwt_mappings)
|
||||
self.replica_db = self.db
|
||||
self._on_lock = on_lock
|
||||
self._fail_locks = fail_locks
|
||||
self._fail_commit = fail_commit
|
||||
|
|
@ -189,6 +190,7 @@ class _FakePrisma:
|
|||
raise RuntimeError("connection reset")
|
||||
except BaseException:
|
||||
self.db.__dict__.update(snapshot.__dict__)
|
||||
self.replica_db = self.db
|
||||
raise
|
||||
self.locks.extend(tx.locks)
|
||||
self.roster_reads.extend(tx.roster_reads)
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ async def test_add_new_member_links_default_team_budget_id():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -265,6 +266,7 @@ async def test_add_new_member_no_budget_when_default_budget_row_is_missing():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -318,6 +320,7 @@ async def test_add_new_member_budget_duration_only_clones_default_max_budget():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -403,6 +406,7 @@ async def test_add_new_member_no_budget_when_no_default_and_no_max_budget():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -494,6 +498,7 @@ async def test_add_new_member_creates_new_budget_when_max_budget_provided():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -572,6 +577,7 @@ async def test_add_new_member_persists_budget_duration():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -636,6 +642,7 @@ async def test_add_new_member_persists_budget_duration_without_max_budget():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_response)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.find_unique = AsyncMock(
|
||||
return_value=mock_user_response
|
||||
)
|
||||
|
|
@ -709,6 +716,7 @@ async def test_add_new_member_with_user_email_links_default_budget():
|
|||
mock_prisma_client.db.litellm_budgettable.find_unique = AsyncMock(
|
||||
return_value=mock_default_budget_row
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_budgettable.create = AsyncMock()
|
||||
|
||||
mock_team_membership_response = MagicMock()
|
||||
|
|
@ -845,6 +853,7 @@ async def test_team_update_reaches_inherited_members_but_not_overridden_ones():
|
|||
db: Final = _FakeDb()
|
||||
prisma_client: Final = MagicMock()
|
||||
prisma_client.db = db
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
admin: Final = UserAPIKeyAuth(user_id="admin_user", user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
team_id: Final = "team-shared-default"
|
||||
default_budget: Final = await db.litellm_budgettable.create(data={"budget_id": "team-default", "max_budget": 100.0})
|
||||
|
|
@ -948,6 +957,7 @@ async def test_attach_object_permission_to_dict_with_object_permission_id():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(
|
||||
return_value=mock_object_permission
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Call the function
|
||||
result = await attach_object_permission_to_dict(
|
||||
|
|
@ -994,6 +1004,7 @@ async def test_attach_object_permission_to_dict_without_object_permission_id():
|
|||
|
||||
# Verify no database query was made
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique.assert_not_called()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1021,6 +1032,7 @@ async def test_attach_object_permission_to_dict_object_permission_not_found():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(
|
||||
return_value=None
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Call the function
|
||||
result = await attach_object_permission_to_dict(
|
||||
|
|
@ -1075,6 +1087,7 @@ async def test_attach_object_permission_to_dict_with_dict_method():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique = AsyncMock(
|
||||
return_value=mock_object_permission
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Call the function
|
||||
result = await attach_object_permission_to_dict(
|
||||
|
|
@ -1138,6 +1151,7 @@ async def test_attach_object_permission_to_dict_with_empty_dict():
|
|||
|
||||
# Verify no database query was made
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique.assert_not_called()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1170,6 +1184,7 @@ async def test_attach_object_permission_to_dict_with_none_object_permission_id()
|
|||
|
||||
# Verify no database query was made
|
||||
mock_prisma_client.db.litellm_objectpermissiontable.find_unique.assert_not_called()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -1202,6 +1217,7 @@ async def test_add_new_member_appends_team_only_if_absent_for_existing_user():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_user_after)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.update_many = AsyncMock()
|
||||
mock_prisma_client.db.litellm_budgettable.find_unique = AsyncMock(return_value=None)
|
||||
mock_membership = MagicMock()
|
||||
|
|
@ -1275,6 +1291,7 @@ async def test_add_new_member_creates_missing_user_atomically_via_upsert():
|
|||
"user_role": "internal_user",
|
||||
}
|
||||
mock_prisma_client.db.litellm_usertable.upsert = AsyncMock(return_value=mock_created)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_usertable.update_many = AsyncMock()
|
||||
mock_prisma_client.db.litellm_usertable.create = AsyncMock()
|
||||
mock_prisma_client.db.litellm_budgettable.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -1383,5 +1400,6 @@ async def test_add_new_member_runs_every_write_on_the_caller_transaction(new_mem
|
|||
assert tx.litellm_usertable.upsert.await_count + tx.litellm_usertable.create.await_count == 1
|
||||
|
||||
prisma_client.db.assert_not_called()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.get_data.assert_not_awaited()
|
||||
prisma_client.insert_data.assert_not_awaited()
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ async def test_set_object_permission():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.create = AsyncMock(
|
||||
return_value=mock_created_permission
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
# Test data with object_permission
|
||||
|
|
@ -104,6 +105,7 @@ async def test_set_object_permission_persists_mcp_tool_search_enabled():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.create = AsyncMock(
|
||||
return_value=mock_created_permission
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
data_json = {
|
||||
"object_permission": {
|
||||
|
|
@ -130,6 +132,7 @@ async def test_set_object_permission_persists_skills():
|
|||
mock_prisma_client.db.litellm_objectpermissiontable.create = AsyncMock(
|
||||
return_value=mock_created_permission
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
data_json = {
|
||||
"object_permission": LiteLLM_ObjectPermissionBase(skills=["private-skill"]).model_dump(),
|
||||
|
|
@ -778,6 +781,7 @@ async def test_validate_db_mcp_server_alias_outside_team_scope_raises_when_regis
|
|||
mock_prisma_client.db.litellm_mcpservertable.find_many = AsyncMock(
|
||||
return_value=[mock_db_server]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
team_obj = _make_team_obj(mcp_servers=[])
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
|
|
@ -1266,6 +1270,7 @@ def _make_grandfather_fixtures(mcp_servers=None, mcp_tool_permissions=None):
|
|||
existing_row.mcp_tool_permissions = mcp_tool_permissions or {}
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
return mock_prisma, existing_row
|
||||
|
||||
|
||||
|
|
@ -1392,6 +1397,7 @@ def _make_ambiguity_prisma(existing_tool_permissions=None):
|
|||
object permission row (if any) stores the given mcp_tool_permissions JSON string."""
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_mcpservertable.find_many = AsyncMock(return_value=list(_SHARED_ALIAS_DB_SERVERS))
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_objectpermissiontable.create = AsyncMock(
|
||||
return_value=MagicMock(object_permission_id="perm-id")
|
||||
)
|
||||
|
|
@ -1423,6 +1429,7 @@ async def test_set_object_permission_rejects_shared_alias_or_name_tool_permissio
|
|||
assert exc_info.value.status_code == 400
|
||||
assert all(server_id in str(exc_info.value.detail) for server_id in colliding_ids)
|
||||
mock_prisma.db.litellm_objectpermissiontable.create.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ async def _drive_create(metadata, mock_sink=None):
|
|||
pc.get_data = AsyncMock(return_value=None)
|
||||
pc.update_data = AsyncMock(return_value=MagicMock())
|
||||
pc.db.litellm_teamtable.create = AsyncMock(return_value=team_row)
|
||||
pc.replica_db = pc.db
|
||||
pc.db.litellm_teamtable.count = AsyncMock(return_value=0)
|
||||
pc.db.litellm_teamtable.update = AsyncMock(return_value=team_row)
|
||||
pc.db.litellm_usertable.update = AsyncMock(return_value=MagicMock())
|
||||
|
|
@ -410,6 +411,7 @@ async def _drive_update(kind, existing_metadata, payload):
|
|||
),
|
||||
):
|
||||
pc.db.litellm_teamtable.find_unique = AsyncMock(return_value=existing)
|
||||
pc.replica_db = pc.db
|
||||
pc.db.litellm_teamtable.update = AsyncMock(
|
||||
return_value=LiteLLM_TeamTable(team_id=team_id, team_alias="matrix")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -212,6 +212,7 @@ def _make_team(team_id: str, *, admin_user_ids: List[str]) -> Any:
|
|||
def _make_prisma() -> MagicMock:
|
||||
client = MagicMock()
|
||||
client.db = MagicMock()
|
||||
client.replica_db = client.db
|
||||
client.db.litellm_memorytable = _InMemoryMemoryTable()
|
||||
client.db.litellm_teamtable = _InMemoryTeamTable()
|
||||
return client
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ async def test_map_raw_file_ids_to_unified_empty_ids_skips_db():
|
|||
assert await map_raw_file_ids_to_unified(frozenset(), prisma_client) == {}
|
||||
|
||||
prisma_client.db.litellm_managedfiletable.find_many.assert_not_called()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -70,6 +71,7 @@ async def test_map_raw_file_ids_to_unified_bulk_queries_and_filters_to_requested
|
|||
row_b = MagicMock(unified_file_id="unified-b", flat_model_file_ids=["file-raw-b"])
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_managedfiletable.find_many = AsyncMock(return_value=[row_a, row_b])
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
mapping = await map_raw_file_ids_to_unified(
|
||||
frozenset({"file-raw-b", "file-raw-a", "file-raw-missing"}), prisma_client
|
||||
|
|
@ -204,6 +206,7 @@ async def _run_update(monkeypatch, poller_active: bool) -> dict:
|
|||
prisma_client = MagicMock()
|
||||
update_mock = AsyncMock()
|
||||
prisma_client.db.litellm_managedobjecttable.update = update_mock
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
db_batch_object = MagicMock()
|
||||
db_batch_object.status = "in_progress"
|
||||
|
|
@ -285,6 +288,7 @@ async def test_retrieving_a_batch_whose_status_is_unchanged_writes_nothing(monke
|
|||
prisma_client = MagicMock()
|
||||
update_mock = AsyncMock()
|
||||
prisma_client.db.litellm_managedobjecttable.update = update_mock
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
db_batch_object = MagicMock()
|
||||
db_batch_object.status = "completed"
|
||||
|
|
@ -310,6 +314,7 @@ async def test_update_batch_in_database_is_a_noop_for_unmanaged_batches(monkeypa
|
|||
prisma_client = MagicMock()
|
||||
update_mock = AsyncMock()
|
||||
prisma_client.db.litellm_managedobjecttable.update = update_mock
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
await cu.update_batch_in_database(
|
||||
batch_id="batch-raw-xyz",
|
||||
|
|
@ -334,6 +339,7 @@ async def test_the_caller_s_accounting_decision_wins_over_a_later_poller_transit
|
|||
prisma_client = MagicMock()
|
||||
update_mock = AsyncMock()
|
||||
prisma_client.db.litellm_managedobjecttable.update = update_mock
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
db_batch_object = MagicMock()
|
||||
db_batch_object.status = "in_progress"
|
||||
|
||||
|
|
@ -364,6 +370,7 @@ async def test_a_caller_that_handed_off_accounting_still_leaves_the_marker_alone
|
|||
prisma_client = MagicMock()
|
||||
update_mock = AsyncMock()
|
||||
prisma_client.db.litellm_managedobjecttable.update = update_mock
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
db_batch_object = MagicMock()
|
||||
db_batch_object.status = "in_progress"
|
||||
|
||||
|
|
|
|||
|
|
@ -3984,6 +3984,7 @@ def test_get_file_content_model_routed_attaches_trusted_model_credentials(monkey
|
|||
managed_file_row.storage_url = None
|
||||
prisma_stub = MagicMock()
|
||||
prisma_stub.db.litellm_managedfiletable.find_first = AsyncMock(return_value=managed_file_row)
|
||||
prisma_stub.replica_db = prisma_stub.db
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma_stub)
|
||||
setup_proxy_logging_object(monkeypatch, router)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ def _user() -> UserAPIKeyAuth:
|
|||
def _prisma_client(file_rows=None, batch_rows=None) -> MagicMock:
|
||||
pc = MagicMock()
|
||||
pc.db = MagicMock()
|
||||
pc.replica_db = pc.db
|
||||
pc.db.litellm_managedfiletable = MagicMock()
|
||||
pc.db.litellm_managedfiletable.find_first = AsyncMock(return_value=None)
|
||||
pc.db.litellm_managedfiletable.find_many = AsyncMock(
|
||||
|
|
@ -118,6 +119,7 @@ async def test_list_batches_out_of_range_limit_raises_400(limit, expected_messag
|
|||
assert exc.value.openai_code == expected_openai_code
|
||||
assert exc.value.message == expected_message
|
||||
pc.db.litellm_managedobjecttable.find_many.assert_not_called()
|
||||
pc.replica_db = pc.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -140,6 +142,7 @@ async def test_list_batches_limit_zero_returns_empty_page_without_db_query():
|
|||
"has_more": False,
|
||||
}
|
||||
pc.db.litellm_managedobjecttable.find_many.assert_not_called()
|
||||
pc.replica_db = pc.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -199,6 +202,7 @@ async def test_streamed_response_is_owned_and_rewritten_across_chunk_boundaries(
|
|||
)
|
||||
|
||||
pc.db.litellm_managedobjecttable.upsert.assert_awaited_once()
|
||||
pc.replica_db = pc.db
|
||||
created = pc.db.litellm_managedobjecttable.upsert.await_args.kwargs["data"]["create"]
|
||||
assert created["created_by"] == "user-1"
|
||||
assert created["team_id"] == "team-1"
|
||||
|
|
@ -229,6 +233,7 @@ async def test_streamed_response_with_cr_only_frame_delimiters_is_still_owned_an
|
|||
)
|
||||
|
||||
pc.db.litellm_managedobjecttable.upsert.assert_awaited_once()
|
||||
pc.replica_db = pc.db
|
||||
managed_id = pc.db.litellm_managedobjecttable.upsert.await_args.kwargs["data"]["create"]["unified_object_id"]
|
||||
assert RAW_RESPONSE_ID.encode() not in output
|
||||
assert output == _response_stream_bytes(managed_id).replace(b"\n", b"\r")
|
||||
|
|
@ -252,12 +257,14 @@ async def test_streamed_bytes_untouched_on_routes_without_a_response_id():
|
|||
|
||||
assert output == payload
|
||||
pc.db.litellm_managedobjecttable.upsert.assert_not_awaited()
|
||||
pc.replica_db = pc.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_streamed_response_stays_raw_and_intact_when_the_row_cannot_be_persisted():
|
||||
pc = _prisma_client()
|
||||
pc.db.litellm_managedobjecttable.upsert = AsyncMock(side_effect=RuntimeError("db down"))
|
||||
pc.replica_db = pc.db
|
||||
payload = _response_stream_bytes()
|
||||
|
||||
output = await _collect(
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ class TestListPoliciesIncludesConfig:
|
|||
row = _make_policy_row(policy_id="uuid-1", policy_name="db-policy", guardrails_add=["db-guard"])
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[row])
|
||||
prisma.replica_db = prisma.db
|
||||
_set_prisma(monkeypatch, prisma)
|
||||
policy_registry.load_policies({"config-policy": {"guardrails": {"add": ["tooling"]}}})
|
||||
|
||||
|
|
@ -124,6 +125,7 @@ class TestListPoliciesIncludesConfig:
|
|||
row = _make_policy_row(policy_id="uuid-1", policy_name="shared-name", guardrails_add=["db-guard"])
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[row])
|
||||
prisma.replica_db = prisma.db
|
||||
_set_prisma(monkeypatch, prisma)
|
||||
policy_registry.load_policies({"shared-name": {"guardrails": {"add": ["config-guard"]}}})
|
||||
|
||||
|
|
@ -146,6 +148,7 @@ class TestListPoliciesIncludesConfig:
|
|||
)
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[row])
|
||||
prisma.replica_db = prisma.db
|
||||
_set_prisma(monkeypatch, prisma)
|
||||
policy_registry.load_policies({"shared-name": {"guardrails": {"add": ["config-guard"]}}})
|
||||
|
||||
|
|
@ -171,11 +174,13 @@ class TestListPoliciesIncludesConfig:
|
|||
production_row = _make_policy_row(policy_id="uuid-1", policy_name="shared-name", guardrails_add=["db-guard"])
|
||||
sync_prisma = MagicMock()
|
||||
sync_prisma.db.litellm_policytable.find_many = AsyncMock(side_effect=[[production_row], []])
|
||||
sync_prisma.replica_db = sync_prisma.db
|
||||
await policy_registry.sync_policies_from_db(sync_prisma)
|
||||
assert policy_registry.get_source("shared-name") == "db"
|
||||
|
||||
fresh_prisma = MagicMock()
|
||||
fresh_prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[])
|
||||
fresh_prisma.replica_db = fresh_prisma.db
|
||||
_set_prisma(monkeypatch, fresh_prisma)
|
||||
|
||||
response = await policy_endpoints.list_policies()
|
||||
|
|
@ -191,6 +196,7 @@ class TestListPoliciesIncludesConfig:
|
|||
row = _make_policy_row(policy_id="uuid-1", policy_name="db-policy", version_status="draft")
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[row])
|
||||
prisma.replica_db = prisma.db
|
||||
_set_prisma(monkeypatch, prisma)
|
||||
policy_registry.load_policies({"config-policy": {"guardrails": {"add": ["tooling"]}}})
|
||||
|
||||
|
|
@ -232,6 +238,7 @@ class TestListAttachmentsIncludesConfig:
|
|||
row = _make_attachment_row(attachment_id="att-1", policy_name="db-policy")
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policyattachmenttable.find_many = AsyncMock(return_value=[row])
|
||||
prisma.replica_db = prisma.db
|
||||
_set_prisma(monkeypatch, prisma)
|
||||
attachment_registry.load_attachments([{"policy": "config-policy", "scope": "*"}])
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class _FakePrisma:
|
|||
|
||||
def __init__(self, teams: Set[str] = frozenset(), keys: Set[str] = frozenset()):
|
||||
self.db = _FakeDB(teams, keys)
|
||||
self.replica_db = self.db
|
||||
|
||||
|
||||
class _FakeRouter:
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ class TestSyncPoliciesFromDbProductionOnly:
|
|||
prisma = MagicMock()
|
||||
prod_row = _make_row(policy_id="prod-1", version_status="production")
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[prod_row])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await registry.get_all_policies_from_db(
|
||||
prisma, version_status="production"
|
||||
|
|
@ -134,6 +135,7 @@ class TestSyncPoliciesFromDbProductionOnly:
|
|||
guardrails_add=["g1"],
|
||||
)
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[prod_row])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
await registry.sync_policies_from_db(prisma)
|
||||
|
||||
|
|
@ -156,6 +158,7 @@ class TestUpdatePolicyDraftOnly:
|
|||
prisma = MagicMock()
|
||||
prod_row = _make_row(policy_id="pid-1", version_status="production")
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=prod_row)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
with pytest.raises(Exception, match='Error updating policy in DB: Only draft versions can be') as exc_info:
|
||||
await registry.update_policy_in_db(
|
||||
|
|
@ -187,6 +190,7 @@ class TestUpdatePolicyDraftOnly:
|
|||
description="new",
|
||||
)
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=draft_row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.update = AsyncMock(return_value=updated_row)
|
||||
|
||||
result = await registry.update_policy_in_db(
|
||||
|
|
@ -215,6 +219,7 @@ class TestDeletePolicyFromDb:
|
|||
version_status="production",
|
||||
)
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=prod_row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.delete = AsyncMock()
|
||||
|
||||
result = await registry.delete_policy_from_db(
|
||||
|
|
@ -238,6 +243,7 @@ class TestDeletePolicyFromDb:
|
|||
version_status="draft",
|
||||
)
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=draft_row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.delete = AsyncMock()
|
||||
|
||||
result = await registry.delete_policy_from_db(
|
||||
|
|
@ -268,6 +274,7 @@ class TestCreateNewVersion:
|
|||
)
|
||||
# find_first for production
|
||||
prisma.db.litellm_policytable.find_first = AsyncMock(return_value=prod)
|
||||
prisma.replica_db = prisma.db
|
||||
# find_first for latest version number
|
||||
prisma.db.litellm_policytable.find_first.side_effect = [
|
||||
prod, # production lookup
|
||||
|
|
@ -321,6 +328,7 @@ class TestUpdateVersionStatus:
|
|||
published_at=datetime.now(timezone.utc),
|
||||
)
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=draft)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.update = AsyncMock(return_value=updated)
|
||||
|
||||
result = await registry.update_version_status(
|
||||
|
|
@ -340,6 +348,7 @@ class TestUpdateVersionStatus:
|
|||
prisma = MagicMock()
|
||||
draft = _make_row(policy_id="d-1", version_status="draft")
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=draft)
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
with pytest.raises(Exception, match='Error updating version status: Cannot promote draft') as exc_info:
|
||||
await registry.update_version_status(
|
||||
|
|
@ -370,6 +379,7 @@ class TestUpdateVersionStatus:
|
|||
prisma.db.litellm_policytable.find_unique = AsyncMock(
|
||||
return_value=published_row
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.update_many = AsyncMock()
|
||||
prisma.db.litellm_policytable.update = AsyncMock(return_value=updated_row)
|
||||
|
||||
|
|
@ -406,6 +416,7 @@ class TestCompareVersions:
|
|||
guardrails_add=["g1", "g2"],
|
||||
)
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(side_effect=[a, b])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await registry.compare_versions(
|
||||
policy_id_a="a",
|
||||
|
|
@ -434,6 +445,7 @@ class TestResolveGuardrailsProductionOnly:
|
|||
guardrails_add=["g1"],
|
||||
)
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[prod_row])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await registry.resolve_guardrails_from_db(
|
||||
policy_name="base",
|
||||
|
|
@ -457,6 +469,7 @@ class TestGetPolicyRegistrySingleton:
|
|||
def _prisma_with_policy_rows(production_rows, non_production_rows=None):
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(side_effect=[production_rows, non_production_rows or []])
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -595,6 +608,7 @@ class TestRemovePolicyRestoresConfigFallback:
|
|||
prisma = MagicMock()
|
||||
prod_row = _make_row(policy_id="prod-1", policy_name="shared-name", version_status="production")
|
||||
prisma.db.litellm_policytable.find_unique = AsyncMock(return_value=prod_row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_policytable.delete = AsyncMock()
|
||||
|
||||
result = await registry.delete_policy_from_db(policy_id="prod-1", prisma_client=prisma)
|
||||
|
|
@ -612,6 +626,7 @@ class TestRemovePolicyRestoresConfigFallback:
|
|||
registry.add_policy("shared-name", Policy(guardrails=PolicyGuardrails(add=["db-guard"])), source="db")
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.delete_many = AsyncMock()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await registry.delete_all_versions(policy_name="shared-name", prisma_client=prisma)
|
||||
|
||||
|
|
@ -626,6 +641,7 @@ class TestRemovePolicyRestoresConfigFallback:
|
|||
registry.add_policy("db-only", Policy(guardrails=PolicyGuardrails(add=["db-guard"])), source="db")
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_policytable.delete_many = AsyncMock()
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
result = await registry.delete_all_versions(policy_name="db-only", prisma_client=prisma)
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ async def test_full_lifecycle_create_draft_edit_publish_promote():
|
|||
return created_v1
|
||||
|
||||
prisma.db.litellm_policytable.create = AsyncMock(side_effect=create_impl)
|
||||
prisma.replica_db = prisma.db
|
||||
req = PolicyCreateRequest(
|
||||
policy_name="lifecycle-policy",
|
||||
description="Initial",
|
||||
|
|
@ -205,6 +206,7 @@ async def test_attachments_resolve_against_production_after_promotion():
|
|||
guardrails_add=["ga", "gb"],
|
||||
)
|
||||
prisma.db.litellm_policytable.find_many = AsyncMock(return_value=[prod_row])
|
||||
prisma.replica_db = prisma.db
|
||||
|
||||
resolved = await registry.resolve_guardrails_from_db(
|
||||
policy_name="att-policy",
|
||||
|
|
|
|||
|
|
@ -396,6 +396,7 @@ class TestConfigPromptInfoWithEnvironment:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_prompttable.find_many = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
return mock_prisma
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ async def test_delete_prompt_success():
|
|||
# Mock DB Client
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_prompttable.delete_many = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock In-Memory Registry
|
||||
with patch(
|
||||
|
|
@ -102,6 +103,7 @@ async def test_delete_prompt_by_base_id_success():
|
|||
# Mock DB Client
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_prompttable.delete_many = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
# Mock In-Memory Registry
|
||||
with patch(
|
||||
|
|
@ -147,6 +149,7 @@ async def test_delete_prompt_environment_scope_reaches_db_and_registry():
|
|||
mock_user_auth = UserAPIKeyAuth(api_key="sk-1234", user_role=LitellmUserRoles.PROXY_ADMIN)
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_prompttable.delete_many = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch( # test-quality-ok: stubs the collaborator so the test pins what the endpoint deletes
|
||||
"litellm.proxy.prompts.prompt_registry.IN_MEMORY_PROMPT_REGISTRY"
|
||||
|
|
@ -235,6 +238,7 @@ async def test_patch_prompt_row_deleted_mid_update_returns_404():
|
|||
mock_prisma_client.db.litellm_prompttable.find_many = AsyncMock(
|
||||
return_value=[target_row]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_prompttable.update = AsyncMock(return_value=None)
|
||||
|
||||
existing_prompt = PromptSpec(
|
||||
|
|
@ -275,6 +279,7 @@ async def test_patch_prompt_merges_unsent_fields_from_db_row_not_stale_memory():
|
|||
db_row = _db_row("Begin every reply with HOWDY")
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_prompttable.find_many = AsyncMock(return_value=[db_row])
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_prompttable.update = AsyncMock(return_value=db_row)
|
||||
stale_in_memory = PromptSpec(
|
||||
prompt_id="test_prompt.v1",
|
||||
|
|
@ -440,6 +445,7 @@ async def test_patch_prompt_info_only_keeps_legacy_keyed_row_patchable():
|
|||
mock_prisma_client.db.litellm_prompttable.find_many = AsyncMock(
|
||||
return_value=[target_row]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_prompttable.update = AsyncMock(return_value=updated_row)
|
||||
|
||||
existing_prompt = PromptSpec(
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ async def test_create_prompt_stores_environment_and_created_by():
|
|||
mock_prisma_client.db.litellm_prompttable.create = AsyncMock(
|
||||
return_value=mock_db_entry
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
mock_prisma_client.db.litellm_prompttable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
request = Prompt(
|
||||
|
|
@ -157,6 +158,7 @@ async def test_update_prompt_stores_environment_and_created_by():
|
|||
mock_prisma_client.db.litellm_prompttable.find_many = AsyncMock(
|
||||
return_value=[mock_existing]
|
||||
)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
mock_db_entry = MagicMock()
|
||||
mock_db_entry.model_dump.return_value = {
|
||||
|
|
@ -223,6 +225,7 @@ async def test_delete_prompt_scoped_to_environment():
|
|||
|
||||
mock_prisma_client = MagicMock()
|
||||
mock_prisma_client.db.litellm_prompttable.delete_many = AsyncMock(return_value=None)
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.prompts.prompt_registry.IN_MEMORY_PROMPT_REGISTRY"
|
||||
|
|
|
|||
|
|
@ -925,6 +925,7 @@ async def test_tuning_baseline_v3_is_created_alongside_the_legacy_row():
|
|||
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_config.create = AsyncMock()
|
||||
deployment = {
|
||||
"model_name": "a",
|
||||
|
|
@ -962,6 +963,7 @@ async def test_scorer_baseline_upgrade_preserves_existing_routers_and_is_not_ref
|
|||
else None
|
||||
)
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_config.create = AsyncMock()
|
||||
|
||||
baseline = await ProxyStartupEvent._load_heuristic_v1_tuning_baselines(prisma_client, deployments)
|
||||
|
|
@ -1003,6 +1005,7 @@ async def test_tuning_baseline_waits_for_a_complete_db_model_census(monkeypatch)
|
|||
|
||||
assert result is None
|
||||
prisma_client.db.litellm_config.find_unique.assert_not_called()
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ def _attach_litellm_config(mock_prisma):
|
|||
table.delete = AsyncMock()
|
||||
table.delete_many = AsyncMock()
|
||||
mock_prisma.db.litellm_config = table
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
return table
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ def _make_prisma_with_end_user_row(spend: float | None):
|
|||
prisma.db.litellm_endusertable.find_unique = AsyncMock(
|
||||
return_value=None if spend is None else MagicMock(spend=spend)
|
||||
)
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -262,6 +263,7 @@ async def test_get_current_spend_end_user_floor_admits_after_a_reset_on_a_stale_
|
|||
|
||||
assert result == 0.0
|
||||
prisma.db.litellm_endusertable.find_unique.assert_awaited_once_with(where={"user_id": "customer-42"})
|
||||
prisma.replica_db = prisma.db
|
||||
fake_cache.redis_cache.async_set_max.assert_not_called()
|
||||
|
||||
|
||||
|
|
@ -331,6 +333,7 @@ async def test_get_current_spend_floors_window_against_spend_logs(monkeypatch):
|
|||
def _make_window_spend_prisma(row=None, spend_logs_total=0.0):
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_budgetwindowspend.find_unique = AsyncMock(return_value=row)
|
||||
prisma.replica_db = prisma.db
|
||||
prisma.db.litellm_spendlogs.group_by = AsyncMock(
|
||||
return_value=[{"api_key": "tok", "_sum": {"spend": spend_logs_total}}]
|
||||
)
|
||||
|
|
@ -366,6 +369,7 @@ async def test_get_current_spend_floors_window_against_maintained_row(monkeypatc
|
|||
|
||||
assert result == 15.0
|
||||
fake_prisma.db.litellm_spendlogs.group_by.assert_not_awaited()
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
fake_cache.redis_cache.async_set_max.assert_awaited_once_with(key=counter_key, value=15.0)
|
||||
|
||||
|
||||
|
|
@ -397,6 +401,7 @@ async def test_get_current_spend_floors_window_against_logs_when_row_stale(monke
|
|||
|
||||
assert result == 15.0
|
||||
fake_prisma.db.litellm_spendlogs.group_by.assert_awaited_once()
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
|
|
@ -552,6 +552,7 @@ def test_rag_ingest_rejects_non_string_provider(client_internal_user):
|
|||
def test_rag_ingest_never_creates_db_row_for_registry_store(client_internal_user):
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_managedvectorstorestable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
create_in_db = AsyncMock()
|
||||
aingest_patch, registry_patch = _patched_ingest_boundary(
|
||||
S3_REGISTRY_STORE, {"vector_store_id": "s3-store", "file_id": "file_123"}
|
||||
|
|
@ -576,6 +577,7 @@ def test_rag_ingest_never_creates_db_row_for_registry_store(client_internal_user
|
|||
def test_rag_ingest_fresh_store_creates_db_row_with_the_requesters_params(client_internal_user):
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_managedvectorstorestable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
create_in_db = AsyncMock()
|
||||
with (
|
||||
patch( # test-quality-ok: aingest is the endpoint's downstream boundary; persistence is what the test asserts
|
||||
|
|
@ -633,6 +635,7 @@ async def test_save_vector_store_from_rag_ingest_appends_file_to_db_managed_stor
|
|||
existing_row.vector_store_metadata = {"ingested_files": [{"file_id": "file_old"}]}
|
||||
prisma_client = MagicMock()
|
||||
table = prisma_client.db.litellm_managedvectorstorestable
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
table.find_unique = AsyncMock(return_value=existing_row)
|
||||
table.update = AsyncMock()
|
||||
create_in_db = AsyncMock()
|
||||
|
|
@ -660,6 +663,7 @@ async def test_save_vector_store_from_rag_ingest_still_creates_row_for_fresh_sto
|
|||
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_managedvectorstorestable.find_unique = AsyncMock(return_value=None)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
create_in_db = AsyncMock()
|
||||
|
||||
with patch( # test-quality-ok: the DB write boundary whose inputs the test asserts
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ async def test_delete_cloudzero_settings_success(client, monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config = mock_litellm_config
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
@ -57,6 +58,7 @@ async def test_delete_cloudzero_settings_not_found(client, monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config = mock_litellm_config
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
@ -93,6 +95,7 @@ async def test_get_cloudzero_settings_success(client, monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config = mock_litellm_config
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
@ -134,6 +137,7 @@ async def test_get_cloudzero_settings_not_configured(client, monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config = mock_litellm_config
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
@ -168,6 +172,7 @@ async def test_get_cloudzero_settings_empty_param_value(client, monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_config = mock_litellm_config
|
||||
|
||||
monkeypatch.setattr(ps, "prisma_client", mock_prisma)
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ async def test_batch_reads_never_touch_a_prisma_client_when_redis_answers(monkey
|
|||
redis = CountingRedis({"spend:key:hashed": 3.0})
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_verificationtoken.find_unique = AsyncMock()
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(ps, "spend_counter_cache", _spend_counter_cache(redis))
|
||||
monkeypatch.setattr(ps, "prisma_client", prisma)
|
||||
|
||||
|
|
@ -301,6 +302,7 @@ async def test_batch_reads_never_touch_a_prisma_client_when_redis_answers(monkey
|
|||
def _reseed_prisma(spend: float) -> MagicMock:
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_verificationtoken.find_unique = AsyncMock(return_value=MagicMock(spend=spend))
|
||||
prisma.replica_db = prisma.db
|
||||
return prisma
|
||||
|
||||
|
||||
|
|
@ -381,6 +383,7 @@ async def test_post_call_cold_counters_seed_from_the_mget_miss_without_a_second_
|
|||
redis.async_set_cache = AsyncMock(return_value=True)
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=MagicMock(spend=4.0))
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(ps, "spend_counter_cache", _spend_counter_cache(redis))
|
||||
monkeypatch.setattr(ps, "prisma_client", prisma)
|
||||
|
||||
|
|
@ -444,6 +447,7 @@ async def test_reconcile_settles_a_flushed_counter_on_its_own_after_the_shared_p
|
|||
redis.async_set_max = AsyncMock(return_value=4.0)
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=MagicMock(spend=4.0))
|
||||
prisma.replica_db = prisma.db
|
||||
monkeypatch.setattr(ps, "spend_counter_cache", _spend_counter_cache(redis))
|
||||
monkeypatch.setattr(ps, "prisma_client", prisma)
|
||||
reservation = _reservation(reserved_cost=0.4)
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ async def test_spend_query_uses_timestamp_filtering():
|
|||
mock_query_raw = AsyncMock(return_value=[])
|
||||
mock_db.query_raw = mock_query_raw
|
||||
mock_prisma.db = mock_db
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
# Use timezone-aware datetime objects
|
||||
start_date = datetime.datetime(2024, 1, 1, tzinfo=timezone.utc)
|
||||
|
|
@ -87,6 +88,7 @@ async def test_global_activity_wraps_params_in_at_time_zone_utc(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
|
@ -134,6 +136,7 @@ async def test_global_activity_internal_user_wraps_params_in_at_time_zone_utc(
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
|
@ -168,6 +171,7 @@ async def test_spend_logs_ui_wraps_params_in_at_time_zone_utc(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
mock_prisma.db.litellm_spendlogs = MagicMock()
|
||||
mock_prisma.db.litellm_spendlogs.count = AsyncMock(return_value=0)
|
||||
|
|
@ -209,6 +213,7 @@ def _make_ui_spend_logs_mock(count_total, page_rows):
|
|||
"""
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(
|
||||
side_effect=[[{"total_count": count_total}], page_rows]
|
||||
)
|
||||
|
|
@ -259,6 +264,7 @@ async def test_spend_logs_ui_uses_bounded_count_not_full_scan(monkeypatch):
|
|||
)
|
||||
|
||||
mock_prisma.db.litellm_spendlogs.count.assert_not_called()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
count_call = mock_prisma.db.query_raw.call_args_list[0]
|
||||
count_sql = count_call[0][0]
|
||||
|
|
@ -347,6 +353,7 @@ async def test_spend_logs_ui_empty_page_reports_zero_total(monkeypatch):
|
|||
# page.
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(side_effect=[[{"total_count": 0}], []])
|
||||
mock_prisma.db.litellm_spendlogs = MagicMock()
|
||||
mock_prisma.db.litellm_spendlogs.count = AsyncMock(return_value=0)
|
||||
|
|
@ -395,6 +402,7 @@ async def test_spend_logs_ui_out_of_range_page_keeps_total(monkeypatch):
|
|||
# out-of-range page (empty).
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(side_effect=[[{"total_count": 7}], []])
|
||||
mock_prisma.db.litellm_spendlogs = MagicMock()
|
||||
mock_prisma.db.litellm_spendlogs.count = AsyncMock(return_value=0)
|
||||
|
|
@ -436,6 +444,7 @@ async def test_get_spend_by_team_binds_optional_team_filter():
|
|||
"""
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_query_raw = AsyncMock(return_value=[])
|
||||
mock_prisma.db.query_raw = mock_query_raw
|
||||
|
||||
|
|
@ -487,6 +496,7 @@ async def test_global_spend_report_team_group_forwards_team_id(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
|
@ -545,6 +555,7 @@ async def test_spend_logs_ui_group_by_session_paginates_sessions(monkeypatch):
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.query_raw = AsyncMock(side_effect=mock_query_raw)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
|
|||
|
|
@ -426,6 +426,7 @@ async def test_should_shrink_second_tag_reservation_to_remaining_budget(
|
|||
)
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_tagtable.find_many = AsyncMock(return_value=[])
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
|
||||
with patch(
|
||||
"litellm.proxy.spend_tracking.budget_reservation.estimate_request_max_cost",
|
||||
|
|
@ -2561,7 +2562,7 @@ async def test_reconcile_before_db_update_does_not_double_count_when_flush_lands
|
|||
counter_cache.redis_cache = redis_cache
|
||||
counter_cache.in_memory_cache.set_cache(key=counter_key, value=0.6)
|
||||
db_floor = _TeamMembershipFloorDb(spend=0.3)
|
||||
ps.prisma_client = SimpleNamespace(db=db_floor)
|
||||
ps.prisma_client = SimpleNamespace(db=db_floor, replica_db=db_floor)
|
||||
|
||||
reservation = {
|
||||
"reserved_cost": 0.6,
|
||||
|
|
@ -3476,6 +3477,7 @@ class _ModelAccessGroupBudgetPrisma:
|
|||
self.db = SimpleNamespace(
|
||||
litellm_modelaccessgroupbudgettable=SimpleNamespace(find_many=self._find_many)
|
||||
)
|
||||
self.replica_db = self.db
|
||||
|
||||
async def _find_many(self, **kwargs):
|
||||
requested = list(kwargs["where"]["access_group_name"]["in"])
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ class TestCreateFallback:
|
|||
"""Create a mock prisma client"""
|
||||
client = MagicMock()
|
||||
client.db.litellm_config.upsert = AsyncMock()
|
||||
client.replica_db = client.db
|
||||
client.jsonify_object = lambda x: x
|
||||
return client
|
||||
|
||||
|
|
@ -178,6 +179,7 @@ class TestCreateFallback:
|
|||
|
||||
# Verify database was updated
|
||||
mock_prisma_client.db.litellm_config.upsert.assert_called_once()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
async def test_create_fallback_router_not_initialized(
|
||||
self, mock_prisma_client, mock_proxy_config, mock_user_api_key_dict
|
||||
|
|
@ -430,6 +432,7 @@ class TestDeleteFallback:
|
|||
"""Create a mock prisma client"""
|
||||
client = MagicMock()
|
||||
client.db.litellm_config.upsert = AsyncMock()
|
||||
client.replica_db = client.db
|
||||
client.jsonify_object = lambda x: x
|
||||
return client
|
||||
|
||||
|
|
@ -487,6 +490,7 @@ class TestDeleteFallback:
|
|||
|
||||
# Verify database was updated
|
||||
mock_prisma_client.db.litellm_config.upsert.assert_called_once()
|
||||
mock_prisma_client.replica_db = mock_prisma_client.db
|
||||
|
||||
async def test_delete_fallback_not_found(
|
||||
self,
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ async def test_filter_resolves_access_group_names():
|
|||
# Prisma mock
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_db)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
result = await _filter_models_by_team_id(
|
||||
|
|
@ -129,6 +130,7 @@ async def test_filter_resolves_mix_of_access_groups_and_literal_names():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_db)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
result = await _filter_models_by_team_id(
|
||||
|
|
@ -173,6 +175,7 @@ async def test_filter_excludes_models_from_other_access_group():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_db)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(return_value=[])
|
||||
|
||||
result = await _filter_models_by_team_id(
|
||||
|
|
@ -212,6 +215,7 @@ async def test_filter_db_fallback_receives_resolved_model_names():
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_db)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_proxymodeltable.find_many = AsyncMock(
|
||||
return_value=[mock_db_model]
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ def mock_prisma():
|
|||
"""Simplified mock PrismaClient with bound methods"""
|
||||
client = MagicMock()
|
||||
client.db.litellm_healthchecktable.create = AsyncMock(return_value={"id": "test-id"})
|
||||
client.replica_db = client.db
|
||||
client.db.litellm_healthchecktable.find_many = AsyncMock(return_value=[{"id": "1", "model_name": "test"}])
|
||||
|
||||
# Bind actual methods
|
||||
|
|
@ -55,6 +56,7 @@ async def test_save_health_check_result(mock_prisma, status, healthy, unhealthy,
|
|||
"""Test health check result saving with various scenarios"""
|
||||
if not should_succeed:
|
||||
mock_prisma.db.litellm_healthchecktable.create.side_effect = Exception("DB Error")
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result = await mock_prisma.save_health_check_result(
|
||||
model_name="test-model",
|
||||
|
|
@ -74,6 +76,7 @@ async def test_get_health_check_history(mock_prisma):
|
|||
"""Test health check history retrieval"""
|
||||
result = await mock_prisma.get_health_check_history(model_name="test", limit=50)
|
||||
mock_prisma.db.litellm_healthchecktable.find_many.assert_called_once()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
assert len(result) == 1
|
||||
|
||||
|
||||
|
|
@ -375,6 +378,7 @@ async def test_save_background_health_checks_to_db():
|
|||
mock_prisma = MagicMock()
|
||||
mock_prisma.save_health_check_result = AsyncMock()
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
model_list = [
|
||||
{
|
||||
|
|
@ -494,6 +498,7 @@ def _one_model_setup():
|
|||
async def test_save_background_health_checks_to_db_returns_false_when_a_write_fails():
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.query_raw = AsyncMock(return_value=[])
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.save_health_check_result = AsyncMock(return_value=None)
|
||||
model_list, healthy_endpoints, unhealthy_endpoints = _one_model_setup()
|
||||
|
||||
|
|
@ -511,6 +516,7 @@ async def test_save_background_health_checks_to_db_writes_nothing_when_the_lates
|
|||
cycle by every pod while the read kept failing, which is what filled the table in production.
|
||||
"""
|
||||
mock_prisma.db.query_raw = AsyncMock(side_effect=RuntimeError("db down"))
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.save_health_check_result = AsyncMock(return_value={"id": "row"})
|
||||
model_list, healthy_endpoints, unhealthy_endpoints = _one_model_setup()
|
||||
|
||||
|
|
@ -533,6 +539,7 @@ async def test_save_background_health_checks_to_db_exception_handling():
|
|||
"""Test exception handling in background health check save"""
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.query_raw = AsyncMock(side_effect=Exception("DB Error"))
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
model_list = [
|
||||
{
|
||||
|
|
@ -584,6 +591,7 @@ async def test_get_all_latest_health_checks_keeps_every_distinct_group_with_its_
|
|||
_raw_latest_row("gpt-4", None, now - timedelta(minutes=3)),
|
||||
]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
result = await mock_prisma.get_all_latest_health_checks()
|
||||
|
||||
|
|
@ -609,6 +617,7 @@ async def test_save_background_health_checks_compares_raw_checked_at_against_utc
|
|||
_raw_latest_row("fresh-model", "fresh-id", fresh),
|
||||
]
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.save_health_check_result = AsyncMock()
|
||||
model_list = [
|
||||
{"model_name": "stale-model", "model_info": {"id": "stale-id"}, "litellm_params": {"model": "openai/stale"}},
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ async def test_route_a2a_model_read_through_recovers_agent_created_on_sibling_re
|
|||
prisma_client.db.litellm_agentstable.find_unique = AsyncMock(
|
||||
side_effect=[None, _DbAgentRow("a2a-sibling-replica-agent-id", agent_name)]
|
||||
)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
|
||||
|
|
|
|||
|
|
@ -1151,7 +1151,8 @@ def _fake_prisma_client_with_models(rows):
|
|||
from types import SimpleNamespace
|
||||
|
||||
table = FakeProxyModelTable(rows)
|
||||
return SimpleNamespace(db=SimpleNamespace(litellm_proxymodeltable=table)), table
|
||||
tables = SimpleNamespace(litellm_proxymodeltable=table)
|
||||
return SimpleNamespace(db=tables, replica_db=tables), table
|
||||
|
||||
|
||||
def _db_model_row(model_name: str, mock_response: str):
|
||||
|
|
@ -1301,6 +1302,7 @@ async def test_route_request_a2a_agent_miss_does_not_consume_model_read_through(
|
|||
fake_prisma, model_table = _fake_prisma_client_with_models([])
|
||||
agents_find_unique = AsyncMock(return_value=None)
|
||||
fake_prisma.db.litellm_agentstable = SimpleNamespace(find_unique=agents_find_unique)
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", fake_prisma)
|
||||
monkeypatch.setattr(proxy_server, "store_model_in_db", True)
|
||||
monkeypatch.setattr(proxy_server, "llm_router", router)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ def happy_path_upsert(monkeypatch):
|
|||
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_row)
|
||||
prisma_client.replica_db = prisma_client.db
|
||||
prisma_client.db.litellm_teamtable.update = AsyncMock()
|
||||
|
||||
class _FakeTx:
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
# Mock decryption to return the values as-is (simulating decryption)
|
||||
|
|
@ -414,6 +415,7 @@ class TestProxySettingEndpoints:
|
|||
mock_db_record = MagicMock()
|
||||
mock_db_record.sso_settings = sso_settings
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=mock_db_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
# The resolver decrypts stored values via decrypt_value_helper; make it an
|
||||
|
|
@ -554,6 +556,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -639,6 +642,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -704,6 +708,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(
|
||||
|
|
@ -762,6 +767,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
|
||||
|
|
@ -842,6 +848,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
env_var_entry = MagicMock()
|
||||
|
|
@ -913,6 +920,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
|
||||
|
|
@ -991,6 +999,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -1336,6 +1345,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
response = client.get("/get/ui_settings")
|
||||
|
|
@ -1368,6 +1378,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", mock_prisma)
|
||||
|
||||
store = SettingsStore("general_settings")
|
||||
|
|
@ -1427,6 +1438,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
response = client.get("/get/ui_settings")
|
||||
|
|
@ -1463,6 +1475,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
class MockUser:
|
||||
|
|
@ -1491,6 +1504,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_uisettings.find_unique.assert_called_once_with(
|
||||
where={"id": "ui_settings"}
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
def test_update_ui_settings_allowlisted_value(self, mock_auth, monkeypatch):
|
||||
"""Test updating UI settings with an allowlisted field"""
|
||||
|
|
@ -1509,6 +1523,7 @@ class TestProxySettingEndpoints:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1551,6 +1566,7 @@ class TestProxySettingEndpoints:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1595,6 +1611,7 @@ class TestProxySettingEndpoints:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1632,6 +1649,7 @@ class TestProxySettingEndpoints:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1678,6 +1696,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1715,6 +1734,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1752,6 +1772,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1798,6 +1819,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -1852,6 +1874,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma = MagicMock()
|
||||
upsert_mock = AsyncMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = upsert_mock
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -1930,6 +1953,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
|
|
@ -1982,6 +2006,7 @@ class TestProxySettingEndpoints:
|
|||
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db = MagicMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
|
|
@ -2026,6 +2051,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client to return None (no record found)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
|
|
@ -2111,6 +2137,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
# Mock decryption to return the values as-is (role_mappings should not be passed to decryption)
|
||||
|
|
@ -2156,6 +2183,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
mock_prisma.db.litellm_config = MagicMock()
|
||||
mock_prisma.db.litellm_config.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -2298,6 +2326,7 @@ class TestProxySettingEndpoints:
|
|||
# Mock the prisma client to return None (no database record)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
# Run the async function
|
||||
role_mappings = asyncio.run(_setup_role_mappings())
|
||||
|
||||
|
|
@ -2335,6 +2364,7 @@ class TestProxySettingEndpoints:
|
|||
mock_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(
|
||||
return_value=mock_db_record
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
|
||||
from litellm.proxy.proxy_server import proxy_config
|
||||
|
|
@ -2391,6 +2421,7 @@ def test_update_internal_user_settings_writes_audit_log(mock_proxy_config, monke
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
monkeypatch.setattr(proxy_server_module, "prisma_client", fake_prisma)
|
||||
monkeypatch.setattr(proxy_server_module, "premium_user", True)
|
||||
|
|
@ -2480,6 +2511,7 @@ def test_update_sso_settings_writes_redacted_audit_log(mock_proxy_config, monkey
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
fake_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
# No prior SSO row, so before_value resolves to None.
|
||||
fake_prisma.db.litellm_ssoconfig.find_unique = AsyncMock(return_value=None)
|
||||
|
|
@ -2545,6 +2577,7 @@ def test_update_sso_settings_audit_captures_redacted_before_snapshot(
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
fake_prisma.db.litellm_ssoconfig.upsert = AsyncMock()
|
||||
|
||||
# Pre-existing SSO row contains the *prior* secret (would be ciphertext in
|
||||
|
|
@ -2624,6 +2657,7 @@ def test_add_allowed_ip_writes_audit_log(mock_proxy_config, monkeypatch):
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
monkeypatch.setattr(proxy_server_module, "prisma_client", fake_prisma)
|
||||
monkeypatch.setattr(proxy_server_module, "premium_user", True)
|
||||
|
|
@ -2684,6 +2718,7 @@ def test_add_allowed_ip_hands_save_config_only_the_changed_general_setting(monke
|
|||
|
||||
fake_prisma: Final = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = AsyncMock()
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
save_config: Final = AsyncMock(side_effect=lambda new_config: new_config)
|
||||
|
||||
async def _get_config():
|
||||
|
|
@ -2731,6 +2766,7 @@ def test_delete_allowed_ip_writes_deleted_audit_log(monkeypatch):
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
config = {"general_settings": {"allowed_ips": ["203.0.113.77", "198.51.100.1"]}}
|
||||
|
||||
|
|
@ -2791,6 +2827,7 @@ def test_allowed_ip_routes_refuse_a_config_owned_list_with_a_clear_400(route, mo
|
|||
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = AsyncMock()
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
async def _get_config():
|
||||
return {"general_settings": {"allowed_ips": ["203.0.113.77"]}}
|
||||
|
|
@ -2837,6 +2874,7 @@ def test_update_ui_theme_settings_writes_audit_log(mock_proxy_config, monkeypatc
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
monkeypatch.setattr(proxy_server_module, "prisma_client", fake_prisma)
|
||||
monkeypatch.setattr(proxy_server_module, "premium_user", True)
|
||||
|
|
@ -2886,6 +2924,7 @@ def test_update_ui_settings_writes_audit_log(monkeypatch):
|
|||
audit_create = AsyncMock()
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_auditlog.create = audit_create
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
fake_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
fake_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
|
||||
|
|
@ -2940,6 +2979,7 @@ def mock_team_lookup(monkeypatch):
|
|||
find_many = AsyncMock(side_effect=_find_many)
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_teamtable.find_many = find_many
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
member_budget_update = AsyncMock()
|
||||
|
||||
|
|
@ -3077,6 +3117,7 @@ def mock_organization_lookup(monkeypatch):
|
|||
find_unique = AsyncMock(side_effect=_find_unique)
|
||||
fake_prisma = MagicMock()
|
||||
fake_prisma.db.litellm_organizationtable.find_unique = find_unique
|
||||
fake_prisma.replica_db = fake_prisma.db
|
||||
|
||||
monkeypatch.setattr(proxy_server_module, "prisma_client", fake_prisma)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
|
|
@ -3516,6 +3557,7 @@ class TestPtuCostAttributionUISetting:
|
|||
mock_record = MagicMock()
|
||||
mock_record.ui_settings = stored
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=mock_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
return mock_prisma
|
||||
|
|
@ -3700,6 +3742,7 @@ class TestApplyUserBudgetToTeamKeysUISetting:
|
|||
mock_record = MagicMock()
|
||||
mock_record.ui_settings = stored
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=mock_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
return mock_prisma
|
||||
|
|
@ -3782,6 +3825,7 @@ class TestTeamAdminEditableTeamFieldsSetting:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
return mock_prisma
|
||||
|
|
@ -3876,6 +3920,7 @@ class TestTeamAdminEditableTeamFieldsSetting:
|
|||
mock_db_record = MagicMock()
|
||||
mock_db_record.ui_settings = {"team_admin_editable_team_fields": ["tpm_limit"]}
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=mock_db_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
general_settings: dict = {}
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", general_settings)
|
||||
|
|
@ -3904,6 +3949,7 @@ class TestTeamAdminEditableTeamFieldsSetting:
|
|||
mock_db_record = MagicMock()
|
||||
mock_db_record.ui_settings = {"team_admin_editable_team_fields": stored}
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=mock_db_record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", {})
|
||||
|
||||
try:
|
||||
|
|
@ -3944,6 +3990,7 @@ class TestSyncUiSettingsToGeneralSettings:
|
|||
}
|
||||
)
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
applied = await self._sync()(mock_prisma)
|
||||
|
||||
|
|
@ -3965,6 +4012,7 @@ class TestSyncUiSettingsToGeneralSettings:
|
|||
record = MagicMock()
|
||||
record.ui_settings = {"team_admin_editable_team_fields": ["rpm_limit"]}
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
await self._sync()(mock_prisma)
|
||||
|
||||
|
|
@ -3978,6 +4026,7 @@ class TestSyncUiSettingsToGeneralSettings:
|
|||
monkeypatch.setattr("litellm.proxy.proxy_server.general_settings", general_settings)
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=None)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
applied = await self._sync()(mock_prisma)
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ def mock_audit_log(monkeypatch):
|
|||
def _mock_prisma(monkeypatch, record=None):
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(return_value=record)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
mock_prisma.db.litellm_uisettings.upsert = AsyncMock()
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", mock_prisma)
|
||||
return mock_prisma
|
||||
|
|
@ -105,6 +106,7 @@ class TestUpdateUserBanner:
|
|||
response = client.patch("/update/user_banner", json=PUBLISH_BODY)
|
||||
assert response.status_code == 403
|
||||
mock_prisma.db.litellm_uisettings.upsert.assert_not_awaited()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
||||
def test_persists_and_round_trips(self, admin_auth, monkeypatch, mock_audit_log):
|
||||
mock_prisma = _mock_prisma(monkeypatch, record=None)
|
||||
|
|
@ -124,6 +126,7 @@ class TestUpdateUserBanner:
|
|||
mock_prisma.db.litellm_uisettings.find_unique = AsyncMock(
|
||||
return_value=SimpleNamespace(ui_settings=persisted_payload)
|
||||
)
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
read_back = client.get("/get/user_banner")
|
||||
assert read_back.status_code == 200
|
||||
assert read_back.json() == saved
|
||||
|
|
@ -173,3 +176,4 @@ class TestUpdateUserBanner:
|
|||
response = client.patch("/update/user_banner", json=payload)
|
||||
assert response.status_code == 422
|
||||
mock_prisma.db.litellm_uisettings.upsert.assert_not_awaited()
|
||||
mock_prisma.replica_db = mock_prisma.db
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue