import pytest from unittest.mock import MagicMock, AsyncMock, patch from app.core.redis.redis_manager import RedisManager from app.shared.progress import Process class TestMovieMakerAPI: """MovieMaker 관련 API 테스트""" @patch('app.workers.tasks.task1_crawl.s') @patch('app.workers.tasks.task2_generate_lyrics.s') @patch('app.workers.tasks.task3_generate_music.s') @patch('app.workers.tasks.task1_crawl_images.s') @patch('app.workers.tasks.task4_generate_video.s') @patch('app.workers.tasks.task5_merge_results.s') def test_start_workflow_success(self, mock_merge, mock_video, mock_images, mock_music, mock_lyrics, mock_crawl, client, mock_redis_manager): """워크플로우 시작 성공 테스트""" # Mock 설정 with patch('app.presentation.api.v1.moviemakers.RedisManager', return_value=mock_redis_manager): with patch('app.presentation.api.v1.moviemakers.Process') as mock_process_class: # Process 인스턴스 mock mock_process_instance = MagicMock() mock_process_instance.init_task_status = AsyncMock(return_value=None) mock_process_class.return_value = mock_process_instance # Celery task mocks mock_workflow = MagicMock() mock_workflow.apply_async.return_value = MagicMock(id="celery_task_123") # 각 task의 signature mock for mock_task in [mock_crawl, mock_lyrics, mock_music, mock_images, mock_video, mock_merge]: mock_task.return_value = MagicMock() # 테스트 실행 response = client.post("/api/v1/moviemaker/start-workflow", json={ "url": "https://example.com/test" }) # 검증 assert response.status_code == 200 data = response.json() assert "task_id" in data assert data["progress"]["metadata"] == False assert data["progress"]["lyrics"] == False assert data["progress"]["songs"] == False assert data["progress"]["images"] == False assert data["progress"]["movies"] == False assert data["progress"]["combined"] == False def test_start_workflow_invalid_url(self, client): """잘못된 URL로 워크플로우 시작 테스트""" response = client.post("/api/v1/moviemaker/start-workflow", json={ "url": "not-a-valid-url" }) # URL 유효성 검사가 없다면 정상적으로 처리됨 assert response.status_code == 200 def test_start_workflow_empty_url(self, client): """빈 URL로 워크플로우 시작 테스트""" response = client.post("/api/v1/moviemaker/start-workflow", json={ "url": "" }) # 빈 문자열도 처리됨 assert response.status_code == 200 def test_get_progress_success(self, client, mock_redis_manager): """진행상황 조회 성공 테스트""" # Mock 설정 with patch('app.presentation.api.v1.moviemakers.RedisManager', return_value=mock_redis_manager): with patch('app.presentation.api.v1.moviemakers.Process') as mock_process_class: # Process 인스턴스 mock mock_process_instance = MagicMock() mock_process_instance.get_task_status = AsyncMock(return_value={ "metadata": True, "lyrics": True, "songs": True, "images": False, "movies": False, "combined": False }) mock_process_class.return_value = mock_process_instance # 테스트 실행 response = client.post("/api/v1/moviemaker/progress", json={ "task_id": "test_task_123" }) # 검증 assert response.status_code == 200 data = response.json() assert data["progress"]["metadata"] == True assert data["progress"]["lyrics"] == True assert data["progress"]["songs"] == True assert data["progress"]["images"] == False def test_get_progress_not_found(self, client, mock_redis_manager): """존재하지 않는 task_id로 진행상황 조회 테스트""" # Mock 설정 with patch('app.presentation.api.v1.moviemakers.RedisManager', return_value=mock_redis_manager): with patch('app.presentation.api.v1.moviemakers.Process') as mock_process_class: # Process 인스턴스 mock mock_process_instance = MagicMock() mock_process_instance.get_task_status = AsyncMock(return_value=None) mock_process_class.return_value = mock_process_instance # 테스트 실행 response = client.post("/api/v1/moviemaker/progress", json={ "task_id": "non_existent_task" }) # 검증 assert response.status_code == 200 data = response.json() assert data["progress"] is None def test_get_progress_completed(self, client, mock_redis_manager): """완료된 작업의 진행상황 조회 테스트""" # Mock 설정 with patch('app.presentation.api.v1.moviemakers.RedisManager', return_value=mock_redis_manager): with patch('app.presentation.api.v1.moviemakers.Process') as mock_process_class: # Process 인스턴스 mock mock_process_instance = MagicMock() mock_process_instance.get_task_status = AsyncMock(return_value={ "metadata": True, "lyrics": True, "songs": True, "images": True, "movies": True, "combined": True }) mock_process_class.return_value = mock_process_instance # 테스트 실행 response = client.post("/api/v1/moviemaker/progress", json={ "task_id": "completed_task_123" }) # 검증 assert response.status_code == 200 data = response.json() # 모든 단계가 완료됨 for key in ["metadata", "lyrics", "songs", "images", "movies", "combined"]: assert data["progress"][key] == True @patch('app.presentation.api.v1.moviemakers.RedisManager') def test_workflow_redis_error(self, mock_redis_class, client): """Redis 연결 오류 시 워크플로우 테스트""" # Redis 연결 실패 시뮬레이션 mock_redis_class.side_effect = Exception("Redis connection failed") # 테스트 실행 response = client.post("/api/v1/moviemaker/start-workflow", json={ "url": "https://example.com/test" }) # 검증 - 에러가 발생하면 500 에러 assert response.status_code == 500