"""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