Files
invoice-master-poc-v2/tests/web/test_storage_integration.py
Yaojia Wang a516de4320 WIP
2026-02-01 00:08:40 +01:00

307 lines
10 KiB
Python

"""
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