test: add data-fix runner characterization tests
This commit is contained in:
142
internal/database/data_fixes_test.go
Normal file
142
internal/database/data_fixes_test.go
Normal file
@@ -0,0 +1,142 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
dbfixes "mal/internal/database/fixes"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func TestRunDataFixListRunsUnappliedFixesAndRecordsSuccesses(t *testing.T) {
|
||||
sqlDB := newEmptyTestDB(t)
|
||||
defer closeTestDB(t, sqlDB)
|
||||
|
||||
var applied []string
|
||||
fixes := []dbfixes.Fix{
|
||||
{
|
||||
ID: "first",
|
||||
Apply: func(ctx context.Context, sqlDB *sql.DB, deps dbfixes.Dependencies) error {
|
||||
applied = append(applied, "first")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "second",
|
||||
Apply: func(ctx context.Context, sqlDB *sql.DB, deps dbfixes.Dependencies) error {
|
||||
applied = append(applied, "second")
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := runDataFixList(sqlDB, dbfixes.Dependencies{}, fixes); err != nil {
|
||||
t.Fatalf("runDataFixList: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(applied, []string{"first", "second"}) {
|
||||
t.Fatalf("applied fixes = %v, want [first second]", applied)
|
||||
}
|
||||
assertAppliedDataFixes(context.Background(), t, sqlDB, []string{"first", "second"})
|
||||
}
|
||||
|
||||
func TestRunDataFixListSkipsAlreadyAppliedFixes(t *testing.T) {
|
||||
sqlDB := newEmptyTestDB(t)
|
||||
defer closeTestDB(t, sqlDB)
|
||||
|
||||
ctx := context.Background()
|
||||
if _, err := sqlDB.ExecContext(ctx, `CREATE TABLE data_fixes (id TEXT PRIMARY KEY, applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP)`); err != nil {
|
||||
t.Fatalf("create data_fixes: %v", err)
|
||||
}
|
||||
if _, err := sqlDB.ExecContext(ctx, `INSERT INTO data_fixes (id) VALUES ('already-applied')`); err != nil {
|
||||
t.Fatalf("insert applied fix: %v", err)
|
||||
}
|
||||
|
||||
var ran bool
|
||||
fixes := []dbfixes.Fix{
|
||||
{
|
||||
ID: "already-applied",
|
||||
Apply: func(ctx context.Context, sqlDB *sql.DB, deps dbfixes.Dependencies) error {
|
||||
ran = true
|
||||
return nil
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := runDataFixList(sqlDB, dbfixes.Dependencies{}, fixes); err != nil {
|
||||
t.Fatalf("runDataFixList: %v", err)
|
||||
}
|
||||
|
||||
if ran {
|
||||
t.Fatal("already applied fix ran")
|
||||
}
|
||||
assertAppliedDataFixes(context.Background(), t, sqlDB, []string{"already-applied"})
|
||||
}
|
||||
|
||||
func TestRunDataFixListDoesNotRecordFailedFix(t *testing.T) {
|
||||
sqlDB := newEmptyTestDB(t)
|
||||
defer closeTestDB(t, sqlDB)
|
||||
|
||||
fixErr := errors.New("boom")
|
||||
fixes := []dbfixes.Fix{
|
||||
{
|
||||
ID: "fails",
|
||||
Apply: func(ctx context.Context, sqlDB *sql.DB, deps dbfixes.Dependencies) error {
|
||||
return fixErr
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := runDataFixList(sqlDB, dbfixes.Dependencies{}, fixes)
|
||||
if !errors.Is(err, fixErr) {
|
||||
t.Fatalf("runDataFixList error = %v, want wrapped %v", err, fixErr)
|
||||
}
|
||||
|
||||
assertAppliedDataFixes(context.Background(), t, sqlDB, nil)
|
||||
}
|
||||
|
||||
func newEmptyTestDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
|
||||
sqlDB, err := sql.Open("sqlite3", ":memory:")
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(1)
|
||||
|
||||
return sqlDB
|
||||
}
|
||||
|
||||
func assertAppliedDataFixes(ctx context.Context, t *testing.T, sqlDB *sql.DB, want []string) {
|
||||
t.Helper()
|
||||
|
||||
rows, err := sqlDB.QueryContext(ctx, `SELECT id FROM data_fixes ORDER BY id`)
|
||||
if err != nil {
|
||||
t.Fatalf("query data_fixes: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
t.Errorf("close rows: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var got []string
|
||||
for rows.Next() {
|
||||
var id string
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
t.Fatalf("scan data_fix id: %v", err)
|
||||
}
|
||||
got = append(got, id)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
t.Fatalf("iterate data_fixes: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("applied data fixes = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user