differential-fuzzer について
Differential Fuzzer は、生成した SQL 文で Turso と SQLite を比較する Rust 製コマンドラインツールです。データベース開発者が動作差を発見・再現でき、失敗スクリプトの縮小と両者を並べたプローブにも対応します。
主な機能
- 01差分テスト用 SQL の生成
- 02Turso と SQLite の結果比較
- 03シードとプロファイルによる再実行
- 04失敗再現スクリプトの縮小
- 05スクリプトの並列プローブ
活用シーン
- 01Turso と SQLite の結果差の発見
- 02シードを使った失敗の再現
- 03失敗テストの小さなスクリプトへの縮小
- 04発見した不具合の回帰テスト化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tursodatabase/ turso --skill differential-fuzzerインストール後、Claude Code で/differential-fuzzerを入力して読み込まれたか確認します。
詳細
Differential Fuzzer
参照用に、常にDebugging スキルを読み込んでください。
差分ファザーは、生成された SQL 文について Turso の結果と SQLite の結果を比較し、正確性に関するバグを見つけます。
場所
testing/differential-oracle/fuzzer/
ファザーの実行
1 回だけ実行
# Basic run (100 statements, random seed)
cargo run --bin differential_fuzzer
# With specific seed for reproducibility
cargo run --bin differential_fuzzer -- --seed 12345
# More statements with verbose output
cargo run --bin differential_fuzzer -- -n 1000 --verbose
# Keep database files after run (for debugging)
cargo run --bin differential_fuzzer -- --seed 12345 --keep-files
# All options
cargo run --bin differential_fuzzer -- \
--seed <SEED> # Deterministic seed
-n <NUM> # Number of statements (default: 100)
-t <NUM> # Number of tables (default: 2)
-c <NUM> # Columns per table (default: 5)
--verbose # Print each SQL statement
--keep-files # Persist .db files to disk
継続的なファジング(ループモード)
# Run forever with random seeds
cargo run --bin differential_fuzzer -- loop
# Run 50 iterations
cargo run --bin differential_fuzzer -- loop 50
Docker ランナー(CI/本番環境)
# Build and run from repo root
docker build -f testing/differential-oracle/fuzzer/docker-runner/Dockerfile -t fuzzer .
docker run -e GITHUB_TOKEN=xxx -e SLACK_WEBHOOK_URL=xxx fuzzer
docker-runner の環境変数:
TIME_LIMIT_MINUTES- 合計実行時間(デフォルト:1440 = 24 時間)PER_RUN_TIMEOUT_SECONDS- 1 回あたりのタイムアウト(デフォルト:1200 = 20 分)NUM_STATEMENTS- 1 回あたりの文の数(デフォルト:1000)LOG_TO_STDOUT- ファザーの出力を表示するかどうか(デフォルト:false)GITHUB_TOKEN- 問題の自動登録に使用SLACK_WEBHOOK_URL- 通知用
出力ファイル
すべての出力は simulator-output/ ディレクトリに保存されます。
| ファイル | 説明 |
|---|---|
test.sql | 実行したすべての SQL 文。失敗した文には -- FAILED:、エラーには -- ERROR: が先頭に付加されます |
schema.json | 実行終了時(または失敗時)のデータベーススキーマ |
test.db | Turso データベースファイル(--keep-files を指定した場合のみ) |
test-sqlite.db | SQLite データベースファイル(--keep-files を指定した場合のみ) |
エラーの再現
常に次の手順に従ってください。
-
エラー出力からシードとプロファイルを見つけます。
INFO: Starting differential_fuzzer with config: SimConfig { seed: 12345, ..., weight_profile: Writes } -
そのシードとプロファイルを指定して再実行します(シードによる再生は同じプロファイルでのみ可能です)。
cargo run --bin differential_fuzzer -- --seed 12345 --profile writes --verbose --keep-files -
まず、最小化された再現ケースを確認します。 オラクルの失敗時に、ファザーは次のファイルを
simulator-output/に書き込みます。minimized.sql- 縮小された状態スクリプトと、縮小された失敗文を含みます。自動生成されます。まずこちらを確認してください。turso-state.sql/sqlite-state.sql- 最小化されたバージョン以上の情報が必要な場合に使用する、各エンジンの完全な状態を再生可能なスクリプトとして保存したものです。test.sql- 実行したすべての文(失敗した文には-- FAILED:のマークが付いています)。失敗が状態の内容だけでなく、状態の構築方法に依存する場合、最小化ツールはこの履歴を再生します。schema.json- 失敗時のテーブル構造です。
-
differential_probeで再現ケースを調べます。 1 行につき 1 文のスクリプトを Turso と SQLite で並行して実行し、各文の両方の結果を表示して差異をマークし、最後にテーブルの内容を比較します。終了コード 1 は、差異があったことを示します。cargo run -q -p differential-fuzzer --bin differential_probe -- \ simulator-output/minimized.sqlSQL を 2 つのシェルにパイプする代わりに、こちらを使用してください。tursodb シェルでは
ATTACH ':memory:' AS auxを実行できないため、auxスキーマを使うファザーの再現ケースは、このプローブでのみ正しく実行できます。標準入力からの読み込みにも対応しています。例:echo "SELECT ~X'96';" | cargo run -q -p differential-fuzzer --bin differential_probe。 -
スクリプトを編集して二分探索します。
minimized.sqlをコピーし、1 回に 1 つずつ簡略化(式を定数に置き換える、列を削除する、状態行を削除するなど)して、編集するたびにプローブを再実行します。差異マーカーを見れば、その編集後もバグが再現するかすぐに分かります。この反復により、通常は両方のエンジンでEXPLAINに渡せる 1 行の最小ケースにたどり着きます。 -
修正が完了する前に、最小ケースから恒久的な
*.sqltest回帰テストを作成します。バグを再現するために必要なスキーマ、データ、文、アサーションだけを残してください。シードと最小化されたファザーの生成物はデバッグ用の補助であり、この回帰テストの代わりにはなりません。.sqltestで表現できない動作に限り Rust テストを使い、参照用にDebugging スキルを必ず読み込んでください。
失敗の理解
オラクルの失敗の種類
- 行セットの不一致 - Turso が SQLite と異なる行を返した
- Turso でエラーになったが SQLite では成功した - Turso が有効な SQL を拒否した
- SQLite でエラーになったが Turso では成功した - Turso が無効な SQL を受け入れた
- スキーマの不一致 - DDL の実行後にテーブルまたは列が異なる
警告(致命的ではありません)
- 順序なしの LIMIT の不一致 -
ORDER BYのない LIMIT では、異なる正当な行が返される場合があります
主要なソースファイル
| ファイル | 用途 |
|---|---|
main.rs | CLI の解析、エントリーポイント |
runner.rs | メインのシミュレーションループ。両方の DB でステートメントを実行します |
oracle.rs | Turso と SQLite の結果を比較します |
schema.rs | 両方のデータベースからスキーマを調査します |
memory/ | 決定論的なシミュレーションのためのインメモリ IO |
トレース
詳細な出力を表示するには、RUST_LOG を設定します。
RUST_LOG=debug cargo run --bin differential_fuzzer -- --seed 12345