106 lines
2.9 KiB
Python
106 lines
2.9 KiB
Python
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import sys
|
||
from typing import AsyncGenerator
|
||
from uuid import uuid4
|
||
|
||
import pytest
|
||
import pytest_asyncio
|
||
from dotenv import load_dotenv
|
||
from httpx import ASGITransport, AsyncClient
|
||
from sqlalchemy import text
|
||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||
|
||
from dataloader.api import app_main
|
||
from dataloader.config import APP_CONFIG
|
||
from dataloader.context import get_session
|
||
from dataloader.storage.engine import create_engine
|
||
|
||
load_dotenv()
|
||
|
||
if sys.platform == "win32":
|
||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||
|
||
pytestmark = pytest.mark.asyncio
|
||
|
||
|
||
@pytest_asyncio.fixture(scope="function")
|
||
async def db_engine() -> AsyncGenerator[AsyncEngine, None]:
|
||
"""
|
||
Создаёт тестовый движок для теста.
|
||
Использует реальную БД из конфига.
|
||
"""
|
||
engine = create_engine(APP_CONFIG.pg.url)
|
||
|
||
yield engine
|
||
|
||
await engine.dispose()
|
||
|
||
|
||
@pytest_asyncio.fixture(scope="function")
|
||
async def db_session(db_engine: AsyncEngine) -> AsyncGenerator[AsyncSession, None]:
|
||
"""
|
||
Предоставляет сессию БД для каждого теста.
|
||
НЕ использует транзакцию, чтобы работали advisory locks.
|
||
"""
|
||
sessionmaker = async_sessionmaker(
|
||
bind=db_engine, expire_on_commit=False, class_=AsyncSession
|
||
)
|
||
async with sessionmaker() as session:
|
||
yield session
|
||
await session.rollback()
|
||
|
||
|
||
@pytest_asyncio.fixture(scope="function")
|
||
async def clean_queue_tables(db_session: AsyncSession) -> None:
|
||
"""
|
||
Очищает таблицы очереди перед каждым тестом.
|
||
"""
|
||
schema = APP_CONFIG.pg.schema_queue
|
||
await db_session.execute(text(f"TRUNCATE TABLE {schema}.dl_job_events CASCADE"))
|
||
await db_session.execute(text(f"TRUNCATE TABLE {schema}.dl_jobs CASCADE"))
|
||
await db_session.commit()
|
||
|
||
|
||
@pytest_asyncio.fixture
|
||
async def client(db_session: AsyncSession) -> AsyncGenerator[AsyncClient, None]:
|
||
"""
|
||
HTTP клиент для тестирования API.
|
||
"""
|
||
|
||
async def override_get_session() -> AsyncGenerator[AsyncSession, None]:
|
||
yield db_session
|
||
|
||
app_main.dependency_overrides[get_session] = override_get_session
|
||
|
||
transport = ASGITransport(app=app_main)
|
||
async with AsyncClient(transport=transport, base_url="http://test") as c:
|
||
yield c
|
||
|
||
app_main.dependency_overrides.clear()
|
||
|
||
|
||
@pytest.fixture
|
||
def job_id() -> str:
|
||
"""
|
||
Генерирует уникальный job_id для тестов.
|
||
"""
|
||
return str(uuid4())
|
||
|
||
|
||
@pytest.fixture
|
||
def queue_name() -> str:
|
||
"""
|
||
Возвращает имя тестовой очереди.
|
||
"""
|
||
return "test.queue"
|
||
|
||
|
||
@pytest.fixture
|
||
def task_name() -> str:
|
||
"""
|
||
Возвращает имя тестовой задачи.
|
||
"""
|
||
return "test.task"
|