mirror of
https://github.com/tiennm99/litellm.git
synced 2026-06-18 05:28:02 +00:00
86 lines
3.8 KiB
Python
86 lines
3.8 KiB
Python
"""
|
|
Regression test for default_deployment shallow copy optimization.
|
|
|
|
Tests the critical side effect: ensure modifying returned deployment
|
|
doesn't corrupt the original default_deployment instance.
|
|
"""
|
|
|
|
import sys
|
|
import os
|
|
|
|
sys.path.insert(0, os.path.abspath("../.."))
|
|
|
|
from litellm import Router
|
|
|
|
|
|
def test_default_deployment_isolation():
|
|
"""
|
|
Regression test for shallow copy optimization in _common_checks_available_deployment.
|
|
|
|
When a model is not in model_names and default_deployment is set, the router
|
|
returns a copy of default_deployment with the model name updated. This test
|
|
ensures the optimization (shallow copy instead of deepcopy) properly isolates
|
|
each returned deployment from the original and from each other.
|
|
|
|
The shallow copy optimization copies two levels:
|
|
1. Top-level deployment dict
|
|
2. litellm_params dict
|
|
|
|
Deeper nested objects are intentionally shared for performance (safe because
|
|
the router only modifies the 'model' field at litellm_params level).
|
|
|
|
Critical behavior verified:
|
|
1. Each deployment gets independent model value
|
|
2. Original default_deployment unchanged for litellm_params fields
|
|
3. Shared fields (api_key) accessible in all copies
|
|
4. Adding new litellm_params fields is isolated per deployment
|
|
5. Deep nested objects ARE shared (acceptable trade-off)
|
|
"""
|
|
# Setup: Router with a default deployment (used for unknown models)
|
|
router = Router(model_list=[])
|
|
|
|
router.default_deployment = { # type: ignore
|
|
"model_name": "default-model",
|
|
"litellm_params": {
|
|
"model": "gpt-3.5-turbo", # This will be overwritten per request
|
|
"api_key": "test-key", # This should be shared
|
|
"custom_config": { # Deep nested - will be SHARED
|
|
"nested_setting": "original",
|
|
},
|
|
},
|
|
}
|
|
|
|
# Act: Request two different unknown models (triggers default deployment path)
|
|
_, deployment1 = router._common_checks_available_deployment(
|
|
model="custom-model-1", # Unknown model
|
|
messages=[{"role": "user", "content": "test"}],
|
|
)
|
|
|
|
_, deployment2 = router._common_checks_available_deployment(
|
|
model="custom-model-2", # Different unknown model
|
|
messages=[{"role": "user", "content": "test"}],
|
|
)
|
|
|
|
# Assert: Each deployment should have its own independent model value
|
|
assert deployment1["litellm_params"]["model"] == "custom-model-1" # type: ignore
|
|
assert deployment2["litellm_params"]["model"] == "custom-model-2" # type: ignore
|
|
|
|
# Assert: Original default_deployment must remain unchanged (not mutated by requests)
|
|
assert router.default_deployment["litellm_params"]["model"] == "gpt-3.5-turbo" # type: ignore
|
|
|
|
# Assert: Shared fields should still be accessible in all copies
|
|
assert deployment1["litellm_params"]["api_key"] == "test-key" # type: ignore
|
|
assert deployment2["litellm_params"]["api_key"] == "test-key" # type: ignore
|
|
|
|
# Assert: Modifying litellm_params in one deployment doesn't affect others
|
|
# This tests the shallow copy properly isolated the litellm_params dict level
|
|
deployment1["litellm_params"]["temperature"] = 0.9 # type: ignore
|
|
assert "temperature" not in deployment2["litellm_params"] # type: ignore
|
|
assert "temperature" not in router.default_deployment["litellm_params"] # type: ignore
|
|
|
|
# Assert: Deep nested objects ARE shared (intentional trade-off for 100x perf gain)
|
|
# Safe because router only modifies top-level litellm_params fields
|
|
deployment1["litellm_params"]["custom_config"]["nested_setting"] = "modified" # type: ignore
|
|
assert deployment2["litellm_params"]["custom_config"]["nested_setting"] == "modified" # type: ignore
|
|
assert router.default_deployment["litellm_params"]["custom_config"]["nested_setting"] == "modified" # type: ignore
|