24 points par GN⁺ 2025-12-19 | 4 commentaires | Partager sur WhatsApp
  • SQLite maintient un haut niveau de fiabilité et de robustesse grâce à un système de tests automatisés extrêmement rigoureux, avec 590 fois plus de code de test que de code produit
  • Quatre harness de test indépendants (TCL, TH3, SQL Logic Test, dbsqlfuzz) valident la bibliothèque principale et exécutent des centaines de millions de tests
  • Des tests de situations anormales (OOM, erreurs d’E/S, simulation de crash) et des tests de fuzzing permettent de vérifier un fonctionnement stable même face à des entrées invalides et à des défaillances système
  • Des procédures de validation multicouches sont maintenues, notamment 100 % de couverture de branches et MC/DC, détection des fuites de ressources, Valgrind, analyse statique et checklist
  • Grâce à cette approche de test systématique, SQLite est considéré comme une base de données open source offrant une fiabilité et une qualité de niveau base de données commerciale

1. Vue d’ensemble

  • La fiabilité et la robustesse de SQLite proviennent d’un processus de test minutieux
    • À la version 3.42.0, SQLite se compose d’environ 155.8 KSLOC de code C et de 92053.1 KSLOC de code de test
  • Le système de test comprend 4 harness indépendants, une couverture de branches à 100 % et des millions de cas de test
    • Il inclut notamment des tests OOM, d’erreurs d’E/S, de crash, de fuzzing, de valeurs limites, de régression, de fichiers DB anormaux et de désactivation des optimisations

2. Harness de test

  • TCL Tests
    • Ensemble de tests public principalement utilisé pendant le développement de SQLite
    • Composé de 27.2 KSLOC de code C et de 1390 fichiers de scripts (23.2MB)
    • Environ 50 000 cas de test, et plusieurs millions d’exécutions lors d’un run complet grâce à la paramétrisation
  • TH3
    • Ensemble de tests commercial en C atteignant 100 % de couverture de branches et MC/DC
    • Fonctionne aussi en environnement embarqué, avec 1055.4 KSLOC et environ 50 000 cas
    • Environ 2,4 millions d’exécutions pour un test complet de couverture, et 248 millions de soak tests avant publication
  • SQL Logic Test (SLT)
    • Compare les résultats de SQLite avec PostgreSQL, MySQL, SQL Server et Oracle 10g
    • Composé de 7,2 millions de requêtes et de 1.12GB de données
  • dbsqlfuzz
    • Fuzzer basé sur libFuzzer qui fait muter simultanément le SQL et les fichiers de base de données
    • Effectue environ 1 milliard de tests de mutation par jour pour vérifier la robustesse face à des entrées malveillantes
  • Outils supplémentaires
    • speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz, etc.
    • Tous les tests doivent passer sur plusieurs plateformes et configurations de compilation avant qu’une release soit possible

3. Tests de situations anormales

  • Tests OOM
    • Simulent des échecs de malloc() pour vérifier la capacité de récupération en cas de manque de mémoire
    • Répétés en incrémentant le compteur du point d’échec
  • Tests d’erreurs d’E/S
    • Utilisent un système de fichiers virtuel (VFS) pour simuler des erreurs disque
    • Vérifient l’intégrité des données après erreur avec PRAGMA integrity_check
  • Tests de crash
    • Simulent des coupures d’alimentation et des crashs du système d’exploitation
    • Le harness TCL s’appuie sur des processus enfants, TH3 sur un VFS en mémoire
    • Vérifient qu’une transaction est soit totalement annulée, soit totalement terminée
  • Tests de pannes combinées
    • Vérifient aussi les cas où un OOM ou une erreur d’E/S survient en chaîne après un crash

4. Tests de fuzzing

  • SQL Fuzz
    • Génère du SQL syntaxiquement valide mais anormal pour vérifier la réaction de SQLite
  • American Fuzzy Lop (AFL)
    • Fuzzer guidé par profil introduit en 2014 pour explorer de nouveaux chemins de contrôle
    • A découvert de nombreux échecs d’assert, crashs et résultats erronés dans SQLite
  • Google OSS Fuzz
    • Fuzzing automatisé exécuté sur l’infrastructure de Google depuis 2016
    • Détecte des problèmes intermittents sur les nouveaux commits
  • dbsqlfuzz / jfuzz
    • Introduits comme fuzzers internes à partir de 2018, avec mutation simultanée du SQL et des fichiers DB
    • Plus de 500 millions de tests par jour, ce qui a presque fait disparaître les rapports de bugs issus de fuzzers externes
    • Depuis 2024, jfuzz ajoute la validation des entrées JSONB
  • Fuzzers tiers et fuzzcheck
    • Des chercheurs externes (par ex. Manuel Rigger) ont découvert de nombreux cas de calculs erronés
    • L’utilitaire fuzzcheck revalide plusieurs milliers d’anciens cas de fuzz jugés « intéressants »
  • La tension entre MC/DC et fuzz testing
    • MC/DC pousse à minimiser le code défensif, tandis que le fuzzing nécessite ce code défensif
    • SQLite combine les deux approches pour conserver un code robuste face aux entrées normales comme malveillantes

5. Tests de régression

  • Tout bug signalé est obligatoirement ajouté sous forme de nouveau cas de test après correction
    • L’objectif est d’éviter la réapparition d’anciens bugs

6. Détection automatique des fuites de ressources

  • Les harness TCL et TH3 surveillent automatiquement les fuites de mémoire, de fichiers, de threads et de mutex
    • Même après un OOM ou une erreur d’E/S, aucune fuite mémoire ne doit subsister

7. Couverture de test

  • Le cœur de SQLite atteint 100 % de couverture de branches selon TH3
    • Hors extensions comme FTS3 et RTree
  • Statement vs Branch Coverage
    • La couverture de branches est plus stricte que la couverture d’instructions, car elle valide chaque embranchement dans les deux sens
  • Couverture du code défensif
    • Les macros ALWAYS() et NEVER() explicitent les conditions défensives
    • Les tests sont répétés avec trois formes de définition pour vérifier la cohérence
  • Tests de valeurs limites et de vecteurs booléens
    • La macro testcase() vérifie à la fois les résultats positifs et négatifs des conditions
    • 1184 appels à testcase() sont utilisés
  • Atteinte de MC/DC
    • La macro testcase() permet de vérifier l’impact indépendant de chaque condition
  • Mesure basée sur gcov
    • La couverture est mesurée avec les options -fprofile-arcs -ftest-coverage
    • La comparaison des résultats permet de détecter des bugs compilateur ou des comportements indéfinis
  • Mutation Testing
    • Modifie les instructions de branchement pour vérifier que les tests détectent ces changements
    • Les branches d’optimisation (/*OPTIMIZATION-IF-TRUE*/) sont traitées comme exception
  • Retour d’expérience sur la couverture complète
    • Le test de toutes les branches minimise les effets de bord lors des modifications du code
    • Le coût de maintenance est élevé, mais il est justifié pour une bibliothèque d’infrastructure largement déployée

8. Analyse dynamique

  • Assert()
    • 6754 assertions vérifient les préconditions, postconditions et invariants de boucle
    • Actives uniquement dans les builds SQLITE_DEBUG
  • Valgrind
    • Détecte les erreurs mémoire, les débordements de pile et les accès à de la mémoire non initialisée
    • Avant chaque release, les tests veryquick et TH3 sont exécutés sous Valgrind
  • Memsys2
    • Dans les builds SQLITE_MEMDEBUG, un wrapper est inséré pour surveiller les erreurs mémoire
    • Permet des vérifications répétées plus rapides qu’avec Valgrind
  • Mutex Asserts
    • sqlite3_mutex_held() et autres vérifient la synchronisation multithread
  • Journal Tests
    • Vérifient que le journal de rollback est écrit avant la DB, garantissant l’atomicité des transactions
  • Undefined Behavior Checks
    • Détectent les comportements indéfinis avec -ftrapv, -fsanitize=undefined, /RTC1, etc.
    • Répétés en 32/64 bits, selon l’endianness et sur diverses architectures CPU

9. Tests avec optimisations désactivées

  • sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) permet de désactiver les optimisations
    • Les résultats doivent être identiques avec ou sans optimisations
    • Certains tests de mesure de performance font exception

10. Checklist

  • Avant chaque release, une checklist manuelle d’environ 200 éléments est vérifiée
    • Certains points prennent quelques secondes, d’autres plusieurs heures
    • En cas de problème détecté, un nouvel élément est ajouté immédiatement pour améliorer le processus en continu

11. Analyse statique

  • Compilation sans avertissement avec GCC, Clang et MSVC
    • Aucun avertissement valide non plus avec Clang Static Analyzer
    • L’analyse statique a une efficacité limitée pour détecter les bugs réels

12. Résumé

  • Bien qu’open source, SQLite maintient une qualité de niveau commercial et un faible taux de défauts
    • Des tests rigoureux et la conception du code en sont les facteurs clés
    • Chaque release passe par les procédures ci-dessus pour fournir un moteur de base de données fiable même dans des environnements critiques

4 commentaires

 
GN⁺ 2025-12-19
Commentaires sur Hacker News
  • Il y a une dizaine d’années, le mainteneur de SQLite a fait une présentation à l’OSCON sur les pratiques de test
    Ce qui m’avait particulièrement marqué, c’était la force des checklists. Exactement l’outil qu’utilisent les pilotes avant chaque vol
    Il a aussi mentionné un cas de Médecins Sans Frontières (Doctors Without Borders), où les résultats des opérations étaient mauvais parce que le personnel médical ne connaissait même pas les noms des autres et ne parlait pas la même langue
    La solution était simple — créer une checklist préopératoire obligeant chacun à dire son nom et son rôle. Ce petit rituel a amélioré le taux de survie non pas grâce à la technique, mais grâce à une meilleure communication
    Ressource liée : exemple de checklist SQLite

    • À l’inverse, je pense que ce genre d’histoire peut engendrer une bureaucratie inutile. Les checklists dans l’aviation, chez MSF ou pour SQLite sont excellentes, mais la plupart des organisations perdent leur temps avec des checklists inutiles
      Il faudrait davantage discuter de la différence entre une bonne checklist et une mauvaise. Comme une belle formule en mathématiques, cela paraît simple, mais c’est difficile à découvrir
    • J’ai toujours eu le sentiment qu’il y avait beaucoup à apprendre des opérations aériennes et de l’ingénierie. J’imagine une organisation IT combinant ces principes avec un leadership de type militaire
      J’ai notamment lu plusieurs fois le document FM22-100 de l’armée américaine, que je trouve étonnamment moderne et inspirant
      Voir le document FM22-100
    • Si vous voulez apprendre à créer de bonnes checklists, je recommande vivement The Checklist Manifesto
      Lien vers le livre
    • Je ne comprends pas pourquoi la plupart des développeurs cherchent à éviter les tâches simples non liées à la programmation
      En plus des tests et de la CI, je suis une checklist de déploiement en Markdown. Je ne sauvegarde même pas les résultats, mais j’exécute les étapes une par une
      Je ne comprends pas pourquoi les autres ne font pas quelque chose d’aussi simple
    • Je trouve intéressant que les rituels améliorent les performances. Même aujourd’hui, dans les réunions, faire un tour de présentation augmente clairement la participation
      S’il existe une page officielle sur le cas de MSF, j’aimerais vraiment la voir. Je n’ai rien trouvé en cherchant sur Google
  • Voici une compilation d’anciennes discussions sur les tests de SQLite
    Liste des fils HN de 2009 à 2024
    On dirait que les reposts reviennent à intervalles d’un an

  • Le processus qui consiste à polir un logiciel comme SQLite à ce point m’inspire à la fois de l’envie et de l’émerveillement
    C’est une œuvre où l’on sent l’artisanat

    • En réalité, n’importe qui peut faire comme ça. Je n’ai jamais été licencié pour avoir construit quelque chose lentement et correctement
      Avec le temps, le niveau d’exigence monte, et on obtient de plus grandes récompenses pour le même effort
      Personne n’aime détester quelqu’un qui laisse la partie qu’il a touchée un peu plus propre qu’avant
  • SQLite est vraiment un excellent logiciel. J’aime aussi le fait que son site officiel soit centré sur l’information plutôt que sur le marketing
    Cela dit, c’est intéressant de voir récemment sur HN les pages du site officiel remonter une à une

    • C’est sans doute parce que le billet de simonw sur le portage d’un LLM a fait parler de lui hier, ce qui a remis les liens associés sous les projecteurs
    • Sur HN, ce genre de chose revient périodiquement. Avant, c’était Haskell ; en ce moment, c’est Zig qui est dans cette phase
      Ce serait amusant de rassembler ce type de liens
  • Je trouve intéressant que SQLite soit un logiciel public tout en utilisant des tests privés
    Je réalise seulement maintenant qu’un projet open source peut avoir des tests fermés
    J’ai l’impression que ce modèle pourrait devenir un nouveau modèle économique, un peu comme l’open-core

    • En réalité, il arrive souvent que la suite de tests ait plus de valeur que le code. Par exemple, documenter les innombrables cas limites d’un logiciel comme Excel est plus difficile que son implémentation
    • Je fais quelque chose de similaire dans un projet d’entreprise. Avec une double licence GPL, les tests et générateurs de données ne sont accessibles qu’aux utilisateurs sous licence commerciale
      Exemple : licence de railgunlabs/unicorn
  • La couverture de branches à 100 % de SQLite est presque aussi impressionnante que le projet lui-même
    Le fait de la maintenir dans le temps est particulièrement remarquable

  • Le fait que les tests soient privés est intéressant. Maintenant que le code assisté par LLM progresse, on entre dans une époque où les tests deviennent plus importants que l’implémentation
    En voyant récemment le cas où simonw a presque automatiquement converti le moteur justHTML de Python vers JS, j’ai repensé à la stratégie de test de SQLite

    • Du point de vue du modèle économique d’un produit open source, une vaste suite de tests devient un actif central pour faire évoluer efficacement le produit et créer de la valeur
    • Le document How SQLite Is Tested donne littéralement l’impression d’être une bible du test
  • J’ai récemment discuté avec un LLM de la compatibilité entre SQLite et DuckDB, et j’en ai conclu que SQLite est meilleur sur le plan de la gestion de la concurrence

  • J’ai été surpris de voir que la documentation de test de SQLite parle peu des tests de régression de performance (performance regression)
    La justesse est importante, mais une dégradation des performances sur certains chemins de requête peut être fatale

    • J’ai travaillé dans le HFT, mais j’ai rarement vu des projets open source mettre en avant des garanties de performance
      Je me demande s’il existe des projets qui en font un objectif central
  • Vu la stabilité de SQLite, j’aurais voulu en savoir plus sur la manière dont les tests d’anomalies étaient réalisés
    Mais l’article n’en parlait presque pas. Malgré cela, SQLite reste l’un des logiciels les plus robustes utilisés sur tous les appareils

    • Comme l’accès à la suite de tests coûte environ 150 000 dollars par an, il semble peu probable que son contenu soit rendu public
 
regentag 2025-12-19

Article connexe à lire : L’histoire méconnue de SQLite

Il s’agit d’un article qui résume une interview de Richard Hipp, le développeur de SQLite.

Les développeurs de SQLite auraient découvert la norme Do-178 à l’époque où ils travaillaient avec Rockwell Collins, et auraient commencé à suivre cette procédure. L’un des points est notamment d’atteindre 100 % de MC/DC.

Le Do-178 est vraiment un guide très utile, donc je recommande à tous les développeurs de le lire.

 
roxie 2025-12-19

Est-ce que c’est celui-ci ? https://alm.parasoft.com/hubfs/…

 
regentag 2025-12-19

Je pense que le lien que vous avez partagé est un support de formation Do-178.
Le document original se trouve à ce lien.
https://studylib.net/doc/27132454/rtca-do-178b