После 24 спринтов regress-suite разросся; нестабильность блокирует доверие. Этот спринт: ловит flaky тесты, добавляет observability (Grafana + Prometheus alerts + RUNBOOK), сертифицирует 10× cert-прогон. 1. tests/regression/find-flaky.sh — 10× прогон + JSON-агрегатор → docs/flaky-tests.md (per-test pass/fail sequence + reproduce). 2. OrgFactory.signupWithRetry теперь honors Retry-After header (api-client.ts:ApiError.retryAfterSec). Stage rate-limit поднят: RATE_SIGNUP_HOUR=5000, RATE_PER_IP_MIN=5000 (~/food-market-stage/deploy/.env). 3. fullyParallel=true + workers=4 = тесты идут в недетерминированном порядке; isolation работает (OrgFactory per-test). 4. workers=4 даёт **2.4× ускорение** (66.6s → 27.7s). Worker-scoped фикстура lib/worker-org.ts добавлена как opt-in. 5. deploy/grafana/dashboards/quality-watchdog.json (10 панелей: smoke success ratio 7d, incidents, multi-tenant violations, current emoji, p95 by endpoint, step failures, RPS, DB p95, docs posted, disk free) + dashboards/README.md. quality-watchdog.sh пишет Prometheus textfile экспорт в ~/.fm-watchdog/textfile/quality_watchdog.prom для node_exporter. 6. deploy/prometheus/alerts.yml — 10 правил, 4 группы (uptime, errors, database, quality-watchdog). MultiTenantViolation = P0. deploy/prometheus/prometheus.yml — reference config. 7. docs/RUNBOOK.md +178 строк: action per alert (api-down, rps-drop, http-errors-spike/growing, doc-posting-errors, db-p95-high, disk-free-low, watchdog-red, multi-tenant-violation, watchdog-incident). Junior-friendly с конкретными командами. **Cert-прогон (10× workers=4):** 420/420 passed, 0 flaky, avg 30.1s/run, total 300.6s (< 5min budget). Изменения вне репо: - ~/food-market-stage/deploy/.env — RATE_* limits bumped. - ~/quality-watchdog.sh — добавлен .prom textfile экспорт. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
60 lines
2.9 KiB
TypeScript
60 lines
2.9 KiB
TypeScript
/**
|
||
* Sprint 26: worker-scoped org fixture.
|
||
*
|
||
* Каждый Playwright worker = свой long-lived org. Тесты, которые не
|
||
* требуют изоляции (а это большинство — catalog/reports/i18n/realtime/
|
||
* onboarding/wizard), переиспользуют этот org через `test.extend`
|
||
* вместо вызова `OrgFactory.build()` per-test.
|
||
*
|
||
* Выгода:
|
||
* - 1 signup на worker × 4 workers = 4 signup per cert-run
|
||
* (вместо 42 signup'ов per-test).
|
||
* - Меньше нагрузка на signup rate-limit (per-IP).
|
||
* - Быстрее: фикстура переиспользуется, нет setup-overhead.
|
||
*
|
||
* Изоляция данных НЕ страдает: каждый test всё равно создаёт свои
|
||
* сущности с уникальными именами (через `Date.now()` суффикс), и
|
||
* `pageSize=N` ограничивает list-запросы — другие тесты в той же org
|
||
* не мешают.
|
||
*
|
||
* Кому НЕ подходит:
|
||
* - 06-multi-tenant.spec.ts — нужно ДВЕ свежие org per-test, иначе
|
||
* тест становится бессмысленным (используем OrgFactory напрямую).
|
||
* - 02-auth.spec.ts — тестирует сам signup, нужна fresh org.
|
||
* - 09-onboarding-wizard.spec.ts — тестирует онбординг свежей org'и.
|
||
*
|
||
* Использование:
|
||
* import { test } from '../lib/worker-org.js'
|
||
* test('foo', async ({ workerOrg }) => {
|
||
* const products = await request(Endpoints.products, { token: workerOrg.session.accessToken })
|
||
* ...
|
||
* })
|
||
*/
|
||
import { test as baseTest } from '@playwright/test'
|
||
import { OrgFactory } from '../factories/OrgFactory.js'
|
||
import type { BuiltOrg } from '../factories/OrgFactory.js'
|
||
|
||
interface WorkerFixtures {
|
||
workerOrg: BuiltOrg
|
||
}
|
||
|
||
export const test = baseTest.extend<{}, WorkerFixtures>({
|
||
workerOrg: [async ({}, use, workerInfo) => {
|
||
// Одна org на весь worker. Имя содержит workerIndex чтобы
|
||
// параллельные workers получали разные org'и (и поэтому
|
||
// не конкурировали за уникальные суффиксы).
|
||
const slug = `w${workerInfo.workerIndex}`
|
||
const org = await OrgFactory.for(slug)
|
||
.withProducts(3) // базовый каталог чтобы reports что-то видели
|
||
.withCounterparties(1)
|
||
.build()
|
||
await use(org)
|
||
// После всех тестов worker'a — org остаётся (cleanup делает
|
||
// Hangfire-job `prune-quality-test-orgs`, см. [[sprint25_done]]).
|
||
// Можно делать явный DELETE здесь, но это требует SuperAdmin-токена
|
||
// и cascade-обвязки — пока не реализуем.
|
||
}, { scope: 'worker' }],
|
||
})
|
||
|
||
export { expect } from '@playwright/test'
|