### 🔄 Изменения - **SQLAlchemy KeyError** - исправление ошибки `KeyError: Reaction` при инициализации - **Исправлена ошибка SQLAlchemy**: Устранена проблема `InvalidRequestError: When initializing mapper Mapper[Shout(shout)], expression Reaction failed to locate a name (Reaction)` ### 🧪 Тестирование - **Исправление тестов** - адаптация к новой структуре моделей - **RBAC инициализация** - добавление `rbac.initialize_rbac()` в `conftest.py` - **Создан тест для getSession**: Добавлен комплексный тест `test_getSession_cookies.py` с проверкой всех сценариев - **Покрытие edge cases**: Тесты проверяют работу с валидными/невалидными токенами, отсутствующими пользователями - **Мокирование зависимостей**: Использование unittest.mock для изоляции тестируемого кода ### 🔧 Рефакторинг - **Упрощена архитектура**: Убраны сложные конструкции с отложенными импортами, заменены на чистую архитектуру - **Перемещение моделей** - `Author` и связанные модели перенесены в `orm/author.py`: Вынесены базовые модели пользователей (`Author`, `AuthorFollower`, `AuthorBookmark`, `AuthorRating`) из `orm.author` в отдельный модуль - **Устранены циклические импорты**: Разорван цикл между `auth.core` → `orm.community` → `orm.author` через реструктуризацию архитектуры - **Создан модуль `utils/password.py`**: Класс `Password` вынесен в utils для избежания циклических зависимостей - **Оптимизированы импорты моделей**: Убран прямой импорт `Shout` из `orm/community.py`, заменен на строковые ссылки ### 🔧 Авторизация с cookies - **getSession теперь работает с cookies**: Мутация `getSession` теперь может получать токен из httpOnly cookies даже без заголовка Authorization - **Убрано требование авторизации**: `getSession` больше не требует декоратор `@login_required`, работает автономно - **Поддержка dual-авторизации**: Токен может быть получен как из заголовка Authorization, так и из cookie `session_token` - **Автоматическая установка cookies**: Middleware автоматически устанавливает httpOnly cookies при успешном `getSession` - **Обновлена GraphQL схема**: `SessionInfo` теперь содержит поля `success`, `error` и опциональные `token`, `author` - **Единообразная обработка токенов**: Все модули теперь используют централизованные функции для работы с токенами - **Улучшена обработка ошибок**: Добавлена детальная валидация токенов и пользователей в `getSession` - **Логирование операций**: Добавлены подробные логи для отслеживания процесса авторизации ### 📝 Документация - **Обновлена схема GraphQL**: `SessionInfo` тип теперь соответствует новому формату ответа - Обновлена документация RBAC - Обновлена документация авторизации с cookies
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
from services.auth import AuthService
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_ensure_user_has_reader_role(db_session):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pytest
|
||||
from auth.password import Password
|
||||
from utils.password import Password
|
||||
|
||||
def test_password_verify():
|
||||
# Создаем пароль
|
||||
|
||||
@@ -6,7 +6,7 @@ import logging
|
||||
from starlette.responses import JSONResponse, RedirectResponse
|
||||
|
||||
from auth.oauth import get_user_profile, oauth_callback_http, oauth_login_http
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from storage.db import local_session
|
||||
|
||||
# Настройка логгера
|
||||
@@ -213,7 +213,7 @@ def oauth_db_session(db_session):
|
||||
@pytest.fixture
|
||||
def simple_user(oauth_db_session):
|
||||
"""Фикстура для простого пользователя"""
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
import time
|
||||
|
||||
# Создаем тестового пользователя
|
||||
|
||||
@@ -62,13 +62,17 @@ def test_engine():
|
||||
# Импортируем все модели, чтобы они были зарегистрированы
|
||||
from orm.base import BaseModel as Base
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.draft import Draft, DraftAuthor, DraftTopic
|
||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic, ShoutReactionsFollower
|
||||
from orm.topic import Topic
|
||||
from orm.reaction import Reaction
|
||||
from orm.invite import Invite
|
||||
from orm.notification import Notification
|
||||
|
||||
# Инициализируем RBAC систему
|
||||
import rbac
|
||||
rbac.initialize_rbac()
|
||||
|
||||
engine = create_engine(
|
||||
"sqlite:///:memory:", echo=False, poolclass=StaticPool, connect_args={"check_same_thread": False}
|
||||
@@ -121,7 +125,7 @@ def db_session(test_session_factory, test_engine):
|
||||
|
||||
# Создаем дефолтное сообщество для тестов
|
||||
from orm.community import Community
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
import time
|
||||
|
||||
# Создаем системного автора если его нет
|
||||
@@ -178,7 +182,7 @@ def db_session_commit(test_session_factory):
|
||||
|
||||
# Создаем дефолтное сообщество для тестов
|
||||
from orm.community import Community
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
|
||||
# Создаем системного автора если его нет
|
||||
system_author = session.query(Author).where(Author.slug == "system").first()
|
||||
@@ -429,7 +433,7 @@ def wait_for_server():
|
||||
@pytest.fixture
|
||||
def test_users(db_session):
|
||||
"""Создает тестовых пользователей для тестов"""
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
|
||||
# Создаем первого пользователя (администратор)
|
||||
admin_user = Author(
|
||||
|
||||
@@ -9,7 +9,7 @@ import pytest
|
||||
import time
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from storage.db import local_session
|
||||
|
||||
@@ -291,7 +291,7 @@ class TestPermissionSystem:
|
||||
|
||||
def test_admin_permissions(self, db_session, admin_user_with_roles, test_community):
|
||||
"""Тест разрешений администратора"""
|
||||
from auth.permissions import ContextualPermissionCheck
|
||||
from rbac.permissions import ContextualPermissionCheck
|
||||
|
||||
# Проверяем что администратор имеет все разрешения
|
||||
permissions_to_check = [
|
||||
@@ -314,7 +314,7 @@ class TestPermissionSystem:
|
||||
|
||||
def test_regular_user_permissions(self, db_session, regular_user_with_roles, test_community):
|
||||
"""Тест разрешений обычного пользователя"""
|
||||
from auth.permissions import ContextualPermissionCheck
|
||||
from rbac.permissions import ContextualPermissionCheck
|
||||
|
||||
# Проверяем что обычный пользователь имеет роли reader и author
|
||||
ca = CommunityAuthor.find_author_in_community(
|
||||
@@ -331,7 +331,7 @@ class TestPermissionSystem:
|
||||
|
||||
def test_permission_without_community_author(self, db_session, test_users, test_community):
|
||||
"""Тест разрешений для пользователя без CommunityAuthor"""
|
||||
from auth.permissions import ContextualPermissionCheck
|
||||
from rbac.permissions import ContextualPermissionCheck
|
||||
|
||||
# Проверяем разрешения для пользователя без ролей в сообществе
|
||||
has_permission = ContextualPermissionCheck.check_permission(
|
||||
|
||||
@@ -11,7 +11,7 @@ async def test_admin_permissions():
|
||||
"""Проверяем, что у роли admin есть все необходимые права"""
|
||||
|
||||
# Загружаем дефолтные права
|
||||
with Path("services/default_role_permissions.json").open() as f:
|
||||
with Path("rbac/default_role_permissions.json").open() as f:
|
||||
default_permissions = json.load(f)
|
||||
|
||||
# Получаем права роли admin
|
||||
|
||||
@@ -7,7 +7,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
# Импортируем модули auth для покрытия
|
||||
import auth.__init__
|
||||
import auth.permissions
|
||||
import rbac.permissions
|
||||
import auth.decorators
|
||||
import auth.oauth
|
||||
import auth.state
|
||||
@@ -17,7 +17,7 @@ import auth.jwtcodec
|
||||
import auth.email
|
||||
import auth.exceptions
|
||||
import auth.validations
|
||||
import auth.orm
|
||||
import orm.author
|
||||
import auth.credentials
|
||||
import auth.handler
|
||||
import auth.internal
|
||||
@@ -39,18 +39,18 @@ class TestAuthInit:
|
||||
|
||||
|
||||
class TestAuthPermissions:
|
||||
"""Тесты для auth.permissions"""
|
||||
"""Тесты для rbac.permissions"""
|
||||
|
||||
def test_permissions_import(self):
|
||||
"""Тест импорта permissions"""
|
||||
import auth.permissions
|
||||
assert auth.permissions is not None
|
||||
import rbac.permissions
|
||||
assert rbac.permissions is not None
|
||||
|
||||
def test_permissions_functions_exist(self):
|
||||
"""Тест существования функций permissions"""
|
||||
import auth.permissions
|
||||
import rbac.permissions
|
||||
# Проверяем что модуль импортируется без ошибок
|
||||
assert auth.permissions is not None
|
||||
assert rbac.permissions is not None
|
||||
|
||||
|
||||
class TestAuthDecorators:
|
||||
@@ -189,16 +189,16 @@ class TestAuthValidations:
|
||||
|
||||
|
||||
class TestAuthORM:
|
||||
"""Тесты для auth.orm"""
|
||||
"""Тесты для orm.author"""
|
||||
|
||||
def test_orm_import(self):
|
||||
"""Тест импорта orm"""
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
assert Author is not None
|
||||
|
||||
def test_orm_functions_exist(self):
|
||||
"""Тест существования функций orm"""
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
# Проверяем что модель Author существует
|
||||
assert Author is not None
|
||||
assert hasattr(Author, 'id')
|
||||
|
||||
@@ -8,11 +8,10 @@ import pytest
|
||||
import time
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from auth.orm import Author, AuthorBookmark, AuthorRating, AuthorFollower
|
||||
from orm.author import Author, AuthorBookmark, AuthorRating, AuthorFollower
|
||||
from auth.internal import verify_internal_auth
|
||||
from auth.permissions import ContextualPermissionCheck
|
||||
from rbac.permissions import ContextualPermissionCheck
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from auth.permissions import ContextualPermissionCheck
|
||||
from storage.db import local_session
|
||||
|
||||
|
||||
@@ -69,7 +68,7 @@ class TestAuthORMFixes:
|
||||
rating = AuthorRating(
|
||||
rater=test_users[0].id,
|
||||
author=test_users[1].id,
|
||||
plus=True
|
||||
rating=5 # Используем поле rating вместо plus
|
||||
)
|
||||
db_session.add(rating)
|
||||
db_session.commit()
|
||||
@@ -83,15 +82,15 @@ class TestAuthORMFixes:
|
||||
assert saved_rating is not None
|
||||
assert saved_rating.rater == test_users[0].id
|
||||
assert saved_rating.author == test_users[1].id
|
||||
assert saved_rating.plus is True
|
||||
assert saved_rating.rating == 5 # Проверяем поле rating
|
||||
|
||||
def test_author_follower_creation(self, db_session, test_users):
|
||||
"""Тест создания подписки автора"""
|
||||
follower = AuthorFollower(
|
||||
follower=test_users[0].id,
|
||||
author=test_users[1].id,
|
||||
created_at=int(time.time()),
|
||||
auto=False
|
||||
following=test_users[1].id, # Используем поле following вместо author
|
||||
created_at=int(time.time())
|
||||
# Убрано поле auto, которого нет в новой модели
|
||||
)
|
||||
db_session.add(follower)
|
||||
db_session.commit()
|
||||
@@ -99,13 +98,13 @@ class TestAuthORMFixes:
|
||||
# Проверяем что подписка создана
|
||||
saved_follower = db_session.query(AuthorFollower).where(
|
||||
AuthorFollower.follower == test_users[0].id,
|
||||
AuthorFollower.author == test_users[1].id
|
||||
AuthorFollower.following == test_users[1].id # Используем поле following
|
||||
).first()
|
||||
|
||||
assert saved_follower is not None
|
||||
assert saved_follower.follower == test_users[0].id
|
||||
assert saved_follower.author == test_users[1].id
|
||||
assert saved_follower.auto is False
|
||||
assert saved_follower.following == test_users[1].id # Проверяем поле following
|
||||
# Убрана проверка поля auto
|
||||
|
||||
def test_author_oauth_methods(self, db_session, test_users):
|
||||
"""Тест методов работы с OAuth"""
|
||||
@@ -145,10 +144,6 @@ class TestAuthORMFixes:
|
||||
"""Тест метода dict() для сериализации"""
|
||||
user = test_users[0]
|
||||
|
||||
# Добавляем роли
|
||||
user.roles_data = {"1": ["reader", "author"]}
|
||||
db_session.commit()
|
||||
|
||||
# Получаем словарь
|
||||
user_dict = user.dict()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import pytest
|
||||
import time
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import (
|
||||
Community,
|
||||
CommunityAuthor,
|
||||
|
||||
@@ -8,7 +8,7 @@ import pytest
|
||||
import time
|
||||
from sqlalchemy import text
|
||||
from orm.community import Community, CommunityAuthor, CommunityFollower
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
|
||||
|
||||
class TestCommunityFunctionality:
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
import uuid
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from rbac.api import (
|
||||
initialize_community_permissions,
|
||||
|
||||
@@ -12,7 +12,7 @@ from starlette.routing import Route
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
# Импортируем все модели чтобы SQLAlchemy знал о них
|
||||
from auth.orm import ( # noqa: F401
|
||||
from orm.author import ( # noqa: F401
|
||||
Author,
|
||||
AuthorBookmark,
|
||||
AuthorFollower,
|
||||
|
||||
@@ -61,7 +61,7 @@ import resolvers.admin
|
||||
|
||||
import auth
|
||||
import auth.__init__
|
||||
import auth.permissions
|
||||
import rbac.permissions
|
||||
import auth.decorators
|
||||
import auth.oauth
|
||||
import auth.state
|
||||
@@ -71,7 +71,7 @@ import auth.jwtcodec
|
||||
import auth.email
|
||||
import auth.exceptions
|
||||
import auth.validations
|
||||
import auth.orm
|
||||
import orm.author
|
||||
import auth.credentials
|
||||
import auth.handler
|
||||
import auth.internal
|
||||
@@ -147,7 +147,7 @@ class TestCoverageImports:
|
||||
"""Тест импорта модулей auth"""
|
||||
assert auth is not None
|
||||
assert auth.__init__ is not None
|
||||
assert auth.permissions is not None
|
||||
assert rbac.permissions is not None
|
||||
assert auth.decorators is not None
|
||||
assert auth.oauth is not None
|
||||
assert auth.state is not None
|
||||
@@ -157,7 +157,7 @@ class TestCoverageImports:
|
||||
assert auth.email is not None
|
||||
assert auth.exceptions is not None
|
||||
assert auth.validations is not None
|
||||
assert auth.orm is not None
|
||||
assert orm.author is not None
|
||||
assert auth.credentials is not None
|
||||
assert auth.handler is not None
|
||||
assert auth.internal is not None
|
||||
|
||||
@@ -60,7 +60,7 @@ class TestDatabaseFunctions:
|
||||
|
||||
# Проверяем, что сессия работает с существующими таблицами
|
||||
# Используем Author вместо TestModel
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
authors_count = session.query(Author).count()
|
||||
assert isinstance(authors_count, int)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.shout import Shout
|
||||
from resolvers.draft import create_draft, load_drafts
|
||||
|
||||
276
tests/test_getSession_cookies.py
Normal file
276
tests/test_getSession_cookies.py
Normal file
@@ -0,0 +1,276 @@
|
||||
"""
|
||||
Тест для проверки работы getSession с cookies
|
||||
|
||||
Проверяет:
|
||||
1. getSession работает без токена в заголовке, но с валидным cookie
|
||||
2. getSession возвращает данные пользователя при валидном cookie
|
||||
3. getSession возвращает ошибку при невалидном cookie
|
||||
4. getSession работает с токеном в заголовке
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch, MagicMock
|
||||
from graphql import GraphQLResolveInfo
|
||||
|
||||
from resolvers.auth import get_session
|
||||
from auth.tokens.storage import TokenStorage as TokenManager
|
||||
from orm.author import Author
|
||||
|
||||
|
||||
class MockRequest:
|
||||
"""Мок для Request объекта"""
|
||||
|
||||
def __init__(self, headers=None, cookies=None):
|
||||
self.headers = headers or {}
|
||||
self.cookies = cookies or {}
|
||||
|
||||
|
||||
class MockContext:
|
||||
"""Мок для GraphQL контекста"""
|
||||
|
||||
def __init__(self, request=None):
|
||||
self.request = request
|
||||
|
||||
def get(self, key, default=None):
|
||||
"""Мокаем метод get для совместимости с DRY функциями"""
|
||||
if key == "request":
|
||||
return self.request
|
||||
return default
|
||||
|
||||
|
||||
class MockGraphQLResolveInfo:
|
||||
"""Мок для GraphQLResolveInfo"""
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_author():
|
||||
"""Мок для объекта Author"""
|
||||
author = MagicMock(spec=Author)
|
||||
author.id = 123
|
||||
author.email = "test@example.com"
|
||||
author.name = "Test User"
|
||||
author.slug = "test-user"
|
||||
author.username = "testuser"
|
||||
|
||||
# Мокаем метод dict()
|
||||
author.dict.return_value = {
|
||||
"id": 123,
|
||||
"email": "test@example.com",
|
||||
"name": "Test User",
|
||||
"slug": "test-user",
|
||||
"username": "testuser"
|
||||
}
|
||||
|
||||
return author
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_payload():
|
||||
"""Мок для payload токена"""
|
||||
payload = MagicMock()
|
||||
payload.user_id = "123"
|
||||
return payload
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_with_valid_cookie(mock_author, mock_payload):
|
||||
"""Тест getSession с валидным cookie"""
|
||||
|
||||
# Мокаем request с cookie
|
||||
request = MockRequest(
|
||||
headers={},
|
||||
cookies={"session_token": "valid_token_123"}
|
||||
)
|
||||
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token, \
|
||||
patch('resolvers.auth.get_user_data_by_token') as mock_get_user_data:
|
||||
|
||||
mock_get_token.return_value = "valid_token_123"
|
||||
mock_get_user_data.return_value = (True, mock_author.dict(), None)
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is True
|
||||
assert result["token"] == "valid_token_123"
|
||||
assert result["author"]["id"] == 123
|
||||
assert result["author"]["email"] == "test@example.com"
|
||||
assert result["error"] is None
|
||||
|
||||
# Проверяем вызовы DRY функций
|
||||
mock_get_token.assert_called_once_with(info)
|
||||
mock_get_user_data.assert_called_once_with("valid_token_123")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_with_authorization_header(mock_author, mock_payload):
|
||||
"""Тест getSession с заголовком Authorization"""
|
||||
|
||||
# Мокаем request с заголовком Authorization
|
||||
request = MockRequest(
|
||||
headers={"authorization": "Bearer bearer_token_456"},
|
||||
cookies={}
|
||||
)
|
||||
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token, \
|
||||
patch('resolvers.auth.get_user_data_by_token') as mock_get_user_data:
|
||||
|
||||
mock_get_token.return_value = "bearer_token_456"
|
||||
mock_get_user_data.return_value = (True, mock_author.dict(), None)
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is True
|
||||
assert result["token"] == "bearer_token_456"
|
||||
assert result["author"]["id"] == 123
|
||||
assert result["error"] is None
|
||||
|
||||
# Проверяем вызовы DRY функций
|
||||
mock_get_token.assert_called_once_with(info)
|
||||
mock_get_user_data.assert_called_once_with("bearer_token_456")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_with_invalid_token(mock_author):
|
||||
"""Тест getSession с невалидным токеном"""
|
||||
|
||||
# Мокаем request с невалидным cookie
|
||||
request = MockRequest(
|
||||
headers={},
|
||||
cookies={"session_token": "invalid_token"}
|
||||
)
|
||||
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token, \
|
||||
patch('resolvers.auth.get_user_data_by_token') as mock_get_user_data:
|
||||
|
||||
mock_get_token.return_value = "invalid_token"
|
||||
mock_get_user_data.return_value = (False, None, "Сессия не найдена")
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is False
|
||||
assert result["token"] is None
|
||||
assert result["author"] is None
|
||||
assert result["error"] == "Сессия не найдена"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_without_token():
|
||||
"""Тест getSession без токена"""
|
||||
|
||||
# Мокаем request без токена
|
||||
request = MockRequest(headers={}, cookies={})
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token:
|
||||
mock_get_token.return_value = None
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is False
|
||||
assert result["token"] is None
|
||||
assert result["author"] is None
|
||||
assert result["error"] == "Сессия не найдена"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_without_request():
|
||||
"""Тест getSession без request в контексте"""
|
||||
|
||||
# Мокаем контекст без request
|
||||
context = MockContext(request=None)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token:
|
||||
mock_get_token.return_value = None
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is False
|
||||
assert result["token"] is None
|
||||
assert result["author"] is None
|
||||
assert result["error"] == "Сессия не найдена"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_user_not_found(mock_payload):
|
||||
"""Тест getSession когда пользователь не найден в БД"""
|
||||
|
||||
# Мокаем request с валидным cookie
|
||||
request = MockRequest(
|
||||
headers={},
|
||||
cookies={"session_token": "valid_token_123"}
|
||||
)
|
||||
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token, \
|
||||
patch('resolvers.auth.get_user_data_by_token') as mock_get_user_data:
|
||||
|
||||
mock_get_token.return_value = "valid_token_123"
|
||||
mock_get_user_data.return_value = (False, None, f"Пользователь с ID 123 не найден в БД")
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is False
|
||||
assert result["token"] is None
|
||||
assert result["author"] is None
|
||||
assert result["error"] == "Пользователь с ID 123 не найден в БД"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_getSession_payload_without_user_id():
|
||||
"""Тест getSession когда payload не содержит user_id"""
|
||||
|
||||
# Мокаем request с валидным cookie
|
||||
request = MockRequest(
|
||||
headers={},
|
||||
cookies={"session_token": "valid_token_123"}
|
||||
)
|
||||
|
||||
context = MockContext(request)
|
||||
info = MockGraphQLResolveInfo(context)
|
||||
|
||||
# Мокаем DRY функции из auth/utils.py
|
||||
with patch('resolvers.auth.get_auth_token_from_context') as mock_get_token, \
|
||||
patch('resolvers.auth.get_user_data_by_token') as mock_get_user_data:
|
||||
|
||||
mock_get_token.return_value = "valid_token_123"
|
||||
mock_get_user_data.return_value = (False, None, "Токен не содержит user_id")
|
||||
|
||||
result = await get_session(None, info)
|
||||
|
||||
# Проверяем результат
|
||||
assert result["success"] is False
|
||||
assert result["token"] is None
|
||||
assert result["author"] is None
|
||||
assert result["error"] == "Токен не содержит user_id"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
from unittest.mock import patch, MagicMock
|
||||
import json
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from rbac.api import (
|
||||
initialize_community_permissions,
|
||||
|
||||
@@ -8,7 +8,7 @@ import pytest
|
||||
import time
|
||||
from unittest.mock import patch, MagicMock
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import Community, CommunityAuthor
|
||||
from rbac.api import (
|
||||
initialize_community_permissions,
|
||||
|
||||
@@ -2,7 +2,7 @@ from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.reaction import ReactionKind
|
||||
from orm.shout import Shout
|
||||
|
||||
@@ -2,7 +2,7 @@ from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import CommunityAuthor
|
||||
from orm.shout import Shout
|
||||
from resolvers.reader import get_shout
|
||||
|
||||
@@ -18,7 +18,7 @@ import pytest
|
||||
|
||||
sys.path.append(str(Path(__file__).parent))
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from orm.community import assign_role_to_user
|
||||
from orm.shout import Shout
|
||||
from resolvers.editor import unpublish_shout
|
||||
|
||||
@@ -16,7 +16,7 @@ from typing import Any
|
||||
|
||||
sys.path.append(str(Path(__file__).parent))
|
||||
|
||||
from auth.orm import Author
|
||||
from orm.author import Author
|
||||
from resolvers.auth import update_security
|
||||
from storage.db import local_session
|
||||
|
||||
|
||||
Reference in New Issue
Block a user