From 4ea320ddf0458b41711682528d6dd7b8c75de47f Mon Sep 17 00:00:00 2001 From: songjianglin <270247441+2017955725@users.noreply.github.com> Date: Wed, 7 Oct 2026 21:31:38 +0800 Subject: [PATCH 1/5] fix(proxy): make the CLI test flag use the configured endpoint --- litellm/proxy/proxy_cli.py | 2 +- tests/unit/proxy/test_proxy_cli.py | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index a9745565799..dfedcd5146e 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -243,7 +243,7 @@ class ProxyInitializationHelpers: api_base = f"http://{host}:{port}" if isinstance(test, str): api_base = test - else: + elif test is not True: raise ValueError("Invalid test value") client: Final = openai.OpenAI(api_key="My API Key", base_url=api_base) diff --git a/tests/unit/proxy/test_proxy_cli.py b/tests/unit/proxy/test_proxy_cli.py index 47071827f2c..3945a5547c6 100644 --- a/tests/unit/proxy/test_proxy_cli.py +++ b/tests/unit/proxy/test_proxy_cli.py @@ -3,7 +3,7 @@ import os from contextlib import nullcontext from pathlib import Path from types import SimpleNamespace -from unittest.mock import AsyncMock, MagicMock, patch +from unittest.mock import AsyncMock, MagicMock, call, patch import click import fastapi @@ -80,16 +80,13 @@ class TestProxyInitializationHelpers: mock_stream_response = MagicMock() mock_stream_response.__iter__.return_value = [MagicMock(), MagicMock()] - mock_client.chat.completions.create.side_effect = [ - mock_response, - mock_stream_response, - ] + mock_client.chat.completions.create.return_value = mock_response + mock_client.completions.create.return_value = mock_response # Execute - with pytest.raises(ValueError, match="Invalid test value"): - ProxyInitializationHelpers._run_test_chat_completion( - "localhost", 8000, "gpt-3.5-turbo", True - ) + ProxyInitializationHelpers._run_test_chat_completion( + "localhost", 8000, "gpt-3.5-turbo", True + ) # Test with valid string test value ProxyInitializationHelpers._run_test_chat_completion( @@ -97,9 +94,10 @@ class TestProxyInitializationHelpers: ) # Assert - mock_openai.assert_called_once_with( - api_key="My API Key", base_url="http://test-url" - ) + assert mock_openai.call_args_list == [ + call(api_key="My API Key", base_url="http://localhost:8000"), + call(api_key="My API Key", base_url="http://test-url"), + ] mock_client.chat.completions.create.assert_called() def test_get_default_unvicorn_init_args(self): From 1c3a41bb1f4b3b4ed6b5dcc1101f5b93372496cd Mon Sep 17 00:00:00 2001 From: songjianglin <270247441+2017955725@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:16:32 +0800 Subject: [PATCH 2/5] test(proxy): cover script path cleanup --- tests/unit/proxy/test_proxy_cli.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/unit/proxy/test_proxy_cli.py b/tests/unit/proxy/test_proxy_cli.py index b19048ea632..4375ee8b8f3 100644 --- a/tests/unit/proxy/test_proxy_cli.py +++ b/tests/unit/proxy/test_proxy_cli.py @@ -37,6 +37,13 @@ def fork_reservation(): @pytest.mark.xdist_group("proxy_cli") class TestProxyInitializationHelpers: + def test_drop_script_dir_from_sys_path(self): + script_dir = os.path.dirname(os.path.abspath(proxy_cli.__file__)) + with patch.object(sys, "path", [script_dir, "outside"]): + proxy_cli._drop_script_dir_from_sys_path() + + assert sys.path == ["outside"] + @patch("importlib.metadata.version") @patch("click.echo") def test_echo_litellm_version(self, mock_echo, mock_version): From 8db78a64c8c69bb879d14782b150717076b41805 Mon Sep 17 00:00:00 2001 From: songjianglin <270247441+2017955725@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:15:42 +0800 Subject: [PATCH 3/5] test(proxy): verify streamed chunks for both CLI test endpoints --- tests/unit/proxy/test_proxy_cli.py | 45 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/tests/unit/proxy/test_proxy_cli.py b/tests/unit/proxy/test_proxy_cli.py index 4375ee8b8f3..5cd0f728bcf 100644 --- a/tests/unit/proxy/test_proxy_cli.py +++ b/tests/unit/proxy/test_proxy_cli.py @@ -37,8 +37,8 @@ def fork_reservation(): @pytest.mark.xdist_group("proxy_cli") class TestProxyInitializationHelpers: - def test_drop_script_dir_from_sys_path(self): - script_dir = os.path.dirname(os.path.abspath(proxy_cli.__file__)) + def test_drop_script_dir_from_sys_path(self) -> None: + script_dir: Final = os.path.dirname(os.path.abspath(proxy_cli.__file__)) with patch.object(sys, "path", [script_dir, "outside"]): proxy_cli._drop_script_dir_from_sys_path() @@ -78,35 +78,34 @@ class TestProxyInitializationHelpers: @patch("openai.OpenAI") @patch("click.echo") @patch("builtins.print") - def test_run_test_chat_completion(self, mock_print, mock_echo, mock_openai): - # Setup - mock_client = MagicMock() + def test_run_test_chat_completion( + self, mock_print: MagicMock, mock_echo: MagicMock, mock_openai: MagicMock + ) -> None: + mock_client: Final = MagicMock() mock_openai.return_value = mock_client - - mock_response = MagicMock() - mock_client.chat.completions.create.return_value = mock_response - - mock_stream_response = MagicMock() - mock_stream_response.__iter__.return_value = [MagicMock(), MagicMock()] - mock_client.chat.completions.create.return_value = mock_response + mock_response: Final = MagicMock() + stream_chunks: Final = ("first chunk", "second chunk") + mock_client.chat.completions.create.side_effect = ( + mock_response, + stream_chunks, + mock_response, + stream_chunks, + ) mock_client.completions.create.return_value = mock_response - # Execute - ProxyInitializationHelpers._run_test_chat_completion( - "localhost", 8000, "gpt-3.5-turbo", True - ) + ProxyInitializationHelpers._run_test_chat_completion("localhost", 8000, "test-model", True) + ProxyInitializationHelpers._run_test_chat_completion("localhost", 8000, "test-model", "http://test-url") - # Test with valid string test value - ProxyInitializationHelpers._run_test_chat_completion( - "localhost", 8000, "gpt-3.5-turbo", "http://test-url" - ) - - # Assert assert mock_openai.call_args_list == [ call(api_key="My API Key", base_url="http://localhost:8000"), call(api_key="My API Key", base_url="http://test-url"), ] - mock_client.chat.completions.create.assert_called() + assert [ + request.kwargs.get("stream", False) for request in mock_client.chat.completions.create.call_args_list + ] == [False, True, False, True] + assert mock_client.completions.create.call_count == 2 + for chunk in stream_chunks: + assert mock_echo.call_args_list.count(call(f"LiteLLM: streaming response from proxy {chunk}")) == 2 def test_get_default_unvicorn_init_args(self): # Test without log_config From 77c9b70e81a943d1de4714e94a7fb72981d81bcd Mon Sep 17 00:00:00 2001 From: songjianglin <270247441+2017955725@users.noreply.github.com> Date: Thu, 8 Oct 2026 18:41:31 +0800 Subject: [PATCH 4/5] test(proxy): run CLI regressions in the runtime CI shard --- .github/workflows/test-unit-proxy-db.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-unit-proxy-db.yml b/.github/workflows/test-unit-proxy-db.yml index ba88464d652..8ed07837917 100644 --- a/.github/workflows/test-unit-proxy-db.yml +++ b/.github/workflows/test-unit-proxy-db.yml @@ -131,6 +131,7 @@ jobs: timeout: 15 - test-group: proxy-runtime test-path: >- + tests/unit/proxy/test_proxy_cli.py tests/unit/proxy/auth/test_multipart_bypass_repro.py tests/unit/proxy/auth/test_proxy_routes.py tests/unit/proxy/middleware/test_request_size_limit_middleware.py From 1cad47643f41acf4d3b7a2a14844b394485e5d82 Mon Sep 17 00:00:00 2001 From: songjianglin <270247441+2017955725@users.noreply.github.com> Date: Fri, 9 Oct 2026 16:52:37 +0800 Subject: [PATCH 5/5] test(proxy): assert real CLI streaming output --- tests/unit/proxy/test_proxy_cli.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/proxy/test_proxy_cli.py b/tests/unit/proxy/test_proxy_cli.py index 338339840a8..b27ed24789b 100644 --- a/tests/unit/proxy/test_proxy_cli.py +++ b/tests/unit/proxy/test_proxy_cli.py @@ -76,10 +76,8 @@ class TestProxyInitializationHelpers: mock_dumps.assert_called_once_with({"status": "healthy"}, indent=4) @patch("openai.OpenAI") - @patch("click.echo") - @patch("builtins.print") def test_run_test_chat_completion( - self, mock_print: MagicMock, mock_echo: MagicMock, mock_openai: MagicMock + self, mock_openai: MagicMock, capsys: pytest.CaptureFixture[str] ) -> None: mock_client: Final = MagicMock() mock_openai.return_value = mock_client @@ -104,8 +102,9 @@ class TestProxyInitializationHelpers: request.kwargs.get("stream", False) for request in mock_client.chat.completions.create.call_args_list ] == [False, True, False, True] assert mock_client.completions.create.call_count == 2 + output: Final = capsys.readouterr().out for chunk in stream_chunks: - assert mock_echo.call_args_list.count(call(f"LiteLLM: streaming response from proxy {chunk}")) == 2 + assert output.count(f"LiteLLM: streaming response from proxy {chunk}\n") == 2 def test_get_default_unvicorn_init_args(self): # Test without log_config