WIP
This commit is contained in:
306
tests/web/test_storage_integration.py
Normal file
306
tests/web/test_storage_integration.py
Normal file
@@ -0,0 +1,306 @@
|
||||
"""
|
||||
Tests for storage backend integration in web application.
|
||||
|
||||
TDD Phase 1: RED - Write tests first, then implement to pass.
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class TestStorageBackendInitialization:
|
||||
"""Tests for storage backend initialization in web config."""
|
||||
|
||||
def test_get_storage_backend_returns_backend(self, tmp_path: Path) -> None:
|
||||
"""Test that get_storage_backend returns a StorageBackend instance."""
|
||||
from shared.storage.base import StorageBackend
|
||||
|
||||
from inference.web.config import get_storage_backend
|
||||
|
||||
env = {
|
||||
"STORAGE_BACKEND": "local",
|
||||
"STORAGE_BASE_PATH": str(tmp_path / "storage"),
|
||||
}
|
||||
|
||||
with patch.dict(os.environ, env, clear=False):
|
||||
backend = get_storage_backend()
|
||||
|
||||
assert isinstance(backend, StorageBackend)
|
||||
|
||||
def test_get_storage_backend_uses_config_file_if_exists(
|
||||
self, tmp_path: Path
|
||||
) -> None:
|
||||
"""Test that storage config file is used when present."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
from inference.web.config import get_storage_backend
|
||||
|
||||
config_file = tmp_path / "storage.yaml"
|
||||
storage_path = tmp_path / "storage"
|
||||
config_file.write_text(f"""
|
||||
backend: local
|
||||
|
||||
local:
|
||||
base_path: {storage_path}
|
||||
""")
|
||||
|
||||
backend = get_storage_backend(config_path=config_file)
|
||||
|
||||
assert isinstance(backend, LocalStorageBackend)
|
||||
|
||||
def test_get_storage_backend_falls_back_to_env(self, tmp_path: Path) -> None:
|
||||
"""Test fallback to environment variables when no config file."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
from inference.web.config import get_storage_backend
|
||||
|
||||
env = {
|
||||
"STORAGE_BACKEND": "local",
|
||||
"STORAGE_BASE_PATH": str(tmp_path / "storage"),
|
||||
}
|
||||
|
||||
with patch.dict(os.environ, env, clear=False):
|
||||
backend = get_storage_backend(config_path=None)
|
||||
|
||||
assert isinstance(backend, LocalStorageBackend)
|
||||
|
||||
def test_app_config_has_storage_backend(self, tmp_path: Path) -> None:
|
||||
"""Test that AppConfig can be created with storage backend."""
|
||||
from shared.storage.base import StorageBackend
|
||||
|
||||
from inference.web.config import AppConfig, create_app_config
|
||||
|
||||
env = {
|
||||
"STORAGE_BACKEND": "local",
|
||||
"STORAGE_BASE_PATH": str(tmp_path / "storage"),
|
||||
}
|
||||
|
||||
with patch.dict(os.environ, env, clear=False):
|
||||
config = create_app_config()
|
||||
|
||||
assert hasattr(config, "storage_backend")
|
||||
assert isinstance(config.storage_backend, StorageBackend)
|
||||
|
||||
|
||||
class TestStorageBackendInDocumentUpload:
|
||||
"""Tests for storage backend usage in document upload."""
|
||||
|
||||
def test_upload_document_uses_storage_backend(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document upload uses storage backend."""
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create a mock upload file
|
||||
pdf_content = b"%PDF-1.4 test content"
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
# Upload should use storage backend
|
||||
result = service.upload_document(
|
||||
content=pdf_content,
|
||||
filename="test.pdf",
|
||||
dataset_id="dataset-1",
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
# Verify file was stored via storage backend
|
||||
assert backend.exists(f"documents/{result.id}.pdf")
|
||||
|
||||
def test_upload_document_stores_logical_path(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document stores logical path, not absolute path."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
pdf_content = b"%PDF-1.4 test content"
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
result = service.upload_document(
|
||||
content=pdf_content,
|
||||
filename="test.pdf",
|
||||
dataset_id="dataset-1",
|
||||
)
|
||||
|
||||
# Path should be logical (relative), not absolute
|
||||
assert not result.file_path.startswith("/")
|
||||
assert not result.file_path.startswith("C:")
|
||||
assert result.file_path.startswith("documents/")
|
||||
|
||||
|
||||
class TestStorageBackendInDocumentDownload:
|
||||
"""Tests for storage backend usage in document download/serving."""
|
||||
|
||||
def test_get_document_url_returns_presigned_url(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document URL uses presigned URL from storage backend."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create a test file
|
||||
doc_path = "documents/test-doc.pdf"
|
||||
backend.upload_bytes(b"%PDF-1.4 test", doc_path)
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
url = service.get_document_url(doc_path)
|
||||
|
||||
# Should return a URL (file:// for local, https:// for cloud)
|
||||
assert url is not None
|
||||
assert "test-doc.pdf" in url
|
||||
|
||||
def test_download_document_uses_storage_backend(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document download uses storage backend."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create a test file
|
||||
doc_path = "documents/test-doc.pdf"
|
||||
original_content = b"%PDF-1.4 test content"
|
||||
backend.upload_bytes(original_content, doc_path)
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
content = service.download_document(doc_path)
|
||||
|
||||
assert content == original_content
|
||||
|
||||
|
||||
class TestStorageBackendInImageServing:
|
||||
"""Tests for storage backend usage in image serving."""
|
||||
|
||||
def test_get_page_image_url_returns_presigned_url(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that page image URL uses presigned URL."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create a test image
|
||||
image_path = "images/doc-123/page_1.png"
|
||||
backend.upload_bytes(b"fake png content", image_path)
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
url = service.get_page_image_url("doc-123", 1)
|
||||
|
||||
assert url is not None
|
||||
assert "page_1.png" in url
|
||||
|
||||
def test_save_page_image_uses_storage_backend(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that page image saving uses storage backend."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
image_content = b"fake png content"
|
||||
service.save_page_image("doc-123", 1, image_content)
|
||||
|
||||
# Verify image was stored
|
||||
assert backend.exists("images/doc-123/page_1.png")
|
||||
|
||||
|
||||
class TestStorageBackendInDocumentDeletion:
|
||||
"""Tests for storage backend usage in document deletion."""
|
||||
|
||||
def test_delete_document_removes_from_storage(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document deletion removes file from storage."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create test files
|
||||
doc_path = "documents/test-doc.pdf"
|
||||
backend.upload_bytes(b"%PDF-1.4 test", doc_path)
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
service.delete_document_files(doc_path)
|
||||
|
||||
assert not backend.exists(doc_path)
|
||||
|
||||
def test_delete_document_removes_images(
|
||||
self, tmp_path: Path, mock_admin_db: MagicMock
|
||||
) -> None:
|
||||
"""Test that document deletion removes associated images."""
|
||||
from shared.storage.local import LocalStorageBackend
|
||||
|
||||
storage_path = tmp_path / "storage"
|
||||
storage_path.mkdir(parents=True, exist_ok=True)
|
||||
backend = LocalStorageBackend(str(storage_path))
|
||||
|
||||
# Create test files
|
||||
doc_id = "test-doc-123"
|
||||
backend.upload_bytes(b"img1", f"images/{doc_id}/page_1.png")
|
||||
backend.upload_bytes(b"img2", f"images/{doc_id}/page_2.png")
|
||||
|
||||
from inference.web.services.document_service import DocumentService
|
||||
|
||||
service = DocumentService(admin_db=mock_admin_db, storage_backend=backend)
|
||||
|
||||
service.delete_document_images(doc_id)
|
||||
|
||||
assert not backend.exists(f"images/{doc_id}/page_1.png")
|
||||
assert not backend.exists(f"images/{doc_id}/page_2.png")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_admin_db() -> MagicMock:
|
||||
"""Create a mock AdminDB for testing."""
|
||||
mock = MagicMock()
|
||||
mock.get_document.return_value = None
|
||||
mock.create_document.return_value = MagicMock(
|
||||
id="test-doc-id",
|
||||
file_path="documents/test-doc-id.pdf",
|
||||
)
|
||||
return mock
|
||||
Reference in New Issue
Block a user