@kirrosh/apitool 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +27 -0
- package/.github/workflows/release.yml +97 -0
- package/.mcp.json +9 -0
- package/APITOOL.md +195 -0
- package/BACKLOG.md +62 -0
- package/CHANGELOG.md +88 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/bun.lock +291 -0
- package/docs/GLOSSARY.md +182 -0
- package/docs/INDEX.md +21 -0
- package/docs/agent.md +135 -0
- package/docs/archive/APITOOL-pre-M22.md +831 -0
- package/docs/archive/BACKLOG-AI-NATIVE.md +56 -0
- package/docs/archive/M1-M2-parser-runner.md +216 -0
- package/docs/archive/M4-M7-reporter-cli.md +179 -0
- package/docs/archive/M5-M7-storage-junit.md +300 -0
- package/docs/archive/M6-webui.md +339 -0
- package/docs/ci.md +274 -0
- package/docs/generation-issues.md +67 -0
- package/generated/.env.yaml +3 -0
- package/install.ps1 +80 -0
- package/install.sh +113 -0
- package/package.json +46 -0
- package/scripts/run-mocked-tests.ts +45 -0
- package/seed-demo.ts +53 -0
- package/self-tests/auth.yaml +18 -0
- package/self-tests/collections-crud.yaml +46 -0
- package/self-tests/environments-crud.yaml +48 -0
- package/self-tests/export.yaml +32 -0
- package/self-tests/runs.yaml +16 -0
- package/src/bun-types.d.ts +5 -0
- package/src/cli/commands/add-api.ts +51 -0
- package/src/cli/commands/ai-generate.ts +106 -0
- package/src/cli/commands/chat.ts +43 -0
- package/src/cli/commands/ci-init.ts +126 -0
- package/src/cli/commands/collections.ts +41 -0
- package/src/cli/commands/coverage.ts +65 -0
- package/src/cli/commands/doctor.ts +127 -0
- package/src/cli/commands/envs.ts +218 -0
- package/src/cli/commands/init.ts +84 -0
- package/src/cli/commands/mcp.ts +16 -0
- package/src/cli/commands/run.ts +137 -0
- package/src/cli/commands/runs.ts +108 -0
- package/src/cli/commands/serve.ts +22 -0
- package/src/cli/commands/update.ts +142 -0
- package/src/cli/commands/validate.ts +18 -0
- package/src/cli/index.ts +500 -0
- package/src/cli/output.ts +24 -0
- package/src/cli/runtime.ts +7 -0
- package/src/core/agent/agent-loop.ts +116 -0
- package/src/core/agent/context-manager.ts +41 -0
- package/src/core/agent/system-prompt.ts +33 -0
- package/src/core/agent/tools/diagnose-failure.ts +51 -0
- package/src/core/agent/tools/explore-api.ts +40 -0
- package/src/core/agent/tools/index.ts +48 -0
- package/src/core/agent/tools/manage-environment.ts +40 -0
- package/src/core/agent/tools/query-results.ts +40 -0
- package/src/core/agent/tools/run-tests.ts +38 -0
- package/src/core/agent/tools/send-request.ts +44 -0
- package/src/core/agent/tools/validate-tests.ts +23 -0
- package/src/core/agent/types.ts +22 -0
- package/src/core/generator/ai/ai-generator.ts +61 -0
- package/src/core/generator/ai/llm-client.ts +159 -0
- package/src/core/generator/ai/output-parser.ts +307 -0
- package/src/core/generator/ai/prompt-builder.ts +153 -0
- package/src/core/generator/ai/types.ts +56 -0
- package/src/core/generator/coverage-scanner.ts +87 -0
- package/src/core/generator/data-factory.ts +115 -0
- package/src/core/generator/index.ts +10 -0
- package/src/core/generator/openapi-reader.ts +142 -0
- package/src/core/generator/schema-utils.ts +52 -0
- package/src/core/generator/serializer.ts +189 -0
- package/src/core/generator/types.ts +47 -0
- package/src/core/parser/filter.ts +14 -0
- package/src/core/parser/index.ts +21 -0
- package/src/core/parser/schema.ts +175 -0
- package/src/core/parser/types.ts +50 -0
- package/src/core/parser/variables.ts +146 -0
- package/src/core/parser/yaml-parser.ts +85 -0
- package/src/core/reporter/console.ts +175 -0
- package/src/core/reporter/index.ts +23 -0
- package/src/core/reporter/json.ts +9 -0
- package/src/core/reporter/junit.ts +78 -0
- package/src/core/reporter/types.ts +12 -0
- package/src/core/runner/assertions.ts +172 -0
- package/src/core/runner/execute-run.ts +75 -0
- package/src/core/runner/executor.ts +150 -0
- package/src/core/runner/http-client.ts +69 -0
- package/src/core/runner/index.ts +12 -0
- package/src/core/runner/types.ts +48 -0
- package/src/core/setup-api.ts +97 -0
- package/src/core/utils.ts +9 -0
- package/src/db/queries.ts +868 -0
- package/src/db/schema.ts +215 -0
- package/src/mcp/server.ts +47 -0
- package/src/mcp/tools/ci-init.ts +57 -0
- package/src/mcp/tools/coverage-analysis.ts +58 -0
- package/src/mcp/tools/explore-api.ts +84 -0
- package/src/mcp/tools/generate-missing-tests.ts +80 -0
- package/src/mcp/tools/generate-tests-guide.ts +353 -0
- package/src/mcp/tools/manage-environment.ts +123 -0
- package/src/mcp/tools/manage-server.ts +87 -0
- package/src/mcp/tools/query-db.ts +141 -0
- package/src/mcp/tools/run-tests.ts +66 -0
- package/src/mcp/tools/save-test-suite.ts +164 -0
- package/src/mcp/tools/send-request.ts +53 -0
- package/src/mcp/tools/setup-api.ts +49 -0
- package/src/mcp/tools/validate-tests.ts +42 -0
- package/src/tui/chat-ui.ts +150 -0
- package/src/web/routes/api.ts +234 -0
- package/src/web/routes/dashboard.ts +348 -0
- package/src/web/routes/runs.ts +64 -0
- package/src/web/schemas.ts +121 -0
- package/src/web/server.ts +134 -0
- package/src/web/static/htmx.min.js +1 -0
- package/src/web/static/style.css +265 -0
- package/src/web/views/layout.ts +46 -0
- package/src/web/views/results.ts +209 -0
- package/tests/agent/agent-loop.test.ts +61 -0
- package/tests/agent/context-manager.test.ts +59 -0
- package/tests/agent/system-prompt.test.ts +42 -0
- package/tests/agent/tools/diagnose-failure.test.ts +85 -0
- package/tests/agent/tools/explore-api.test.ts +59 -0
- package/tests/agent/tools/manage-environment.test.ts +78 -0
- package/tests/agent/tools/query-results.test.ts +77 -0
- package/tests/agent/tools/run-tests.test.ts +89 -0
- package/tests/agent/tools/send-request.test.ts +78 -0
- package/tests/agent/tools/validate-tests.test.ts +59 -0
- package/tests/ai/ai-generator.integration.test.ts +131 -0
- package/tests/ai/llm-client.test.ts +145 -0
- package/tests/ai/output-parser.test.ts +132 -0
- package/tests/ai/prompt-builder.test.ts +67 -0
- package/tests/ai/types.test.ts +55 -0
- package/tests/cli/args.test.ts +63 -0
- package/tests/cli/chat.test.ts +38 -0
- package/tests/cli/ci-init.test.ts +112 -0
- package/tests/cli/commands.test.ts +316 -0
- package/tests/cli/coverage.test.ts +58 -0
- package/tests/cli/doctor.test.ts +39 -0
- package/tests/cli/envs.test.ts +181 -0
- package/tests/cli/init.test.ts +80 -0
- package/tests/cli/runs.test.ts +94 -0
- package/tests/cli/safe-run.test.ts +103 -0
- package/tests/cli/update.test.ts +32 -0
- package/tests/core/generator/schema-utils.test.ts +108 -0
- package/tests/core/parser/nested-assertions.test.ts +80 -0
- package/tests/core/runner/root-body-assertions.test.ts +70 -0
- package/tests/db/chat-queries.test.ts +88 -0
- package/tests/db/chat-schema.test.ts +37 -0
- package/tests/db/environments.test.ts +131 -0
- package/tests/db/queries.test.ts +409 -0
- package/tests/db/schema.test.ts +141 -0
- package/tests/fixtures/.env.yaml +3 -0
- package/tests/fixtures/auth-token-test.yaml +8 -0
- package/tests/fixtures/bail/suite-a.yaml +6 -0
- package/tests/fixtures/bail/suite-b.yaml +6 -0
- package/tests/fixtures/crud.yaml +35 -0
- package/tests/fixtures/invalid-missing-name.yaml +5 -0
- package/tests/fixtures/invalid-no-method.yaml +6 -0
- package/tests/fixtures/petstore-auth.json +295 -0
- package/tests/fixtures/petstore-simple.json +151 -0
- package/tests/fixtures/post-only.yaml +12 -0
- package/tests/fixtures/simple.yaml +6 -0
- package/tests/fixtures/valid/.env.yaml +1 -0
- package/tests/fixtures/valid/a.yaml +5 -0
- package/tests/fixtures/valid/b.yml +5 -0
- package/tests/generator/coverage-scanner.test.ts +129 -0
- package/tests/generator/data-factory.test.ts +133 -0
- package/tests/generator/openapi-reader.test.ts +131 -0
- package/tests/integration/auth-flow.test.ts +217 -0
- package/tests/mcp/coverage-analysis.test.ts +64 -0
- package/tests/mcp/explore-api-schemas.test.ts +105 -0
- package/tests/mcp/explore-api.test.ts +49 -0
- package/tests/mcp/generate-missing-tests.test.ts +69 -0
- package/tests/mcp/manage-environment.test.ts +89 -0
- package/tests/mcp/save-test-suite.test.ts +116 -0
- package/tests/mcp/send-request.test.ts +79 -0
- package/tests/mcp/setup-api.test.ts +106 -0
- package/tests/mcp/tools.test.ts +248 -0
- package/tests/parser/schema.test.ts +134 -0
- package/tests/parser/variables.test.ts +227 -0
- package/tests/parser/yaml-parser.test.ts +69 -0
- package/tests/reporter/console.test.ts +256 -0
- package/tests/reporter/json.test.ts +98 -0
- package/tests/reporter/junit.test.ts +284 -0
- package/tests/runner/assertions.test.ts +262 -0
- package/tests/runner/executor.test.ts +310 -0
- package/tests/runner/http-client.test.ts +138 -0
- package/tests/web/routes.test.ts +160 -0
- package/tsconfig.json +31 -0
|
@@ -0,0 +1,831 @@
|
|
|
1
|
+
# APITOOL
|
|
2
|
+
|
|
3
|
+
**API Testing Platform** — CLI + WebUI для тестирования API из одного бинарника.
|
|
4
|
+
|
|
5
|
+
OpenAPI спецификация → AI-генерация тестов + дашборд + MCP для AI-агентов. Один файл. Ноль настроек.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Содержание
|
|
10
|
+
|
|
11
|
+
- [Стек](#стек)
|
|
12
|
+
- [Структура проекта](#структура-проекта)
|
|
13
|
+
- [Модули](#модули)
|
|
14
|
+
- [M1: Parser](#m1-parser-srcoreparser)
|
|
15
|
+
- [M2: Runner](#m2-runner-srcorerunner)
|
|
16
|
+
- [M3: Generator](#m3-generator-scoregenerator)
|
|
17
|
+
- [M4: Reporter](#m4-reporter-srcorereporter)
|
|
18
|
+
- [M5: Storage](#m5-storage-srcdb)
|
|
19
|
+
- [M6: WebUI](#m6-webui-srcweb)
|
|
20
|
+
- [M7: CLI](#m7-cli-srccli)
|
|
21
|
+
- [M10: AI Generation](#m10-ai-generation-srccoregeneratorai)
|
|
22
|
+
- [Agent — AI Chat](#agent--ai-chat)
|
|
23
|
+
- [Формат YAML-тестов](#формат-yaml-тестов)
|
|
24
|
+
- [Поток данных](#поток-данных)
|
|
25
|
+
- [Roadmap](#roadmap-mvp)
|
|
26
|
+
- [Сборка и установка](#сборка-и-установка)
|
|
27
|
+
- [Принципы](#принципы)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Стек
|
|
32
|
+
|
|
33
|
+
| Компонент | Технология |
|
|
34
|
+
|-----------|-----------|
|
|
35
|
+
| Runtime | Bun |
|
|
36
|
+
| Язык | TypeScript (strict) |
|
|
37
|
+
| HTTP-клиент | `fetch` (Bun native) |
|
|
38
|
+
| БД | SQLite (`bun:sqlite`) |
|
|
39
|
+
| Веб-сервер | Hono + `@hono/zod-openapi` |
|
|
40
|
+
| Frontend | HTMX + минимальный CSS |
|
|
41
|
+
| OpenAPI парсер | `@readme/openapi-parser` |
|
|
42
|
+
| Формат тестов | YAML |
|
|
43
|
+
| Сборка | `bun build --compile` |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Структура проекта
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
apitool/
|
|
51
|
+
├── src/
|
|
52
|
+
│ ├── core/
|
|
53
|
+
│ │ ├── parser/
|
|
54
|
+
│ │ │ ├── yaml-parser.ts # Парсинг YAML → TestSuite
|
|
55
|
+
│ │ │ ├── schema.ts # JSON Schema для валидации
|
|
56
|
+
│ │ │ ├── variables.ts # Подстановка {{var}}, {{$generators}}
|
|
57
|
+
│ │ │ └── types.ts # TestSuite, TestStep, Assertion, Capture
|
|
58
|
+
│ │ ├── runner/
|
|
59
|
+
│ │ │ ├── http-client.ts # fetch-обёртка с таймаутами и retry
|
|
60
|
+
│ │ │ ├── executor.ts # Выполнение TestSuite, цепочки captures
|
|
61
|
+
│ │ │ ├── execute-run.ts # Shared executeRun() — парсинг, запуск, сохранение
|
|
62
|
+
│ │ │ ├── assertions.ts # Проверка ассертов (status, jsonpath, regex, type)
|
|
63
|
+
│ │ │ └── types.ts # TestRunResult, StepResult
|
|
64
|
+
│ │ ├── generator/
|
|
65
|
+
│ │ │ ├── openapi-reader.ts # Парсинг OpenAPI 3.x
|
|
66
|
+
│ │ │ ├── serializer.ts # RawSuite → YAML сериализация, sanitizeEnvName
|
|
67
|
+
│ │ │ ├── coverage-scanner.ts # Сканер покрытия для инкрементальной генерации
|
|
68
|
+
│ │ │ ├── data-factory.ts # Генерация тестовых данных по схеме
|
|
69
|
+
│ │ │ └── ai/ # AI-генерация тестов (M10)
|
|
70
|
+
│ │ │ ├── ai-generator.ts # Оркестратор: spec → prompt → LLM → YAML
|
|
71
|
+
│ │ │ ├── llm-client.ts # HTTP-клиент для LLM провайдеров
|
|
72
|
+
│ │ │ ├── prompt-builder.ts # Сборка системного + user промпта
|
|
73
|
+
│ │ │ ├── output-parser.ts # Парсинг JSON-ответа LLM → TestSuite
|
|
74
|
+
│ │ │ └── types.ts # AIGenerateOptions, AIGenerateResult
|
|
75
|
+
│ │ └── agent/ # AI Chat Agent (AI SDK v6)
|
|
76
|
+
│ │ ├── agent-loop.ts # generateText + tools + stopWhen
|
|
77
|
+
│ │ ├── context-manager.ts # Автосжатие длинных диалогов
|
|
78
|
+
│ │ ├── system-prompt.ts # Системный промпт с примерами tools
|
|
79
|
+
│ │ ├── types.ts # AgentConfig, ToolEvent, AgentTurnResult
|
|
80
|
+
│ │ └── tools/ # 7 tools как AI SDK tool()
|
|
81
|
+
│ │ └── reporter/
|
|
82
|
+
│ │ ├── json.ts # JSON-отчёт
|
|
83
|
+
│ │ ├── junit.ts # JUnit XML
|
|
84
|
+
│ │ └── console.ts # Цветной вывод в терминал
|
|
85
|
+
│ ├── db/
|
|
86
|
+
│ │ ├── schema.ts # Создание таблиц, миграции
|
|
87
|
+
│ │ └── queries.ts # CRUD-операции с историей прогонов
|
|
88
|
+
│ ├── web/
|
|
89
|
+
│ │ ├── server.ts # OpenAPIHono-сервер, /api/openapi.json
|
|
90
|
+
│ │ ├── schemas.ts # Zod-схемы для API (валидация + OpenAPI)
|
|
91
|
+
│ │ ├── routes/
|
|
92
|
+
│ │ │ ├── dashboard.ts # GET / — главная с trend chart, коллекциями
|
|
93
|
+
│ │ │ ├── collections.ts # GET /collections/:id, POST/DELETE /api/collections
|
|
94
|
+
│ │ │ ├── suites.ts # GET /collections/:id/suites, detail — test file browser
|
|
95
|
+
│ │ │ ├── ai-generate.ts # POST /api/ai-generate, save, GET /api/ai-generation/:id
|
|
96
|
+
│ │ │ ├── runs.ts # GET /runs (с фильтрами), GET /runs/:id
|
|
97
|
+
│ │ │ ├── environments.ts # CRUD окружений: list, detail, create, update, delete
|
|
98
|
+
│ │ │ ├── explorer.ts # GET /explorer — дерево API
|
|
99
|
+
│ │ │ └── api.ts # POST /api/run, POST /api/try, GET /api/export
|
|
100
|
+
│ │ ├── views/
|
|
101
|
+
│ │ │ ├── layout.ts # HTML layout, escapeHtml()
|
|
102
|
+
│ │ │ └── trend-chart.ts # Shared SVG trend chart component
|
|
103
|
+
│ │ └── static/ # HTMX, CSS, иконки
|
|
104
|
+
│ ├── mcp/ # MCP Server — AI-agent integration (M15)
|
|
105
|
+
│ │ ├── server.ts # McpServer setup + stdio transport
|
|
106
|
+
│ │ └── tools/
|
|
107
|
+
│ │ ├── run-tests.ts # run_tests — запуск тестов
|
|
108
|
+
│ │ ├── validate-tests.ts # validate_tests — валидация YAML
|
|
109
|
+
│ │ ├── list-collections.ts # list_collections — список коллекций
|
|
110
|
+
│ │ ├── list-runs.ts # list_runs — список прогонов
|
|
111
|
+
│ │ ├── get-run-results.ts # get_run_results — детали прогона
|
|
112
|
+
│ │ ├── list-environments.ts # list_environments — список окружений
|
|
113
|
+
│ │ ├── send-request.ts # send_request — ad-hoc HTTP запросы
|
|
114
|
+
│ │ ├── explore-api.ts # explore_api — просмотр OpenAPI спеки
|
|
115
|
+
│ │ ├── manage-environment.ts # manage_environment — CRUD окружений
|
|
116
|
+
│ │ ├── diagnose-failure.ts # diagnose_failure — диагностика падений
|
|
117
|
+
│ │ └── coverage-analysis.ts # coverage_analysis — анализ покрытия
|
|
118
|
+
│ └── cli/
|
|
119
|
+
│ ├── index.ts # Точка входа, роутинг команд, --api резолвинг
|
|
120
|
+
│ ├── commands/
|
|
121
|
+
│ │ ├── add-api.ts # apitool add-api — регистрация нового API
|
|
122
|
+
│ │ ├── run.ts # apitool run
|
|
123
|
+
│ │ ├── ai-generate.ts # apitool ai-generate
|
|
124
|
+
│ │ ├── collections.ts # apitool collections
|
|
125
|
+
│ │ ├── serve.ts # apitool serve
|
|
126
|
+
│ │ ├── validate.ts # apitool validate
|
|
127
|
+
│ │ ├── mcp.ts # apitool mcp
|
|
128
|
+
│ │ ├── request.ts # apitool request
|
|
129
|
+
│ │ ├── envs.ts # apitool envs (--api для scoped envs)
|
|
130
|
+
│ │ ├── runs.ts # apitool runs
|
|
131
|
+
│ │ ├── coverage.ts # apitool coverage
|
|
132
|
+
│ │ ├── chat.ts # apitool chat
|
|
133
|
+
│ │ ├── init.ts # apitool init
|
|
134
|
+
│ │ ├── doctor.ts # apitool doctor
|
|
135
|
+
│ │ └── update.ts # apitool update
|
|
136
|
+
│ ├── runtime.ts # Определение standalone vs dev режима
|
|
137
|
+
│ └── output.ts # Форматирование CLI-вывода
|
|
138
|
+
├── tests/ # Тесты самого инструмента
|
|
139
|
+
├── self-tests/ # Сгенерированные skeleton-тесты для apitool API
|
|
140
|
+
├── examples/ # Примеры YAML-тестов
|
|
141
|
+
├── docs/ # Документация
|
|
142
|
+
├── package.json
|
|
143
|
+
├── tsconfig.json
|
|
144
|
+
└── bunfig.toml
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Модули
|
|
150
|
+
|
|
151
|
+
### M1: Parser (`src/core/parser/`)
|
|
152
|
+
|
|
153
|
+
Читает YAML-файлы, валидирует, возвращает типизированные структуры.
|
|
154
|
+
|
|
155
|
+
**Вход:** путь к `.yaml` файлу или директории.
|
|
156
|
+
**Выход:** `TestSuite[]`
|
|
157
|
+
|
|
158
|
+
При парсинге директории невалидные файлы пропускаются (один сломанный файл не блокирует остальные). Каждый распарсенный suite получает `_source` — путь к исходному файлу (используется для AI badge в WebUI).
|
|
159
|
+
|
|
160
|
+
Функция `parseDirectorySafe(dirPath)` возвращает `{ suites: TestSuite[], errors: { file: string, error: string }[] }` — собирает ошибки парсинга вместо их игнорирования. Используется в WebUI для показа broken-файлов. Функции `parse()` / `parseDirectory()` не изменены (обратная совместимость).
|
|
161
|
+
|
|
162
|
+
Ключевые типы:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
interface TestSuite {
|
|
166
|
+
name: string;
|
|
167
|
+
base_url?: string;
|
|
168
|
+
headers?: Record<string, string>; // общие заголовки для всех тестов
|
|
169
|
+
tests: TestStep[];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface TestStep {
|
|
173
|
+
name: string;
|
|
174
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
175
|
+
path: string;
|
|
176
|
+
headers?: Record<string, string>;
|
|
177
|
+
json?: unknown; // тело запроса
|
|
178
|
+
form?: Record<string, string>; // form-urlencoded
|
|
179
|
+
query?: Record<string, string>; // query-параметры
|
|
180
|
+
expect: {
|
|
181
|
+
status?: number;
|
|
182
|
+
body?: Record<string, AssertionRule>; // JSONPath-подобные проверки
|
|
183
|
+
headers?: Record<string, string>;
|
|
184
|
+
duration?: number; // максимальное время ответа (мс)
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface AssertionRule {
|
|
189
|
+
capture?: string; // сохранить значение в переменную
|
|
190
|
+
type?: "string" | "integer" | "number" | "boolean" | "array" | "object";
|
|
191
|
+
equals?: unknown; // точное совпадение
|
|
192
|
+
contains?: string; // строка содержит подстроку
|
|
193
|
+
matches?: string; // regex
|
|
194
|
+
gt?: number; // больше
|
|
195
|
+
lt?: number; // меньше
|
|
196
|
+
exists?: boolean; // поле существует / не существует
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Встроенные генераторы переменных:
|
|
201
|
+
|
|
202
|
+
| Генератор | Пример значения |
|
|
203
|
+
|-----------|----------------|
|
|
204
|
+
| `{{$randomName}}` | "John Smith" |
|
|
205
|
+
| `{{$randomEmail}}` | "xk92m@test.com" |
|
|
206
|
+
| `{{$uuid}}` | "550e8400-e29b-41d4-a716-446655440000" |
|
|
207
|
+
| `{{$timestamp}}` | 1708876800 |
|
|
208
|
+
| `{{$randomInt}}` | 42 |
|
|
209
|
+
| `{{$randomString}}` | "aBcDeFgH" |
|
|
210
|
+
|
|
211
|
+
Environments — файлы `.env.yaml` и/или DB:
|
|
212
|
+
|
|
213
|
+
```yaml
|
|
214
|
+
# .env.yaml (по умолчанию)
|
|
215
|
+
base_url: http://localhost:3000/api
|
|
216
|
+
token: dev-token-123
|
|
217
|
+
|
|
218
|
+
# .env.staging.yaml
|
|
219
|
+
base_url: https://staging.example.com/api
|
|
220
|
+
token: staging-token-456
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Использование: `apitool run tests/ --env staging` или `apitool run --api myapi --env staging`
|
|
224
|
+
|
|
225
|
+
**Приоритет резолва переменных:** файл `.env.<name>.yaml` > DB scoped env (привязан к коллекции) > DB global env (collection_id IS NULL) > генераторы > оставить `{{raw}}`
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### M2: Runner (`src/core/runner/`)
|
|
230
|
+
|
|
231
|
+
Выполняет `TestSuite`, отправляет HTTP-запросы, проверяет ассерты, передаёт captures между шагами.
|
|
232
|
+
|
|
233
|
+
**Вход:** `TestSuite` + `Environment`
|
|
234
|
+
**Выход:** `TestRunResult`
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
interface TestRunResult {
|
|
238
|
+
suite_name: string;
|
|
239
|
+
started_at: string; // ISO 8601
|
|
240
|
+
finished_at: string;
|
|
241
|
+
total: number;
|
|
242
|
+
passed: number;
|
|
243
|
+
failed: number;
|
|
244
|
+
skipped: number;
|
|
245
|
+
steps: StepResult[];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
interface StepResult {
|
|
249
|
+
name: string;
|
|
250
|
+
status: "pass" | "fail" | "skip" | "error";
|
|
251
|
+
duration_ms: number;
|
|
252
|
+
request: {
|
|
253
|
+
method: string;
|
|
254
|
+
url: string;
|
|
255
|
+
headers: Record<string, string>;
|
|
256
|
+
body?: string;
|
|
257
|
+
};
|
|
258
|
+
response: {
|
|
259
|
+
status: number;
|
|
260
|
+
headers: Record<string, string>;
|
|
261
|
+
body: string; // сырой текст (для отчёта)
|
|
262
|
+
body_parsed?: unknown; // JSON если application/json
|
|
263
|
+
};
|
|
264
|
+
assertions: AssertionResult[];
|
|
265
|
+
captures: Record<string, unknown>; // извлечённые значения
|
|
266
|
+
error?: string; // если error/skip — причина
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
interface AssertionResult {
|
|
270
|
+
field: string; // "status" | "body.id" | "headers.content-type"
|
|
271
|
+
rule: string; // "equals 201" | "type integer" | "matches .*@.*"
|
|
272
|
+
passed: boolean;
|
|
273
|
+
actual: unknown;
|
|
274
|
+
expected: unknown;
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Логика выполнения:
|
|
279
|
+
|
|
280
|
+
1. Подставить переменные окружения и captures в URL, headers, body
|
|
281
|
+
2. Отправить HTTP-запрос (fetch)
|
|
282
|
+
3. Извлечь captures из ответа
|
|
283
|
+
4. Проверить все ассерты
|
|
284
|
+
5. Если шаг упал и он имеет `capture` — последующие шаги, зависящие от этой переменной, получают `status: skip`
|
|
285
|
+
|
|
286
|
+
Параллельность: файлы (suites) выполняются параллельно, шаги внутри suite — последовательно (из-за captures).
|
|
287
|
+
|
|
288
|
+
Конфигурация:
|
|
289
|
+
|
|
290
|
+
```yaml
|
|
291
|
+
# в YAML-тесте или глобально
|
|
292
|
+
config:
|
|
293
|
+
timeout: 30000 # мс, таймаут на один запрос
|
|
294
|
+
retries: 0 # количество повторов при ошибке
|
|
295
|
+
retry_delay: 1000 # задержка между повторами
|
|
296
|
+
follow_redirects: true
|
|
297
|
+
verify_ssl: true
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
### M3: Generator (`src/core/generator/`)
|
|
303
|
+
|
|
304
|
+
Утилиты для работы с OpenAPI и генерации тестов. Шаблонная генерация (CRUD/skeleton) удалена — остались только AI-генерация и вспомогательные модули.
|
|
305
|
+
|
|
306
|
+
- `openapi-reader.ts` — парсинг OpenAPI 3.x (файл или URL), `readOpenApiSpec()`, `extractEndpoints()`, `extractSecuritySchemes()`
|
|
307
|
+
- `serializer.ts` — конвертирует `RawSuite` в YAML формат, содержит `sanitizeEnvName()`
|
|
308
|
+
- `coverage-scanner.ts` — анализ покрытия: `scanCoveredEndpoints()`, `filterUncoveredEndpoints()`
|
|
309
|
+
- `data-factory.ts` — генерация тестовых данных по JSON Schema
|
|
310
|
+
- `ai/` — AI-генерация тестов (см. [M10: AI Generation](#m10-ai-generation-srccoregeneratorai))
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
### M4: Reporter (`src/core/reporter/`)
|
|
315
|
+
|
|
316
|
+
Формирует отчёты из `TestRunResult`.
|
|
317
|
+
|
|
318
|
+
**JSON** — полный дамп `TestRunResult`, сохраняется в SQLite.
|
|
319
|
+
|
|
320
|
+
**JUnit XML** — для CI:
|
|
321
|
+
|
|
322
|
+
```xml
|
|
323
|
+
<testsuites tests="5" failures="1" time="2.34">
|
|
324
|
+
<testsuite name="Users CRUD" tests="5" failures="1">
|
|
325
|
+
<testcase name="Create user" time="0.45"/>
|
|
326
|
+
<testcase name="Get user" time="0.12"/>
|
|
327
|
+
<testcase name="Update user" time="0.31">
|
|
328
|
+
<failure message="Expected status 200, got 500">...</failure>
|
|
329
|
+
</testcase>
|
|
330
|
+
</testsuite>
|
|
331
|
+
</testsuites>
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**Console** — цветной вывод:
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
Users CRUD
|
|
338
|
+
✓ Create user (450ms)
|
|
339
|
+
✓ Get user (120ms)
|
|
340
|
+
✗ Update user (310ms)
|
|
341
|
+
Expected status 200, got 500
|
|
342
|
+
✓ Delete user (89ms)
|
|
343
|
+
○ Verify deleted (skipped)
|
|
344
|
+
|
|
345
|
+
Results: 3 passed, 1 failed, 1 skipped (1.2s)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### M5: Storage (`src/db/`)
|
|
351
|
+
|
|
352
|
+
SQLite через `bun:sqlite`. Файл `apitool.db` создаётся автоматически при первом запуске.
|
|
353
|
+
|
|
354
|
+
```sql
|
|
355
|
+
CREATE TABLE collections (
|
|
356
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
357
|
+
name TEXT NOT NULL,
|
|
358
|
+
base_dir TEXT, -- корневая директория коллекции
|
|
359
|
+
test_path TEXT NOT NULL, -- абсолютный путь к тестам (forward slashes)
|
|
360
|
+
openapi_spec TEXT, -- путь к OpenAPI спеке
|
|
361
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
CREATE TABLE runs (
|
|
365
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
366
|
+
started_at TEXT NOT NULL, -- ISO 8601
|
|
367
|
+
finished_at TEXT,
|
|
368
|
+
total INTEGER NOT NULL DEFAULT 0,
|
|
369
|
+
passed INTEGER NOT NULL DEFAULT 0,
|
|
370
|
+
failed INTEGER NOT NULL DEFAULT 0,
|
|
371
|
+
skipped INTEGER NOT NULL DEFAULT 0,
|
|
372
|
+
trigger TEXT DEFAULT 'manual', -- manual | ci | scheduled
|
|
373
|
+
commit_sha TEXT,
|
|
374
|
+
branch TEXT,
|
|
375
|
+
environment TEXT,
|
|
376
|
+
duration_ms INTEGER,
|
|
377
|
+
collection_id INTEGER REFERENCES collections(id) -- nullable, привязка к коллекции
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
CREATE TABLE results (
|
|
381
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
382
|
+
run_id INTEGER NOT NULL REFERENCES runs(id),
|
|
383
|
+
suite_name TEXT NOT NULL,
|
|
384
|
+
test_name TEXT NOT NULL,
|
|
385
|
+
status TEXT NOT NULL, -- pass | fail | skip | error
|
|
386
|
+
duration_ms INTEGER NOT NULL,
|
|
387
|
+
request_method TEXT,
|
|
388
|
+
request_url TEXT,
|
|
389
|
+
request_body TEXT,
|
|
390
|
+
response_status INTEGER,
|
|
391
|
+
response_body TEXT, -- хранить только при fail (экономия)
|
|
392
|
+
error_message TEXT,
|
|
393
|
+
assertions TEXT, -- JSON массив AssertionResult[]
|
|
394
|
+
captures TEXT -- JSON Record<string, unknown>
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
CREATE TABLE environments (
|
|
398
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
399
|
+
name TEXT NOT NULL,
|
|
400
|
+
collection_id INTEGER REFERENCES collections(id) ON DELETE CASCADE,
|
|
401
|
+
variables TEXT NOT NULL -- JSON
|
|
402
|
+
);
|
|
403
|
+
-- Уникальность: (name, collection_id) — scoped к коллекции
|
|
404
|
+
-- + отдельный индекс для глобальных (collection_id IS NULL)
|
|
405
|
+
CREATE UNIQUE INDEX idx_env_name_collection ON environments(name, collection_id);
|
|
406
|
+
CREATE UNIQUE INDEX idx_env_name_global ON environments(name) WHERE collection_id IS NULL;
|
|
407
|
+
|
|
408
|
+
CREATE TABLE ai_generations (
|
|
409
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
410
|
+
collection_id INTEGER REFERENCES collections(id),
|
|
411
|
+
prompt TEXT NOT NULL,
|
|
412
|
+
model TEXT NOT NULL,
|
|
413
|
+
provider TEXT NOT NULL, -- ollama | openai | anthropic | custom
|
|
414
|
+
generated_yaml TEXT, -- результат генерации (YAML)
|
|
415
|
+
output_path TEXT, -- путь к сохранённому файлу
|
|
416
|
+
status TEXT NOT NULL, -- success | error
|
|
417
|
+
error_message TEXT,
|
|
418
|
+
prompt_tokens INTEGER,
|
|
419
|
+
completion_tokens INTEGER,
|
|
420
|
+
duration_ms INTEGER,
|
|
421
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
-- Индексы для дашборда
|
|
425
|
+
CREATE INDEX idx_runs_started ON runs(started_at DESC);
|
|
426
|
+
CREATE INDEX idx_runs_collection ON runs(collection_id);
|
|
427
|
+
CREATE INDEX idx_results_run ON results(run_id);
|
|
428
|
+
CREATE INDEX idx_results_status ON results(status);
|
|
429
|
+
CREATE INDEX idx_results_name ON results(suite_name, test_name);
|
|
430
|
+
CREATE INDEX idx_collections_name ON collections(name);
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Миграции: массив SQL-строк с номером версии. При старте проверяется `PRAGMA user_version`, применяются недостающие миграции. Текущая версия: **5**.
|
|
434
|
+
|
|
435
|
+
Версии: V1 — базовые таблицы, V2 — `ai_generations`, V3 — `chat_sessions`/`chat_messages`, V4 — `settings`, V5 — `base_dir` в collections + `collection_id` в environments (scoped envs).
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
### M6: WebUI (`src/web/`)
|
|
440
|
+
|
|
441
|
+
Запускается командой `apitool serve --port 8080`.
|
|
442
|
+
|
|
443
|
+
Hono-сервер рендерит HTML, интерактивность через HTMX.
|
|
444
|
+
|
|
445
|
+
**Страницы:**
|
|
446
|
+
|
|
447
|
+
| Route | Описание |
|
|
448
|
+
|-------|----------|
|
|
449
|
+
| `GET /` | Dashboard: глобальные метрики, grid коллекций, форма добавления, recent runs, slowest/flaky |
|
|
450
|
+
| `GET /collections/:id` | Детали коллекции: метрики, trend chart, test suites (кликабельные — YAML, source, AI prompt/model), broken-файлы с Delete, per-suite Run, таблица прогонов |
|
|
451
|
+
| `GET /runs` | Список прогонов с фильтрацией (статус, environment, дата, поиск по имени теста) и пагинацией |
|
|
452
|
+
| `GET /runs/:id` | Детали прогона: каждый тест → запрос/ответ/ассерты + кнопки Export (JUnit XML, JSON) |
|
|
453
|
+
| `GET /environments` | Список окружений: имя, scope (global/api:N), кол-во переменных, actions (Edit/Delete), форма создания |
|
|
454
|
+
| `GET /environments/:id` | Редактор окружения: key-value editor с добавлением/удалением строк |
|
|
455
|
+
| `POST /environments` | Создать окружение (HTMX form-data) |
|
|
456
|
+
| `PUT /environments/:id` | Обновить переменные окружения (HTMX form-data) |
|
|
457
|
+
| `DELETE /environments/:id` | Удалить окружение (HTMX) |
|
|
458
|
+
| `GET /collections/:id/suites` | Список YAML test files: имя suite, кол-во тестов, base URL, Run/View/Delete |
|
|
459
|
+
| `GET /collections/:id/suites/detail?file=` | Детали suite: карточки метрик, таблица шагов с method badge, Run Suite |
|
|
460
|
+
| `GET /explorer` | Дерево API из OpenAPI, параметры, описания, multi-auth panel |
|
|
461
|
+
| `POST /collections` | Создать коллекцию из формы на дашборде (HTMX form-data) |
|
|
462
|
+
| `DELETE /collections/:id` | Удалить коллекцию (HTMX, runs unlinked) |
|
|
463
|
+
| `POST /run` | Запустить прогон из WebUI (HTMX form-data), авто-привязка к коллекции |
|
|
464
|
+
| `POST /api/try` | Отправить единичный запрос из Explorer (HTMX, с auth injection) |
|
|
465
|
+
| `POST /api/authorize` | Proxy login для Bearer auth (username/password → token) |
|
|
466
|
+
| `GET /api/export/:runId/junit` | Скачать JUnit XML отчёт для прогона |
|
|
467
|
+
| `GET /api/export/:runId/json` | Скачать JSON отчёт для прогона |
|
|
468
|
+
| `POST /api/ai-generate` | Генерация тестов через AI (Ollama/OpenAI/Anthropic) |
|
|
469
|
+
| `POST /api/ai-generate/save` | Сохранить YAML в файл, записать `output_path` в БД, показать подтверждение |
|
|
470
|
+
| `POST /api/ai-generate/delete-file` | Удалить broken/ненужный файл из коллекции (с проверкой что файл внутри test_path) |
|
|
471
|
+
| `GET /api/ai-generation/:id` | Просмотр деталей генерации (YAML, метаданные, путь файла) — HTMX fragment |
|
|
472
|
+
|
|
473
|
+
Dashboard-метрики (SQL-запросы):
|
|
474
|
+
|
|
475
|
+
- **Pass rate trend:** последние 30 прогонов, `passed / total * 100` — SVG line chart с area fill
|
|
476
|
+
- **Flaky-тесты:** тесты с разным статусом в последних N прогонах
|
|
477
|
+
- **Средняя длительность:** `AVG(duration_ms)` по тестам
|
|
478
|
+
- **Самые медленные:** `ORDER BY duration_ms DESC LIMIT 5`
|
|
479
|
+
|
|
480
|
+
Фильтрация прогонов (`GET /runs`):
|
|
481
|
+
- **Status:** All / Has Failures / All Passed
|
|
482
|
+
- **Environment:** dropdown из `listEnvironments()` + `getDistinctEnvironments()` (объединение определённых и из истории прогонов)
|
|
483
|
+
- **Date range:** from / to
|
|
484
|
+
- **Test name:** поиск по имени теста (LIKE)
|
|
485
|
+
|
|
486
|
+
Экспорт результатов (`/runs/:id`):
|
|
487
|
+
- **JUnit XML** — `GET /api/export/:runId/junit` (Content-Disposition: attachment)
|
|
488
|
+
- **JSON** — `GET /api/export/:runId/json` (Content-Disposition: attachment)
|
|
489
|
+
|
|
490
|
+
Статика: HTMX (CDN или вкомпилирован), CSS (один файл, без фреймворков).
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
### M7: CLI (`src/cli/`)
|
|
495
|
+
|
|
496
|
+
| Команда | Описание | Основные флаги |
|
|
497
|
+
|---------|----------|----------------|
|
|
498
|
+
| `add-api <name>` | Регистрация нового API (создаёт коллекцию, директории, .env.yaml) | `--spec <path-or-url>`, `--dir <directory>`, `--env key=value` |
|
|
499
|
+
| `run <path>` | Запуск тестов (авто-привязка к коллекции) | `--api <name>`, `--env`, `--report json\|junit\|console`, `--timeout`, `--bail`, `--no-db`, `--db`, `--auth-token`, `--safe` |
|
|
500
|
+
| `ai-generate` | AI-генерация тестов из OpenAPI | `--api <name>`, `--from <spec>`, `--prompt`, `--provider`, `--model`, `--api-key`, `--base-url`, `--output` |
|
|
501
|
+
| `request <METHOD> <URL>` | Ad-hoc HTTP запрос с цветным выводом | `--header "K:V"` (multiple), `--body '{}'`, `--env`, `--timeout` |
|
|
502
|
+
| `envs [list\|get\|set\|delete]` | Управление окружениями (CRUD) | `--api <name>`, `envs get <name>`, `envs set <name> K=V ...`, `envs delete <name>` |
|
|
503
|
+
| `runs [id]` | История прогонов и детали | `--limit <n>`, `--db <path>` |
|
|
504
|
+
| `coverage` | Анализ покрытия API тестами | `--api <name>`, `--spec <path>`, `--tests <dir>` |
|
|
505
|
+
| `collections` | Список коллекций с pass rate и датой последнего прогона | `--db <path>` |
|
|
506
|
+
| `serve` | Запуск WebUI | `--port`, `--host`, `--openapi <spec>`, `--db <path>`, `--watch` |
|
|
507
|
+
| `validate` | Проверка YAML-тестов | `<path>` |
|
|
508
|
+
| `chat` | Интерактивный AI-агент для управления тестами | `--provider`, `--model`, `--api-key`, `--base-url`, `--safe` |
|
|
509
|
+
| `mcp` | MCP-сервер для AI-агентов | `--db` |
|
|
510
|
+
| `doctor` | Диагностика (DB, тесты, OpenAPI, Ollama) | `--db <path>` |
|
|
511
|
+
| `init` | Scaffolding нового проекта | `--force` |
|
|
512
|
+
| `update` | Обновление до последней версии | `--force` |
|
|
513
|
+
|
|
514
|
+
Флаг `--api <name>` — альтернатива пути, автоматически резолвит `test_path`, `openapi_spec` и `base_dir` из коллекции в DB. Пример: `apitool run --api petstore` вместо `apitool run ./apis/petstore/tests/`.
|
|
515
|
+
|
|
516
|
+
Exit codes: `0` — все тесты прошли, `1` — есть падения, `2` — ошибка конфигурации.
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### M10: AI Generation (`src/core/generator/ai/`)
|
|
521
|
+
|
|
522
|
+
AI-генерация тестов из OpenAPI-спецификации с использованием LLM.
|
|
523
|
+
|
|
524
|
+
**Архитектура:**
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
OpenAPI spec + prompt
|
|
528
|
+
│
|
|
529
|
+
▼
|
|
530
|
+
prompt-builder.ts → системный промпт + контекст API + пользовательский запрос
|
|
531
|
+
│
|
|
532
|
+
▼
|
|
533
|
+
llm-client.ts → HTTP-запрос к LLM-провайдеру
|
|
534
|
+
│
|
|
535
|
+
▼
|
|
536
|
+
output-parser.ts → JSON-ответ LLM → TestSuite[] → serializeSuite() → YAML
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
**Ключевое решение:** LLM генерирует **JSON** (не YAML), затем `serializeSuite()` конвертирует в YAML. Это обеспечивает валидный формат вне зависимости от качества ответа модели.
|
|
540
|
+
|
|
541
|
+
**Провайдеры:**
|
|
542
|
+
|
|
543
|
+
| Провайдер | Base URL | Модель по умолчанию |
|
|
544
|
+
|-----------|----------|-------------------|
|
|
545
|
+
| `ollama` | `http://localhost:11434/v1` | `qwen3:4b` |
|
|
546
|
+
| `openai` | `https://api.openai.com/v1` | `gpt-4o` |
|
|
547
|
+
| `anthropic` | `https://api.anthropic.com` | `claude-sonnet-4-20250514` |
|
|
548
|
+
| `custom` | задаётся через `--base-url` | задаётся через `--model` |
|
|
549
|
+
|
|
550
|
+
**CLI:** `apitool ai-generate --from <spec> --prompt "..." --provider <name> --model <name> --api-key <key> --output <dir>`
|
|
551
|
+
|
|
552
|
+
**WebUI:**
|
|
553
|
+
- Форма генерации: выбор провайдера, модель, промпт
|
|
554
|
+
- Preview сгенерированного YAML перед сохранением
|
|
555
|
+
- Сохранение в файл с привязкой к коллекции
|
|
556
|
+
- История генераций с View/Reuse
|
|
557
|
+
- AI badge на suite'ах, сгенерированных через AI
|
|
558
|
+
|
|
559
|
+
**БД:** таблица `ai_generations` — хранит prompt, model, provider, результат, token usage, duration.
|
|
560
|
+
|
|
561
|
+
---
|
|
562
|
+
|
|
563
|
+
### Agent — AI Chat
|
|
564
|
+
|
|
565
|
+
Интерактивный AI-агент в терминале. Использует AI SDK v6 (`generateText` + `tool()` + `stopWhen`).
|
|
566
|
+
|
|
567
|
+
**Запуск:** `apitool chat` (Ollama/qwen3:4b по умолчанию), `apitool chat --provider openai --api-key sk-...`
|
|
568
|
+
|
|
569
|
+
**7 tools:** `run_tests`, `validate_tests`, `query_results`, `manage_environment`, `diagnose_failure`, `send_request`, `explore_api` — каждый как AI SDK `tool()` с Zod `inputSchema`.
|
|
570
|
+
|
|
571
|
+
**Особенности:**
|
|
572
|
+
- Safe mode (`--safe`) — принудительно только GET-тесты
|
|
573
|
+
- Context manager — автосжатие диалога при >20 сообщений
|
|
574
|
+
- Для Ollama system prompt инжектируется в user message (workaround для thinking-моделей)
|
|
575
|
+
|
|
576
|
+
Подробная документация: [docs/agent.md](docs/agent.md)
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## Формат YAML-тестов
|
|
581
|
+
|
|
582
|
+
### Минимальный пример
|
|
583
|
+
|
|
584
|
+
```yaml
|
|
585
|
+
name: Health Check
|
|
586
|
+
tests:
|
|
587
|
+
- name: "API is alive"
|
|
588
|
+
GET: /health
|
|
589
|
+
expect:
|
|
590
|
+
status: 200
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### Полный пример (CRUD-цепочка)
|
|
594
|
+
|
|
595
|
+
```yaml
|
|
596
|
+
name: Users CRUD
|
|
597
|
+
base_url: "{{base}}"
|
|
598
|
+
headers:
|
|
599
|
+
Authorization: "Bearer {{token}}"
|
|
600
|
+
Content-Type: application/json
|
|
601
|
+
|
|
602
|
+
config:
|
|
603
|
+
timeout: 10000
|
|
604
|
+
retries: 1
|
|
605
|
+
|
|
606
|
+
tests:
|
|
607
|
+
- name: "Create user"
|
|
608
|
+
POST: /users
|
|
609
|
+
json:
|
|
610
|
+
name: "{{$randomName}}"
|
|
611
|
+
email: "{{$randomEmail}}"
|
|
612
|
+
expect:
|
|
613
|
+
status: 201
|
|
614
|
+
body:
|
|
615
|
+
id: { capture: user_id, type: integer }
|
|
616
|
+
name: { type: string }
|
|
617
|
+
duration: 2000
|
|
618
|
+
|
|
619
|
+
- name: "Get created user"
|
|
620
|
+
GET: /users/{{user_id}}
|
|
621
|
+
expect:
|
|
622
|
+
status: 200
|
|
623
|
+
body:
|
|
624
|
+
id: { equals: "{{user_id}}" }
|
|
625
|
+
email: { matches: ".+@.+" }
|
|
626
|
+
|
|
627
|
+
- name: "Update user"
|
|
628
|
+
PUT: /users/{{user_id}}
|
|
629
|
+
json:
|
|
630
|
+
name: "Updated Name"
|
|
631
|
+
expect:
|
|
632
|
+
status: 200
|
|
633
|
+
body:
|
|
634
|
+
name: { equals: "Updated Name" }
|
|
635
|
+
|
|
636
|
+
- name: "List users"
|
|
637
|
+
GET: /users
|
|
638
|
+
query:
|
|
639
|
+
page: "1"
|
|
640
|
+
limit: "10"
|
|
641
|
+
expect:
|
|
642
|
+
status: 200
|
|
643
|
+
body:
|
|
644
|
+
data: { type: array }
|
|
645
|
+
total: { type: integer, gt: 0 }
|
|
646
|
+
|
|
647
|
+
- name: "Delete user"
|
|
648
|
+
DELETE: /users/{{user_id}}
|
|
649
|
+
expect:
|
|
650
|
+
status: 204
|
|
651
|
+
|
|
652
|
+
- name: "Verify deleted"
|
|
653
|
+
GET: /users/{{user_id}}
|
|
654
|
+
expect:
|
|
655
|
+
status: 404
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
## Поток данных
|
|
661
|
+
|
|
662
|
+
```
|
|
663
|
+
CLI WebUI
|
|
664
|
+
│ │
|
|
665
|
+
▼ ▼
|
|
666
|
+
┌──────────┐ ┌───────────┐
|
|
667
|
+
│ Commands │ │ Hono │
|
|
668
|
+
└────┬─────┘ └─────┬─────┘
|
|
669
|
+
│ │
|
|
670
|
+
▼ ▼
|
|
671
|
+
┌───────────────────────────────────────┐
|
|
672
|
+
│ Core Engine │
|
|
673
|
+
│ │
|
|
674
|
+
│ ┌──────────┐ ┌──────────┐ │
|
|
675
|
+
│ │ Parser │→ │ Runner │ │
|
|
676
|
+
│ └──────────┘ └────┬─────┘ │
|
|
677
|
+
│ │ │
|
|
678
|
+
│ ┌──────────┐ ┌────▼─────┐ │
|
|
679
|
+
│ │Generator │ │ Reporter │ │
|
|
680
|
+
│ └──────────┘ └────┬─────┘ │
|
|
681
|
+
└─────────────────────┼──────────────────┘
|
|
682
|
+
│
|
|
683
|
+
┌─────▼─────┐
|
|
684
|
+
│ Storage │
|
|
685
|
+
│ (SQLite) │
|
|
686
|
+
└───────────┘
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## Roadmap (MVP)
|
|
692
|
+
|
|
693
|
+
| Модуль | Статус | Коммит | Результат |
|
|
694
|
+
|--------|--------|--------|-----------|
|
|
695
|
+
| M1 (Parser) + M2 (Runner) | DONE | `4e270ab` | `apitool run test.yaml` работает |
|
|
696
|
+
| M3 (Generator) | DONE | `e3d94d8` | OpenAPI reader, data factory, serializer (шаблонная генерация удалена → только AI) |
|
|
697
|
+
| M4 (Reporter) + M7 (CLI basic) | DONE | `e179180` | console/json/junit отчёты, CLI команды |
|
|
698
|
+
| M5 (Storage/SQLite) | DONE | `2245e79` | История прогонов в apitool.db |
|
|
699
|
+
| M6 (WebUI) | DONE | `94a58e4` | `apitool serve --port 8080 --openapi <spec>`, multi-auth panel, trend chart, filters, export |
|
|
700
|
+
| M7 (CLI) | DONE | — | run, generate, ai-generate, collections, serve, validate |
|
|
701
|
+
| M8 (Standalone binary) | DONE | `6bd2401` | `bun run build` → `apitool.exe`, CSS embedded, runtime detection |
|
|
702
|
+
| M9 (Collections) | DONE | `56a3995` | Сущность Collection, группировка runs, CLI `collections`, dashboard redesign |
|
|
703
|
+
| M10 (AI Generate) | DONE | `7901df7` | AI-генерация тестов, история генераций с View/Reuse, AI badge на сьютах, сохранение с output_path |
|
|
704
|
+
| M11 (Suite Details) | DONE | `9e4e87e` | Кликабельные сьюты (YAML, source file, AI prompt/model), показ broken-файлов с Delete, per-suite Run, улучшенный AI-промпт |
|
|
705
|
+
| M12 (Public Release) | DONE | `da9e027` | README, CHANGELOG, CI pipeline, GitHub Release workflow |
|
|
706
|
+
| M13 (Environments) | DONE | — | CRUD окружений в WebUI, key-value editor, env selector при запуске тестов |
|
|
707
|
+
| M14 (Self-Documented API) | DONE | — | OpenAPI спека из собственного API, инкрементальная генерация, dogfooding |
|
|
708
|
+
| M15 (MCP Server) | DONE | — | 11 MCP tools для AI-агентов, stdio transport |
|
|
709
|
+
| M16 (Generate Wizard) | DONE | — | Safe mode, auth-token, env creation, relative base_url |
|
|
710
|
+
| M19 (Unified Capabilities) | DONE | — | request, envs, runs, coverage CLI + 5 MCP tools + 2 agent tools |
|
|
711
|
+
| M20 (Post-M19) | DONE | — | doctor, envs import/export, DB singleton fix |
|
|
712
|
+
| M21 (Collection Architecture) | DONE | — | add-api, --api flag, environment scoping, base_dir, DB V5 |
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## Сборка и установка
|
|
717
|
+
|
|
718
|
+
```bash
|
|
719
|
+
# Разработка (требуется Bun runtime)
|
|
720
|
+
bun run src/cli/index.ts run tests/
|
|
721
|
+
|
|
722
|
+
# Компиляция в standalone бинарник
|
|
723
|
+
bun run build
|
|
724
|
+
# или: bun build --compile src/cli/index.ts --outfile apitool
|
|
725
|
+
|
|
726
|
+
# Результат: apitool / apitool.exe — один файл, Bun не нужен
|
|
727
|
+
./apitool run tests/*.yaml
|
|
728
|
+
./apitool serve --port 8080
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### Установка
|
|
732
|
+
|
|
733
|
+
Скопировать бинарник в любую папку из `PATH`:
|
|
734
|
+
|
|
735
|
+
```bash
|
|
736
|
+
# Linux / macOS
|
|
737
|
+
cp apitool /usr/local/bin/
|
|
738
|
+
|
|
739
|
+
# Windows — скопировать apitool.exe в папку из PATH
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
После этого `apitool` доступен из любой директории.
|
|
743
|
+
|
|
744
|
+
### Как работает бинарник
|
|
745
|
+
|
|
746
|
+
Бинарник **stateless** — он ничего не хранит внутри себя. Все файлы создаются в **текущей рабочей директории** (cwd):
|
|
747
|
+
|
|
748
|
+
```bash
|
|
749
|
+
cd ~/projects/myapi
|
|
750
|
+
|
|
751
|
+
# Регистрация API — создаст ./apis/myapi/, .env.yaml, запись в DB
|
|
752
|
+
apitool add-api myapi --spec openapi.json
|
|
753
|
+
|
|
754
|
+
# AI-генерация тестов
|
|
755
|
+
apitool ai-generate --api myapi --prompt "test all user endpoints"
|
|
756
|
+
|
|
757
|
+
# Запуск тестов — создаст ./apitool.db для хранения результатов
|
|
758
|
+
apitool run --api myapi
|
|
759
|
+
|
|
760
|
+
# Web-дашборд — читает apitool.db и спеку из cwd
|
|
761
|
+
apitool serve --port 4000 --openapi openapi.json
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
| Артефакт | Расположение | Описание |
|
|
765
|
+
|----------|-------------|----------|
|
|
766
|
+
| YAML-тесты | `./generated/` (или `--output <dir>`) | Сгенерированные/написанные тесты |
|
|
767
|
+
| `apitool.db` | `./apitool.db` (или `--db <path>`) | SQLite — история прогонов |
|
|
768
|
+
| OpenAPI спека | указывается через `--from` / `--openapi` | Читается, не копируется |
|
|
769
|
+
|
|
770
|
+
### Runtime detection
|
|
771
|
+
|
|
772
|
+
```bash
|
|
773
|
+
./apitool --version
|
|
774
|
+
# apitool 0.1.0 (standalone) — из скомпилированного бинарника
|
|
775
|
+
|
|
776
|
+
bun src/cli/index.ts --version
|
|
777
|
+
# apitool 0.1.0 (bun) — из dev-режима
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
---
|
|
781
|
+
|
|
782
|
+
## M15: MCP Server (AI-agent интеграция)
|
|
783
|
+
|
|
784
|
+
APITOOL предоставляет MCP (Model Context Protocol) сервер для интеграции с AI-агентами (Claude Code, Cursor, Windsurf, Cline).
|
|
785
|
+
|
|
786
|
+
### Запуск
|
|
787
|
+
|
|
788
|
+
```bash
|
|
789
|
+
apitool mcp # stdio transport
|
|
790
|
+
apitool mcp --db ./my.db # с кастомным путём к БД
|
|
791
|
+
```
|
|
792
|
+
|
|
793
|
+
### MCP Tools
|
|
794
|
+
|
|
795
|
+
| Tool | Описание |
|
|
796
|
+
|------|----------|
|
|
797
|
+
| `run_tests` | Запуск тестов из YAML-файла/директории, возврат summary |
|
|
798
|
+
| `validate_tests` | Валидация YAML без запуска |
|
|
799
|
+
| `list_collections` | Список коллекций с статистикой |
|
|
800
|
+
| `list_runs` | Список последних прогонов |
|
|
801
|
+
| `get_run_results` | Детальные результаты конкретного прогона |
|
|
802
|
+
| `list_environments` | Список окружений (ключи переменных, без значений) |
|
|
803
|
+
| `send_request` | Ad-hoc HTTP запрос с variable interpolation из окружений |
|
|
804
|
+
| `explore_api` | Просмотр OpenAPI спеки — endpoints, servers, security schemes, фильтр по tag |
|
|
805
|
+
| `manage_environment` | CRUD окружений — list, get, set, delete (с `collectionName` для scoping) |
|
|
806
|
+
| `diagnose_failure` | Диагностика падений — анализ failed steps и assertion mismatches |
|
|
807
|
+
| `coverage_analysis` | Анализ покрытия API тестами (spec vs test files) |
|
|
808
|
+
|
|
809
|
+
### Конфигурация Claude Code
|
|
810
|
+
|
|
811
|
+
```json
|
|
812
|
+
// .claude/settings.json или claude_desktop_config.json
|
|
813
|
+
{
|
|
814
|
+
"mcpServers": {
|
|
815
|
+
"apitool": {
|
|
816
|
+
"command": "apitool",
|
|
817
|
+
"args": ["mcp"]
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
## Принципы
|
|
826
|
+
|
|
827
|
+
1. **Один файл** — скачал бинарник, запустил, работает. Без Docker, без apt install.
|
|
828
|
+
2. **Тесты как код** — YAML в git, code review, merge requests.
|
|
829
|
+
3. **OpenAPI-first** — спецификация есть → тесты генерируются.
|
|
830
|
+
4. **Два режима** — CLI для CI/CD, WebUI для команды. Одна кодовая база.
|
|
831
|
+
5. **SQLite по умолчанию** — история работает из коробки, без настройки БД.
|