"""Integration tests for version streaming endpoints.""" import pytest import uuid from unittest.mock import AsyncMock, patch, MagicMock import httpx from rehearsalhub.routers.versions import stream_version, get_waveform from rehearsalhub.db.models import Member, AudioVersion, Song from rehearsalhub.schemas.audio_version import AudioVersionRead @pytest.mark.asyncio @pytest.mark.integration async def test_stream_version_connection_error(): """Test stream_version endpoint handles connection errors gracefully.""" # Mock dependencies mock_session = MagicMock() mock_member = Member(id=uuid.uuid4()) # Mock song and version mock_song = Song(id=uuid.uuid4(), band_id=uuid.uuid4()) mock_version = AudioVersion( id="test-version-id", song_id=mock_song.id, nc_file_path="test/path/file.mp3", waveform_url="test/path/waveform.json", version_number=1 ) # Mock the storage client to raise connection error with patch("rehearsalhub.routers.versions.NextcloudClient") as mock_client_class: mock_client = MagicMock() mock_client.download = AsyncMock(side_effect=httpx.ConnectError("Connection failed")) mock_client_class.for_member.return_value = mock_client # Mock the membership check with patch("rehearsalhub.routers.versions._get_version_and_assert_band_membership", return_value=(mock_version, mock_song)): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: await stream_version( version_id="test-version-id", session=mock_session, current_member=mock_member ) # Should return 503 Service Unavailable assert exc_info.value.status_code == 503 assert "Storage service unavailable" in str(exc_info.value.detail) @pytest.mark.asyncio @pytest.mark.integration async def test_stream_version_file_not_found(): """Test stream_version endpoint handles 404 errors gracefully.""" # Mock dependencies mock_session = MagicMock() mock_member = Member(id=uuid.uuid4()) # Mock song and version mock_song = Song(id=uuid.uuid4(), band_id=uuid.uuid4()) mock_version = AudioVersion( id="test-version-id", song_id=mock_song.id, nc_file_path="test/path/file.mp3", waveform_url="test/path/waveform.json", version_number=1 ) # Mock the storage client to raise 404 error with patch("rehearsalhub.routers.versions.NextcloudClient") as mock_client_class: mock_client = MagicMock() # Create mock response with 404 status mock_response = MagicMock() mock_response.status_code = 404 mock_response.text = "Not Found" mock_client.download = AsyncMock( side_effect=httpx.HTTPStatusError("Not found", request=MagicMock(), response=mock_response) ) mock_client_class.for_member.return_value = mock_client # Mock the membership check with patch("rehearsalhub.routers.versions._get_version_and_assert_band_membership", return_value=(mock_version, mock_song)): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: await stream_version( version_id="test-version-id", session=mock_session, current_member=mock_member ) # Should return 404 Not Found assert exc_info.value.status_code == 404 assert "File not found in storage" in str(exc_info.value.detail) @pytest.mark.asyncio @pytest.mark.integration async def test_get_waveform_connection_error(): """Test get_waveform endpoint handles connection errors gracefully.""" # Mock dependencies mock_session = MagicMock() mock_member = Member(id=uuid.uuid4()) # Mock song and version mock_song = Song(id=uuid.uuid4(), band_id=uuid.uuid4()) mock_version = AudioVersion( id="test-version-id", song_id=mock_song.id, nc_file_path="test/path/file.mp3", waveform_url="test/path/waveform.json", version_number=1 ) # Mock the storage client to raise connection error with patch("rehearsalhub.routers.versions.NextcloudClient") as mock_client_class: mock_client = MagicMock() mock_client.download = AsyncMock(side_effect=httpx.ConnectError("Connection failed")) mock_client_class.for_member.return_value = mock_client # Mock the membership check with patch("rehearsalhub.routers.versions._get_version_and_assert_band_membership", return_value=(mock_version, mock_song)): from fastapi import HTTPException with pytest.raises(HTTPException) as exc_info: await get_waveform( version_id="test-version-id", session=mock_session, current_member=mock_member ) # Should return 503 Service Unavailable assert exc_info.value.status_code == 503 assert "Storage service unavailable" in str(exc_info.value.detail) @pytest.mark.asyncio @pytest.mark.integration async def test_stream_version_success(): """Test successful streaming when connection works.""" # Mock dependencies mock_session = MagicMock() mock_member = Member(id=uuid.uuid4()) # Mock song and version mock_song = Song(id=uuid.uuid4(), band_id=uuid.uuid4()) mock_version = AudioVersion( id="test-version-id", song_id=mock_song.id, nc_file_path="test/path/file.mp3", waveform_url="test/path/waveform.json", version_number=1 ) # Mock the storage client to return success with patch("rehearsalhub.routers.versions.NextcloudClient") as mock_client_class: mock_client = MagicMock() mock_client.download = AsyncMock(return_value=b"audio_data") mock_client_class.for_member.return_value = mock_client # Mock the membership check with patch("rehearsalhub.routers.versions._get_version_and_assert_band_membership", return_value=(mock_version, mock_song)): result = await stream_version( version_id="test-version-id", session=mock_session, current_member=mock_member ) # Should return Response with audio data assert result.status_code == 200 assert result.body == b"audio_data" assert result.media_type == "audio/mpeg"