From 473f28fae19ba9eb64290c6f979df65931802fc7 Mon Sep 17 00:00:00 2001 From: Obrams Date: Sun, 21 Dec 2025 22:16:11 +0300 Subject: [PATCH 1/2] Enhance README with detailed design and architecture overview, including client implementations for REST, GraphQL, gRPC, and Kafka, along with testing strategies and stability improvements. --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index a8580d7..8c6fefe 100644 --- a/README.md +++ b/README.md @@ -415,6 +415,36 @@ send_result, received = helper.send_and_receive("topic", {"data": "test"}) client.close() ``` +## Design/Architecture + +Проект демонстрирует не только умение писать тесты, но и способность строить общий инфраструктурный слой для разных типов интеграций. Каждый клиент решает специфичные задачи своей области и предоставляет единообразный интерфейс для тестов. + +### RestClient + +**Sync/Async поддержка:** Единый класс с lazy initialization для синхронного (`httpx.Client`) и асинхронного (`httpx.AsyncClient`) клиентов. Методы `get/post/put/delete` для sync, `aget/apost/aput/adelete` для async. Оба клиента создаются только при первом обращении через `@property`. + +**Retry механизм:** Все HTTP методы обёрнуты декоратором `@retry()` с экспоненциальной задержкой. Настраивается через `config.settings` (количество попыток, минимальная/максимальная задержка). Автоматически обрабатывает сетевые ошибки и временные сбои. + +**Хуки для логирования:** Структурированное логирование через `structlog` на уровне каждого запроса/ответа. Логируются endpoint, параметры, статус-коды. Поддержка Pydantic моделей через `_serialize()` — автоматическая конвертация в JSON. + +### GraphQLClient + +**Работа со схемами/queries:** Поддержка загрузки схемы через `fetch_schema_from_transport`. Выполнение запросов из файлов через `execute_from_file()` для переиспользования `.graphql` файлов. Методы `query()` и `mutate()` как семантические обёртки над `execute()`. Поддержка subscriptions через WebSocket транспорт. + +**Стратегия обработки ошибок:** GraphQL специфична — ошибки могут быть в `errors` массиве при HTTP 200. Клиент логирует предупреждения, но не бросает исключения (в отличие от HTTP ошибок). Метод `raw_request()` для тестирования негативных сценариев — возвращает `httpx.Response` для проверки статус-кодов и тела ответа. + +### GrpcClient + +**Единый helper вокруг stubs и методов:** Абстракция над низкоуровневыми gRPC stub'ами. Методы `unary_call()`, `server_streaming()`, `client_streaming()`, `bidirectional_streaming()` принимают `stub_class` и `method_name` как параметры — не нужно создавать stub'ы вручную. Lazy initialization канала через `@property channel` с поддержкой secure/insecure соединений. + +**Работа со streaming:** Все типы streaming (server, client, bidirectional) реализованы через генераторы. `server_streaming()` и `bidirectional_streaming()` возвращают `Iterator[Message]`, `client_streaming()` принимает `Iterator[Message]` как входной параметр. Единообразная обработка метаданных и таймаутов для всех типов вызовов. + +### KafkaClient + KafkaTestHelper + +**Решение проблемы «дождаться сообщения»:** Метод `consume_until()` с предикатом — получает сообщения до тех пор, пока условие не выполнится или не истечёт таймаут. `KafkaTestHelper.wait_for_message()` — высокоуровневая обёртка для ожидания сообщения по ключу или значению поля. Избегает проблем с порядком сообщений и race conditions. + +**Стабильность тестов:** Каждый consumer создаётся с уникальным `group_id` (через фикстуры с UUID) — изоляция тестов друг от друга. `consume_one()` и `consume_batch()` создают временные consumer'ы и закрывают их автоматически — нет утечек соединений. `send_and_receive()` в helper'е — атомарная операция отправки и получения для E2E тестов. Поддержка `auto_offset_reset="earliest"` для чтения всех сообщений в топике. + ## Примеры тестов ### REST тест From b4b5c9913fc56b7e3100ecf0f4581ac7d44ff5a0 Mon Sep 17 00:00:00 2001 From: Obrams Date: Sun, 21 Dec 2025 22:18:34 +0300 Subject: [PATCH 2/2] fix: add email-validator dependency for pydantic EmailStr --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 7ed94c6..188dd89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ dependencies = [ # Валидация данных "pydantic>=2.5.0", "pydantic-settings>=2.1.0", + "email-validator>=2.0.0", # Генерация данных "faker>=22.0.0",