"""Unit tests for migrate_to_short_ids script logic.""" from unittest.mock import AsyncMock, MagicMock, patch import pytest @pytest.fixture def mock_image_null_short_id(): img = MagicMock() img.id = "img-uuid-1" img.short_id = None img.storage_key = "oldhashkey1234567890" img.thumbnail_key = "oldhashkey1234567890-thumb" img.mime_type = "image/jpeg" return img @pytest.fixture def mock_image_with_short_id(): img = MagicMock() img.id = "img-uuid-2" img.short_id = "AbCd1234" img.storage_key = "AbCd1234" img.thumbnail_key = "AbCd1234-thumb" img.mime_type = "image/jpeg" return img @pytest.mark.asyncio async def test_migrate_processes_image_without_short_id(mock_image_null_short_id): """Images with short_id IS NULL are processed: storage copied, DB updated, old keys deleted.""" from scripts.migrate_to_short_ids import migrate_image storage = MagicMock() storage.get = AsyncMock(return_value=b"imagedata") storage.put = AsyncMock() storage.delete = AsyncMock() session = MagicMock() session.execute = AsyncMock() session.flush = AsyncMock() old_key = mock_image_null_short_id.storage_key new_short_id = "NewSh123" with patch("scripts.migrate_to_short_ids.generate_short_id", return_value=new_short_id): result = await migrate_image(mock_image_null_short_id, storage, session) assert result is True storage.put.assert_any_call(new_short_id, b"imagedata", "image/jpeg") storage.delete.assert_any_call(old_key) @pytest.mark.asyncio async def test_migrate_skips_image_with_short_id(mock_image_with_short_id): """Images that already have a short_id are skipped.""" from scripts.migrate_to_short_ids import migrate_image storage = MagicMock() session = MagicMock() result = await migrate_image(mock_image_with_short_id, storage, session) assert result is False storage.get.assert_not_called() if hasattr(storage.get, "assert_not_called") else None @pytest.mark.asyncio async def test_migrate_continues_on_storage_error(mock_image_null_short_id): """If storage copy fails, error is logged and migrate_image returns False without aborting.""" from scripts.migrate_to_short_ids import migrate_image storage = MagicMock() storage.get = AsyncMock(side_effect=Exception("storage read error")) storage.put = AsyncMock() storage.delete = AsyncMock() session = MagicMock() session.execute = AsyncMock() session.flush = AsyncMock() with patch("scripts.migrate_to_short_ids.generate_short_id", return_value="ErrSh123"): result = await migrate_image(mock_image_null_short_id, storage, session) assert result is False storage.put.assert_not_called() @pytest.mark.asyncio async def test_migrate_summary_counts(mock_image_null_short_id, mock_image_with_short_id): """run_migration reports correct migrated and skipped counts.""" from scripts.migrate_to_short_ids import run_migration storage = MagicMock() storage.get = AsyncMock(return_value=b"data") storage.put = AsyncMock() storage.delete = AsyncMock() session = MagicMock() session.execute = AsyncMock() session.flush = AsyncMock() images = [mock_image_null_short_id, mock_image_with_short_id] with patch("scripts.migrate_to_short_ids.generate_short_id", return_value="NewSh999"): migrated, skipped, failed = await run_migration(images, storage, session) assert migrated == 1 assert skipped == 1 assert failed == 0