feat: Add VLC player API endpoints and associated tests
- Implemented VLC player API endpoints for playing and stopping sounds. - Added tests for successful playback, error handling, and authentication scenarios. - Created utility function to get sound file paths based on sound properties. - Refactored player service to utilize shared sound path utility. - Enhanced test coverage for sound file path utility with various sound types. - Introduced tests for VLC player service, including subprocess handling and play count tracking.
This commit is contained in:
@@ -21,6 +21,7 @@ from app.services.player import (
|
||||
initialize_player_service,
|
||||
shutdown_player_service,
|
||||
)
|
||||
from app.utils.audio import get_sound_file_path
|
||||
|
||||
|
||||
class TestPlayerState:
|
||||
@@ -196,7 +197,7 @@ class TestPlayerService:
|
||||
)
|
||||
player_service.state.playlist_sounds = [sound]
|
||||
|
||||
with patch.object(player_service, "_get_sound_file_path") as mock_path:
|
||||
with patch("app.services.player.get_sound_file_path") as mock_path:
|
||||
mock_file_path = Mock(spec=Path)
|
||||
mock_file_path.exists.return_value = True
|
||||
mock_path.return_value = mock_file_path
|
||||
@@ -385,51 +386,6 @@ class TestPlayerService:
|
||||
assert player_service.state.playlist_length == 2
|
||||
assert player_service.state.playlist_duration == 75000
|
||||
|
||||
def test_get_sound_file_path_normalized(self, player_service):
|
||||
"""Test getting file path for normalized sound."""
|
||||
sound = Sound(
|
||||
id=1,
|
||||
name="Test Song",
|
||||
filename="original.mp3",
|
||||
normalized_filename="normalized.mp3",
|
||||
is_normalized=True,
|
||||
type="SDB",
|
||||
)
|
||||
|
||||
result = player_service._get_sound_file_path(sound)
|
||||
|
||||
expected = Path("sounds/normalized/sdb/normalized.mp3")
|
||||
assert result == expected
|
||||
|
||||
def test_get_sound_file_path_original(self, player_service):
|
||||
"""Test getting file path for original sound."""
|
||||
sound = Sound(
|
||||
id=1,
|
||||
name="Test Song",
|
||||
filename="original.mp3",
|
||||
is_normalized=False,
|
||||
type="SDB",
|
||||
)
|
||||
|
||||
result = player_service._get_sound_file_path(sound)
|
||||
|
||||
expected = Path("sounds/originals/sdb/original.mp3")
|
||||
assert result == expected
|
||||
|
||||
def test_get_sound_file_path_ext_type(self, player_service):
|
||||
"""Test getting file path for EXT type sound."""
|
||||
sound = Sound(
|
||||
id=1,
|
||||
name="Test Song",
|
||||
filename="extracted.mp3",
|
||||
is_normalized=False,
|
||||
type="EXT",
|
||||
)
|
||||
|
||||
result = player_service._get_sound_file_path(sound)
|
||||
|
||||
expected = Path("sounds/originals/extracted/extracted.mp3")
|
||||
assert result == expected
|
||||
|
||||
def test_get_next_index_continuous_mode(self, player_service):
|
||||
"""Test getting next index in continuous mode."""
|
||||
@@ -538,36 +494,24 @@ class TestPlayerService:
|
||||
|
||||
# Mock repositories
|
||||
with patch("app.services.player.SoundRepository") as mock_sound_repo_class:
|
||||
with patch("app.services.player.UserRepository") as mock_user_repo_class:
|
||||
mock_sound_repo = AsyncMock()
|
||||
mock_user_repo = AsyncMock()
|
||||
mock_sound_repo_class.return_value = mock_sound_repo
|
||||
mock_user_repo_class.return_value = mock_user_repo
|
||||
mock_sound_repo = AsyncMock()
|
||||
mock_sound_repo_class.return_value = mock_sound_repo
|
||||
|
||||
# Mock sound and user
|
||||
mock_sound = Mock()
|
||||
mock_sound.play_count = 5
|
||||
mock_sound_repo.get_by_id.return_value = mock_sound
|
||||
# Mock sound
|
||||
mock_sound = Mock()
|
||||
mock_sound.play_count = 5
|
||||
mock_sound_repo.get_by_id.return_value = mock_sound
|
||||
|
||||
mock_user = Mock()
|
||||
mock_user.id = 1
|
||||
mock_user_repo.get_by_id.return_value = mock_user
|
||||
await player_service._record_play_count(1)
|
||||
|
||||
# Mock no existing SoundPlayed record
|
||||
mock_result = Mock()
|
||||
mock_result.first.return_value = None
|
||||
mock_session.exec.return_value = mock_result
|
||||
# Verify sound play count was updated
|
||||
mock_sound_repo.update.assert_called_once_with(
|
||||
mock_sound, {"play_count": 6}
|
||||
)
|
||||
|
||||
await player_service._record_play_count(1)
|
||||
|
||||
# Verify sound play count was updated
|
||||
mock_sound_repo.update.assert_called_once_with(
|
||||
mock_sound, {"play_count": 6}
|
||||
)
|
||||
|
||||
# Verify SoundPlayed record was created
|
||||
mock_session.add.assert_called_once()
|
||||
mock_session.commit.assert_called_once()
|
||||
# Verify SoundPlayed record was created with None user_id for player
|
||||
mock_session.add.assert_called_once()
|
||||
mock_session.commit.assert_called_once()
|
||||
|
||||
def test_get_state(self, player_service):
|
||||
"""Test getting current player state."""
|
||||
@@ -577,6 +521,27 @@ class TestPlayerService:
|
||||
assert "mode" in result
|
||||
assert "volume" in result
|
||||
|
||||
def test_uses_shared_sound_path_utility(self, player_service):
|
||||
"""Test that player service uses the shared sound path utility."""
|
||||
sound = Sound(
|
||||
id=1,
|
||||
name="Test Song",
|
||||
filename="test.mp3",
|
||||
type="SDB",
|
||||
is_normalized=False,
|
||||
)
|
||||
player_service.state.playlist_sounds = [sound]
|
||||
|
||||
with patch("app.services.player.get_sound_file_path") as mock_path:
|
||||
mock_file_path = Mock(spec=Path)
|
||||
mock_file_path.exists.return_value = False # File doesn't exist
|
||||
mock_path.return_value = mock_file_path
|
||||
|
||||
# This should fail because file doesn't exist
|
||||
result = asyncio.run(player_service.play(0))
|
||||
# Verify the utility was called
|
||||
mock_path.assert_called_once_with(sound)
|
||||
|
||||
|
||||
class TestPlayerServiceGlobalFunctions:
|
||||
"""Test global player service functions."""
|
||||
|
||||
Reference in New Issue
Block a user