- SQLite, son derece kapsamlı bir otomatik test sistemi sayesinde yüksek güvenilirlik ve dayanıklılık sağlıyor; koddan 590 kat fazla test kodu bulunuyor
- Dört adet bağımsız test harness’i (TCL, TH3, SQL Logic Test, dbsqlfuzz) çekirdek kütüphaneyi doğruluyor ve yüz milyonlarca test çalıştırıyor
- Anormal durum testleri (OOM, I/O hataları, çökme simülasyonu) ve fuzz testing ile, olağandışı girdiler ve sistem arızaları altında da kararlı çalıştığı doğrulanıyor
- %100 branch ve MC/DC coverage, kaynak sızıntısı tespiti, Valgrind·statik analiz·checklist gibi çok katmanlı doğrulama süreçleri sürdürülüyor
- Bu sistematik test yaklaşımı sayesinde SQLite, ticari veritabanı düzeyinde güvenilirlik ve kaliteye sahip bir açık kaynak veritabanı olarak değerlendiriliyor
1. Genel bakış
- SQLite’ın güvenilirliği ve dayanıklılığı, ayrıntılı test süreçlerinden kaynaklanıyor
- Sürüm 3.42.0 itibarıyla SQLite, yaklaşık 155.8 KSLOC C kodu ve 92053.1 KSLOC test kodundan oluşuyor
- Test sistemi; 4 bağımsız harness, %100 branch coverage ve milyonlarca test vakasını içeriyor
- OOM, I/O hatası, çökme, fuzz, sınır değer, regresyon, bozuk DB dosyaları, optimizasyon devre dışı testleri gibi çok sayıda başlık dahil
2. Test harness’leri
- TCL Tests
- SQLite geliştirme sürecinde ağırlıklı olarak kullanılan, herkese açık test seti
- 27.2 KSLOC C kodu ve 1390 script dosyasından (23.2MB) oluşuyor
- Yaklaşık 50 bin test vakası içeriyor; parametreleştirme ile tam çalıştırmada yüz milyonlarca test yapılıyor
- TH3
- Ticari C tabanlı test seti; %100 branch ve MC/DC coverage sağlıyor
- Gömülü ortamlarda da çalışıyor; 1055.4 KSLOC ve yaklaşık 50 bin vaka içeriyor
- Tam coverage testinde yaklaşık 2.4 milyon, sürüm öncesinde ise 248 milyon soak test yürütülüyor
- SQL Logic Test (SLT)
- SQLite sonuçlarını PostgreSQL, MySQL, SQL Server ve Oracle 10g ile karşılaştırıyor
- 7.2 milyon sorgu ve 1.12GB veriden oluşuyor
- dbsqlfuzz
- SQL ile veritabanı dosyalarını aynı anda mutasyona uğratan libFuzzer tabanlı bir fuzzer
- Günde yaklaşık 1 milyar mutasyon testi çalıştırıyor; kötü niyetli girdilere karşı dayanıklılığı doğruluyor
- Ek araçlar
- speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz vb.
- Tüm testlerin çoklu platform ve derleme yapılandırmalarında geçmesi gerekiyor; ancak o zaman sürüm yayımlanabiliyor
3. Anormal durum testleri
- OOM testleri
malloc() başarısızlığı simüle edilerek, bellek yetersizliği durumunda düzgün toparlanıp toparlanmadığı doğrulanıyor
- Hata anı sayacı artırılarak test tekrar tekrar çalıştırılıyor
- I/O hata testleri
- Sanal dosya sistemi (VFS) kullanılarak disk hataları simüle ediliyor
- Hata sonrası
PRAGMA integrity_check ile veri bozulması olup olmadığı kontrol ediliyor
- Çökme testleri
- Güç kesintisi ve OS çökmesi senaryoları simüle ediliyor
- TCL harness’i child process tabanlı, TH3 ise bellek tabanlı VFS kullanıyor
- Transaction’ın ya tamamen rollback olması ya da tamamen tamamlanması gerektiği doğrulanıyor
- Birleşik hata testleri
- Çökme sonrasında OOM veya I/O hatalarının art arda yaşandığı senaryolar da test ediliyor
4. Fuzz testleri
- SQL Fuzz
- Sözdizimi açısından geçerli ama olağandışı SQL üreterek SQLite’ın tepkisi doğrulanıyor
- American Fuzzy Lop (AFL)
- 2014’te devreye alınan, profile tabanlı bir fuzzer; yeni kontrol yollarını keşfediyor
- SQLite’ta çok sayıda assert hatası, çökme ve yanlış sonuç buldu
- Google OSS Fuzz
- 2016’dan beri Google altyapısında otomatik fuzzing yürütüyor
- Yeni commit’lerde aralıklı ortaya çıkan sorunları tespit ediyor
- dbsqlfuzz / jfuzz
- 2018’den sonra kurum içi fuzzer olarak devreye alındı; SQL ve DB dosyalarını birlikte mutasyona uğratıyor
- Günde 500 milyondan fazla test yapılıyor; dış fuzzer’lardan gelen bug raporları neredeyse yok oldu
- 2024’ten itibaren jfuzz, JSONB girdileri için ek doğrulama yapıyor
- Üçüncü taraf fuzzer’lar ve fuzzcheck
- Harici araştırmacılar (ör. Manuel Rigger), çok sayıda yanlış sonuç hesaplama örneği buldu
- fuzzcheck yardımcı aracı, geçmiş fuzz vakaları arasındaki “ilginç” binlerce örneği yeniden doğruluyor
- MC/DC ile fuzz testleri arasındaki gerilim
- MC/DC, savunma kodunu en aza indirmeyi; fuzz ise savunma koduna ihtiyaç duyulmasını teşvik ediyor
- SQLite, bu iki yaklaşımı birlikte kullanarak hem normal hem kötü niyetli girdilere karşı dayanıklı kod sürdürüyor
5. Regresyon testleri
- Bildirilen her hata, düzeltildikten sonra mutlaka yeni bir test vakası olarak ekleniyor
- Amaç, geçmişteki hataların tekrar ortaya çıkmasını önlemek
6. Otomatik kaynak sızıntısı tespiti
- TCL ve TH3 harness’leri; bellek, dosya, thread ve mutex sızıntılarını otomatik olarak izliyor
- OOM ve I/O hatalarından sonra bile bellek sızıntısı olmamalı
7. Test coverage
- SQLite çekirdeği, TH3'e göre %100 branch coverage sağlıyor
- FTS3, RTree gibi eklentiler hariç
- Statement vs Branch Coverage
- Branch coverage, statement coverage’dan daha katıdır; tüm koşul dallarını iki yönde de doğrular
- Savunma kodu coverage
- ALWAYS(), NEVER() makrolarıyla savunma koşulları açıkça belirtiliyor
- Üç farklı tanım biçimiyle testler tekrarlanarak tutarlılık doğrulanıyor
- Sınır değer ve boolean vector testleri
testcase() makrosu ile koşulların hem doğru hem yanlış sonuçları doğrulanıyor
- 1184 adet
testcase() kullanılıyor
- MC/DC sağlanması
testcase() makrosu sayesinde tüm koşulların bağımsız etkisi doğrulanıyor
- gcov tabanlı ölçüm
- Coverage,
-fprofile-arcs -ftest-coverage seçenekleriyle ölçülüyor
- Sonuç karşılaştırmaları üzerinden compiler bug’ları veya tanımsız davranış tespit ediliyor
- Mutation Testing
- Branch komutları değiştirilerek testlerin bunu yakalayıp yakalamadığı kontrol ediliyor
- Optimizasyon branch’leri (
/*OPTIMIZATION-IF-TRUE*/) istisna olarak ele alınıyor
- Tam coverage deneyimi
- Tüm branch’lerin test edilmesi sayesinde, kod değişikliklerinde yan etki en aza indiriliyor
- Bakım maliyeti yüksek olsa da, geniş çapta dağıtılan bir altyapı kütüphanesi için bu yaklaşım haklı görülüyor
8. Dinamik analiz
- Assert()
- 6754 adet assert ifadesiyle ön/son koşullar ve döngü değişmezleri doğrulanıyor
- Yalnızca
SQLITE_DEBUG build’lerinde etkin
- Valgrind
- Bellek hataları, stack overflow ve ilklendirilmemiş bellek erişimi tespit ediliyor
- Sürüm öncesinde veryquick ve TH3 testleri Valgrind ile çalıştırılıyor
- Memsys2
SQLITE_MEMDEBUG build’inde, bellek hatalarını izlemek için wrapper ekleniyor
- Valgrind’e göre daha hızlı yinelenen doğrulama yapılabiliyor
- Mutex Asserts
sqlite3_mutex_held() vb. ile çoklu thread senkronizasyonu doğrulanıyor
- Journal Tests
- Rollback journal’ın DB’den önce yazılıp yazılmadığı kontrol edilerek transaction atomikliği güvence altına alınıyor
- Undefined Behavior Checks
-ftrapv, -fsanitize=undefined, /RTC1 vb. ile tanımsız davranış tespit ediliyor
- 32/64 bit, endian farkları ve çeşitli CPU mimarilerinde tekrar tekrar yürütülüyor
9. Optimizasyon devre dışı testleri
sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) ile optimizasyonlar kapatılıyor
- Optimizasyon açık ya da kapalıyken aynı sonuçların üretilmesi gerekiyor
- Bazı performans ölçüm testleri istisna
10. Checklist
- Sürüm öncesinde yaklaşık 200 maddelik manuel checklist doğrulanıyor
- Bazıları birkaç saniye, bazıları ise birkaç saat sürüyor
- Sorun bulunduğunda ilgili madde hemen ekleniyor; süreç sürekli iyileştiriliyor
11. Statik analiz
- GCC, Clang ve MSVC üzerinde uyarı olmadan derleniyor
- Clang Static Analyzer’da da geçerli uyarı yok
- Statik analizin gerçek hata bulma etkisi sınırlı kabul ediliyor
12. Özet
- SQLite, açık kaynak olmasına rağmen ticari düzeyde kalite ve düşük hata oranını koruyor
- Bunun temel nedeni, son derece titiz testler ve kod tasarımı
- Her sürüm, yukarıdaki süreçlerden geçirilerek mission-critical ortamlarda bile güvenilebilecek bir DB engine olarak sunuluyor
4 yorum
Birlikte okumaya değer yazı: SQLite'in bilinmeyen hikayesi
Bu, SQLite geliştiricisi Richard Hipp ile yapılan röportajı özetleyen bir yazıdır.
SQLite geliştiricilerinin, Rockwell Collins'te çalıştıkları dönemde Do-178 ile tanıştıkları ve bu prosedürü izlemeye başladıkları söyleniyor. Bunlardan biri de %100 MC/DC'ye ulaşmak.
Do-178 gerçekten çok kullanışlı bir kılavuzdur; bu yüzden geliştiriciyseniz herkesin okumasını tavsiye ederim.
Bu mu? https://alm.parasoft.com/hubfs/…
Paylaştığınız bağlantı sanırım bir DO-178 eğitim materyali.
Asıl belgeye şu bağlantıdan bakabilirsiniz.
https://studylib.net/doc/27132454/rtca-do-178b
Hacker News yorumları
Yaklaşık 10 yıl önce SQLite’ın bakımcısı OSCON’da test uygulamaları hakkında bir sunum yapmıştı
Özellikle etkileyici olan şey kontrol listesi (checklist) gücüydü. Pilotların her uçuş öncesi kullandığı aracın aynısı
Ayrıca Sınır Tanımayan Doktorlar (Doctors Without Borders) örneğini de vermişti; sağlık çalışanları birbirlerinin adını bilmiyor ve farklı diller konuşuyordu, bu yüzden ameliyat sonuçları düşüktü
Çözüm basitti — ameliyat öncesi bir kontrol listesi hazırlayıp herkesin adını ve rolünü söylemesini sağlamak. Bu küçük ritüelin, teknik değil iletişimi iyileştirerek hayatta kalma oranını artırdığı söylenmişti
İlgili kaynak: SQLite checklist örneği
İyi kontrol listesi ile kötü kontrol listesi arasındaki fark hakkında daha fazla tartışma gerek. Matematikteki güzel formüller gibi, basit görünüyor ama keşfetmesi zor
Özellikle ABD Ordusu’nun FM22-100 belgesini birkaç kez okudum; şaşırtıcı derecede modern ve ilham verici
FM22-100 belgesine bakın
Kitap bağlantısı
Testler ve CI dışında, Markdown biçiminde bir dağıtım kontrol listesi de takip ediyorum. Sonuçları kaydetmiyorum bile ama adımları tek tek uyguluyorum
İnsanların neden böyle basit bir şeyi yapmadığını anlamıyorum
MSF örneğini ele alan resmî bir sayfa varsa gerçekten görmek isterim. Google’da aradım ama bulamadım
SQLite’ın testleriyle ilgili eski tartışmaları burada toplamışlar
2009~2024 HN başlık listesi
Yeniden paylaşımın her yıl tekrarlandığı anlaşılıyor
SQLite gibi bir yazılımı bu kadar kusursuzca cilalama sürecini hem kıskanıyor hem hayranlıkla izliyorum
Gerçek bir zanaatkârlık hissi veriyor
Zamanla kalite standardınız yükselir ve aynı emekle daha büyük ödüller alırsınız
El attığı yeri biraz daha temiz bırakan birinden kimse nefret etmez
SQLite gerçekten harika bir yazılım. Resmî web sitesinin de pazarlama yerine bilgi odaklı olması hoşuma gidiyor
Yine de son dönemde HN’de resmî siteden sayfaların tek tek paylaşılması ilginç
Böyle bağlantıları bir yerde toplamak eğlenceli olabilir
SQLite’ın açık yazılım olmasına rağmen kapalı testler kullanması ilginç
Bir açık kaynak projenin kapalı testlere sahip olabileceğini ancak şimdi fark ettim
Bu model, open-core benzeri yeni bir iş modeli bile olabilir
Örnek: railgunlabs/unicorn lisansı
SQLite’ın %100 branch coverage değerine ulaşması, projenin kendisi kadar etkileyici
Bunu sürekli koruyabilmeleri özellikle olağanüstü
Testlerin kapalı olması ilginç. LLM tabanlı kodlamanın geliştiği bugünlerde, testlerin implementasyondan daha önemli hâle geldiği bir döneme giriyoruz
Kısa süre önce simonw’nin justHTML motorunu Python’dan JS’e neredeyse otomatik çevirdiği örneği görünce SQLite’ın test stratejisi aklıma geldi
Yakın zamanda SQLite ile DuckDB arasındaki uyumluluğu düşünerek bir LLM ile tartıştım; eşzamanlılık işleme açısından SQLite’ın daha iyi olduğu sonucuna vardım
SQLite’ın test dokümanında performance regression hakkında az şey söylenmesine şaşırdım
Doğruluk önemli, ama belirli sorgu yollarındaki performans düşüşleri de ölümcül olabilir
Acaba bunu temel misyonu olarak benimseyen bir proje var mı diye merak ediyorum
SQLite’ın kararlılığına bakınca anomali testlerinin nasıl yapıldığı hakkında daha fazla şey öğrenmek istedim
Ama yazıda buna neredeyse hiç değinilmemişti. Buna rağmen SQLite, her cihazda kullanılan en sağlam yazılımlardan biri olmaya devam ediyor