|
9 | 9 | import click
|
10 | 10 | import httpx
|
11 | 11 | import pytest
|
| 12 | +import yaml |
12 | 13 | from fastapi import FastAPI
|
13 | 14 | from fastapi.testclient import TestClient
|
14 | 15 |
|
@@ -74,3 +75,92 @@ async def test_initialize_scheduled_jobs_credentials(monkeypatch):
|
74 | 75 | call[0] for call in mock_proxy_config.get_credentials.mock_calls
|
75 | 76 | ]
|
76 | 77 | assert len(mock_scheduler_calls) > 0
|
| 78 | + |
| 79 | + |
| 80 | +# Mock Prisma |
| 81 | +class MockPrisma: |
| 82 | + def __init__(self, database_url=None, proxy_logging_obj=None, http_client=None): |
| 83 | + self.database_url = database_url |
| 84 | + self.proxy_logging_obj = proxy_logging_obj |
| 85 | + self.http_client = http_client |
| 86 | + |
| 87 | + async def connect(self): |
| 88 | + pass |
| 89 | + |
| 90 | + async def disconnect(self): |
| 91 | + pass |
| 92 | + |
| 93 | + |
| 94 | +mock_prisma = MockPrisma() |
| 95 | + |
| 96 | + |
| 97 | +@patch( |
| 98 | + "litellm.proxy.proxy_server.ProxyStartupEvent._setup_prisma_client", |
| 99 | + return_value=mock_prisma, |
| 100 | +) |
| 101 | +@pytest.mark.asyncio |
| 102 | +async def test_aaaproxy_startup_master_key(mock_prisma, monkeypatch, tmp_path): |
| 103 | + """ |
| 104 | + Test that master_key is correctly loaded from either config.yaml or environment variables |
| 105 | + """ |
| 106 | + import yaml |
| 107 | + from fastapi import FastAPI |
| 108 | + |
| 109 | + # Import happens here - this is when the module probably reads the config path |
| 110 | + from litellm.proxy.proxy_server import proxy_startup_event |
| 111 | + |
| 112 | + # Mock the Prisma import |
| 113 | + monkeypatch.setattr("litellm.proxy.proxy_server.PrismaClient", MockPrisma) |
| 114 | + |
| 115 | + # Create test app |
| 116 | + app = FastAPI() |
| 117 | + |
| 118 | + # Test Case 1: Master key from config.yaml |
| 119 | + test_master_key = "sk-12345" |
| 120 | + test_config = {"general_settings": {"master_key": test_master_key}} |
| 121 | + |
| 122 | + # Create a temporary config file |
| 123 | + config_path = tmp_path / "config.yaml" |
| 124 | + with open(config_path, "w") as f: |
| 125 | + yaml.dump(test_config, f) |
| 126 | + |
| 127 | + print(f"SET ENV VARIABLE - CONFIG_FILE_PATH, str(config_path): {str(config_path)}") |
| 128 | + # Second setting of CONFIG_FILE_PATH to a different value |
| 129 | + monkeypatch.setenv("CONFIG_FILE_PATH", str(config_path)) |
| 130 | + print(f"config_path: {config_path}") |
| 131 | + print(f"os.getenv('CONFIG_FILE_PATH'): {os.getenv('CONFIG_FILE_PATH')}") |
| 132 | + async with proxy_startup_event(app): |
| 133 | + from litellm.proxy.proxy_server import master_key |
| 134 | + |
| 135 | + assert master_key == test_master_key |
| 136 | + |
| 137 | + # Test Case 2: Master key from environment variable |
| 138 | + test_env_master_key = "sk-67890" |
| 139 | + |
| 140 | + # Create empty config |
| 141 | + empty_config = {"general_settings": {}} |
| 142 | + with open(config_path, "w") as f: |
| 143 | + yaml.dump(empty_config, f) |
| 144 | + |
| 145 | + monkeypatch.setenv("LITELLM_MASTER_KEY", test_env_master_key) |
| 146 | + print("test_env_master_key: {}".format(test_env_master_key)) |
| 147 | + async with proxy_startup_event(app): |
| 148 | + from litellm.proxy.proxy_server import master_key |
| 149 | + |
| 150 | + assert master_key == test_env_master_key |
| 151 | + |
| 152 | + # Test Case 3: Master key with os.environ prefix |
| 153 | + test_resolved_key = "sk-resolved-key" |
| 154 | + test_config_with_prefix = { |
| 155 | + "general_settings": {"master_key": "os.environ/CUSTOM_MASTER_KEY"} |
| 156 | + } |
| 157 | + |
| 158 | + # Create config with os.environ prefix |
| 159 | + with open(config_path, "w") as f: |
| 160 | + yaml.dump(test_config_with_prefix, f) |
| 161 | + |
| 162 | + monkeypatch.setenv("CUSTOM_MASTER_KEY", test_resolved_key) |
| 163 | + async with proxy_startup_event(app): |
| 164 | + from litellm.proxy.proxy_server import master_key |
| 165 | + |
| 166 | + assert master_key == test_resolved_key |
0 commit comments