feature/e2e #4
@@ -65,7 +65,6 @@ def test_engine():
|
||||
from orm.invite import Invite
|
||||
from orm.notification import Notification
|
||||
from orm.collection import Collection
|
||||
from orm.shout import ShoutReactionsFollower
|
||||
from orm.author import AuthorFollower, AuthorRating
|
||||
|
||||
# Инициализируем RBAC систему
|
||||
@@ -79,6 +78,49 @@ def test_engine():
|
||||
# Принудительно удаляем все таблицы и создаем заново
|
||||
Base.metadata.drop_all(engine)
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
# Debug: проверяем какие таблицы созданы на уровне сессии
|
||||
from sqlalchemy import inspect
|
||||
inspector = inspect(engine)
|
||||
session_tables = inspector.get_table_names()
|
||||
print(f"🔍 Created tables in test_engine fixture: {session_tables}")
|
||||
|
||||
# Проверяем что все критические таблицы созданы
|
||||
required_tables = [
|
||||
'author', 'community', 'community_author', 'community_follower',
|
||||
'draft', 'draft_author', 'draft_topic',
|
||||
'shout', 'shout_author', 'shout_topic', 'shout_reactions_followers',
|
||||
'topic', 'topic_followers', 'reaction', 'invite', 'notification',
|
||||
'collection', 'author_follower', 'author_rating', 'author_bookmark'
|
||||
]
|
||||
|
||||
missing_tables = [table for table in required_tables if table not in session_tables]
|
||||
|
||||
if missing_tables:
|
||||
print(f"❌ Missing tables in test_engine: {missing_tables}")
|
||||
print(f"Available tables: {session_tables}")
|
||||
|
||||
# Fallback: попробуем создать отсутствующие таблицы явно
|
||||
print("🔄 Attempting to create missing tables explicitly in test_engine...")
|
||||
try:
|
||||
# Создаем все таблицы снова с принудительным импортом моделей
|
||||
Base.metadata.create_all(engine)
|
||||
|
||||
# Проверяем снова
|
||||
inspector = inspect(engine)
|
||||
updated_tables = inspector.get_table_names()
|
||||
still_missing = [table for table in required_tables if table not in updated_tables]
|
||||
|
||||
if still_missing:
|
||||
print(f"❌ Still missing tables after explicit creation: {still_missing}")
|
||||
raise RuntimeError(f"Failed to create required tables: {still_missing}")
|
||||
else:
|
||||
print("✅ All missing tables created successfully in test_engine")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to create missing tables in test_engine: {e}")
|
||||
raise
|
||||
else:
|
||||
print("✅ All required tables created in test_engine")
|
||||
|
||||
yield engine
|
||||
|
||||
@@ -103,12 +145,87 @@ def db_session(test_session_factory, test_engine):
|
||||
# Принудительно пересоздаем таблицы для каждого теста
|
||||
from orm.base import BaseModel as Base
|
||||
from sqlalchemy import inspect
|
||||
|
||||
# Убеждаемся что все модели импортированы перед созданием таблиц
|
||||
# Явно импортируем все модели чтобы они были зарегистрированы в Base.metadata
|
||||
from orm.community import Community, CommunityAuthor, CommunityFollower
|
||||
from orm.author import Author, AuthorFollower, AuthorRating, AuthorBookmark
|
||||
from orm.draft import Draft, DraftAuthor, DraftTopic
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic, ShoutReactionsFollower
|
||||
from orm.topic import Topic, TopicFollower
|
||||
from orm.reaction import Reaction
|
||||
from orm.invite import Invite
|
||||
from orm.notification import Notification
|
||||
from orm.collection import Collection
|
||||
|
||||
# Проверяем что все модели зарегистрированы
|
||||
print(f"🔍 Registered tables in Base.metadata: {list(Base.metadata.tables.keys())}")
|
||||
|
||||
# Убеждаемся что все критические таблицы зарегистрированы в metadata
|
||||
required_tables = [
|
||||
'author', 'community', 'community_author', 'community_follower',
|
||||
'draft', 'draft_author', 'draft_topic',
|
||||
'shout', 'shout_author', 'shout_topic', 'shout_reactions_followers',
|
||||
'topic', 'topic_followers', 'reaction', 'invite', 'notification',
|
||||
'collection', 'author_follower', 'author_rating', 'author_bookmark'
|
||||
]
|
||||
|
||||
missing_metadata_tables = [table for table in required_tables if table not in Base.metadata.tables]
|
||||
|
||||
if missing_metadata_tables:
|
||||
print(f"❌ Missing tables in Base.metadata: {missing_metadata_tables}")
|
||||
print("Available tables:", list(Base.metadata.tables.keys()))
|
||||
raise RuntimeError(f"Critical tables not registered in Base.metadata: {missing_metadata_tables}")
|
||||
else:
|
||||
print("✅ All required tables registered in Base.metadata")
|
||||
|
||||
# Удаляем все таблицы
|
||||
Base.metadata.drop_all(test_engine)
|
||||
|
||||
# Создаем таблицы заново
|
||||
Base.metadata.create_all(test_engine)
|
||||
|
||||
# Debug: проверяем какие таблицы созданы
|
||||
inspector = inspect(test_engine)
|
||||
created_tables = inspector.get_table_names()
|
||||
print(f"🔍 Created tables in db_session fixture: {created_tables}")
|
||||
|
||||
# Проверяем что все критические таблицы созданы
|
||||
required_tables = [
|
||||
'author', 'community', 'community_author', 'community_follower',
|
||||
'draft', 'draft_author', 'draft_topic',
|
||||
'shout', 'shout_author', 'shout_topic', 'shout_reactions_followers',
|
||||
'topic', 'topic_followers', 'reaction', 'invite', 'notification',
|
||||
'collection', 'author_follower', 'author_rating', 'author_bookmark'
|
||||
]
|
||||
|
||||
missing_tables = [table for table in required_tables if table not in created_tables]
|
||||
|
||||
if missing_tables:
|
||||
print(f"❌ Missing tables in db_session: {missing_tables}")
|
||||
print(f"Available tables: {created_tables}")
|
||||
|
||||
# Fallback: попробуем создать отсутствующие таблицы явно
|
||||
print("🔄 Attempting to create missing tables explicitly in db_session...")
|
||||
try:
|
||||
# Создаем все таблицы снова с принудительным импортом моделей
|
||||
Base.metadata.create_all(test_engine)
|
||||
|
||||
# Проверяем снова
|
||||
inspector = inspect(test_engine)
|
||||
updated_tables = inspector.get_table_names()
|
||||
still_missing = [table for table in required_tables if table not in updated_tables]
|
||||
|
||||
if still_missing:
|
||||
print(f"❌ Still missing tables after explicit creation: {still_missing}")
|
||||
raise RuntimeError(f"Failed to create required tables: {still_missing}")
|
||||
else:
|
||||
print("✅ All missing tables created successfully in db_session")
|
||||
except Exception as e:
|
||||
print(f"❌ Failed to create missing tables in db_session: {e}")
|
||||
raise
|
||||
else:
|
||||
print("✅ All required tables created in db_session")
|
||||
|
||||
# Проверяем что таблица draft создана с правильной схемой
|
||||
inspector = inspect(test_engine)
|
||||
@@ -582,18 +699,27 @@ def redis_client():
|
||||
return redis_service._client
|
||||
|
||||
|
||||
# Mock для Redis если он недоступен
|
||||
@pytest.fixture
|
||||
def mock_redis_if_unavailable():
|
||||
"""Мокает Redis если он недоступен - для тестов которые нуждаются в Redis"""
|
||||
def fake_redis():
|
||||
"""Создает fakeredis экземпляр для тестов"""
|
||||
try:
|
||||
import fakeredis.aioredis
|
||||
# Используем fakeredis для тестов
|
||||
with patch('storage.redis.redis') as mock_redis:
|
||||
# Создаем fakeredis сервер
|
||||
fake_redis = fakeredis.aioredis.FakeRedis()
|
||||
return fakeredis.aioredis.FakeRedis()
|
||||
except ImportError:
|
||||
pytest.skip("fakeredis не установлен - установите: pip install fakeredis[aioredis]")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def redis_service_mock(fake_redis):
|
||||
"""Создает мок RedisService с fakeredis"""
|
||||
try:
|
||||
import fakeredis.aioredis
|
||||
|
||||
with patch('storage.redis.RedisService') as mock_service:
|
||||
# Создаем экземпляр с fakeredis
|
||||
mock_service.return_value._client = fake_redis
|
||||
|
||||
# Создаем mock для execute метода, который эмулирует поведение RedisService.execute
|
||||
# Эмулируем execute метод
|
||||
async def mock_execute(command: str, *args):
|
||||
cmd_method = getattr(fake_redis, command.lower(), None)
|
||||
if cmd_method is not None:
|
||||
@@ -603,16 +729,66 @@ def mock_redis_if_unavailable():
|
||||
return cmd_method
|
||||
return None
|
||||
|
||||
# Патчим методы Redis
|
||||
mock_service.return_value.execute = mock_execute
|
||||
mock_service.return_value.get = fake_redis.get
|
||||
mock_service.return_value.set = fake_redis.set
|
||||
mock_service.return_value.delete = fake_redis.delete
|
||||
mock_service.return_value.exists = fake_redis.exists
|
||||
mock_service.return_value.hset = fake_redis.hset
|
||||
mock_service.return_value.hget = fake_redis.hget
|
||||
mock_service.return_value.hgetall = fake_redis.hgetall
|
||||
mock_service.return_value.hdel = fake_redis.hdel
|
||||
mock_service.return_value.expire = fake_redis.expire
|
||||
mock_service.return_value.ttl = fake_redis.ttl
|
||||
mock_service.return_value.keys = fake_redis.keys
|
||||
mock_service.return_value.scan = fake_redis.scan
|
||||
|
||||
yield mock_service.return_value
|
||||
|
||||
except ImportError:
|
||||
pytest.skip("fakeredis не установлен - установите: pip install fakeredis[aioredis]")
|
||||
|
||||
|
||||
# Используем fakeredis для тестов Redis
|
||||
@pytest.fixture
|
||||
def mock_redis_if_unavailable():
|
||||
"""Заменяет Redis на fakeredis для тестов - более реалистичная имитация Redis"""
|
||||
try:
|
||||
import fakeredis.aioredis
|
||||
|
||||
# Создаем fakeredis сервер
|
||||
fake_redis = fakeredis.aioredis.FakeRedis()
|
||||
|
||||
# Патчим глобальный redis экземпляр
|
||||
with patch('storage.redis.redis') as mock_redis:
|
||||
# Эмулируем RedisService.execute метод
|
||||
async def mock_execute(command: str, *args):
|
||||
cmd_method = getattr(fake_redis, command.lower(), None)
|
||||
if cmd_method is not None:
|
||||
if hasattr(cmd_method, '__call__'):
|
||||
return await cmd_method(*args)
|
||||
else:
|
||||
return cmd_method
|
||||
return None
|
||||
|
||||
# Патчим все основные методы Redis
|
||||
mock_redis.execute = mock_execute
|
||||
mock_redis.get = fake_redis.get
|
||||
mock_redis.set = fake_redis.set
|
||||
mock_redis.delete = fake_redis.delete
|
||||
mock_redis.exists = fake_redis.exists
|
||||
mock_redis.ping = fake_redis.ping
|
||||
mock_redis.hset = fake_redis.hset
|
||||
mock_redis.hget = fake_redis.hget
|
||||
mock_redis.hgetall = fake_redis.hgetall
|
||||
mock_redis.hdel = fake_redis.hdel
|
||||
mock_redis.expire = fake_redis.expire
|
||||
mock_redis.ttl = fake_redis.ttl
|
||||
mock_redis.keys = fake_redis.keys
|
||||
mock_redis.scan = fake_redis.scan
|
||||
mock_redis.is_connected = True
|
||||
|
||||
# Добавляем async методы для connect/disconnect
|
||||
# Async методы для connect/disconnect
|
||||
async def mock_connect():
|
||||
return True
|
||||
|
||||
@@ -623,29 +799,9 @@ def mock_redis_if_unavailable():
|
||||
mock_redis.disconnect = mock_disconnect
|
||||
|
||||
yield
|
||||
|
||||
except ImportError:
|
||||
# fakeredis не установлен, используем базовый mock
|
||||
with patch('storage.redis.redis') as mock_redis:
|
||||
# Создаем базовый mock для Redis методов
|
||||
mock_redis.execute.return_value = None
|
||||
mock_redis.get.return_value = None
|
||||
mock_redis.set.return_value = True
|
||||
mock_redis.delete.return_value = True
|
||||
mock_redis.exists.return_value = False
|
||||
mock_redis.ping.return_value = True
|
||||
mock_redis.is_connected = False
|
||||
|
||||
# Добавляем async методы для connect/disconnect
|
||||
async def mock_connect():
|
||||
return True
|
||||
|
||||
async def mock_disconnect():
|
||||
pass
|
||||
|
||||
mock_redis.connect = mock_connect
|
||||
mock_redis.disconnect = mock_disconnect
|
||||
|
||||
yield
|
||||
pytest.skip("fakeredis не установлен - установите: pip install fakeredis[aioredis]")
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
||||
Reference in New Issue
Block a user