Bagaimana SQLite Diuji
(sqlite.org)- SQLite mempertahankan keandalan dan ketangguhan yang tinggi melalui sistem pengujian otomatis yang sangat menyeluruh, dengan kode pengujian 590 kali lebih banyak daripada kode utamanya
- Empat harness pengujian independen (TCL, TH3, SQL Logic Test, dbsqlfuzz) memverifikasi pustaka inti, dengan ratusan juta pengujian dijalankan
- Melalui pengujian kondisi abnormal (OOM, error I/O, simulasi crash) dan fuzz testing, dipastikan tetap bekerja stabil terhadap input tidak normal dan kegagalan sistem
- Menjaga prosedur verifikasi berlapis seperti cakupan branch 100% dan MC/DC, deteksi kebocoran sumber daya, serta Valgrind, analisis statis, dan checklist
- Berkat pengujian sistematis ini, SQLite dinilai sebagai basis data open source dengan keandalan dan kualitas setara DB komersial
1. Gambaran umum
- Keandalan dan ketangguhan SQLite berasal dari proses pengujian yang sangat rinci
- Per versi 3.42.0, SQLite terdiri dari sekitar 155.8 KSLOC kode C dan 92053.1 KSLOC kode pengujian
- Sistem pengujiannya mencakup 4 harness independen, cakupan branch 100%, dan jutaan test case
- Termasuk OOM, error I/O, crash, fuzz, nilai batas, regresi, file DB abnormal, pengujian dengan optimisasi dinonaktifkan, dan banyak item lainnya
2. Harness pengujian
- TCL Tests
- Kumpulan pengujian publik yang terutama digunakan selama pengembangan SQLite
- Terdiri dari 27.2 KSLOC kode C dan 1390 file skrip (23.2MB)
- Sekitar 50 ribu test case, dan dengan parameterisasi total eksekusi mencapai jutaan pengujian
- TH3
- Kumpulan pengujian komersial berbasis C yang mencapai cakupan branch 100% dan MC/DC
- Dapat berjalan di lingkungan embedded, mencakup 1055.4 KSLOC dan sekitar 50 ribu case
- Untuk pengujian cakupan penuh, sekitar 2.4 juta pengujian dijalankan, dan sebelum rilis dilakukan 248 juta soak test
- SQL Logic Test (SLT)
- Membandingkan hasil SQLite dengan PostgreSQL, MySQL, SQL Server, dan Oracle 10g
- Terdiri dari 7.2 juta query dan 1.12GB data
- dbsqlfuzz
- Fuzzer berbasis libFuzzer yang memodifikasi SQL dan file basis data secara bersamaan
- Menjalankan sekitar 1 miliar uji mutasi per hari, memverifikasi ketangguhan terhadap input berbahaya
- Alat tambahan
- speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz, dan lainnya
- Semua pengujian harus lulus di berbagai platform dan konfigurasi kompilasi agar bisa dirilis
3. Pengujian kondisi abnormal
- Pengujian OOM
- Mensimulasikan kegagalan
malloc()untuk memverifikasi apakah pemulihan berjalan normal saat memori habis - Dilakukan berulang sambil menaikkan penghitung titik kegagalan
- Mensimulasikan kegagalan
- Pengujian error I/O
- Menggunakan virtual file system (VFS) untuk mensimulasikan error disk
- Setelah error, memeriksa kerusakan data dengan
PRAGMA integrity_check
- Pengujian crash
- Mensimulasikan kondisi listrik padam atau OS crash
- Harness TCL berbasis child process, sedangkan TH3 menggunakan VFS berbasis memori
- Memverifikasi bahwa transaksi sepenuhnya di-rollback atau sepenuhnya selesai
- Pengujian kegagalan gabungan
- Juga memverifikasi skenario ketika setelah crash terjadi OOM atau error I/O secara berurutan
4. Fuzz testing
- SQL Fuzz
- Menghasilkan SQL yang valid secara sintaks tetapi tidak normal untuk memverifikasi respons SQLite
- American Fuzzy Lop (AFL)
- Fuzzer berbasis profil yang diperkenalkan pada 2014 untuk menelusuri jalur kontrol baru
- Menemukan banyak assert failure, crash, dan hasil yang salah di SQLite
- Google OSS Fuzz
- Sejak 2016 menjalankan fuzzing otomatis di infrastruktur Google
- Mendeteksi masalah intermiten pada commit baru
- dbsqlfuzz / jfuzz
- Diperkenalkan sebagai fuzzer internal sejak 2018, memodifikasi SQL dan file DB secara bersamaan
- Menguji lebih dari 500 juta kali per hari, hingga laporan bug dari fuzzer eksternal hampir lenyap
- Sejak 2024, jfuzz menambahkan validasi input JSONB
- Fuzzer pihak ketiga dan fuzzcheck
- Peneliti eksternal (misalnya Manuel Rigger) menemukan banyak kasus perhitungan hasil yang salah
- Utilitas fuzzcheck memverifikasi ulang ribuan case “menarik” dari fuzz case sebelumnya
- Relasi tegang antara MC/DC dan fuzz testing
- MC/DC meminimalkan kode defensif, sedangkan fuzz membutuhkan kode defensif
- SQLite menjalankan kedua pendekatan ini secara bersamaan untuk menjaga kode yang tangguh terhadap input normal maupun berbahaya
5. Pengujian regresi
- Bug yang dilaporkan setelah diperbaiki wajib ditambahkan sebagai test case baru
- Tujuannya mencegah bug lama muncul kembali
6. Deteksi otomatis kebocoran sumber daya
- Harness TCL dan TH3 secara otomatis memantau kebocoran memori, file, thread, dan mutex
- Bahkan setelah OOM atau error I/O, tidak boleh ada kebocoran memori
7. Cakupan pengujian
- Core SQLite mencapai cakupan branch 100% menurut TH3
- Ekstensi seperti FTS3 dan RTree tidak termasuk
- Statement vs Branch Coverage
- Cakupan branch lebih ketat daripada statement coverage, karena memverifikasi semua percabangan kondisi ke dua arah
- Cakupan kode defensif
- Kondisi defensif dinyatakan dengan makro ALWAYS() dan NEVER()
- Pengujian diulang dengan tiga bentuk definisi untuk memverifikasi konsistensi
- Pengujian nilai batas dan vektor boolean
- Makro testcase() memverifikasi hasil positif maupun negatif dari kondisi
- Digunakan 1184 testcase()
- Pencapaian MC/DC
- Melalui makro testcase(), dampak independen dari setiap kondisi diverifikasi
- Pengukuran berbasis gcov
- Cakupan diukur dengan opsi
-fprofile-arcs -ftest-coverage - Perbandingan hasil digunakan untuk mendeteksi bug compiler atau undefined behavior
- Cakupan diukur dengan opsi
- Mutation Testing
- Mengubah instruksi branch untuk memastikan pengujian dapat mendeteksinya
- Branch optimisasi (
/*OPTIMIZATION-IF-TRUE*/) diperlakukan sebagai pengecualian
- Pengalaman cakupan penuh
- Berkat pengujian semua branch, efek samping saat kode diubah dapat diminimalkan
- Biaya pemeliharaannya tinggi, tetapi dapat dibenarkan untuk pustaka infrastruktur yang didistribusikan luas
8. Analisis dinamis
- Assert()
- Sebanyak 6754 pernyataan assert memverifikasi prakondisi, pascakondisi, dan invariant loop
- Hanya aktif pada build
SQLITE_DEBUG
- Valgrind
- Mendeteksi error memori, stack overflow, dan akses ke memori yang belum diinisialisasi
- Sebelum rilis, pengujian veryquick dan TH3 dijalankan dengan Valgrind
- Memsys2
- Pada build
SQLITE_MEMDEBUG, wrapper dimasukkan untuk memantau error memori - Memungkinkan verifikasi berulang lebih cepat daripada Valgrind
- Pada build
- Mutex Asserts
- Memverifikasi sinkronisasi multithread dengan
sqlite3_mutex_held()dan lainnya
- Memverifikasi sinkronisasi multithread dengan
- Journal Tests
- Memastikan rollback journal ditulis lebih dulu daripada DB, menjamin atomicity transaksi
- Undefined Behavior Checks
- Mendeteksi undefined behavior dengan
-ftrapv,-fsanitize=undefined,/RTC1, dan lainnya - Dilakukan berulang di 32/64-bit, endian berbeda, dan berbagai arsitektur CPU
- Mendeteksi undefined behavior dengan
9. Pengujian dengan optimisasi dinonaktifkan
- Menonaktifkan optimisasi dengan
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)- Hasil yang dihasilkan harus sama terlepas dari ada atau tidaknya optimisasi
- Beberapa pengujian untuk pengukuran performa menjadi pengecualian
10. Checklist
- Sebelum rilis, diverifikasi checklist manual berisi sekitar 200 item
- Sebagian memerlukan beberapa detik, sebagian lain beberapa jam
- Jika ditemukan masalah, item langsung ditambahkan untuk perbaikan berkelanjutan
11. Analisis statis
- Dikompilasi di GCC, Clang, dan MSVC tanpa warning
- Juga tidak ada warning valid dari Clang Static Analyzer
- Efektivitas analisis statis untuk menemukan bug nyata terbatas
12. Ringkasan
- Meski open source, SQLite mempertahankan kualitas setingkat komersial dan tingkat cacat yang rendah
- Faktor utamanya adalah pengujian yang sangat ketat dan desain kode
- Setiap rilis melalui prosedur di atas dan disajikan sebagai engine DB yang dapat dipercaya bahkan di lingkungan mission-critical
4 komentar
Komentar Hacker News
Sekitar 10 tahun lalu, maintainer SQLite pernah memberikan presentasi di OSCON tentang praktik pengujian
Hal yang paling mengesankan adalah kekuatan checklist. Alat yang sama persis dipakai pilot sebelum penerbangan
Ia juga menyebut kasus Doctors Without Borders (Médecins Sans Frontières), di mana hasil operasi rendah karena tenaga medis tidak saling tahu nama dan berbicara dalam bahasa yang berbeda
Solusinya sederhana — membuat checklist praoperasi dan meminta setiap orang menyebutkan nama serta perannya. Ritual kecil ini meningkatkan tingkat kelangsungan hidup lewat perbaikan komunikasi, bukan teknologi
Referensi terkait: contoh checklist SQLite
Perlu ada lebih banyak diskusi tentang perbedaan checklist yang baik dan yang buruk. Rasanya seperti rumus matematika yang indah: tampak sederhana, tetapi sulit ditemukan
Khususnya, saya sudah membaca dokumen FM22-100 milik Angkatan Darat AS beberapa kali, dan isinya terasa sangat modern sekaligus menginspirasi
Lihat dokumen FM22-100
Tautan buku
Selain test dan CI, saya juga mengikuti checklist deployment dalam Markdown. Saya bahkan tidak menyimpan hasilnya, tetapi tetap menjalankannya langkah demi langkah
Saya tidak paham kenapa orang lain tidak melakukan hal sesederhana ini
Kalau ada halaman resmi yang membahas kasus MSF ini, saya benar-benar ingin melihatnya. Saya belum menemukannya lewat Google
Kumpulan diskusi lama tentang pengujian SQLite
Daftar thread HN 2009~2024
Sepertinya repost berulang setiap selang satu tahun
Saya iri sekaligus kagum pada proses memoles perangkat lunak seperti SQLite hingga sesempurna itu
Ini terasa seperti karya dengan jiwa craftsmanship
Seiring waktu, standar kualitas akan naik, dan dengan usaha yang sama kita akan mendapat imbalan yang lebih besar
Tidak ada orang yang membenci seseorang yang meninggalkan bagian yang disentuhnya sedikit lebih bersih
SQLite benar-benar perangkat lunak yang luar biasa. Situs resminya juga bagus karena berfokus pada informasi, bukan pemasaran
Namun menarik melihat halaman-halaman dari situs resmi itu satu per satu muncul di HN belakangan ini
Akan menarik kalau ada yang mengumpulkan tautan-tautan seperti ini
Menarik bahwa SQLite adalah perangkat lunak terbuka tetapi menggunakan pengujian tertutup
Baru sekarang saya sadar proyek open source bisa saja memiliki pengujian yang tertutup
Model seperti ini mungkin bisa menjadi model bisnis baru yang mirip open-core
Contoh: lisensi railgunlabs/unicorn
100% branch coverage SQLite sama mengesankannya dengan proyek itu sendiri
Terutama fakta bahwa mereka terus menjaganya dari waktu ke waktu
Menarik bahwa test-nya tertutup. Di saat coding berbasis LLM makin maju, kita memasuki era ketika test menjadi lebih penting daripada implementasi
Baru-baru ini saya melihat contoh simonw yang hampir otomatis mengonversi engine justHTML dari Python ke JS, dan itu membuat saya teringat pada strategi pengujian SQLite
Baru-baru ini saya berdiskusi dengan LLM sambil mempertimbangkan kompatibilitas antara SQLite dan DuckDB, dan sampai pada kesimpulan bahwa SQLite lebih baik dari sisi penanganan konkurensi
Saya agak terkejut karena dalam dokumen pengujian SQLite hanya sedikit disebutkan soal performance regression test
Akurasi memang penting, tetapi penurunan performa pada jalur query tertentu bisa sangat fatal
Saya jadi penasaran apakah ada proyek yang menjadikan tujuan itu sebagai misi utamanya
Melihat kestabilan SQLite, saya ingin tahu lebih banyak bagaimana pengujian anomali dilakukan
Namun di tulisan itu nyaris tidak dibahas. Meski begitu, SQLite tetap menjadi salah satu perangkat lunak paling tangguh yang digunakan di semua perangkat
Artikel terkait yang menarik: Kisah SQLite yang Tidak Diketahui
Ini adalah tulisan yang merangkum wawancara dengan pengembang SQLite, Richard Hipp.
Para pengembang SQLite mengetahui Do-178 saat bekerja dengan Rockwell Collins, dan sejak itu mulai mengikuti prosedur tersebut. Salah satunya adalah mencapai 100% MC/DC.
Do-178 benar-benar merupakan panduan yang sangat berguna, jadi saya merekomendasikan agar setiap pengembang membacanya.
Apakah ini? https://alm.parasoft.com/hubfs/…
Sepertinya yang Anda tautkan adalah materi pelatihan Do-178.
Dokumen aslinya bisa Anda lihat di tautan ini.
https://studylib.net/doc/27132454/rtca-do-178b