veza/docs/STRATEGIE_COUVERTURE_ET_TMT_2025_02.md

340 lines
13 KiB
Markdown
Raw Normal View History

# STRATÉGIE DE COUVERTURE & ORCHESTRATION TMT — VEZA
**Date** : 2025-02-10
**Mandat** : Architecte qualité — redressement de la base de tests
**Audits de référence** : AUDIT_TESTS_ET_COUVERTURE_2025_02.md, AUDIT_FRONTEND_EXHAUSTIF_2025_02.md
**Objectif** : *« Une régression significative ne peut plus passer inaperçue. »*
---
## 0. POSTURE
Décisions appliquées. Pas de pédagogie. Pas de généralités.
---
## 1. REDÉFINITION DE LA COUVERTURE
### 1.1 Définition opérationnelle
> **Couverture** = probabilité que le système se comporte correctement lorsqu'il est modifié.
Trois axes :
| Axe | Signification | Mesure |
|-----|---------------|--------|
| **Logique critique** | Auth, RBAC, commerce, upload, webhooks | Branches exercées sur chemins nominaux ET erreurs |
| **Branches d'erreur** | catch, retry, fallback, validation | % branches catch/error couvertes |
| **Contrats implicites** | API, auth, invariants métier | Tests contractuels, assertions sur schémas |
### 1.2 Cibles chiffrées (différenciées)
| Domaine | Cible branches | Cible lignes | Bloquant |
|---------|----------------|--------------|----------|
| **Auth / RBAC** | ≥ 90% | ≥ 85% | Oui |
| **Commerce / Marketplace** | ≥ 85% | ≥ 80% | Oui |
| **Upload / Tracks** | ≥ 85% | ≥ 80% | Oui |
| **Services API (client.ts, interceptors)** | ≥ 80% | ≥ 75% | Oui |
| **Handlers / Services Go critiques** | ≥ 90% | ≥ 85% | Oui |
| **Hooks / utils frontend** | ≥ 80% | ≥ 80% | Oui |
| **Logique utilitaire** | ≥ 80% | ≥ 80% | Non (warning) |
| **UI pure (composants)** | Indicateur | Indicateur | Non |
**Pourquoi un seuil global unique est architecturalement débile** :
Un seuil global (ex. 80%) masque les zones critiques sous-testées. Le client API (2238 lignes) peut être négligé tandis que des utils triviales gonflent le pourcentage. Les domaines à fort risque (auth, RBAC) doivent avoir des seuils plus élevés et être vérifiés séparément.
---
## 2. STRATÉGIE PAR COUCHE
### 2.1 Backend (Go)
**Fonctions critiques identifiées** (à couvrir en priorité) :
- `internal/core/auth/service.go` — ValidateSession, HasRole, HasPermission
- `internal/api/router.go` — Middleware auth, RBAC
- Handlers : auth, tracks, playlists, marketplace, webhooks
- `internal/database/` — Migrations, prepared statements (chemins erreur)
**Tests à écrire/corriger** :
| Type | Action | Justification |
|------|--------|---------------|
| Chemins nominaux | Corriger mocks auth middleware | Échec actuel : `0 out of 1 expectation(s) were met` |
| Erreurs métier | Ajouter tests sur erreurs 401, 403, 404 | RBAC non validé |
| Erreurs infra | Simuler DB down, timeout | Branches jamais exercées |
**Interdictions** :
- Mocks non alignés avec les interfaces réelles (signatures Go)
- Tests dépendants du timing (supprimer ou utiliser `testify/assert.Eventually`)
### 2.2 Frontend
| Couche | Rôle | Outil | Couverture |
|--------|------|-------|------------|
| **Unitaire** | Hooks, helpers, utils, services purs | Vitest | branches ≥ 80% sur `features/*`, `hooks`, `services` |
| **Intégration** | Pages, flows (MSW) | Vitest + MSW | Pas de logique métier significative non testée hors E2E |
| **E2E** | Flux critiques (auth, playlists, search) | Playwright | Smoke obligatoire |
**Objectif** : *Zéro logique métier significative non testée hors E2E.*
**Zones prioritaires** :
- `authStore` vs `AuthContext` — cohérence (réduire après unification auth)
- `client.ts` — découper puis tester interceptors, retry, offline queue
- `optimisticUpdates.ts` — rollback, invalidation
- `marketplaceService`, `webhookService` — peu couverts
### 2.3 Rust (Chat, Stream)
- **Clippy** : 0 warnings (déjà vital)
- **Tests** : Déjà dans TMT vital
- Pas de changement structurel prévu
---
## 3. ÉLIMINATION DES FAUX POSITIFS
| Élément | Action | Argument |
|---------|--------|----------|
| `npm run test -- --run \|\| true` | **Supprimer** | Tests qui passent malgré régression = illusion |
| Snapshots sans assertion sémantique | **Supprimer ou remplacer** | Snapshots décoratifs ; ajouter `expect` sur comportement |
| Tests qui ne testent que React/framework | **Supprimer** | Redondants avec tests framework |
| `PlaylistErrorBoundary.test.tsx` (jest.spyOn) | **Remplacer** par `vi.spyOn` | Incohérence Vitest |
| Tests Go auth/RBAC avec mocks cassés | **Réparer** | Sinon les exclure explicitement (documenté) |
---
## 4. RÉDUCTION DU MOCKING
**Objectif** : remplacer le mocking par de la **composition testable**.
| Action | Détail |
|--------|--------|
| Extraction de ports/adapters | Interfaces pour `authService`, `apiClient` — injection en tests |
| MSW ciblé | Garder MSW pour les handlers HTTP ; ne pas mocker 10+ modules par test |
| Doubles de test minimaux | Backend : interfaces Go déjà présentes ; utiliser des implémentations stub |
| Unifier auth | Une source (Store) → un mock au lieu de deux |
**Critère** : si un test nécessite > 5 mocks, le design est toxique.
---
## 5. ORCHESTRATION TMT
### 5.1 État actuel (diagnostic)
| Aspect | État | Détail |
|--------|------|--------|
| **TMT utilisé en CI** | ❌ Non | La CI n'appelle jamais `tmt run` |
| **Types de tests TMT** | Partiel | Build, bundle_size, build_perf, no_critical_js ; Go unit (internal) ; Rust clippy/test |
| **Vitest** | ❌ Hors TMT | Exécuté directement dans ci.yml avec `\|\| true` |
| **Playwright** | ❌ Hors TMT | Workflow séparé, sans `working-directory: apps/web` |
| **Contournement** | CI directe | `go test`, `npm run test`, `npx playwright test` sans TMT |
**Conclusion** : TMT est une couche déclarative sous-exploitée. La CI est une projection ad-hoc, pas fidèle à TMT.
### 5.2 Rôle cible de TMT
TMT devient :
- **Point d'entrée unique** pour tous les tests
- Garant de l'ordre, des dépendances, des profils (local / CI / nightly)
### 5.3 Modélisation TMT cible
```
tmt/
├── plans/
│ ├── vital.fmf # Tier 1 — bloque tout
│ ├── integration.fmf # Tier 2 — nécessite infra (DB, Redis)
│ └── nightly.fmf # Tier 3 — E2E, contract, visuels
├── tests/
│ ├── frontend/
│ │ ├── build.sh
│ │ ├── build_perf.sh
│ │ ├── bundle_size.sh
│ │ ├── no_critical_js.sh
│ │ └── unit.sh # NOUVEAU — npm run test -- --run
│ ├── frontend-e2e/
│ │ └── playwright.sh # NOUVEAU — npx playwright test
│ ├── backend/
│ │ ├── unit.sh
│ │ ├── integration.sh
│ │ ├── core_isolation.sh
│ │ ├── startup_time.sh
│ │ └── memory_budget.sh
│ └── services/
│ ├── rust_clippy.sh
│ └── rust_test.sh
└── README.md
```
**Variables d'environnement explicites** :
| Variable | Valeur | Rôle |
|----------|--------|------|
| `GOMAXPROCS` | 1 | Low-power backend |
| `LIBGL_ALWAYS_SOFTWARE` | 1 | GPU désactivé |
| `RUST_BACKTRACE` | 0 | Bruit minimisé |
| `VEZA_TEST_DB_URL` | (optionnel) | Intégration |
| `VEZA_E2E_API_URL` | (optionnel) | E2E |
**Artefacts de sortie** :
| Artefact | Emplacement | Usage |
|----------|-------------|-------|
| Coverage Go | `veza-backend-api/coverage.out` | Rapport, seuils |
| Coverage Vitest | `apps/web/coverage/` | Rapport, seuils |
| Playwright report | `apps/web/playwright-report/` | Debug E2E |
### 5.4 Plans TMT
| Plan | Tier | Contenu | Bloquant |
|------|------|---------|----------|
| **vital** | 1 | build, bundle_size, build_perf, no_critical_js, backend unit, rust clippy/test, **frontend unit** | Oui |
| **legacy** | 2 | integration (backend), startup_time, memory_budget | Non (warning) |
| **nightly** | 3 | E2E Playwright, contract, Storybook audit | Non |
**Changement majeur** : `frontend/unit.sh` ajouté au plan vital. Exécute `npm run test -- --run` sans `|| true`.
---
## 6. COUVERTURE & TMT
| Plan | Couverture produite | Agrégation | Seuils |
|------|---------------------|-------------|--------|
| **vital** | `vitest run --coverage`, `go test -coverprofile` | Rapports séparés par composant | Évalués en CI ; échec si seuils non atteints |
| **legacy** | Idem | Idem | Indicateur |
| **nightly** | E2E (pas de coverage classique) | Playwright HTML report | Binaire (pass/fail) |
**Agrégation** : pas de rapport global unique. Chaque composant (frontend, backend) a ses seuils. CI échoue si un seuil est violé.
**Aucun** `|| true`. Aucune exception silencieuse.
---
## 7. INTÉGRATION CI
**Principe** : La CI est une **projection fidèle** de l'exécution TMT.
### 7.1 Règle
La CI ne doit **jamais** appeler directement `vitest`, `go test`, `playwright`.
Elle appelle **toujours** `tmt run plan --name /vital` (ou équivalent).
### 7.2 Schéma cible
```yaml
# .github/workflows/ci.yml (simplifié)
jobs:
test:
steps:
- uses: actions/checkout@v4
- name: Install TMT
run: pip install tmt
- name: Run Vital Tests
run: tmt run plan --name /vital
# Plus de go test, npm test, etc. directs
```
### 7.3 Workflows à corriger/supprimer
| Workflow | Action | Raison |
|----------|--------|--------|
| `ci.yml` | Remplacer jobs par `tmt run` | Point d'entrée unique |
| `frontend-ci.yml` | Supprimer | Chemin `apps/web-frontend` inexistant |
| `backend-ci.yml` | Supprimer | Chemin `apps/backend-api` inexistant |
| `playwright.yml` | Intégrer dans TMT nightly ou garder séparé avec `working-directory: apps/web` | E2E nécessite runtime différent |
---
## 8. FEUILLE DE ROUTE
### Phase 1 — Rétablissement de la vérité (12 semaines)
| Priorité | Action | Effort |
|----------|--------|--------|
| **P0** | Supprimer `|| true` des tests frontend (ci.yml) | 5 min |
| **P0** | Corriger `playlist_duplicate_transaction_test.go:80` (compile) | 2 h |
| **P0** | Exclure/corriger tests Go qui paniquent (testutils, RoomService) | 4 h |
| **P1** | Ajouter `working-directory: apps/web` à playwright.yml | 15 min |
| **P1** | Supprimer frontend-ci.yml, backend-ci.yml (ou corriger chemins) | 15 min |
**Objectif** : tests qui échouent = build rouge assumé.
### Phase 2 — Couverture ciblée (13 mois)
| Priorité | Action | Effort |
|----------|--------|--------|
| **P1** | Réparer tests auth middleware (Go) | 8 h |
| **P1** | Ajouter `tmt/tests/frontend/unit.sh` et l'intégrer au plan vital | 2 h |
| **P1** | Faire appeler la CI `tmt run plan --name /vital` | 4 h |
| **P2** | Validation seuils coverage en CI (par domaine) | 8 h |
| **P2** | Remplacer jest.spyOn par vi.spyOn | 2 h |
| **P2** | Tests branches d'erreur sur auth, RBAC, client API | 24 h |
**Objectif** : ajout de tests uniquement sur zones critiques ; suppression de tests toxiques.
### Phase 3 — Stabilisation (24 semaines)
| Priorité | Action | Effort |
|----------|--------|--------|
| **P2** | Temps d'exécution suite unitaire < 2 min (frontend) | Variable |
| **P2** | Flakiness = 0 (audit, correction) | Variable |
| **P3** | Découper client.ts (modules testables) | 40 h |
| **P3** | Unifier auth (Context → Store) | 24 h |
**Objectif** : temps maîtrisé ; zéro tolérance au flaky.
---
## 9. LIVRABLE — LISTE PRIORISÉE
### 9.1 Tests à écrire
| Domaine | Fichier / Zone | Type | Priorité |
|---------|----------------|------|----------|
| Auth | `internal/core/auth` | Unit (chemins erreur) | P0 |
| RBAC | `rbac_auth_middleware_test.go` | Corriger mocks | P0 |
| Client API | `client.ts` (après découpage) | Interceptors, retry | P1 |
| Commerce | `marketplaceService`, `cartStore` | Unit | P1 |
| Webhooks | `webhookService`, handlers | Unit + integration | P1 |
| Optimistic | `optimisticUpdates.ts` | Rollback, invalidation | P2 |
### 9.2 Tests à corriger
| Test | Action | Priorité |
|------|--------|----------|
| `auth_middleware_test.go` | Aligner mocks avec ValidateSession | P0 |
| `rbac_auth_middleware_test.go` | Aligner mocks HasRole/HasPermission | P0 |
| `PlaylistErrorBoundary.test.tsx` | jest → vi | P1 |
| `auth.integration.test.tsx` | Réduire mocks, scinder | P2 |
### 9.3 Tests à supprimer
| Test | Raison | Priorité |
|------|--------|----------|
| Snapshots sans assertion sémantique | Illusion de couverture | P2 |
| Tests redondants (framework only) | Aucune valeur métier | P2 |
| Tests orphelins (`jest.config.js` si Jest inutilisé) | Nettoyage | P3 |
---
## 10. RÉSUMÉ EXÉCUTIF
| Principe | Décision |
|----------|----------|
| **Couverture** | Différenciée par domaine ; domaines critiques ≥ 90% branches |
| **Faux positifs** | Suppression de `\|\| true` ; tests cassés = build rouge |
| **Mocking** | Réduction ; composition testable ; ≤ 5 mocks par test |
| **TMT** | Point d'entrée unique ; CI appelle `tmt run` |
| **Phases** | 1. Vérité → 2. Couverture ciblée → 3. Stabilisation |
**Phrase de clôture** : *Une régression significative ne peut plus passer inaperçue* — à condition que les phases 1 et 2 soient exécutées sans compromis.
---
**Fin du document.**