"""Integration tests for annotation endpoints.""" import uuid import pytest from tests.factories import ( create_annotation, create_audio_version, create_band, create_member, create_song, ) @pytest.mark.asyncio @pytest.mark.integration async def test_create_point_annotation(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id, uploader_id=current_member.id) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.post( f"/api/v1/versions/{version.id}/annotations", json={"type": "point", "timestamp_ms": 3000, "body": "Nice groove here", "tags": ["groove"]}, headers=headers, ) assert resp.status_code == 201, resp.text data = resp.json() assert data["type"] == "point" assert data["timestamp_ms"] == 3000 assert data["tags"] == ["groove"] @pytest.mark.asyncio @pytest.mark.integration async def test_create_range_annotation(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id, uploader_id=current_member.id) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.post( f"/api/v1/versions/{version.id}/annotations", json={ "type": "range", "timestamp_ms": 5000, "range_end_ms": 15000, "label": "Vamp section", "tags": ["vamp", "groove"], }, headers=headers, ) assert resp.status_code == 201, resp.text data = resp.json() assert data["type"] == "range" assert data["range_end_ms"] == 15000 @pytest.mark.asyncio @pytest.mark.integration async def test_create_annotation_invalid_range_returns_422(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.post( f"/api/v1/versions/{version.id}/annotations", json={"type": "range", "timestamp_ms": 5000, "range_end_ms": 3000}, headers=headers, ) assert resp.status_code == 422 @pytest.mark.asyncio @pytest.mark.integration async def test_list_annotations(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) await create_annotation(db_session, version_id=version.id, author_id=current_member.id, timestamp_ms=1000) await create_annotation(db_session, version_id=version.id, author_id=current_member.id, timestamp_ms=3000) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.get(f"/api/v1/versions/{version.id}/annotations", headers=headers) assert resp.status_code == 200 data = resp.json() assert len(data) == 2 assert data[0]["timestamp_ms"] == 1000 assert data[1]["timestamp_ms"] == 3000 @pytest.mark.asyncio @pytest.mark.integration async def test_update_annotation(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) annotation = await create_annotation( db_session, version_id=version.id, author_id=current_member.id ) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.patch( f"/api/v1/annotations/{annotation.id}", json={"resolved": True, "label": "Updated label"}, headers=headers, ) assert resp.status_code == 200 data = resp.json() assert data["resolved"] is True assert data["label"] == "Updated label" @pytest.mark.asyncio @pytest.mark.integration async def test_delete_annotation(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) annotation = await create_annotation( db_session, version_id=version.id, author_id=current_member.id ) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.delete(f"/api/v1/annotations/{annotation.id}", headers=headers) assert resp.status_code == 204 # Should be gone from list list_resp = await client.get(f"/api/v1/versions/{version.id}/annotations", headers=headers) assert all(a["id"] != str(annotation.id) for a in list_resp.json()) @pytest.mark.asyncio @pytest.mark.integration async def test_add_reaction(client, db_session, auth_headers_for, current_member): band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) annotation = await create_annotation( db_session, version_id=version.id, author_id=current_member.id ) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.post( f"/api/v1/annotations/{annotation.id}/reactions", json={"emoji": "🔥"}, headers=headers, ) assert resp.status_code == 201 assert resp.json()["emoji"] == "🔥" @pytest.mark.asyncio @pytest.mark.integration async def test_search_ranges(client, db_session, auth_headers_for, current_member): from rehearsalhub.db.models import RangeAnalysis from rehearsalhub.repositories.annotation import AnnotationRepository band = await create_band(db_session, creator_id=current_member.id) song = await create_song(db_session, band_id=band.id, creator_id=current_member.id) version = await create_audio_version(db_session, song_id=song.id) annotation = await create_annotation( db_session, version_id=version.id, author_id=current_member.id, type="range", timestamp_ms=5000, range_end_ms=15000, tags=["groove"], ) # Manually insert a range_analysis ra = RangeAnalysis( annotation_id=annotation.id, version_id=version.id, start_ms=5000, end_ms=15000, bpm=120.0, key="G major", scale="major", ) db_session.add(ra) await db_session.commit() headers = await auth_headers_for(current_member) resp = await client.get( f"/api/v1/bands/{band.id}/search/ranges", params={"bpm_min": 110, "bpm_max": 130, "key": "G major"}, headers=headers, ) assert resp.status_code == 200 results = resp.json() assert len(results) >= 1 assert any(r["bpm"] is not None for r in results)