Files
kite/backend/tests/conftest.py
T
curo1305 3e4b1f1f91 feat(01-04): rewrite services/storage.py as async SQLAlchemy + MinIO orchestrator
- Replaced entire flat-file + filelock implementation with async ORM + MinIO
- All 14 DB-touching functions are async def accepting AsyncSession as first param
- load_settings/save_settings/mask_api_key/settings_masked remain sync (flat-file, Phase 2 will migrate)
- save_upload uses null-user D-03 sentinel; object_key via MinIO put_object
- update_document_topics auto-creates missing topics via create_topic deduplication
- No filelock, no METADATA_DIR/UPLOADS_DIR/TOPICS_FILE references remain
- Added __all__ listing all 18 public functions
- Updated conftest.py: removed filelock patching no longer needed
- Fixed test_object_key_schema: removed unused db_session param (SQLite INET type conflict)
2026-05-22 09:39:32 +02:00

130 lines
4.2 KiB
Python

"""
pytest configuration: isolate each test with a temporary data directory.
Async fixtures (db_session, async_client) are added for Phase 1 — sync fixtures remain until Plan 05 cuts over.
"""
from __future__ import annotations
import os
import json
import pytest
import pytest_asyncio
import tempfile
import shutil
from pathlib import Path
from fastapi.testclient import TestClient
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.pool import StaticPool
# ── Sync fixtures (legacy — retained until Plan 05 cuts over) ──────────────────
@pytest.fixture(autouse=True)
def isolated_data_dir(monkeypatch, tmp_path):
"""Each test gets its own clean data directory."""
data_dir = tmp_path / "data"
(data_dir / "uploads").mkdir(parents=True)
(data_dir / "metadata").mkdir(parents=True)
(data_dir / "topics.json").write_text(json.dumps({"topics": []}))
from config import DEFAULT_SETTINGS
(data_dir / "settings.json").write_text(json.dumps(DEFAULT_SETTINGS))
monkeypatch.setenv("DATA_DIR", str(data_dir))
# Patch the module-level path constants so the running app sees the temp dir
import config
monkeypatch.setattr(config, "DATA_DIR", data_dir)
monkeypatch.setattr(config, "UPLOADS_DIR", data_dir / "uploads")
monkeypatch.setattr(config, "METADATA_DIR", data_dir / "metadata")
monkeypatch.setattr(config, "TOPICS_FILE", data_dir / "topics.json")
monkeypatch.setattr(config, "SETTINGS_FILE", data_dir / "settings.json")
# Plan 04: services.storage is now async (PostgreSQL + MinIO).
# The flat-file _topics_lock / _settings_lock attributes no longer exist.
# Only SETTINGS_FILE is still used by the sync load_settings/save_settings.
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", data_dir / "settings.json")
yield data_dir
@pytest.fixture
def client(isolated_data_dir):
from main import app
with TestClient(app) as c:
yield c
@pytest.fixture
def sample_txt(tmp_path):
p = tmp_path / "sample.txt"
p.write_text("This is a test document about invoices and finance.")
return p
@pytest.fixture
def sample_pdf(tmp_path):
"""Create a minimal valid PDF for testing."""
import fitz
doc = fitz.open()
page = doc.new_page()
page.insert_text((50, 50), "Test PDF document about contracts and legal matters.")
pdf_path = tmp_path / "sample.pdf"
doc.save(str(pdf_path))
doc.close()
return pdf_path
# ── Async fixtures (Phase 1 additions — Plan 03+ tests use these) ──────────────
@pytest_asyncio.fixture
async def db_session():
"""In-memory async SQLite session for unit tests.
Tries to import db.models.Base (available after Plan 03). If the module
does not yet exist the fixture skips the test gracefully so the suite
stays green during Wave 1.
"""
engine = create_async_engine(
"sqlite+aiosqlite:///:memory:",
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
try:
from db.models import Base
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
except ImportError:
await engine.dispose()
pytest.skip("db.models not yet implemented — plan 03")
AsyncTestSession = async_sessionmaker(engine, expire_on_commit=False)
async with AsyncTestSession() as session:
yield session
await engine.dispose()
@pytest_asyncio.fixture
async def async_client(db_session):
"""Async HTTP test client with DB dependency overridden.
Tries to import deps.db.get_db (available after Plan 03). If the module
does not yet exist the fixture skips the test gracefully.
"""
try:
from deps.db import get_db
from main import app
except ImportError as exc:
pytest.skip(f"deps.db.get_db not yet implemented — plan 03: {exc}")
app.dependency_overrides[get_db] = lambda: db_session
async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
yield c
app.dependency_overrides.clear()