check / check (push) Successful in 3m13s
REPO_POLICIES.md puts migrations in internal/db/migrations/ as 000_migration.sql and 001_schema.sql. The two files move there with their contents unchanged. go:embed cannot reach outside its own package, so internal/db/migrations has a small package that embeds them, and internal/database reads them through its FS(). The database package stays where CONVENTIONS.md puts it; moving it would change existing test files in other packages. The version still comes from the filename prefix, so a database that has recorded versions 0 and 1 runs neither again. A new test applies the migrations twice to one database file and checks that the second run applies nothing. Model: opus-5-5
55 lines
1.4 KiB
Go
55 lines
1.4 KiB
Go
package database
|
|
|
|
import (
|
|
"bytes"
|
|
"database/sql"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite" // SQLite driver registration
|
|
)
|
|
|
|
// TestApplyMigrations_SecondRunAppliesNothing applies the migrations twice
|
|
// to one database file, as happens when pixad starts again on the database
|
|
// it created, and checks that the second run applies none of them.
|
|
// ApplyMigrations logs a message starting with "applying" before it runs
|
|
// any migration, the bootstrap one included.
|
|
func TestApplyMigrations_SecondRunAppliesNothing(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ctx := t.Context()
|
|
|
|
db, err := sql.Open("sqlite", filepath.Join(t.TempDir(), "state.sqlite3"))
|
|
if err != nil {
|
|
t.Fatalf("failed to open test db: %v", err)
|
|
}
|
|
|
|
t.Cleanup(func() { _ = db.Close() })
|
|
|
|
var firstLog bytes.Buffer
|
|
|
|
err = ApplyMigrations(ctx, db, slog.New(slog.NewTextHandler(&firstLog, nil)))
|
|
if err != nil {
|
|
t.Fatalf("first ApplyMigrations failed: %v", err)
|
|
}
|
|
|
|
if !strings.Contains(firstLog.String(), "applying") {
|
|
t.Fatalf("first ApplyMigrations logged no applied migration:\n%s",
|
|
firstLog.String())
|
|
}
|
|
|
|
var secondLog bytes.Buffer
|
|
|
|
err = ApplyMigrations(ctx, db, slog.New(slog.NewTextHandler(&secondLog, nil)))
|
|
if err != nil {
|
|
t.Fatalf("second ApplyMigrations failed: %v", err)
|
|
}
|
|
|
|
if strings.Contains(secondLog.String(), "applying") {
|
|
t.Errorf("second ApplyMigrations ran a migration again:\n%s",
|
|
secondLog.String())
|
|
}
|
|
}
|