import time import pytest from server import mf, jobs as jobs_mod @pytest.fixture(autouse=True) def _clear_jobs(): jobs_mod.JOBS.clear() yield jobs_mod.JOBS.clear() def _yt_hit(): return mf.Hit(source="youtube", kind="track", title="Together", artist="Avril Lavigne", album="Under My Skin", year="2004", payload={"videoId": "abc"}) def test_fetch_returns_job_and_message(client, auth, monkeypatch): hit = _yt_hit() monkeypatch.setattr("server.app.mf.build_combined_hits", lambda q, limit, yt_first, lidarr_only, yt_only: [hit]) monkeypatch.setattr("server.app.mf.pick", lambda hits, q, noninteractive, yt_first: hits[0]) monkeypatch.setattr("server.app.actions.perform_fetch", lambda chosen, hits, quality, root: {"path": "/media/music/x", "lidarr_album_id": None}) r = client.post("/fetch", params={"q": "Under My Skin"}, headers=auth) assert r.status_code == 200 body = r.json() assert body["status"] == "queued" assert "Together" in body["message"] assert body["hit"]["artist"] == "Avril Lavigne" assert body["job_id"] def test_fetch_no_hits_returns_404(client, auth, monkeypatch): monkeypatch.setattr("server.app.mf.build_combined_hits", lambda q, limit, yt_first, lidarr_only, yt_only: []) r = client.post("/fetch", params={"q": "zzzz"}, headers=auth) assert r.status_code == 404 assert "zzzz" in r.json()["message"] def test_fetch_missing_q_returns_422(client, auth): r = client.post("/fetch", headers=auth) assert r.status_code == 422 assert "message" in r.json() def test_job_lifecycle_done(client, auth, monkeypatch): hit = _yt_hit() monkeypatch.setattr("server.app.mf.build_combined_hits", lambda q, limit, yt_first, lidarr_only, yt_only: [hit]) monkeypatch.setattr("server.app.mf.pick", lambda hits, q, noninteractive, yt_first: hits[0]) monkeypatch.setattr("server.app.actions.perform_fetch", lambda chosen, hits, quality, root: {"path": "/media/music/x", "lidarr_album_id": None}) job_id = client.post("/fetch", params={"q": "x"}, headers=auth).json()["job_id"] end = time.time() + 2 status = None while time.time() < end: body = client.get(f"/jobs/{job_id}", headers=auth).json() status = body["status"] if status == "done": break time.sleep(0.01) assert status == "done" assert body["result"]["path"] == "/media/music/x" assert "Finished" in body["message"] def test_unknown_job_404(client, auth): r = client.get("/jobs/deadbeef", headers=auth) assert r.status_code == 404 assert "message" in r.json() def test_jobs_requires_key(client): r = client.get("/jobs/whatever") assert r.status_code == 401 def test_fetch_invalid_quality_422(client, auth): r = client.post("/fetch", params={"q": "x", "quality": "bogus"}, headers=auth) assert r.status_code == 422 assert "message" in r.json() def test_fetch_invalid_source_422(client, auth): r = client.post("/fetch", params={"q": "x", "source": "spotify"}, headers=auth) assert r.status_code == 422 assert "message" in r.json() def test_fetch_pick_none_returns_404(client, auth, monkeypatch): hit = _yt_hit() monkeypatch.setattr("server.app.mf.build_combined_hits", lambda q, limit, yt_first, lidarr_only, yt_only: [hit]) monkeypatch.setattr("server.app.mf.pick", lambda hits, q, noninteractive, yt_first: None) r = client.post("/fetch", params={"q": "x"}, headers=auth) assert r.status_code == 404 assert "message" in r.json()