24 pontos por GN⁺ 2025-12-19 | 4 comentários | Compartilhar no WhatsApp
  • O SQLite mantém alta confiabilidade e robustez por meio de um sistema de testes automatizados extremamente rigoroso, com 590 vezes mais código de teste do que código-fonte
  • Quatro harnesses de teste independentes (TCL, TH3, SQL Logic Test, dbsqlfuzz) verificam a biblioteca principal e executam centenas de milhões de testes
  • Testes de condições anormais (OOM, erros de I/O, simulação de falhas) e fuzz testing confirmam que ele opera de forma estável mesmo com entradas inválidas e falhas do sistema
  • Mantém procedimentos de verificação em múltiplas camadas, como 100% de cobertura de branches e MC/DC, detecção de vazamento de recursos, Valgrind, análise estática e checklists
  • Graças a esse sistema de testes metódico, o SQLite é avaliado como um banco de dados open source com confiabilidade e qualidade de nível comercial

1. Visão geral

  • A confiabilidade e robustez do SQLite vêm de um processo de testes minucioso
    • Na versão 3.42.0, o SQLite é composto por cerca de 155,8 KSLOC de código C e 92053,1 KSLOC de código de teste
  • O sistema de testes inclui 4 harnesses independentes, 100% de cobertura de branches e milhões de casos de teste
    • Inclui OOM, erros de I/O, falhas, fuzzing, valores de fronteira, regressão, arquivos de banco de dados anormais, testes com otimizações desativadas e muitos outros itens

2. Harnesses de teste

  • TCL Tests
    • Conjunto público de testes usado principalmente durante o desenvolvimento do SQLite
    • Composto por 27,2 KSLOC de código C e 1390 arquivos de script (23,2 MB)
    • Cerca de 50 mil casos de teste e, com parametrização, centenas de milhões de execuções no total
  • TH3
    • Conjunto comercial de testes em C que atinge 100% de cobertura de branches e MC/DC
    • Também funciona em ambientes embarcados e inclui 1055,4 KSLOC e cerca de 50 mil casos
    • Nos testes completos de cobertura, executa cerca de 2,4 milhões de testes, e antes de cada release são feitos 248 milhões de soak tests
  • SQL Logic Test (SLT)
    • Compara os resultados do SQLite com PostgreSQL, MySQL, SQL Server e Oracle 10g
    • Composto por 7,2 milhões de queries e 1,12 GB de dados
  • dbsqlfuzz
    • Fuzzer baseado em libFuzzer que altera ao mesmo tempo SQL e arquivos de banco de dados
    • Executa cerca de 1 bilhão de testes de mutação por dia, validando a robustez contra entradas maliciosas
  • Ferramentas adicionais
    • speedtest1.c, mptester.c, threadtest3.c, fuzzershell.c, jfuzz etc.
    • Todos os testes precisam passar em múltiplas plataformas e configurações de compilação para que uma release seja possível

3. Testes de condições anormais

  • Teste de OOM
    • Simula falhas de malloc() para verificar se a recuperação ocorre corretamente em situações de falta de memória
    • É executado repetidamente, aumentando o contador do ponto de falha
  • Teste de erro de I/O
    • Usa um sistema de arquivos virtual (VFS) para simular erros de disco
    • Após o erro, verifica corrupção de dados com PRAGMA integrity_check
  • Teste de falha
    • Simula corte de energia e falhas do sistema operacional
    • O harness TCL usa processos-filho, e o TH3 usa VFS baseado em memória
    • Verifica se a transação é totalmente revertida ou totalmente concluída
  • Teste de falhas combinadas
    • Também valida cenários em que, após uma falha, ocorrem em sequência OOM ou erro de I/O

4. Fuzz testing

  • SQL Fuzz
    • Gera SQL sintaticamente válido, mas anômalo, para validar a resposta do SQLite
  • American Fuzzy Lop (AFL)
    • Fuzzer guiado por perfil, introduzido em 2014, que explora novos caminhos de controle
    • Encontrou diversos casos de falha de assert, crashes e resultados incorretos no SQLite
  • Google OSS Fuzz
    • Desde 2016, executa fuzzing automático na infraestrutura do Google
    • Detecta problemas intermitentes em novos commits
  • dbsqlfuzz / jfuzz
    • Introduzidos como fuzzers internos a partir de 2018, alteram simultaneamente SQL e arquivos de banco
    • Executam mais de 500 milhões de testes por dia, praticamente eliminando relatórios de bugs de fuzzers externos
    • Desde 2024, o jfuzz adicionou validação de entradas JSONB
  • Fuzzers de terceiros e fuzzcheck
    • Pesquisadores externos (por exemplo, Manuel Rigger) encontraram vários casos de cálculo incorreto de resultados
    • O utilitário fuzzcheck revalida milhares de casos “interessantes” entre os casos de fuzz do passado
  • A relação tensa entre MC/DC e fuzz testing
    • MC/DC minimiza código defensivo, enquanto fuzzing exige código defensivo
    • O SQLite combina as duas abordagens para manter código robusto tanto para entradas normais quanto maliciosas

5. Testes de regressão

  • Bugs reportados, depois de corrigidos, são sempre adicionados como novos casos de teste
    • O objetivo é evitar a reincidência de bugs antigos

6. Detecção automática de vazamento de recursos

  • Os harnesses TCL e TH3 monitoram automaticamente vazamentos de memória, arquivos, threads e mutexes
    • Não pode haver vazamento de memória mesmo após OOM ou erros de I/O

7. Cobertura de testes

  • O núcleo do SQLite atinge 100% de cobertura de branches com base no TH3
    • Extensões como FTS3 e RTree ficam de fora
  • Cobertura de instruções vs cobertura de branches
    • A cobertura de branches é mais rigorosa que a cobertura de instruções e valida ambos os lados de cada condição
  • Cobertura de código defensivo
    • As macros ALWAYS() e NEVER() explicitam condições defensivas
    • Os testes são repetidos em três formas de definição para verificar consistência
  • Testes de valor de fronteira e vetores booleanos
    • A macro testcase() valida tanto o resultado positivo quanto o negativo das condições
    • São usados 1184 testcase()
  • Alcance de MC/DC
    • A macro testcase() verifica o efeito independente de cada condição
  • Medição com base em gcov
    • A cobertura é medida com as opções -fprofile-arcs -ftest-coverage
    • A comparação dos resultados detecta bugs de compilador ou comportamento indefinido
  • Mutation Testing
    • Altera instruções de branch para verificar se os testes detectam isso
    • Branches de otimização (/*OPTIMIZATION-IF-TRUE*/) são tratados como exceção
  • Experiência com cobertura completa
    • Graças aos testes de todos os branches, efeitos colaterais ao alterar o código são minimizados
    • O custo de manutenção é alto, mas se justifica por ser uma biblioteca de infraestrutura amplamente distribuída

8. Análise dinâmica

  • Assert()
    • 6754 instruções assert verificam pré-condições, pós-condições e invariantes de loop
    • Só ficam ativas em builds com SQLITE_DEBUG
  • Valgrind
    • Detecta erros de memória, stack overflow e acesso a memória não inicializada
    • Antes de cada release, os testes veryquick e TH3 são executados com Valgrind
  • Memsys2
    • Em builds com SQLITE_MEMDEBUG, wrappers são inseridos para monitorar erros de memória
    • Permite validação repetida mais rápida que o Valgrind
  • Mutex Asserts
    • Valida sincronização multithread com sqlite3_mutex_held() e afins
  • Journal Tests
    • Verifica se o rollback journal é gravado antes do banco de dados, garantindo a atomicidade da transação
  • Undefined Behavior Checks
    • Detecta comportamento indefinido com -ftrapv, -fsanitize=undefined, /RTC1 etc.
    • É repetido em 32/64 bits, diferentes endiannesses e várias arquiteturas de CPU

9. Testes com otimizações desativadas

  • sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) permite desativar otimizações
    • O resultado deve ser o mesmo, com ou sem otimizações
    • Alguns testes voltados à medição de desempenho são exceções

10. Checklist

  • Antes de cada release, é validado um checklist manual de cerca de 200 itens
    • Alguns levam segundos, outros levam horas
    • Quando um problema é encontrado, novos itens são adicionados imediatamente, promovendo melhoria contínua

11. Análise estática

  • Compila sem warnings em GCC, Clang e MSVC
    • Também não há warnings válidos no Clang Static Analyzer
    • A análise estática tem efeito limitado na detecção de bugs reais

12. Resumo

  • Mesmo sendo open source, o SQLite mantém qualidade de nível comercial e baixa taxa de defeitos
    • Testes rigorosos e design de código são os fatores centrais
    • Todas as releases passam por esses procedimentos e são entregues como um motor de banco de dados confiável até mesmo em ambientes mission critical

4 comentários

 
regentag 2025-12-19

Artigo relacionado: A história desconhecida do SQLite

Este é um texto que resume uma entrevista com Richard Hipp, desenvolvedor do SQLite.

Os desenvolvedores do SQLite dizem que conheceram o Do-178 quando trabalhavam na Rockwell Collins e passaram a seguir esse processo. Uma das exigências é atingir 100% de MC/DC.

O Do-178 é realmente um guia muito útil, então recomendo que todo desenvolvedor o leia.

 
regentag 2025-12-19

O link que você compartilhou parece ser um material de treinamento do DO-178.
Você pode ver o documento original neste link.
https://studylib.net/doc/27132454/rtca-do-178b

 
GN⁺ 2025-12-19
Comentários no Hacker News
  • Há mais de 10 anos, o mantenedor do SQLite fez uma apresentação na OSCON sobre práticas de teste
    O que mais impressionou foi especialmente o poder das checklists. Exatamente aquela ferramenta usada por pilotos antes de cada voo
    Ele também mencionou um caso dos Médicos Sem Fronteiras (Doctors Without Borders), em que a equipe médica não sabia nem os nomes uns dos outros e falava idiomas diferentes, o que levava a resultados piores nas cirurgias
    A solução foi simples — criar uma checklist pré-operatória para que cada pessoa dissesse seu nome e sua função. Esse pequeno ritual aumentou a taxa de sobrevivência por meio de melhor comunicação, não por técnica
    Material relacionado: exemplo de checklist do SQLite

    • Por outro lado, acho que esse tipo de história gera burocracia desnecessária. As checklists da aviação, do MSF e do SQLite são excelentes, mas a maioria das organizações desperdiça tempo com checklists inúteis
      Precisamos discutir mais a diferença entre uma checklist boa e uma ruim. Parece algo simples, como uma fórmula elegante da matemática, mas difícil de encontrar
    • Sempre achei que há muito a aprender com operações de aviação e engenharia. Imagino uma organização de TI que combine esses princípios com liderança de estilo militar
      Em especial, já li o documento FM22-100 do Exército dos EUA várias vezes, e ele é surpreendentemente moderno e inspirador
      Ver documento FM22-100
    • Se você quer saber como criar boas checklists, recomendo fortemente The Checklist Manifesto
      Link do livro
    • Não entendo por que a maioria dos desenvolvedores evita tarefas simples não relacionadas à programação
      Além de testes e CI, sigo uma checklist de deploy em Markdown. Nem guardo o resultado, mas executo passo a passo
      Não sei por que os outros não fazem algo tão simples
    • É interessante como rituais melhoram o desempenho. Hoje em dia, quando fazemos uma rodada de apresentações nas reuniões, o nível de participação claramente aumenta
      Se houver uma página oficial sobre o caso do MSF, eu gostaria muito de ver. Não consegui encontrar no Google
  • Aqui está uma coleção de discussões antigas sobre testes no SQLite
    Lista de threads do HN de 2009 a 2024
    Parece que os reposts se repetem em intervalos de um ano

  • Inveja e admiração pelo processo de polir um software como o SQLite até esse nível de perfeição
    É uma obra com verdadeiro espírito artesanal

    • Na verdade, qualquer um pode fazer isso. Nunca fui demitido por fazer devagar e direito
      Com o tempo, o padrão de qualidade sobe e você passa a receber recompensas maiores pelo mesmo esforço
      Ninguém desgosta de alguém que deixa a parte em que mexeu um pouco mais limpa
  • O SQLite é realmente um software excelente. Também gosto do site oficial, que é centrado em informação em vez de marketing
    Mas é curioso como, recentemente, as páginas do site oficial vêm aparecendo uma a uma no HN

    • Provavelmente o post do simonw sobre portar com LLM virou assunto ontem e fez esses links ganharem atenção de novo
    • No HN isso acontece periodicamente. Antigamente era com Haskell; hoje em dia parece ser a vez do Zig
      Seria interessante juntar esses links
  • É interessante que o SQLite seja software aberto e ainda assim use testes privados
    Só agora percebi que um projeto open source pode ter testes fechados
    Parece que esse modelo pode até virar um novo modelo de negócios parecido com open-core

    • Na prática, muitas vezes a suíte de testes vale mais do que o código. Por exemplo, documentar os inúmeros edge cases de um software como o Excel é mais difícil do que a implementação
    • Faço algo parecido em projetos da empresa. Junto com o licenciamento duplo GPL, os geradores de testes e de dados só são liberados para usuários da licença comercial
      Exemplo: licença do railgunlabs/unicorn
  • A cobertura de branches de 100% do SQLite é tão impressionante quanto o próprio projeto
    O mais incrível é conseguir manter isso continuamente

  • É interessante que os testes sejam privados. Agora que a programação com base em LLM está avançando, estamos entrando numa era em que os testes estão se tornando mais importantes do que a implementação
    Ao ver recentemente o caso em que simonw converteu quase automaticamente o motor justHTML de Python para JS, lembrei da estratégia de testes do SQLite

    • Do ponto de vista do modelo de negócios de um produto open source, uma suíte de testes enorme se torna um ativo central para fazer mudanças de forma eficiente e gerar valor
    • O documento How SQLite Is Tested do SQLite parece literalmente uma bíblia dos testes
  • Recentemente discuti com um LLM a compatibilidade entre SQLite e DuckDB e cheguei à conclusão de que, em termos de tratamento de concorrência, o SQLite é melhor

  • Fiquei surpreso com a pouca menção a testes de regressão de desempenho (performance regression) na documentação de testes do SQLite
    Correção é importante, mas uma queda de desempenho em certos caminhos de consulta pode ser fatal

    • Trabalhei no setor de HFT, mas quase nunca vi projetos open source que enfatizem garantias de desempenho
      Fico curioso se existe algum projeto que tenha esse objetivo como missão principal
  • Ao ver a estabilidade do SQLite, quis saber mais sobre como foram feitos os testes de anomalias
    Mas o texto quase não fala disso. Mesmo assim, o SQLite continua sendo um dos softwares mais robustos usados em todo tipo de dispositivo

    • Como o acesso à suíte de testes custa algo em torno de US$ 150 mil por ano, parece improvável que revelem o conteúdo interno