Skip to content

Commit c13b7c0

Browse files
committed
test(proxy): cover list-valued fallback preflight
1 parent 55471c2 commit c13b7c0

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
from unittest.mock import AsyncMock
2+
3+
import pytest
4+
5+
from litellm.proxy.route_llm_request import _get_available_fallback_request
6+
7+
8+
class _ListFallbackRouter:
9+
max_fallbacks = 5
10+
model_group_alias = {}
11+
12+
def __init__(self, fallbacks, healthy_models):
13+
self.fallbacks = fallbacks
14+
self.healthy_models = set(healthy_models)
15+
self.model_list = [
16+
{"model_info": {"id": "primary-deployment"}},
17+
{"model_info": {"id": "first-deployment"}},
18+
{"model_info": {"id": "second-deployment"}},
19+
{"model_info": {"id": "later-deployment"}},
20+
]
21+
self.async_pre_routing_hook = AsyncMock(return_value=None)
22+
23+
async def async_get_healthy_deployments(self, *, model, **kwargs):
24+
if model not in self.healthy_models:
25+
return []
26+
deployment_id = {
27+
"first-model": "first-deployment",
28+
"second-model": "second-deployment",
29+
"later-model": "later-deployment",
30+
}[model]
31+
return [{"model_info": {"id": deployment_id}}]
32+
33+
34+
@pytest.mark.asyncio
35+
async def test_list_valued_direct_fallback_uses_first_healthy_candidate():
36+
router = _ListFallbackRouter(
37+
fallbacks=[{"model": ["first-model", "second-model"], "temperature": 0.2}],
38+
healthy_models={"second-model"},
39+
)
40+
41+
request = await _get_available_fallback_request(
42+
llm_router=router,
43+
model_name="blocked-model",
44+
team_id=None,
45+
request_data={"messages": [{"role": "user", "content": "hello"}]},
46+
)
47+
48+
assert request is not None
49+
assert request["model"] == "second-model"
50+
assert request["temperature"] == 0.2
51+
assert request["fallbacks"] == []
52+
assert [call.kwargs["model"] for call in router.async_pre_routing_hook.await_args_list] == [
53+
"first-model",
54+
"second-model",
55+
]
56+
57+
58+
@pytest.mark.asyncio
59+
async def test_list_valued_direct_fallback_preserves_remaining_candidates_in_trusted_tail():
60+
router = _ListFallbackRouter(
61+
fallbacks=[
62+
{"model": ["first-model", "second-model"], "temperature": 0.2},
63+
"later-model",
64+
],
65+
healthy_models={"first-model", "second-model", "later-model"},
66+
)
67+
68+
request = await _get_available_fallback_request(
69+
llm_router=router,
70+
model_name="blocked-model",
71+
team_id=None,
72+
request_data={"messages": [{"role": "user", "content": "hello"}]},
73+
)
74+
75+
assert request is not None
76+
assert request["model"] == "first-model"
77+
assert request["fallbacks"] == [
78+
{"model": "second-model", "temperature": 0.2},
79+
"later-model",
80+
]

0 commit comments

Comments
 (0)