Wie wird SQLite getestet?
(sqlite.org)- SQLite erhält seine hohe Zuverlässigkeit und Robustheit durch ein gründlich automatisiertes Testsystem; es gibt 590-mal mehr Testcode als Produktivcode
- Vier unabhängige Test-Harnesses (TCL, TH3, SQL Logic Test, dbsqlfuzz) validieren die Kernbibliothek und führen Hunderte Millionen Tests aus
- Durch Tests von Ausnahmezuständen (OOM, I/O-Fehler, Crash-Simulationen) und Fuzz-Testing wird geprüft, dass das System auch bei fehlerhaften Eingaben und Systemausfällen stabil arbeitet
- Es wird ein mehrschichtiger Verifizierungsprozess mit 100 % Branch- und MC/DC-Coverage, Erkennung von Ressourcenlecks, Valgrind, statischer Analyse und Checklisten aufrechterhalten
- Dank dieser systematischen Tests wird SQLite als Open-Source-Datenbank mit Zuverlässigkeit und Qualität auf kommerziellem DB-Niveau bewertet
1. Überblick
- Die Zuverlässigkeit und Robustheit von SQLite resultiert aus einem detaillierten Testprozess
- Mit Stand Version 3.42.0 besteht SQLite aus etwa 155,8 KSLOC C-Code und 92053,1 KSLOC Testcode
- Das Testsystem umfasst 4 unabhängige Harnesses, 100 % Branch-Coverage und Millionen von Testfällen
- Enthalten sind unter anderem OOM-, I/O-Fehler-, Crash-, Fuzz-, Grenzwert-, Regressions-, fehlerhafte-DB-Datei- und Tests mit deaktivierten Optimierungen
2. Test-Harnesses
- TCL Tests
- Öffentlich verfügbares Testset, das hauptsächlich während der SQLite-Entwicklung verwendet wird
- Besteht aus 27,2 KSLOC C-Code und 1390 Skriptdateien (23,2 MB)
- Etwa 50.000 Testfälle; durch Parametrisierung werden bei einer vollständigen Ausführung Hunderte Millionen Tests durchgeführt
- TH3
- Kommerzielles C-basiertes Testset, das 100 % Branch- und MC/DC-Coverage erreicht
- Läuft auch in Embedded-Umgebungen und umfasst 1055,4 KSLOC sowie etwa 50.000 Fälle
- Bei vollständigen Coverage-Tests etwa 2,4 Millionen Ausführungen, vor Releases 248 Millionen Soak-Tests
- SQL Logic Test (SLT)
- Vergleicht Ergebnisse von SQLite mit PostgreSQL, MySQL, SQL Server und Oracle 10g
- Besteht aus 7,2 Millionen Queries und 1,12 GB Daten
- dbsqlfuzz
- libFuzzer-basierter Fuzzer, der SQL und Datenbankdateien gleichzeitig mutiert
- Führt pro Tag etwa 1 Milliarde Mutationstests durch und prüft die Robustheit gegenüber bösartigen Eingaben
- Zusätzliche Werkzeuge
- speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz usw.
- Ein Release ist nur möglich, wenn alle Tests auf mehreren Plattformen und mit verschiedenen Compiler-Konfigurationen bestehen
3. Tests von Ausnahmezuständen
- OOM-Tests
- Simulieren
malloc()-Fehlschläge, um zu prüfen, ob bei Speichermangel korrekt wiederhergestellt wird - Die Tests werden wiederholt ausgeführt, wobei der Zähler für den Fehlerzeitpunkt schrittweise erhöht wird
- Simulieren
- I/O-Fehlertests
- Simulieren Plattenfehler mithilfe eines virtuellen Dateisystems (VFS)
- Nach einem Fehler wird mit
PRAGMA integrity_checkgeprüft, ob Daten beschädigt wurden
- Crash-Tests
- Simulieren Stromausfälle und OS-Abstürze
- Das TCL-Harness basiert auf Kindprozessen, TH3 verwendet ein speicherbasiertes VFS
- Es wird verifiziert, dass Transaktionen entweder vollständig zurückgerollt oder vollständig abgeschlossen werden
- Kombinierte Fehlertests
- Prüfen auch Szenarien, in denen nach einem Crash zusätzlich OOM- oder I/O-Fehler nacheinander auftreten
4. Fuzz-Testing
- SQL Fuzz
- Erzeugt syntaktisch gültiges, aber ungewöhnliches SQL, um die Reaktion von SQLite zu prüfen
- American Fuzzy Lop (AFL)
- Profilbasierter Fuzzer, eingeführt 2014, der neue Kontrollpfade erkundet
- Fand zahlreiche
assert-Fehlschläge, Abstürze und fehlerhafte Ergebnisse in SQLite
- Google OSS Fuzz
- Führt seit 2016 automatisches Fuzzing auf der Google-Infrastruktur durch
- Erkennt sporadische Probleme in neuen Commits
- dbsqlfuzz / jfuzz
- Seit 2018 als interne Fuzzer eingeführt; mutieren SQL und DB-Dateien gleichzeitig
- Mehr als 500 Millionen Tests pro Tag; Bug-Reports von externen Fuzzern sind fast vollständig verschwunden
- Seit 2024 ergänzt jfuzz die Validierung von JSONB-Eingaben
- Fuzzer von Drittanbietern und fuzzcheck
- Externe Forschende (z. B. Manuel Rigger) fanden zahlreiche Fälle falsch berechneter Ergebnisse
- Das Hilfsprogramm fuzzcheck validiert erneut Tausende „interessante“ frühere Fuzz-Fälle
- Spannungsverhältnis zwischen MC/DC und Fuzz-Testing
- MC/DC minimiert defensiven Code, Fuzzing erfordert defensiven Code
- SQLite kombiniert beide Ansätze, um Code aufrechtzuerhalten, der sowohl bei normalen als auch bei bösartigen Eingaben robust ist
5. Regressionstests
- Gemeldete Bugs werden nach der Behebung zwingend als neue Testfälle ergänzt
- Ziel ist es, das Wiederauftreten früherer Bugs zu verhindern
6. Automatische Erkennung von Ressourcenlecks
- TCL- und TH3-Harnesses überwachen automatisch Speicher-, Datei-, Thread- und Mutex-Lecks
- Auch nach OOM- oder I/O-Fehlern darf es keine Speicherlecks geben
7. Testabdeckung
- Der SQLite-Core erreicht 100 % Branch-Coverage nach TH3
- Erweiterungen wie FTS3 und RTree sind ausgenommen
- Statement- vs. Branch-Coverage
- Branch-Coverage ist strenger als Statement-Coverage und prüft alle Bedingungszweige in beide Richtungen
- Coverage für defensiven Code
- Defensive Bedingungen werden mit den Makros ALWAYS() und NEVER() gekennzeichnet
- Durch wiederholte Tests mit drei Definitionsformen wird Konsistenz verifiziert
- Grenzwert- und Boolean-Vektor-Tests
- Mit dem Makro testcase() werden sowohl positive als auch negative Ergebnisse einer Bedingung geprüft
- 1184 Verwendungen von testcase()
- Erreichen von MC/DC
- Über das Makro testcase() wird der unabhängige Einfluss jeder Bedingung validiert
- gcov-basierte Messung
- Die Coverage wird mit den Optionen
-fprofile-arcs -ftest-coveragegemessen - Durch den Vergleich der Ergebnisse werden Compiler-Bugs oder undefiniertes Verhalten erkannt
- Die Coverage wird mit den Optionen
- Mutation Testing
- Ändert Branch-Anweisungen, um zu prüfen, ob die Tests dies erkennen
- Optimierungszweige (
/*OPTIMIZATION-IF-TRUE*/) werden als Ausnahme behandelt
- Erfahrung mit vollständiger Coverage
- Dank der Tests aller Branches werden Nebenwirkungen bei Codeänderungen minimiert
- Die Wartungskosten sind hoch, aber für eine breit eingesetzte Infrastruktur-Bibliothek gerechtfertigt
8. Dynamische Analyse
- Assert()
- 6754
assert-Anweisungen prüfen Vor- und Nachbedingungen sowie Schleifeninvarianten - Nur in
SQLITE_DEBUG-Builds aktiv
- 6754
- Valgrind
- Erkennt Speicherfehler, Stack-Overflows und Zugriffe auf nicht initialisierten Speicher
- Vor Releases werden veryquick- und TH3-Tests unter Valgrind ausgeführt
- Memsys2
- In
SQLITE_MEMDEBUG-Builds werden Wrapper zur Überwachung von Speicherfehlern eingefügt - Wiederholte Prüfungen sind damit schneller als mit Valgrind möglich
- In
- Mutex Asserts
- Validieren Multithreading-Synchronisation mit
sqlite3_mutex_held()usw.
- Validieren Multithreading-Synchronisation mit
- Journal-Tests
- Prüfen, ob das Rollback-Journal vor der DB geschrieben wird, und gewährleisten so die Atomizität von Transaktionen
- Checks auf undefiniertes Verhalten
- Erkennen undefiniertes Verhalten mit
-ftrapv,-fsanitize=undefined,/RTC1usw. - Werden wiederholt auf 32-/64-Bit-Systemen, mit unterschiedlicher Endianness und auf verschiedenen CPU-Architekturen ausgeführt
- Erkennen undefiniertes Verhalten mit
9. Tests mit deaktivierten Optimierungen
- Optimierungen können mit
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)deaktiviert werden- Unabhängig davon, ob Optimierungen aktiv sind oder nicht, müssen identische Ergebnisse erzeugt werden
- Einige Tests zur Leistungsmessung sind ausgenommen
10. Checkliste
- Vor einem Release wird eine manuelle Checkliste mit etwa 200 Punkten geprüft
- Einige Punkte dauern nur Sekunden, andere mehrere Stunden
- Wenn Probleme entdeckt werden, werden sofort neue Punkte ergänzt, um das Verfahren kontinuierlich zu verbessern
11. Statische Analyse
- Kompiliert auf GCC, Clang und MSVC ohne Warnungen
- Auch der Clang Static Analyzer liefert keine gültigen Warnungen
- Die tatsächliche Wirksamkeit statischer Analyse bei der Erkennung realer Bugs ist begrenzt
12. Zusammenfassung
- Trotz seines Open-Source-Status hält SQLite Qualität auf kommerziellem Niveau und eine niedrige Fehlerrate aufrecht
- Gründliche Tests und Code-Design sind die entscheidenden Faktoren
- Jedes Release durchläuft die oben genannten Verfahren und wird so als auch in mission-kritischen Umgebungen vertrauenswürdige DB-Engine bereitgestellt
4 Kommentare
Hacker-News-Kommentare
Vor gut 10 Jahren hielt der Maintainer von SQLite auf der OSCON einen Vortrag über Testpraktiken
Besonders beeindruckend war für mich die Stärke von Checklisten. Genau das Werkzeug, das Piloten vor jedem Flug verwenden
Er erwähnte auch einen Fall von Ärzte ohne Grenzen (Doctors Without Borders), bei dem die Ergebnisse von Operationen schlecht waren, weil das medizinische Personal einander nicht kannte und unterschiedliche Sprachen sprach
Die Lösung war einfach — vor der Operation wurde eine Checkliste eingeführt, bei der jede Person ihren Namen und ihre Rolle nennt. Dieses kleine Ritual erhöhte die Überlebensrate nicht durch Technik, sondern durch verbesserte Kommunikation
Weiterführendes Material: Beispiel einer SQLite-Checkliste
Es braucht mehr Diskussion darüber, was gute von schlechten Checklisten unterscheidet. Wie bei einer schönen Formel in der Mathematik wirkt es einfach, ist aber offenbar schwer zu finden
Besonders das Dokument FM22-100 der US Army habe ich mehrfach gelesen; es ist überraschend modern und inspirierend
FM22-100 ansehen
Buchlink
Ich folge zusätzlich zu Tests und CI auch einer Deployment-Checkliste in Markdown. Ich speichere die Ergebnisse nicht einmal, arbeite aber Schritt für Schritt danach
Ich verstehe nicht, warum andere so etwas Einfaches nicht machen
Falls es eine offizielle Seite zum MSF-Fall gibt, würde ich sie sehr gern sehen. Ich konnte sie per Google nicht finden
Hier sind frühere Diskussionen zu den Tests von SQLite gesammelt
Liste der HN-Threads von 2009 bis 2024
Es scheint, als würde die Wiederveröffentlichung im Abstand von einem Jahr immer wiederkehren
Ich beneide und bewundere den Prozess, mit dem Software wie SQLite bis zur Perfektion ausgearbeitet wird
Es ist ein Werk, in dem man wahre Handwerkskunst spürt
Mit der Zeit steigt der Qualitätsmaßstab, und mit demselben Aufwand bekommt man größere Belohnungen
Niemand hasst jemanden, der die Stellen, die er berührt hat, ein wenig sauberer hinterlässt
SQLite ist wirklich großartige Software. Auch die offizielle Website gefällt mir, weil sie informationsorientiert statt marketinggetrieben ist
Allerdings ist es interessant, dass in letzter Zeit auf HN die Seiten der offiziellen Website Stück für Stück auftauchen
Es wäre interessant, solche Links einmal zu sammeln
Ich finde es interessant, dass SQLite offene Software ist und dennoch nicht öffentliche Tests verwendet
Erst jetzt wird mir klar, dass ein Open-Source-Projekt geschlossene Tests haben kann
So ein Modell könnte zu einem neuen Geschäftsmodell ähnlich Open Core werden
Beispiel: railgunlabs/unicorn-Lizenz
Die 100% Branch Coverage von SQLite ist fast genauso beeindruckend wie das Projekt selbst
Vor allem, dass sie dauerhaft aufrechterhalten wird, ist außergewöhnlich
Ich finde es interessant, dass die Tests nicht öffentlich sind. In einer Zeit, in der LLM-basiertes Coding voranschreitet, kommen wir in eine Ära, in der Tests wichtiger als die Implementierung werden
Als ich kürzlich den Fall sah, in dem simonw die justHTML-Engine fast automatisch von Python nach JS umgewandelt hat, musste ich an die Teststrategie von SQLite denken
Ich habe kürzlich mit einem LLM über die Kompatibilität zwischen SQLite und DuckDB gesprochen und bin zu dem Schluss gekommen, dass SQLite beim Umgang mit Nebenläufigkeit besser ist
Ich war überrascht, dass es in der Testdokumentation von SQLite nur wenig Erwähnung von Performance-Regressionstests gibt
Korrektheit ist wichtig, aber Leistungseinbrüche auf bestimmten Query-Pfaden können fatal sein
Ich frage mich, ob es Projekte gibt, die dieses Ziel zu ihrem Kernauftrag machen
Angesichts der Stabilität von SQLite wollte ich mehr darüber wissen, wie Anomalie-Tests durchgeführt wurden
Im Artikel wurde das aber kaum erwähnt. Trotzdem ist SQLite eine der robustesten Softwares, die auf praktisch allen Geräten verwendet wird
Lesenswerter Begleitartikel: Die unbekannte Geschichte von SQLite
Dies ist ein zusammenfassender Beitrag zu einem Interview mit dem SQLite-Entwickler Richard Hipp.
Die SQLite-Entwickler lernten Do-178 kennen, als sie bei Rockwell Collins arbeiteten, und begannen, diesem Verfahren zu folgen. Dazu gehört unter anderem das Erreichen von 100 % MC/DC.
Do-178 ist wirklich ein nützlicher Leitfaden, daher kann ich jedem Entwickler nur empfehlen, ihn zu lesen.
Ist das hier? https://alm.parasoft.com/hubfs/…
Der von Ihnen verlinkte Inhalt scheint ein Schulungsmaterial zu DO-178 zu sein.
Das Originaldokument finden Sie unter diesem Link.
https://studylib.net/doc/27132454/rtca-do-178b