mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-14 04:09:09 +00:00
Some checks failed
CI Coverage / assert-ci-coverage (push) Waiting to run
CodSpeed Benchmarks / benchmarks (push) Waiting to run
Helm unit test / unit-test (push) Waiting to run
Lens Worker Image / lens-worker-image (push) Waiting to run
Publish basedpyright base counts / publish (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
Code Quality Checks / python-310-import-smoke (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
LiteLLM Rust / rust-wheel (push) Waiting to run
LiteLLM Rust / rust-lint (push) Waiting to run
LiteLLM Rust / rust-test (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Proxy DB Operations / Lens Python 3.10 (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests / Vertex AI (push) Blocked by required conditions
Unit Tests / misc (push) Blocked by required conditions
Unit Tests / Build the Rust bridge (push) Waiting to run
Unit Tests / caching-local (push) Blocked by required conditions
Unit Tests / core-utils (push) Blocked by required conditions
Unit Tests / enterprise-managed-files (push) Blocked by required conditions
Unit Tests / enterprise-package (push) Blocked by required conditions
Unit Tests / enterprise-routing (push) Blocked by required conditions
Unit Tests / integrations (push) Blocked by required conditions
Unit Tests / OpenAI and Meta Providers (push) Blocked by required conditions
Unit Tests / All Other Providers (push) Blocked by required conditions
Unit Tests / misc-dirs (push) Blocked by required conditions
Unit Tests / proxy-auth (push) Blocked by required conditions
Unit Tests / proxy-endpoints (push) Blocked by required conditions
Unit Tests / unit (push) Blocked by required conditions
GitHub Actions Security Analysis / zizmor (push) Waiting to run
Unit Tests / proxy-extras (push) Blocked by required conditions
Unit Tests / proxy-feature-endpoints (push) Blocked by required conditions
Unit Tests / proxy-hooks-client (push) Blocked by required conditions
Unit Tests / proxy-infra (push) Blocked by required conditions
Unit Tests / proxy-infra-root (push) Blocked by required conditions
Unit Tests / proxy-server (push) Blocked by required conditions
Unit Tests / responses-caching-types (push) Blocked by required conditions
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Terraform Provider / gofmt, vet, build, test (push) Has been cancelled
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Has been cancelled
* feat(mcp): add portable authorized catalog pagination * fix(mcp): preserve routing and isolation across catalog pages * fix(mcp): preserve bare calls after complete catalog pages * test(mcp): verify bare calls with cached database catalog revisions * test(mcp): cover refreshed authority and failed catalog continuations * refactor(mcp): narrow pagination interfaces and preserve listed metadata * fix(mcp): publish listed metadata only after successful pagination * fix(mcp): defer bare routes until aggregate listing succeeds * fix(mcp): refresh key access groups on catalog pages * fix(mcp): accept read-only optional catalog headers * fix(mcp): preserve consolidated listing metadata after restack * fix(mcp): propagate unexpected catalog continuation failures * fix(mcp): preserve key grants when a user record is absent --------- Co-authored-by: Joshua Valluru <326636767+joshua-berri@users.noreply.github.com>
148 lines
4.9 KiB
Python
148 lines
4.9 KiB
Python
import asyncio
|
|
import importlib
|
|
import os
|
|
|
|
import pytest
|
|
|
|
import litellm
|
|
from litellm.litellm_core_utils.logging_worker import GLOBAL_LOGGING_WORKER
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def event_loop():
|
|
try:
|
|
loop = asyncio.get_running_loop()
|
|
except RuntimeError:
|
|
loop = asyncio.new_event_loop()
|
|
yield loop
|
|
loop.close()
|
|
|
|
|
|
@pytest.fixture(scope="function", autouse=True)
|
|
def setup_and_teardown():
|
|
"""
|
|
This fixture reloads litellm before every function. To speed up testing by removing callbacks being chained.
|
|
"""
|
|
importlib.reload(litellm)
|
|
import asyncio
|
|
|
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
asyncio.set_event_loop(loop)
|
|
yield
|
|
|
|
# Teardown code (executes after the yield point)
|
|
# LoggingWorker carries still-queued coroutines onto the next test's loop, where they'd log into that test's callbacks
|
|
asyncio.run(GLOBAL_LOGGING_WORKER.clear_queue())
|
|
loop.close() # Close the loop created earlier
|
|
asyncio.set_event_loop(None) # Remove the reference to the loop
|
|
|
|
|
|
@pytest.fixture(scope="function", autouse=True)
|
|
async def drain_logging_worker():
|
|
"""
|
|
The logging queue is bound to the running loop, so anything left queued when a test's loop
|
|
goes away is carried onto the next test's loop and fires against its callbacks.
|
|
"""
|
|
from litellm.litellm_core_utils.logging_worker import GLOBAL_LOGGING_WORKER
|
|
|
|
yield
|
|
|
|
try:
|
|
await asyncio.wait_for(GLOBAL_LOGGING_WORKER.clear_queue(), timeout=10)
|
|
except asyncio.TimeoutError:
|
|
pass
|
|
|
|
|
|
def pytest_collection_modifyitems(config, items):
|
|
# Separate tests in 'test_amazing_proxy_custom_logger.py' and other tests
|
|
custom_logger_tests = [
|
|
item for item in items if "custom_logger" in item.parent.name
|
|
]
|
|
other_tests = [item for item in items if "custom_logger" not in item.parent.name]
|
|
|
|
# Sort tests based on their names
|
|
custom_logger_tests.sort(key=lambda x: x.name)
|
|
other_tests.sort(key=lambda x: x.name)
|
|
|
|
# Reorder the items list
|
|
items[:] = custom_logger_tests + other_tests
|
|
|
|
|
|
@pytest.fixture
|
|
def config_only_mcp_manager_factory():
|
|
from litellm.proxy._experimental.mcp_server.mcp_server_manager import MCPServerManager
|
|
|
|
class ConfigOnlyManager(MCPServerManager):
|
|
def initialize_tool_name_to_mcp_server_name_mapping(self):
|
|
return None
|
|
|
|
return ConfigOnlyManager
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _hermetic_mcp_server_registry():
|
|
from litellm.proxy._experimental.mcp_server.catalog import CatalogSnapshots
|
|
|
|
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
|
global_mcp_server_manager,
|
|
)
|
|
|
|
from litellm.proxy._experimental.mcp_server.tool_registry import global_mcp_tool_registry
|
|
|
|
saved_tools = global_mcp_tool_registry.published_tools
|
|
global_mcp_tool_registry.published_tools = {}
|
|
saved_catalog = global_mcp_server_manager.catalog
|
|
global_mcp_server_manager.catalog = CatalogSnapshots(global_mcp_server_manager)
|
|
saved_registry = dict(global_mcp_server_manager.registry)
|
|
saved_config_servers = dict(global_mcp_server_manager.config_mcp_servers)
|
|
saved_tool_mapping = dict(global_mcp_server_manager.tool_name_to_mcp_server_name_mapping)
|
|
saved_oauth_slots = global_mcp_server_manager._oauth_discovery_slots
|
|
global_mcp_server_manager.registry.clear()
|
|
global_mcp_server_manager.config_mcp_servers.clear()
|
|
global_mcp_server_manager.tool_name_to_mcp_server_name_mapping.clear()
|
|
global_mcp_server_manager._oauth_discovery_slots = ()
|
|
try:
|
|
yield
|
|
finally:
|
|
global_mcp_server_manager.registry.clear()
|
|
global_mcp_server_manager.registry.update(saved_registry)
|
|
global_mcp_server_manager.config_mcp_servers.clear()
|
|
global_mcp_server_manager.config_mcp_servers.update(saved_config_servers)
|
|
global_mcp_server_manager.tool_name_to_mcp_server_name_mapping.clear()
|
|
global_mcp_server_manager.tool_name_to_mcp_server_name_mapping.update(saved_tool_mapping)
|
|
global_mcp_server_manager._oauth_discovery_slots = saved_oauth_slots
|
|
global_mcp_server_manager.catalog = saved_catalog
|
|
global_mcp_tool_registry.published_tools = saved_tools
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _hermetic_server_root_path():
|
|
saved = os.environ.pop("SERVER_ROOT_PATH", None)
|
|
try:
|
|
yield
|
|
finally:
|
|
if saved is not None:
|
|
os.environ["SERVER_ROOT_PATH"] = saved
|
|
|
|
|
|
@pytest.fixture
|
|
def _mcp_request_ctx():
|
|
def _mcp_request_ctx(**overrides):
|
|
from types import SimpleNamespace
|
|
|
|
from mcp.server.context import ServerRequestContext
|
|
|
|
kwargs = {
|
|
"session": SimpleNamespace(),
|
|
"lifespan_context": {},
|
|
"protocol_version": "2025-06-18",
|
|
"method": "",
|
|
"params": None,
|
|
"request_id": 1,
|
|
"meta": None,
|
|
"request": None,
|
|
}
|
|
kwargs.update(overrides)
|
|
return ServerRequestContext(**kwargs)
|
|
|
|
return _mcp_request_ctx
|