From 49980db0b9b2e97109ff27dcd8d33e8d5647463d Mon Sep 17 00:00:00 2001 From: JingHao-Leon <102573344+JingHao-Leon@users.noreply.github.com> Date: Sun, 11 Oct 2026 18:40:06 +0800 Subject: [PATCH] test(streaming): cover the three failure branches of the abandoned-stream flush codecov/patch was at 77.41% against an 87.23% target. The uncovered lines were all error paths, so this adds a test per branch rather than reshaping the happy path: - nothing streamed (`wrapper.chunks` empty): the flush must not assemble or record anything, and must not mark the stream as logged; - `litellm.stream_chunk_builder` raising: the failure is logged and swallowed, no half-built response is recorded, and the stream still counts as logged so a second close does not retry; - the provider stream's own `close()` raising: that must not mask the caller's error, and the reference is still dropped. `test_close_survives_provider_stream_raising` uses a real object whose `close` raises rather than a mock with a configured side effect, so the assertion is about the outcome (reference dropped, no propagation) instead of the call. --- .../test_streaming_handler.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/unit/litellm_core_utils/test_streaming_handler.py b/tests/unit/litellm_core_utils/test_streaming_handler.py index 6c2b8f52455..5ebc7a2c1ab 100644 --- a/tests/unit/litellm_core_utils/test_streaming_handler.py +++ b/tests/unit/litellm_core_utils/test_streaming_handler.py @@ -6210,3 +6210,41 @@ class TestCloseFlushesAbandonedStream: # the provider stream was closed and the reference dropped assert released == [True] assert wrapper.completion_stream is None + + def test_no_flush_when_nothing_was_streamed(self): + wrapper, logging_obj = self._wrapper_with_chunk() + wrapper.chunks = [] + + wrapper.close_stream() + + # nothing was served, so there is nothing to bill or log + assert "async_complete_streaming_response" not in logging_obj.model_call_details + assert wrapper._abandonment_logged is False + + def test_flush_survives_stream_chunk_builder_raising(self): + wrapper, logging_obj = self._wrapper_with_chunk() + + def _boom(**_kwargs): + raise RuntimeError("builder exploded") + + with patch("litellm.stream_chunk_builder", _boom): + wrapper.close_stream() + + # the failure is logged, not raised, and nothing half-built is recorded + assert "async_complete_streaming_response" not in logging_obj.model_call_details + assert wrapper._abandonment_logged is True + + def test_close_survives_provider_stream_raising(self): + wrapper, _ = self._wrapper_with_chunk() + + class _Angry: + def close(inner_self): + raise OSError("already closed") + + wrapper.completion_stream = _Angry() + + wrapper.close_stream() + + # a provider that fails to close must not mask the caller's own error, + # and the reference is still dropped + assert wrapper.completion_stream is None