qa

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 0 Imported by: 0

README

qa — кроссплатформенные прогоны QA

Прогон целиком на Go — без sh/cmd/bat (внешние команды — только go, gofmt, git для коммита в отчёте и собранные бинарники проекта); работает на Linux, macOS, Windows, железо и окружение определяет сам.

Состав

Файл Назначение
runner/ Прогонщик: фазы environment → build → static → consumer → сценарии CLI/REST по ногам → load; структурный отчёт qa-log/1 в qa/reports/*.log; код выхода 0 — все проверки зелёные
restsrv/ Минимальный хост REST /api/v1 для прогонов (модуль серверов не запускает — план 04 §5); поднимается прогонщиком, порт выбирает сам (--addr 127.0.0.1:0) и сообщает фактический адрес строкой готовности
load_test.go Нагрузочная прикидка: генерация NDJSON-датасета синтетических транзисторов JEDEC, импорт боевым путём, измерения поиска/карточки/suggest против ориентиров; запускается прогонщиком (-scale) либо напрямую go test (с -count=1 — измерение не берётся из кэша результатов)
reports/ Авто-отчёты прогонов qa-*.log (формат ниже; коммитятся как свидетельство прогонов) и аналитические отчёты *.md

Запуск

go run ./qa/runner                                        # SQLite
CATALOG_TEST_POSTGRES_DSN=postgres://… go run ./qa/runner # + PostgreSQL
CATALOG_QA_DIALECT=postgres CATALOG_TEST_POSTGRES_DSN=postgres://… \
    go run ./qa/runner                                    # только PostgreSQL
go run ./qa/runner -scale 10000                           # + нагрузочная прикидка
go run ./qa/runner -report qa/reports/x.log -keep         # свой отчёт, не удалять временный каталог

Ключи: -report (путь файла отчёта; по умолчанию qa/reports/qa-<дата>-<goos>-<goarch>.log, где <дата> — ГГГГММДД-ЧЧММСС-наносекунды: коллизии имён повторных прогонов в пределах секунды исключены), -postgres-dsn (DSN PostgreSQL; по умолчанию CATALOG_TEST_POSTGRES_DSN, пусто — нога опущена), -reset-postgres, -dialect (единственная нога прогона: sqlite | postgres, переносятся сценарии и нагрузочная прикидка; по умолчанию CATALOG_QA_DIALECT, пусто — все доступные ноги; postgres без DSN — отказ до прогона), -scale (по умолчанию CATALOG_QA_SCALE; 0 — фаза опущена, отрицательное значение — отказ до прогона), -keep.

Сброс PostgreSQL деструктивен (DROP таблиц модуля) и ограждён: база из env-конвенции CATALOG_TEST_POSTGRES_DSN — одноразовая по регламенту (internal/testutil чистит её каждым go test) и сбрасывается автоматически; база из флага -postgres-dsn — произвольная, сбрасывается только с явным -reset-postgres, без него нога идёт по текущему состоянию базы (грязная база падает на абсолютных проверках видимым образом — безопасный отказ вместо разрушения данных). Список таблиц — storage.TableNames(), выводится из DDL хранилища.

Код выхода: 0 — PASS, 1 — есть отказы проверок, 2 — прогон не начат (не найден корень модуля, не открыт отчёт, неверные ключи — в том числе отрицательный -scale), 130 — прогон отменён сигналом (Ctrl+C/SIGTERM). Отменённый прогон: шаги, прерванные отменой или не начатые, помечаются заметками «отменён» и не числятся FAIL; в [summary] добавляется поле cancelled: yes; код 130 приоритетнее кода 1 (реальные отказы до отмены видны в отчёте). Повторный Ctrl+C после первого завершает процесс немедленно (умолчание сигнала), не дожидаясь остановки команд фаз.

CI (.github/workflows/ci.yml): три джобы — Linux на SQLite, Linux со службой PostgreSQL 16 и Windows на SQLite, каждая с прикидкой 10⁴ (CATALOG_QA_SCALE=10000, CATALOG_QA_DIALECT задаёт единственную ногу джобы) — кроссплатформенность и обе СУБД проверяются каждым PR и каждым коммитом без зелёного прогона: на пуше (main или тег v*) джоба skip-check ищет через Actions API успешный прогон CI на том же коммите и при находке пропускает все три джобы (тег указывает на коммит из main, fast-forward-мерж — на голову PR, оба уже покрыты); артефакт сборки — только отчёт текущего прогона (свежий qa/reports/*.log копируется в qa-artifact/ по маркеру времени старта шага и выгружается оттуда; закоммиченные исторические отчёты в артефакт не попадают).

Фазы прогона

  1. environment — железо и окружение (см. ниже).
  2. build — сборка catalogctl и qa/restsrv во временный каталог.
  3. static — go build ./..., go vet ./..., gofmt -l . (обязан быть пуст), go test ./... — полный контур проверки AGENTS.md. При заданном DSN PostgreSQL go test идёт с -p 1: одноразовая база одна на все пакеты, параллельные пакеты конфликтуют на DROP/CREATE таблиц (deadlock 40P01, гонка создания системных типов 23505). Отказ фазы не прерывает прогон (итог — в отчёте); фаза выполняется и при провале сборки бинарников — ей они не нужны.
  4. consumer — сборка и запуск примера встраивания examples/embed (внешний модуль: зависимость на библиотеку подключена require + replace на локальный путь, импортируется только публичный фасад components): компилируемость у внешнего потребителя — часть контракта фасада, внутримодульные тесты импортируют internal/ и подлинности не доказывают. Бинарник исполняется (одноразовая база sqlite — пример создаёт и удаляет её сам): импорт файла наполнения, поиск, REST через app.Handler(), round-trip экспорт.
  5. cli / rest по ногам — SQLite всегда; PostgreSQL при заданном DSN (одноразовая база очищается прогонщиком перед ногой по ограждённым правилам — см. «Запуск»; абсолютные проверки count не зависят от остатков прошлых прогонов); -dialect оставляет единственную указанную ногу. При провале сборки бинарников (фаза build) обе сценарные фазы помечаются пропуском с причиной — зависят от catalogctl/restsrv. Сценарии CLI: init, импорт выверенной выборки data/, идемпотентность, round-trip экспорта (ndjson по классу, yaml полностью), list с фильтрами класса/системы/подстроки, info (карточка, матрица исполнений), find с подсказкой равнозначного по материалу, parse (автодетект, JEDEC, негатив), --dry-run, каскадное удаление, битый файл, catalog list; негативные случаи — префикс Error: (канонический en — D9) и код выхода 1. Сценарии REST: kinds/catalog/stats, поиск с фильтрами и параметрический фильтр, ETag → 304, карточки по ключу и по id, POST/PUT/DELETE с кодами 201/409/422/204/404, suggest, неизвестный маршрут; HTTP — net/http, без внешних инструментов.
  6. load (при -scale/CATALOG_QA_SCALE) — нагрузочная прикидка боевым go test ./qa -run TestLoad -count=1 (кэш результатов отключён — прикидка обязана выполняться, а не реплицироваться); строки измерений (p50/p95, скорость импорта) попадают в отчёт заметками.

Определение железа и окружения

Прогонщик сам определяет платформу и фиксирует её в секции [environment]:

  • переносимо (stdlib): ОС (runtime.GOOS), архитектура, число логических ядер, имя хоста, версия Go, модуль и коммит (build info, при отсутствии штампов vcs — git rev-parse), грязнота рабочего дерева, версии драйверов СУБД, версия библиотеки SQLite, версия сервера PostgreSQL (при заданном DSN);
  • ядро ОС: Linux — /proc/sys/kernel/osrelease (uname -r), macOS — XNU (kern.osrelease), Windows — номер сборки ядра NT (CurrentBuildNumber
    • UBR из реестра);
  • Linux: модель CPU (/proc/cpuinfo), память (/proc/meminfo), издание ОС (/etc/os-release);
  • macOS: sysctl (machdep.cpu.brand_string, hw.memsize, kern.osproductversion) через golang.org/x/sys/unix;
  • Windows: реестр (ProcessorNameString, ProductName/DisplayVersion) и GlobalMemoryStatusEx (kernel32) через golang.org/x/sys/windows.

Внешних зависимостей не добавлено: golang.org/x/sys уже был в графе модуля.

Формат отчёта qa-log/1

Отчёт — текстовый .log с фиксированной грамматикой (парсится построчно, читается человеком; пишется построчно — прерванный прогон оставляет частичный отчёт):

# components-catalog QA report
format: qa-log/1

[environment]
ключ: значение          # поля окружения и железа

[phase: cli sqlite]
ok   cli/init — init: база инициализирована
FAIL cli/count — count: записи выборки
      | exit=0          # детали — только у отказов
      | 65

[summary]
checks: 50
passed: 50
failed: 0
verdict: PASS
  • первая строка — маркер отчёта, поле format: qa-log/1 — версия формата;
  • секции — [environment], [phase: <имя>], [summary];
  • поля — ключ: значение, отсутствующее значение — —;
  • проверки — ok <id> — <описание> / FAIL <id> — <описание> (<id> — стабильный латинский идентификатор вида cli/init, rest/post-create, static/gofmt); детали отказа — строки с отступом, начинающиеся с |;
  • заметки — строки note … (в том числе пропущенные шаги: отменённые сигналом — note <id> — …: отменён — и зависящие от проваленной сборки фазы);
  • итог — verdict: PASS|FAIL (FAIL — код выхода 1); у отменённого сигналом прогона в [summary] появляется поле cancelled: yes, отменённые шаги не FAIL, код выхода — 130.

Ориентиры производительности (docs/plan/04 §5)

  • поиск с фильтрами по 10⁴–10⁵ устройств ≤ 100 мс;
  • карточка ≤ 20 мс.

Прикидка — измерение, а не порог: медиана (p50) и 95-й перцентиль (p95) печатаются с меткой ok / ПРЕВЫШЕНИЕ (метка — по медиане) и фиксируются отчётом. Превышение ориентира — материал для плана Б по риску R2 (денормализация/материализация вынесенных фильтров без смены публичного API), а не автоматический отказ прогона; отказ — только строгий режим (CATALOG_QA_STRICT=1, превышение на порядок) либо ошибки корректности (отказы импорта).

Переменные прикидки: CATALOG_QA_SCALE (число записей), CATALOG_QA_DIALECT (sqlite по умолчанию; заданная — единственная нога и прогона целиком), CATALOG_QA_DB (путь файла sqlite; учитывается только при диалекте sqlite — при CATALOG_QA_DIALECT=postgres игнорируется, база ноги определяется CATALOG_TEST_POSTGRES_DSN), CATALOG_QA_STRICT=1. Масштаб 10⁵ — ручной прогон по мере надобности (в аналитический отчёт). База прикидки по умолчанию — одноразовый каталог qa/tmp/load-* внутри репозитория (игнорируется git, удаляется после прогона вместе с WAL/SHM): база обязана лежать на реальном диске — каталог ОС по умолчанию (/tmp, %TEMP%) на части систем — tmpfs в памяти, и импорт перестал бы касаться диска, делая сравнение носителей бессмысленным. Явный CATALOG_QA_DB сохраняет файл для диагностики; фактическое расположение фиксируется строкой диалект=… база=… в отчёте. Повторный прогон с сохранённой базой допустим с тем же или большим масштабом (проверяется итоговое число записей); масштаб меньше уже находящегося в базе даст честный отказ количество/переполнение. При прямом запуске go test без прогонщика добавляйте -count=1 — иначе повторный прогон с тем же масштабом вернётся из кэша результатов go test за нулевое время со старыми результатами измерений.

Толкование цифр PostgreSQL: импорт — транзакция на запись (~20 statement'ов), каждый — round-trip до сервера, поэтому скорость импорта определяется задержкой сети, а не СУБД (docker-прокси опубликованного порта добавляет ~40% к RTT против прямого адреса; sqlite тот же путь выполняет in-process). Поиск/карточка на postgres несут 1–3 round-trip на операцию — разница с sqlite в единицы мс это норма клиент-серверной СУБД. JIT postgres для соединений модуля отключён на уровне драйвера (jit=off в DSN, план 02 §4) — иначе компиляция планов параметрического поиска добавляла сотни мс на каждый запрос.

Documentation

Overview

Package qa — прогоны QA: кроссплатформенный прогонщик qa/runner (сборка, статические проверки, сквозные сценарии CLI и REST на SQLite и PostgreSQL, структурный отчёт qa-log/1) и нагрузочная прикидка против ориентиров производительности (load_test.go). Регламент запуска и формат отчётов — qa/README.md.

Directories

Path Synopsis
Команда restsrv — минимальный хост REST /api/v1 для сквозных сценарных прогонов (qa/runner).
Команда restsrv — минимальный хост REST /api/v1 для сквозных сценарных прогонов (qa/runner).
Сценарии CLI: сквозной прогон catalogctl против ноги прогона (sqlite или postgres).
Сценарии CLI: сквозной прогон catalogctl против ноги прогона (sqlite или postgres).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL