feat(music-lab): pipeline 오케스트레이터 + 14 엔드포인트
This commit is contained in:
110
music-lab/tests/test_pipeline_endpoints.py
Normal file
110
music-lab/tests/test_pipeline_endpoints.py
Normal file
@@ -0,0 +1,110 @@
|
||||
import sqlite3
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.main import app
|
||||
from app import db
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(monkeypatch, tmp_path):
|
||||
monkeypatch.setattr(db, "DB_PATH", str(tmp_path / "music.db"))
|
||||
db.init_db()
|
||||
# 최소 트랙 1개 — music_library 테이블에 직접 삽입
|
||||
conn = sqlite3.connect(db.DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute(
|
||||
"""INSERT INTO music_library
|
||||
(id, title, genre, moods, instruments, duration_sec, bpm, key, scale,
|
||||
prompt, audio_url, file_path, task_id, tags)
|
||||
VALUES (1, 'T', 'lo-fi', '["chill"]', '["piano"]', 120, 85, 'C', 'maj',
|
||||
'p', '/media/music/x.mp3', '/app/data/music/x.mp3', NULL, '[]')""",
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_create_pipeline(client):
|
||||
r = client.post("/api/music/pipeline", json={"track_id": 1})
|
||||
assert r.status_code == 201
|
||||
assert r.json()["state"] == "created"
|
||||
|
||||
|
||||
def test_create_duplicate_pipeline_returns_409(client):
|
||||
client.post("/api/music/pipeline", json={"track_id": 1})
|
||||
r = client.post("/api/music/pipeline", json={"track_id": 1})
|
||||
assert r.status_code == 409
|
||||
|
||||
|
||||
def test_get_pipeline_returns_jobs_and_feedback(client):
|
||||
pid = client.post("/api/music/pipeline", json={"track_id": 1}).json()["id"]
|
||||
r = client.get(f"/api/music/pipeline/{pid}")
|
||||
assert "jobs" in r.json()
|
||||
assert "feedback" in r.json()
|
||||
|
||||
|
||||
def test_list_pipelines_active_filter(client):
|
||||
pid = client.post("/api/music/pipeline", json={"track_id": 1}).json()["id"]
|
||||
db.update_pipeline_state(pid, "published")
|
||||
r = client.get("/api/music/pipeline?status=active")
|
||||
assert all(p["state"] != "published" for p in r.json()["pipelines"])
|
||||
|
||||
|
||||
def test_feedback_reject_records_feedback_and_increments_count(client):
|
||||
pid = client.post("/api/music/pipeline", json={"track_id": 1}).json()["id"]
|
||||
db.update_pipeline_state(pid, "cover_pending")
|
||||
# orchestrator.run_step를 mock해서 백그라운드 작업이 cover_pending을 변경하지 않도록
|
||||
with patch("app.main.orchestrator.run_step", new=AsyncMock()):
|
||||
r = client.post(
|
||||
f"/api/music/pipeline/{pid}/feedback",
|
||||
json={"step": "cover", "intent": "reject", "feedback_text": "더 어둡게"},
|
||||
)
|
||||
assert r.status_code == 202
|
||||
p = db.get_pipeline(pid)
|
||||
assert p["feedback_count_per_step"]["cover"] == 1
|
||||
history = db.get_feedback_history(pid)
|
||||
assert history[0]["feedback_text"] == "더 어둡게"
|
||||
|
||||
|
||||
def test_feedback_after_5_rejects_marks_awaiting_manual(client):
|
||||
pid = client.post("/api/music/pipeline", json={"track_id": 1}).json()["id"]
|
||||
db.update_pipeline_state(pid, "cover_pending")
|
||||
with patch("app.main.orchestrator.run_step", new=AsyncMock()):
|
||||
for i in range(5):
|
||||
client.post(
|
||||
f"/api/music/pipeline/{pid}/feedback",
|
||||
json={"step": "cover", "intent": "reject", "feedback_text": f"again {i}"},
|
||||
)
|
||||
r = client.post(
|
||||
f"/api/music/pipeline/{pid}/feedback",
|
||||
json={"step": "cover", "intent": "reject", "feedback_text": "6th"},
|
||||
)
|
||||
assert r.status_code == 409
|
||||
assert db.get_pipeline(pid)["state"] == "awaiting_manual"
|
||||
|
||||
|
||||
def test_cancel_pipeline(client):
|
||||
pid = client.post("/api/music/pipeline", json={"track_id": 1}).json()["id"]
|
||||
r = client.post(f"/api/music/pipeline/{pid}/cancel")
|
||||
assert r.status_code == 200
|
||||
assert db.get_pipeline(pid)["state"] == "cancelled"
|
||||
|
||||
|
||||
def test_setup_get_returns_defaults(client):
|
||||
r = client.get("/api/music/setup")
|
||||
assert r.status_code == 200
|
||||
assert r.json()["review_threshold"] == 60
|
||||
|
||||
|
||||
def test_setup_put_updates(client):
|
||||
r = client.put("/api/music/setup", json={"review_threshold": 70})
|
||||
assert r.status_code == 200
|
||||
assert r.json()["review_threshold"] == 70
|
||||
|
||||
|
||||
def test_youtube_status_when_disconnected(client):
|
||||
r = client.get("/api/music/youtube/status")
|
||||
assert r.status_code == 200
|
||||
assert r.json() == {"connected": False}
|
||||
Reference in New Issue
Block a user