# tests/test_api_nodes.py — integration tests for branch/commit/discard endpoints from __future__ import annotations import io def _create_chain_with_root(client, tmp_path=None): """Helper: create a chain and upload a root node.""" resp = client.post("/api/chains/", json={"name": "test chain"}) chain_id = resp.json()["id"] resp = client.post( f"/api/chains/{chain_id}/upload", files={"file": ("root.wav", io.BytesIO(b"RIFF" + b"\x00" * 40), "audio/wav")}, ) node = resp.json() return chain_id, node["id"] def test_create_branch_returns_202(client, tmp_path): chain_id, root_id = _create_chain_with_root(client) resp = client.post( f"/api/nodes/{root_id}/branch", json={"prompt": "upbeat jazz", "duration_s": 10.0}, ) assert resp.status_code == 202 node = resp.json() assert node["status"] == "pending" assert node["parent_id"] == root_id assert node["prompt"] == "upbeat jazz" def test_branch_parent_not_found(client): resp = client.post( "/api/nodes/nonexistent/branch", json={"prompt": "test"}, ) assert resp.status_code == 404 def test_commit_requires_ready_status(client, conn): """ Directly insert a pending node into the shared DB (bypasses BackgroundTasks so we control the status without triggering mock generation). """ from app.services import chain as svc chain_id, root_id = _create_chain_with_root(client) # Create branch via service (no background task), stays "pending" branch = svc.create_branch_node( conn, root_id, chain_id, "test", None, None, None, 3.0, 10.0 ) resp = client.post(f"/api/nodes/{branch['id']}/commit") assert resp.status_code == 409 def test_delete_root_node_refused(client): chain_id, root_id = _create_chain_with_root(client) resp = client.delete(f"/api/nodes/{root_id}") assert resp.status_code == 409 def test_delete_node_not_found(client): resp = client.delete("/api/nodes/doesnotexist") assert resp.status_code == 409 def test_audio_not_found_for_pending_node(client, conn): """Pending node (no audio_path yet) returns 404 on the audio endpoint.""" from app.services import chain as svc chain_id, root_id = _create_chain_with_root(client) branch = svc.create_branch_node( conn, root_id, chain_id, "test", None, None, None, 3.0, 10.0 ) resp = client.get(f"/api/nodes/{branch['id']}/audio") assert resp.status_code == 404 def test_mock_generation_completes(client, conn): """ With CF_MUSICGEN_MOCK=1, TestClient runs BackgroundTasks synchronously, so the node transitions to 'ready' before client.post() returns. We verify the completed state via the shared conn fixture. """ from app.services import chain as svc chain_id, root_id = _create_chain_with_root(client) resp = client.post( f"/api/nodes/{root_id}/branch", json={"prompt": "test mock", "duration_s": 5.0}, ) assert resp.status_code == 202 branch_id = resp.json()["id"] # Background task completed synchronously — node is ready node = svc.get_node(conn, branch_id) assert node is not None assert node["status"] == "ready", ( f"Expected ready, got: {node['status']}, error: {node.get('error_msg')}" )