Полная регрессия всех сценариев + 6 новых областей этой сессии (employees, roles, superadmin-console, platform-smtp, auth-password, security-edge). За день исправлено 4 бага: уволенный сотрудник логинится (P0), конкурентное проведение приёмки ломает инвариант (critical), refresh не гасится после ротации (high), change-owner принимал короткий reason (medium). Нереализованный по ТЗ функционал (отчёты/склад-документы/POS/permission-authz/login-ratelimit) зафиксирован как Logic gaps. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.3 KiB
Системное тестирование Food Market — 2026-05-26
Инициировано Opus 4.7 по плану
docs/TZ-тестирование.md(продолжениеsystemic-2026-05-23.md). Среда: dockerfood-market-postgres(postgres:16-alpine, 127.0.0.1:5434) + dotnet 8 API локально на :5081 + E2E через axios/psql + mock MoySklad. Запуск:E2E_ADMIN_URL=http://127.0.0.1:5081 ./tests/e2e/run.sh <scenario> --api-only.
0. TL;DR
| Сценарий | Шаги | Результат |
|---|---|---|
| full-cycle | 12 | ✓ |
| multi-tenant-isolation | 12 | ✓ |
| documents-edge | 10 | ✓ |
| auth-edge | 10 | ✓ |
| auth-password | 6 | ✓ |
| catalog-edge | 12 | ✓ |
| stock-invariant-deep | 10 | ✓ |
| stock-concurrency | 4 | ✓ |
| reports-stats | 5 | ✓ |
| moysklad-import | 7 | ✓ |
| employees | 10 | ✓ |
| roles | 8 | ✓ |
| superadmin-console | 6 | ✓ |
| platform-smtp | 6 | ✓ |
| security-edge | 6 | ✓ |
Итого 15 сценариев, 124 шага — все зелёные. Багов нет.
Исправлено за день: 4 бага (2 P0/critical, 1 high, 1 medium) + доработка тестируемости MoySklad.
1. Найденные баги и исправления
BUG #1 (P0) — Уволенный сотрудник продолжает логиниться (commit 5091d43)
employees step07. EmployeesController.Delete (увольнение и soft-delete) и Update (деактивация) меняли только Employee.IsActive, но не трогали связанный AppUser. Логин и refresh гейтятся на User.IsActive → уволенный сохранял полный доступ и обновлял токены до 30 дней (ТЗ 0.4).
Fix: SetLinkedUserActiveAsync — при деактивации сотрудника гасит User.IsActive и отзывает его valid OpenIddict-токены; при реактивации возвращает доступ.
BUG #2 (critical) — Конкурентное проведение приёмки ломает инвариант остатков (commit 15f27fd)
stock-concurrency step03. Supply.Post шёл на Read Committed, ApplyMovementAsync делает read-modify-write по Stock.Quantity без RowVersion. Двойное проведение одной приёмки применяло остаток дважды (Stock=32, Σ Movement=39).
Fix: IsolationLevel.Serializable + перехват конфликта сериализации (40001/40P01) → 409.
BUG #3 (high) — Refresh-token остаётся валидным после ротации (commit 32729e7)
auth-edge step03. Новый principal не получал TokenId старого refresh → RedeemTokenEntry не гасил его; плюс 30-секундный reuse-leeway OpenIddict.
Fix: проброс TokenId + SetRefreshTokenReuseLeeway(TimeSpan.Zero).
BUG #4 (medium) — change-owner принимал слишком короткий reason (commit 01568ba)
superadmin-console step04. Смена владельца писала reason в аудит, но проверяла лишь непустоту. PlatformSettings уже требует ≥10 — привели change-owner к той же планке (ТЗ 2.8).
Доработка — базовый URL MoySklad из конфигурации (commit e78e921)
MoySklad:BaseUrl (дефолт — боевой) позволяет наводить клиент на mock-сервер в e2e, не трогая прод.
2. Покрытие по разделам ТЗ
P0/P1 функциональные области, реализованные в коде, — покрыты и зелёные: Auth (login/refresh/signup/forgot-reset), Multi-tenancy, Catalog, Supplies, RetailSales, Stock (+ конкурентность), Employees, Roles, SuperAdmin Console, SMTP, MoySklad import, дашбордная выручка, безопасность (auth-гейт, traversal, SQLi, CORS, межтенантная 404).
3. Logic gaps — нереализованный по ТЗ функционал (НЕ баги)
- Отчёты (2.12): профит по себестоимости, ABC-анализ, «остатки на дату», экспорт CSV/XLSX — нет
ReportsController,RetailSaleLineбез Cost-снимка. Есть только/stats(валовая выручка). - Складские документы (2.11): Оприходование/Списание/Перемещение/Инвентаризация — не реализованы (только read-only
StockController). - POS Sync API (2.13) — не реализован.
- Permission-based авторизация (2.7.2, «после P0-5») — эндпоинты только role-based
[Authorize(Roles=...)]; флагиRolePermissionsсправочные. - Рейт-лимит логина (2.1.2, «после P0-3») — на
/connect/tokenнет (у forgot-password — есть). - Системных ролей 3, а не 4-6 — намеренное упрощение (миграция
Phase4b_RolesSimplify): Администратор/Кладовщик/Кассир. ТЗ устарело. Supply.Unpostиспользует тот же read-modify-write без транзакции — теоретически уязвим к гонке (вне фокуса;Postзакрыт).
4. Вне зоны API-e2e (по ТЗ — отдельные инструменты)
UI/UX (2.14, Playwright), публичный сайт (2.15, Astro/Lighthouse), инфраструктура/DevOps (2.16), нагрузочное (2.18) — требуют браузера/нагрузочных стендов, в данном прогоне не покрывались.
5. Окружение
- SDK на dev-vm только 8.0.126;
global.jsonрепозитория остаётся8.0.417(локальный даунгрейд в коммиты не включён). admin.food-market.kz— отдельный деплой с другой БД; e2e гоняются против локального API, подключённого к контейнеруfood-market-postgres.