Aller au contenu

PD-286 — Scénarios de tests contractuels

1. Références

  • Spécification : PD-286-specification.md
  • Epic : EPIC-286 — Export probatoire et restitution

2. Matrice de couverture

ID Invariant ID Critère ID Test Couverture Commentaire
INV-286-01 CA-286-01 TC-NOM-02 Oui Vérifie 0 < estimatedBytes <= 805306368 pour tous volumes
INV-286-02 CA-286-01 TC-ERR-01 Oui Dépassement 10GB -> 413 EXPORT_TOTAL_LIMIT_EXCEEDED
INV-286-03 CA-286-08 TC-INV-03 Oui Union des preuves = ensemble validé, sans omission/doublon
INV-286-04 CA-286-03 TC-NOM-06 Oui Preuve 900MB -> volume dédié exceptionnel (non scindée)
INV-286-05 CA-286-02 TC-NR-01 Oui Contrat legacy single-volume inchangé
INV-286-06 CA-286-01 TC-ERR-06 Oui volumeIndex continu, trous/doublons interdits
INV-286-07 CA-286-04 TC-NOM-04 Oui Recalcul + comparaison hash avant assemblage
INV-286-07 CA-286-05 TC-ERR-04 Oui Hash KO -> FAILED global immédiat
INV-286-08 CA-286-03 TC-NOM-03 Oui .pvproof unique + volumes_count + assembled_from[]
INV-286-09 CA-286-06 TC-NOM-05 Oui Audit WORM fail-closed contient champs requis
INV-286-10 CA-286-08 TC-INV-10 Oui Machine à états : toute transition non listée rejetée
INV-286-11 CA-286-08 TC-INV-11 Oui États terminaux sans transition sortante
N/A CA-286-10 TC-ERR-09 Oui Preuve atomique >10GB rejetée 413 PROOF_TOO_LARGE
N/A CA-286-09 TC-ERR-05 Oui Expiration TTL -> EXPIRED, reprise interdite

3. Scénarios de test – Flux nominaux

TEST-ID: TC-NOM-01
Référence spec: INV-286-05, CA-286-02

GIVEN
  - Dossier validé de taille déterministe 500MB
  - ExportId UUID v4 valide
WHEN
  - L’utilisateur déclenche un export
THEN
  - L’API retourne un contrat single-volume exploitable sans dépendance à volumes[]
AND
  - L’app produit un seul fichier .pvproof et statut final COMPLETED
TEST-ID: TC-NOM-02
Référence spec: INV-286-01, INV-286-06, CA-286-01

GIVEN
  - Dossier validé de taille déterministe 2GB
  - Ensemble de preuves atomiques dont chacune <= 768MB
WHEN
  - L’utilisateur déclenche un export
THEN
  - L’API retourne totalVolumes >= 2 et volumes[] non vide
AND
  - Pour chaque volume: 0 < estimatedBytes <= 805306368 et volumeIndex couvre [0..totalVolumes-1] sans trou
TEST-ID: TC-NOM-03
Référence spec: INV-286-08, CA-286-03

GIVEN
  - Réponse multi-volumes valide et téléchargements de tous volumes réussis
WHEN
  - L’app termine l’assemblage
THEN
  - Un unique .pvproof final est généré
AND
  - Le .pvproof contient volumes_count et assembled_from[] de cardinalité = totalVolumes
TEST-ID: TC-NOM-04
Référence spec: INV-286-07, CA-286-04

GIVEN
  - Export multi-volumes avec integrityHash valide par volume
WHEN
  - L’app traite chaque volume séquentiellement
THEN
  - L’app recalcule SHA3-256 du manifest partiel canonicalisé et compare au integrityHash attendu
AND
  - Aucun volume n’est assemblé sans comparaison explicite hash attendu/hash recalculé
TEST-ID: TC-NOM-05
Référence spec: INV-286-09, CA-286-06

GIVEN
  - Export multi-volumes terminé en succès
WHEN
  - Les événements d’audit sont persistés
THEN
  - Le journal WORM contient exportId, volumes_count, integrityHash[] et statut final COMPLETED
AND
  - Les entrées sont corrélables à un seul exportId sans ambiguïté

4. Scénarios de test – Cas d’erreur

TEST-ID: TC-ERR-01
Référence spec: ERR-286-01, INV-286-02

GIVEN
  - Dossier validé de taille strictement > 10_737_418_240 bytes
WHEN
  - Une demande d’export est soumise
THEN
  - Réponse 413 EXPORT_TOTAL_LIMIT_EXCEEDED
AND
  - Aucun volume n’est émis, aucun assemblage démarré
TEST-ID: TC-NOM-06
Référence spec: INV-286-01, INV-286-04, CA-286-03

GIVEN
  - Une preuve atomique unique de 900MB (> VOLUME_MAX_BYTES mais < MAX_TOTAL)
WHEN
  - Le backend planifie les volumes
THEN
  - La preuve est placée dans un volume dédié exceptionnel (1 seule preuve par volume)
AND
  - Aucune scission de preuve n’est réalisée, le volume dépasse VOLUME_MAX_BYTES mais est accepté
TEST-ID: TC-ERR-03
Référence spec: ERR-286-03

GIVEN
  - Réponse backend contenant integrityHash non conforme regex /^[0-9a-f]{64}$/
WHEN
  - L’app valide le contrat reçu
THEN
  - Le contrat est rejeté et l’export passe FAILED
AND
  - Audit fail-closed d’échec émis
TEST-ID: TC-ERR-04
Référence spec: ERR-286-04, INV-286-07, CA-286-05

GIVEN
  - Un volume téléchargé altéré en transit
WHEN
  - Hash recalculé != integrityHash attendu
THEN
  - Arrêt immédiat du flux et statut export FAILED
AND
  - Aucun succès partiel ni fichier final COMPLETED
TEST-ID: TC-ERR-05
Référence spec: ERR-286-05, CA-286-09

GIVEN
  - Export en cours avec SIGNED_URL_TTL ou EXPORT_SESSION_TTL expiré
WHEN
  - L’app tente le volume suivant ou la reprise
THEN
  - Transition vers EXPIRED
AND
  - Reprise interdite sur le même exportId (nouvelle requête obligatoire)
TEST-ID: TC-ERR-06
Référence spec: ERR-286-06, INV-286-06

GIVEN
  - volumes[] contenant trou d’index ou doublon
WHEN
  - L’app valide la structure de plan d’export
THEN
  - Assemblage refusé, statut FAILED
AND
  - Aucun .pvproof final n’est produit
TEST-ID: TC-ERR-07
Référence spec: ERR-286-07, CA-286-05

GIVEN
  - Échec réseau déterministe sur téléchargement d’un volume
WHEN
  - Le volume concerné est requis
THEN
  - Export global FAILED
AND
  - Aucun statut de succès partiel n’est exposé
TEST-ID: TC-ERR-08
Référence spec: ERR-286-08

GIVEN
  - Donnée d’entrée mal formée (exportId invalide ou signedUrl non HTTPS/format invalide)
WHEN
  - Validation contractuelle exécutée
THEN
  - Code 400/422 selon champ
AND
  - Aucune tentative d’assemblage n’est lancée
TEST-ID: TC-ERR-09
Référence spec: ERR-286-02, CA-286-10

GIVEN
  - Une preuve atomique unique de 11GB (> MAX_TOTAL_EXPORT_BYTES)
WHEN
  - Le backend planifie les volumes
THEN
  - Réponse 413 PROOF_TOO_LARGE
AND
  - Aucun volume émis, aucun assemblage engagé

4bis. Scénarios de test — Finalisation (POST /exports/:exportId/finalize)

TEST-ID: TC-FIN-01
Référence spec: INV-286-09, §5.6

GIVEN
  - Export multi-volumes en état ASSEMBLING, ownership vérifié
WHEN
  - L’app appelle POST /exports/{exportId}/finalize avec {finalStatus: "COMPLETED"}
THEN
  - Session transite vers COMPLETED
AND
  - Audit FINAL émis via ExportAuditService.appendFinal() avec integrityHashes[] et volumes_count
AND
  - Réponse 204 No Content
TEST-ID: TC-FIN-02
Référence spec: INV-286-09, §5.6

GIVEN
  - Export en état DOWNLOADING, hash mismatch détecté par l’app
WHEN
  - L’app appelle POST /exports/{exportId}/finalize avec {finalStatus: "FAILED", reasonCode: "HASH_MISMATCH"}
THEN
  - Session transite vers FAILED
AND
  - Audit FINAL émis avec status FAILED et reasonCode
AND
  - Réponse 204 No Content
TEST-ID: TC-FIN-03
Référence spec: §5.6, anti-énumération

GIVEN
  - exportId inconnu ou non détenu par l’utilisateur authentifié
WHEN
  - L’app appelle POST /exports/{exportId}/finalize
THEN
  - Réponse 404 EXPORT_NOT_FOUND (message uniforme, anti-énumération)
AND
  - Aucune transition ni audit émis
TEST-ID: TC-FIN-04
Référence spec: INV-286-11, §5.6

GIVEN
  - Export déjà en état terminal (COMPLETED, FAILED ou EXPIRED)
WHEN
  - L’app appelle POST /exports/{exportId}/finalize
THEN
  - Transition refusée par la state machine (ForbiddenStateTransitionException)
AND
  - Réponse 500 ou 409

5. Tests d’invariants (non négociables)

Invariant Test(s) dédiés Observable Commentaire
INV-286-01 TC-NOM-02, TC-INV-01 estimatedBytes borné par volume Inclut cas bordes 1 byte et 805306368 bytes
INV-286-02 TC-ERR-01, TC-INV-02 413 au-delà 10GB Cas limite exact 10GB inclus à tester
INV-286-03 TC-INV-03 Couverture des IDs de preuves sur tous volumes Vérifie égalité d’ensemble + cardinalité
INV-286-04 TC-ERR-02, TC-INV-04 Aucune preuve répartie sur >1 volume Contrôle par identifiants de preuve
INV-286-05 TC-NR-01, TC-NOM-01 Compatibilité contrat legacy Régression API/client legacy
INV-286-06 TC-ERR-06, TC-INV-06 Continuité index [0..N-1] Rejet trous, doublons, index hors bornes
INV-286-07 TC-NOM-04, TC-ERR-04 Recalcul hash effectif + arrêt sur mismatch Preuve de comparaison obligatoire
INV-286-08 TC-NOM-03, TC-INV-08 .pvproof unique + métadonnées multi-volumes assembled_from[] complet et cohérent
INV-286-09 TC-NOM-05, TC-INV-09 Écritures WORM fail-closed Champs requis et statut final présents
INV-286-10 TC-INV-10 Transitions autorisées uniquement Matrice d’états exhaustive
INV-286-11 TC-INV-11 États terminaux sans sortie Toute sortie depuis terminal = rejet

6. Tests de non-régression

Test ID Objet Observable Commentaire
TC-NR-01 Contrat single-volume legacy inchangé Clients legacy consomment manifest/signedUrls sans volumes[] obligatoire Couvre INV-286-05
TC-NR-02 Format final .pvproof inchangé Ouverture/validation des consommateurs existants Ajout champs multi-volumes sans rupture
TC-NR-03 Guards auth/premium inchangés Même matrice d’accès avant/après Hors périmètre confirmé
TC-NR-04 Rate limiting inchangé Seuils/comportements identiques avant/après Hors périmètre confirmé
TC-NR-05 Validation des preuves inchangée Même verdict pipeline pour même entrée Hors périmètre confirmé

7. Tests négatifs et adversariaux

Test ID Entrée invalide / abus Résultat attendu Observable
TC-NEG-01 exportId non UUIDv4 400 INVALID_EXPORT_ID Code HTTP + message
TC-NEG-02 integrityHash en majuscules ou longueur != 64 422 VOLUME_INTEGRITY_HASH_INVALID / rejet contrat Validation regex stricte
TC-NEG-03 signedUrl non HTTPS ou >4096 chars 422 SIGNED_URL_INVALID Validation URL
TC-NEG-04 totalVolumes=0 500 INVALID_TOTAL_VOLUMES Rejet backend
TC-NEG-05 volumeIndex <0 500 INVALID_VOLUME_INDEX_RANGE Rejet backend
TC-NEG-06 Tentative de transition FAILED -> REQUESTED même exportId Transition interdite Erreur contractuelle + état inchangé
TC-NEG-07 Tentative de transition depuis COMPLETED vers état non terminal Transition interdite Erreur contractuelle
TC-NEG-08 Réutilisation exportId EXPIRED pour reprise Reprise refusée Nouvelle requête exigée

8. Observabilité requise pour les tests

  • État système : état courant export (REQUESTED/PLANNED_*/DOWNLOADING/ASSEMBLING/COMPLETED/FAILED/EXPIRED) avec horodatage de transition.
  • Réponse API : payload complet (exportId, totalVolumes, volumes[], estimatedBytes, integrityHash, codes erreur contractuels).
  • Journal d’audit : événements WORM corrélés (exportId, volumeIndex, hash_ok/hash_mismatch, volumes_count, statut final).
  • Événement signé / horodaté : preuve d’écriture append-only et d’ordre temporel des événements.
  • Export probatoire : fichier final .pvproof, présence/absence de volumes_count et assembled_from[] selon totalVolumes.

9. Règles non testables

Règle Raison Impact
Canonicalisation JSON exacte (Q-286-01) RFC 8785 (JCS) référencée mais implémentation cross-platform à valider Mineur
Taxonomie finale des codes d’erreur (Q-286-02) Nomenclature non figée contractuellement Majeur
Durée chiffrée de rétention post FAILED/EXPIRED (Q-286-03) Politique citée mais valeur normative absente Mineur
Valeurs TTL de production finales (Q-286-04) Bornes définies, valeurs déployées non confirmées Mineur

10. Verdict QA

  • ⚠️ Testable partiellement (avec réserves listées)

En l’état, la conformité est testable de manière robuste sur flux, erreurs, invariants et non-régression, sous réserve de lever les ambiguïtés Q-286-01 et Q-286-02 pour éviter des verdicts divergents inter-environnements/outils.