http: тесты приёма переписаны на подставные адаптеры
- проверки больше не зовут ffprobe и не меняют рабочий каталог процесса; добавлены случаи на отказ чтения метаданных и на отсутствие поля audio - заведена спека intake на приём по HTTP, ADR о подставных адаптерах, запись в журнал ревью о проверке, которая не могла упасть - go test снят из объявленных долгов CLAUDE.md, послабление errcheck для _test.go в .golangci.yml убрано
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# Проверки не зовут внешних программ
|
||||
|
||||
- **Дата:** 2026-08-11
|
||||
- **Источник:** openspec/changes/archive/2026-08-11-fix-http-handler-tests/design.md
|
||||
|
||||
## Решение
|
||||
|
||||
Тесты приёма получают длительность записи от подставного источника метаданных, а
|
||||
не от `ffprobe`. Годность содержимого судит адаптер, тест судит наш код.
|
||||
|
||||
## Почему
|
||||
|
||||
Цитата из источника, раздел `Decisions`:
|
||||
|
||||
> **проверять приём сквозь настоящий `ffprobe`.** Отвергнуто: это проверка
|
||||
> внешней программы, а не нашего кода. Она найдёт отказ `ffprobe` и не найдёт
|
||||
> ошибку в приёме — ровно наоборот тому, зачем эти тесты писались.
|
||||
|
||||
Отвергнуты там же два очевидных пути, и оба по записанным правилам проекта, а не
|
||||
по вкусу:
|
||||
|
||||
> **положить настоящую запись в `testdata`.** Отвергнуто дважды: `.gitignore`
|
||||
> строкой `*.m4a` её не пустит, а `CLAUDE.md` прямо говорит, что `testdata` в
|
||||
> проекте нет и тесты создают нужное во временном каталоге. Снимать запрет ради
|
||||
> теста — менять правило проекта под удобство одного файла;
|
||||
>
|
||||
> **порождать запись `ffmpeg` прямо в тесте.** Отвергнуто: проверка приёма
|
||||
> начинает требовать установленных `ffmpeg` и `ffprobe`, а критерий приёмки
|
||||
> требует обратного — прогона с `ffprobe`, убранным из `PATH`.
|
||||
|
||||
Решение попадает в журнал как **намеренный отказ от очевидного подхода**: файл с
|
||||
настоящей записью в `testdata` — первое, что сделал бы человек, и отказ от него
|
||||
из кода не виден.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` прогон проверок на чистом клоне зелёный без подготовки файлов руками и без
|
||||
установленных внешних программ. Проверено сборкой тестового бинарника и
|
||||
прогоном под `env -i PATH=<пустой каталог>`.
|
||||
- `+` ветка отказа чтения метаданных впервые проверяема: подставной источник
|
||||
умеет вернуть ошибку, настоящий `ffprobe` по заказу не отказывает.
|
||||
- `+` проверки не держат состояния процесса: каталог хранения задаётся снаружи,
|
||||
`os.Chdir` ушёл, и параллельный прогон перестал быть запрещённым.
|
||||
- `−` разбор вывода настоящего `ffprobe` не проверяется ничем: своего теста у
|
||||
`internal/adapter/metaviewer/ffmpeg` нет. Формально покрытие не потеряно —
|
||||
прежние проверки звали его так, что он всегда отказывал, — но дыра теперь
|
||||
наша и записана в [../review.md](../review.md), «Перестали проверять
|
||||
сознательно».
|
||||
- `−` правило распространяется на будущие проверки: узел, чья работа и есть
|
||||
обращение к внешней программе, придётся проверять иначе, и чем — здесь не
|
||||
решено.
|
||||
+5
-5
@@ -31,9 +31,9 @@
|
||||
|
||||
| Дата | Запись | Статус |
|
||||
| --- | --- | --- |
|
||||
| 2026-08-11 | [Проверки не зовут внешних программ](ADR-2026-08-11-stub-adapters-in-tests.md) | |
|
||||
|
||||
Записей нет: канон заведён 2026-08-10, а решения, принятые до него, источника в
|
||||
архиве изменений не имеют — сочинять их задним числом правило запрещает.
|
||||
Ближайшие кандидаты назовёт первое же изменение, которое тронет хранилище или
|
||||
вход: замена SQLite на PocketBase и вход через OIDC оба проходят триггер
|
||||
«дорогой откат».
|
||||
Решения, принятые до заведения канона 2026-08-10, источника в архиве изменений
|
||||
не имеют — сочинять их задним числом правило запрещает. Ближайшие кандидаты
|
||||
назовёт первое же изменение, которое тронет хранилище или вход: замена SQLite на
|
||||
PocketBase и вход через OIDC оба подпадают под критерий «дорогой откат».
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
[passport.md](passport.md) и в [tasks/ROADMAP.md](../tasks/ROADMAP.md); что из
|
||||
этого ещё не решено — в разделе «Открытые вопросы».
|
||||
|
||||
Спеки ещё не заведены: capability ни одной, поведение живёт только в коде.
|
||||
Первая задача, которая трогает поведение, заводит спеку — до тех пор у темы
|
||||
`requirements` нормативного документа нет.
|
||||
Заведена одна capability — [intake](../openspec/specs/intake/spec.md), и в ней
|
||||
описан **только приём по HTTP**: его нормируют проверки, написанные задачей
|
||||
`http-handler-tests-never-green` 2026-08-11. Поведение прочих узлов, включая
|
||||
приём из Telegram, по-прежнему живёт только в коде. Задача, которая его трогает,
|
||||
дописывает спеку своей capability.
|
||||
|
||||
## Принципы
|
||||
|
||||
|
||||
+38
-6
@@ -55,7 +55,12 @@
|
||||
|
||||
- изменённое место покрыто хоть одним **проходящим** тестом. Тест, который
|
||||
никогда не был зелёным, обнуляет сигнал всего пакета: настоящий отказ в нём
|
||||
становится неотличим от привычного шума (журнал, запись 2026-08-10).
|
||||
становится неотличим от привычного шума (журнал, запись 2026-08-10);
|
||||
- проверка **способна упасть**. Утверждение, разбирающее ответ в ту же
|
||||
структуру, чьи теги и составляют проверяемый контракт, меняется вместе с ним
|
||||
и никогда не ловит поломку; такое судят по сырому виду ответа. Признак ищется
|
||||
мутацией: сломай проверяемое свойство и убедись, что тест краснеет (журнал,
|
||||
запись 2026-08-11).
|
||||
|
||||
### Типовые ложноположительные
|
||||
|
||||
@@ -154,14 +159,39 @@ API и имя не откатываются обратной правкой по
|
||||
|
||||
**Перестали проверять сознательно:**
|
||||
|
||||
Ничего не отключали — проверять пока и не начинали.
|
||||
- `autotests`: разбор вывода настоящего `ffprobe`. Проверки приёма звали его до
|
||||
2026-08-11 — правда, звали так, что он всегда отказывал, — а теперь получают
|
||||
длительность от подставного источника. Своего теста у
|
||||
`adapter/metaviewer/ffmpeg` нет; решение и его цена — в
|
||||
[adr/ADR-2026-08-11-stub-adapters-in-tests.md](adr/ADR-2026-08-11-stub-adapters-in-tests.md).
|
||||
|
||||
## Журнал дефектов
|
||||
|
||||
Первая запись найдена прогоном гейта при заведении канона 2026-08-10, две
|
||||
нижние восстановлены по истории git тогда же. Все три помечены `проскочил`:
|
||||
ревью тогда не было, и поймать их было некому. У восстановленных нет поля «Чем
|
||||
воспроизведён», и выдумывать его задним числом нельзя.
|
||||
Верхняя запись найдена конвейером ревью на первом же его прогоне, вторая —
|
||||
прогоном гейта при заведении канона 2026-08-10, две нижние восстановлены по
|
||||
истории git тогда же. Три нижние помечены `проскочил`: ревью тогда не было, и
|
||||
поймать их было некому. У восстановленных нет поля «Чем воспроизведён», и
|
||||
выдумывать его задним числом нельзя.
|
||||
|
||||
## 2026-08-11 — проверка приёма не могла упасть [пойман ревью]
|
||||
|
||||
- **Где:** `internal/controller/http/transcribe_test.go`, случай успеха приёма
|
||||
- **Симптом:** тест не поймал ни одного настоящего дефекта приёма, хотя был
|
||||
зелёным и выглядел содержательным
|
||||
- **Причина:** две штуки одного рода. Тест разбирал ответ в
|
||||
`CreateTranscribeJobResponse` — ту самую структуру, чьи теги `json` и
|
||||
составляют публичный контракт: переименование тега меняло и проверяемое, и
|
||||
ожидаемое разом. И заведение задачи тест подтверждал только эхом ответа, а не
|
||||
чтением базы
|
||||
- **Чем воспроизведён:** мутацией. Замена тега на `json:"jobId"` и удаление
|
||||
`s.jobRepo.Create(job)` из `internal/service/transcribe.go` — тесты в обоих
|
||||
случаях оставались зелёными; после правки обе мутации их роняют
|
||||
- **Почему не поймали:** проверки писались тем же заходом, что и правились, а
|
||||
«зелено» на новом тесте читается как подтверждение. Поймал проход `specs`
|
||||
ревью кода, и поймал ровно тем, что добыл оракул мутацией, а не рассуждением
|
||||
- **Что меняем:** успех судится по сырому JSON и по строке в базе. В типовые
|
||||
узлы, «Любой узел», добавлено свойство «проверка способна упасть» с указанием
|
||||
на мутацию как способ его проверить
|
||||
|
||||
## 2026-08-10 — тесты http-обработчика ни разу не были зелёными [проскочил]
|
||||
|
||||
@@ -181,6 +211,8 @@ API и имя не откатываются обратной правкой по
|
||||
шире: **тест, который никогда не проходил, обнуляет сигнал всего пакета** — в
|
||||
типовые узлы добавлено свойство «покрыт хоть одним проходящим тестом», а в
|
||||
вопросы темы `autotests` — вопрос про изменённый шаг конвейера
|
||||
- **Закрыт** 2026-08-11: проверки переписаны, `go test ./...` зелёный и из
|
||||
списка объявленных долгов в [CLAUDE.md](../CLAUDE.md) снят
|
||||
|
||||
## 2025-10-23 — пустой ответ вместо текста расшифровки [проскочил]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user