Fixtures : le générateur de cartes SD¶
Les cartes SD de recette (arbres LogPR<serie>.txt + PaRecPR<serie>_THLog.csv + bruts/*.wav)
pesaient autrefois plusieurs centaines de méga-octets et étaient faites à la main : impossibles à
committer (binaire lourd, dépôt public et forké) et non rejouables (rien ne garantissait de les
reconstruire à l'identique).
On les décrit désormais par des specs déclaratives de quelques kilo-octets, sous
recette/fixtures/spec/, qu'un générateur déterministe matérialise sur disque. La spec est la
source de vérité ; l'arbre SD n'en est qu'un artefact reconstructible octet pour octet : le
générateur ne tire aucune date de l'horloge ni aucun octet aléatoire.
Le générateur vit en portée test (src/test/java/fr/univ_amu/iut/recette/) : l'application
distribuée n'embarque pas la fabrique de fixtures ; ce sont les tests qui fabriquent WAV/ZIP.
Le format de spec¶
Une spec est un fichier YAML. Tous les champs ont des valeurs par défaut raisonnables, donc une spec reste concise. Exemple commenté (le cas propre) :
fixture: sd-nominale # nom de la carte (= nom du sous-dossier généré)
but: "Cas propre : 6 wav, un seul enregistreur, une seule nuit."
journal: # journal du capteur LogPR<serie>.txt
present: true # false -> aucun journal (mode dégradé)
serie: "1925492" # n° de série déclaré (nomme aussi le fichier)
nuit: "2026-04-22" # date de la 1re ligne (fixe dateDebut pour l'analyseur)
sondePresente: true # ajoute la ligne « Sonde ... présente »
corrompu: false # true -> journal illisible (aucune série extractible)
thlog: # relevé climatique PaRecPR<serie>_THLog.csv
present: true
mesures: 6 # nombre de lignes de mesures déterministes
wav: # paramètres communs des WAV (RIFF mono 16 bits valide)
frequenceHz: 384000 # inscrite dans l'en-tête ; divisible par 10 (règle R10)
dureeSecondes: 1.5 # courte, pour des fixtures légères
zip: true # produit aussi sd-nominale.zip (chemin de décompression)
enregistreurs: # un ou plusieurs enregistreurs présents dans bruts/
- serie: "1925492"
horodatages: # PaRecPR<serie>_<yyyyMMdd>_<HHmmss>.wav
- "20260422_203922"
- "20260422_210515"
# fauxWav: ["20260422_211500"] # octets non-WAV : rejetés à l'import
attendu: # contrat de recette (voir « Le garde-fou »)
aJournal: true
aReleve: true
journalLisible: true # false -> l'inspection doit échouer
plusieursEnregistreurs: false # bandeau « mélange »
incoherent: false # bandeau « incohérence »
nuits: 1 # nombre de nuits détectées
etatNommage: "BRUT" # BRUT, PREFIXE ou VIDE
rejets: 0 # > 0 déclenche la vérification d'import réel
Deux variantes utiles :
-
Préfixe (carte déjà nommée en session) : un bloc
prefixe:ajoute le préfixe R6Car<carre>-<annee>-Pass<passage>-<point>-devant chaque nom de brut. -
Horodatages génératifs (grosses cartes) : au lieu de lister chaque fichier, on décrit une série déterministe.
Les 9 cartes de recette¶
Chaque carte exerce une pathologie de l'assistant d'import (voir l'étape 5 de S2 · Importer une nuit).
| Carte | Ce qu'elle exerce | wav |
|---|---|---|
sd-nominale (+ .zip) |
cas propre ; l'archive exerce le chemin de décompression | 6 |
sd-melange |
deux enregistreurs dans le même dossier -> bandeau « mélange » | 6 |
sd-incoherente |
journal et wav en désaccord (série + date) -> bandeau « incohérence » | 3 |
sd-multi-nuits |
trois nuits sous un journal unique -> table des nuits | 6 |
sd-sans-journal |
aucun LogPR -> mode dégradé (import possible sans journal) |
3 |
sd-journal-corrompu |
LogPR illisible -> l'inspection échoue avec un message clair |
3 |
sd-prefixee |
bruts déjà préfixés Car... -> état de nommage PREFIXE |
3 |
sd-rejets |
un faux wav parmi huit valides -> l'import aboutit, zone des rejets | 9 |
sd-grosse |
soixante wav -> test de charge (progression, parallélisme, disque) | 60 |
Régénérer les cartes¶
Le générateur ne fait pas partie du binaire ; on le lance en portée test via un goal de confort (non lié à une phase, jamais exécuté en CI ni au packaging) :
env -u DISPLAY ./mvnw -q test-compile exec:java@generer-sd \
-Dexec.args="recette/fixtures/spec /chemin/vers/dest"
Chaque carte est écrite dans dest/<fixture>/ (et dest/<fixture>.zip si la spec le demande). Deux
exécutions produisent des octets identiques. Passer une seule spec au lieu du dossier ne génère
que cette carte.
Le garde-fou¶
Le bloc attendu de chaque spec est un contrat vérifié contre le code réel, pas contre une
liste tenue à la main. Deux tests (esprit cliquet, sans JavaFX) amarrent le générateur à la réalité :
GenerationCartesSDCliquetTest: pour chaque spec, génère la carte puis vérifie que l'inspection réelle (InspecteurDossier) constate la pathologie déclarée (mélange, incohérence, nombre de nuits, état de nommage, nombre d'originaux, journal illisible), plus le round-trip du zip viaExtracteurZip.GenerationCartesSDImportCliquetTest: pour toute spec à rejets (attendu.rejets > 0), lance un import réel headless (ServiceImportsur base SQLite jetable) et vérifiecompte(REJETE). C'est le seul cas de recette qui se joue à l'import et non à la seule inspection.
Ces tests deviennent rouges si le générateur cesse de produire la bonne carte ou si un détecteur
d'import change de comportement (AnalyseMelange, AnalyseCoherence, PartitionNuits,
AnalyseurLogPR, ServiceImport, ExtracteurZip).
Où ça vit¶
recette/fixtures/spec/*.yaml: les specs (source de vérité, versionnées).src/test/java/fr/univ_amu/iut/recette/: le générateur (GenerateurCartesSD,FabriqueWav,LecteurSpec,SpecCarteSd) et les deux garde-fous.- Le rejeu déterministe complet (générer -> importer via la CLI -> comparer à un golden) prolonge ce socle : voir la section « Rejouer une campagne » de la méthode.
La décision de conception (specs déclaratives + générateur déterministe, portée test) est consignée dans l'ADR 0015.