Add tests for extraction API endpoints and enhance existing tests
Some checks failed
Backend CI / lint (push) Successful in 9m25s
Backend CI / test (push) Failing after 4m48s

- Implement tests for admin extraction API endpoints including status retrieval, deletion of extractions, and permission checks.
- Add tests for user extraction deletion, ensuring proper handling of permissions and non-existent extractions.
- Enhance sound endpoint tests to include duplicate handling in responses.
- Refactor favorite service tests to utilize mock dependencies for better maintainability and clarity.
- Update sound scanner tests to improve file handling and ensure proper deletion of associated files.
This commit is contained in:
JSC
2025-08-25 21:40:31 +02:00
parent d3ce17f10d
commit 7dee6e320e
15 changed files with 1560 additions and 721 deletions

View File

@@ -541,3 +541,143 @@ class TestExtractionService:
assert result[0]["id"] == 1
assert result[0]["status"] == "pending"
assert result[0]["user_name"] == "Test User"
@pytest.mark.asyncio
async def test_delete_extraction_with_sound(self, extraction_service, test_user):
"""Test deleting extraction with associated sound and files."""
import tempfile
from pathlib import Path
# Create temporary directories for testing
with tempfile.TemporaryDirectory() as temp_dir:
temp_dir_path = Path(temp_dir)
# Set up temporary directories
original_dir = temp_dir_path / "originals" / "extracted"
normalized_dir = temp_dir_path / "normalized" / "extracted"
thumbnail_dir = temp_dir_path / "thumbnails"
original_dir.mkdir(parents=True)
normalized_dir.mkdir(parents=True)
thumbnail_dir.mkdir(parents=True)
# Create test files
audio_file = original_dir / "test_audio.mp3"
normalized_file = normalized_dir / "test_audio.mp3"
thumbnail_file = thumbnail_dir / "test_thumb.jpg"
audio_file.write_text("audio content")
normalized_file.write_text("normalized content")
thumbnail_file.write_text("thumbnail content")
# Create extraction and sound records
extraction = Extraction(
id=1,
url="https://example.com/video",
user_id=test_user.id,
status="completed",
sound_id=1,
)
sound = Sound(
id=1,
type="EXT",
name="Test Audio",
filename="test_audio.mp3",
duration=60000,
size=2048,
hash="test_hash",
is_normalized=True,
normalized_filename="test_audio.mp3",
thumbnail="test_thumb.jpg",
is_deletable=True,
is_music=True,
)
# Mock repository methods
extraction_service.extraction_repo.get_by_id = AsyncMock(return_value=extraction)
extraction_service.sound_repo.get_by_id = AsyncMock(return_value=sound)
extraction_service.extraction_repo.delete = AsyncMock()
extraction_service.sound_repo.delete = AsyncMock()
extraction_service.session.commit = AsyncMock()
extraction_service.session.rollback = AsyncMock()
# Monkey patch the paths in the service method
import app.services.extraction
original_path_class = app.services.extraction.Path
def mock_path(*args: str):
path_str = str(args[0])
if path_str == "sounds/originals/extracted":
return original_dir
if path_str == "sounds/normalized/extracted":
return normalized_dir
if path_str.endswith("thumbnails"):
return thumbnail_dir
return original_path_class(*args)
# Mock the Path constructor and settings
with patch("app.services.extraction.Path", side_effect=mock_path), \
patch("app.services.extraction.settings") as mock_settings:
mock_settings.EXTRACTION_THUMBNAILS_DIR = str(thumbnail_dir)
# Test deletion
result = await extraction_service.delete_extraction(1, test_user.id)
assert result is True
# Verify repository calls
extraction_service.extraction_repo.get_by_id.assert_called_once_with(1)
extraction_service.sound_repo.get_by_id.assert_called_once_with(1)
extraction_service.extraction_repo.delete.assert_called_once_with(extraction)
extraction_service.sound_repo.delete.assert_called_once_with(sound)
extraction_service.session.commit.assert_called_once()
# Verify files were deleted
assert not audio_file.exists()
assert not normalized_file.exists()
assert not thumbnail_file.exists()
@pytest.mark.asyncio
async def test_delete_extraction_not_found(self, extraction_service, test_user):
"""Test deleting non-existent extraction."""
extraction_service.extraction_repo.get_by_id = AsyncMock(return_value=None)
result = await extraction_service.delete_extraction(999, test_user.id)
assert result is False
@pytest.mark.asyncio
async def test_delete_extraction_permission_denied(self, extraction_service, test_user):
"""Test deleting extraction owned by another user."""
extraction = Extraction(
id=1,
url="https://example.com/video",
user_id=999, # Different user ID
status="completed",
)
extraction_service.extraction_repo.get_by_id = AsyncMock(return_value=extraction)
with pytest.raises(ValueError, match="You don't have permission"):
await extraction_service.delete_extraction(1, test_user.id)
@pytest.mark.asyncio
async def test_delete_extraction_admin(self, extraction_service, test_user):
"""Test admin deleting any extraction."""
extraction = Extraction(
id=1,
url="https://example.com/video",
user_id=999, # Different user ID
status="completed",
)
extraction_service.extraction_repo.get_by_id = AsyncMock(return_value=extraction)
extraction_service.extraction_repo.delete = AsyncMock()
extraction_service.session.commit = AsyncMock()
# Admin deletion (user_id=None)
result = await extraction_service.delete_extraction(1, None)
assert result is True
extraction_service.extraction_repo.delete.assert_called_once_with(extraction)