24 điểm bởi GN⁺ 2025-12-19 | 4 bình luận | Chia sẻ qua WhatsApp
  • SQLite duy trì độ tin cậy và độ bền vững rất cao nhờ hệ thống kiểm thử tự động cực kỳ chặt chẽ, với lượng mã kiểm thử nhiều gấp 590 lần mã nguồn
  • Bốn test harness độc lập (TCL, TH3, SQL Logic Test, dbsqlfuzz) xác minh thư viện cốt lõi, thực hiện hàng trăm triệu lượt kiểm thử
  • Thông qua kiểm thử tình huống bất thường (OOM, lỗi I/O, mô phỏng crash)fuzz testing, SQLite được xác nhận vẫn hoạt động ổn định ngay cả với đầu vào bất thường và sự cố hệ thống
  • SQLite duy trì quy trình xác minh nhiều lớp gồm 100% branch coverage và MC/DC, phát hiện rò rỉ tài nguyên, Valgrind, phân tích tĩnh và checklist
  • Nhờ hệ thống kiểm thử có tổ chức này, SQLite được đánh giá là cơ sở dữ liệu mã nguồn mở đạt độ tin cậy và chất lượng ở mức cơ sở dữ liệu thương mại

1. Tổng quan

  • Độ tin cậy và độ bền vững của SQLite bắt nguồn từ quy trình kiểm thử tỉ mỉ
    • Tính đến phiên bản 3.42.0, SQLite gồm khoảng 155.8 KSLOC mã C và 92053.1 KSLOC mã kiểm thử
  • Hệ thống kiểm thử bao gồm 4 harness độc lập, 100% branch coveragehàng triệu test case
    • Bao gồm nhiều hạng mục như OOM, lỗi I/O, crash, fuzz, giá trị biên, hồi quy, tệp DB bất thường, kiểm thử khi tắt tối ưu hóa, v.v.

2. Test harness

  • TCL Tests
    • Bộ kiểm thử công khai được sử dụng chủ yếu trong quá trình phát triển SQLite
    • Gồm 27.2 KSLOC mã C và 1390 tệp script (23.2MB)
    • Khoảng hơn 50 nghìn test case, khi chạy toàn bộ với tham số hóa sẽ thực hiện hàng triệu lượt kiểm thử
  • TH3
    • Bộ kiểm thử thương mại viết bằng C, đạt 100% branch coverage và MC/DC coverage
    • Hoạt động được cả trong môi trường nhúng, gồm 1055.4 KSLOC và khoảng hơn 50 nghìn case
    • Khi chạy kiểm thử coverage đầy đủ sẽ có khoảng 2.4 triệu lượt, và trước khi phát hành thực hiện 248 triệu lượt soak test
  • SQL Logic Test (SLT)
    • So sánh kết quả của SQLite với PostgreSQL, MySQL, SQL Server và Oracle 10g
    • Gồm 7.2 triệu truy vấn và 1.12GB dữ liệu
  • dbsqlfuzz
    • Fuzzer dựa trên libFuzzer có thể đồng thời biến đổi SQL và tệp cơ sở dữ liệu
    • Thực hiện khoảng 1 tỷ lượt kiểm thử đột biến mỗi ngày, xác minh độ bền vững trước đầu vào độc hại
  • Công cụ bổ sung
    • speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz, v.v.
    • Mọi bài kiểm thử đều phải vượt qua trên nhiều nền tảng và cấu hình biên dịch thì mới có thể phát hành

3. Kiểm thử tình huống bất thường

  • Kiểm thử OOM
    • Mô phỏng lỗi malloc() để xác minh khả năng phục hồi bình thường khi thiếu bộ nhớ
    • Lặp lại bài kiểm thử bằng cách tăng bộ đếm thời điểm thất bại
  • Kiểm thử lỗi I/O
    • Dùng virtual file system (VFS) để mô phỏng lỗi đĩa
    • Sau lỗi, dùng PRAGMA integrity_check để xác nhận có xảy ra hỏng dữ liệu hay không
  • Kiểm thử crash
    • Mô phỏng tình huống mất điện hoặc OS crash
    • TCL harness dùng tiến trình con, còn TH3 dùng VFS dựa trên bộ nhớ
    • Xác minh giao dịch либо được rollback hoàn toàn, либо được hoàn tất hoàn toàn
  • Kiểm thử lỗi kết hợp
    • Xác minh cả những tình huống mà sau crash lại tiếp tục xảy ra OOM hoặc lỗi I/O

4. Fuzz testing

  • SQL Fuzz
    • Tạo ra SQL hợp lệ về mặt cú pháp nhưng bất thường để kiểm tra phản ứng của SQLite
  • American Fuzzy Lop (AFL)
    • Fuzzer dựa trên profiling được đưa vào từ năm 2014 để khám phá các đường điều khiển mới
    • Đã phát hiện nhiều trường hợp assert fail, crash và kết quả sai trong SQLite
  • Google OSS Fuzz
    • Từ năm 2016, tự động fuzzing trên hạ tầng của Google
    • Phát hiện các vấn đề gián đoạn trên các commit mới
  • dbsqlfuzz / jfuzz
    • Được đưa vào làm fuzzer nội bộ từ sau năm 2018, biến đổi đồng thời SQL và tệp DB
    • Kiểm thử hơn 500 triệu lượt mỗi ngày, khiến báo cáo lỗi từ fuzzer bên ngoài gần như biến mất
    • Từ năm 2024, jfuzz bổ sung xác minh đầu vào JSONB
  • Fuzzer bên thứ ba và fuzzcheck
    • Các nhà nghiên cứu bên ngoài (ví dụ Manuel Rigger) đã phát hiện nhiều trường hợp tính toán kết quả sai
    • Tiện ích fuzzcheck tái xác minh hàng nghìn case “thú vị” từ các ca fuzz trước đây
  • Mối căng thẳng giữa MC/DC và fuzz testing
    • MC/DC khuyến khích tối thiểu hóa mã phòng vệ, còn fuzz thì cần mã phòng vệ
    • SQLite theo đuổi song song cả hai hướng để duy trì mã đủ bền vững với cả đầu vào bình thường lẫn độc hại

5. Kiểm thử hồi quy

  • Mọi lỗi đã được báo cáo sau khi sửa xong đều обязательно được thêm thành test case mới
    • Mục đích là ngăn lỗi cũ tái diễn

6. Tự động phát hiện rò rỉ tài nguyên

  • TCL và TH3 harness tự động giám sát rò rỉ bộ nhớ, tệp, luồng và mutex
    • Ngay cả sau OOM hay lỗi I/O cũng không được có rò rỉ bộ nhớ

7. Độ bao phủ kiểm thử

  • Phần lõi của SQLite đạt 100% branch coverage theo TH3
    • Không bao gồm các phần mở rộng như FTS3, RTree
  • Statement vs Branch Coverage
    • Branch coverage nghiêm ngặt hơn statement coverage, vì xác minh mọi nhánh điều kiện theo cả hai hướng
  • Độ bao phủ của mã phòng vệ
    • Dùng các macro ALWAYS(), NEVER() để biểu thị điều kiện phòng vệ
    • Lặp lại kiểm thử với ba kiểu định nghĩa khác nhau để xác minh tính nhất quán
  • Kiểm thử giá trị biên và vector boolean
    • Dùng macro testcase() để xác minh cả kết quả dương và âm của điều kiện
    • Có 1184 lần sử dụng testcase()
  • Đạt MC/DC
    • Thông qua macro testcase(), xác minh ảnh hưởng độc lập của mọi điều kiện
  • Đo lường dựa trên gcov
    • Đo coverage với tùy chọn -fprofile-arcs -ftest-coverage
    • So sánh kết quả để phát hiện lỗi compiler hoặc undefined behavior
  • Mutation Testing
    • Thay đổi lệnh rẽ nhánh để xem bài kiểm thử có phát hiện được hay không
    • Nhánh tối ưu hóa (/*OPTIMIZATION-IF-TRUE*/) được xử lý như ngoại lệ
  • Kinh nghiệm với độ bao phủ hoàn toàn
    • Nhờ kiểm thử mọi nhánh mà tác dụng phụ khi thay đổi mã được giảm thiểu
    • Chi phí bảo trì cao, nhưng là điều hợp lý đối với một thư viện hạ tầng được triển khai rộng khắp

8. Phân tích động

  • Assert()
    • 6754 câu lệnh assert dùng để xác minh tiền điều kiện, hậu điều kiện và bất biến vòng lặp
    • Chỉ được kích hoạt trong bản dựng SQLITE_DEBUG
  • Valgrind
    • Phát hiện lỗi bộ nhớ, stack overflow và truy cập bộ nhớ chưa được khởi tạo
    • Trước khi phát hành, chạy veryquick và TH3 test bằng Valgrind
  • Memsys2
    • Khi build với SQLITE_MEMDEBUG, sẽ chèn wrapper để giám sát lỗi bộ nhớ
    • Có thể kiểm tra lặp lại nhanh hơn Valgrind
  • Mutex Asserts
    • Xác minh đồng bộ hóa đa luồng bằng sqlite3_mutex_held() và các hàm tương tự
  • Journal Tests
    • Kiểm tra rollback journal có được ghi trước DB hay không để bảo đảm tính nguyên tử của giao dịch
  • Undefined Behavior Checks
    • Dùng -ftrapv, -fsanitize=undefined, /RTC1, v.v. để phát hiện undefined behavior
    • Lặp lại trên môi trường 32/64-bit, endian khác nhau và nhiều kiến trúc CPU

9. Kiểm thử khi tắt tối ưu hóa

  • Tắt tối ưu hóa bằng sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
    • Dù có hay không có tối ưu hóa cũng phải cho ra cùng một kết quả
    • Một số bài kiểm thử dùng để đo hiệu năng là ngoại lệ

10. Checklist

  • Trước khi phát hành, xác minh checklist thủ công khoảng 200 hạng mục
    • Có mục chỉ mất vài giây, có mục mất vài giờ
    • Khi phát hiện vấn đề sẽ lập tức thêm hạng mục mới để cải tiến liên tục

11. Phân tích tĩnh

  • Biên dịch không có cảnh báo trên GCC, Clang và MSVC
    • Cũng không có cảnh báo hợp lệ trong Clang Static Analyzer
    • Hiệu quả phát hiện lỗi thực tế của phân tích tĩnh là khá hạn chế

12. Tóm tắt

  • Dù là mã nguồn mở, SQLite vẫn duy trì chất lượng cấp thương mại và tỷ lệ lỗi thấp
    • Kiểm thử nghiêm ngặt và thiết kế mã là các yếu tố cốt lõi
    • Mọi bản phát hành đều đi qua các quy trình trên để cung cấp một DB engine đáng tin cậy ngay cả trong môi trường mission-critical

4 bình luận

 
regentag 2025-12-19

Bài nên đọc cùng: Câu chuyện ít người biết về SQLite

Đây là bài viết tóm tắt một cuộc phỏng vấn với Richard Hipp, nhà phát triển của SQLite.

Các nhà phát triển SQLite cho biết họ đã biết đến Do-178 trong thời gian làm việc với Rockwell Collins và bắt đầu tuân theo quy trình này. Một trong số đó là đạt 100% MC/DC.

Do-178 thực sự là một bộ hướng dẫn rất hữu ích, nên tôi khuyến nghị bất kỳ nhà phát triển nào cũng nên đọc.

 
roxie 2025-12-19

Cái này phải không? https://alm.parasoft.com/hubfs/…

 
regentag 2025-12-19

Có vẻ như thứ bạn đã liên kết là tài liệu đào tạo về DO-178.
Bạn có thể xem tài liệu gốc tại liên kết này.
https://studylib.net/doc/27132454/rtca-do-178b

 
GN⁺ 2025-12-19
Ý kiến trên Hacker News
  • Hơn 10 năm trước, người bảo trì SQLite đã có một bài nói chuyện tại OSCON về thực hành kiểm thử
    Điều đặc biệt gây ấn tượng là sức mạnh của checklist. Chính là công cụ mà phi công dùng trước mỗi chuyến bay
    Ông ấy cũng nhắc đến trường hợp của Bác sĩ Không Biên giới (Doctors Without Borders), nơi đội ngũ y tế không biết tên nhau và còn khác ngôn ngữ, nên kết quả phẫu thuật kém
    Giải pháp rất đơn giản — tạo một checklist trước phẫu thuật để mỗi người nói tên và vai trò của mình. Nghi thức nhỏ này đã nâng tỷ lệ sống sót nhờ cải thiện giao tiếp chứ không phải công nghệ
    Tài liệu liên quan: ví dụ checklist của SQLite

    • Ngược lại, tôi nghĩ kiểu câu chuyện này dễ sinh ra quan liêu không cần thiết. Checklist trong hàng không, MSF và SQLite thì rất tuyệt, nhưng phần lớn tổ chức chỉ lãng phí thời gian với các checklist vô dụng
      Cần có thêm thảo luận về sự khác biệt giữa checklist tốt và checklist tệ. Nó có vẻ đơn giản như một công thức đẹp trong toán học, nhưng lại rất khó tìm ra
    • Tôi luôn cảm thấy có rất nhiều điều để học từ vận hành hàng không và kỹ thuật. Tôi hình dung một tổ chức IT kết hợp các nguyên tắc này với phong cách lãnh đạo quân đội
      Đặc biệt, tôi đã đọc tài liệu FM22-100 của Lục quân Mỹ nhiều lần, và nó hiện đại cũng như truyền cảm hứng đến mức đáng ngạc nhiên
      Xem tài liệu FM22-100
    • Nếu muốn biết cách tạo checklist tốt, tôi cực kỳ khuyến nghị The Checklist Manifesto
      Liên kết sách
    • Tôi không hiểu vì sao phần lớn lập trình viên lại tránh né những việc đơn giản, không mang tính lập trình
      Ngoài test và CI, tôi còn làm theo một checklist phát hành viết bằng Markdown. Tôi thậm chí không lưu lại kết quả, chỉ thực hiện từng bước
      Tôi không hiểu vì sao người khác lại không làm một việc đơn giản như vậy
    • Thật thú vị khi một nghi thức lại có thể nâng cao hiệu quả. Dạo gần đây, ngay cả trong các cuộc họp, nếu làm vòng giới thiệu người tham gia thì mức độ tham gia cũng tăng lên rõ rệt
      Nếu có trang chính thức nào nói về trường hợp của MSF thì tôi rất muốn xem. Tôi tìm Google mà không thấy
  • Đây là bộ sưu tập các cuộc thảo luận trước đây về việc kiểm thử của SQLite
    Danh sách các thread HN từ 2009~2024
    Có vẻ bài này được đăng lại theo chu kỳ khoảng 1 năm

  • Tôi vừa ghen tị vừa kinh ngạc trước quá trình mài giũa phần mềm như SQLite đến mức hoàn hảo
    Đây là một tác phẩm toát lên tinh thần thủ công bậc thầy

    • Thật ra ai cũng có thể làm vậy. Chưa ai bị sa thải chỉ vì làm chậm mà chắc, làm cho đúng
      Theo thời gian, tiêu chuẩn chất lượng sẽ tăng lên, và với cùng một nỗ lực bạn sẽ nhận được phần thưởng lớn hơn
      Không ai ghét một người để lại phần mình chạm vào sạch sẽ hơn một chút
  • SQLite thực sự là phần mềm tuyệt vời. Tôi cũng thích việc website chính thức của nó tập trung vào thông tin thay vì marketing
    Tuy vậy, khá thú vị khi gần đây trên HN, các trang từ site chính thức cứ lần lượt được đưa lên

    • Có lẽ vì bài viết port LLM của simonw hôm qua gây chú ý nên các liên kết liên quan lại được quan tâm
    • Trên HN, chuyện này lặp lại theo chu kỳ. Trước đây là Haskell, còn dạo này Zig đang ở đúng vòng đó
      Nếu gom các liên kết kiểu này lại thì chắc sẽ khá vui
  • Điều thú vị là SQLite là phần mềm công khai nhưng lại dùng bộ kiểm thử không công khai
    Giờ tôi mới nhận ra rằng một dự án mã nguồn mở vẫn có thể có kiểm thử đóng
    Có cảm giác mô hình này có thể trở thành một mô hình kinh doanh mới tương tự open-core

    • Thực tế, nhiều khi test suite còn có giá trị hơn cả mã nguồn. Ví dụ, với phần mềm như Excel, việc tài liệu hóa vô số edge case còn khó hơn cả triển khai
    • Tôi cũng làm tương tự trong dự án của công ty. Cùng với giấy phép kép GPL, trình tạo test và dữ liệu chỉ được công khai cho người dùng giấy phép thương mại
      Ví dụ: giấy phép railgunlabs/unicorn
  • Độ bao phủ nhánh 100% của SQLite ấn tượng chẳng kém gì chính dự án này
    Đặc biệt là việc họ duy trì nó liên tục

  • Việc test không công khai thật đáng chú ý. Trong bối cảnh lập trình với LLM đang phát triển, chúng ta đang bước vào thời đại mà test quan trọng hơn phần triển khai
    Gần đây tôi thấy trường hợp simonw gần như tự động chuyển đổi engine justHTML từ Python sang JS, và điều đó làm tôi nhớ đến chiến lược kiểm thử của SQLite

    • Nếu nhìn từ góc độ mô hình kinh doanh của sản phẩm mã nguồn mở, một test suite khổng lồ là tài sản cốt lõi để thay đổi hiệu quả và tạo ra giá trị
    • Tài liệu How SQLite Is Tested của SQLite đúng nghĩa mang cảm giác như kinh thánh của kiểm thử
  • Gần đây tôi đã thảo luận với LLM về khả năng tương thích giữa SQLite và DuckDB, và đi đến kết luận rằng SQLite tốt hơn ở khía cạnh xử lý đồng thời

  • Tôi ngạc nhiên vì trong tài liệu kiểm thử của SQLite, phần nhắc đến kiểm thử hồi quy hiệu năng (performance regression) lại khá ít
    Tính đúng đắn là quan trọng, nhưng suy giảm hiệu năng trên một số đường truy vấn nhất định cũng có thể là chí mạng

    • Tôi từng làm trong lĩnh vực HFT, nhưng gần như chưa thấy dự án mã nguồn mở nào lấy đảm bảo hiệu năng làm điểm nhấn
      Tôi tò mò không biết có dự án nào xem mục tiêu này là sứ mệnh cốt lõi hay không
  • Nhìn vào độ ổn định của SQLite, tôi muốn biết thêm cách họ thực hiện kiểm thử bất thường (anomaly)
    Nhưng bài viết hầu như không đề cập đến. Dù vậy, SQLite vẫn là một trong những phần mềm vững chắc nhất được dùng trên mọi loại thiết bị

    • Quyền truy cập vào test suite có giá khoảng 150.000 USD mỗi năm, nên có lẽ họ sẽ khó công khai nội dung bên trong