- Add pytest config with 90% coverage threshold - 15 test files covering all routers, services, schemas, models - 300 tests: unit tests, integration tests, edge cases, mocked external APIs - Update CI workflow to run pytest with coverage enforcement - Mock external services (Genius, MusicBrainz, RadioBrowser) - In-memory SQLite DB per test via conftest fixtures
164 lines
5.3 KiB
Python
164 lines
5.3 KiB
Python
"""Router tests - Playlist endpoints."""
|
|
from app.models.song import Song
|
|
from app.models.playlist import Playlist, PlaylistSong
|
|
|
|
|
|
class TestListPlaylists:
|
|
def test_empty_list(self, client):
|
|
r = client.get("/api/playlists")
|
|
assert r.status_code == 200
|
|
assert r.json() == []
|
|
|
|
def test_with_playlists(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test Playlist")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/playlists")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert len(data) == 1
|
|
assert data[0]["name"] == "Test Playlist"
|
|
assert "song_count" in data[0]
|
|
|
|
|
|
class TestCreatePlaylist:
|
|
def test_create_basic(self, client):
|
|
r = client.post("/api/playlists", json={"name": "New Playlist", "description": "Test"})
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data["name"] == "New Playlist"
|
|
assert "id" in data
|
|
assert len(data["id"]) > 0
|
|
|
|
def test_create_with_songs(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
song = Song(id="s1", title="Test", artist="A", file_path="/tmp/t.mp3")
|
|
db.add(song)
|
|
db.commit()
|
|
db.close()
|
|
r = client.post("/api/playlists", json={"name": "With Songs", "song_ids": ["s1"]})
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestGetPlaylist:
|
|
def test_found(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/playlists/p1")
|
|
assert r.status_code == 200
|
|
assert r.json()["name"] == "Test"
|
|
assert "songs" in r.json()
|
|
|
|
def test_not_found(self, client):
|
|
r = client.get("/api/playlists/nonexistent")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestUpdatePlaylist:
|
|
def test_update(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Old")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.put("/api/playlists/p1", json={"name": "New", "description": "Updated"})
|
|
assert r.status_code == 200
|
|
assert r.json()["name"] == "New"
|
|
|
|
def test_update_not_found(self, client):
|
|
r = client.put("/api/playlists/nonexistent", json={"name": "X"})
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestDeletePlaylist:
|
|
def test_delete(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.delete("/api/playlists/p1")
|
|
assert r.status_code == 200
|
|
assert r.json()["message"] == "Playlist deleted"
|
|
|
|
def test_delete_not_found(self, client):
|
|
r = client.delete("/api/playlists/nonexistent")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestAddRemoveSong:
|
|
def test_add_song(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
s = Song(id="s1", title="T", artist="A", file_path="/tmp/t.mp3")
|
|
db.add(p)
|
|
db.add(s)
|
|
db.commit()
|
|
db.close()
|
|
r = client.post("/api/playlists/p1/songs", params={"song_id": "s1"})
|
|
assert r.status_code == 200
|
|
|
|
def test_add_duplicate(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
s = Song(id="s1", title="T", artist="A", file_path="/tmp/t.mp3")
|
|
ps = PlaylistSong(playlist_id="p1", song_id="s1", position=0)
|
|
db.add(p)
|
|
db.add(s)
|
|
db.add(ps)
|
|
db.commit()
|
|
db.close()
|
|
r = client.post("/api/playlists/p1/songs", params={"song_id": "s1"})
|
|
assert r.status_code == 400
|
|
|
|
def test_remove_song(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
s = Song(id="s1", title="T", artist="A", file_path="/tmp/t.mp3")
|
|
ps = PlaylistSong(playlist_id="p1", song_id="s1", position=0)
|
|
db.add(p)
|
|
db.add(s)
|
|
db.add(ps)
|
|
db.commit()
|
|
db.close()
|
|
r = client.delete("/api/playlists/p1/songs/s1")
|
|
assert r.status_code == 200
|
|
|
|
def test_remove_not_in_playlist(self, client):
|
|
r = client.delete("/api/playlists/p1/songs/s1")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestSharePlaylist:
|
|
def test_share(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.post("/api/playlists/p1/share")
|
|
assert r.status_code == 200
|
|
assert "token" in r.json()
|
|
|
|
def test_share_not_found(self, client):
|
|
r = client.post("/api/playlists/nonexistent/share")
|
|
assert r.status_code == 404
|
|
|
|
def test_get_shared(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
p = Playlist(id="p1", name="Test", share_token="abc123", is_shared=True)
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/playlists/shared/abc123")
|
|
assert r.status_code == 200
|
|
|
|
def test_get_shared_not_found(self, client):
|
|
r = client.get("/api/playlists/shared/nonexistent")
|
|
assert r.status_code == 404
|