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