Files
core/tests/test_community_rbac.py
2025-07-31 18:55:59 +03:00

557 lines
24 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Тесты для системы ролей в сообществах с учетом наследования ролей.
Проверяет работу с ролями пользователей в сообществах,
включая наследование разрешений между ролями.
"""
import pytest
import time
import uuid
from unittest.mock import patch, MagicMock
from auth.orm import Author
from orm.community import Community, CommunityAuthor
from services.rbac import (
initialize_community_permissions,
get_permissions_for_role,
user_has_permission,
roles_have_permission
)
from services.db import local_session
@pytest.fixture
def unique_email():
"""Генерирует уникальный email для каждого теста"""
return f"test-{uuid.uuid4()}@example.com"
@pytest.fixture
def unique_slug():
"""Генерирует уникальный slug для каждого теста"""
return f"test-{uuid.uuid4().hex[:8]}"
@pytest.fixture
def session():
"""Создает сессию базы данных для тестов"""
with local_session() as session:
yield session
session.rollback()
class TestCommunityRoleInheritance:
"""Тесты наследования ролей в сообществах"""
@pytest.mark.asyncio
async def test_community_author_role_inheritance(self, session, unique_email, unique_slug):
"""Тест наследования ролей в CommunityAuthor"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test User",
slug=unique_slug,
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Community",
slug=f"test-community-{unique_slug}",
desc="Test community for role inheritance",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
# Инициализируем разрешения для сообщества
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью author
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="author"
)
session.add(ca)
session.commit()
# Проверяем что author наследует разрешения reader
reader_permissions = ["shout:read", "topic:read", "collection:read", "chat:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Author должен наследовать разрешение {perm} от reader"
# Проверяем специфичные разрешения author
author_permissions = ["draft:create", "shout:create", "collection:create", "invite:create"]
for perm in author_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Author должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_community_editor_role_inheritance(self, session, unique_email, unique_slug):
"""Тест наследования ролей для editor в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Editor",
slug=f"test-editor-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Editor Community",
slug=f"test-editor-community-{unique_slug}",
desc="Test community for editor role",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью editor
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="editor"
)
session.add(ca)
session.commit()
# Проверяем что editor наследует разрешения author
author_permissions = ["draft:create", "shout:create", "collection:create"]
for perm in author_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Editor должен наследовать разрешение {perm} от author"
# Проверяем что editor наследует разрешения reader через author
reader_permissions = ["shout:read", "topic:read", "collection:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Editor должен наследовать разрешение {perm} от reader через author"
# Проверяем специфичные разрешения editor
editor_permissions = ["shout:delete_any", "shout:update_any", "topic:create", "community:create"]
for perm in editor_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Editor должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_community_admin_role_inheritance(self, session, unique_email, unique_slug):
"""Тест наследования ролей для admin в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Admin",
slug=f"test-admin-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Admin Community",
slug=f"test-admin-community-{unique_slug}",
desc="Test community for admin role",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью admin
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="admin"
)
session.add(ca)
session.commit()
# Проверяем что admin имеет разрешения всех ролей через наследование
all_role_permissions = [
"shout:read", # reader
"draft:create", # author
"shout:delete_any", # editor
"author:delete_any" # admin
]
for perm in all_role_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Admin должен иметь разрешение {perm} через наследование"
@pytest.mark.asyncio
async def test_community_expert_role_inheritance(self, session, unique_email, unique_slug):
"""Тест наследования ролей для expert в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Expert",
slug=f"test-expert-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Expert Community",
slug=f"test-expert-community-{unique_slug}",
desc="Test community for expert role",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью expert
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="expert"
)
session.add(ca)
session.commit()
# Проверяем что expert наследует разрешения reader
reader_permissions = ["shout:read", "topic:read", "collection:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Expert должен наследовать разрешение {perm} от reader"
# Проверяем специфичные разрешения expert
expert_permissions = ["reaction:create:PROOF", "reaction:create:DISPROOF", "reaction:create:AGREE"]
for perm in expert_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Expert должен иметь разрешение {perm}"
# Проверяем что expert НЕ имеет разрешения author
author_permissions = ["draft:create", "shout:create"]
for perm in author_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert not has_permission, f"Expert НЕ должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_community_artist_role_inheritance(self, session, unique_email, unique_slug):
"""Тест наследования ролей для artist в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Artist",
slug=f"test-artist-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Artist Community",
slug=f"test-artist-community-{unique_slug}",
desc="Test community for artist role",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью artist
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="artist"
)
session.add(ca)
session.commit()
# Проверяем что artist наследует разрешения author
author_permissions = ["draft:create", "shout:create", "collection:create"]
for perm in author_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Artist должен наследовать разрешение {perm} от author"
# Проверяем что artist наследует разрешения reader через author
reader_permissions = ["shout:read", "topic:read", "collection:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Artist должен наследовать разрешение {perm} от reader через author"
# Проверяем специфичные разрешения artist
artist_permissions = ["reaction:create:CREDIT", "reaction:read:CREDIT", "reaction:update_own:CREDIT"]
for perm in artist_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Artist должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_community_multiple_roles_inheritance(self, session, unique_email, unique_slug):
"""Тест множественных ролей с наследованием в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Multi-Role User",
slug=f"test-multi-role-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Multi-Role Community",
slug=f"test-multi-role-community-{unique_slug}",
desc="Test community for multiple roles",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с несколькими ролями
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="author,expert"
)
session.add(ca)
session.commit()
# Проверяем разрешения от роли author
author_permissions = ["draft:create", "shout:create", "collection:create"]
for perm in author_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Пользователь с ролями author,expert должен иметь разрешение {perm} от author"
# Проверяем разрешения от роли expert
expert_permissions = ["reaction:create:PROOF", "reaction:create:DISPROOF", "reaction:create:AGREE"]
for perm in expert_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Пользователь с ролями author,expert должен иметь разрешение {perm} от expert"
# Проверяем общие разрешения от reader (наследуются обеими ролями)
reader_permissions = ["shout:read", "topic:read", "collection:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Пользователь с ролями author,expert должен иметь разрешение {perm} от reader"
@pytest.mark.asyncio
async def test_community_roles_have_permission_inheritance(self, session, unique_email, unique_slug):
"""Тест функции roles_have_permission с наследованием в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Permission Check",
slug=f"test-permission-check-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Permission Community",
slug=f"test-permission-community-{unique_slug}",
desc="Test community for permission checks",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Проверяем что editor имеет разрешения author через наследование
has_author_permission = await roles_have_permission(["editor"], "draft:create", community.id)
assert has_author_permission, "Editor должен иметь разрешение draft:create через наследование от author"
# Проверяем что admin имеет разрешения reader через наследование
has_reader_permission = await roles_have_permission(["admin"], "shout:read", community.id)
assert has_reader_permission, "Admin должен иметь разрешение shout:read через наследование от reader"
# Проверяем что artist имеет разрешения author через наследование
has_artist_author_permission = await roles_have_permission(["artist"], "shout:create", community.id)
assert has_artist_author_permission, "Artist должен иметь разрешение shout:create через наследование от author"
# Проверяем что expert НЕ имеет разрешения author
has_expert_author_permission = await roles_have_permission(["expert"], "draft:create", community.id)
assert not has_expert_author_permission, "Expert НЕ должен иметь разрешение draft:create"
@pytest.mark.asyncio
async def test_community_deep_inheritance_chain(self, session, unique_email, unique_slug):
"""Тест глубокой цепочки наследования в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Deep Inheritance",
slug=f"test-deep-inheritance-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Deep Inheritance Community",
slug=f"test-deep-inheritance-community-{unique_slug}",
desc="Test community for deep inheritance",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью admin
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="admin"
)
session.add(ca)
session.commit()
# Проверяем что admin имеет разрешения через всю цепочку наследования
# admin -> editor -> author -> reader
inheritance_chain_permissions = [
"shout:read", # reader
"draft:create", # author
"shout:delete_any", # editor
"author:delete_any" # admin
]
for perm in inheritance_chain_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Admin должен иметь разрешение {perm} через цепочку наследования"
@pytest.mark.asyncio
async def test_community_permission_denial_with_inheritance(self, session, unique_email, unique_slug):
"""Тест отказа в разрешениях с учетом наследования в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Permission Denial",
slug=f"test-permission-denial-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Permission Denial Community",
slug=f"test-permission-denial-community-{unique_slug}",
desc="Test community for permission denial",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Создаем CommunityAuthor с ролью reader
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles="reader"
)
session.add(ca)
session.commit()
# Проверяем что reader НЕ имеет разрешения более высоких ролей
denied_permissions = [
"draft:create", # author
"shout:create", # author
"shout:delete_any", # editor
"author:delete_any", # admin
"reaction:create:PROOF", # expert
"reaction:create:CREDIT" # artist
]
for perm in denied_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert not has_permission, f"Reader НЕ должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_community_role_permissions_consistency(self, session, unique_email, unique_slug):
"""Тест консистентности разрешений ролей в сообществе"""
# Создаем тестового пользователя
user = Author(
email=unique_email,
name="Test Consistency",
slug=f"test-consistency-{unique_slug}",
created_at=int(time.time())
)
user.set_password("password123")
session.add(user)
session.flush()
# Создаем тестовое сообщество
community = Community(
name="Test Consistency Community",
slug=f"test-consistency-community-{unique_slug}",
desc="Test community for role consistency",
created_by=user.id,
created_at=int(time.time())
)
session.add(community)
session.flush()
await initialize_community_permissions(community.id)
# Проверяем что все роли имеют корректные разрешения
role_permissions_map = {
"reader": ["shout:read", "topic:read", "collection:read"],
"author": ["draft:create", "shout:create", "collection:create"],
"expert": ["reaction:create:PROOF", "reaction:create:DISPROOF"],
"artist": ["reaction:create:CREDIT", "reaction:read:CREDIT"],
"editor": ["shout:delete_any", "shout:update_any", "topic:create"],
"admin": ["author:delete_any", "author:update_any"]
}
for role, expected_permissions in role_permissions_map.items():
# Создаем CommunityAuthor с текущей ролью
ca = CommunityAuthor(
community_id=community.id,
author_id=user.id,
roles=role
)
session.add(ca)
session.commit()
# Проверяем что роль имеет ожидаемые разрешения
for perm in expected_permissions:
has_permission = await user_has_permission(user.id, perm, community.id)
assert has_permission, f"Роль {role} должна иметь разрешение {perm}"
# Удаляем запись для следующей итерации
session.delete(ca)
session.commit()