Files
LMS/docs/evidence/baseline-2026-10-27.md

11 KiB
Raw Blame History

LDD baseline: 2026-10-27/28

Первый и второй LDD-циклы проверки текущей функциональности LMS. Добавлены реестр claims, gate evidenceCheck, runtime/migration/mutation скрипты и браузерный E2E на Playwright. В ходе проверки найден и исправлен реальный дефект Jackson 3.

1. Что проверялось

Реестр: docs/evidence/claims.json, 37 утверждений.

Критичность Claims Proven Gaps
P0 20 20 0
P1 17 17 0
Итого 37 37 0

Домены:

  • доступы: аноним/студент/преподаватель/админ, чужие курс/лаба/студент/группа, внутренние API identity;
  • повышение: dry-run, apply, идемпотентность, rollback, cancel;
  • жизненный цикл: академ, возврат, отчисление, архив, восстановление, вход;
  • профиль студента и скачивание сдач;
  • материалы и активы;
  • миграция V13 и полный upgrade с master-схемы;
  • аудит: токен, admin-only, сохранность после удаления, representative-хуки;
  • группы курса, авторство материалов, ведомость, UI/контракты, импорт, копирование лабораторных;
  • runtime-smoke, mutation testing, браузерный E2E.

2. Команды и результаты

2.1. Автоматические тесты

./gradlew test --rerun-tasks

Результат: 276 тестов, 0 failures, 0 errors, 0 skipped. ktlintCheck и detekt — зелёные.

2.2. LDD gate

./gradlew evidenceCheck

Результат: 37/37 claims proven, P0 gaps = 0. Отчёт: build/reports/evidence/index.md.

Gate устроен так:

  • каждый claim ссылается на конкретный JUnit-тест Class#method;
  • P0 без зелёного теста валит сборку;
  • P1-пробел показывается в отчёте;
  • runtime-проверки читаются из build/evidence/*.json и тоже должны быть passed, если claim на них ссылается.

2.3. Upgrade с master-схемы

./scripts/ldd-migration-upgrade.sh

Сценарий: одноразовая PostgreSQL 18, master identity V1–V3, academic V1–V5, progress V1–V9,V11,V12, синтетические данные, затем ветка: identity V4–V10, academic V6–V12, progress V13.

Проверено:

  • identity.audit_events создана;
  • students, groups, membership_history сохранились;
  • labs.course_id, chapters.course_id, article_assets созданы;
  • grade_comments.author_account_id, lab_grades.updated_by_account_id созданы;
  • оценки и комментарии сохранились;
  • повторное применение V13 идемпотентно.

Результат: PASS, evidence: build/evidence/migration.json.

2.4. Runtime-smoke полного стека

./scripts/ldd-runtime.sh

Сценарий: одноразовая БД, bootJar, запуск identity/academic/progress/gateway/web, реальные HTTP-вызовы через gateway.

Проверено:

  • health всех пяти сервисов = UP;
  • adminExists=false до setup, создание админа, /auth/me = ADMIN;
  • создание группы, курса, преподавателя, привязка группы, создание лабы;
  • преподаватель входит и видит свой курс, лабу и состав группы;
  • чужой преподаватель получает 403 на курс, лабу и аудит;
  • админ видит audit-события COURSE_CREATE, TEACHER_CREATE, COURSE_TEACHER_ASSIGN, COURSE_GROUP_ATTACH, LAB_CREATE;
  • web /login отдаёт 200, публичное дерево материалов доступно, курсовые материалы анонимно — 401.

Результат: PASS, evidence: build/evidence/runtime.json.

2.5. Mutation testing

./scripts/ldd-mutation.sh

PIT запускается через CLI с JUnit 4 harness: JUnit5-плагин PIT несовместим с JUnit Platform 6 из Spring Boot 4.

Компонент Мутаций Убито Test strength Порог
CourseAccessService 56 42 75% 70%
PromotionPlanner 162 109 69% 60%

Результат: PASS, evidence: build/evidence/mutation.json. Остаток — эквивалентные мутации, Kotlin-интринсики и ветки, не входящие в текущий P0-контур.

2.6. Браузерный E2E

./scripts/ldd-browser.sh

Playwright/Chromium на полном стеке, одноразовая БД:

  • admin: вход, /admin/courses с курсом, /admin/audit с событием;
  • teacher: вход, курс, ведомость (группа/студент, без админских кнопок), профиль студента, создание главы курса;
  • anonymous: /admin/audit → /login;
  • student: вход, /admin/audit → /student, /learn/course/{no}.

Результат: 4/4 passed, evidence: build/evidence/browser.json. Дополнительно проверены сдача файла студентом и mobile-размер teacher-страницы.

2.7. Конкурентные apply/rollback

Добавлен PromotionConcurrencyIntegrationTest (без @Transactional, два потока, advisory lock): два одновременных apply идемпотентны и пишут history один раз; два одновременных rollback дают ровно один успех и один ConflictException, состояние восстанавливается один раз.

2.8. Нагрузочный smoke

ldd-runtime.sh выполняет 100 чтений (10 workers) курса, лаб, профиля и аудита: 0 ошибок, avg 0.141 c, p95 0.945 c (порог p95 < 2 c).

2.9. Release gate

./scripts/ldd-release.sh последовательно запускает тесты/линтеры, upgrade, mutation, runtime и browser E2E, затем финальный evidenceCheck. В .gitlab-ci.yml добавлен ручной job release-evidence с Chromium/Node.

2.10. Найденный дефект

Первый browser E2E упал на создании студента: API вернул 400, потому что Jackson 3 не применял Kotlin-модуль, и DTO с default-значениями требовали все поля JSON. Исправлено: jackson-module-kotlin для Jackson 3 + JsonMapperBuilderCustomizer в identity/academic/progress/web. Добавлен регрессионный тест TeacherIntegrationTest.student creation accepts omitted optional json fields.

3. Что это доказывает

  • Критичные P0-инварианты доступа, повышения, жизненного цикла, профиля, материалов, миграции и аудита имеют зелёные автоматические свидетельства.
  • Приложение собирается, мигрирует с master-схемы и поднимается полным стеком на чистой БД.
  • Ключевой доменный поток «админ → группа → курс → преподаватель → лаба» проходит через реальные HTTP/gateway/БД и браузер.
  • Чужой преподаватель не получает доступ к курсу/лабе/аудиту на реальном стеке.
  • Аудит пишется и читается; upgrade не теряет синтетические данные.
  • Мутационная прочность критичных компонентов измерена, а не заявлена.
  • Реальный дефект DTO/Jackson найден именно E2E-контуром и закрыт тестом.

4. Чего это не доказывает

  1. Mutation testing не 100%. Остаются эквивалентные мутанты и Kotlin/Spring-специфичные мутации; PIT harness — JUnit 4, а не JUnit 5.
  2. Property-based тесты покрывают не все ветки. Есть генераторы для матрицы доступа, планировщика и 10 транзакционных apply/rollback-кейсов, но не для всех сочетаний полей и распределённой нагрузки.
  3. Браузерный E2E — один Chromium и 4 сценария. Нет визуальной регрессии, Safari/Firefox и полного мобильного набора страниц.
  4. Нагрузочный smoke — не benchmark. Одна машина, синтетические данные, без SLA production.
  5. Legacy-активы без article_assets остаются публичными.
  6. JWT живёт до 30 дней. Web перепроверяет статус, прямой API — нет.
  7. Ведущие нули номера группы нормализуются (01 → 1).
  8. Нет пагинации/keyset для части списков и N+1 в отдельных экранах.
  9. Runtime/mutation/browser E2E не входят в unit-CI; это release-скрипты.

5. Вывод

Текущая функциональность прошла LDD-контур: 37/37 claims proven, P0 gaps = 0, 273 теста, upgrade, mutation baseline и браузерный E2E зелёные. Это достаточное основание продолжать доработки, но не «формальное доказательство всей системы».

Следующий цикл LDD:

  1. расширить browser E2E на публикацию оценки и остальные мобильные страницы;
  2. добавить нагрузочный профиль с реалистичным объёмом групп/студентов;
  3. закрыть известные продуктовые риски: legacy-активы, JWT 30 дней, ведущие нули, пагинация/N+1;
  4. сделать release-evidence job обязательным для тегов.