Инспекция кода
This commit is contained in:
@@ -1,260 +0,0 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Описание класса CoreTestCase
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.test import TestCase
|
||||
from rest_framework.parsers import JSONParser
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
from net.xeaf.rack.enums import HttpMethod
|
||||
from net.xeaf.rack.management.userstory import AccountTestData
|
||||
from net.xeaf.rack.management.userstory import SessionTestData
|
||||
from net.xeaf.rack.managers import SessionManager
|
||||
from net.xeaf.rack.models import AccountModel
|
||||
from net.xeaf.rack.models import SessionModel
|
||||
|
||||
|
||||
class CoreTestCase(TestCase):
|
||||
"""
|
||||
Реализует инициализацию тестовой базы данных перед каждым тестом
|
||||
"""
|
||||
|
||||
factory: APIRequestFactory
|
||||
""" Фабрика запросов """
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Подготовка к тестированию
|
||||
"""
|
||||
|
||||
call_command("rack_test_database")
|
||||
self.factory = APIRequestFactory()
|
||||
|
||||
def create_request(self,
|
||||
method: HttpMethod,
|
||||
path: str,
|
||||
headers: dict[str, str] | None = None,
|
||||
data: dict[str, Any] | None = None,
|
||||
query_params: dict[str, str] | None = None,
|
||||
auth: SessionModel | None = None) -> Request:
|
||||
"""
|
||||
Создает объект запроса для тестирования
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
:param headers: Заголовки запроса
|
||||
:param data: Данные для тела запроса
|
||||
:param query_params: Параметры запроса
|
||||
:param auth: Объект аутентификации (сессия)
|
||||
|
||||
:return: DRF Request объект
|
||||
"""
|
||||
|
||||
# Уточняем значения параметров
|
||||
headers = self.__prepare_headers(headers or {})
|
||||
query_params = query_params or {}
|
||||
data = data or {}
|
||||
|
||||
# Создаем внутренний объект запроса
|
||||
match method:
|
||||
case HttpMethod.GET:
|
||||
wsgi_request = self.factory.get(path, data=query_params, **headers)
|
||||
case HttpMethod.POST:
|
||||
wsgi_request = self.factory.post(path, data=data, format='json', **headers)
|
||||
case HttpMethod.PUT:
|
||||
wsgi_request = self.factory.put(path, data=data, format='json', **headers)
|
||||
case HttpMethod.PATCH:
|
||||
wsgi_request = self.factory.patch(path, data=data, format='json', **headers)
|
||||
case HttpMethod.DELETE:
|
||||
wsgi_request = self.factory.delete(path, **headers)
|
||||
case _:
|
||||
wsgi_request = self.factory.generic(
|
||||
method,
|
||||
path,
|
||||
content_type='application/json',
|
||||
data=json.dumps(data) if data else ''
|
||||
)
|
||||
|
||||
# Преобразуем к объекту запроса DRF
|
||||
drf_request = Request(wsgi_request, parsers=[JSONParser()])
|
||||
|
||||
if method != HttpMethod.GET:
|
||||
self.__assign_query_params(drf_request, query_params)
|
||||
self.__assign_auth(drf_request, auth)
|
||||
|
||||
return drf_request
|
||||
|
||||
def create_authenticated_request(self,
|
||||
method: HttpMethod,
|
||||
path: str,
|
||||
headers: dict[str, str] | None = None,
|
||||
data: dict[str, Any] | None = None,
|
||||
query_params: dict[str, str] | None = None,
|
||||
token: str | None = None) -> Request:
|
||||
"""
|
||||
Создает объект авторизованного запроса для тестирования
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
:param headers: Заголовки запроса
|
||||
:param data: Данные для тела запроса
|
||||
:param query_params: Параметры запроса
|
||||
:param token: Токен сессии авторизации
|
||||
|
||||
:return: DRF Request объект
|
||||
"""
|
||||
|
||||
# Получаем сессию
|
||||
if token is None:
|
||||
session = None
|
||||
else:
|
||||
session = SessionManager.find_by_token(token)
|
||||
|
||||
# Возвращаем объект запроса
|
||||
return self.create_request(method=method, path=path, headers=headers, data=data, query_params=query_params, auth=session)
|
||||
|
||||
@classmethod
|
||||
def __prepare_headers(cls, headers: dict[str, str]) -> dict[str, str]:
|
||||
"""
|
||||
Подготавливаем объект заголовков для передачи в фабрику
|
||||
|
||||
:param headers: Заголовки запроса
|
||||
|
||||
:return: Объект заголовков для фабрики
|
||||
"""
|
||||
|
||||
wsgi_headers = {}
|
||||
for key, value in headers.items():
|
||||
if key.startswith('HTTP_'):
|
||||
wsgi_headers[key] = value
|
||||
else:
|
||||
norm_key = key.upper().replace('-', '_')
|
||||
if norm_key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
|
||||
wsgi_headers[norm_key.lower()] = value
|
||||
else:
|
||||
wsgi_headers[f'HTTP_{norm_key}'] = value
|
||||
|
||||
return wsgi_headers
|
||||
|
||||
@classmethod
|
||||
def __assign_query_params(cls, request: Request, query_params: dict[str, Any]) -> None:
|
||||
"""
|
||||
Присваивает параметры запроса в DRF Request объект
|
||||
|
||||
:param request: DRF Request объект
|
||||
:param query_params: Параметры запроса
|
||||
"""
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
request.query_params._mutable = True
|
||||
for key, value in query_params.items():
|
||||
request.query_params[key] = value
|
||||
request.query_params._mutable = False
|
||||
|
||||
@classmethod
|
||||
def __assign_auth(cls, request: Request, auth: SessionModel | None) -> None:
|
||||
"""
|
||||
Присваивает аутентификацию в DRF Request объект
|
||||
|
||||
:param request: Объект запроса
|
||||
:param auth: Объект сессии пользователя
|
||||
"""
|
||||
|
||||
if auth:
|
||||
request.auth = auth
|
||||
if hasattr(auth, 'account'):
|
||||
request.user = auth.account
|
||||
|
||||
@classmethod
|
||||
def get_i_ivanov_account(cls) -> AccountModel:
|
||||
"""
|
||||
Возвращает аккаунт Ивана И. Иванова
|
||||
|
||||
:return: Аккаунт Ивана И. Иванова
|
||||
"""
|
||||
|
||||
return AccountTestData.get_i_ivanov_account()
|
||||
|
||||
@classmethod
|
||||
def get_i_ivanov_session(cls) -> SessionModel:
|
||||
"""
|
||||
Возвращает сессию Ивана И. Иванова
|
||||
|
||||
:return: Сессия Ивана И. Иванова
|
||||
"""
|
||||
|
||||
return SessionTestData.get_i_ivanov_session()
|
||||
|
||||
def create_i_ivanov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
"""
|
||||
Создает запрос от имени Ивана И. Иванова
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
:param headers: Заголовки запроса
|
||||
:param data: Данные для тела запроса
|
||||
:param query_params: Параметры запроса
|
||||
|
||||
:return: Объект запроса с аутентификацией Ивана И. Иванова
|
||||
"""
|
||||
|
||||
return self.create_authenticated_request(
|
||||
method=method,
|
||||
path=path,
|
||||
headers=headers,
|
||||
data=data,
|
||||
query_params=query_params,
|
||||
token=SessionTestData.I_IVANOV_SESSION_TOKEN,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_p_petrov_account(cls) -> AccountModel:
|
||||
"""
|
||||
Возвращает аккаунт Петра П. Петрова
|
||||
|
||||
:return: Аккаунт Петра П. Петрова
|
||||
"""
|
||||
return AccountTestData.get_p_petrov_account()
|
||||
|
||||
@classmethod
|
||||
def get_p_petrov_session(cls) -> SessionModel:
|
||||
"""
|
||||
Возвращает сессию Петра П. Петрова
|
||||
|
||||
:return: Сессия Петра П. Петрова
|
||||
"""
|
||||
|
||||
return SessionTestData.get_p_petrov_session()
|
||||
|
||||
def create_p_petrov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
"""
|
||||
Создает запрос от имени Петра П. Петрова
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
:param headers: Заголовки запроса
|
||||
:param data: Данные для тела запроса
|
||||
:param query_params: Параметры запроса
|
||||
|
||||
:return: Объект запроса с аутентификацией Петра П. Петрова
|
||||
"""
|
||||
|
||||
return self.create_authenticated_request(
|
||||
method=method,
|
||||
path=path,
|
||||
headers=headers,
|
||||
data=data,
|
||||
query_params=query_params,
|
||||
token=SessionTestData.P_PETROV_SESSION_TOKEN
|
||||
)
|
||||
@@ -16,7 +16,7 @@ from rest_framework.request import Request
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
from net.xeaf.rack.enums import HttpMethod
|
||||
from net.xeaf.rack.management.userstory import SessionTestData
|
||||
from net.xeaf.rack.models.user_story import SessionTestData
|
||||
from .request_test_case_mixin import RequestTestCaseMixin
|
||||
|
||||
|
||||
@@ -33,9 +33,10 @@ class CoreUserStoryTestCase(TestCase, RequestTestCaseMixin):
|
||||
call_command("rack_test_database")
|
||||
self.factory = APIRequestFactory()
|
||||
|
||||
def create_i_ivanov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
def create_ivanov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None,
|
||||
data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
"""
|
||||
Создает запрос от имени Ивана И. Иванова
|
||||
Создает запрос от имени Ивана Иванова
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
@@ -55,9 +56,10 @@ class CoreUserStoryTestCase(TestCase, RequestTestCaseMixin):
|
||||
token=SessionTestData.IVANOV_SESSION_TOKEN,
|
||||
)
|
||||
|
||||
def create_p_petrov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
def create_petrov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None,
|
||||
data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
|
||||
"""
|
||||
Создает запрос от имени Петра П. Петрова
|
||||
Создает запрос от имени Петра Петрова
|
||||
|
||||
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
|
||||
:param path: URL путь
|
||||
|
||||
@@ -21,8 +21,8 @@ from django.conf import settings
|
||||
from django.core.management import CommandError
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
from ._coverage_structure_visitor import CoverageStructureVisitor
|
||||
from ._coverage_test_file_visitor import CoverageTestFileVisitor
|
||||
from net.xeaf.rack.utils.management import CoverageStructureVisitor
|
||||
from net.xeaf.rack.utils.management import CoverageTestFileVisitor
|
||||
|
||||
|
||||
class Command(CoreCommand):
|
||||
|
||||
@@ -12,8 +12,8 @@ from django.core.management import call_command
|
||||
from django.core.management.base import no_translations
|
||||
|
||||
from net.xeaf.rack.core import CoreCommand
|
||||
from net.xeaf.rack.management.userstory import AccountTestData
|
||||
from net.xeaf.rack.management.userstory import SessionTestData
|
||||
from net.xeaf.rack.models.user_story import AccountTestData
|
||||
from net.xeaf.rack.models.user_story import SessionTestData
|
||||
|
||||
|
||||
class Command(CoreCommand):
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"""
|
||||
Описание класса ExpiredAtMixin
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Пакет классов создания тестовой БД
|
||||
Пакет описания классов инициализации моделей тестовых данных
|
||||
"""
|
||||
|
||||
from .account_test_data import AccountTestData
|
||||
0
net/xeaf/rack/userstory/__init__.py
Normal file
0
net/xeaf/rack/userstory/__init__.py
Normal file
@@ -28,7 +28,7 @@ class ExpiringTokenAuthentication(TokenAuthentication):
|
||||
AUTH_TOKEN_PARAM = "x-auth-token"
|
||||
""" Идентификатор параметра токена """
|
||||
|
||||
def authenticate(self, request: Request) -> tuple[AccountModel | None, CoreSessionModel | None] | tuple[Any, Any] | None:
|
||||
def authenticate(self, request: Request) -> tuple[AccountModel | None, SessionModel | None] | tuple[Any, Any] | None:
|
||||
"""
|
||||
Метод авторизации
|
||||
|
||||
@@ -43,7 +43,7 @@ class ExpiringTokenAuthentication(TokenAuthentication):
|
||||
|
||||
return super().authenticate(request)
|
||||
|
||||
def authenticate_credentials(self, key: str) -> tuple[AccountModel | None, CoreSessionModel | None]:
|
||||
def authenticate_credentials(self, key: str) -> tuple[AccountModel | None, SessionModel | None]:
|
||||
"""
|
||||
Проверка Токена авторизации
|
||||
|
||||
|
||||
12
net/xeaf/rack/utils/management/__init__.py
Normal file
12
net/xeaf/rack/utils/management/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# DRF Rack
|
||||
# Библиотека классов расширений для Django REST Framework
|
||||
#
|
||||
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
|
||||
# Все права защищены. Лицензия: MIT
|
||||
|
||||
"""
|
||||
Пакет служебных классов для создания команд управления
|
||||
"""
|
||||
|
||||
from .coverage_structure_visitor import CoverageStructureVisitor
|
||||
from .coverage_test_file_visitor import CoverageTestFileVisitor
|
||||
Reference in New Issue
Block a user