"""Фикстуры тестов: in-memory БД и авторизация-заглушка."""
import os
import tempfile
from collections.abc import Iterator
from typing import Any
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker
from sqlalchemy.pool import StaticPool
from app import services
from app.db import Base
from app.dependencies import get_db, require_user
from app.main import app
detailing = services.detailing
TEST_DB_URL = "sqlite://"
_engine = create_engine(
TEST_DB_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
Base.metadata.create_all(_engine)
_test_session_factory = sessionmaker(bind=_engine, expire_on_commit=False)
def _override_get_db() -> Iterator[Session]:
session = _test_session_factory()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
app.dependency_overrides[get_db] = _override_get_db
AUTH_USER: dict[str, str] = {"user_id": "1", "email": "test@example.com"}
app.dependency_overrides[require_user] = lambda: AUTH_USER
# Вложения в тестах — во временный каталог
_tmpdir = tempfile.mkdtemp(prefix="gntodo-att-")
os.environ.setdefault("ATTACHMENTS_PATH", _tmpdir)
@pytest.fixture(autouse=True)
def _mock_detailing(monkeypatch: Any) -> Iterator[None]:
"""Фоновая детализация в тестах: тестовая БД и без реального вызова Ollama."""
monkeypatch.setattr(detailing, "get_session_factory", lambda: _test_session_factory)
# Запрещаем сетевой вызов LLM: propose вернёт None (как при недоступной Ollama).
# Тесты при необходимости подменяют propose/generate поверх этого.
monkeypatch.setattr(
detailing.DetailingService,
"generate",
lambda self, prompt: (_ for _ in ()).throw(RuntimeError("LLM отключён в тестах")),
)
@pytest.fixture(autouse=True)
def _isolate_db() -> Iterator[None]:
"""Чистые таблицы перед каждым тестом (in-memory БД общая на процесс)."""
conn = _engine.connect()
trans = conn.begin()
for table in reversed(Base.metadata.sorted_tables):
conn.execute(table.delete())
trans.commit()
conn.close()
yield
@pytest.fixture
def client() -> Iterator[TestClient]:
with TestClient(app) as c:
yield c