feat(01-04): add StorageBackend ABC + MinIOBackend + factory
- backend/storage/base.py: StorageBackend ABC with 5 abstract methods mirroring ai/base.py
- backend/storage/minio_backend.py: MinIOBackend wrapping all sync Minio SDK calls in asyncio.to_thread(); STORE-02 key schema: {user_id}/{document_id}/{uuid4()}{ext}
- backend/storage/__init__.py: get_storage_backend() factory mirroring ai/__init__.py
- backend/tests/test_storage.py: remove xfail markers (plan 04 implements the module)
This commit is contained in:
@@ -20,7 +20,6 @@ import pytest
|
||||
# Test 1: object key matches STORE-02 regex
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
async def test_object_key_schema(db_session):
|
||||
"""STORE-02: put_object must return a key matching {user_id}/{doc_id}/{uuid4}{ext}."""
|
||||
try:
|
||||
@@ -69,7 +68,6 @@ async def test_object_key_schema(db_session):
|
||||
# Test 2: human filename never in object key
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
async def test_filename_not_in_object_key():
|
||||
"""STORE-02: The human-readable filename must never appear in the MinIO object key."""
|
||||
try:
|
||||
@@ -102,7 +100,6 @@ async def test_filename_not_in_object_key():
|
||||
# Test 3: StorageBackend ABC enforcement
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
def test_storage_backend_abc_methods():
|
||||
"""StorageBackend is abstract — concrete subclass missing all 5 methods raises TypeError."""
|
||||
try:
|
||||
@@ -121,7 +118,6 @@ def test_storage_backend_abc_methods():
|
||||
# Test 4: factory returns MinIOBackend instance
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
def test_get_storage_backend_returns_minio():
|
||||
"""get_storage_backend() factory must return a MinIOBackend instance."""
|
||||
try:
|
||||
@@ -138,7 +134,6 @@ def test_get_storage_backend_returns_minio():
|
||||
# Test 5: put_object wraps sync SDK call in asyncio.to_thread
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
async def test_put_object_uses_asyncio_to_thread(monkeypatch):
|
||||
"""MinIOBackend.put_object must delegate the blocking SDK call via asyncio.to_thread."""
|
||||
try:
|
||||
@@ -182,7 +177,6 @@ async def test_put_object_uses_asyncio_to_thread(monkeypatch):
|
||||
# Test 6: health_check returns bool
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.xfail(strict=False, reason="implemented in plan 04")
|
||||
async def test_minio_backend_health_check_returns_bool():
|
||||
"""MinIOBackend.health_check() returns True when bucket exists, False on exception."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user