24 คะแนน โดย GN⁺ 2025-12-19 | 4 ความคิดเห็น | แชร์ทาง WhatsApp
  • SQLite รักษาความน่าเชื่อถือและความทนทานในระดับสูงด้วย ระบบทดสอบอัตโนมัติที่เข้มงวด โดยมี โค้ดทดสอบมากกว่าโค้ดจริง 590 เท่า
  • มี ชุดทดสอบอิสระ (test harness) 4 แบบ ได้แก่ TCL, TH3, SQL Logic Test และ dbsqlfuzz ที่ใช้ตรวจสอบไลบรารีแกนหลัก พร้อมรัน การทดสอบหลายร้อยล้านครั้ง
  • ใช้ การทดสอบสถานการณ์ผิดปกติ (OOM, ข้อผิดพลาด I/O, การจำลองแครช) และ fuzz testing เพื่อตรวจสอบว่ายังทำงานได้เสถียรแม้เจออินพุตผิดปกติหรือระบบขัดข้อง
  • คงไว้ซึ่งกระบวนการตรวจสอบหลายชั้น เช่น branch coverage และ MC/DC 100%, การตรวจจับ resource leak, Valgrind, static analysis และ checklist
  • ด้วยระบบทดสอบที่เป็นระบบเช่นนี้ SQLite จึงได้รับการประเมินว่าเป็นฐานข้อมูลโอเพนซอร์สที่มี ความน่าเชื่อถือและคุณภาพในระดับฐานข้อมูลเชิงพาณิชย์

1. ภาพรวม

  • ความน่าเชื่อถือและความทนทาน ของ SQLite มาจากกระบวนการทดสอบที่ละเอียดถี่ถ้วน
    • ณ เวอร์ชัน 3.42.0 SQLite ประกอบด้วยโค้ด C ประมาณ 155.8 KSLOC และโค้ดทดสอบ 92053.1 KSLOC
  • ระบบทดสอบประกอบด้วย harness อิสระ 4 ชุด, branch coverage 100% และ กรณีทดสอบหลายล้านรายการ
    • ครอบคลุมหัวข้อต่าง ๆ เช่น OOM, ข้อผิดพลาด I/O, การแครช, fuzz, ค่าขอบเขต, regression, ไฟล์ DB ที่ผิดปกติ, การทดสอบแบบปิด optimization เป็นต้น

2. Test Harness

  • TCL Tests
    • เป็นชุดทดสอบสาธารณะที่ใช้หลัก ๆ ระหว่างการพัฒนา SQLite
    • ประกอบด้วยโค้ด C 27.2 KSLOC และไฟล์สคริปต์ 1,390 ไฟล์ (23.2MB)
    • มี กรณีทดสอบมากกว่า 50,000 รายการ และเมื่อรันทั้งหมดแบบ parameterized จะมีการทดสอบหลายล้านครั้ง
  • TH3
    • เป็นชุดทดสอบเชิงพาณิชย์ที่พัฒนาด้วย C และทำให้บรรลุ branch coverage และ MC/DC 100%
    • ทำงานได้แม้ในสภาพแวดล้อมแบบ embedded และมี 1055.4 KSLOC พร้อมเคสมากกว่า 50,000 รายการ
    • เมื่อรันการทดสอบ coverage แบบเต็มจะมีประมาณ 2.4 ล้านครั้ง และก่อนออกรีลีสจะทำ soak test 248 ล้านครั้ง
  • SQL Logic Test (SLT)
    • เปรียบเทียบผลลัพธ์ของ SQLite กับ PostgreSQL, MySQL, SQL Server และ Oracle 10g
    • ประกอบด้วย 7.2 ล้านคิวรี และข้อมูลขนาด 1.12GB
  • dbsqlfuzz
    • เป็น fuzzer ที่ใช้ libFuzzer ซึ่งกลายพันธุ์ทั้ง SQL และไฟล์ฐานข้อมูลพร้อมกัน
    • รัน การทดสอบกลายพันธุ์ราว 1 พันล้านครั้งต่อวัน เพื่อตรวจสอบความทนทานต่ออินพุตที่เป็นอันตราย
  • เครื่องมือเพิ่มเติม
    • speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz เป็นต้น
    • ทุกการทดสอบต้องผ่านบน หลายแพลตฟอร์มและหลายการตั้งค่าคอมไพล์ จึงจะออกรีลีสได้

3. การทดสอบสถานการณ์ผิดปกติ

  • การทดสอบ OOM
    • จำลองการล้มเหลวของ malloc() เพื่อตรวจสอบว่าสามารถกู้คืนได้ถูกต้องเมื่อหน่วยความจำไม่พอ
    • รันซ้ำโดยเพิ่มตัวนับตำแหน่งที่ทำให้ล้มเหลวไปเรื่อย ๆ
  • การทดสอบข้อผิดพลาด I/O
    • ใช้ virtual file system (VFS) เพื่อจำลองข้อผิดพลาดของดิสก์
    • หลังเกิดข้อผิดพลาดจะใช้ PRAGMA integrity_check ตรวจสอบว่าข้อมูลเสียหายหรือไม่
  • การทดสอบการแครช
    • จำลองสถานการณ์ไฟดับหรือ OS แครช
    • TCL harness ใช้ child process เป็นฐาน ส่วน TH3 ใช้ VFS แบบอิงหน่วยความจำ
    • ตรวจสอบว่าธุรกรรมถูก rollback ทั้งหมดหรือเสร็จสมบูรณ์ทั้งหมด
  • การทดสอบความล้มเหลวแบบผสม
    • ตรวจสอบไปถึงกรณีที่หลังแครชแล้วเกิด OOM หรือข้อผิดพลาด I/O ต่อเนื่องกัน

4. Fuzz Testing

  • SQL Fuzz
    • สร้าง SQL ที่ถูกต้องตามไวยากรณ์แต่ผิดปกติ เพื่อตรวจสอบการตอบสนองของ SQLite
  • American Fuzzy Lop (AFL)
    • เป็น fuzzer แบบอาศัยโปรไฟล์ที่นำมาใช้ในปี 2014 เพื่อสำรวจเส้นทางควบคุมใหม่ ๆ
    • พบ assert failure, การแครช และผลลัพธ์ที่ผิดพลาดของ SQLite ได้จำนวนมาก
  • Google OSS Fuzz
    • ตั้งแต่ปี 2016 มีการทำ fuzzing อัตโนมัติบนโครงสร้างพื้นฐานของ Google
    • ใช้ตรวจจับปัญหาที่เกิดเป็นครั้งคราวใน commit ใหม่
  • dbsqlfuzz / jfuzz
    • ถูกนำมาใช้เป็น fuzzer ภายในตั้งแต่ปี 2018 โดยกลายพันธุ์ทั้ง SQL และไฟล์ DB พร้อมกัน
    • ทดสอบมากกว่า 500 ล้านครั้งต่อวัน จนรายงานบั๊กจาก fuzzer ภายนอกแทบหายไป
    • ตั้งแต่ปี 2024 เป็นต้นมา jfuzz ได้เพิ่มการตรวจสอบอินพุต JSONB
  • fuzzer ของบุคคลที่สามและ fuzzcheck
    • นักวิจัยภายนอก (เช่น Manuel Rigger) พบกรณีการคำนวณผลลัพธ์ผิดจำนวนมาก
    • ยูทิลิตี fuzzcheck ใช้ตรวจสอบซ้ำเคส fuzz ในอดีตที่ “น่าสนใจ” หลายพันกรณี
  • ความตึงเครียดระหว่าง MC/DC กับ fuzz testing
    • MC/DC มุ่งลดโค้ดเชิงป้องกันให้น้อยที่สุด ขณะที่ fuzz ต้องการโค้ดเชิงป้องกัน
    • SQLite ใช้ทั้งสองแนวทางควบคู่กันเพื่อคงไว้ซึ่ง โค้ดที่ทนทานทั้งต่ออินพุตปกติและอินพุตประสงค์ร้าย

5. Regression Testing

  • บั๊กที่มีการรายงานเข้ามา เมื่อแก้แล้วจะต้องเพิ่มเป็น กรณีทดสอบใหม่ เสมอ
    • เพื่อป้องกันไม่ให้บั๊กเดิมกลับมาอีก

6. การตรวจจับ Resource Leak อัตโนมัติ

  • harness ของ TCL และ TH3 เฝ้าตรวจ memory leak, file leak, thread leak และ mutex leak แบบอัตโนมัติ
    • แม้หลัง OOM หรือข้อผิดพลาด I/O ก็ต้องไม่มี memory leak

7. Test Coverage

  • SQLite core บรรลุ branch coverage 100% ตามเกณฑ์ของ TH3
    • ไม่รวมส่วนขยายอย่าง FTS3 และ RTree
  • Statement vs Branch Coverage
    • branch coverage เข้มงวดกว่า statement coverage และตรวจสอบทุกเงื่อนไขแตกแขนงทั้งสองทาง
  • การครอบคลุมโค้ดเชิงป้องกัน
    • ใช้แมโคร ALWAYS() และ NEVER() เพื่อระบุเงื่อนไขเชิงป้องกันอย่างชัดเจน
    • ทดสอบซ้ำด้วยนิยาม 3 รูปแบบเพื่อยืนยันความสอดคล้อง
  • การทดสอบค่าขอบเขตและ boolean vector
    • ใช้แมโคร testcase() เพื่อตรวจสอบทั้งผลลัพธ์จริงและเท็จของเงื่อนไข
    • มีการใช้ testcase() จำนวน 1184 จุด
  • การบรรลุ MC/DC
    • ใช้แมโคร testcase() เพื่อตรวจสอบผลกระทบอย่างเป็นอิสระของทุกเงื่อนไข
  • การวัดผลด้วย gcov
    • วัด coverage ด้วยออปชัน -fprofile-arcs -ftest-coverage
    • ใช้การเปรียบเทียบผลลัพธ์เพื่อตรวจจับ compiler bug หรือ undefined behavior
  • Mutation Testing
    • เปลี่ยนคำสั่ง branch เพื่อดูว่าชุดทดสอบสามารถตรวจจับได้หรือไม่
    • branch สำหรับ optimization (/*OPTIMIZATION-IF-TRUE*/) ถูกจัดเป็นข้อยกเว้น
  • ประสบการณ์จากการมี coverage ครบถ้วน
    • การทดสอบทุก branch ช่วยลดผลข้างเคียงเมื่อมีการแก้โค้ด
    • แม้ต้นทุนการดูแลสูง แต่ถือว่าสมเหตุสมผลสำหรับไลบรารีโครงสร้างพื้นฐานที่ถูกใช้งานอย่างกว้างขวาง

8. Dynamic Analysis

  • Assert()
    • มีคำสั่ง assert 6754 จุดสำหรับตรวจสอบ precondition, postcondition และ loop invariant
    • เปิดใช้งานเฉพาะในบิลด์ SQLITE_DEBUG
  • Valgrind
    • ตรวจจับข้อผิดพลาดหน่วยความจำ, stack overflow และการเข้าถึงหน่วยความจำที่ยังไม่ได้กำหนดค่าเริ่มต้น
    • ก่อนออกรีลีสจะรัน veryquick และ TH3 tests ผ่าน Valgrind
  • Memsys2
    • ในบิลด์ SQLITE_MEMDEBUG จะใส่ wrapper สำหรับเฝ้าระวังข้อผิดพลาดหน่วยความจำ
    • สามารถตรวจสอบซ้ำได้เร็วกว่า Valgrind
  • Mutex Asserts
    • ใช้ sqlite3_mutex_held() เป็นต้น เพื่อตรวจสอบการซิงโครไนซ์ในงานหลายเธรด
  • Journal Tests
    • ตรวจสอบว่า rollback journal ถูกเขียนก่อน DB เพื่อรับประกัน atomicity ของธุรกรรม
  • Undefined Behavior Checks
    • ใช้ -ftrapv, -fsanitize=undefined, /RTC1 เป็นต้น เพื่อตรวจจับ undefined behavior
    • รันซ้ำบน 32/64 บิต, endian ที่ต่างกัน และ CPU architecture หลายแบบ

9. การทดสอบแบบปิด Optimization

  • ใช้ sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) เพื่อปิด optimization
    • ไม่ว่าจะเปิดหรือปิด optimization ก็ต้องให้ผลลัพธ์เหมือนกัน
    • ยกเว้นการทดสอบบางรายการที่ใช้วัดประสิทธิภาพ

10. Checklist

  • ก่อนออกรีลีสจะตรวจสอบ checklist แบบ manual ราว 200 รายการ
    • บางข้อใช้เวลาไม่กี่วินาที บางข้อใช้เวลาหลายชั่วโมง
    • หากพบปัญหาจะเพิ่มรายการทันทีและปรับปรุงอย่างต่อเนื่อง

11. Static Analysis

  • คอมไพล์ผ่านโดย ไม่มี warning บน GCC, Clang และ MSVC
    • และไม่มี warning ที่มีนัยสำคัญจาก Clang Static Analyzer
    • static analysis มีประสิทธิภาพจำกัดในการค้นหาบั๊กจริง

12. สรุป

  • แม้ SQLite จะเป็นโอเพนซอร์ส แต่ก็ยังคงไว้ซึ่ง คุณภาพระดับเชิงพาณิชย์และอัตราข้อบกพร่องต่ำ
    • การทดสอบที่เข้มงวดและการออกแบบโค้ดคือปัจจัยสำคัญ
    • ทุกรีลีสผ่านกระบวนการข้างต้น จึงถูกส่งมอบในฐานะ DB engine ที่เชื่อถือได้แม้ในสภาพแวดล้อม mission-critical

4 ความคิดเห็น

 
regentag 2025-12-19

บทความที่น่าอ่านร่วมกัน: เรื่องราวที่ไม่ค่อยมีใครรู้ของ SQLite

นี่คือบทความสรุปบทสัมภาษณ์ของ Richard Hipp ผู้พัฒนา SQLite

ผู้พัฒนา SQLite บอกว่าได้รู้จัก Do-178 ระหว่างที่ทำงานกับ Rockwell Collins และเริ่มปฏิบัติตามกระบวนการนี้ หนึ่งในนั้นคือการบรรลุ MC/DC ให้ได้ 100%

Do-178 เป็นแนวทางที่ใช้งานได้ดีมาก จึงอยากแนะนำให้นักพัฒนาทุกคนลองอ่านดู

 
roxie 2025-12-19

อันนี้หรือเปล่า? https://alm.parasoft.com/hubfs/…

 
regentag 2025-12-19

ลิงก์ที่คุณแชร์น่าจะเป็นเอกสารการอบรม Do-178 ครับ
เอกสารต้นฉบับดูได้ที่ลิงก์นี้ครับ
https://studylib.net/doc/27132454/rtca-do-178b

 
GN⁺ 2025-12-19
ความเห็นบน Hacker News
  • เมื่อราว 10 กว่าปีก่อน ผู้ดูแล SQLite เคยพูดที่ OSCON เกี่ยวกับ แนวปฏิบัติด้านการทดสอบ
    สิ่งที่น่าประทับใจเป็นพิเศษคือพลังของ เช็กลิสต์ (checklist) ซึ่งก็คือเครื่องมือแบบเดียวกับที่นักบินใช้ก่อนขึ้นบินทุกครั้ง
    เขายังพูดถึงกรณีของ Doctors Without Borders ด้วย โดยบอกว่าบุคลากรทางการแพทย์ไม่รู้จักชื่อกันและพูดกันคนละภาษา ทำให้ผลลัพธ์ของการผ่าตัดไม่ดีนัก
    วิธีแก้นั้นง่ายมาก — สร้างเช็กลิสต์ก่อนผ่าตัดให้แต่ละคนพูดชื่อและบทบาทของตัวเอง พิธีกรรมเล็ก ๆ นี้ช่วยเพิ่มอัตราการรอดชีวิตผ่านการ ปรับปรุงการสื่อสาร ไม่ใช่เทคโนโลยี
    เนื้อหาที่เกี่ยวข้อง: ตัวอย่างเช็กลิสต์ของ SQLite

    • แต่อีกด้านหนึ่งก็คิดว่าเรื่องแบบนี้อาจก่อให้เกิด ระบบราชการที่ไม่จำเป็น ได้ เช็กลิสต์ของวงการการบิน, MSF และ SQLite นั้นยอดเยี่ยม แต่หลายองค์กรกลับเสียเวลากับเช็กลิสต์ที่ไร้ประโยชน์
      น่าจะต้องมีการถกกันมากกว่านี้เรื่องความต่างระหว่างเช็กลิสต์ที่ดีกับเช็กลิสต์ที่แย่ มันดูเรียบง่ายเหมือน สูตรคณิตศาสตร์ที่งดงาม แต่กลับค้นพบได้ยาก
    • รู้สึกมาโดยตลอดว่ามีเรื่องให้เรียนรู้จากการปฏิบัติการด้านการบินและวิศวกรรมมากมาย ลองจินตนาการถึงองค์กรไอทีที่นำหลักการเหล่านี้ไปผสานกับ ภาวะผู้นำแบบทหาร
      โดยเฉพาะเอกสาร FM22-100 ของกองทัพบกสหรัฐฯ ที่อ่านมาหลายครั้งแล้ว ซึ่งทันสมัยและสร้างแรงบันดาลใจอย่างน่าประหลาด
      ดูเอกสาร FM22-100
    • ถ้าอยากรู้วิธีสร้างเช็กลิสต์ที่ดี ขอแนะนำ The Checklist Manifesto อย่างมาก
      ลิงก์หนังสือ
    • ไม่เข้าใจว่าทำไมนักพัฒนาส่วนใหญ่ถึงพยายามหลีกเลี่ยง งานง่าย ๆ ที่ไม่ใช่การเขียนโปรแกรม
      นอกจากการทดสอบและ CI แล้ว ฉันยังทำตาม เช็กลิสต์การ deploy ที่เขียนเป็น Markdown ด้วย แม้จะไม่ได้เก็บผลลัพธ์ไว้ แต่ก็ทำตามทีละขั้น
      ไม่เข้าใจว่าทำไมคนอื่นถึงไม่ทำเรื่องง่าย ๆ แบบนี้
    • น่าสนใจที่พิธีกรรมช่วยยกระดับผลลัพธ์ได้ ทุกวันนี้แค่ให้มีรอบแนะนำตัวผู้เข้าร่วมในประชุม ระดับการมีส่วนร่วมก็เพิ่มขึ้นอย่างชัดเจน
      ถ้ามีหน้าอย่างเป็นทางการที่พูดถึงกรณีของ MSF ก็อยากอ่านมาก หาใน Google แล้วไม่เจอ
  • รวบรวมการพูดคุยในอดีตเกี่ยวกับการทดสอบของ SQLite ไว้
    รายชื่อเธรด HN ปี 2009~2024
    ดูเหมือนการรีโพสต์จะวนกลับมาทุก ๆ 1 ปี

  • อิจฉาและทึ่งกับกระบวนการขัดเกลาซอฟต์แวร์อย่าง SQLite ให้สมบูรณ์แบบขนาดนี้
    เป็นงานที่ให้ความรู้สึกถึงความเป็นช่างฝีมือ

    • จริง ๆ แล้วใครก็ทำแบบนั้นได้ ไม่เคยมีใครถูกไล่ออกเพราะทำของให้ ช้าแต่ถูกต้อง
      เมื่อเวลาผ่านไป มาตรฐานคุณภาพจะสูงขึ้น และคุณก็จะได้ผลตอบแทนที่มากขึ้นจากความพยายามเท่าเดิม
      ไม่มีใครเกลียดคนที่ทิ้งส่วนที่ตัวเองแตะต้องไว้ให้สะอาดขึ้นอีกนิด
  • SQLite เป็นซอฟต์แวร์ที่ยอดเยี่ยมจริง ๆ เว็บไซต์ทางการก็ดีตรงที่ เน้นข้อมูลมากกว่าการตลาด
    แต่ก็แปลกดีที่ช่วงหลัง ๆ มีหน้าในเว็บทางการถูกโพสต์ขึ้น HN ทีละหน้า

    • น่าจะเป็นเพราะเมื่อวาน บทความพอร์ต LLM ของ simonw กลายเป็นประเด็น เลยทำให้ลิงก์ที่เกี่ยวข้องกลับมาได้รับความสนใจอีกครั้ง
    • ใน HN เรื่องแบบนี้เกิดซ้ำเป็นระยะ ๆ เมื่อก่อนเป็น Haskell ส่วนช่วงนี้ดูเหมือน Zig กำลังอยู่ในรอบนั้น
      ถ้ารวบรวมลิงก์พวกนี้ไว้ก็น่าจะสนุกดี
  • น่าสนใจที่ SQLite เป็น ซอฟต์แวร์เปิดเผยต่อสาธารณะ แต่กลับใช้ การทดสอบแบบปิด
    เพิ่งตระหนักได้ว่าโปรเจกต์โอเพนซอร์สก็สามารถมีการทดสอบแบบปิดได้
    โมเดลแบบนี้อาจกลายเป็นโมเดลธุรกิจใหม่ที่คล้าย open-core ก็ได้

    • ในความเป็นจริง test suite มักมีค่ามากกว่าตัวโค้ด เสียอีก เช่น การบันทึก edge case นับไม่ถ้วนของซอฟต์แวร์อย่าง Excel นั้นยากกว่าการลงมือ implement เสียอีก
    • ฉันก็ทำคล้ายกันในโปรเจกต์ของบริษัท โดยใช้ dual license แบบ GPL และเปิดเผย ตัวสร้างการทดสอบและข้อมูล เฉพาะผู้ใช้ที่มีไลเซนส์เชิงพาณิชย์เท่านั้น
      ตัวอย่าง: ไลเซนส์ของ railgunlabs/unicorn
  • Branch coverage 100% ของ SQLite น่าประทับใจพอ ๆ กับตัวโปรเจกต์เอง
    โดยเฉพาะการรักษาระดับนั้นไว้ได้อย่างต่อเนื่อง

  • น่าสนใจที่การทดสอบเป็นแบบปิด ในยุคที่การเขียนโค้ดด้วย LLM กำลังพัฒนา การทดสอบกำลังสำคัญกว่าการ implement มากขึ้นเรื่อย ๆ
    ช่วงหลังเห็นกรณีที่ simonw แปลงเอนจิน justHTML จาก Python เป็น JS ได้แทบจะอัตโนมัติ เลยนึกถึงกลยุทธ์การทดสอบของ SQLite ขึ้นมา

    • ถ้ามองจากมุมของ โมเดลธุรกิจ สำหรับผลิตภัณฑ์โอเพนซอร์ส test suite ขนาดใหญ่คือสินทรัพย์หลักที่ทำให้เปลี่ยนแปลงได้อย่างมีประสิทธิภาพและสร้างมูลค่าได้
    • เอกสาร How SQLite Is Tested ของ SQLite ให้ความรู้สึกราวกับเป็น คัมภีร์ของการทดสอบ ตามชื่อจริง ๆ
  • ช่วงหลังได้คุยกับ LLM เรื่องความเข้ากันได้ระหว่าง SQLite กับ DuckDB และได้ข้อสรุปว่าในแง่ของ การจัดการ concurrency นั้น SQLite ดีกว่า

  • แปลกใจที่ในเอกสารการทดสอบของ SQLite แทบไม่พูดถึง performance regression เลย
    ความถูกต้องสำคัญก็จริง แต่การถดถอยของประสิทธิภาพในเส้นทางของ query บางแบบอาจร้ายแรงถึงขั้นวิกฤตได้

    • เคยทำงานในวงการ HFT แต่แทบไม่เคยเห็นโปรเจกต์โอเพนซอร์สที่ชูเรื่อง การรับประกันประสิทธิภาพ เป็นจุดขายเลย
      เลยสงสัยว่ามีโปรเจกต์ไหนที่ยึดเป้าหมายนี้เป็นภารกิจหลักบ้างไหม
  • เมื่อดูความเสถียรของ SQLite ก็เลยอยากรู้เพิ่มว่าเขาทดสอบ anomaly กันอย่างไร
    แต่ในบทความแทบไม่ได้พูดถึงเลย ถึงอย่างนั้น SQLite ก็ยังเป็นหนึ่งใน ซอฟต์แวร์ที่แข็งแกร่งที่สุด ที่ถูกใช้งานอยู่บนอุปกรณ์แทบทุกชนิด

    • สิทธิ์เข้าถึง test suite มีราคาประมาณ 150,000 ดอลลาร์ต่อปี ดังนั้นก็คงยากที่จะคาดหวังให้มีการเปิดเผยรายละเอียดภายใน