mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-24 00:52:24 +00:00
test(router): call both mid-stream fallback attempt functions directly
The router coverage gate wants every router.py function reached by name from a router test. The two per-endpoint attempt functions were only reached through their callers, so each now has a direct test proving the per-request controls carrier never reaches the provider call and every hop's stream comes back wrapped.
This commit is contained in:
parent
a2ae80ec9b
commit
b0305d0a31
2 changed files with 82 additions and 0 deletions
|
|
@ -423,6 +423,44 @@ async def test_aresponses_per_request_fallbacks_survive_into_hop_streams():
|
|||
assert collected == [completed_event]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aresponses_attempt_strips_the_controls_carrier_and_wraps_every_hop_stream():
|
||||
"""Each attempt of the chain, not only the primary's, comes back wrapped for mid-stream
|
||||
failover, and the per-request controls carrier rides into the wrapper's re-entry kwargs
|
||||
without ever reaching the provider call."""
|
||||
from types import MappingProxyType
|
||||
|
||||
from litellm.router_utils.fallback_event_handlers import (
|
||||
MID_STREAM_FALLBACK_CONTROLS_KEY,
|
||||
MidStreamFallbackControls,
|
||||
)
|
||||
|
||||
router = _make_three_tier_router()
|
||||
completed_event = _make_completed_event(1, 1, 2)
|
||||
hop_stream = _scripted_responses_stream([completed_event])
|
||||
seen: dict = {}
|
||||
|
||||
async def fake_original(**kwargs):
|
||||
seen.update(kwargs)
|
||||
return hop_stream
|
||||
|
||||
controls = MidStreamFallbackControls(MappingProxyType({"fallbacks": [{"primary": ["fb1", "fb2"]}]}))
|
||||
stream = await router._ageneric_api_call_with_fallbacks_responses_attempt(
|
||||
model="fb1",
|
||||
original_generic_function=fake_original,
|
||||
stream=True,
|
||||
input="hi",
|
||||
**{MID_STREAM_FALLBACK_CONTROLS_KEY: controls},
|
||||
)
|
||||
collected = [event async for event in stream]
|
||||
|
||||
assert seen["model"] == "openai/fb1-model"
|
||||
assert MID_STREAM_FALLBACK_CONTROLS_KEY not in seen
|
||||
assert "fallbacks" not in seen
|
||||
assert stream is not hop_stream
|
||||
assert collected == [completed_event]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_aresponses_fallback_on_in_stream_error_event():
|
||||
"""A retriable in-stream error event (429) must trigger the router's mid-stream
|
||||
|
|
|
|||
|
|
@ -14222,6 +14222,50 @@ async def test_anthropic_messages_hop_stream_failure_reaches_second_fallback_ent
|
|||
assert b"overloaded_error" not in body
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_anthropic_messages_attempt_strips_the_controls_carrier_and_wraps_every_hop_stream():
|
||||
"""Each attempt of the chain, not only the primary's, comes back wrapped for mid-stream
|
||||
failover, and the per-request controls carrier never reaches the provider call."""
|
||||
from types import MappingProxyType
|
||||
|
||||
from litellm.router_utils.fallback_event_handlers import (
|
||||
MID_STREAM_FALLBACK_CONTROLS_KEY,
|
||||
MidStreamFallbackControls,
|
||||
)
|
||||
|
||||
router = Router(
|
||||
model_list=[
|
||||
{"model_name": "fb1", "litellm_params": {"model": "anthropic/fb1-model", "api_key": "sk-test"}},
|
||||
],
|
||||
num_retries=0,
|
||||
)
|
||||
hop_stream = _AnthropicMessagesFakeByteStream(
|
||||
[_anthropic_messages_message_start_chunk(), _anthropic_messages_content_chunk("from fb1")]
|
||||
)
|
||||
seen: dict = {}
|
||||
|
||||
async def fake_original(**kwargs):
|
||||
seen.update(kwargs)
|
||||
return hop_stream
|
||||
|
||||
controls = MidStreamFallbackControls(MappingProxyType({"fallbacks": [{"primary": ["fb1", "fb2"]}]}))
|
||||
stream = await router._ageneric_api_call_with_fallbacks_anthropic_messages_attempt(
|
||||
model="fb1",
|
||||
original_generic_function=fake_original,
|
||||
stream=True,
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
max_tokens=10,
|
||||
**{MID_STREAM_FALLBACK_CONTROLS_KEY: controls},
|
||||
)
|
||||
body = b"".join([chunk async for chunk in stream])
|
||||
|
||||
assert seen["model"] == "anthropic/fb1-model"
|
||||
assert MID_STREAM_FALLBACK_CONTROLS_KEY not in seen
|
||||
assert "fallbacks" not in seen
|
||||
assert stream is not hop_stream
|
||||
assert b"from fb1" in body
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_anthropic_messages_fallback_triggers_after_lifecycle_only_frame():
|
||||
"""Regression: Anthropic routinely sends a message_start lifecycle frame
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue