mirror of https://github.com/pressly/goose.git
268 lines
8.8 KiB
Go
268 lines
8.8 KiB
Go
package goose
|
|
|
|
import (
|
|
"io/fs"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestMigrationSort(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ms := Migrations{}
|
|
|
|
// insert in any order
|
|
ms = append(ms, newMigration(20120000, "test"))
|
|
ms = append(ms, newMigration(20128000, "test"))
|
|
ms = append(ms, newMigration(20129000, "test"))
|
|
ms = append(ms, newMigration(20127000, "test"))
|
|
|
|
ms = sortAndConnectMigrations(ms)
|
|
|
|
sorted := []int64{20120000, 20127000, 20128000, 20129000}
|
|
|
|
validateMigrationSort(t, ms, sorted)
|
|
}
|
|
|
|
func newMigration(v int64, src string) *Migration {
|
|
return &Migration{Version: v, Previous: -1, Next: -1, Source: src}
|
|
}
|
|
|
|
func validateMigrationSort(t *testing.T, ms Migrations, sorted []int64) {
|
|
t.Helper()
|
|
for i, m := range ms {
|
|
if sorted[i] != m.Version {
|
|
t.Error("incorrect sorted version")
|
|
}
|
|
|
|
var next, prev int64
|
|
|
|
if i == 0 {
|
|
prev = -1
|
|
next = ms[i+1].Version
|
|
} else if i == len(ms)-1 {
|
|
prev = ms[i-1].Version
|
|
next = -1
|
|
} else {
|
|
prev = ms[i-1].Version
|
|
next = ms[i+1].Version
|
|
}
|
|
|
|
if m.Next != next {
|
|
t.Errorf("mismatched Next. v: %v, got %v, wanted %v\n", m, m.Next, next)
|
|
}
|
|
|
|
if m.Previous != prev {
|
|
t.Errorf("mismatched Previous v: %v, got %v, wanted %v\n", m, m.Previous, prev)
|
|
}
|
|
}
|
|
|
|
t.Log(ms)
|
|
}
|
|
|
|
func TestCollectMigrations(t *testing.T) {
|
|
// Not safe to run in parallel
|
|
t.Run("no_migration_files_found", func(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
err := os.MkdirAll(filepath.Join(tmp, "migrations-test"), 0755)
|
|
require.NoError(t, err)
|
|
_, err = collectMigrationsFS(os.DirFS(tmp), "migrations-test", 0, math.MaxInt64, nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "no migration files found")
|
|
})
|
|
t.Run("filesystem_registered_with_single_dirpath", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
file1, file2 := "09081_a.go", "09082_b.go"
|
|
file3, file4 := "19081_a.go", "19082_b.go"
|
|
AddNamedMigrationContext(file1, nil, nil)
|
|
AddNamedMigrationContext(file2, nil, nil)
|
|
require.Len(t, registeredGoMigrations, 2)
|
|
tmp := t.TempDir()
|
|
dir := filepath.Join(tmp, "migrations", "dir1")
|
|
err := os.MkdirAll(dir, 0755)
|
|
require.NoError(t, err)
|
|
createEmptyFile(t, dir, file1)
|
|
createEmptyFile(t, dir, file2)
|
|
createEmptyFile(t, dir, file3)
|
|
createEmptyFile(t, dir, file4)
|
|
fsys := os.DirFS(tmp)
|
|
files, err := fs.ReadDir(fsys, "migrations/dir1")
|
|
require.NoError(t, err)
|
|
require.Len(t, files, 4)
|
|
all, err := collectMigrationsFS(fsys, "migrations/dir1", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 4)
|
|
require.EqualValues(t, 9081, all[0].Version)
|
|
require.EqualValues(t, 9082, all[1].Version)
|
|
require.EqualValues(t, 19081, all[2].Version)
|
|
require.EqualValues(t, 19082, all[3].Version)
|
|
})
|
|
t.Run("filesystem_registered_with_multiple_dirpath", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
file1, file2, file3 := "00001_a.go", "00002_b.go", "01111_c.go"
|
|
AddNamedMigrationContext(file1, nil, nil)
|
|
AddNamedMigrationContext(file2, nil, nil)
|
|
AddNamedMigrationContext(file3, nil, nil)
|
|
require.Len(t, registeredGoMigrations, 3)
|
|
tmp := t.TempDir()
|
|
dir1 := filepath.Join(tmp, "migrations", "dir1")
|
|
dir2 := filepath.Join(tmp, "migrations", "dir2")
|
|
err := os.MkdirAll(dir1, 0755)
|
|
require.NoError(t, err)
|
|
err = os.MkdirAll(dir2, 0755)
|
|
require.NoError(t, err)
|
|
createEmptyFile(t, dir1, file1)
|
|
createEmptyFile(t, dir1, file2)
|
|
createEmptyFile(t, dir2, file3)
|
|
fsys := os.DirFS(tmp)
|
|
// Validate if dirpath 1 is specified we get the two Go migrations in migrations/dir1 folder
|
|
// even though 3 Go migrations have been registered.
|
|
{
|
|
all, err := collectMigrationsFS(fsys, "migrations/dir1", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 2)
|
|
require.EqualValues(t, 1, all[0].Version)
|
|
require.EqualValues(t, 2, all[1].Version)
|
|
}
|
|
// Validate if dirpath 2 is specified we only get the one Go migration in migrations/dir2 folder
|
|
// even though 3 Go migrations have been registered.
|
|
{
|
|
all, err := collectMigrationsFS(fsys, "migrations/dir2", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 1)
|
|
require.EqualValues(t, 1111, all[0].Version)
|
|
}
|
|
})
|
|
t.Run("empty_filesystem_registered_manually", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
AddNamedMigrationContext("00101_a.go", nil, nil)
|
|
AddNamedMigrationContext("00102_b.go", nil, nil)
|
|
require.Len(t, registeredGoMigrations, 2)
|
|
tmp := t.TempDir()
|
|
err := os.MkdirAll(filepath.Join(tmp, "migrations"), 0755)
|
|
require.NoError(t, err)
|
|
all, err := collectMigrationsFS(os.DirFS(tmp), "migrations", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 2)
|
|
require.EqualValues(t, 101, all[0].Version)
|
|
require.EqualValues(t, 102, all[1].Version)
|
|
})
|
|
t.Run("unregistered_go_migrations", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
file1, file2, file3 := "00001_a.go", "00998_b.go", "00999_c.go"
|
|
// Only register file1 and file3, somehow user forgot to init in the
|
|
// valid looking file2 Go migration
|
|
AddNamedMigrationContext(file1, nil, nil)
|
|
AddNamedMigrationContext(file3, nil, nil)
|
|
require.Len(t, registeredGoMigrations, 2)
|
|
tmp := t.TempDir()
|
|
dir1 := filepath.Join(tmp, "migrations", "dir1")
|
|
err := os.MkdirAll(dir1, 0755)
|
|
require.NoError(t, err)
|
|
// Include the valid file2 with file1, file3. But remember, it has NOT been
|
|
// registered.
|
|
createEmptyFile(t, dir1, file1)
|
|
createEmptyFile(t, dir1, file2)
|
|
createEmptyFile(t, dir1, file3)
|
|
all, err := collectMigrationsFS(os.DirFS(tmp), "migrations/dir1", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 3)
|
|
require.EqualValues(t, 1, all[0].Version)
|
|
require.True(t, all[0].Registered)
|
|
require.EqualValues(t, 998, all[1].Version)
|
|
// This migrations is marked unregistered and will lazily raise an error if/when this
|
|
// migration is run
|
|
require.False(t, all[1].Registered)
|
|
require.EqualValues(t, 999, all[2].Version)
|
|
require.True(t, all[2].Registered)
|
|
})
|
|
t.Run("with_skipped_go_files", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
file1, file2, file3, file4 := "00001_a.go", "00002_b.sql", "00999_c_test.go", "embed.go"
|
|
AddNamedMigrationContext(file1, nil, nil)
|
|
require.Len(t, registeredGoMigrations, 1)
|
|
tmp := t.TempDir()
|
|
dir1 := filepath.Join(tmp, "migrations", "dir1")
|
|
err := os.MkdirAll(dir1, 0755)
|
|
require.NoError(t, err)
|
|
createEmptyFile(t, dir1, file1)
|
|
createEmptyFile(t, dir1, file2)
|
|
createEmptyFile(t, dir1, file3)
|
|
createEmptyFile(t, dir1, file4)
|
|
all, err := collectMigrationsFS(os.DirFS(tmp), "migrations/dir1", 0, math.MaxInt64, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 2)
|
|
require.EqualValues(t, 1, all[0].Version)
|
|
require.True(t, all[0].Registered)
|
|
require.EqualValues(t, 2, all[1].Version)
|
|
require.False(t, all[1].Registered)
|
|
})
|
|
t.Run("current_and_target", func(t *testing.T) {
|
|
t.Cleanup(func() { clearMap(registeredGoMigrations) })
|
|
file1, file2, file3 := "01001_a.go", "01002_b.sql", "01003_c.go"
|
|
AddNamedMigrationContext(file1, nil, nil)
|
|
AddNamedMigrationContext(file3, nil, nil)
|
|
require.Len(t, registeredGoMigrations, 2)
|
|
tmp := t.TempDir()
|
|
dir1 := filepath.Join(tmp, "migrations", "dir1")
|
|
err := os.MkdirAll(dir1, 0755)
|
|
require.NoError(t, err)
|
|
createEmptyFile(t, dir1, file1)
|
|
createEmptyFile(t, dir1, file2)
|
|
createEmptyFile(t, dir1, file3)
|
|
all, err := collectMigrationsFS(os.DirFS(tmp), "migrations/dir1", 1001, 1003, registeredGoMigrations)
|
|
require.NoError(t, err)
|
|
require.Len(t, all, 2)
|
|
require.EqualValues(t, 1002, all[0].Version)
|
|
require.EqualValues(t, 1003, all[1].Version)
|
|
})
|
|
}
|
|
|
|
func TestVersionFilter(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
v int64
|
|
current int64
|
|
target int64
|
|
want bool
|
|
}{
|
|
{2, 1, 3, true}, // v is within the range
|
|
{4, 1, 3, false}, // v is outside the range
|
|
{2, 3, 1, true}, // v is within the reversed range
|
|
{4, 3, 1, false}, // v is outside the reversed range
|
|
{3, 1, 3, true}, // v is equal to target
|
|
{1, 1, 3, false}, // v is equal to current, not within the range
|
|
{1, 3, 1, false}, // v is equal to current, not within the reversed range
|
|
// Always return false if current equal target
|
|
{1, 2, 2, false},
|
|
{2, 2, 2, false},
|
|
{3, 2, 2, false},
|
|
}
|
|
for _, tc := range tests {
|
|
t.Run("", func(t *testing.T) {
|
|
got := versionFilter(tc.v, tc.current, tc.target)
|
|
if got != tc.want {
|
|
t.Errorf("versionFilter(%d, %d, %d) = %v, want %v", tc.v, tc.current, tc.target, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
func createEmptyFile(t *testing.T, dir, name string) {
|
|
t.Helper()
|
|
path := filepath.Join(dir, name)
|
|
f, err := os.Create(path)
|
|
require.NoError(t, err)
|
|
defer f.Close()
|
|
}
|
|
|
|
func clearMap(m map[int64]*Migration) {
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
}
|