Документирован 3-й аудит, трёхсостояночный lock_check, созданные тесты и план эмулятора API
This commit is contained in:
@@ -241,3 +241,90 @@ CREATE UNIQUE INDEX idx_one_running
|
|||||||
| escName `"` | JS | ❌ Неполный → ✅ добавлен `"` |
|
| escName `"` | JS | ❌ Неполный → ✅ добавлен `"` |
|
||||||
| instances.js onclick | JS | ⚠️ Низкий риск, UUID безопасен |
|
| instances.js onclick | JS | ⚠️ Низкий риск, UUID безопасен |
|
||||||
| `lock_check` fallback | Python | ✅ `True`→`False` при ошибке БД |
|
| `lock_check` fallback | Python | ✅ `True`→`False` при ошибке БД |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Третий аудит Codex + трёхсостояночный lock_check (v1.2.22-v1.2.23)
|
||||||
|
|
||||||
|
Codex проверил v1.2.21 и нашёл 3 проблемы. Две исправлены, одну — обсудили и
|
||||||
|
пришли к правильному решению:
|
||||||
|
|
||||||
|
### Исправлено
|
||||||
|
|
||||||
|
1. **UniqueViolation → 500 (не 409)** — `api_scenario_run.py:78`.
|
||||||
|
INSERT ловился общим `except` → 500. Теперь: `e.pgcode == '23505'` → 409. (v1.2.22)
|
||||||
|
|
||||||
|
2. **escName без `&`** — `scenario-list.js:128`.
|
||||||
|
`'` декодируется браузером в `'` до JS → разрыв строки.
|
||||||
|
Добавлен `.replace(/&/g,'&')` ПЕРВЫМ шагом. (v1.2.22)
|
||||||
|
|
||||||
|
### Обсуждено и исправлено правильно
|
||||||
|
|
||||||
|
3. **`lock_check` fallback — трёхсостояночный подход** (v1.2.23):
|
||||||
|
|
||||||
|
Исходно Codex предложил `True`→`False` при no-db. AI слепо сделал.
|
||||||
|
Пользователь возразил: `False` ломает запуск при деградации БД.
|
||||||
|
|
||||||
|
Codex согласился и предложил трёхсостояночный возврат:
|
||||||
|
- `True` — можно запускать (нет RUNNING)
|
||||||
|
- `False` — нельзя (есть RUNNING) → 409
|
||||||
|
- `None` — БД недоступна → 503
|
||||||
|
|
||||||
|
`api_scenario_run.py` обрабатывает `None` как 503 DB unavailable.
|
||||||
|
|
||||||
|
### Созданы тесты (Codex, только сохранены, не запущены)
|
||||||
|
|
||||||
|
`tests/` — 4 файла, покрывают критические фиксы:
|
||||||
|
|
||||||
|
| Файл | Что тестирует |
|
||||||
|
|------|---------------|
|
||||||
|
| `conftest.py` | Flask test client + sys.path |
|
||||||
|
| `test_api_scenario_run.py` | 503 при `lock_check=None`, 409 при `False`, 409 при `UniqueViolation(pgcode=23505)` |
|
||||||
|
| `test_db_scenario_defs.py` | `lock_check → None` при no-db и ошибке БД |
|
||||||
|
| `test_static_regressions.py` | Статическая проверка `idx_one_running` в init_db.py и цепочки `escName` в scenario-list.js |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## План: эмулятор Nubes API для интеграционных тестов
|
||||||
|
|
||||||
|
### Зачем
|
||||||
|
Реальные тесты медленные (поллинг до 30 минут) и жрут ресурсы облака.
|
||||||
|
Эмулятор даст: быстрые тесты (< 1 сек), детерминизм, краевые случаи, CI/CD.
|
||||||
|
|
||||||
|
### Архитектура
|
||||||
|
```
|
||||||
|
site/
|
||||||
|
├── app.py # основное приложение
|
||||||
|
└── mock/
|
||||||
|
└── nubes_mock.py # эмулятор API Nubes (Flask, порт 5001)
|
||||||
|
```
|
||||||
|
|
||||||
|
В `app.py` — переключение по `NUBES_MOCK=1` → эндпоинт `http://localhost:5001/api/v1/svc`.
|
||||||
|
|
||||||
|
### Эндпоинты для эмуляции (Болванка, сервис 1)
|
||||||
|
|
||||||
|
| Метод | Путь | Ответ |
|
||||||
|
|-------|------|-------|
|
||||||
|
| POST | `/instances` | 201 + `{instanceUid}` |
|
||||||
|
| GET | `/instances?pageSize=200` | `{results: [...]}` |
|
||||||
|
| GET | `/instances/{uid}` | `{instance: {state: {params: {...}}}}` |
|
||||||
|
| GET | `/services` | `{results: [{svcId: 1, svc: "dummy"}]}` |
|
||||||
|
| GET | `/services/1` | `{svc: {operations: [...]}}` |
|
||||||
|
| POST | `/instanceOperations` | `{instanceOperationUid}` |
|
||||||
|
| POST | `/instanceOperationCfsParams` | `{}` |
|
||||||
|
| POST | `/instanceOperations/{uid}/run` | `{}` |
|
||||||
|
| GET | `/instanceOperations/{uid}?fields=...` | `{instanceOperation: {dtFinish, isSuccessful, ...}}` |
|
||||||
|
| GET | `/instanceOperations/default/{id}` | `{svcOperation: {cfsParams: [...]}}` |
|
||||||
|
| GET | `/instanceOperations/{uid}/validate-cfs` | `{}` (200 OK) |
|
||||||
|
|
||||||
|
### Что сложнее
|
||||||
|
|
||||||
|
- `cfsParams` — у каждого сервиса своя структура, придётся хардкодить под Болванку
|
||||||
|
- `refSvcId` — ссылки на другие сервисы (External IP и т.д.) — отложить
|
||||||
|
- `stages` — этапы выполнения (plan→apply→...) — отдавать фейковые
|
||||||
|
|
||||||
|
### Порядок создания
|
||||||
|
|
||||||
|
1. `mock/nubes_mock.py` — Flask-заглушка (~150 строк)
|
||||||
|
2. Интеграционный тест: сценарий `create→modify→delete` через `app_client`
|
||||||
|
3. `NUBES_MOCK=1` в `app.py` для переключения эндпоинта
|
||||||
|
|||||||
Reference in New Issue
Block a user