| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- """
- Unit tests for playlist API endpoints.
- Tests the following endpoints:
- - GET /list_all_playlists
- - GET /get_playlist
- - POST /create_playlist
- - POST /modify_playlist
- - DELETE /delete_playlist
- - POST /rename_playlist
- - POST /add_to_playlist
- - POST /run_playlist (when disconnected)
- """
- import pytest
- from unittest.mock import patch, MagicMock, AsyncMock
- class TestListAllPlaylists:
- """Tests for /list_all_playlists endpoint."""
- @pytest.mark.asyncio
- async def test_list_all_playlists(self, async_client):
- """Test list_all_playlists returns list of playlist names."""
- mock_playlists = ["favorites", "evening", "morning"]
- with patch("main.playlist_manager.list_all_playlists", return_value=mock_playlists):
- response = await async_client.get("/list_all_playlists")
- assert response.status_code == 200
- data = response.json()
- assert isinstance(data, list)
- assert len(data) == 3
- assert "favorites" in data
- @pytest.mark.asyncio
- async def test_list_all_playlists_empty(self, async_client):
- """Test list_all_playlists returns empty list when no playlists."""
- with patch("main.playlist_manager.list_all_playlists", return_value=[]):
- response = await async_client.get("/list_all_playlists")
- assert response.status_code == 200
- data = response.json()
- assert data == []
- class TestGetPlaylist:
- """Tests for /get_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_get_playlist_exists(self, async_client):
- """Test get_playlist returns playlist data."""
- mock_playlist = {
- "name": "favorites",
- "files": ["circle.thr", "spiral.thr"]
- }
- with patch("main.playlist_manager.get_playlist", return_value=mock_playlist):
- response = await async_client.get("/get_playlist", params={"name": "favorites"})
- assert response.status_code == 200
- data = response.json()
- assert data["name"] == "favorites"
- assert data["files"] == ["circle.thr", "spiral.thr"]
- @pytest.mark.asyncio
- async def test_get_playlist_creates_empty_if_not_found(self, async_client):
- """Test get_playlist auto-creates empty playlist if not found.
- Note: This is the actual behavior - the endpoint auto-creates empty playlists.
- """
- with patch("main.playlist_manager.get_playlist", return_value=None):
- with patch("main.playlist_manager.create_playlist", return_value=True):
- response = await async_client.get("/get_playlist", params={"name": "nonexistent"})
- assert response.status_code == 200
- data = response.json()
- assert data["name"] == "nonexistent"
- assert data["files"] == []
- class TestCreatePlaylist:
- """Tests for /create_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_create_playlist(self, async_client):
- """Test creating a new playlist."""
- with patch("main.playlist_manager.create_playlist", return_value=True):
- response = await async_client.post(
- "/create_playlist",
- json={
- "playlist_name": "new_playlist", # API uses playlist_name, not name
- "files": ["circle.thr", "spiral.thr"]
- }
- )
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- class TestModifyPlaylist:
- """Tests for /modify_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_modify_playlist(self, async_client):
- """Test modifying an existing playlist."""
- with patch("main.playlist_manager.modify_playlist", return_value=True):
- response = await async_client.post(
- "/modify_playlist",
- json={
- "playlist_name": "favorites", # API uses playlist_name
- "files": ["new_pattern.thr"]
- }
- )
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- class TestDeletePlaylist:
- """Tests for /delete_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_delete_playlist(self, async_client):
- """Test deleting a playlist."""
- with patch("main.playlist_manager.delete_playlist", return_value=True):
- response = await async_client.request(
- "DELETE",
- "/delete_playlist",
- json={"playlist_name": "to_delete"} # DELETE with body
- )
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- @pytest.mark.asyncio
- async def test_delete_playlist_not_found(self, async_client):
- """Test deleting a non-existent playlist returns 404."""
- with patch("main.playlist_manager.delete_playlist", return_value=False):
- response = await async_client.request(
- "DELETE",
- "/delete_playlist",
- json={"playlist_name": "nonexistent"}
- )
- assert response.status_code == 404
- class TestRenamePlaylist:
- """Tests for /rename_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_rename_playlist_success(self, async_client):
- """Test renaming a playlist."""
- with patch("main.playlist_manager.rename_playlist", return_value=(True, "Renamed")):
- response = await async_client.post(
- "/rename_playlist",
- json={
- "old_name": "old_playlist",
- "new_name": "new_playlist"
- }
- )
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- @pytest.mark.asyncio
- async def test_rename_playlist_not_found(self, async_client):
- """Test renaming a non-existent playlist fails."""
- with patch("main.playlist_manager.rename_playlist", return_value=(False, "Playlist not found")):
- response = await async_client.post(
- "/rename_playlist",
- json={
- "old_name": "nonexistent",
- "new_name": "new_name"
- }
- )
- # Returns 400 with message (not 404)
- assert response.status_code == 400
- class TestAddToPlaylist:
- """Tests for /add_to_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_add_to_playlist(self, async_client):
- """Test adding a pattern to a playlist."""
- with patch("main.playlist_manager.add_to_playlist", return_value=True):
- response = await async_client.post(
- "/add_to_playlist",
- json={
- "playlist_name": "favorites", # API uses playlist_name
- "pattern": "new_pattern.thr" # API uses pattern, not file
- }
- )
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- @pytest.mark.asyncio
- async def test_add_to_playlist_not_found(self, async_client):
- """Test adding to a non-existent playlist fails."""
- with patch("main.playlist_manager.add_to_playlist", return_value=False):
- response = await async_client.post(
- "/add_to_playlist",
- json={
- "playlist_name": "nonexistent",
- "pattern": "pattern.thr"
- }
- )
- assert response.status_code == 404
- class TestRunPlaylist:
- """Tests for /run_playlist endpoint."""
- @pytest.mark.asyncio
- async def test_run_playlist_when_disconnected(self, async_client, mock_state):
- """Test run_playlist fails when not connected.
- Note: The endpoint catches HTTPException and re-raises as 500.
- """
- mock_state.conn = None
- mock_state.is_homing = False
- with patch("main.state", mock_state):
- response = await async_client.post(
- "/run_playlist",
- json={
- "playlist_name": "test",
- "pause_time": 5,
- "clear_pattern": None,
- "run_mode": "single"
- }
- )
- # Endpoint wraps in try/except and returns 500
- assert response.status_code == 500
- data = response.json()
- assert "not established" in data["detail"].lower()
- @pytest.mark.asyncio
- async def test_run_playlist_during_homing(self, async_client, mock_state):
- """Test run_playlist fails during homing.
- Note: The endpoint catches HTTPException and re-raises as 500.
- """
- mock_state.is_homing = True
- mock_state.conn = MagicMock()
- mock_state.conn.is_connected.return_value = True
- with patch("main.state", mock_state):
- response = await async_client.post(
- "/run_playlist",
- json={
- "playlist_name": "test",
- "pause_time": 5,
- "clear_pattern": None,
- "run_mode": "single"
- }
- )
- # Endpoint wraps in try/except and returns 500
- assert response.status_code == 500
- data = response.json()
- assert "homing" in data["detail"].lower()
- class TestSkipPattern:
- """Tests for /skip_pattern endpoint."""
- @pytest.mark.asyncio
- async def test_skip_pattern(self, async_client, mock_state):
- """Test skip_pattern during playlist execution."""
- mock_state.current_playlist = ["a.thr", "b.thr"]
- mock_state.current_playlist_index = 0
- mock_state.skip_requested = False
- with patch("main.state", mock_state):
- response = await async_client.post("/skip_pattern")
- assert response.status_code == 200
- data = response.json()
- assert data["success"] is True
- # Endpoint sets skip_requested directly
- assert mock_state.skip_requested is True
- @pytest.mark.asyncio
- async def test_skip_pattern_no_playlist(self, async_client, mock_state):
- """Test skip_pattern fails when no playlist is running."""
- mock_state.current_playlist = None
- with patch("main.state", mock_state):
- response = await async_client.post("/skip_pattern")
- assert response.status_code == 400
- data = response.json()
- assert "no playlist" in data["detail"].lower()
|