- 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
85 lines
2.5 KiB
Python
85 lines
2.5 KiB
Python
"""Router tests - Songs endpoints."""
|
|
from app.models.song import Song
|
|
|
|
|
|
class TestListSongs:
|
|
def test_empty_list(self, client):
|
|
r = client.get("/api/songs")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data["total"] == 0
|
|
assert data["items"] == []
|
|
assert data["page"] == 1
|
|
assert data["per_page"] == 50
|
|
|
|
def test_pagination_fields(self, client):
|
|
r = client.get("/api/songs?page=1&per_page=10")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert "total_pages" in data
|
|
assert data["total_pages"] >= 1
|
|
|
|
def test_with_songs(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
song = Song(id="s1", title="Test", artist="Artist", file_path="/tmp/test.mp3")
|
|
db.add(song)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/songs")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert data["total"] == 1
|
|
assert data["items"][0]["title"] == "Test"
|
|
|
|
|
|
class TestGetSong:
|
|
def test_found(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
song = Song(id="s1", title="Test", artist="Artist", file_path="/tmp/test.mp3")
|
|
db.add(song)
|
|
db.commit()
|
|
db.close()
|
|
r = client.get("/api/songs/s1")
|
|
assert r.status_code == 200
|
|
assert r.json()["title"] == "Test"
|
|
|
|
def test_not_found(self, client):
|
|
r = client.get("/api/songs/nonexistent")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestDeleteSong:
|
|
def test_delete_found(self, client, db_module):
|
|
db = db_module.SessionLocal()
|
|
song = Song(id="s1", title="Test", artist="Artist", file_path="/tmp/test.mp3")
|
|
db.add(song)
|
|
db.commit()
|
|
db.close()
|
|
r = client.delete("/api/songs/s1")
|
|
assert r.status_code == 200
|
|
assert r.json()["message"] == "Song deleted"
|
|
|
|
def test_delete_not_found(self, client):
|
|
r = client.delete("/api/songs/nonexistent")
|
|
assert r.status_code == 404
|
|
|
|
|
|
class TestScanSongs:
|
|
def test_scan_default_dir(self, client):
|
|
r = client.post("/api/songs/scan")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert "scanned" in data
|
|
assert "added" in data
|
|
assert "skipped" in data
|
|
assert "errors" in data
|
|
|
|
|
|
class TestUploadSong:
|
|
def test_unsupported_format(self, client):
|
|
r = client.post(
|
|
"/api/songs/upload",
|
|
files={"file": ("test.txt", b"content", "text/plain")},
|
|
)
|
|
assert r.status_code == 400
|