fix(caching): route redis test_connection through the shared client factory

The connection test built its client with async Redis(**redis_kwargs), which rejects a url kwarg, so every url-mode Test Connection from the admin UI failed with "Redis.__init__() got an unexpected keyword argument 'url'". Going through get_redis_async_client reuses the from_url / cluster / sentinel routing the cache itself uses.
This commit is contained in:
Devin AI 2026-07-25 19:09:11 +00:00
parent 998a372417
commit 00144f438a
2 changed files with 50 additions and 9 deletions

View file

@ -1286,17 +1286,15 @@ class RedisCache(BaseCache):
Returns:
dict: {"status": "success" | "failed", "message": str, "error": Optional[str]}
"""
from .._redis import get_redis_async_client
try:
import redis.asyncio as redis_async
redis_client = get_redis_async_client(**self.redis_kwargs)
# Create a fresh Redis client with current settings
redis_client = redis_async.Redis(**self.redis_kwargs)
# Test the connection
ping_result = await redis_client.ping() # type: ignore[misc]
# Close the connection
await redis_client.aclose() # type: ignore[attr-defined]
try:
ping_result = await redis_client.ping() # type: ignore[misc]
finally:
await redis_client.aclose() # type: ignore[attr-defined]
if ping_result:
return {

View file

@ -428,3 +428,46 @@ def test_delete_cache_namespaces_key(namespace, expected, monkeypatch, redis_no_
redis_cache.redis_client = mock_client
redis_cache.delete_cache(key="k")
mock_client.delete.assert_called_once_with(expected)
@pytest.mark.asyncio
async def test_test_connection_with_url_pings_url_target(monkeypatch, redis_no_ping):
"""A url-mode cache must connect through redis.asyncio.Redis.from_url.
Building the client with `Redis(**redis_kwargs)` instead blows up with
"Redis.__init__() got an unexpected keyword argument 'url'", so the admin
UI's "Test Connection" always fails for a redis:// url.
"""
monkeypatch.delenv("REDIS_HOST", raising=False)
monkeypatch.delenv("REDIS_URL", raising=False)
redis_cache = RedisCache(url="redis://cache-host:6380")
mock_client = AsyncMock()
mock_client.ping.return_value = True
with patch(
"litellm._redis.async_redis.Redis.from_url", return_value=mock_client
) as mock_from_url:
result = await redis_cache.test_connection()
assert result["status"] == "success"
assert mock_from_url.call_args.kwargs["url"] == "redis://cache-host:6380"
mock_client.ping.assert_awaited_once()
mock_client.aclose.assert_awaited_once()
@pytest.mark.asyncio
async def test_test_connection_with_host_pings_host_target(monkeypatch, redis_no_ping):
"""Host-mode configs keep connecting with the discrete host/port kwargs."""
monkeypatch.delenv("REDIS_URL", raising=False)
redis_cache = RedisCache(host="cache-host", port=6380, password="hunter2")
mock_client = AsyncMock()
mock_client.ping.return_value = True
with patch("litellm._redis.async_redis.Redis", return_value=mock_client) as mock_redis:
result = await redis_cache.test_connection()
assert result["status"] == "success"
assert mock_redis.call_args.kwargs["host"] == "cache-host"
assert mock_redis.call_args.kwargs["port"] == 6380
assert mock_redis.call_args.kwargs["password"] == "hunter2"
mock_client.ping.assert_awaited_once()