import pytest from unittest.mock import patch, MagicMock from app.pipeline.orchestrator import _resolve_input def test_resolve_input_track(): pipeline = {"id": 1, "track_id": 13, "compile_job_id": None} track = { "id": 13, "title": "Lo-Fi Drive", "genre": "lo-fi", "moods": ["chill"], "duration_sec": 176, "file_path": "/app/data/x.mp3", "audio_url": "/media/music/x.mp3", } with patch("app.pipeline.orchestrator.db.get_track_by_id", return_value=track): result = _resolve_input(pipeline) assert result["audio_path"] == "/app/data/x.mp3" assert result["duration_sec"] == 176 assert len(result["tracks"]) == 1 assert result["tracks"][0]["start_offset_sec"] == 0 assert result["title"] == "Lo-Fi Drive" assert result["genre"] == "lo-fi" def test_resolve_input_compile_job(): pipeline = {"id": 2, "track_id": None, "compile_job_id": 5} job = { "id": 5, "status": "succeeded", "title": "Chill Mix", "audio_path": "/app/data/compiles/5.mp3", "track_ids": [13, 14, 15], "crossfade_sec": 3, } tracks = { 13: {"id": 13, "title": "T1", "duration_sec": 180}, 14: {"id": 14, "title": "T2", "duration_sec": 200}, 15: {"id": 15, "title": "T3", "duration_sec": 150}, } with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job), \ patch("app.pipeline.orchestrator.db.get_track_by_id", side_effect=lambda i: tracks[i]): result = _resolve_input(pipeline) assert result["audio_path"] == "/app/data/compiles/5.mp3" # 누적 = 180+200+150 - 2*3(crossfade pair gaps) = 524 assert result["duration_sec"] == 524 assert len(result["tracks"]) == 3 assert result["tracks"][0]["start_offset_sec"] == 0 assert result["tracks"][1]["start_offset_sec"] == 177 # 180 - 3 assert result["tracks"][2]["start_offset_sec"] == 374 # 177 + 200 - 3 assert result["title"] == "Chill Mix" assert result["genre"] == "mix" def test_resolve_input_compile_not_ready(): pipeline = {"id": 3, "track_id": None, "compile_job_id": 6} job = {"id": 6, "status": "rendering"} with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job): with pytest.raises(ValueError, match="not ready"): _resolve_input(pipeline) def test_resolve_input_neither(): pipeline = {"id": 4, "track_id": None, "compile_job_id": None} with pytest.raises(ValueError): _resolve_input(pipeline) def test_resolve_input_compile_job_done_status(): """compile job status='done'도 accept (production convention).""" pipeline = {"id": 5, "track_id": None, "compile_job_id": 7} job = { "id": 7, "status": "done", "title": "Done Mix", "audio_path": "/app/data/compiles/7.mp3", "track_ids": [1], "crossfade_sec": 0, } track = {"id": 1, "title": "T1", "duration_sec": 100} with patch("app.pipeline.orchestrator.db.get_compile_job", return_value=job), \ patch("app.pipeline.orchestrator.db.get_track_by_id", return_value=track): result = _resolve_input(pipeline) assert result["audio_path"] == "/app/data/compiles/7.mp3" assert result["title"] == "Done Mix"