- 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
168 lines
5.2 KiB
Python
168 lines
5.2 KiB
Python
"""Tests for uncovered routes: import, streaming, websocket."""
|
|
import tempfile
|
|
import os
|
|
|
|
|
|
class TestImportRouter:
|
|
def test_bulk_import_unsupported(self, client):
|
|
r = client.post(
|
|
"/api/import/bulk",
|
|
files=[("files", ("test.txt", b"content", "text/plain"))],
|
|
)
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data["scanned"] == 0
|
|
assert len(data["errors"]) == 1
|
|
|
|
|
|
class TestSongStreaming:
|
|
def test_stream_not_found(self, client):
|
|
r = client.get("/api/songs/nonexistent/stream")
|
|
assert r.status_code == 404
|
|
|
|
def test_stream_file_not_found(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
from app.models.song import Song
|
|
s = Song(id="s1", title="T", artist="A", file_path="/no/file.mp3")
|
|
db.add(s)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/songs/s1/stream")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestSongDelete:
|
|
def test_delete_song(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
from app.models.song import Song
|
|
tmpdir = tempfile.mkdtemp()
|
|
fp = os.path.join(tmpdir, "test.mp3")
|
|
with open(fp, "w") as f:
|
|
f.write("test")
|
|
s = Song(id="s1", title="T", artist="A", file_path=fp)
|
|
db.add(s)
|
|
db.commit()
|
|
db.close()
|
|
r = client.delete("/api/songs/s1")
|
|
assert r.status_code == 200
|
|
assert not os.path.exists(fp)
|
|
os.unlink(fp) if os.path.exists(fp) else None
|
|
os.rmdir(tmpdir)
|
|
|
|
|
|
class TestPlaylistEdgeCases:
|
|
def test_add_song_playlist_not_found(self, client):
|
|
r = client.post("/api/playlists/nonexistent/songs", params={"song_id": "s1"})
|
|
assert r.status_code == 404
|
|
|
|
def test_add_song_song_not_found(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
from app.models.playlist import Playlist
|
|
p = Playlist(id="p1", name="Test")
|
|
db.add(p)
|
|
db.commit()
|
|
db.close()
|
|
r = client.post("/api/playlists/p1/songs", params={"song_id": "nonexistent"})
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestMoodRouter:
|
|
def test_save_mood_playlist(self, client):
|
|
r = client.post("/api/mood/save", params={"mood": "Chill"})
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data["name"] == "Chill Playlist"
|
|
|
|
|
|
class TestEventsAdd:
|
|
def test_add_event(self, client):
|
|
r = client.post("/api/events", json={
|
|
"id": "e99",
|
|
"name": "New Event",
|
|
"venue": "Venue",
|
|
"location_lat": 40.7,
|
|
"location_lon": -74.0,
|
|
"date": "2025-12-25",
|
|
"description": "Desc"
|
|
})
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestReleasesRouter:
|
|
def test_add_release_to_playlist_not_found(self, client):
|
|
r = client.post("/api/releases/add", params={
|
|
"artist": "A", "album_id": "b1", "playlist_id": "nonexistent"
|
|
})
|
|
assert r.status_code == 200
|
|
assert r.json().get("error") == "Playlist not found"
|
|
|
|
|
|
class TestSharePlayCue:
|
|
def test_add_to_cue_not_found(self, client):
|
|
r = client.post("/api/shareplay/cue", params={"room_id": "r1", "song_id": "nonexistent"})
|
|
assert r.status_code == 400
|
|
|
|
|
|
class TestSettingsRemoveServer:
|
|
def test_remove_server_bounds(self, client):
|
|
r = client.delete("/api/settings/servers/99")
|
|
# Should return 404 since no servers configured
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestRadioStream:
|
|
def test_stream_radio_not_found(self, client):
|
|
r = client.get("/api/radio/stream/nonexistent")
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestLofiChannels:
|
|
def test_list_after_add(self, client):
|
|
before = client.get("/api/lofi/channels").json()
|
|
client.post("/api/lofi/add", json={
|
|
"name": "Unique Lofi",
|
|
"stream_url": "https://unique.com/stream"
|
|
})
|
|
after = client.get("/api/lofi/channels").json()
|
|
assert len(after) == len(before) + 1
|
|
|
|
|
|
class TestSearchEdgeCases:
|
|
def test_search_special_chars(self, client):
|
|
r = client.get("/api/search?q=%25%27%22")
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestSongListEdgeCases:
|
|
def test_songs_per_page_max(self, client):
|
|
r = client.get("/api/songs?per_page=200")
|
|
assert r.status_code == 200
|
|
assert r.json()["per_page"] == 200
|
|
|
|
def test_songs_page_zero(self, client):
|
|
r = client.get("/api/songs?page=0")
|
|
assert r.status_code == 422
|
|
|
|
|
|
class TestMoodPlaylistLimit:
|
|
def test_mood_playlist_limit(self, client):
|
|
r = client.get("/api/mood/Happy/playlist?limit=5")
|
|
assert r.status_code == 200
|
|
|
|
def test_mood_playlist_limit_min(self, client):
|
|
r = client.get("/api/mood/Happy/playlist?limit=1")
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestSettingsUpdatePartial:
|
|
def test_update_partial_settings(self, client):
|
|
r = client.put("/api/settings", json={"theme": "light"})
|
|
assert r.status_code == 200
|
|
|
|
|
|
class TestAccountHistory:
|
|
def test_history_empty(self, client):
|
|
r = client.get("/api/account/history")
|
|
assert r.status_code == 200
|
|
assert r.json() == []
|