Help us shape the future of Go! Take the 2026 Go Developer Survey

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