feature/e2e #4

Merged
to merged 22 commits from feature/e2e into dev 2025-08-20 17:21:31 +00:00
144 changed files with 7464 additions and 3793 deletions
Showing only changes of commit b92594d6a7 - Show all commits

View File

@@ -50,7 +50,7 @@ dependencies = [
# https://docs.astral.sh/uv/concepts/dependencies/#development-dependencies
[dependency-groups]
dev = [
"fakeredis",
"fakeredis[aioredis]",
"pytest",
"pytest-asyncio",
"pytest-cov",
@@ -61,7 +61,7 @@ dev = [
]
test = [
"fakeredis",
"fakeredis[aioredis]",
"pytest",
"pytest-asyncio",
"pytest-cov",

View File

@@ -9,10 +9,46 @@ import requests
import subprocess
from typing import Optional
from unittest.mock import patch
import importlib
from orm.base import BaseModel as Base
def force_create_all_tables(engine):
"""
Принудительно создает все таблицы, перезагружая модели если нужно.
Это помогает в CI среде где могут быть проблемы с метаданными.
"""
from sqlalchemy import inspect
import orm
# Перезагружаем все модули ORM для гарантии актуальности метаданных
importlib.reload(orm.base)
importlib.reload(orm.community)
importlib.reload(orm.author)
importlib.reload(orm.draft)
importlib.reload(orm.shout)
importlib.reload(orm.topic)
importlib.reload(orm.reaction)
importlib.reload(orm.invite)
importlib.reload(orm.notification)
importlib.reload(orm.collection)
importlib.reload(orm.rating)
# Получаем обновленную Base
from orm.base import BaseModel as Base
# Создаем все таблицы
Base.metadata.create_all(engine)
# Проверяем результат
inspector = inspect(engine)
created_tables = inspector.get_table_names()
print(f"🔧 Force created tables: {created_tables}")
return created_tables
def get_test_client():
"""
Создает и возвращает тестовый клиент для интеграционных тестов.
@@ -54,10 +90,24 @@ def test_engine():
Создает тестовый engine для всей сессии тестирования.
Использует in-memory SQLite для быстрых тестов.
"""
# Импортируем все модели, чтобы они были зарегистрированы
# Принудительно импортируем ВСЕ модели чтобы они были зарегистрированы в Base.metadata
# Это критично для CI среды где импорты могут работать по-разному
import orm.base
import orm.community
import orm.author
import orm.draft
import orm.shout
import orm.topic
import orm.reaction
import orm.invite
import orm.notification
import orm.collection
import orm.rating
# Явно импортируем классы для гарантии регистрации
from orm.base import BaseModel as Base
from orm.community import Community, CommunityAuthor
from orm.author import Author
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
@@ -65,7 +115,6 @@ def test_engine():
from orm.invite import Invite
from orm.notification import Notification
from orm.collection import Collection
from orm.author import AuthorFollower, AuthorRating
# Инициализируем RBAC систему
import rbac
@@ -89,8 +138,8 @@ def test_engine():
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',
'shout', 'shout_author', 'shout_topic', 'shout_reactions_followers', 'shout_collection',
'topic', 'topic_followers', 'reaction', 'invite', 'notification', 'notification_seen',
'collection', 'author_follower', 'author_rating', 'author_bookmark'
]
@@ -113,7 +162,60 @@ def test_engine():
if still_missing:
print(f"❌ Still missing tables after explicit creation: {still_missing}")
raise RuntimeError(f"Failed to create required tables: {still_missing}")
# Последняя попытка: создаем таблицы по одной
print("🔄 Last attempt: creating tables one by one...")
for table_name in still_missing:
try:
if table_name == 'community_author':
CommunityAuthor.__table__.create(engine, checkfirst=True)
elif table_name == 'community_follower':
CommunityFollower.__table__.create(engine, checkfirst=True)
elif table_name == 'author_follower':
AuthorFollower.__table__.create(engine, checkfirst=True)
elif table_name == 'author_rating':
AuthorRating.__table__.create(engine, checkfirst=True)
elif table_name == 'author_bookmark':
AuthorBookmark.__table__.create(engine, checkfirst=True)
elif table_name == 'draft_author':
DraftAuthor.__table__.create(engine, checkfirst=True)
elif table_name == 'draft_topic':
DraftTopic.__table__.create(engine, checkfirst=True)
elif table_name == 'shout_author':
ShoutAuthor.__table__.create(engine, checkfirst=True)
elif table_name == 'shout_topic':
ShoutTopic.__table__.create(engine, checkfirst=True)
elif table_name == 'shout_reactions_followers':
ShoutReactionsFollower.__table__.create(engine, checkfirst=True)
elif table_name == 'collection':
Collection.__table__.create(engine, checkfirst=True)
elif table_name == 'topic_followers':
TopicFollower.__table__.create(engine, checkfirst=True)
elif table_name == 'notification_seen':
# notification_seen может быть частью notification модели
pass
print(f"✅ Created table {table_name}")
except Exception as e:
print(f"❌ Failed to create table {table_name}: {e}")
# Финальная проверка
inspector = inspect(engine)
final_tables = inspector.get_table_names()
final_missing = [table for table in required_tables if table not in final_tables]
if final_missing:
print(f"❌ Still missing tables after individual creation: {final_missing}")
print("🔄 Last resort: forcing table creation with module reload...")
try:
final_tables = force_create_all_tables(engine)
final_missing = [table for table in required_tables if table not in final_tables]
if final_missing:
raise RuntimeError(f"Failed to create required tables after all attempts: {final_missing}")
else:
print("✅ All missing tables created successfully with force creation")
except Exception as e:
print(f"❌ Force creation failed: {e}")
raise RuntimeError(f"Failed to create required tables after all attempts: {final_missing}")
else:
print("✅ All missing tables created successfully in test_engine")
else:
print("✅ All missing tables created successfully in test_engine")
except Exception as e:

4
uv.lock generated
View File

@@ -479,7 +479,7 @@ requires-dist = [
[package.metadata.requires-dev]
dev = [
{ name = "fakeredis" },
{ name = "fakeredis", extras = ["aioredis"] },
{ name = "mypy" },
{ name = "playwright" },
{ name = "pytest" },
@@ -493,7 +493,7 @@ lint = [
{ name = "ruff" },
]
test = [
{ name = "fakeredis" },
{ name = "fakeredis", extras = ["aioredis"] },
{ name = "playwright" },
{ name = "pytest" },
{ name = "pytest-asyncio" },