210 lines
11 KiB
Markdown
210 lines
11 KiB
Markdown
# 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. Автоматические тесты
|
||
|
||
```bash
|
||
./gradlew test --rerun-tasks
|
||
```
|
||
|
||
Результат: **276 тестов, 0 failures, 0 errors, 0 skipped**.
|
||
`ktlintCheck` и `detekt` — зелёные.
|
||
|
||
### 2.2. LDD gate
|
||
|
||
```bash
|
||
./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-схемы
|
||
|
||
```bash
|
||
./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 полного стека
|
||
|
||
```bash
|
||
./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
|
||
|
||
```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}`.
|
||
|
||
Результат: **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 обязательным для тегов.
|