"""Tests for VLC player API endpoints.""" from unittest.mock import AsyncMock import pytest from fastapi import FastAPI from httpx import AsyncClient from app.api.v1.sounds import get_vlc_player from app.models.user import User class TestVLCEndpoints: """Test VLC player API endpoints.""" @pytest.mark.asyncio async def test_play_sound_with_vlc_success( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test successful sound playback via VLC.""" # Set up mock VLC service mock_vlc_service = AsyncMock() # Set up expected response from the service method expected_response = { "message": "Sound 'Test Sound' is now playing via VLC", "sound_id": 1, "sound_name": "Test Sound", "success": True, "credits_deducted": 1, } mock_vlc_service.play_sound_with_credits.return_value = expected_response # Override dependencies test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/play/1") assert response.status_code == 200 data = response.json() assert data["sound_id"] == 1 assert data["sound_name"] == "Test Sound" assert "Test Sound" in data["message"] assert data["success"] is True assert data["credits_deducted"] == 1 # Verify service method was called with correct parameters mock_vlc_service.play_sound_with_credits.assert_called_once_with( 1, authenticated_user.id, ) finally: # Clean up dependency overrides test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_play_sound_with_vlc_sound_not_found( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test VLC playback when sound is not found.""" from fastapi import HTTPException # Set up mock VLC service mock_vlc_service = AsyncMock() # Configure mock to raise HTTPException for sound not found mock_vlc_service.play_sound_with_credits.side_effect = HTTPException( status_code=404, detail="Sound with ID 999 not found", ) # Override dependencies test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/play/999") assert response.status_code == 404 data = response.json() assert "Sound with ID 999 not found" in data["detail"] finally: # Clean up dependency overrides test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_play_sound_with_vlc_launch_failure( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test VLC playback when VLC launch fails.""" from fastapi import HTTPException # Set up mock VLC service mock_vlc_service = AsyncMock() # Configure mock to raise HTTPException for VLC launch failure mock_vlc_service.play_sound_with_credits.side_effect = HTTPException( status_code=500, detail="Failed to launch VLC for sound playback", ) # Override dependencies test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/play/1") assert response.status_code == 500 data = response.json() assert "Failed to launch VLC for sound playback" in data["detail"] finally: # Clean up dependency overrides test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_play_sound_with_vlc_service_exception( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test VLC playback when service raises an exception.""" # Set up mock VLC service mock_vlc_service = AsyncMock() # Configure mock to raise a generic exception mock_vlc_service.play_sound_with_credits.side_effect = Exception( "Database error", ) # Override dependencies test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/play/1") assert response.status_code == 500 data = response.json() assert "Failed to play sound" in data["detail"] finally: # Clean up dependency overrides test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_play_sound_with_vlc_unauthenticated( self, client: AsyncClient, ) -> None: """Test VLC playback without authentication.""" response = await client.post("/api/v1/sounds/play/1") assert response.status_code == 401 @pytest.mark.asyncio async def test_stop_all_vlc_instances_success( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test successful stopping of all VLC instances.""" # Set up mock mock_vlc_service = AsyncMock() mock_result = { "success": True, "processes_found": 3, "processes_killed": 3, "processes_remaining": 0, "message": "Killed 3 VLC processes", } mock_vlc_service.stop_all_vlc_instances.return_value = mock_result # Override dependency test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/stop") assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["processes_found"] == 3 assert data["processes_killed"] == 3 assert data["processes_remaining"] == 0 assert "Killed 3 VLC processes" in data["message"] # Verify service call mock_vlc_service.stop_all_vlc_instances.assert_called_once() finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_stop_all_vlc_instances_no_processes( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test stopping VLC instances when none are running.""" # Set up mock mock_vlc_service = AsyncMock() mock_result = { "success": True, "processes_found": 0, "processes_killed": 0, "message": "No VLC processes found", } mock_vlc_service.stop_all_vlc_instances.return_value = mock_result # Override dependency test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/stop") assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["processes_found"] == 0 assert data["processes_killed"] == 0 assert data["message"] == "No VLC processes found" finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_stop_all_vlc_instances_partial_success( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test stopping VLC instances with partial success.""" # Set up mock mock_vlc_service = AsyncMock() mock_result = { "success": True, "processes_found": 3, "processes_killed": 2, "processes_remaining": 1, "message": "Killed 2 VLC processes", } mock_vlc_service.stop_all_vlc_instances.return_value = mock_result # Override dependency test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/stop") assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["processes_found"] == 3 assert data["processes_killed"] == 2 assert data["processes_remaining"] == 1 finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_stop_all_vlc_instances_failure( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test stopping VLC instances when service fails.""" # Set up mock mock_vlc_service = AsyncMock() mock_result = { "success": False, "processes_found": 0, "processes_killed": 0, "error": "Command failed", "message": "Failed to stop VLC processes", } mock_vlc_service.stop_all_vlc_instances.return_value = mock_result # Override dependency test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/stop") assert response.status_code == 200 data = response.json() assert data["success"] is False assert data["error"] == "Command failed" assert data["message"] == "Failed to stop VLC processes" finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_stop_all_vlc_instances_service_exception( self, test_app: FastAPI, authenticated_client: AsyncClient, authenticated_user: User, ) -> None: """Test stopping VLC instances when service raises an exception.""" # Set up mock to raise an exception mock_vlc_service = AsyncMock() mock_vlc_service.stop_all_vlc_instances.side_effect = Exception("Service error") # Override dependency test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_client.post("/api/v1/sounds/stop") assert response.status_code == 500 data = response.json() assert "Failed to stop VLC instances" in data["detail"] finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None) @pytest.mark.asyncio async def test_stop_all_vlc_instances_unauthenticated( self, client: AsyncClient, ) -> None: """Test stopping VLC instances without authentication.""" response = await client.post("/api/v1/sounds/stop") assert response.status_code == 401 @pytest.mark.asyncio async def test_vlc_endpoints_with_admin_user( self, test_app: FastAPI, authenticated_admin_client: AsyncClient, admin_user: User, ) -> None: """Test VLC endpoints work with admin user.""" # Set up mock VLC service mock_vlc_service = AsyncMock() # Set up expected response from the service method expected_response = { "message": "Sound 'Admin Test Sound' is now playing via VLC", "sound_id": 1, "sound_name": "Admin Test Sound", "success": True, "credits_deducted": 1, } mock_vlc_service.play_sound_with_credits.return_value = expected_response # Override dependencies test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service try: response = await authenticated_admin_client.post("/api/v1/sounds/play/1") assert response.status_code == 200 data = response.json() assert data["sound_name"] == "Admin Test Sound" # Verify service method was called with admin user ID mock_vlc_service.play_sound_with_credits.assert_called_once_with( 1, admin_user.id, ) finally: # Clean up dependency overrides test_app.dependency_overrides.pop(get_vlc_player, None) # Test stop-all endpoint with admin mock_vlc_service_2 = AsyncMock() mock_result = { "success": True, "processes_found": 1, "processes_killed": 1, "processes_remaining": 0, "message": "Killed 1 VLC processes", } mock_vlc_service_2.stop_all_vlc_instances.return_value = mock_result # Override dependency for stop-all test test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service_2 try: response = await authenticated_admin_client.post("/api/v1/sounds/stop") assert response.status_code == 200 data = response.json() assert data["success"] is True assert data["processes_killed"] == 1 finally: # Clean up dependency override test_app.dependency_overrides.pop(get_vlc_player, None)