This commit is contained in:
@@ -42,6 +42,43 @@ 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
|
||||
|
||||
# Очищаем все данные после теста
|
||||
@@ -63,6 +100,42 @@ def db_session_commit(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
|
||||
|
||||
# Очищаем все данные после теста
|
||||
@@ -121,6 +194,43 @@ def oauth_db_session(test_session_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
|
||||
|
||||
# Очищаем данные и восстанавливаем оригинальную фабрику
|
||||
|
@@ -16,11 +16,7 @@ from auth.orm import ( # noqa: F401
|
||||
Author,
|
||||
AuthorBookmark,
|
||||
AuthorFollower,
|
||||
AuthorRating,
|
||||
AuthorRole,
|
||||
Permission,
|
||||
Role,
|
||||
RolePermission,
|
||||
AuthorRating
|
||||
)
|
||||
from orm.collection import ShoutCollection # noqa: F401
|
||||
from orm.community import Community, CommunityAuthor, CommunityFollower # noqa: F401
|
||||
|
@@ -1,22 +1,13 @@
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author, AuthorRole, Role
|
||||
from auth.orm import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.shout import Shout
|
||||
from resolvers.draft import create_draft, load_drafts
|
||||
|
||||
|
||||
def ensure_test_user_with_roles(db_session):
|
||||
"""Создает тестового пользователя с ID 1 и назначает ему роли"""
|
||||
# Создаем роли если их нет
|
||||
reader_role = db_session.query(Role).filter(Role.id == "reader").first()
|
||||
if not reader_role:
|
||||
reader_role = Role(id="reader", name="Читатель")
|
||||
db_session.add(reader_role)
|
||||
|
||||
author_role = db_session.query(Role).filter(Role.id == "author").first()
|
||||
if not author_role:
|
||||
author_role = Role(id="author", name="Автор")
|
||||
db_session.add(author_role)
|
||||
"""Создает тестового пользователя с ID 1 и назначает ему роли через CommunityAuthor"""
|
||||
|
||||
# Создаем пользователя с ID 1 если его нет
|
||||
test_user = db_session.query(Author).filter(Author.id == 1).first()
|
||||
@@ -26,15 +17,25 @@ def ensure_test_user_with_roles(db_session):
|
||||
db_session.add(test_user)
|
||||
db_session.flush()
|
||||
|
||||
# Удаляем старые роли и добавляем новые
|
||||
db_session.query(AuthorRole).filter(AuthorRole.author == 1).delete()
|
||||
# Удаляем старые роли
|
||||
existing_community_author = (
|
||||
db_session.query(CommunityAuthor)
|
||||
.filter(CommunityAuthor.author_id == test_user.id, CommunityAuthor.community_id == 1)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Добавляем роли
|
||||
for role_id in ["reader", "author"]:
|
||||
author_role_link = AuthorRole(community=1, author=1, role=role_id)
|
||||
db_session.add(author_role_link)
|
||||
if existing_community_author:
|
||||
db_session.delete(existing_community_author)
|
||||
|
||||
# Создаем новую запись с ролями
|
||||
community_author = CommunityAuthor(
|
||||
community_id=1,
|
||||
author_id=test_user.id,
|
||||
roles="reader,author", # CSV строка с ролями
|
||||
)
|
||||
db_session.add(community_author)
|
||||
db_session.commit()
|
||||
|
||||
return test_user
|
||||
|
||||
|
||||
|
497
tests/test_rbac_integration.py
Normal file
497
tests/test_rbac_integration.py
Normal file
@@ -0,0 +1,497 @@
|
||||
"""
|
||||
Тесты интеграции RBAC системы с существующими компонентами проекта.
|
||||
|
||||
Проверяет работу вспомогательных функций из orm/community.py
|
||||
и интеграцию с GraphQL резолверами.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.community import (
|
||||
Community,
|
||||
CommunityAuthor,
|
||||
assign_role_to_user,
|
||||
bulk_assign_roles,
|
||||
check_user_permission_in_community,
|
||||
get_user_roles_in_community,
|
||||
remove_role_from_user,
|
||||
)
|
||||
from services.rbac import get_permissions_for_role
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def integration_users(db_session):
|
||||
"""Создает тестовых пользователей для интеграционных тестов"""
|
||||
users = []
|
||||
|
||||
# Создаем пользователей с ID 100-105 для избежания конфликтов
|
||||
for i in range(100, 106):
|
||||
user = db_session.query(Author).filter(Author.id == i).first()
|
||||
if not user:
|
||||
user = Author(
|
||||
id=i,
|
||||
email=f"integration_user{i}@example.com",
|
||||
name=f"Integration User {i}",
|
||||
slug=f"integration-user-{i}",
|
||||
)
|
||||
user.set_password("password123")
|
||||
db_session.add(user)
|
||||
users.append(user)
|
||||
|
||||
db_session.commit()
|
||||
return users
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def integration_community(db_session, integration_users):
|
||||
"""Создает тестовое сообщество для интеграционных тестов"""
|
||||
community = db_session.query(Community).filter(Community.id == 100).first()
|
||||
if not community:
|
||||
community = Community(
|
||||
id=100,
|
||||
name="Integration Test Community",
|
||||
slug="integration-test-community",
|
||||
desc="Community for integration tests",
|
||||
created_by=integration_users[0].id,
|
||||
)
|
||||
db_session.add(community)
|
||||
db_session.commit()
|
||||
|
||||
return community
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def clean_community_authors(db_session, integration_community):
|
||||
"""Автоматически очищает все записи CommunityAuthor для тестового сообщества перед каждым тестом"""
|
||||
# Очистка перед тестом - используем более агрессивную очистку
|
||||
try:
|
||||
db_session.query(CommunityAuthor).filter(CommunityAuthor.community_id == integration_community.id).delete()
|
||||
db_session.commit()
|
||||
except Exception:
|
||||
db_session.rollback()
|
||||
|
||||
# Дополнительная очистка всех записей для тестовых пользователей
|
||||
try:
|
||||
db_session.query(CommunityAuthor).filter(CommunityAuthor.author_id.in_([100, 101, 102, 103, 104, 105])).delete()
|
||||
db_session.commit()
|
||||
except Exception:
|
||||
db_session.rollback()
|
||||
|
||||
yield # Тест выполняется
|
||||
|
||||
# Очистка после теста
|
||||
try:
|
||||
db_session.query(CommunityAuthor).filter(CommunityAuthor.community_id == integration_community.id).delete()
|
||||
db_session.commit()
|
||||
except Exception:
|
||||
db_session.rollback()
|
||||
|
||||
|
||||
class TestHelperFunctions:
|
||||
"""Тесты для вспомогательных функций RBAC"""
|
||||
|
||||
def test_get_user_roles_in_community(self, db_session, integration_users, integration_community):
|
||||
"""Тест функции получения ролей пользователя в сообществе"""
|
||||
# Назначаем роли через функции вместо прямого создания записи
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "expert", integration_community.id)
|
||||
|
||||
# Проверяем функцию
|
||||
roles = get_user_roles_in_community(integration_users[0].id, integration_community.id)
|
||||
assert "reader" in roles
|
||||
assert "author" in roles
|
||||
assert "expert" in roles
|
||||
|
||||
# Проверяем для пользователя без ролей
|
||||
no_roles = get_user_roles_in_community(integration_users[1].id, integration_community.id)
|
||||
assert no_roles == []
|
||||
|
||||
async def test_check_user_permission_in_community(self, db_session, integration_users, integration_community):
|
||||
"""Тест функции проверки разрешения в сообществе"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "expert", integration_community.id)
|
||||
|
||||
# Проверяем разрешения
|
||||
assert (
|
||||
await check_user_permission_in_community(integration_users[0].id, "shout:create", integration_community.id)
|
||||
is True
|
||||
)
|
||||
|
||||
assert (
|
||||
await check_user_permission_in_community(integration_users[0].id, "shout:read", integration_community.id) is True
|
||||
)
|
||||
|
||||
# Проверяем для пользователя без ролей
|
||||
# Сначала проверим какие роли у пользователя
|
||||
user_roles = get_user_roles_in_community(integration_users[1].id, integration_community.id)
|
||||
print(f"[DEBUG] User {integration_users[1].id} roles: {user_roles}")
|
||||
|
||||
result = await check_user_permission_in_community(integration_users[1].id, "shout:create", integration_community.id)
|
||||
print(f"[DEBUG] Permission check result: {result}")
|
||||
|
||||
assert result is False
|
||||
|
||||
def test_assign_role_to_user(self, db_session, integration_users, integration_community):
|
||||
"""Тест функции назначения роли пользователю"""
|
||||
# Назначаем роль пользователю без существующих ролей
|
||||
result = assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assert result is True
|
||||
|
||||
# Проверяем что роль назначилась
|
||||
roles = get_user_roles_in_community(integration_users[0].id, integration_community.id)
|
||||
assert "reader" in roles
|
||||
|
||||
# Назначаем ещё одну роль
|
||||
result = assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
assert result is True
|
||||
|
||||
roles = get_user_roles_in_community(integration_users[0].id, integration_community.id)
|
||||
assert "reader" in roles
|
||||
assert "author" in roles
|
||||
|
||||
# Попытка назначить существующую роль
|
||||
result = assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assert result is False # Роль уже есть
|
||||
|
||||
def test_remove_role_from_user(self, db_session, integration_users, integration_community):
|
||||
"""Тест функции удаления роли у пользователя"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[1].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "expert", integration_community.id)
|
||||
|
||||
# Удаляем роль
|
||||
result = remove_role_from_user(integration_users[1].id, "author", integration_community.id)
|
||||
assert result is True
|
||||
|
||||
# Проверяем что роль удалилась
|
||||
roles = get_user_roles_in_community(integration_users[1].id, integration_community.id)
|
||||
assert "author" not in roles
|
||||
assert "reader" in roles
|
||||
assert "expert" in roles
|
||||
|
||||
# Попытка удалить несуществующую роль
|
||||
result = remove_role_from_user(integration_users[1].id, "admin", integration_community.id)
|
||||
assert result is False
|
||||
|
||||
async def test_get_all_community_members_with_roles(self, db_session, integration_users: list[Author], integration_community: Community):
|
||||
"""Тест функции получения всех участников сообщества с ролями"""
|
||||
# Назначаем роли нескольким пользователям через функции
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
|
||||
assign_role_to_user(integration_users[1].id, "expert", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "editor", integration_community.id)
|
||||
|
||||
assign_role_to_user(integration_users[2].id, "admin", integration_community.id)
|
||||
|
||||
# Получаем участников
|
||||
members = integration_community.get_community_members(with_roles=True)
|
||||
|
||||
assert len(members) == 3
|
||||
|
||||
# Проверяем структуру данных
|
||||
for member in members:
|
||||
assert "author_id" in member
|
||||
assert "roles" in member
|
||||
assert "permissions" in member
|
||||
assert "joined_at" in member
|
||||
|
||||
# Проверяем конкретного участника
|
||||
admin_member = next(m for m in members if m["author_id"] == integration_users[2].id)
|
||||
assert "admin" in admin_member["roles"]
|
||||
assert len(admin_member["permissions"]) > 0
|
||||
|
||||
def test_bulk_assign_roles(self, db_session, integration_users: list[Author], integration_community: Community):
|
||||
"""Тест функции массового назначения ролей"""
|
||||
# Подготавливаем данные для массового назначения
|
||||
user_role_pairs = [
|
||||
(integration_users[0].id, "reader"),
|
||||
(integration_users[1].id, "author"),
|
||||
(integration_users[2].id, "expert"),
|
||||
(integration_users[3].id, "editor"),
|
||||
(integration_users[4].id, "admin"),
|
||||
]
|
||||
|
||||
# Выполняем массовое назначение
|
||||
result = bulk_assign_roles(user_role_pairs, integration_community.id)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] == 5
|
||||
assert result["failed"] == 0
|
||||
|
||||
# Проверяем что роли назначились
|
||||
for user_id, expected_role in user_role_pairs:
|
||||
roles = get_user_roles_in_community(user_id, integration_community.id)
|
||||
assert expected_role in roles
|
||||
|
||||
|
||||
class TestRoleHierarchy:
|
||||
"""Тесты иерархии ролей и наследования разрешений"""
|
||||
|
||||
async def test_role_inheritance(self, integration_community):
|
||||
"""Тест наследования разрешений между ролями"""
|
||||
# Читатель имеет базовые разрешения
|
||||
reader_perms = set(await get_permissions_for_role("reader", integration_community.id))
|
||||
|
||||
# Автор должен иметь все разрешения читателя + свои
|
||||
author_perms = set(await get_permissions_for_role("author", integration_community.id))
|
||||
|
||||
# Проверяем что автор имеет базовые разрешения читателя
|
||||
basic_read_perms = {"shout:read", "topic:read"}
|
||||
assert basic_read_perms.issubset(author_perms)
|
||||
|
||||
# Админ должен иметь максимальные разрешения
|
||||
admin_perms = set(await get_permissions_for_role("admin", integration_community.id))
|
||||
assert len(admin_perms) >= len(author_perms)
|
||||
assert len(admin_perms) >= len(reader_perms)
|
||||
|
||||
async def test_permission_aggregation(self, db_session, integration_users, integration_community):
|
||||
"""Тест агрегации разрешений от нескольких ролей"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "expert", integration_community.id)
|
||||
|
||||
# Получаем объект CommunityAuthor для проверки агрегированных разрешений
|
||||
from services.db import local_session
|
||||
|
||||
with local_session() as session:
|
||||
ca = CommunityAuthor.find_by_user_and_community(integration_users[0].id, integration_community.id, session)
|
||||
|
||||
# Получаем агрегированные разрешения
|
||||
all_permissions = await ca.get_permissions()
|
||||
|
||||
# Проверяем что есть разрешения от всех ролей
|
||||
reader_perms = await get_permissions_for_role("reader", integration_community.id)
|
||||
author_perms = await get_permissions_for_role("author", integration_community.id)
|
||||
expert_perms = await get_permissions_for_role("expert", integration_community.id)
|
||||
|
||||
# Все разрешения от отдельных ролей должны быть в общем списке
|
||||
for perm in reader_perms:
|
||||
assert perm in all_permissions
|
||||
for perm in author_perms:
|
||||
assert perm in all_permissions
|
||||
for perm in expert_perms:
|
||||
assert perm in all_permissions
|
||||
|
||||
|
||||
class TestCommunityMethods:
|
||||
"""Тесты методов Community для работы с ролями"""
|
||||
|
||||
def test_community_get_user_roles(self, db_session, integration_users, integration_community):
|
||||
"""Тест получения ролей пользователя через сообщество"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "expert", integration_community.id)
|
||||
|
||||
# Проверяем через метод сообщества
|
||||
user_roles = integration_community.get_user_roles(integration_users[0].id)
|
||||
assert "reader" in user_roles
|
||||
assert "author" in user_roles
|
||||
assert "expert" in user_roles
|
||||
|
||||
# Проверяем для пользователя без ролей
|
||||
no_roles = integration_community.get_user_roles(integration_users[1].id)
|
||||
assert no_roles == []
|
||||
|
||||
def test_community_has_user_role(self, db_session, integration_users, integration_community):
|
||||
"""Тест проверки роли пользователя в сообществе"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[1].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "author", integration_community.id)
|
||||
|
||||
# Проверяем существующие роли
|
||||
assert integration_community.has_user_role(integration_users[1].id, "reader") is True
|
||||
assert integration_community.has_user_role(integration_users[1].id, "author") is True
|
||||
|
||||
# Проверяем несуществующие роли
|
||||
assert integration_community.has_user_role(integration_users[1].id, "admin") is False
|
||||
|
||||
def test_community_add_user_role(self, db_session, integration_users, integration_community):
|
||||
"""Тест добавления роли пользователю через сообщество"""
|
||||
# Добавляем роль пользователю без записи
|
||||
integration_community.add_user_role(integration_users[0].id, "reader")
|
||||
|
||||
# Проверяем что роль добавилась
|
||||
roles = integration_community.get_user_roles(integration_users[0].id)
|
||||
assert "reader" in roles
|
||||
|
||||
# Добавляем ещё одну роль
|
||||
integration_community.add_user_role(integration_users[0].id, "author")
|
||||
roles = integration_community.get_user_roles(integration_users[0].id)
|
||||
assert "reader" in roles
|
||||
assert "author" in roles
|
||||
|
||||
def test_community_remove_user_role(self, db_session, integration_users, integration_community):
|
||||
"""Тест удаления роли у пользователя через сообщество"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[1].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "author", integration_community.id)
|
||||
assign_role_to_user(integration_users[1].id, "expert", integration_community.id)
|
||||
|
||||
# Удаляем роль
|
||||
integration_community.remove_user_role(integration_users[1].id, "author")
|
||||
roles = integration_community.get_user_roles(integration_users[1].id)
|
||||
assert "author" not in roles
|
||||
assert "reader" in roles
|
||||
assert "expert" in roles
|
||||
|
||||
def test_community_set_user_roles(self, db_session, integration_users, integration_community):
|
||||
"""Тест установки ролей пользователя через сообщество"""
|
||||
# Устанавливаем роли пользователю без записи
|
||||
integration_community.set_user_roles(integration_users[2].id, ["admin", "editor"])
|
||||
roles = integration_community.get_user_roles(integration_users[2].id)
|
||||
assert set(roles) == {"admin", "editor"}
|
||||
|
||||
# Меняем роли
|
||||
integration_community.set_user_roles(integration_users[2].id, ["reader"])
|
||||
roles = integration_community.get_user_roles(integration_users[2].id)
|
||||
assert roles == ["reader"]
|
||||
|
||||
# Очищаем роли
|
||||
integration_community.set_user_roles(integration_users[2].id, [])
|
||||
roles = integration_community.get_user_roles(integration_users[2].id)
|
||||
assert roles == []
|
||||
|
||||
async def test_community_get_members(self, db_session, integration_users: list[Author], integration_community: Community):
|
||||
"""Тест получения участников сообщества"""
|
||||
# Назначаем роли через функции
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
assign_role_to_user(integration_users[0].id, "author", integration_community.id)
|
||||
|
||||
assign_role_to_user(integration_users[1].id, "expert", integration_community.id)
|
||||
|
||||
# Получаем участников без ролей
|
||||
members = integration_community.get_community_members(with_roles=False)
|
||||
for member in members:
|
||||
assert "author_id" in member
|
||||
assert "joined_at" in member
|
||||
assert "roles" not in member
|
||||
|
||||
# Получаем участников с ролями
|
||||
members_with_roles = integration_community.get_community_members(with_roles=True)
|
||||
for member in members_with_roles:
|
||||
assert "author_id" in member
|
||||
assert "joined_at" in member
|
||||
assert "roles" in member
|
||||
assert "permissions" in member
|
||||
|
||||
|
||||
class TestEdgeCasesIntegration:
|
||||
"""Тесты граничных случаев интеграции"""
|
||||
|
||||
async def test_nonexistent_community(self, integration_users):
|
||||
"""Тест работы с несуществующим сообществом"""
|
||||
# Функции должны корректно обрабатывать несуществующие сообщества
|
||||
roles = get_user_roles_in_community(integration_users[0].id, 99999)
|
||||
assert roles == []
|
||||
|
||||
has_perm = await check_user_permission_in_community(integration_users[0].id, "shout:read", 99999)
|
||||
assert has_perm is False
|
||||
|
||||
async def test_nonexistent_user(self, integration_community):
|
||||
"""Тест работы с несуществующим пользователем"""
|
||||
# Функции должны корректно обрабатывать несуществующих пользователей
|
||||
roles = get_user_roles_in_community(99999, integration_community.id)
|
||||
assert roles == []
|
||||
|
||||
has_perm = await check_user_permission_in_community(99999, "shout:read", integration_community.id)
|
||||
assert has_perm is False
|
||||
|
||||
async def test_empty_permission_check(self, db_session, integration_users, integration_community):
|
||||
"""Тест проверки пустых разрешений"""
|
||||
# Создаем пользователя без ролей через прямое создание записи (пустые роли)
|
||||
ca = CommunityAuthor(community_id=integration_community.id, author_id=integration_users[0].id, roles="")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Проверяем что нет разрешений
|
||||
assert ca.has_permission("shout:read") is False
|
||||
assert ca.has_permission("shout:create") is False
|
||||
permissions = await ca.get_permissions()
|
||||
assert len(permissions) == 0
|
||||
|
||||
|
||||
class TestDataIntegrity:
|
||||
"""Тесты целостности данных"""
|
||||
|
||||
def test_joined_at_field(self, db_session, integration_users, integration_community):
|
||||
"""Тест что поле joined_at корректно заполняется"""
|
||||
# Назначаем роль через функцию
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
|
||||
# Получаем созданную запись
|
||||
from services.db import local_session
|
||||
|
||||
with local_session() as session:
|
||||
ca = CommunityAuthor.find_by_user_and_community(integration_users[0].id, integration_community.id, session)
|
||||
|
||||
# Проверяем что joined_at заполнено
|
||||
assert ca.joined_at is not None
|
||||
assert isinstance(ca.joined_at, int)
|
||||
assert ca.joined_at > 0
|
||||
|
||||
def test_roles_field_constraints(self, db_session, integration_users, integration_community):
|
||||
"""Тест ограничений поля roles"""
|
||||
# Тест с пустой строкой ролей
|
||||
ca = CommunityAuthor(community_id=integration_community.id, author_id=integration_users[0].id, roles="")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
assert ca.role_list == []
|
||||
|
||||
# Тест с None
|
||||
ca.roles = None
|
||||
db_session.commit()
|
||||
assert ca.role_list == []
|
||||
|
||||
def test_unique_constraints(self, db_session, integration_users, integration_community):
|
||||
"""Тест уникальных ограничений"""
|
||||
# Создаем первую запись через функцию
|
||||
assign_role_to_user(integration_users[0].id, "reader", integration_community.id)
|
||||
|
||||
# Попытка создать дублирующуюся запись должна вызвать ошибку
|
||||
ca2 = CommunityAuthor(community_id=integration_community.id, author_id=integration_users[0].id, roles="author")
|
||||
db_session.add(ca2)
|
||||
|
||||
with pytest.raises(Exception): # IntegrityError или подобная
|
||||
db_session.commit()
|
||||
|
||||
|
||||
class TestCommunitySettings:
|
||||
"""Тесты настроек сообщества для ролей"""
|
||||
|
||||
def test_default_roles_management(self, db_session, integration_community):
|
||||
"""Тест управления дефолтными ролями"""
|
||||
# Проверяем дефолтные роли по умолчанию
|
||||
default_roles = integration_community.get_default_roles()
|
||||
assert "reader" in default_roles
|
||||
|
||||
# Устанавливаем новые дефолтные роли
|
||||
integration_community.set_default_roles(["reader", "author"])
|
||||
new_default_roles = integration_community.get_default_roles()
|
||||
assert set(new_default_roles) == {"reader", "author"}
|
||||
|
||||
def test_available_roles_management(self, integration_community):
|
||||
"""Тест управления доступными ролями"""
|
||||
# Проверяем доступные роли по умолчанию
|
||||
available_roles = integration_community.get_available_roles()
|
||||
expected_roles = ["reader", "author", "artist", "expert", "editor", "admin"]
|
||||
assert set(available_roles) == set(expected_roles)
|
||||
|
||||
def test_assign_default_roles(self, db_session, integration_users, integration_community):
|
||||
"""Тест назначения дефолтных ролей"""
|
||||
# Устанавливаем дефолтные роли
|
||||
integration_community.set_default_roles(["reader", "author"])
|
||||
|
||||
# Назначаем дефолтные роли пользователю
|
||||
integration_community.assign_default_roles_to_user(integration_users[0].id)
|
||||
|
||||
# Проверяем что роли назначились
|
||||
roles = integration_community.get_user_roles(integration_users[0].id)
|
||||
assert set(roles) == {"reader", "author"}
|
413
tests/test_rbac_system.py
Normal file
413
tests/test_rbac_system.py
Normal file
@@ -0,0 +1,413 @@
|
||||
"""
|
||||
Тесты для новой системы RBAC (Role-Based Access Control).
|
||||
|
||||
Проверяет работу системы ролей и разрешений на основе CSV хранения
|
||||
в таблице CommunityAuthor.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from services.rbac import get_role_permissions_for_community, get_permissions_for_role
|
||||
from orm.reaction import REACTION_KINDS
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_users(db_session):
|
||||
"""Создает тестовых пользователей"""
|
||||
users = []
|
||||
|
||||
# Создаем пользователей с ID 1-5
|
||||
for i in range(1, 6):
|
||||
user = db_session.query(Author).filter(Author.id == i).first()
|
||||
if not user:
|
||||
user = Author(id=i, email=f"user{i}@example.com", name=f"Test User {i}", slug=f"test-user-{i}")
|
||||
user.set_password("password123")
|
||||
db_session.add(user)
|
||||
users.append(user)
|
||||
|
||||
db_session.commit()
|
||||
return users
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_community(db_session, test_users):
|
||||
"""Создает тестовое сообщество"""
|
||||
community = db_session.query(Community).filter(Community.id == 1).first()
|
||||
if not community:
|
||||
community = Community(
|
||||
id=1,
|
||||
name="Test Community",
|
||||
slug="test-community",
|
||||
desc="Test community for RBAC tests",
|
||||
created_by=test_users[0].id,
|
||||
)
|
||||
db_session.add(community)
|
||||
db_session.commit()
|
||||
|
||||
return community
|
||||
|
||||
|
||||
class TestCommunityAuthorRoles:
|
||||
"""Тесты для управления ролями в CommunityAuthor"""
|
||||
|
||||
def test_role_list_property(self, db_session, test_users, test_community):
|
||||
"""Тест свойства role_list для CSV ролей"""
|
||||
# Очищаем существующие записи для этого пользователя
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[0].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
# Создаем запись с ролями
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles="reader,author,expert")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Проверяем получение списка ролей
|
||||
assert ca.role_list == ["reader", "author", "expert"]
|
||||
|
||||
# Проверяем установку списка ролей
|
||||
ca.role_list = ["admin", "editor"]
|
||||
assert ca.roles == "admin,editor"
|
||||
|
||||
# Проверяем пустые роли
|
||||
ca.role_list = []
|
||||
assert ca.roles is None
|
||||
assert ca.role_list == []
|
||||
|
||||
def test_has_role(self, db_session, test_users, test_community):
|
||||
"""Тест проверки наличия роли"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[1].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[1].id, roles="reader,author")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Проверяем существующие роли
|
||||
assert ca.has_role("reader") is True
|
||||
assert ca.has_role("author") is True
|
||||
|
||||
# Проверяем несуществующие роли
|
||||
assert ca.has_role("admin") is False
|
||||
assert ca.has_role("editor") is False
|
||||
|
||||
def test_add_role(self, db_session, test_users, test_community):
|
||||
"""Тест добавления роли"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[2].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[2].id, roles="reader")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Добавляем новую роль
|
||||
ca.add_role("author")
|
||||
assert ca.role_list == ["reader", "author"]
|
||||
|
||||
# Попытка добавить существующую роль (не должна дублироваться)
|
||||
ca.add_role("reader")
|
||||
assert ca.role_list == ["reader", "author"]
|
||||
|
||||
# Добавляем ещё одну роль
|
||||
ca.add_role("expert")
|
||||
assert ca.role_list == ["reader", "author", "expert"]
|
||||
|
||||
def test_remove_role(self, db_session, test_users, test_community):
|
||||
"""Тест удаления роли"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[3].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[3].id, roles="reader,author,expert")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Удаляем роль
|
||||
ca.remove_role("author")
|
||||
assert ca.role_list == ["reader", "expert"]
|
||||
|
||||
# Попытка удалить несуществующую роль (не должна ломаться)
|
||||
ca.remove_role("admin")
|
||||
assert ca.role_list == ["reader", "expert"]
|
||||
|
||||
# Удаляем все роли
|
||||
ca.remove_role("reader")
|
||||
ca.remove_role("expert")
|
||||
assert ca.role_list == []
|
||||
|
||||
def test_set_roles(self, db_session, test_users, test_community):
|
||||
"""Тест установки полного списка ролей"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[4].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[4].id, roles="reader")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Устанавливаем новый список ролей
|
||||
ca.set_roles(["admin", "editor", "expert"])
|
||||
assert ca.role_list == ["admin", "editor", "expert"]
|
||||
|
||||
# Очищаем роли
|
||||
ca.set_roles([])
|
||||
assert ca.role_list == []
|
||||
|
||||
|
||||
class TestPermissionsSystem:
|
||||
"""Тесты для системы разрешений"""
|
||||
|
||||
async def test_get_permissions_for_role(self):
|
||||
"""Тест получения разрешений для роли"""
|
||||
community_id = 1 # Используем основное сообщество
|
||||
|
||||
# Проверяем базовые роли
|
||||
reader_perms = await get_permissions_for_role("reader", community_id)
|
||||
assert "shout:read" in reader_perms
|
||||
assert "shout:create" not in reader_perms
|
||||
|
||||
author_perms = await get_permissions_for_role("author", community_id)
|
||||
assert "shout:create" in author_perms
|
||||
assert "draft:create" in author_perms
|
||||
assert "shout:delete_any" not in author_perms
|
||||
|
||||
admin_perms = await get_permissions_for_role("admin", community_id)
|
||||
assert "author:delete_any" in admin_perms
|
||||
assert "author:update_any" in admin_perms
|
||||
|
||||
# Проверяем несуществующую роль
|
||||
unknown_perms = await get_permissions_for_role("unknown_role", community_id)
|
||||
assert unknown_perms == []
|
||||
|
||||
async def test_reaction_permissions_generation(self):
|
||||
"""Тест генерации разрешений для реакций"""
|
||||
community_id = 1 # Используем основное сообщество
|
||||
|
||||
# Проверяем что система генерирует разрешения для реакций
|
||||
admin_perms = await get_permissions_for_role("admin", community_id)
|
||||
|
||||
# Админ должен иметь все разрешения на реакции
|
||||
assert len(admin_perms) > 0, "Admin should have some permissions"
|
||||
|
||||
# Проверяем что есть хотя бы базовые разрешения на реакции у читателей
|
||||
reader_perms = await get_permissions_for_role("reader", community_id)
|
||||
assert len(reader_perms) > 0, "Reader should have some permissions"
|
||||
|
||||
# Проверяем что у reader есть разрешения на чтение реакций
|
||||
assert any("reaction:read:" in perm for perm in reader_perms), "Reader should have reaction read permissions"
|
||||
|
||||
async def test_community_author_get_permissions(self, db_session, test_users, test_community):
|
||||
"""Тест получения разрешений через CommunityAuthor"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[0].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles="reader,author")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
permissions = await ca.get_permissions()
|
||||
|
||||
# Должны быть разрешения от обеих ролей
|
||||
assert "shout:read" in permissions # От reader
|
||||
assert "shout:create" in permissions # От author
|
||||
assert len(permissions) > 0 # Должны быть какие-то разрешения
|
||||
|
||||
async def test_community_author_has_permission(self, db_session, test_users, test_community):
|
||||
"""Тест проверки разрешения через CommunityAuthor"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[1].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[1].id, roles="expert,editor")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Проверяем разрешения
|
||||
permissions = await ca.get_permissions()
|
||||
# Expert имеет разрешения на реакции PROOF/DISPROOF
|
||||
assert any("reaction:create:PROOF" in perm for perm in permissions)
|
||||
# Editor имеет разрешения на удаление и обновление шаутов
|
||||
assert "shout:delete_any" in permissions
|
||||
assert "shout:update_any" in permissions
|
||||
|
||||
|
||||
class TestClassMethods:
|
||||
"""Тесты для классовых методов CommunityAuthor"""
|
||||
|
||||
async def test_find_by_user_and_community(self, db_session, test_users, test_community):
|
||||
"""Тест поиска записи CommunityAuthor"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[0].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
# Создаем запись
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles="reader,author")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Ищем существующую запись
|
||||
found = CommunityAuthor.find_by_user_and_community(test_users[0].id, test_community.id, db_session)
|
||||
assert found is not None
|
||||
assert found.author_id == test_users[0].id
|
||||
assert found.community_id == test_community.id
|
||||
|
||||
# Ищем несуществующую запись
|
||||
not_found = CommunityAuthor.find_by_user_and_community(test_users[1].id, test_community.id, db_session)
|
||||
assert not_found is None
|
||||
|
||||
async def test_get_users_with_role(self, db_session, test_users, test_community):
|
||||
"""Тест получения пользователей с определенной ролью"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(CommunityAuthor.community_id == test_community.id).delete()
|
||||
db_session.commit()
|
||||
|
||||
# Создаем пользователей с разными ролями
|
||||
cas = [
|
||||
CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles="reader,author"),
|
||||
CommunityAuthor(community_id=test_community.id, author_id=test_users[1].id, roles="reader,expert"),
|
||||
CommunityAuthor(community_id=test_community.id, author_id=test_users[2].id, roles="admin"),
|
||||
]
|
||||
for ca in cas:
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Ищем пользователей с ролью reader
|
||||
readers = CommunityAuthor.get_users_with_role(test_community.id, "reader", db_session)
|
||||
assert test_users[0].id in readers
|
||||
assert test_users[1].id in readers
|
||||
assert test_users[2].id not in readers
|
||||
|
||||
# Ищем пользователей с ролью admin
|
||||
admins = CommunityAuthor.get_users_with_role(test_community.id, "admin", db_session)
|
||||
assert test_users[2].id in admins
|
||||
assert test_users[0].id not in admins
|
||||
|
||||
|
||||
class TestEdgeCases:
|
||||
"""Тесты для граничных случаев"""
|
||||
|
||||
async def test_empty_roles_handling(self, db_session, test_users, test_community):
|
||||
"""Тест обработки пустых ролей"""
|
||||
# Создаем запись с пустыми ролями
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles="")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
assert ca.role_list == []
|
||||
permissions = await ca.get_permissions()
|
||||
assert permissions == []
|
||||
|
||||
async def test_none_roles_handling(self, db_session, test_users, test_community):
|
||||
"""Тест обработки NULL ролей"""
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles=None)
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
assert ca.role_list == []
|
||||
assert await ca.get_permissions() == []
|
||||
|
||||
async def test_whitespace_roles_handling(self, db_session, test_users, test_community):
|
||||
"""Тест обработки ролей с пробелами"""
|
||||
ca = CommunityAuthor(
|
||||
community_id=test_community.id, author_id=test_users[0].id, roles=" reader , author , expert "
|
||||
)
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Пробелы должны убираться
|
||||
assert ca.role_list == ["reader", "author", "expert"]
|
||||
|
||||
async def test_duplicate_roles_handling(self, db_session, test_users, test_community):
|
||||
"""Тест обработки дублирующихся ролей"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[0].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(
|
||||
community_id=test_community.id, author_id=test_users[0].id, roles="reader,author,reader,expert,author"
|
||||
)
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# При установке через set_roles дубликаты должны убираться
|
||||
unique_roles = set(["reader", "author", "reader", "expert"])
|
||||
ca.set_roles(unique_roles)
|
||||
roles = ca.role_list
|
||||
# Проверяем что нет дубликатов
|
||||
assert len(roles) == len(set(roles))
|
||||
assert "reader" in roles
|
||||
assert "author" in roles
|
||||
assert "expert" in roles
|
||||
|
||||
async def test_invalid_role(self):
|
||||
"""Тест получения разрешений для несуществующих ролей"""
|
||||
community_id = 1 # Используем основное сообщество
|
||||
|
||||
# Проверяем что несуществующая роль не ломает систему
|
||||
perms = await get_permissions_for_role("nonexistent_role", community_id)
|
||||
assert perms == []
|
||||
|
||||
|
||||
class TestPerformance:
|
||||
"""Тесты производительности (базовые)"""
|
||||
|
||||
async def test_large_role_list_performance(self, db_session, test_users, test_community):
|
||||
"""Тест производительности с большим количеством ролей"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[0].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
# Создаем запись с множеством ролей
|
||||
many_roles = ",".join([f"role_{i}" for i in range(50)]) # Уменьшим количество
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[0].id, roles=many_roles)
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Операции должны работать быстро даже с множеством ролей
|
||||
role_list = ca.role_list
|
||||
assert len(role_list) == 50
|
||||
assert all(role.startswith("role_") for role in role_list)
|
||||
|
||||
async def test_permissions_caching_behavior(self, db_session, test_users, test_community):
|
||||
"""Тест поведения кеширования разрешений"""
|
||||
# Очищаем существующие записи
|
||||
db_session.query(CommunityAuthor).filter(
|
||||
CommunityAuthor.community_id == test_community.id, CommunityAuthor.author_id == test_users[1].id
|
||||
).delete()
|
||||
db_session.commit()
|
||||
|
||||
ca = CommunityAuthor(community_id=test_community.id, author_id=test_users[1].id, roles="reader,author,expert")
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
|
||||
# Многократный вызов get_permissions должен работать стабильно
|
||||
perms1 = await ca.get_permissions()
|
||||
perms2 = await ca.get_permissions()
|
||||
perms3 = await ca.get_permissions()
|
||||
|
||||
assert perms1.sort() == perms2.sort() == perms3.sort()
|
||||
assert len(perms1) > 0
|
@@ -2,25 +2,15 @@ from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author, AuthorRole, Role
|
||||
from auth.orm import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.reaction import ReactionKind
|
||||
from orm.shout import Shout
|
||||
from resolvers.reaction import create_reaction
|
||||
|
||||
|
||||
def ensure_test_user_with_roles(db_session):
|
||||
"""Создает тестового пользователя с ID 1 и назначает ему роли"""
|
||||
# Создаем роли если их нет
|
||||
reader_role = db_session.query(Role).filter(Role.id == "reader").first()
|
||||
if not reader_role:
|
||||
reader_role = Role(id="reader", name="Читатель")
|
||||
db_session.add(reader_role)
|
||||
|
||||
author_role = db_session.query(Role).filter(Role.id == "author").first()
|
||||
if not author_role:
|
||||
author_role = Role(id="author", name="Автор")
|
||||
db_session.add(author_role)
|
||||
|
||||
"""Создает тестового пользователя с ID 1 и назначает ему роли через CSV"""
|
||||
# Создаем пользователя с ID 1 если его нет
|
||||
test_user = db_session.query(Author).filter(Author.id == 1).first()
|
||||
if not test_user:
|
||||
@@ -29,13 +19,24 @@ def ensure_test_user_with_roles(db_session):
|
||||
db_session.add(test_user)
|
||||
db_session.flush()
|
||||
|
||||
# Удаляем старые роли и добавляем новые
|
||||
db_session.query(AuthorRole).filter(AuthorRole.author == 1).delete()
|
||||
# Создаем связь пользователя с сообществом с ролями через CSV
|
||||
community_author = (
|
||||
db_session.query(CommunityAuthor)
|
||||
.filter(CommunityAuthor.community_id == 1, CommunityAuthor.author_id == 1)
|
||||
.first()
|
||||
)
|
||||
|
||||
# Добавляем роли
|
||||
for role_id in ["reader", "author"]:
|
||||
author_role_link = AuthorRole(community=1, author=1, role=role_id)
|
||||
db_session.add(author_role_link)
|
||||
if not community_author:
|
||||
community_author = CommunityAuthor(
|
||||
community_id=1,
|
||||
author_id=1,
|
||||
roles="reader,author", # Роли через CSV
|
||||
joined_at=int(datetime.now().timestamp()),
|
||||
)
|
||||
db_session.add(community_author)
|
||||
else:
|
||||
# Обновляем роли если связь уже существует
|
||||
community_author.roles = "reader,author"
|
||||
|
||||
db_session.commit()
|
||||
return test_user
|
||||
|
@@ -2,43 +2,12 @@ from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author, AuthorRole, Role
|
||||
from auth.orm import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.shout import Shout
|
||||
from resolvers.reader import get_shout
|
||||
|
||||
|
||||
def ensure_test_user_with_roles(db_session):
|
||||
"""Создает тестового пользователя с ID 1 и назначает ему роли"""
|
||||
# Создаем роли если их нет
|
||||
reader_role = db_session.query(Role).filter(Role.id == "reader").first()
|
||||
if not reader_role:
|
||||
reader_role = Role(id="reader", name="Читатель")
|
||||
db_session.add(reader_role)
|
||||
|
||||
author_role = db_session.query(Role).filter(Role.id == "author").first()
|
||||
if not author_role:
|
||||
author_role = Role(id="author", name="Автор")
|
||||
db_session.add(author_role)
|
||||
|
||||
# Создаем пользователя с ID 1 если его нет
|
||||
test_user = db_session.query(Author).filter(Author.id == 1).first()
|
||||
if not test_user:
|
||||
test_user = Author(id=1, email="test@example.com", name="Test User", slug="test-user")
|
||||
test_user.set_password("password123")
|
||||
db_session.add(test_user)
|
||||
db_session.flush()
|
||||
|
||||
# Удаляем старые роли и добавляем новые
|
||||
db_session.query(AuthorRole).filter(AuthorRole.author == 1).delete()
|
||||
|
||||
# Добавляем роли
|
||||
for role_id in ["reader", "author"]:
|
||||
author_role_link = AuthorRole(community=1, author=1, role=role_id)
|
||||
db_session.add(author_role_link)
|
||||
|
||||
db_session.commit()
|
||||
return test_user
|
||||
|
||||
|
||||
class MockInfo:
|
||||
"""Мок для GraphQL info объекта"""
|
||||
@@ -85,7 +54,13 @@ class MockName:
|
||||
@pytest.fixture
|
||||
def test_shout(db_session):
|
||||
"""Create test shout with required fields."""
|
||||
author = ensure_test_user_with_roles(db_session)
|
||||
author = Author(id=1, email="test@example.com", name="Test User", slug="test-user")
|
||||
author.set_password("password123")
|
||||
author.set_email_verified(True)
|
||||
ca = CommunityAuthor(community_id=1, author_id=author.id, roles="reader,author")
|
||||
db_session.add(author)
|
||||
db_session.add(ca)
|
||||
db_session.commit()
|
||||
now = int(datetime.now().timestamp())
|
||||
|
||||
# Создаем публикацию со всеми обязательными полями
|
||||
|
@@ -17,7 +17,8 @@ from pathlib import Path
|
||||
|
||||
sys.path.append(str(Path(__file__).parent))
|
||||
|
||||
from auth.orm import Author, AuthorRole, Role
|
||||
from auth.orm import Author
|
||||
from orm.community import assign_role_to_user
|
||||
from orm.shout import Shout
|
||||
from resolvers.editor import unpublish_shout
|
||||
from services.db import local_session
|
||||
@@ -27,44 +28,6 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(mess
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def ensure_roles_exist():
|
||||
"""Создает стандартные роли в БД если их нет"""
|
||||
with local_session() as session:
|
||||
# Создаем базовые роли если их нет
|
||||
roles_to_create = [
|
||||
("reader", "Читатель"),
|
||||
("author", "Автор"),
|
||||
("editor", "Редактор"),
|
||||
("admin", "Администратор"),
|
||||
]
|
||||
|
||||
for role_id, role_name in roles_to_create:
|
||||
role = session.query(Role).filter(Role.id == role_id).first()
|
||||
if not role:
|
||||
role = Role(id=role_id, name=role_name)
|
||||
session.add(role)
|
||||
|
||||
session.commit()
|
||||
|
||||
|
||||
def add_roles_to_author(author_id: int, roles: list[str]):
|
||||
"""Добавляет роли пользователю в БД"""
|
||||
with local_session() as session:
|
||||
# Удаляем старые роли
|
||||
session.query(AuthorRole).filter(AuthorRole.author == author_id).delete()
|
||||
|
||||
# Добавляем новые роли
|
||||
for role_id in roles:
|
||||
author_role = AuthorRole(
|
||||
community=1, # Основное сообщество
|
||||
author=author_id,
|
||||
role=role_id,
|
||||
)
|
||||
session.add(author_role)
|
||||
|
||||
session.commit()
|
||||
|
||||
|
||||
class MockInfo:
|
||||
"""Мок для GraphQL info контекста"""
|
||||
|
||||
@@ -88,9 +51,6 @@ async def setup_test_data() -> tuple[Author, Shout, Author]:
|
||||
"""Создаем тестовые данные: автора, публикацию и другого автора"""
|
||||
logger.info("🔧 Настройка тестовых данных")
|
||||
|
||||
# Создаем роли в БД
|
||||
ensure_roles_exist()
|
||||
|
||||
current_time = int(time.time())
|
||||
|
||||
with local_session() as session:
|
||||
@@ -133,8 +93,10 @@ async def setup_test_data() -> tuple[Author, Shout, Author]:
|
||||
session.commit()
|
||||
|
||||
# Добавляем роли пользователям в БД
|
||||
add_roles_to_author(test_author.id, ["reader", "author"])
|
||||
add_roles_to_author(other_author.id, ["reader", "author"])
|
||||
assign_role_to_user(test_author.id, "reader")
|
||||
assign_role_to_user(test_author.id, "author")
|
||||
assign_role_to_user(other_author.id, "reader")
|
||||
assign_role_to_user(other_author.id, "author")
|
||||
|
||||
logger.info(
|
||||
f" ✅ Созданы: автор {test_author.id}, другой автор {other_author.id}, публикация {test_shout.id}"
|
||||
@@ -191,7 +153,9 @@ async def test_unpublish_by_editor() -> None:
|
||||
session.commit()
|
||||
|
||||
# Добавляем роль "editor" другому автору в БД
|
||||
add_roles_to_author(other_author.id, ["reader", "author", "editor"])
|
||||
assign_role_to_user(other_author.id, "reader")
|
||||
assign_role_to_user(other_author.id, "author")
|
||||
assign_role_to_user(other_author.id, "editor")
|
||||
|
||||
logger.info(" 📝 Тест: Снятие публикации редактором")
|
||||
info = MockInfo(other_author.id, roles=["reader", "author", "editor"]) # Другой автор с ролью редактора
|
||||
@@ -243,7 +207,8 @@ async def test_access_denied_scenarios() -> None:
|
||||
# Тест 2: Не-автор без прав редактора
|
||||
logger.info(" 📝 Тест 2: Не-автор без прав редактора")
|
||||
# Убеждаемся что у other_author нет роли editor
|
||||
add_roles_to_author(other_author.id, ["reader", "author"]) # Только базовые роли
|
||||
assign_role_to_user(other_author.id, "reader")
|
||||
assign_role_to_user(other_author.id, "author")
|
||||
info = MockInfo(other_author.id, roles=["reader", "author"]) # Другой автор без прав редактора
|
||||
|
||||
result = await unpublish_shout(None, info, test_shout.id)
|
||||
@@ -314,28 +279,11 @@ async def cleanup_test_data() -> None:
|
||||
|
||||
try:
|
||||
with local_session() as session:
|
||||
# Удаляем роли тестовых авторов
|
||||
test_author = session.query(Author).filter(Author.email == "test_author@example.com").first()
|
||||
if test_author:
|
||||
session.query(AuthorRole).filter(AuthorRole.author == test_author.id).delete()
|
||||
|
||||
other_author = session.query(Author).filter(Author.email == "other_author@example.com").first()
|
||||
if other_author:
|
||||
session.query(AuthorRole).filter(AuthorRole.author == other_author.id).delete()
|
||||
|
||||
# Удаляем тестовую публикацию
|
||||
test_shout = session.query(Shout).filter(Shout.slug == "test-shout-published").first()
|
||||
if test_shout:
|
||||
session.delete(test_shout)
|
||||
|
||||
# Удаляем тестовых авторов
|
||||
if test_author:
|
||||
session.delete(test_author)
|
||||
|
||||
if other_author:
|
||||
session.delete(other_author)
|
||||
|
||||
session.commit()
|
||||
logger.info(" ✅ Тестовые данные очищены")
|
||||
except Exception as e:
|
||||
logger.warning(f" ⚠️ Ошибка при очистке: {e}")
|
||||
|
Reference in New Issue
Block a user