mirror of
https://github.com/tiennm99/litellm.git
synced 2026-06-17 22:48:35 +00:00
171 lines
5.2 KiB
Python
171 lines
5.2 KiB
Python
"""Unit tests for ProxyStartupEvent._init_pyroscope (Grafana Pyroscope profiling)."""
|
|
|
|
import os
|
|
import sys
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from litellm.proxy.proxy_server import ProxyStartupEvent
|
|
|
|
|
|
def _mock_pyroscope_module():
|
|
"""Return a mock module so 'import pyroscope' succeeds in _init_pyroscope."""
|
|
m = MagicMock()
|
|
m.configure = MagicMock()
|
|
return m
|
|
|
|
|
|
def test_init_pyroscope_returns_cleanly_when_disabled():
|
|
"""When LITELLM_ENABLE_PYROSCOPE is false, _init_pyroscope returns without error."""
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=False,
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{"LITELLM_ENABLE_PYROSCOPE": "false"},
|
|
clear=False,
|
|
),
|
|
):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
|
|
|
|
def test_init_pyroscope_raises_when_enabled_but_missing_app_name():
|
|
"""When LITELLM_ENABLE_PYROSCOPE is true but PYROSCOPE_APP_NAME is not set, raises ValueError."""
|
|
mock_pyroscope = _mock_pyroscope_module()
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=True,
|
|
),
|
|
patch.dict(
|
|
sys.modules,
|
|
{"pyroscope": mock_pyroscope},
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{
|
|
"LITELLM_ENABLE_PYROSCOPE": "true",
|
|
"PYROSCOPE_APP_NAME": "",
|
|
"PYROSCOPE_SERVER_ADDRESS": "http://localhost:4040",
|
|
},
|
|
clear=False,
|
|
),
|
|
):
|
|
with pytest.raises(ValueError, match="PYROSCOPE_APP_NAME"):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
|
|
|
|
def test_init_pyroscope_raises_when_enabled_but_missing_server_address():
|
|
"""When LITELLM_ENABLE_PYROSCOPE is true but PYROSCOPE_SERVER_ADDRESS is not set, raises ValueError."""
|
|
mock_pyroscope = _mock_pyroscope_module()
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=True,
|
|
),
|
|
patch.dict(
|
|
sys.modules,
|
|
{"pyroscope": mock_pyroscope},
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{
|
|
"LITELLM_ENABLE_PYROSCOPE": "true",
|
|
"PYROSCOPE_APP_NAME": "myapp",
|
|
"PYROSCOPE_SERVER_ADDRESS": "",
|
|
},
|
|
clear=False,
|
|
),
|
|
):
|
|
with pytest.raises(ValueError, match="PYROSCOPE_SERVER_ADDRESS"):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
|
|
|
|
def test_init_pyroscope_raises_when_sample_rate_invalid():
|
|
"""When PYROSCOPE_SAMPLE_RATE is not a number, raises ValueError."""
|
|
mock_pyroscope = _mock_pyroscope_module()
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=True,
|
|
),
|
|
patch.dict(
|
|
sys.modules,
|
|
{"pyroscope": mock_pyroscope},
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{
|
|
"LITELLM_ENABLE_PYROSCOPE": "true",
|
|
"PYROSCOPE_APP_NAME": "myapp",
|
|
"PYROSCOPE_SERVER_ADDRESS": "http://localhost:4040",
|
|
"PYROSCOPE_SAMPLE_RATE": "not-a-number",
|
|
},
|
|
clear=False,
|
|
),
|
|
):
|
|
with pytest.raises(ValueError, match="PYROSCOPE_SAMPLE_RATE"):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
|
|
|
|
def test_init_pyroscope_accepts_integer_sample_rate():
|
|
"""When enabled with valid config and integer sample rate, configures pyroscope."""
|
|
mock_pyroscope = _mock_pyroscope_module()
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=True,
|
|
),
|
|
patch.dict(
|
|
sys.modules,
|
|
{"pyroscope": mock_pyroscope},
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{
|
|
"LITELLM_ENABLE_PYROSCOPE": "true",
|
|
"PYROSCOPE_APP_NAME": "myapp",
|
|
"PYROSCOPE_SERVER_ADDRESS": "http://localhost:4040",
|
|
"PYROSCOPE_SAMPLE_RATE": "100",
|
|
},
|
|
clear=False,
|
|
),
|
|
):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
mock_pyroscope.configure.assert_called_once()
|
|
call_kw = mock_pyroscope.configure.call_args[1]
|
|
assert call_kw["app_name"] == "myapp"
|
|
assert call_kw["server_address"] == "http://localhost:4040"
|
|
assert call_kw["sample_rate"] == 100
|
|
|
|
|
|
def test_init_pyroscope_accepts_float_sample_rate_parsed_as_int():
|
|
"""PYROSCOPE_SAMPLE_RATE can be a float string; it is parsed as integer."""
|
|
mock_pyroscope = _mock_pyroscope_module()
|
|
with (
|
|
patch(
|
|
"litellm.proxy.proxy_server.get_secret_bool",
|
|
return_value=True,
|
|
),
|
|
patch.dict(
|
|
sys.modules,
|
|
{"pyroscope": mock_pyroscope},
|
|
),
|
|
patch.dict(
|
|
os.environ,
|
|
{
|
|
"LITELLM_ENABLE_PYROSCOPE": "true",
|
|
"PYROSCOPE_APP_NAME": "myapp",
|
|
"PYROSCOPE_SERVER_ADDRESS": "http://localhost:4040",
|
|
"PYROSCOPE_SAMPLE_RATE": "100.7",
|
|
},
|
|
clear=False,
|
|
),
|
|
):
|
|
ProxyStartupEvent._init_pyroscope()
|
|
call_kw = mock_pyroscope.configure.call_args[1]
|
|
assert call_kw["sample_rate"] == 100
|