mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-02-05 10:45:09 +02:00
238 lines
6.1 KiB
Go
238 lines
6.1 KiB
Go
package core_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
"github.com/pocketbase/pocketbase/tests"
|
|
)
|
|
|
|
func TestMigrationsRunnerUpAndDown(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
callsOrder := []string{}
|
|
|
|
l := core.MigrationsList{}
|
|
l.Register(func(app core.App) error {
|
|
callsOrder = append(callsOrder, "up2")
|
|
return nil
|
|
}, func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down2")
|
|
return nil
|
|
}, "2_test")
|
|
l.Register(func(app core.App) error {
|
|
callsOrder = append(callsOrder, "up3")
|
|
return nil
|
|
}, func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down3")
|
|
return nil
|
|
}, "3_test")
|
|
l.Register(func(app core.App) error {
|
|
callsOrder = append(callsOrder, "up1")
|
|
return nil
|
|
}, func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down1")
|
|
return nil
|
|
}, "1_test")
|
|
l.Register(func(app core.App) error {
|
|
callsOrder = append(callsOrder, "up4")
|
|
return nil
|
|
}, func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down4")
|
|
return nil
|
|
}, "4_test")
|
|
l.Add(&core.Migration{
|
|
Up: func(app core.App) error {
|
|
callsOrder = append(callsOrder, "up5")
|
|
return nil
|
|
},
|
|
Down: func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down5")
|
|
return nil
|
|
},
|
|
File: "5_test",
|
|
ReapplyCondition: func(txApp core.App, runner *core.MigrationsRunner, fileName string) (bool, error) {
|
|
return true, nil
|
|
},
|
|
})
|
|
|
|
runner := core.NewMigrationsRunner(app, l)
|
|
|
|
// ---------------------------------------------------------------
|
|
// simulate partially out-of-order applied migration
|
|
// ---------------------------------------------------------------
|
|
|
|
_, err := app.DB().Insert(core.DefaultMigrationsTable, dbx.Params{
|
|
"file": "4_test",
|
|
"applied": time.Now().UnixMicro() - 2,
|
|
}).Execute()
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert 5_test migration: %v", err)
|
|
}
|
|
|
|
_, err = app.DB().Insert(core.DefaultMigrationsTable, dbx.Params{
|
|
"file": "5_test",
|
|
"applied": time.Now().UnixMicro() - 1,
|
|
}).Execute()
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert 5_test migration: %v", err)
|
|
}
|
|
|
|
_, err = app.DB().Insert(core.DefaultMigrationsTable, dbx.Params{
|
|
"file": "2_test",
|
|
"applied": time.Now().UnixMicro(),
|
|
}).Execute()
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert 2_test migration: %v", err)
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// Up()
|
|
// ---------------------------------------------------------------
|
|
|
|
if _, err := runner.Up(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedUpCallsOrder := `["up1","up3","up5"]` // skip up2 and up4 since they were applied already (up5 has extra reapply condition)
|
|
|
|
upCallsOrder, err := json.Marshal(callsOrder)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if v := string(upCallsOrder); v != expectedUpCallsOrder {
|
|
t.Fatalf("Expected Up() calls order %s, got %s", expectedUpCallsOrder, upCallsOrder)
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// reset callsOrder
|
|
callsOrder = []string{}
|
|
|
|
// simulate unrun migration
|
|
l.Register(nil, func(app core.App) error {
|
|
callsOrder = append(callsOrder, "down6")
|
|
return nil
|
|
}, "6_test")
|
|
|
|
// simulate applied migrations from different migrations list
|
|
_, err = app.DB().Insert(core.DefaultMigrationsTable, dbx.Params{
|
|
"file": "from_different_list",
|
|
"applied": time.Now().UnixMicro(),
|
|
}).Execute()
|
|
if err != nil {
|
|
t.Fatalf("Failed to insert from_different_list migration: %v", err)
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// ---------------------------------------------------------------
|
|
// Down()
|
|
// ---------------------------------------------------------------
|
|
|
|
if _, err := runner.Down(2); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expectedDownCallsOrder := `["down5","down3"]` // revert in the applied order
|
|
|
|
downCallsOrder, err := json.Marshal(callsOrder)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if v := string(downCallsOrder); v != expectedDownCallsOrder {
|
|
t.Fatalf("Expected Down() calls order %s, got %s", expectedDownCallsOrder, downCallsOrder)
|
|
}
|
|
}
|
|
|
|
func TestMigrationsRunnerRemoveMissingAppliedMigrations(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
app, _ := tests.NewTestApp()
|
|
defer app.Cleanup()
|
|
|
|
// mock migrations history
|
|
for i := 1; i <= 3; i++ {
|
|
_, err := app.DB().Insert(core.DefaultMigrationsTable, dbx.Params{
|
|
"file": fmt.Sprintf("%d_test", i),
|
|
"applied": time.Now().UnixMicro(),
|
|
}).Execute()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
if !isMigrationApplied(app, "2_test") {
|
|
t.Fatalf("Expected 2_test migration to be applied")
|
|
}
|
|
|
|
// create a runner without 2_test to mock deleted migration
|
|
l := core.MigrationsList{}
|
|
l.Register(func(app core.App) error {
|
|
return nil
|
|
}, func(app core.App) error {
|
|
return nil
|
|
}, "1_test")
|
|
l.Register(func(app core.App) error {
|
|
return nil
|
|
}, func(app core.App) error {
|
|
return nil
|
|
}, "3_test")
|
|
|
|
r := core.NewMigrationsRunner(app, l)
|
|
|
|
if err := r.RemoveMissingAppliedMigrations(); err != nil {
|
|
t.Fatalf("Failed to remove missing applied migrations: %v", err)
|
|
}
|
|
|
|
if isMigrationApplied(app, "2_test") {
|
|
t.Fatalf("Expected 2_test migration to NOT be applied")
|
|
}
|
|
}
|
|
|
|
func isMigrationApplied(app core.App, file string) bool {
|
|
var exists bool
|
|
|
|
err := app.DB().Select("count(*)").
|
|
From(core.DefaultMigrationsTable).
|
|
Where(dbx.HashExp{"file": file}).
|
|
Limit(1).
|
|
Row(&exists)
|
|
|
|
return err == nil && exists
|
|
}
|
|
|
|
// // -------------------------------------------------------------------
|
|
|
|
// type testDB struct {
|
|
// *dbx.DB
|
|
// CalledQueries []string
|
|
// }
|
|
|
|
// // NB! Don't forget to call `db.Close()` at the end of the test.
|
|
// func createTestDB() (*testDB, error) {
|
|
// sqlDB, err := sql.Open("sqlite", ":memory:")
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// db := testDB{DB: dbx.NewFromDB(sqlDB, "sqlite")}
|
|
// db.QueryLogFunc = func(ctx context.Context, t time.Duration, sql string, rows *sql.Rows, err error) {
|
|
// db.CalledQueries = append(db.CalledQueries, sql)
|
|
// }
|
|
// db.ExecLogFunc = func(ctx context.Context, t time.Duration, sql string, result sql.Result, err error) {
|
|
// db.CalledQueries = append(db.CalledQueries, sql)
|
|
// }
|
|
|
|
// return &db, nil
|
|
// }
|