// Package dbdoortest builds real litestream replicas for the db door's tests, // on both sides of the wire (internal/console serves one, internal/dbdoor and // the CLI restore one). A fake replica would prove only that the fake agrees // with itself; these are written by litestream's own replication code, in // the layout its file client reads, so a restore through the door is the // restore production runs. // // Test support only: nothing outside a _test.go file may import it. package dbdoortest import ( "context" "database/sql" "fmt" "path/filepath" "testing" "time" "github.com/benbjohnson/litestream" lsfile "github.com/benbjohnson/litestream/file" _ "modernc.org/sqlite" ) // Rows is how many rows each batch inserts into table t. const Rows = 10 // Replicate creates a WAL-mode SQLite database with a table t(id, body) and // replicates it into dir in `batches` separate syncs, so the replica holds // several L0 files rather than one. It returns the source database's path; // the source holds batches*Rows rows when it returns. func Replicate(t testing.TB, dir string, batches int) string { t.Helper() src := filepath.Join(t.TempDir(), "source.db") db, err := sql.Open("sqlite", src) if err != nil { t.Fatal(err) } defer db.Close() if _, err := db.Exec(`PRAGMA journal_mode=WAL; CREATE TABLE t (id INTEGER PRIMARY KEY, body TEXT)`); err != nil { t.Fatal(err) } for b := 0; b < batches; b++ { for i := 0; i < Rows; i++ { if _, err := db.Exec(`INSERT INTO t (body) VALUES (?)`, fmt.Sprintf("row-%d-%d", b, i)); err != nil { t.Fatal(err) } } Sync(t, src, dir) } return src } // Sync replicates the source's committed state into dir once, the way the // lease package's Checkpoint does: open, one explicit sync, close. func Sync(t testing.TB, src, dir string) { t.Helper() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() ldb := litestream.NewDB(src) ldb.SetMetaPath(filepath.Join(filepath.Dir(src), ".dbdoortest-litestream")) ldb.MonitorInterval = 0 ldb.Replica = litestream.NewReplicaWithClient(ldb, lsfile.NewReplicaClient(dir)) ldb.Replica.MonitorEnabled = false store := litestream.NewStore([]*litestream.DB{ldb}, litestream.CompactionLevels{{Level: 0}}) store.CompactionMonitorEnabled = false store.L0RetentionCheckInterval = 0 store.SetRetentionEnabled(false) if err := store.Open(ctx); err != nil { t.Fatal(err) } syncErr := ldb.SyncAndWait(ctx) if err := store.Close(ctx); err != nil { t.Fatal(err) } if syncErr != nil { t.Fatal(syncErr) } }