11P by GN⁺ 1일전 | ★ favorite | 댓글 4개
  • SQLite는 철저한 자동화 테스트 체계를 통해 높은 신뢰성과 견고성을 유지하며, 코드보다 590배 많은 테스트 코드가 존재함
  • 네 가지 독립 테스트 하니스(TCL, TH3, SQL Logic Test, dbsqlfuzz) 가 핵심 라이브러리를 검증하며, 수억 건의 테스트를 수행
  • 이상 상황 테스트(OOM, I/O 오류, 크래시 시뮬레이션)퍼즈 테스트(fuzz testing) 를 통해 비정상 입력과 시스템 장애에도 안정적으로 동작함을 확인
  • 100% 분기 및 MC/DC 커버리지, 리소스 누수 검출, Valgrind·정적 분석·체크리스트 등 다층적 검증 절차를 유지
  • 이러한 체계적 테스트 덕분에 SQLite는 상용 DB 수준의 신뢰성과 품질을 확보한 오픈소스 데이터베이스로 평가됨

1. 개요

  • SQLite의 신뢰성과 견고성은 세밀한 테스트 과정에서 비롯됨
    • 버전 3.42.0 기준, SQLite는 약 155.8 KSLOC의 C 코드와 92053.1 KSLOC의 테스트 코드로 구성
  • 테스트 체계는 4개의 독립 하니스, 100% 분기 커버리지, 수백만 건의 테스트 케이스를 포함
    • OOM, I/O 오류, 크래시, 퍼즈, 경계값, 회귀, 비정상 DB 파일, 최적화 비활성화 테스트 등 다수 항목 포함

2. 테스트 하니스

  • TCL Tests
    • SQLite 개발 중 주로 사용되는 공개 테스트 세트
    • 27.2 KSLOC의 C 코드와 1390개 스크립트 파일(23.2MB)로 구성
    • 5만여 개 테스트 케이스, 매개변수화로 전체 실행 시 수백만 건 수행
  • TH3
    • 상용 C 기반 테스트 세트로 100% 분기 및 MC/DC 커버리지 달성
    • 임베디드 환경에서도 동작하며, 1055.4 KSLOC·약 5만여 케이스 포함
    • 전체 커버리지 테스트 시 약 2.4백만 건, 릴리스 전 2.48억 건 soak 테스트 수행
  • SQL Logic Test (SLT)
    • SQLite와 PostgreSQL, MySQL, SQL Server, Oracle 10g 결과를 비교
    • 7.2백만 쿼리, 1.12GB 데이터로 구성
  • dbsqlfuzz
    • SQL과 데이터베이스 파일을 동시에 변형하는 libFuzzer 기반 퍼저
    • 하루 약 10억 번의 변이 테스트 수행, 악의적 입력에 대한 견고성 검증
  • 추가 도구
    • speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz 등
    • 모든 테스트는 다중 플랫폼·컴파일 설정에서 통과해야 릴리스 가능

3. 이상 상황 테스트

  • OOM 테스트
    • malloc() 실패를 시뮬레이션하여 메모리 부족 시 정상 복구 여부 검증
    • 실패 시점 카운터를 증가시키며 반복 수행
  • I/O 오류 테스트
    • 가상 파일 시스템(VFS)을 이용해 디스크 오류를 시뮬레이션
    • 오류 후 PRAGMA integrity_check로 데이터 손상 여부 확인
  • 크래시 테스트
    • 전원 차단·OS 크래시 상황을 시뮬레이션
    • TCL 하니스는 자식 프로세스 기반, TH3는 메모리 기반 VFS 사용
    • 트랜잭션의 완전 롤백 또는 완전 완료 여부 검증
  • 복합 실패 테스트
    • 크래시 후 OOM 또는 I/O 오류가 연속 발생하는 상황까지 검증

4. 퍼즈 테스트

  • SQL Fuzz
    • 문법적으로 유효하지만 비정상적인 SQL을 생성해 SQLite 반응 검증
  • American Fuzzy Lop (AFL)
    • 2014년 도입된 프로파일 기반 퍼저로, 새로운 제어 경로를 탐색
    • SQLite의 assert 실패·크래시·잘못된 결과를 다수 발견
  • Google OSS Fuzz
    • 2016년부터 Google 인프라에서 자동 퍼징 수행
    • 신규 커밋에서 간헐적 문제를 탐지
  • dbsqlfuzz / jfuzz
    • 2018년 이후 내부 퍼저로 도입, SQL과 DB 파일 동시 변이
    • 하루 5억 건 이상 테스트, 외부 퍼저의 버그 리포트 거의 소멸
    • 2024년부터 jfuzz가 JSONB 입력 검증 추가
  • 타사 퍼저 및 fuzzcheck
    • 외부 연구자(예: Manuel Rigger)가 잘못된 결과 계산 사례 다수 발견
    • fuzzcheck 유틸리티가 과거 퍼즈 케이스 중 ‘흥미로운’ 수천 건을 재검증
  • MC/DC와 퍼즈 테스트의 긴장 관계
    • MC/DC는 방어 코드 최소화, 퍼즈는 방어 코드 필요
    • SQLite는 두 접근을 병행해 정상·악의적 입력 모두에 견고한 코드 유지

5. 회귀 테스트

  • 보고된 버그는 수정 후 반드시 새 테스트 케이스로 추가
    • 과거 버그의 재발 방지 목적

6. 자동 리소스 누수 검출

  • TCL·TH3 하니스가 메모리·파일·스레드·뮤텍스 누수 자동 감시
    • OOM·I/O 오류 후에도 메모리 누수가 없어야 함

7. 테스트 커버리지

  • SQLite 코어는 TH3 기준 100% 분기 커버리지 달성
    • FTS3, RTree 등 확장은 제외
  • Statement vs Branch Coverage
    • 분기 커버리지는 문장 커버리지보다 엄격하며, 모든 조건 분기를 양방향으로 검증
  • 방어 코드 커버리지
    • ALWAYS(), NEVER() 매크로로 방어 조건을 명시
    • 세 가지 정의 형태로 테스트를 반복해 일관성 검증
  • 경계값 및 불리언 벡터 테스트
    • testcase() 매크로로 조건의 양·음 결과 모두 검증
    • 1184개 testcase() 사용
  • MC/DC 달성
    • testcase() 매크로를 통해 모든 조건의 독립적 영향 검증
  • gcov 기반 측정
    • -fprofile-arcs -ftest-coverage 옵션으로 커버리지 측정
    • 결과 비교를 통해 컴파일러 버그나 정의되지 않은 동작 탐지
  • Mutation Testing
    • 분기 명령을 변경해 테스트가 이를 감지하는지 확인
    • 최적화 분기(/*OPTIMIZATION-IF-TRUE*/)는 예외 처리
  • 완전 커버리지 경험
    • 모든 분기 테스트 덕분에 코드 변경 시 부작용 최소화
    • 유지 비용은 높지만, 광범위 배포되는 인프라 라이브러리로서 정당화됨

8. 동적 분석

  • Assert()
    • 6754개 assert 문으로 전·후조건 및 루프 불변식 검증
    • SQLITE_DEBUG 빌드에서만 활성화
  • Valgrind
    • 메모리 오류·스택 오버플로·초기화되지 않은 메모리 접근 탐지
    • 릴리스 전 veryquick 및 TH3 테스트를 Valgrind로 실행
  • Memsys2
    • SQLITE_MEMDEBUG 빌드 시 메모리 오류 감시용 래퍼 삽입
    • Valgrind보다 빠르게 반복 검증 가능
  • Mutex Asserts
    • sqlite3_mutex_held() 등으로 멀티스레드 동기화 검증
  • Journal Tests
    • 롤백 저널이 DB보다 먼저 기록되는지 확인, 트랜잭션 원자성 보장
  • Undefined Behavior Checks
    • -ftrapv, -fsanitize=undefined, /RTC1 등으로 비정의 동작 탐지
    • 32/64비트, 엔디언, 다양한 CPU 아키텍처에서 반복 수행

9. 최적화 비활성화 테스트

  • sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)으로 최적화 끄기
    • 최적화 유무에 관계없이 동일 결과를 산출해야 함
    • 일부 성능 측정용 테스트는 예외

10. 체크리스트

  • 릴리스 전 약 200개 항목의 수동 체크리스트 검증
    • 일부는 수초, 일부는 수시간 소요
    • 문제 발견 시 즉시 항목 추가, 지속적 개선

11. 정적 분석

  • GCC·Clang·MSVC에서 경고 없이 컴파일
    • Clang Static Analyzer에서도 유효 경고 없음
    • 정적 분석은 실제 버그 탐지 효과가 제한적

12. 요약

  • SQLite는 오픈소스임에도 상용 수준의 품질과 낮은 결함률을 유지
    • 철저한 테스트와 코드 설계가 핵심 요인
    • 모든 릴리스는 위 절차를 거쳐 미션 크리티컬 환경에서도 신뢰 가능한 DB 엔진으로 제공됨

함께 보면 좋은 글: SQLite의 알려지지 않은 이야기

SQLite 개발자 Richard Hipp의 인터뷰를 요약한 글입니다.

SQLite의 개발자들은 록웰 콜린스와 일하던 시기에 Do-178을 알게되어 이 절차를 따르기 시작했다고 합니다. 그 중 하나가 100%의 MC/DC 달성이구요.

Do-178은 정말로 쓸만한 지침서이니 개발자라면 누구나 읽어보시길 추천합니다.

링크하신건 Do-178 교육자료인것 같아요.
원 문서는 이 링크를 보시면 됩니다.
https://studylib.net/doc/27132454/rtca-do-178b

Hacker News 의견들
  • 10여 년 전 SQLite의 유지보수자가 OSCON에서 테스트 관행에 대해 발표했음
    특히 인상 깊었던 건 체크리스트(checklist) 의 힘이었음. 비행 전마다 파일럿이 사용하는 바로 그 도구임
    그는 또한 국경없는의사회(Doctors Without Borders) 사례를 언급했는데, 의료진이 서로 이름도 모르고 언어도 달라서 수술 성과가 낮았다고 함
    해결책은 간단했음 — 수술 전 체크리스트를 만들어 각자 이름과 역할을 말하게 한 것임. 이 작은 의식이 기술이 아닌 소통 개선을 통해 생존율을 높였다고 함
    관련 자료: SQLite checklist 예시

    • 반면 이런 이야기가 불필요한 관료주의를 낳는다고 생각함. 항공, MSF, SQLite의 체크리스트는 훌륭하지만, 대부분의 조직은 쓸모없는 체크리스트로 시간을 낭비함
      좋은 체크리스트와 나쁜 체크리스트의 차이에 대한 논의가 더 필요함. 수학의 아름다운 공식처럼 단순해 보이지만 발견하기는 어려운 것 같음
    • 항공 운영과 공학에서 배울 점이 많다고 느껴왔음. 이런 원칙을 군대식 리더십과 결합한 IT 조직을 상상해봄
      특히 미 육군의 FM22-100 문서를 여러 번 읽었는데, 놀라울 만큼 현대적이고 영감을 줌
      FM22-100 문서 보기
    • 좋은 체크리스트를 만드는 방법을 알고 싶다면 The Checklist Manifesto를 강력히 추천함
      책 링크
    • 대부분의 개발자들이 비프로그래밍적 단순한 일을 회피하려는 게 이해되지 않음
      나는 테스트와 CI 외에도 Markdown으로 된 배포 체크리스트를 따라감. 결과를 저장하지도 않지만, 단계별로 수행함
      이렇게 간단한 일을 왜 다른 사람들은 안 하는지 모르겠음
    • 의식이 성과를 높인다는 점이 흥미로움. 요즘 회의에서도 참가자 소개 라운드를 하면 참여도가 확실히 높아짐
      MSF 사례를 다룬 공식 페이지가 있다면 꼭 보고 싶음. 구글링으로는 찾지 못했음
  • SQLite의 테스트 관련 과거 토론들을 모아둠
    2009~2024년 HN 스레드 목록
    재게시가 1년 간격으로 반복되는 듯함

  • SQLite 같은 소프트웨어를 완벽하게 다듬는 과정이 부럽고 경이로움
    장인정신이 느껴지는 작품임

    • 사실 누구나 그렇게 할 수 있음. 천천히, 제대로 만드는 걸로 해고된 적은 없음
      시간이 지나면 품질 기준이 높아지고, 같은 노력으로 더 큰 보상을 얻게 됨
      자신이 손댄 부분을 조금이라도 더 깨끗하게 남기는 사람을 싫어하는 이는 없음
  • SQLite는 정말 훌륭한 소프트웨어임. 공식 웹사이트도 마케팅 대신 정보 중심이라 좋음
    다만 최근 HN에 공식 사이트의 페이지들이 하나씩 올라오는 게 흥미로움

    • 아마 어제 simonw의 LLM 포팅 글이 화제가 되면서 관련 링크가 다시 주목받은 듯함
    • HN에서는 이런 일이 주기적으로 반복됨. 예전엔 Haskell이 그랬고, 요즘은 Zig가 그 주기를 도는 중임
      이런 링크들을 모아두면 재밌을 것 같음
  • SQLite가 공개 소프트웨어이면서도 비공개 테스트를 사용한다는 점이 흥미로움
    오픈소스 프로젝트가 폐쇄형 테스트를 갖는 게 가능하다는 걸 이제야 깨달음
    이런 모델이 오픈코어(open-core) 와 비슷한 새로운 비즈니스 모델이 될 수도 있을 것 같음

    • 실제로 테스트 스위트가 코드보다 더 가치 있는 경우가 많음. 예를 들어 Excel 같은 소프트웨어의 수많은 엣지 케이스를 문서화하는 건 구현보다 어렵기 때문임
    • 나도 회사 프로젝트에서 비슷하게 함. GPL 이중 라이선스와 함께 테스트 및 데이터 생성기는 상용 라이선스 사용자에게만 공개함
      예시: railgunlabs/unicorn 라이선스
  • SQLite의 100% 브랜치 커버리지는 프로젝트 자체만큼이나 인상적임
    지속적으로 유지한다는 게 특히 대단함

  • 테스트가 비공개라는 점이 흥미로움. LLM 기반 코딩이 발전하는 지금, 테스트가 구현보다 중요해지는 시대가 오고 있음
    최근 simonw가 justHTML 엔진을 Python에서 JS로 거의 자동 변환한 사례를 보며 SQLite의 테스트 전략이 떠올랐음

    • 오픈소스 제품의 비즈니스 모델 관점에서 보면, 방대한 테스트 스위트는 효율적인 변경과 가치 창출의 핵심 자산이 됨
    • SQLite의 How SQLite Is Tested 문서는 말 그대로 테스트의 성서처럼 느껴짐
  • 최근 SQLite와 DuckDB 간 호환성을 고려하며 LLM과 논의했는데, 동시성 처리 측면에서는 SQLite가 더 낫다는 결론을 얻었음

  • SQLite의 테스트 문서에서 성능 회귀 테스트(performance regression) 에 대한 언급이 적은 게 의외였음
    정확성도 중요하지만, 특정 쿼리 경로에서의 성능 저하는 치명적일 수 있음

    • HFT 분야에서 일했지만, 성능 보증을 내세우는 오픈소스 프로젝트는 거의 본 적이 없음
      혹시 이런 목표를 핵심 사명으로 삼는 프로젝트가 있는지 궁금함
  • SQLite의 안정성을 보면 이상(anomaly) 테스트가 어떻게 이루어졌는지 더 알고 싶었음
    하지만 글에서는 거의 언급이 없었음. 그럼에도 불구하고 SQLite는 모든 기기에서 쓰이는 가장 견고한 소프트웨어 중 하나임

    • 테스트 스위트 접근권이 연간 15만 달러 수준이라, 내부 내용을 공개할 가능성은 낮을 것 같음