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

View File

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