Chaos Métier¶
Le Chaos Métier injecte des anomalies fonctionnelles dans le parcours e-commerce de PerfShop. Contrairement au Chaos Backend (dégradation infrastructure) ou au Chaos Scripting (tokens HTTP), ces anomalies touchent la logique applicative : prix, stock, commandes, livraison.
Principe pédagogique¶
Les étudiants doivent identifier et noter les anomalies — pas les corriger.
Règle d'or
Avec les bonnes données de test, une commande doit toujours pouvoir aboutir, quel que soit le niveau de chaos actif.
Les anomalies sont cumulatives : le niveau 2 inclut les anomalies du niveau 1, etc.
Niveaux¶
| Niveau | Label | Anomalies actives | Profil étudiant |
|---|---|---|---|
| 0 | Désactivé | 0 | Référence — tout nominal |
| 1 | Junior | 3 (A1–A3) | Tests fonctionnels basiques |
| 2 | Confirmé | 7 (A1–A7) | Tests de régression |
| 3 | Expert | 11 (A1–A11) | Analyse avancée / TMAP |
| 4 | Master | 16 (A1–A16) | Validation métier par assertions |
Anomalies niveau 1 — Junior¶
A1 · TVA 19,6% au lieu de 20%¶
Implémentation : BusinessChaosService.applyTva() → appelée dans OrderService.createOrderFromItems()
// Niveau 0 : taux correct
return new BigDecimal("0.20");
// Niveau 1+ : ancien taux (supprimé en France en 2014)
return new BigDecimal("0.196");
Le taux est appliqué au total HT pour calculer le totalAmount stocké en base — le montant
affiché dans "Mes commandes" est donc réellement différent du montant correct.
Détection dans l'UI et les logs
A1 est détectable directement dans l'interface :
- Commander un article à 100,00 € HT → total affiché 119,60 € au lieu de 120,00 €
- Écart de 0,33% — subtil mais mesurable par un test de régression sur le calcul TTC
Et dans les logs applicatifs du container perfshop-app :
Approche de test recommandée : passer une commande d'un montant HT connu,
comparer le TTC affiché avec montant_HT × 1,20 attendu — l'écart révèle le taux incorrect.
A2 · Arrondi prix à l'entier inférieur¶
Implémentation : BusinessChaosService.applyPriceRounding()
Niveau 1+ : tout prix > 10 EUR est arrondi à l'entier inférieur (floor).
Impact : 99,99 € facturé 99,00 € → manque à gagner de 0,99 € par article.
Détection : comparer le prix unitaire affiché dans le panier avec le prix catalogue produit.
A3 · Stock non décrémenté¶
Implémentation : BusinessChaosService.shouldDecrementStock() → OrderService
Niveau 0 : après chaque commande, product.setStock(stock - quantité) est appelé et persisté en base.
Niveau 1+ : shouldDecrementStock() retourne false → la mise à jour du stock est sautée. Le produit reste affiché "disponible" indéfiniment, même épuisé.
Impact : survente silencieuse — un produit commandé 10 fois reste toujours disponible.
Détection : noter le stock affiché sur la fiche produit, passer une commande, revérifier — le stock est inchangé en niveau 1+.
Anomalies niveau 2 — Confirmé¶
A4 · Frais de port absents de l'email de confirmation¶
Email envoyé sans la ligne "Frais de livraison" alors que le montant total les inclut.
A5 · Double commande sur double-clic¶
Absence d'idempotence sur POST /api/orders : deux clics rapides créent deux commandes identiques.
Détection : la liste des commandes affiche deux entrées avec le même contenu et des numéros consécutifs.
A6 · Code promo invalide accepté¶
Un code promo inexistant est accepté sans erreur, avec 0% de réduction appliquée.
Détection : soumettre un code aléatoire — la réponse est 200 OK au lieu de 400 Bad Request.
A7 · Délai de livraison en jours calendaires¶
Le délai affiché ("3 jours ouvrés") est calculé sur 7 jours/7 au lieu de jours ouvrés.
Anomalies niveau 3 — Expert¶
A8 · Race condition sur le stock¶
Lecture et écriture du stock sans verrou → survente possible en charge concurrente.
A9 · Injection de logs (log poisoning)¶
Les champs texte libres (prénom, nom, ville) acceptent des caractères LF/CRLF,
permettant d'injecter de fausses entrées dans les logs applicatifs.
A10 · Total historique des commandes incorrect¶
Le total cumulé affiché dans "Mes commandes" est différent de la somme réelle en base.
A11 · Token session non invalidé après logout¶
Après un POST /api/auth/logout, le comportement diffère selon le niveau :
Niveau 0-2 (normal) : session.invalidate() est appelé → tous les attributs de session sont détruits (user, securityToken, bundle scripting, données checkout).
Niveau 3 (anomalie A11) : seul session.removeAttribute("LOGGED_IN_USER") est appelé. La session HTTP elle-même reste active avec :
- le securityToken encore valide → POST /api/orders accessible
- le bundle scripting non invalidé → tokens Chaos Scripting encore utilisables
- les données checkout encore présentes en session
En pratique, tout le parcours checkout reste exploitable pendant 30 secondes après le logout — pas seulement un token.
Le champ graceActive est exposé dans /api/auth/status pour indiquer si A11 est configurée :
GET /api/auth/status
{
"authenticated": false,
"hasToken": false,
"userId": null,
"graceActive": true
}
graceActive: true signifie que le chaos est en niveau 3 — la surface d'attaque est donc plus large que le simple securityToken.
Anomalies niveau 4 — Master¶
Détection par assertion uniquement
Toutes les anomalies Master sont silencieuses — aucune erreur HTTP, aucune exception visible. La détection nécessite des assertions explicites sur les données métier. C'est l'enjeu du niveau Master : passer de la détection d'erreurs techniques à la validation fonctionnelle.
A12 · Remise fidélité silencieuse¶
Implémentation : BusinessChaosService.applyLoyaltyDiscount() → OrderService.createOrderFromItems()
Le programme fidélité prévoit une remise de -5% à partir de 6 commandes. En niveau 4, la condition de déclenchement contient un bug silencieux (orderCount != -999, condition toujours vraie) qui empêche systématiquement l'application de la remise.
Impact : l'interface MyOrders.jsx affiche "Programme Fidélité — ✓ Éligible" mais le total payé ne bénéficie d'aucune réduction.
Détection : créer un compte avec 6+ commandes, calculer le total attendu avec remise -5%, comparer avec le total réellement débité.
A13 · Devise affichage USD¶
Implémentation : BusinessChaosService.getCurrency() → ProductController.getAllProducts()
En niveau 4, GET /api/products retourne un champ currency: "USD" dans la réponse. Le bandeau ⚠️ Les prix sont affichés en USD apparaît dans l'interface.
// Réponse niveau 0–3 (nominal)
[{ "id": 1, "name": "...", "price": 29.99 }]
// Réponse niveau 4 (A13 actif)
{ "currency": "USD", "products": [{ "id": 1, "name": "...", "price": 29.99 }] }
Détection : parser la réponse JSON de /api/products, valider que currency === "EUR".
A14 · Frais de port doublés¶
Implémentation : BusinessChaosService.applyShippingCost() → OrderService.createOrderFromItems()
En niveau 4, les frais de port sont multipliés par 2 dans le calcul du total commande.
Interaction A14 × A1
En niveau 4, A1 (TVA 19,6%) est aussi active. La formule effective cumulative est :
Un test correct doit tenir compte des deux anomalies simultanément.Détection : calculer (prix_HT + frais_port_nominal) × 1.20, comparer avec le total affiché.
A15 · Corruption historique ×1.1¶
Implémentation : BusinessChaosService.applyHistoryCorruption() → OrderController.getUserOrders()
En niveau 4, chaque total retourné par GET /api/orders est multiplié par 1.1. Le total stocké en base reste correct — seule la lecture de l'historique est altérée.
Impact : une commande de 100 € apparaît à 110 € dans "Mes commandes".
Détection : croiser le total enregistré au moment de la création vs le total affiché dans l'historique.
A16 · Annulation sans remboursement stock¶
Implémentation : BusinessChaosService.shouldRestockOnCancel() → OrderController.cancelOrder()
En niveau 4, l'annulation d'une commande ne recrédite pas le stock des produits concernés. La commande est bien passée en statut CANCELLED en base, mais product.stock n'est pas incrémenté.
Détection : noter le stock avant commande, commander, annuler, vérifier que le stock est revenu à sa valeur initiale.
Observabilité¶
Chaque anomalie déclenchée produit :
- un log
WARNdans les logs du containerperfshop-app(préfixe[BusinessChaos][AN]) - une entrée dans l'activity log visible dans l'onglet Métier du monitoring
Endpoint logs :
Endpoint statut + compteurs :
Contrôle admin¶
POST /api/admin/chaos/business
{ "level": 1 } # 0 = off, 1 = Junior, 2 = Confirmé, 3 = Expert, 4 = Master
Accessible depuis l'onglet 💼 Chaos Métier du chaos-admin, via cookie de session
ou header X-Admin-Token.