259 lines
10 KiB
Python
259 lines
10 KiB
Python
"""Integration tests for cache API endpoints."""
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from unittest.mock import patch, AsyncMock, MagicMock
|
|
|
|
from backend.main import app
|
|
from backend.services.enhanced_cache_manager import EnhancedCacheManager, CacheConfig, CacheMetrics
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
"""Create test client."""
|
|
return TestClient(app)
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_cache_manager():
|
|
"""Create mock enhanced cache manager."""
|
|
manager = MagicMock(spec=EnhancedCacheManager)
|
|
manager.config = CacheConfig()
|
|
manager.metrics = CacheMetrics(hits=50, misses=10, write_operations=20)
|
|
manager._initialized = True
|
|
manager.redis_client = None
|
|
|
|
# Setup async methods
|
|
manager.get_cache_analytics = AsyncMock(return_value={
|
|
"performance_metrics": {
|
|
"hit_rate": 0.833,
|
|
"total_hits": 50,
|
|
"total_misses": 10,
|
|
"total_writes": 20,
|
|
"average_response_time_ms": 25.5
|
|
},
|
|
"redis_usage": None,
|
|
"memory_cache_usage": {
|
|
"entries": 15,
|
|
"estimated_size_mb": 0.5
|
|
},
|
|
"configuration": {
|
|
"transcript_ttl_hours": 168,
|
|
"summary_ttl_hours": 72,
|
|
"using_redis": False
|
|
}
|
|
})
|
|
|
|
manager.invalidate_cache = AsyncMock(return_value=15)
|
|
manager.initialize = AsyncMock()
|
|
|
|
return manager
|
|
|
|
|
|
class TestCacheAnalyticsEndpoint:
|
|
"""Test cache analytics endpoint."""
|
|
|
|
def test_get_cache_analytics_success(self, client, mock_cache_manager):
|
|
"""Test successfully getting cache analytics."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/analytics")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert "data" in data
|
|
assert data["data"]["performance_metrics"]["hit_rate"] == 0.833
|
|
assert data["data"]["memory_cache_usage"]["entries"] == 15
|
|
|
|
def test_get_cache_analytics_error(self, client, mock_cache_manager):
|
|
"""Test error handling in cache analytics."""
|
|
mock_cache_manager.get_cache_analytics = AsyncMock(side_effect=Exception("Analytics error"))
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/analytics")
|
|
|
|
assert response.status_code == 500
|
|
assert "Analytics error" in response.json()["detail"]
|
|
|
|
|
|
class TestCacheInvalidationEndpoint:
|
|
"""Test cache invalidation endpoint."""
|
|
|
|
def test_invalidate_all_cache(self, client, mock_cache_manager):
|
|
"""Test invalidating all cache entries."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.post("/api/cache/invalidate")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert data["count"] == 15
|
|
assert "Invalidated 15 cache entries" in data["message"]
|
|
|
|
def test_invalidate_cache_with_pattern(self, client, mock_cache_manager):
|
|
"""Test invalidating cache with pattern."""
|
|
mock_cache_manager.invalidate_cache = AsyncMock(return_value=5)
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.post("/api/cache/invalidate?pattern=transcript")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert data["count"] == 5
|
|
mock_cache_manager.invalidate_cache.assert_called_once_with("transcript")
|
|
|
|
def test_invalidate_cache_error(self, client, mock_cache_manager):
|
|
"""Test error handling in cache invalidation."""
|
|
mock_cache_manager.invalidate_cache = AsyncMock(side_effect=Exception("Invalidation error"))
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.post("/api/cache/invalidate")
|
|
|
|
assert response.status_code == 500
|
|
assert "Invalidation error" in response.json()["detail"]
|
|
|
|
|
|
class TestCacheStatsEndpoint:
|
|
"""Test cache statistics endpoint."""
|
|
|
|
def test_get_cache_stats_success(self, client, mock_cache_manager):
|
|
"""Test successfully getting cache stats."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/stats")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert data["data"]["hit_rate"] == 0.8333333333333334
|
|
assert data["data"]["total_hits"] == 50
|
|
assert data["data"]["total_misses"] == 10
|
|
assert data["data"]["total_operations"] == 80
|
|
assert data["data"]["errors"] == 0
|
|
|
|
def test_get_cache_stats_error(self, client, mock_cache_manager):
|
|
"""Test error handling in cache stats."""
|
|
mock_cache_manager.metrics.to_dict = MagicMock(side_effect=Exception("Stats error"))
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/stats")
|
|
|
|
assert response.status_code == 500
|
|
assert "Stats error" in response.json()["detail"]
|
|
|
|
|
|
class TestCacheWarmingEndpoint:
|
|
"""Test cache warming endpoint."""
|
|
|
|
def test_warm_cache_success(self, client, mock_cache_manager):
|
|
"""Test cache warming initiation."""
|
|
video_ids = ["video1", "video2", "video3"]
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.post("/api/cache/warm", json=video_ids)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert data["video_count"] == 3
|
|
assert "initiated for 3 videos" in data["message"]
|
|
|
|
def test_warm_cache_empty_list(self, client, mock_cache_manager):
|
|
"""Test cache warming with empty list."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.post("/api/cache/warm", json=[])
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "success"
|
|
assert data["video_count"] == 0
|
|
|
|
|
|
class TestCacheHealthEndpoint:
|
|
"""Test cache health check endpoint."""
|
|
|
|
def test_cache_health_check_healthy(self, client, mock_cache_manager):
|
|
"""Test healthy cache system."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/health")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "healthy"
|
|
assert data["components"]["memory_cache"] is True
|
|
assert data["components"]["redis"] is False
|
|
assert data["components"]["background_tasks"] is True
|
|
|
|
def test_cache_health_with_redis(self, client, mock_cache_manager):
|
|
"""Test cache health with Redis connection."""
|
|
mock_redis = AsyncMock()
|
|
mock_redis.ping = AsyncMock(return_value=True)
|
|
mock_cache_manager.redis_client = mock_redis
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/health")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "healthy"
|
|
assert data["components"]["redis"] is True
|
|
|
|
def test_cache_health_low_hit_rate_warning(self, client, mock_cache_manager):
|
|
"""Test cache health with low hit rate warning."""
|
|
mock_cache_manager.metrics.hit_rate = 0.5 # Below threshold
|
|
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', return_value=mock_cache_manager):
|
|
response = client.get("/api/cache/health")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "healthy"
|
|
assert "warnings" in data
|
|
assert "Hit rate" in data["warnings"][0]
|
|
assert "below threshold" in data["warnings"][0]
|
|
|
|
def test_cache_health_check_error(self, client, mock_cache_manager):
|
|
"""Test cache health check with error."""
|
|
with patch('backend.api.cache.get_enhanced_cache_manager', side_effect=Exception("Health check error")):
|
|
response = client.get("/api/cache/health")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["status"] == "unhealthy"
|
|
assert "Health check error" in data["error"]
|
|
|
|
|
|
class TestCacheIntegrationWithPipeline:
|
|
"""Test cache integration with pipeline endpoints."""
|
|
|
|
def test_pipeline_uses_cache(self, client):
|
|
"""Test that pipeline endpoints utilize cache."""
|
|
# This would be a more comprehensive integration test
|
|
# Testing the actual cache usage in the pipeline
|
|
pass # TODO: Implement when pipeline is fully integrated
|
|
|
|
|
|
class TestCacheManagerInitialization:
|
|
"""Test cache manager initialization."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cache_manager_singleton(self):
|
|
"""Test that cache manager is a singleton."""
|
|
from backend.api.cache import get_enhanced_cache_manager, _cache_manager_instance
|
|
|
|
# Reset instance
|
|
import backend.api.cache
|
|
backend.api.cache._cache_manager_instance = None
|
|
|
|
# First call creates instance
|
|
manager1 = await get_enhanced_cache_manager()
|
|
assert manager1 is not None
|
|
assert backend.api.cache._cache_manager_instance is not None
|
|
|
|
# Second call returns same instance
|
|
manager2 = await get_enhanced_cache_manager()
|
|
assert manager1 is manager2
|
|
|
|
# Cleanup
|
|
await manager1.close()
|
|
backend.api.cache._cache_manager_instance = None |