//go:build !windows package plugins import ( "database/sql" _ "github.com/mattn/go-sqlite3" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) var _ = Describe("migrateDB", func() { var db *sql.DB BeforeEach(func() { var err error db, err = sql.Open("sqlite3", ":memory:") Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { if db != nil { db.Close() } }) getUserVersion := func() int { var version int Expect(db.QueryRow(`PRAGMA user_version`).Scan(&version)).To(Succeed()) return version } It("applies all migrations on a fresh database", func() { migrations := []string{ `CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`, `ALTER TABLE test ADD COLUMN email TEXT`, } Expect(migrateDB(db, migrations)).To(Succeed()) Expect(getUserVersion()).To(Equal(2)) // Verify schema _, err := db.Exec(`INSERT INTO test (id, name, email) VALUES (1, 'Alice', 'alice@test.com')`) Expect(err).ToNot(HaveOccurred()) }) It("skips already applied migrations", func() { migrations1 := []string{ `CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`, } Expect(migrateDB(db, migrations1)).To(Succeed()) Expect(getUserVersion()).To(Equal(1)) // Add a new migration migrations2 := []string{ `CREATE TABLE test (id INTEGER PRIMARY KEY, name TEXT)`, `ALTER TABLE test ADD COLUMN email TEXT`, } Expect(migrateDB(db, migrations2)).To(Succeed()) Expect(getUserVersion()).To(Equal(2)) // Verify the new column exists _, err := db.Exec(`INSERT INTO test (id, name, email) VALUES (1, 'Alice', 'alice@test.com')`) Expect(err).ToNot(HaveOccurred()) }) It("is a no-op when all migrations are applied", func() { migrations := []string{ `CREATE TABLE test (id INTEGER PRIMARY KEY)`, } Expect(migrateDB(db, migrations)).To(Succeed()) Expect(migrateDB(db, migrations)).To(Succeed()) Expect(getUserVersion()).To(Equal(1)) }) It("is a no-op with empty migrations slice", func() { Expect(migrateDB(db, nil)).To(Succeed()) Expect(getUserVersion()).To(Equal(0)) }) It("rolls back on failure", func() { migrations := []string{ `CREATE TABLE test (id INTEGER PRIMARY KEY)`, `INVALID SQL STATEMENT`, } err := migrateDB(db, migrations) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("migration 2 failed")) // Version should remain 0 (rolled back) Expect(getUserVersion()).To(Equal(0)) // Table should not exist (rolled back) _, err = db.Exec(`INSERT INTO test (id) VALUES (1)`) Expect(err).To(HaveOccurred()) }) })