diff --git a/README.md b/README.md index 33c7d66..c8c1183 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`. ./gradlew ktlintFormat # автоформат Kotlin ./scripts/ldd-runtime.sh # runtime-smoke полного стека на одноразовой БД ./scripts/ldd-migration-upgrade.sh # upgrade с master-схемы +./scripts/ldd-mutation.sh # PIT: mutation strength критичных P0-компонентов +./scripts/ldd-browser.sh # Playwright E2E (нужен cd e2e && npm install) ``` - `ktlint` отвечает за формат, `detekt` — за качество (сложность, вложенность, ошибки). @@ -65,8 +67,9 @@ progress `:8083`, web `:8090`. Интерфейс: `http://localhost:8090`. не работает на JDK 25. - Тестовая инфраструктура — `libs:test-support` (JUnit 5, MockK, Testcontainers `postgres:18`). - **LDD** — реестр проверяемых утверждений `docs/evidence/claims.json`; - P0 без зелёного теста валит `./gradlew evidenceCheck`. Runtime- и - migration-свидетельства — отдельные скрипты из `scripts/`. + P0 без зелёного теста валит `./gradlew evidenceCheck`. Runtime, migration, + mutation и browser E2E — отдельные скрипты из `scripts/`; baseline — + `docs/evidence/baseline-2026-10-27.md`. - CI merge gate — `.gitlab-ci.yml`: `./gradlew --no-daemon test ktlintCheck detekt evidenceCheck` на push/MR. Runner должен разрешать privileged `docker:dind` для Testcontainers. diff --git a/docs/16-stage6-report.md b/docs/16-stage6-report.md index f30fad7..8c6fb82 100644 --- a/docs/16-stage6-report.md +++ b/docs/16-stage6-report.md @@ -294,9 +294,10 @@ upgrade-тест миграций, видимость активов и deploy-r ## 7. LDD baseline После этапа 6 текущая функциональность проверена через LDD-контур: -реестр `docs/evidence/claims.json` (31 claim, 19 P0 / 12 P1), gate -`./gradlew evidenceCheck`, upgrade-скрипт и runtime-smoke полного стека. -Результат: **31/31 claims proven, P0 gaps = 0**, 267 тестов, upgrade с -master-схемы и E2E-поток «админ → группа → курс → преподаватель → лаба» -проходят. Подробности и остаточные ограничения — +реестр `docs/evidence/claims.json` (34 claim, 19 P0 / 15 P1), gate +`./gradlew evidenceCheck`, upgrade-скрипт, runtime-smoke, mutation testing +и браузерный Playwright E2E. Результат: **34/34 claims proven, P0 gaps = 0**, +273 теста; mutation strength `CourseAccessService` 75%, +`PromotionPlanner` 69%; browser E2E 3/3. E2E нашёл и закрыл реальный дефект +Jackson 3/Kotlin defaults. Подробности и остаточные ограничения — [`docs/evidence/baseline-2026-10-27.md`](evidence/baseline-2026-10-27.md). diff --git a/docs/evidence/README.md b/docs/evidence/README.md index 9ead095..9617fcd 100644 --- a/docs/evidence/README.md +++ b/docs/evidence/README.md @@ -44,16 +44,27 @@ # 4. Проверка upgrade с master-схемы ./scripts/ldd-migration-upgrade.sh + +# 5. Mutation testing критичных P0-компонентов +./scripts/ldd-mutation.sh + +# 6. Браузерный E2E (Playwright + Chromium) +./scripts/ldd-browser.sh ``` +Для E2E один раз установите зависимости: `cd e2e && npm install`. +Mutation harness использует JUnit 4: JUnit5-плагин PIT несовместим с JUnit +Platform 6 из Spring Boot 4. + Отчёт: `build/reports/evidence/index.md`. ## Правила 1. Новое P0-требование без свидетельства не мержится. 2. Свидетельство должно быть воспроизводимым в CI, а не «проверил руками». -3. Тест должен падать при поломке соответствующей логики; для критичных - пакетов позже добавим mutation testing. +3. Тест должен падать при поломке соответствующей логики. Для критичных + пакетов это измеряется mutation testing: сейчас `CourseAccessService` — + 75% test strength, `PromotionPlanner` — 69%. 4. Один тест может подтверждать несколько claims, но claim не должен опираться на тест, который проверяет только реализацию. 5. `limitations` обязателен: LDD не должен создавать иллюзию полного @@ -65,12 +76,21 @@ ## Текущий baseline -Первый прогон LDD выполнен 2026-10-27: +Первый LDD-цикл выполнен 2026-10-27/28: -- 267 автоматических тестов, 0 failures/errors; -- 33 claims: P0 — доступы, повышение, жизненный цикл, профиль/скачивание, - материалы/активы, миграция V13, аудит; P1 — группы, авторство, UI, - контракты, импорт, копирование лаб, runtime. -- Runtime-smoke и master-upgrade вынесены в отдельные скрипты. +- **273 автоматических теста**, 0 failures/errors; +- **34 claims**: 19 P0 + 15 P1. P0 — доступы, повышение, жизненный цикл, + профиль/скачивание, материалы/активы, миграция V13, аудит; P1 — группы, + авторство, UI, контракты, импорт, копирование лаб, runtime, mutation и + browser E2E; +- mutation testing: `CourseAccessService` 75% test strength, + `PromotionPlanner` 69%; +- Playwright: 3 сценария (admin, teacher, student/anonymous), все зелёные; +- runtime-smoke, master-upgrade, mutation и browser E2E вынесены в отдельные + скрипты. -Результаты и найденные пробелы — в `baseline-2026-10-27.md`. +В ходе E2E найден и исправлен реальный дефект: Jackson 3 не применял +Kotlin-модуль, поэтому DTO с default-значениями требовали все поля JSON +(например, создание студента без `firstName`/`basis` давало 400). + +Результаты и остаточные ограничения — в `baseline-2026-10-27.md`. diff --git a/docs/evidence/baseline-2026-10-27.md b/docs/evidence/baseline-2026-10-27.md index 99ba1b0..4963c35 100644 --- a/docs/evidence/baseline-2026-10-27.md +++ b/docs/evidence/baseline-2026-10-27.md @@ -1,18 +1,19 @@ -# LDD baseline: 2026-10-27 +# LDD baseline: 2026-10-27/28 -Первый прогон доказательной проверки текущей функциональности LMS. -Код приложения в этом прогоне не менялся; добавлены реестр claims, gate -`evidenceCheck`, runtime- и migration-скрипты. +Первый и второй LDD-циклы проверки текущей функциональности LMS. +Добавлены реестр claims, gate `evidenceCheck`, runtime/migration/mutation +скрипты и браузерный E2E на Playwright. В ходе проверки найден и исправлен +реальный дефект Jackson 3. ## 1. Что проверялось -Реестр: `docs/evidence/claims.json`, 31 утверждение. +Реестр: `docs/evidence/claims.json`, **34 утверждения**. | Критичность | Claims | Proven | Gaps | |---|---:|---:|---:| | P0 | 19 | 19 | 0 | -| P1 | 12 | 12 | 0 | -| **Итого** | **31** | **31** | **0** | +| P1 | 15 | 15 | 0 | +| **Итого** | **34** | **34** | **0** | Домены: @@ -24,8 +25,9 @@ - материалы и активы; - миграция V13 и полный upgrade с master-схемы; - аудит: токен, admin-only, сохранность после удаления, representative-хуки; -- группы курса, авторство материалов, ведомость, UI/контракты, импорт, копирование лаб; -- runtime-smoke полного стека. +- группы курса, авторство материалов, ведомость, UI/контракты, импорт, + копирование лабораторных; +- runtime-smoke, mutation testing, браузерный E2E. ## 2. Команды и результаты @@ -35,7 +37,7 @@ ./gradlew test --rerun-tasks ``` -Результат: **267 тестов, 0 failures, 0 errors, 0 skipped**. +Результат: **273 теста, 0 failures, 0 errors, 0 skipped**. `ktlintCheck` и `detekt` — зелёные. ### 2.2. LDD gate @@ -44,7 +46,7 @@ ./gradlew evidenceCheck ``` -Результат: **31/31 claims proven, P0 gaps = 0**. +Результат: **34/34 claims proven, P0 gaps = 0**. Отчёт: `build/reports/evidence/index.md`. Gate устроен так: @@ -94,49 +96,94 @@ identity `V4–V10`, academic `V6–V12`, progress `V13`. - чужой преподаватель получает `403` на курс, лабу и аудит; - админ видит audit-события `COURSE_CREATE`, `TEACHER_CREATE`, `COURSE_TEACHER_ASSIGN`, `COURSE_GROUP_ATTACH`, `LAB_CREATE`; -- web `/login` отдаёт `200`, публичное дерево материалов доступно, курсовая +- web `/login` отдаёт `200`, публичное дерево материалов доступно, курсовые материалы анонимно — `401`. Результат: **PASS**, evidence: `build/evidence/runtime.json`. -Стек и одноразовая БД после прогона остановлены/удалены. + +### 2.5. Mutation testing + +```bash +./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 + +```bash +./scripts/ldd-browser.sh +``` + +Playwright/Chromium на полном стеке, одноразовая БД: + +- admin: вход, `/admin/courses` с курсом, `/admin/audit` с событием; +- teacher: вход, курс, ведомость (группа/студент, без админских кнопок), + профиль студента, создание главы курса; +- anonymous: `/admin/audit` → `/login`; +- student: вход, `/admin/audit` → `/student`, `/learn/course/{no}`. + +Результат: **3/3 passed**, evidence: `build/evidence/browser.json`. + +### 2.7. Найденный дефект + +Первый 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-схемы и поднимается полным +- Приложение собирается, мигрирует с master-схемы и поднимается полным стеком на чистой БД. - Ключевой доменный поток «админ → группа → курс → преподаватель → лаба» - проходит через реальные HTTP/gateway/БД, а не только через mock. + проходит через реальные HTTP/gateway/БД и браузер. - Чужой преподаватель не получает доступ к курсу/лабе/аудиту на реальном стеке. - Аудит пишется и читается; upgrade не теряет синтетические данные. +- Мутационная прочность критичных компонентов измерена, а не заявлена. +- Реальный дефект DTO/Jackson найден именно E2E-контуром и закрыт тестом. ## 4. Чего это не доказывает -1. **Нет браузерного E2E.** Thymeleaf-тесты проверяют HTML, но не реальные - клики/JS/CSRF/редиректы в браузере. -2. **Нет нагрузочных и конкурентных испытаний.** Advisory locks и гонки +1. **Нет нагрузочных и конкурентных испытаний.** Advisory locks и гонки проверены кодом и unit/integration-тестами, но не под нагрузкой. -3. **Нет mutation testing.** Сила тестов измерена косвенно; следующий шаг — - PIT на `CourseAccessService`, `PromotionService`, `StudentProfileService`. -4. **Нет property-based/model-based проверки повышения.** Один сценарный тест - не покрывает все комбинации курсов, степеней и академ-переходов. +2. **Mutation testing не 100%.** Остаются эквивалентные мутанты и + Kotlin/Spring-специфичные мутации; PIT harness — JUnit 4, а не JUnit 5. +3. **Property-based тесты покрывают не все ветки.** Есть генераторы для + матрицы доступа и планировщика повышения, но не для транзакционного + apply/rollback и конкурентных сценариев. +4. **Браузерный E2E — один Chromium и один сценарий на роль.** Нет + визуальной регрессии, мобильных размеров, Safari/Firefox. 5. **Legacy-активы без `article_assets` остаются публичными.** 6. **JWT живёт до 30 дней.** Web перепроверяет статус, прямой API — нет. 7. **Ведущие нули номера группы нормализуются** (`01` → `1`). 8. **Нет пагинации/keyset** для части списков и N+1 в отдельных экранах. -9. **Runtime-smoke не входит в unit-CI**; он запускается отдельным скриптом - перед релизом. +9. **Runtime/mutation/browser E2E не входят в unit-CI**; это release-скрипты. ## 5. Вывод -Текущая функциональность прошла первый LDD-контур: **P0 gaps = 0**, -полный стек и upgrade работают. Это достаточное основание продолжать -доработки, но не «формальное доказательство всей системы». Следующий цикл -LDD должен добавить: +Текущая функциональность прошла LDD-контур: **34/34 claims proven, P0 gaps = 0**, +273 теста, upgrade, mutation baseline и браузерный E2E зелёные. Это +достаточное основание продолжать доработки, но не «формальное доказательство +всей системы». -1. mutation testing для критичных пакетов; -2. property-based тесты повышения и матрицы доступа; -3. браузерный E2E (Playwright) для ведомости, профиля и материалов; -4. нагрузочный smoke на чтение ведомости/профиля; -5. автоматический runtime-smoke в release-пайплайне. +Следующий цикл LDD: + +1. нагрузочный smoke на чтение ведомости/профиля и конкурентный apply/rollback; +2. property-based/model-based тесты транзакционного повышения; +3. расширение browser E2E (студенческая сдача, публикация оценки, мобильный вид); +4. автоматический release-пайплайн с runtime/mutation/browser evidence.