// Package testutil provides composable test helpers for spinning up // real infrastructure (in-memory SQLite, session managers) in // integration tests. package testutil import ( "database/sql" "io/fs" "testing" "github.com/ryanhamamura/c4/db" "github.com/ryanhamamura/c4/db/repository" "github.com/pressly/goose/v3" _ "modernc.org/sqlite" ) // NewTestDB opens an in-memory SQLite database with the same pragmas as // production, runs all goose migrations, and returns the raw connection // alongside the sqlc Queries handle. The database is closed automatically // when the test finishes. func NewTestDB(t *testing.T) (*sql.DB, *repository.Queries) { t.Helper() pragmas := "?_pragma=busy_timeout(10000)&_pragma=journal_mode(WAL)&_pragma=journal_size_limit(200000000)&_pragma=synchronous(NORMAL)&_pragma=foreign_keys(ON)&_pragma=temp_store(MEMORY)&_pragma=cache_size(-32000)" database, err := goose.OpenDBWithDriver("sqlite", ":memory:"+pragmas) if err != nil { t.Fatalf("open test database: %v", err) } t.Cleanup(func() { database.Close() }) //nolint:errcheck // test cleanup if err := database.Ping(); err != nil { t.Fatalf("ping test database: %v", err) } sub, err := fs.Sub(db.MigrationFS, "migrations") if err != nil { t.Fatalf("migrations sub fs: %v", err) } goose.SetBaseFS(sub) if err := goose.Up(database, "."); err != nil { t.Fatalf("run migrations: %v", err) } return database, repository.New(database) }