From 2e7c69c5afc04831fc17f02969dfa20bfd674743 Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 24 Aug 2026 17:02:37 +0300 Subject: [PATCH] docs: Added documentation for models and methods --- info.md | 730 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 730 insertions(+) create mode 100644 info.md diff --git a/info.md b/info.md new file mode 100644 index 0000000..cb1228d --- /dev/null +++ b/info.md @@ -0,0 +1,730 @@ +# API Checker + +Инструмент для автоматизированного end-to-end тестирования API через GitHub Actions. + +--- + +## Содержание + +- [Архитектура](#архитектура) +- [Models](#models) + - [AuthModel](#authmodel) + - [RequestModel](#requestmodel) + - [ExtractModel](#extractmodel) + - [AssertModel](#assertmodel) + - [StepModel](#stepmodel) + - [TestModel](#testmodel) + - [Context](#context) + - [Response](#response) + - [Executor](#executor) + - [Extractor](#extractor) + - [Validator](#validator) + - [StepResult](#stepresult) + - [TestResult](#testresult) + - [TestRunner](#testrunner) +- [YAML Readers](#yaml-readers) + - [ParseError](#parseerror) + - [BaseReader](#basereader) + - [YamlReader](#yamlreader) + - [PostmanReader](#postmanreader) + - [OpenAPIReader](#openapireader) + - [get_reader](#get_reader) +- [Примеры использования](#примеры-использования) + +--- + +## Архитектура + +``` +YAML/OpenAPI/Postman → Parser → TestModel → Context → Runner → TestResult +``` + +--- + +## Models + +### AuthModel + +**Файл:** `models/itm.py` + +Модель аутентификации. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `type` | `str` | `"none"` | Тип аутентификации: `none`, `basic`, `bearer`, `api_key`, `oauth2` | +| `credentials` | `dict[str, str]` | `{}` | Данные для аутентификации | + +**Когда использовать:** Когда API требует аутентификацию. Передаётся в `TestModel.auth`. + +--- + +### RequestModel + +**Файл:** `models/itm.py` + +Модель HTTP запроса. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `method` | `str` | `"GET"` | HTTP метод: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS` | +| `path` | `str` | `"/"` | Путь URL (поддерживает `{{variable}}`) | +| `headers` | `dict[str, str]` | `{}` | HTTP заголовки | +| `query` | `dict[str, str]` | `{}` | Query параметры | +| `body` | `dict \| str \| None` | `None` | Тело запроса | +| `body_type` | `str` | `"json"` | Тип тела: `json`, `form`, `raw` | +| `timeout` | `int` | `30` | Таймаут в секундах | + +**Когда использовать:** Определяет что отправить серверу. Передаётся в `StepModel.request`. + +--- + +### ExtractModel + +**Файл:** `models/itm.py` + +Модель извлечения данных из ответа. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `name` | `str` | — | Имя переменной (обязательное) | +| `json_path` | `str` | — | JSON-путь к значению: `$.token`, `$.user.id` (обязательное) | +| `source` | `str` | `"body"` | Источник: `body`, `header`, `status` | + +**Когда использовать:** Когда нужно сохранить данные из ответа для использования в следующих запросах. Передаётся в `StepModel.extract`. + +--- + +### AssertModel + +**Файл:** `models/itm.py` + +Модель проверки ответа. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `type` | `str` | — | Тип проверки: `status`, `json`, `header` (обязательное) | +| `path` | `str \| None` | `None` | JSON-путь к полю для проверки | +| `operator` | `str` | `"equals"` | Оператор: `equals`, `exists`, `gt`, `lt`, `contains`, `matches` | +| `value` | `Any` | `None` | Ожидаемое значение | + +**Когда использовать:** Когда нужно проверить что ответ соответствует ожиданиям. Передаётся в `StepModel.assert_`. + +--- + +### StepModel + +**Файл:** `models/itm.py` + +Модель одного шага теста. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `name` | `str` | — | Название шага (обязательное) | +| `request` | `RequestModel` | — | HTTP запрос (обязательное) | +| `extract` | `list[ExtractModel]` | `[]` | Извлечение данных | +| `assert_` | `list[AssertModel]` | `[]` | Проверки | + +**Когда использовать:** Один логический шаг теста (например, "Залогиниться"). Передаётся в `TestModel.steps`. + +--- + +### TestModel + +**Файл:** `models/itm.py` + +Основная модель теста. Содержит всю конфигурацию. + +| Поле | Тип | По умолчанию | Описание | +|------|-----|--------------|----------| +| `name` | `str` | `"Unnamed Test"` | Название теста | +| `base_url` | `str` | `""` | Базовый URL API | +| `variables` | `dict[str, str]` | `{}` | Статические переменные | +| `auth` | `AuthModel \| None` | `None` | Аутентификация | +| `steps` | `list[StepModel]` | `[]` | Шаги теста | + +**Когда использовать:** Главная входная точка. Создаётся парсерами или вручную. + +--- + +### Context + +**Файл:** `models/context.py` + +Контекст выполнения. Хранит состояние во время запуска теста. + +| Поле | Тип | Описание | +|------|-----|----------| +| `config` | `TestModel` | Оригинальная конфигурация теста | +| `variables` | `dict[str, str]` | Статические переменные из config | +| `extracted` | `dict[str, Any]` | Извлечённые данные из ответов | + +**Методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `__init__(config)` | `TestModel` | — | Создаёт контекст из конфигурации | +| `resolve(template)` | `str` | `str` | Заменяет `{{var}}` на значение из variables или extracted | +| `set_extracted(name, value)` | `str, Any` | — | Сохраняет извлечённое значение | + +**Когда использовать:** Передаётся всем компонентам (Executor, Extractor, TestRunner) для доступа к данным. + +**Пример:** + +```python +context = Context(TestModel(variables={"email": "test@x.com"})) +context.set_extracted("token", "abc123") + +context.resolve("{{email}}") # "test@x.com" +context.resolve("Bearer {{token}}") # "Bearer abc123" +``` + +--- + +### Response + +**Файл:** `models/executor.py` + +Модель HTTP ответа. + +| Поле | Тип | Описание | +|------|-----|----------| +| `status` | `int` | HTTP статус-код (200, 404, ...) | +| `body` | `dict` | Тело ответа (JSON) | +| `headers` | `dict` | Заголовки ответа | + +**Когда использовать:** Создаётся Executor после выполнения запроса. Передаётся в Extractor и Validator. + +--- + +### Executor + +**Файл:** `models/executor.py` + +Выполняет HTTP запросы. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `__init__(context)` | `Context` | — | Создаёт executor с контекстом | +| `_resolve_url(request)` | `RequestModel` | `str` | Разрешает URL с переменными | +| `execute(request)` | `RequestModel` | `Response` | Выполняет HTTP запрос | + +**Когда использовать:** Отправляет запросы к API. Используется TestRunner. + +**Пример:** + +```python +context = Context(model) +executor = Executor(context) +response = executor.execute(RequestModel(method="GET", path="/api/users")) +print(response.status) # 200 +``` + +--- + +### Extractor + +**Файл:** `models/extractor.py` + +Извлекает данные из HTTP ответов. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `__init__(context)` | `Context` | — | Создаёт extractor с контекстом | +| `extract(configs, response)` | `list[ExtractModel], Response` | — | Извлекает данные в context.extracted | + +**Внутренние методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `_get_value(response, config)` | `Response, ExtractModel` | `Any` | Получает значение из ответа | +| `_json_path(data, path)` | `dict, str` | `Any` | Извлекает значение по JSON-пути | + +**Когда использовать:** Когда нужно сохранить данные из ответа (токен, ID, ...) для использования в следующих шагах. + +**Пример:** + +```python +extractor = Extractor(context) +response = Response(status=200, body={"token": "abc123"}, headers={}) +extractor.extract([ExtractModel(name="token", json_path="$.token")], response) + +print(context.extracted["token"]) # "abc123" +``` + +--- + +### Validator + +**Файл:** `models/validator.py` + +Проверяет HTTP ответы. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `validate(asserts, response)` | `list[AssertModel], Response` | `bool` | Все ли проверки прошли | + +**Внутренние методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `_check(assertion, response)` | `AssertModel, Response` | `bool` | Проверяет одно утверждение | + +**Когда использовать:** Проверяет что ответ соответствует ожиданиям. Используется TestRunner. + +**Пример:** + +```python +validator = Validator() +response = Response(status=200, body={}, headers={}) +asserts = [AssertModel(type="status", value=200)] + +print(validator.validate(asserts, response)) # True +``` + +--- + +### StepResult + +**Файл:** `models/runner.py` + +Результат выполнения одного шага. + +| Поле | Тип | Описание | +|------|-----|----------| +| `name` | `str` | Название шага | +| `passed` | `bool` | Прошёл ли шаг | +| `response` | `Response` | HTTP ответ | + +**Когда использовать:** Создаётся TestRunner после выполнения шага. Возвращается в TestResult. + +--- + +### TestResult + +**Файл:** `models/runner.py` + +Результат выполнения всего теста. + +| Поле | Тип | Описание | +|------|-----|----------| +| `steps` | `list[StepResult]` | Результаты всех шагов | + +**Свойства:** + +| Свойство | Тип | Описание | +|----------|-----|----------| +| `passed` | `bool` | True если все шаги прошли | + +**Когда использовать:** Возвращается TestRunner.run(). Используется для вывода результатов. + +--- + +### TestRunner + +**Файл:** `models/runner.py` + +Оркестратор выполнения теста. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `__init__(context)` | `Context` | — | Создаёт runner с контекстом | +| `run()` | — | `TestResult` | Запускает все шаги теста | + +**Когда использовать:** Главная точка входа для запуска теста. + +**Пример:** + +```python +context = Context(model) +runner = TestRunner(context) +result = runner.run() + +print(result.passed) # True/False +for step in result.steps: + print(f"{step.name}: {'OK' if step.passed else 'FAIL'}") +``` + +--- + +## YAML Readers + +### ParseError + +**Файл:** `yamlreaders/base.py` + +Исключение при ошибке парсинга. + +| Поле | Тип | Описание | +|------|-----|----------| +| `line` | `int \| None` | Номер строки с ошибкой | + +**Когда использовать:** Ловить при парсинге невалидных YAML файлов. + +--- + +### BaseReader + +**Файл:** `yamlreaders/base.py` + +Абстрактный базовый класс для всех парсеров. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `validate(source)` | `str \| Path` | `bool` | Проверяет валидность файла | +| `parse(source)` | `str \| Path` | `TestModel` | Конвертирует файл в TestModel | +| `load_yaml(source)` | `str \| Path` | `dict` | Загружает YAML файл | + +**Исключения:** +- `FileNotFoundError` — файл не найден +- `ParseError` — ошибка парсинга + +**Когда использовать:** Не используется напрямую. Используйте наследников (YamlReader, PostmanReader, OpenAPIReader). + +--- + +### YamlReader + +**Файл:** `yamlreaders/yaml_reader.py` + +Парсер для кастомного формата YAML. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `validate(source)` | `str \| Path` | `bool` | Проверяет наличие steps, request, method | +| `parse(source)` | `str \| Path` | `TestModel` | Парсит YAML в TestModel | + +**Внутренние методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `_parse_steps(steps)` | `list[dict]` | `list[StepModel]` | Парсит шаги | +| `_parse_request(request)` | `dict` | `RequestModel` | Парсит запрос | +| `_parse_extract(extract)` | `list[dict]` | `list[ExtractModel]` | Парсит извлечение | +| `_parse_assert(asserts)` | `list[dict]` | `list[AssertModel]` | Парсит проверки | + +**Формат YAML:** + +```yaml +name: "Test Name" +base_url: http://localhost:8080 +variables: + email: test@example.com + +steps: + - name: "Login" + request: + method: POST + url: /api/login + headers: + Content-Type: application/json + body: + email: "{{email}}" + extract: + - name: token + json_path: "$.token" + assert: + - type: status + value: 200 +``` + +**Когда использовать:** Для собственных тест-спецификаций проекта. + +--- + +### PostmanReader + +**Файл:** `yamlreaders/postman_reader.py` + +Парсер для Postman Collection v2/v2.1. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `validate(source)` | `str \| Path` | `bool` | Проверяет наличие info и item | +| `parse(source)` | `str \| Path` | `TestModel` | Парсит Postman Collection в TestModel | + +**Внутренние методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `_extract_variables(data)` | `dict` | `dict[str, str]` | Извлекает переменные | +| `_extract_base_url(data)` | `dict` | `str` | Ищет переменную base_url | +| `_extract_auth(data)` | `dict` | `AuthModel \| None` | Парсит аутентификацию | +| `_parse_items(items)` | `list[dict]` | `list[StepModel]` | Рекурсивно парсит items | +| `_parse_item(item)` | `dict` | `StepModel \| None` | Парсит один request | +| `_parse_request(request)` | `dict` | `RequestModel` | Парсит HTTP запрос | +| `_parse_events(events)` | `list[dict]` | `list[ExtractModel]` | Парсит test scripts | +| `_parse_test_script(line)` | `str` | `list[ExtractModel] \| None` | Извлекает pm.environment.set() | +| `_convert_pm_to_json_path(pm_expr)` | `str` | `str` | Конвертирует pm表达式 в JSON-путь | + +**Формат YAML:** + +```yaml +info: + name: "Collection Name" + +variable: + - key: base_url + value: http://localhost:8080 + +item: + - name: "Login" + request: + method: POST + url: + raw: "{{base_url}}/api/login" + path: + - api + - login + header: + - key: Content-Type + value: application/json + body: + mode: raw + raw: '{"email": "{{email}}"}' + event: + - listen: test + script: + exec: + - "pm.environment.set('token', pm.response.json().token);" +``` + +**Когда использовать:** Для импорта коллекций из Postman. + +--- + +### OpenAPIReader + +**Файл:** `yamlreaders/openapi_reader.py` + +Парсер для OpenAPI 3.0/3.1 спецификаций. + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `validate(source)` | `str \| Path` | `bool` | Проверяет наличие openapi и paths | +| `parse(source)` | `str \| Path` | `TestModel` | Парсит OpenAPI в TestModel | + +**Внутренние методы:** + +| Метод | Вход | Возврат | Описание | +|-------|------|---------|----------| +| `_extract_base_url(data)` | `dict` | `str` | Берёт URL из servers | +| `_extract_auth(data)` | `dict` | `AuthModel \| None` | Парсит securitySchemes | +| `_parse_paths(paths)` | `dict` | `list[StepModel]` | Конвертирует paths в шаги | +| `_parse_operation(path, method, operation)` | `str, str, dict` | `StepModel` | Парсит один operation | +| `_build_request(path, method, operation)` | `str, str, dict` | `RequestModel` | Создаёт RequestModel | +| `_schema_to_example(schema)` | `dict` | `dict` | Создаёт example из schema | +| `_generate_extracts(operation)` | `dict` | `list[ExtractModel]` | Генерирует extraction | +| `_generate_asserts(operation)` | `dict` | `list[AssertModel]` | Генерирует asserts | + +**Формат YAML:** + +```yaml +openapi: "3.0.0" +info: + title: "API Name" + version: "1.0.0" + +servers: + - url: http://localhost:8080 + +paths: + /api/login: + post: + operationId: "loginUser" + requestBody: + content: + application/json: + schema: + type: object + properties: + email: + type: string + responses: + "200": + description: "Success" + content: + application/json: + schema: + type: object + properties: + token: + type: string +``` + +**Когда использовать:** Для импорта API из OpenAPI спецификаций. + +--- + +### get_reader + +**Файл:** `yamlreaders/__init__.py` + +Функция для автоопределения формата и получения appropriate reader. + +| Параметр | Тип | Описание | +|----------|-----|----------| +| `source` | `str` | Путь к YAML файлу | + +**Возврат:** `BaseReader` (YamlReader, PostmanReader или OpenAPIReader) + +**Исключения:** +- `FileNotFoundError` — файл не найден + +**Логика определения:** + +| Признак | Формат | Reader | +|---------|--------|--------| +| `openapi:` в содержимом | OpenAPI | OpenAPIReader | +| `info` и `item` в YAML | Postman | PostmanReader | +| Иначе | Кастомный YAML | YamlReader | + +**Когда использовать:** Когда нужно автоматически определить формат файла. + +**Пример:** + +```python +from yamlreaders import get_reader + +reader = get_reader("tests/api.yaml") +model = reader.parse("tests/api.yaml") +``` + +--- + +## Примеры использования + +### Базовый пример + +```python +from models import TestModel, StepModel, RequestModel, ExtractModel, AssertModel +from models import Context, TestRunner + +# Создаём модель теста +model = TestModel( + name="Тест логина", + base_url="http://localhost:8080", + variables={"email": "test@x.com", "password": "123456"}, + steps=[ + StepModel( + name="Логин", + request=RequestModel( + method="POST", + path="/api/login", + body={"email": "{{email}}", "password": "{{password}}"} + ), + extract=[ + ExtractModel(name="token", json_path="$.token") + ], + assert_=[ + AssertModel(type="status", value=200) + ] + ) + ] +) + +# Запускаем +context = Context(model) +runner = TestRunner(context) +result = runner.run() + +# Результат +print(f"Тест: {result.passed}") +``` + +### Парсинг из YAML + +```python +from yamlreaders import get_reader +from models import Context, TestRunner + +# Автоопределение формата +reader = get_reader("tests/api.yaml") +model = reader.parse("tests/api.yaml") + +# Запуск +context = Context(model) +runner = TestRunner(context) +result = runner.run() + +print(result.passed) +``` + +### Парсинг из Postman + +```python +from yamlreaders import PostmanReader +from models import Context, TestRunner + +reader = PostmanReader() +model = reader.parse("exports/postman_collection.yaml") + +context = Context(model) +result = TestRunner(context).run() +``` + +### Парсинг из OpenAPI + +```python +from yamlreaders import OpenAPIReader +from models import Context, TestRunner + +reader = OpenAPIReader() +model = reader.parse("docs/openapi.yaml") + +context = Context(model) +result = TestRunner(context).run() +``` + +### Использование переменных + +```python +model = TestModel( + variables={"host": "localhost"}, + steps=[ + StepModel( + name="Запрос", + request=RequestModel( + method="GET", + path="http://{{host}}:8080/api/users" + ) + ) + ] +) + +context = Context(model) +context.resolve("{{host}}") # "localhost" +``` + +### Извлечение данных + +```python +from models import Extractor, Response, ExtractModel + +context = Context(model) +extractor = Extractor(context) + +response = Response( + status=200, + body={"user": {"id": 123, "name": "Test"}}, + headers={} +) + +extractor.extract([ + ExtractModel(name="user_id", json_path="$.user.id") +], response) + +print(context.extracted["user_id"]) # 123 +``` + +### Проверка ответов + +```python +from models import Validator, Response, AssertModel + +validator = Validator() +response = Response(status=200, body={}, headers={}) + +# Проверка статуса +asserts = [AssertModel(type="status", value=200)] +print(validator.validate(asserts, response)) # True +```