mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-14 07:05:10 +00:00
fix lint and format errors
This commit is contained in:
@@ -45,6 +45,7 @@ from litellm.proxy.auth.auth_checks import (
|
||||
get_user_object,
|
||||
)
|
||||
|
||||
|
||||
class CacheCallTracker:
|
||||
"""
|
||||
Tracks cache read/write operations by wrapping DualCache methods.
|
||||
@@ -184,10 +185,6 @@ async def test_get_key_object_warm_cache():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n=== get_key_object WARM CACHE ===")
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Keys read: {summary['cache_read_keys']}")
|
||||
|
||||
# Should have exactly 1 cache read
|
||||
assert summary["total_cache_reads"] == 1
|
||||
assert hashed_token in summary["cache_read_keys"]
|
||||
@@ -221,7 +218,7 @@ async def test_get_key_object_cold_cache():
|
||||
mock_prisma = MagicMock()
|
||||
mock_prisma.get_data = AsyncMock(return_value=valid_token)
|
||||
|
||||
result = await get_key_object(
|
||||
await get_key_object(
|
||||
hashed_token=hashed_token,
|
||||
prisma_client=mock_prisma,
|
||||
user_api_key_cache=tracked_cache,
|
||||
@@ -231,10 +228,6 @@ async def test_get_key_object_cold_cache():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n=== get_key_object COLD CACHE ===")
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Cache writes: {summary['total_cache_writes']}")
|
||||
|
||||
# Should have 1 cache read (miss) and at least 1 cache write (populate cache)
|
||||
assert summary["total_cache_reads"] >= 1
|
||||
|
||||
@@ -267,7 +260,7 @@ async def test_get_team_object_warm_cache():
|
||||
mock_prisma.db.litellm_teamtable = MagicMock()
|
||||
mock_prisma.db.litellm_teamtable.find_unique = AsyncMock()
|
||||
|
||||
result = await get_team_object(
|
||||
await get_team_object(
|
||||
team_id=team_id,
|
||||
prisma_client=mock_prisma,
|
||||
user_api_key_cache=tracked_cache,
|
||||
@@ -277,10 +270,6 @@ async def test_get_team_object_warm_cache():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n=== get_team_object WARM CACHE ===")
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Keys read: {summary['cache_read_keys']}")
|
||||
|
||||
assert summary["total_cache_reads"] >= 1
|
||||
assert cache_key in summary["cache_read_keys"]
|
||||
|
||||
@@ -289,7 +278,7 @@ async def test_get_team_object_warm_cache():
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# TEST: get_user_object cache behavior
|
||||
# TEST: get_user_object cache behavior
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@@ -312,7 +301,7 @@ async def test_get_user_object_warm_cache():
|
||||
mock_prisma.db.litellm_usertable = MagicMock()
|
||||
mock_prisma.db.litellm_usertable.find_unique = AsyncMock()
|
||||
|
||||
result = await get_user_object(
|
||||
await get_user_object(
|
||||
user_id=user_id,
|
||||
prisma_client=mock_prisma,
|
||||
user_api_key_cache=tracked_cache,
|
||||
@@ -323,10 +312,6 @@ async def test_get_user_object_warm_cache():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n=== get_user_object WARM CACHE ===")
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Keys read: {summary['cache_read_keys']}")
|
||||
|
||||
assert summary["total_cache_reads"] >= 1
|
||||
assert user_id in summary["cache_read_keys"]
|
||||
|
||||
@@ -368,7 +353,7 @@ async def test_get_team_membership_warm_cache():
|
||||
mock_prisma.db.litellm_teammembership = MagicMock()
|
||||
mock_prisma.db.litellm_teammembership.find_unique = AsyncMock()
|
||||
|
||||
result = await get_team_membership(
|
||||
await get_team_membership(
|
||||
user_id=user_id,
|
||||
team_id=team_id,
|
||||
prisma_client=mock_prisma,
|
||||
@@ -379,10 +364,6 @@ async def test_get_team_membership_warm_cache():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n=== get_team_membership WARM CACHE ===")
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Keys read: {summary['cache_read_keys']}")
|
||||
|
||||
assert summary["total_cache_reads"] >= 1
|
||||
assert cache_key in summary["cache_read_keys"]
|
||||
|
||||
@@ -399,11 +380,11 @@ async def test_get_team_membership_warm_cache():
|
||||
async def test_team_membership_cache_key_duplication():
|
||||
"""
|
||||
Document the team membership duplicate cache key issue:
|
||||
|
||||
|
||||
Team membership is queried via TWO different cache keys:
|
||||
1. "{team_id}_{user_id}" - used in user_api_key_auth.py:1048
|
||||
2. "team_membership:{user_id}:{team_id}" - used in auth_checks.py:960 (get_team_membership)
|
||||
|
||||
|
||||
This test documents that both keys refer to the same data but use different
|
||||
cache key formats, potentially leading to duplicate lookups.
|
||||
"""
|
||||
@@ -414,20 +395,21 @@ async def test_team_membership_cache_key_duplication():
|
||||
key_format_1 = f"{team_id}_{user_id}" # user_api_key_auth format
|
||||
key_format_2 = f"team_membership:{user_id}:{team_id}" # auth_checks format
|
||||
|
||||
membership_data = {
|
||||
_ = {
|
||||
"user_id": user_id,
|
||||
"team_id": team_id,
|
||||
"spend": 3.0,
|
||||
}
|
||||
|
||||
# Document that these are different keys
|
||||
assert key_format_1 != key_format_2, "Cache keys should be different (this is the bug)"
|
||||
|
||||
print("\n=== DOCUMENTATION: Team Membership Duplicate Cache Keys ===")
|
||||
print(f"Cache key format 1 (user_api_key_auth): {key_format_1}")
|
||||
print(f"Cache key format 2 (auth_checks): {key_format_2}")
|
||||
print("\nRecommendation: Consolidate to a single cache key format")
|
||||
print("to avoid duplicate cache reads/writes for the same data.")
|
||||
assert (
|
||||
key_format_1 != key_format_2
|
||||
), "Cache keys should be different (this is the bug)"
|
||||
|
||||
# Document that these are different keys
|
||||
assert (
|
||||
key_format_1 != key_format_2
|
||||
), "Cache keys should be different (this is the bug)"
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -440,7 +422,7 @@ async def test_full_hot_path_network_count():
|
||||
"""
|
||||
Summary test that counts all network operations when processing
|
||||
a request with a key that has team_id and user_id attached.
|
||||
|
||||
|
||||
This test verifies the baseline number of cache operations expected
|
||||
on a fully warm cache path.
|
||||
"""
|
||||
@@ -450,7 +432,9 @@ async def test_full_hot_path_network_count():
|
||||
hashed_token = hash_token(api_key)
|
||||
|
||||
# Create all objects
|
||||
valid_token = _create_valid_token(api_key, team_id, user_id, has_team_member_spend=True)
|
||||
valid_token = _create_valid_token(
|
||||
api_key, team_id, user_id, has_team_member_spend=True
|
||||
)
|
||||
team_obj = _create_team_object(team_id)
|
||||
user_obj = _create_user_object(user_id)
|
||||
membership_data = LiteLLM_TeamMembership(
|
||||
@@ -466,8 +450,12 @@ async def test_full_hot_path_network_count():
|
||||
await cache.async_set_cache(key=hashed_token, value=valid_token)
|
||||
await cache.async_set_cache(key=f"team_id:{team_id}", value=team_obj)
|
||||
await cache.async_set_cache(key=user_id, value=user_obj)
|
||||
await cache.async_set_cache(key=f"team_membership:{user_id}:{team_id}", value=membership_data.model_dump())
|
||||
await cache.async_set_cache(key=f"{team_id}_{user_id}", value=membership_data.model_dump())
|
||||
await cache.async_set_cache(
|
||||
key=f"team_membership:{user_id}:{team_id}", value=membership_data.model_dump()
|
||||
)
|
||||
await cache.async_set_cache(
|
||||
key=f"{team_id}_{user_id}", value=membership_data.model_dump()
|
||||
)
|
||||
|
||||
# Create tracker AFTER populating cache
|
||||
tracker = CacheCallTracker()
|
||||
@@ -484,7 +472,7 @@ async def test_full_hot_path_network_count():
|
||||
parent_otel_span=None,
|
||||
proxy_logging_obj=None,
|
||||
)
|
||||
|
||||
|
||||
await get_team_object(
|
||||
team_id=team_id,
|
||||
prisma_client=mock_prisma,
|
||||
@@ -492,7 +480,7 @@ async def test_full_hot_path_network_count():
|
||||
parent_otel_span=None,
|
||||
proxy_logging_obj=None,
|
||||
)
|
||||
|
||||
|
||||
await get_user_object(
|
||||
user_id=user_id,
|
||||
prisma_client=mock_prisma,
|
||||
@@ -501,7 +489,7 @@ async def test_full_hot_path_network_count():
|
||||
proxy_logging_obj=None,
|
||||
user_id_upsert=False,
|
||||
)
|
||||
|
||||
|
||||
await get_team_membership(
|
||||
user_id=user_id,
|
||||
team_id=team_id,
|
||||
@@ -513,31 +501,18 @@ async def test_full_hot_path_network_count():
|
||||
|
||||
summary = tracker.get_summary()
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print("HOT PATH NETWORK REQUEST SUMMARY")
|
||||
print("Key with team_id and user_id attached - WARM CACHE")
|
||||
print("=" * 70)
|
||||
print(f"Cache reads: {summary['total_cache_reads']}")
|
||||
print(f"Cache writes: {summary['total_cache_writes']}")
|
||||
print(f"DB queries: {summary['total_db_queries']}")
|
||||
print(f"TOTAL: {summary['total_network_requests']}")
|
||||
print(f"\nCache keys read:")
|
||||
for key in summary["cache_read_keys"]:
|
||||
print(f" - {key}")
|
||||
print("=" * 70)
|
||||
|
||||
# Assertions for expected baseline
|
||||
# On warm cache: 4 reads (key, team, user, team_membership)
|
||||
assert summary["total_cache_reads"] == 4, (
|
||||
f"Expected 4 cache reads on warm path, got {summary['total_cache_reads']}"
|
||||
)
|
||||
|
||||
assert (
|
||||
summary["total_cache_reads"] == 4
|
||||
), f"Expected 4 cache reads on warm path, got {summary['total_cache_reads']}"
|
||||
|
||||
# No DB queries on warm cache
|
||||
assert summary["total_db_queries"] == 0, (
|
||||
f"Expected 0 DB queries on warm path, got {summary['total_db_queries']}"
|
||||
)
|
||||
|
||||
assert (
|
||||
summary["total_db_queries"] == 0
|
||||
), f"Expected 0 DB queries on warm path, got {summary['total_db_queries']}"
|
||||
|
||||
# Total network requests should be exactly 4 on warm cache
|
||||
assert summary["total_network_requests"] == 4, (
|
||||
f"Expected 4 total network requests on warm path, got {summary['total_network_requests']}"
|
||||
)
|
||||
assert (
|
||||
summary["total_network_requests"] == 4
|
||||
), f"Expected 4 total network requests on warm path, got {summary['total_network_requests']}"
|
||||
|
||||
@@ -135,7 +135,7 @@ class TestDockerNoNetworkOnDeploy:
|
||||
def test_container_starts_without_network(self):
|
||||
"""
|
||||
Test that the container can start with network completely disabled.
|
||||
|
||||
|
||||
This test runs the container with --network=none to ensure no outbound
|
||||
network requests are required during startup.
|
||||
"""
|
||||
@@ -200,9 +200,7 @@ environment_variables: {}
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
pytest.fail(
|
||||
f"Failed to start container: {result.stderr}"
|
||||
)
|
||||
pytest.fail(f"Failed to start container: {result.stderr}")
|
||||
|
||||
# Wait for container to start up
|
||||
time.sleep(5)
|
||||
@@ -240,12 +238,7 @@ environment_variables: {}
|
||||
|
||||
is_running = inspect_result.stdout.strip() == "true"
|
||||
|
||||
# Print diagnostic info
|
||||
print("\n=== Container Startup Logs (first 100 lines) ===")
|
||||
log_lines = logs.split("\n")[:100]
|
||||
for line in log_lines:
|
||||
print(line)
|
||||
print("=" * 50)
|
||||
# If container crashed, get exit code and reason
|
||||
|
||||
# If container crashed, get exit code and reason
|
||||
if not is_running:
|
||||
@@ -281,7 +274,7 @@ environment_variables: {}
|
||||
"""
|
||||
Static analysis test: check that startup code doesn't contain
|
||||
hardcoded external URLs that would be called during import/startup.
|
||||
|
||||
|
||||
This is a complementary test to catch issues without needing Docker.
|
||||
"""
|
||||
# Directories to check for startup code
|
||||
@@ -337,22 +330,15 @@ environment_variables: {}
|
||||
content = f.read()
|
||||
|
||||
for pattern in problematic_patterns:
|
||||
matches = re.findall(
|
||||
pattern, content, re.MULTILINE
|
||||
)
|
||||
matches = re.findall(pattern, content, re.MULTILINE)
|
||||
if matches:
|
||||
issues_found.append(
|
||||
f"{filepath}: {pattern} matched"
|
||||
)
|
||||
issues_found.append(f"{filepath}: {pattern} matched")
|
||||
except Exception:
|
||||
pass # Skip unreadable files
|
||||
|
||||
# This test is informational - we document but don't fail
|
||||
if issues_found:
|
||||
print(
|
||||
"\n=== Potential startup network calls found ===\n"
|
||||
+ "\n".join(issues_found)
|
||||
)
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
@@ -362,10 +348,10 @@ environment_variables: {}
|
||||
def test_container_build_no_network_fetch():
|
||||
"""
|
||||
Test that the Docker build process doesn't require network for runtime.
|
||||
|
||||
|
||||
This verifies that all dependencies are properly bundled and no
|
||||
runtime network calls are made during container initialization.
|
||||
|
||||
|
||||
Note: Build itself may need network for pip install, but runtime should not.
|
||||
"""
|
||||
# This is a simplified version - full test would need to:
|
||||
@@ -396,8 +382,10 @@ def test_container_build_no_network_fetch():
|
||||
):
|
||||
problematic.append(f"Line {i}: {line.strip()}")
|
||||
|
||||
assert len(problematic) == 0, (
|
||||
f"Dockerfile CMD/ENTRYPOINT contains network calls: {problematic}"
|
||||
)
|
||||
assert (
|
||||
len(problematic) == 0
|
||||
), f"Dockerfile CMD/ENTRYPOINT contains network calls: {problematic}"
|
||||
|
||||
print("\nDockerfile CMD/ENTRYPOINT does not contain network calls.")
|
||||
assert (
|
||||
len(problematic) == 0
|
||||
), f"Dockerfile CMD/ENTRYPOINT contains network calls: {problematic}"
|
||||
|
||||
Reference in New Issue
Block a user