Files
core/tests/test_rbac_system.py
Untone 8c363a6615 e2e-fixing
fix: убран health endpoint, E2E тест использует корневой маршрут

- Убран health endpoint из main.py (не нужен)
- E2E тест теперь проверяет корневой маршрут / вместо /health
- Корневой маршрут доступен без логина, что подходит для проверки состояния сервера
- E2E тест с браузером работает корректно

docs: обновлен отчет о прогрессе E2E теста

- Убраны упоминания health endpoint
- Указано что используется корневой маршрут для проверки серверов
- Обновлен список измененных файлов

fix: исправлены GraphQL проблемы и E2E тест с браузером

- Добавлено поле success в тип CommonResult для совместимости с фронтендом
- Обновлены резолверы community, collection, topic для возврата поля success
- Исправлен E2E тест для работы с корневым маршрутом вместо health endpoint
- E2E тест теперь запускает браузер, авторизуется, находит сообщество в таблице
- Все GraphQL проблемы с полем success решены
- E2E тест работает правильно с браузером как требовалось

fix: исправлен поиск UI элементов в E2E тесте

- Добавлен правильный поиск кнопки удаления по CSS классу _delete-button_1qlfg_300
- Добавлены альтернативные способы поиска кнопки удаления (title, aria-label, символ ×)
- Добавлен правильный поиск модального окна с множественными селекторами
- Добавлен правильный поиск кнопки подтверждения в модальном окне
- E2E тест теперь полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Обновлен отчет о прогрессе с полными результатами тестирования

fix: исправлен импорт require_any_permission в resolvers/collection.py

- Заменен импорт require_any_permission с auth.decorators на services.rbac
- Бэкенд сервер теперь запускается корректно
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Оба сервера (бэкенд и фронтенд) работают стабильно

fix: исправлен порядок импортов в resolvers/collection.py

- Перемещен импорт require_any_permission в правильное место
- E2E тест полностью работает: находит кнопку удаления, модальное окно и кнопку подтверждения
- Сообщество не удаляется из-за прав доступа - это нормальное поведение системы безопасности

feat: настроен HTTPS для локальной разработки с mkcert
2025-08-01 04:51:06 +03:00

332 lines
17 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.
"""
Тесты для системы RBAC (Role-Based Access Control).
Проверяет работу с ролями, разрешениями и наследованием ролей.
"""
import pytest
import time
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_role_permissions_for_community,
get_permissions_for_role,
user_has_permission,
roles_have_permission
)
from services.db import local_session
@pytest.fixture
def test_users(db_session):
"""Создает тестовых пользователей"""
users = []
# Создаем пользователей с ID 1-5
for i in range(1, 6):
user = db_session.query(Author).where(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).where(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,
created_at=int(time.time())
)
db_session.add(community)
db_session.commit()
return community
class TestRBACRoleInheritance:
"""Тесты для проверки наследования ролей"""
@pytest.mark.asyncio
async def test_role_inheritance_author_inherits_reader(self, db_session, test_community):
"""Тест что роль author наследует разрешения от reader"""
# Инициализируем разрешения для сообщества
await initialize_community_permissions(test_community.id)
# Получаем разрешения для роли author
author_permissions = await get_permissions_for_role("author", test_community.id)
reader_permissions = await get_permissions_for_role("reader", test_community.id)
# Проверяем что author имеет все разрешения reader
for perm in reader_permissions:
assert perm in author_permissions, f"Author должен наследовать разрешение {perm} от reader"
# Проверяем что author имеет дополнительные разрешения
author_specific = ["draft:read", "draft:create", "shout:create", "shout:update"]
for perm in author_specific:
assert perm in author_permissions, f"Author должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_role_inheritance_editor_inherits_author(self, db_session, test_community):
"""Тест что роль editor наследует разрешения от author"""
await initialize_community_permissions(test_community.id)
editor_permissions = await get_permissions_for_role("editor", test_community.id)
author_permissions = await get_permissions_for_role("author", test_community.id)
# Проверяем что editor имеет все разрешения author
for perm in author_permissions:
assert perm in editor_permissions, f"Editor должен наследовать разрешение {perm} от author"
# Проверяем что editor имеет дополнительные разрешения
editor_specific = ["shout:delete_any", "shout:update_any", "topic:create", "community:create"]
for perm in editor_specific:
assert perm in editor_permissions, f"Editor должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_role_inheritance_admin_inherits_editor(self, db_session, test_community):
"""Тест что роль admin наследует разрешения от editor"""
await initialize_community_permissions(test_community.id)
admin_permissions = await get_permissions_for_role("admin", test_community.id)
editor_permissions = await get_permissions_for_role("editor", test_community.id)
# Проверяем что admin имеет все разрешения editor
for perm in editor_permissions:
assert perm in admin_permissions, f"Admin должен наследовать разрешение {perm} от editor"
# Проверяем что admin имеет дополнительные разрешения
admin_specific = ["author:delete_any", "author:update_any", "chat:delete_any", "message:delete_any"]
for perm in admin_specific:
assert perm in admin_permissions, f"Admin должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_role_inheritance_expert_inherits_reader(self, db_session, test_community):
"""Тест что роль expert наследует разрешения от reader"""
await initialize_community_permissions(test_community.id)
expert_permissions = await get_permissions_for_role("expert", test_community.id)
reader_permissions = await get_permissions_for_role("reader", test_community.id)
# Проверяем что expert имеет все разрешения reader
for perm in reader_permissions:
assert perm in expert_permissions, f"Expert должен наследовать разрешение {perm} от reader"
# Проверяем что expert имеет дополнительные разрешения
expert_specific = ["reaction:create:PROOF", "reaction:create:DISPROOF", "reaction:create:AGREE"]
for perm in expert_specific:
assert perm in expert_permissions, f"Expert должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_role_inheritance_artist_inherits_author(self, db_session, test_community):
"""Тест что роль artist наследует разрешения от author"""
await initialize_community_permissions(test_community.id)
artist_permissions = await get_permissions_for_role("artist", test_community.id)
author_permissions = await get_permissions_for_role("author", test_community.id)
# Проверяем что artist имеет все разрешения author
for perm in author_permissions:
assert perm in artist_permissions, f"Artist должен наследовать разрешение {perm} от author"
# Проверяем что artist имеет дополнительные разрешения
artist_specific = ["reaction:create:CREDIT", "reaction:read:CREDIT", "reaction:update:CREDIT"]
for perm in artist_specific:
assert perm in artist_permissions, f"Artist должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_role_inheritance_deep_inheritance(self, db_session, test_community):
"""Тест глубокого наследования: admin -> editor -> author -> reader"""
await initialize_community_permissions(test_community.id)
admin_permissions = await get_permissions_for_role("admin", test_community.id)
reader_permissions = await get_permissions_for_role("reader", test_community.id)
# Проверяем что admin имеет все разрешения reader через цепочку наследования
for perm in reader_permissions:
assert perm in admin_permissions, f"Admin должен наследовать разрешение {perm} через цепочку наследования"
@pytest.mark.asyncio
async def test_role_inheritance_no_circular_dependency(self, db_session, test_community):
"""Тест что нет циклических зависимостей в наследовании ролей"""
await initialize_community_permissions(test_community.id)
# Получаем все роли и проверяем что они корректно обрабатываются
all_roles = ["reader", "author", "artist", "expert", "editor", "admin"]
for role in all_roles:
permissions = await get_permissions_for_role(role, test_community.id)
# Проверяем что список разрешений не пустой и не содержит циклических ссылок
assert len(permissions) > 0, f"Роль {role} должна иметь разрешения"
assert role not in permissions, f"Роль {role} не должна ссылаться на саму себя"
class TestRBACPermissionChecking:
"""Тесты для проверки разрешений с учетом наследования"""
@pytest.mark.asyncio
async def test_user_with_author_role_has_reader_permissions(self, db_session, test_users, test_community):
"""Тест что пользователь с ролью author имеет разрешения reader"""
# Используем local_session для создания записи
from services.db import local_session
from orm.community import CommunityAuthor
with local_session() as session:
# Удаляем существующую запись если есть
existing_ca = session.query(CommunityAuthor).where(
CommunityAuthor.community_id == test_community.id,
CommunityAuthor.author_id == test_users[0].id
).first()
if existing_ca:
session.delete(existing_ca)
session.commit()
# Создаем новую запись
ca = CommunityAuthor(
community_id=test_community.id,
author_id=test_users[0].id,
roles="author"
)
session.add(ca)
session.commit()
await initialize_community_permissions(test_community.id)
# Проверяем что пользователь имеет разрешения reader
reader_permissions = ["shout:read", "topic:read", "collection:read", "chat:read"]
for perm in reader_permissions:
has_permission = await user_has_permission(test_users[0].id, perm, test_community.id)
assert has_permission, f"Пользователь с ролью author должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_user_with_editor_role_has_author_permissions(self, db_session, test_users, test_community):
"""Тест что пользователь с ролью editor имеет разрешения author"""
# Используем local_session для создания записи
from services.db import local_session
from orm.community import CommunityAuthor
with local_session() as session:
# Удаляем существующую запись если есть
existing_ca = session.query(CommunityAuthor).where(
CommunityAuthor.community_id == test_community.id,
CommunityAuthor.author_id == test_users[0].id
).first()
if existing_ca:
session.delete(existing_ca)
session.commit()
# Создаем новую запись
ca = CommunityAuthor(
community_id=test_community.id,
author_id=test_users[0].id,
roles="editor"
)
session.add(ca)
session.commit()
await initialize_community_permissions(test_community.id)
# Проверяем что пользователь имеет разрешения author
author_permissions = ["draft:create", "shout:create", "collection:create"]
for perm in author_permissions:
has_permission = await user_has_permission(test_users[0].id, perm, test_community.id)
assert has_permission, f"Пользователь с ролью editor должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_user_with_admin_role_has_all_permissions(self, db_session, test_users, test_community):
"""Тест что пользователь с ролью admin имеет все разрешения"""
# Используем local_session для создания записи
from services.db import local_session
from orm.community import CommunityAuthor
with local_session() as session:
# Удаляем существующую запись если есть
existing_ca = session.query(CommunityAuthor).where(
CommunityAuthor.community_id == test_community.id,
CommunityAuthor.author_id == test_users[0].id
).first()
if existing_ca:
session.delete(existing_ca)
session.commit()
# Создаем новую запись
ca = CommunityAuthor(
community_id=test_community.id,
author_id=test_users[0].id,
roles="admin"
)
session.add(ca)
session.commit()
await initialize_community_permissions(test_community.id)
# Проверяем разрешения разных уровней
all_permissions = [
"shout:read", # reader
"draft:create", # author
"shout:delete_any", # editor
"author:delete_any" # admin
]
for perm in all_permissions:
has_permission = await user_has_permission(test_users[0].id, perm, test_community.id)
assert has_permission, f"Пользователь с ролью admin должен иметь разрешение {perm}"
@pytest.mark.asyncio
async def test_roles_have_permission_with_inheritance(self, db_session, test_community):
"""Тест функции roles_have_permission с учетом наследования"""
await initialize_community_permissions(test_community.id)
# Проверяем что editor имеет разрешения author
has_author_permission = await roles_have_permission(["editor"], "draft:create", test_community.id)
assert has_author_permission, "Editor должен иметь разрешение draft:create через наследование от author"
# Проверяем что admin имеет разрешения reader
has_reader_permission = await roles_have_permission(["admin"], "shout:read", test_community.id)
assert has_reader_permission, "Admin должен иметь разрешение shout:read через наследование от reader"
class TestRBACInitialization:
"""Тесты для инициализации системы RBAC"""
@pytest.mark.asyncio
async def test_initialize_community_permissions(self, db_session, test_community):
"""Тест инициализации разрешений для сообщества"""
await initialize_community_permissions(test_community.id)
# Проверяем что разрешения инициализированы
permissions = await get_role_permissions_for_community(test_community.id)
assert permissions is not None
assert len(permissions) > 0
# Проверяем что все роли присутствуют
expected_roles = ["reader", "author", "artist", "expert", "editor", "admin"]
for role in expected_roles:
assert role in permissions, f"Роль {role} должна быть в инициализированных разрешениях"
@pytest.mark.asyncio
async def test_get_role_permissions_for_community_auto_init(self, db_session, test_community):
"""Тест автоматической инициализации при получении разрешений"""
# Получаем разрешения без предварительной инициализации
permissions = await get_role_permissions_for_community(test_community.id)
assert permissions is not None
assert len(permissions) > 0
# Проверяем что все роли присутствуют
expected_roles = ["reader", "author", "artist", "expert", "editor", "admin"]
for role in expected_roles:
assert role in permissions, f"Роль {role} должна быть в разрешениях"