246 lines
8.3 KiB
Python
246 lines
8.3 KiB
Python
import pytest
|
||
from sqlalchemy import create_engine
|
||
from sqlalchemy.orm import sessionmaker
|
||
from sqlalchemy.pool import StaticPool
|
||
|
||
from services.db import Base
|
||
from services.redis import redis
|
||
from tests.test_config import get_test_client
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def test_engine():
|
||
"""
|
||
Создает тестовый engine для всей сессии тестирования.
|
||
Использует in-memory SQLite для быстрых тестов.
|
||
"""
|
||
engine = create_engine(
|
||
"sqlite:///:memory:", echo=False, poolclass=StaticPool, connect_args={"check_same_thread": False}
|
||
)
|
||
|
||
# Создаем все таблицы
|
||
Base.metadata.create_all(engine)
|
||
|
||
yield engine
|
||
|
||
# Cleanup после всех тестов
|
||
Base.metadata.drop_all(engine)
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def test_session_factory(test_engine):
|
||
"""
|
||
Создает фабрику сессий для тестирования.
|
||
"""
|
||
return sessionmaker(bind=test_engine, expire_on_commit=False)
|
||
|
||
|
||
@pytest.fixture
|
||
def db_session(test_session_factory):
|
||
"""
|
||
Создает новую сессию БД для каждого теста.
|
||
Простая реализация без вложенных транзакций.
|
||
"""
|
||
session = test_session_factory()
|
||
|
||
# Создаем дефолтное сообщество для тестов
|
||
from orm.community import Community
|
||
from auth.orm import Author
|
||
import time
|
||
|
||
# Создаем системного автора если его нет
|
||
system_author = session.query(Author).filter(Author.slug == "system").first()
|
||
if not system_author:
|
||
system_author = Author(
|
||
name="System",
|
||
slug="system",
|
||
email="system@test.local",
|
||
created_at=int(time.time()),
|
||
updated_at=int(time.time()),
|
||
last_seen=int(time.time())
|
||
)
|
||
session.add(system_author)
|
||
session.flush()
|
||
|
||
# Создаем дефолтное сообщество если его нет
|
||
default_community = session.query(Community).filter(Community.id == 1).first()
|
||
if not default_community:
|
||
default_community = Community(
|
||
id=1,
|
||
name="Главное сообщество",
|
||
slug="main",
|
||
desc="Основное сообщество для тестов",
|
||
pic="",
|
||
created_at=int(time.time()),
|
||
created_by=system_author.id,
|
||
settings={"default_roles": ["reader", "author"], "available_roles": ["reader", "author", "artist", "expert", "editor", "admin"]},
|
||
private=False
|
||
)
|
||
session.add(default_community)
|
||
session.commit()
|
||
|
||
yield session
|
||
|
||
# Очищаем все данные после теста
|
||
try:
|
||
for table in reversed(Base.metadata.sorted_tables):
|
||
session.execute(table.delete())
|
||
session.commit()
|
||
except Exception:
|
||
session.rollback()
|
||
finally:
|
||
session.close()
|
||
|
||
|
||
@pytest.fixture
|
||
def db_session_commit(test_session_factory):
|
||
"""
|
||
Создает сессию БД с реальными commit'ами для интеграционных тестов.
|
||
Используется когда нужно тестировать реальные транзакции.
|
||
"""
|
||
session = test_session_factory()
|
||
|
||
# Создаем дефолтное сообщество для интеграционных тестов
|
||
from orm.community import Community
|
||
from auth.orm import Author
|
||
import time
|
||
|
||
# Создаем системного автора если его нет
|
||
system_author = session.query(Author).filter(Author.slug == "system").first()
|
||
if not system_author:
|
||
system_author = Author(
|
||
name="System",
|
||
slug="system",
|
||
email="system@test.local",
|
||
created_at=int(time.time()),
|
||
updated_at=int(time.time()),
|
||
last_seen=int(time.time())
|
||
)
|
||
session.add(system_author)
|
||
session.flush()
|
||
|
||
# Создаем дефолтное сообщество если его нет
|
||
default_community = session.query(Community).filter(Community.id == 1).first()
|
||
if not default_community:
|
||
default_community = Community(
|
||
id=1,
|
||
name="Главное сообщество",
|
||
slug="main",
|
||
desc="Основное сообщество для тестов",
|
||
pic="",
|
||
created_at=int(time.time()),
|
||
created_by=system_author.id,
|
||
settings={"default_roles": ["reader", "author"], "available_roles": ["reader", "author", "artist", "expert", "editor", "admin"]},
|
||
private=False
|
||
)
|
||
session.add(default_community)
|
||
session.commit()
|
||
|
||
yield session
|
||
|
||
# Очищаем все данные после теста
|
||
try:
|
||
for table in reversed(Base.metadata.sorted_tables):
|
||
session.execute(table.delete())
|
||
session.commit()
|
||
except Exception:
|
||
session.rollback()
|
||
finally:
|
||
session.close()
|
||
|
||
|
||
@pytest.fixture(scope="session")
|
||
def test_app():
|
||
"""Create a test client and session factory."""
|
||
client, session_local = get_test_client()
|
||
return client, session_local
|
||
|
||
|
||
@pytest.fixture
|
||
def test_client(test_app):
|
||
"""Get the test client."""
|
||
client, _ = test_app
|
||
return client
|
||
|
||
|
||
@pytest.fixture
|
||
async def redis_client():
|
||
"""Create a test Redis client."""
|
||
try:
|
||
await redis.connect()
|
||
await redis.execute("FLUSHALL") # Очищаем Redis перед каждым тестом
|
||
yield redis
|
||
await redis.execute("FLUSHALL") # Очищаем после теста
|
||
finally:
|
||
try:
|
||
await redis.disconnect()
|
||
except Exception:
|
||
pass
|
||
|
||
|
||
@pytest.fixture
|
||
def oauth_db_session(test_session_factory):
|
||
"""
|
||
Fixture для dependency injection OAuth модуля с тестовой БД.
|
||
Настраивает OAuth модуль на использование тестовой сессии.
|
||
"""
|
||
# Импортируем OAuth модуль и настраиваем dependency injection
|
||
from auth import oauth
|
||
|
||
# Сохраняем оригинальную фабрику через SessionManager
|
||
original_factory = oauth.session_manager._factory
|
||
|
||
# Устанавливаем тестовую фабрику
|
||
oauth.set_session_factory(lambda: test_session_factory())
|
||
|
||
session = test_session_factory()
|
||
|
||
# Создаем дефолтное сообщество для OAuth тестов
|
||
from orm.community import Community
|
||
from auth.orm import Author
|
||
import time
|
||
|
||
# Создаем системного автора если его нет
|
||
system_author = session.query(Author).filter(Author.slug == "system").first()
|
||
if not system_author:
|
||
system_author = Author(
|
||
name="System",
|
||
slug="system",
|
||
email="system@test.local",
|
||
created_at=int(time.time()),
|
||
updated_at=int(time.time()),
|
||
last_seen=int(time.time())
|
||
)
|
||
session.add(system_author)
|
||
session.flush()
|
||
|
||
# Создаем дефолтное сообщество если его нет
|
||
default_community = session.query(Community).filter(Community.id == 1).first()
|
||
if not default_community:
|
||
default_community = Community(
|
||
id=1,
|
||
name="Главное сообщество",
|
||
slug="main",
|
||
desc="Основное сообщество для OAuth тестов",
|
||
pic="",
|
||
created_at=int(time.time()),
|
||
created_by=system_author.id,
|
||
settings={"default_roles": ["reader", "author"], "available_roles": ["reader", "author", "artist", "expert", "editor", "admin"]},
|
||
private=False
|
||
)
|
||
session.add(default_community)
|
||
session.commit()
|
||
|
||
yield session
|
||
|
||
# Очищаем данные и восстанавливаем оригинальную фабрику
|
||
try:
|
||
for table in reversed(Base.metadata.sorted_tables):
|
||
session.execute(table.delete())
|
||
session.commit()
|
||
except Exception:
|
||
session.rollback()
|
||
finally:
|
||
session.close()
|
||
oauth.session_manager.set_factory(original_factory)
|