refactor: Update player API test responses to use consistent field names and structures

This commit is contained in:
JSC
2025-07-31 11:35:20 +02:00
parent c13285ca4e
commit f24698e3ff
2 changed files with 281 additions and 145 deletions

View File

@@ -516,10 +516,9 @@ class TestPlayerEndpoints:
"status": PlayerStatus.PLAYING.value, "status": PlayerStatus.PLAYING.value,
"mode": PlayerMode.CONTINUOUS.value, "mode": PlayerMode.CONTINUOUS.value,
"volume": 50, "volume": 50,
"current_sound_id": 1, "position_ms": 5000,
"current_sound_index": 0, "duration_ms": 30000,
"current_sound_position": 5000, "index": 0,
"current_sound_duration": 30000,
"current_sound": { "current_sound": {
"id": 1, "id": 1,
"name": "Test Song", "name": "Test Song",
@@ -530,11 +529,13 @@ class TestPlayerEndpoints:
"thumbnail": None, "thumbnail": None,
"play_count": 0, "play_count": 0,
}, },
"playlist_id": 1, "playlist": {
"playlist_name": "Test Playlist", "id": 1,
"playlist_length": 1, "name": "Test Playlist",
"playlist_duration": 30000, "length": 1,
"playlist_sounds": [], "duration": 30000,
"sounds": [],
},
} }
mock_player_service.get_state.return_value = mock_state mock_player_service.get_state.return_value = mock_state

View File

@@ -1,12 +1,16 @@
"""Tests for VLC player API endpoints.""" """Tests for VLC player API endpoints."""
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, Mock, patch
import pytest import pytest
from httpx import AsyncClient from httpx import AsyncClient
from fastapi import FastAPI
from app.models.sound import Sound from app.models.sound import Sound
from app.models.user import User from app.models.user import User
from app.api.v1.sounds import get_vlc_player, get_sound_repository, get_credit_service
class TestVLCEndpoints: class TestVLCEndpoints:
@@ -15,101 +19,168 @@ class TestVLCEndpoints:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_play_sound_with_vlc_success( async def test_play_sound_with_vlc_success(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test successful sound playback via VLC.""" """Test successful sound playback via VLC."""
# Mock the VLC player service and sound repository methods # Set up mocks
with patch("app.services.vlc_player.VLCPlayerService.play_sound") as mock_play_sound: mock_vlc_service = AsyncMock()
mock_play_sound.return_value = True mock_repo = AsyncMock()
mock_credit_service = AsyncMock()
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_by_id: # Set up test data
mock_sound = Sound( mock_sound = Sound(
id=1, id=1,
type="SDB", type="SDB",
name="Test Sound", name="Test Sound",
filename="test.mp3", filename="test.mp3",
duration=5000, duration=5000,
size=1024, size=1024,
hash="test_hash", hash="test_hash",
) )
mock_get_by_id.return_value = mock_sound
response = await authenticated_client.post("/api/v1/sounds/vlc/play/1") # Configure mocks
mock_repo.get_by_id.return_value = mock_sound
mock_credit_service.validate_and_reserve_credits.return_value = None
mock_credit_service.deduct_credits.return_value = None
mock_vlc_service.play_sound.return_value = True
assert response.status_code == 200 # Override dependencies
data = response.json() test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service
assert data["success"] is True test_app.dependency_overrides[get_sound_repository] = lambda: mock_repo
assert data["sound_id"] == 1 test_app.dependency_overrides[get_credit_service] = lambda: mock_credit_service
assert data["sound_name"] == "Test Sound"
assert "Test Sound" in data["message"]
# Verify service calls try:
mock_get_by_id.assert_called_once_with(1) response = await authenticated_client.post("/api/v1/sounds/vlc/play/1")
mock_play_sound.assert_called_once_with(mock_sound)
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"]
# Verify service calls
mock_repo.get_by_id.assert_called_once_with(1)
mock_vlc_service.play_sound.assert_called_once_with(mock_sound)
finally:
# Clean up dependency overrides (except get_db which is needed for other tests)
test_app.dependency_overrides.pop(get_vlc_player, None)
test_app.dependency_overrides.pop(get_sound_repository, None)
test_app.dependency_overrides.pop(get_credit_service, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_play_sound_with_vlc_sound_not_found( async def test_play_sound_with_vlc_sound_not_found(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test VLC playback when sound is not found.""" """Test VLC playback when sound is not found."""
# Mock the sound repository to return None # Set up mocks
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_by_id: mock_vlc_service = AsyncMock()
mock_get_by_id.return_value = None mock_repo = AsyncMock()
mock_credit_service = AsyncMock()
# Configure mocks
mock_repo.get_by_id.return_value = None
# Override dependencies
test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service
test_app.dependency_overrides[get_sound_repository] = lambda: mock_repo
test_app.dependency_overrides[get_credit_service] = lambda: mock_credit_service
try:
response = await authenticated_client.post("/api/v1/sounds/vlc/play/999") response = await authenticated_client.post("/api/v1/sounds/vlc/play/999")
assert response.status_code == 404 assert response.status_code == 404
data = response.json() data = response.json()
assert "Sound with ID 999 not found" in data["detail"] assert "Sound with ID 999 not found" in data["detail"]
finally:
# Clean up dependency overrides (except get_db which is needed for other tests)
test_app.dependency_overrides.pop(get_vlc_player, None)
test_app.dependency_overrides.pop(get_sound_repository, None)
test_app.dependency_overrides.pop(get_credit_service, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_play_sound_with_vlc_launch_failure( async def test_play_sound_with_vlc_launch_failure(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test VLC playback when VLC launch fails.""" """Test VLC playback when VLC launch fails."""
# Mock the VLC player service to fail # Set up mocks
with patch("app.services.vlc_player.VLCPlayerService.play_sound") as mock_play_sound: mock_vlc_service = AsyncMock()
mock_play_sound.return_value = False mock_repo = AsyncMock()
mock_credit_service = AsyncMock()
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_by_id: # Set up test data
mock_sound = Sound( mock_sound = Sound(
id=1, id=1,
type="SDB", type="SDB",
name="Test Sound", name="Test Sound",
filename="test.mp3", filename="test.mp3",
duration=5000, duration=5000,
size=1024, size=1024,
hash="test_hash", hash="test_hash",
) )
mock_get_by_id.return_value = mock_sound
response = await authenticated_client.post("/api/v1/sounds/vlc/play/1") # Configure mocks
mock_repo.get_by_id.return_value = mock_sound
mock_credit_service.validate_and_reserve_credits.return_value = None
mock_credit_service.deduct_credits.return_value = None
mock_vlc_service.play_sound.return_value = False
assert response.status_code == 500 # Override dependencies
data = response.json() test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service
assert "Failed to launch VLC for sound playback" in data["detail"] test_app.dependency_overrides[get_sound_repository] = lambda: mock_repo
test_app.dependency_overrides[get_credit_service] = lambda: mock_credit_service
try:
response = await authenticated_client.post("/api/v1/sounds/vlc/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 (except get_db which is needed for other tests)
test_app.dependency_overrides.pop(get_vlc_player, None)
test_app.dependency_overrides.pop(get_sound_repository, None)
test_app.dependency_overrides.pop(get_credit_service, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_play_sound_with_vlc_service_exception( async def test_play_sound_with_vlc_service_exception(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test VLC playback when service raises an exception.""" """Test VLC playback when service raises an exception."""
# Mock the sound repository to raise an exception # Set up mocks
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_by_id: mock_vlc_service = AsyncMock()
mock_get_by_id.side_effect = Exception("Database error") mock_repo = AsyncMock()
mock_credit_service = AsyncMock()
# Configure mocks
mock_repo.get_by_id.side_effect = Exception("Database error")
# Override dependencies
test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service
test_app.dependency_overrides[get_sound_repository] = lambda: mock_repo
test_app.dependency_overrides[get_credit_service] = lambda: mock_credit_service
try:
response = await authenticated_client.post("/api/v1/sounds/vlc/play/1") response = await authenticated_client.post("/api/v1/sounds/vlc/play/1")
assert response.status_code == 500 assert response.status_code == 500
data = response.json() data = response.json()
assert "Failed to play sound" in data["detail"] assert "Failed to play sound" in data["detail"]
finally:
# Clean up dependency overrides (except get_db which is needed for other tests)
test_app.dependency_overrides.pop(get_vlc_player, None)
test_app.dependency_overrides.pop(get_sound_repository, None)
test_app.dependency_overrides.pop(get_credit_service, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_play_sound_with_vlc_unauthenticated( async def test_play_sound_with_vlc_unauthenticated(
@@ -123,21 +194,26 @@ class TestVLCEndpoints:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_stop_all_vlc_instances_success( async def test_stop_all_vlc_instances_success(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test successful stopping of all VLC instances.""" """Test successful stopping of all VLC instances."""
# Mock the VLC player service # Set up mock
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service = AsyncMock()
mock_result = { mock_result = {
"success": True, "success": True,
"processes_found": 3, "processes_found": 3,
"processes_killed": 3, "processes_killed": 3,
"processes_remaining": 0, "processes_remaining": 0,
"message": "Killed 3 VLC processes", "message": "Killed 3 VLC processes",
} }
mock_stop_all.return_value = mock_result 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/vlc/stop-all") response = await authenticated_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 200 assert response.status_code == 200
@@ -149,25 +225,33 @@ class TestVLCEndpoints:
assert "Killed 3 VLC processes" in data["message"] assert "Killed 3 VLC processes" in data["message"]
# Verify service call # Verify service call
mock_stop_all.assert_called_once() 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 @pytest.mark.asyncio
async def test_stop_all_vlc_instances_no_processes( async def test_stop_all_vlc_instances_no_processes(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test stopping VLC instances when none are running.""" """Test stopping VLC instances when none are running."""
# Mock the VLC player service # Set up mock
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service = AsyncMock()
mock_result = { mock_result = {
"success": True, "success": True,
"processes_found": 0, "processes_found": 0,
"processes_killed": 0, "processes_killed": 0,
"message": "No VLC processes found", "message": "No VLC processes found",
} }
mock_stop_all.return_value = mock_result 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/vlc/stop-all") response = await authenticated_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 200 assert response.status_code == 200
@@ -176,25 +260,33 @@ class TestVLCEndpoints:
assert data["processes_found"] == 0 assert data["processes_found"] == 0
assert data["processes_killed"] == 0 assert data["processes_killed"] == 0
assert data["message"] == "No VLC processes found" assert data["message"] == "No VLC processes found"
finally:
# Clean up dependency override
test_app.dependency_overrides.pop(get_vlc_player, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_stop_all_vlc_instances_partial_success( async def test_stop_all_vlc_instances_partial_success(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test stopping VLC instances with partial success.""" """Test stopping VLC instances with partial success."""
# Mock the VLC player service # Set up mock
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service = AsyncMock()
mock_result = { mock_result = {
"success": True, "success": True,
"processes_found": 3, "processes_found": 3,
"processes_killed": 2, "processes_killed": 2,
"processes_remaining": 1, "processes_remaining": 1,
"message": "Killed 2 VLC processes", "message": "Killed 2 VLC processes",
} }
mock_stop_all.return_value = mock_result 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/vlc/stop-all") response = await authenticated_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 200 assert response.status_code == 200
@@ -203,25 +295,33 @@ class TestVLCEndpoints:
assert data["processes_found"] == 3 assert data["processes_found"] == 3
assert data["processes_killed"] == 2 assert data["processes_killed"] == 2
assert data["processes_remaining"] == 1 assert data["processes_remaining"] == 1
finally:
# Clean up dependency override
test_app.dependency_overrides.pop(get_vlc_player, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_stop_all_vlc_instances_failure( async def test_stop_all_vlc_instances_failure(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test stopping VLC instances when service fails.""" """Test stopping VLC instances when service fails."""
# Mock the VLC player service # Set up mock
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service = AsyncMock()
mock_result = { mock_result = {
"success": False, "success": False,
"processes_found": 0, "processes_found": 0,
"processes_killed": 0, "processes_killed": 0,
"error": "Command failed", "error": "Command failed",
"message": "Failed to stop VLC processes", "message": "Failed to stop VLC processes",
} }
mock_stop_all.return_value = mock_result 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/vlc/stop-all") response = await authenticated_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 200 assert response.status_code == 200
@@ -229,23 +329,34 @@ class TestVLCEndpoints:
assert data["success"] is False assert data["success"] is False
assert data["error"] == "Command failed" assert data["error"] == "Command failed"
assert data["message"] == "Failed to stop VLC processes" 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 @pytest.mark.asyncio
async def test_stop_all_vlc_instances_service_exception( async def test_stop_all_vlc_instances_service_exception(
self, self,
test_app: FastAPI,
authenticated_client: AsyncClient, authenticated_client: AsyncClient,
authenticated_user: User, authenticated_user: User,
): ):
"""Test stopping VLC instances when service raises an exception.""" """Test stopping VLC instances when service raises an exception."""
# Mock the VLC player service to raise an exception # Set up mock to raise an exception
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service = AsyncMock()
mock_stop_all.side_effect = Exception("Service error") 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/vlc/stop-all") response = await authenticated_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 500 assert response.status_code == 500
data = response.json() data = response.json()
assert "Failed to stop VLC instances" in data["detail"] 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 @pytest.mark.asyncio
async def test_stop_all_vlc_instances_unauthenticated( async def test_stop_all_vlc_instances_unauthenticated(
@@ -259,47 +370,71 @@ class TestVLCEndpoints:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_vlc_endpoints_with_admin_user( async def test_vlc_endpoints_with_admin_user(
self, self,
test_app: FastAPI,
authenticated_admin_client: AsyncClient, authenticated_admin_client: AsyncClient,
admin_user: User, admin_user: User,
): ):
"""Test VLC endpoints work with admin user.""" """Test VLC endpoints work with admin user."""
# Test play endpoint with admin # Set up mocks
with patch("app.services.vlc_player.VLCPlayerService.play_sound") as mock_play_sound: mock_vlc_service = AsyncMock()
mock_play_sound.return_value = True mock_repo = AsyncMock()
mock_credit_service = AsyncMock()
with patch("app.repositories.sound.SoundRepository.get_by_id") as mock_get_by_id: # Set up test data
mock_sound = Sound( mock_sound = Sound(
id=1, id=1,
type="SDB", type="SDB",
name="Admin Test Sound", name="Admin Test Sound",
filename="admin_test.mp3", filename="admin_test.mp3",
duration=3000, duration=3000,
size=512, size=512,
hash="admin_hash", hash="admin_hash",
) )
mock_get_by_id.return_value = mock_sound
response = await authenticated_admin_client.post("/api/v1/sounds/vlc/play/1") # Configure mocks
mock_repo.get_by_id.return_value = mock_sound
mock_credit_service.validate_and_reserve_credits.return_value = None
mock_credit_service.deduct_credits.return_value = None
mock_vlc_service.play_sound.return_value = True
assert response.status_code == 200 # Override dependencies
data = response.json() test_app.dependency_overrides[get_vlc_player] = lambda: mock_vlc_service
assert data["success"] is True test_app.dependency_overrides[get_sound_repository] = lambda: mock_repo
assert data["sound_name"] == "Admin Test Sound" test_app.dependency_overrides[get_credit_service] = lambda: mock_credit_service
try:
response = await authenticated_admin_client.post("/api/v1/sounds/vlc/play/1")
assert response.status_code == 200
data = response.json()
assert data["sound_name"] == "Admin Test Sound"
finally:
# Clean up dependency overrides (except get_db which is needed for other tests)
test_app.dependency_overrides.pop(get_vlc_player, None)
test_app.dependency_overrides.pop(get_sound_repository, None)
test_app.dependency_overrides.pop(get_credit_service, None)
# Test stop-all endpoint with admin # Test stop-all endpoint with admin
with patch("app.services.vlc_player.VLCPlayerService.stop_all_vlc_instances") as mock_stop_all: mock_vlc_service_2 = AsyncMock()
mock_result = { mock_result = {
"success": True, "success": True,
"processes_found": 1, "processes_found": 1,
"processes_killed": 1, "processes_killed": 1,
"processes_remaining": 0, "processes_remaining": 0,
"message": "Killed 1 VLC processes", "message": "Killed 1 VLC processes",
} }
mock_stop_all.return_value = mock_result 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/vlc/stop-all") response = await authenticated_admin_client.post("/api/v1/sounds/vlc/stop-all")
assert response.status_code == 200 assert response.status_code == 200
data = response.json() data = response.json()
assert data["success"] is True assert data["success"] is True
assert data["processes_killed"] == 1 assert data["processes_killed"] == 1
finally:
# Clean up dependency override
test_app.dependency_overrides.pop(get_vlc_player, None)