mirror of https://github.com/pressly/goose.git
154 lines
4.5 KiB
Go
154 lines
4.5 KiB
Go
package provider_test
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
"io/fs"
|
|
"path/filepath"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"github.com/pressly/goose/v3/database"
|
|
"github.com/pressly/goose/v3/internal/check"
|
|
"github.com/pressly/goose/v3/internal/provider"
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func TestProvider(t *testing.T) {
|
|
dir := t.TempDir()
|
|
db, err := sql.Open("sqlite", filepath.Join(dir, "sql_embed.db"))
|
|
check.NoError(t, err)
|
|
t.Run("empty", func(t *testing.T) {
|
|
_, err := provider.NewProvider(database.DialectSQLite3, db, fstest.MapFS{})
|
|
check.HasError(t, err)
|
|
check.Bool(t, errors.Is(err, provider.ErrNoMigrations), true)
|
|
})
|
|
|
|
mapFS := fstest.MapFS{
|
|
"migrations/001_foo.sql": {Data: []byte(`-- +goose Up`)},
|
|
"migrations/002_bar.sql": {Data: []byte(`-- +goose Up`)},
|
|
}
|
|
fsys, err := fs.Sub(mapFS, "migrations")
|
|
check.NoError(t, err)
|
|
p, err := provider.NewProvider(database.DialectSQLite3, db, fsys)
|
|
check.NoError(t, err)
|
|
sources := p.ListSources()
|
|
check.Equal(t, len(sources), 2)
|
|
check.Equal(t, sources[0], newSource(provider.TypeSQL, "001_foo.sql", 1))
|
|
check.Equal(t, sources[1], newSource(provider.TypeSQL, "002_bar.sql", 2))
|
|
|
|
t.Run("duplicate_go", func(t *testing.T) {
|
|
// Not parallel because it modifies global state.
|
|
register := []*provider.MigrationCopy{
|
|
{
|
|
Version: 1, Source: "00001_users_table.go", Registered: true,
|
|
UpFnContext: nil,
|
|
DownFnContext: nil,
|
|
},
|
|
}
|
|
err := provider.SetGlobalGoMigrations(register)
|
|
check.NoError(t, err)
|
|
t.Cleanup(provider.ResetGlobalGoMigrations)
|
|
|
|
db := newDB(t)
|
|
_, err = provider.NewProvider(database.DialectSQLite3, db, nil,
|
|
provider.WithGoMigration(1, nil, nil),
|
|
)
|
|
check.HasError(t, err)
|
|
check.Equal(t, err.Error(), "go migration with version 1 already registered")
|
|
})
|
|
t.Run("empty_go", func(t *testing.T) {
|
|
db := newDB(t)
|
|
// explicit
|
|
_, err := provider.NewProvider(database.DialectSQLite3, db, nil,
|
|
provider.WithGoMigration(1, &provider.GoMigrationFunc{Run: nil}, &provider.GoMigrationFunc{Run: nil}),
|
|
)
|
|
check.HasError(t, err)
|
|
check.Contains(t, err.Error(), "go migration with version 1 must have an up function")
|
|
})
|
|
t.Run("duplicate_up", func(t *testing.T) {
|
|
err := provider.SetGlobalGoMigrations([]*provider.MigrationCopy{
|
|
{
|
|
Version: 1, Source: "00001_users_table.go", Registered: true,
|
|
UpFnContext: func(context.Context, *sql.Tx) error { return nil },
|
|
UpFnNoTxContext: func(ctx context.Context, db *sql.DB) error { return nil },
|
|
},
|
|
})
|
|
t.Cleanup(provider.ResetGlobalGoMigrations)
|
|
check.HasError(t, err)
|
|
check.Contains(t, err.Error(), "must specify exactly one of UpFnContext or UpFnNoTxContext")
|
|
})
|
|
t.Run("duplicate_down", func(t *testing.T) {
|
|
err := provider.SetGlobalGoMigrations([]*provider.MigrationCopy{
|
|
{
|
|
Version: 1, Source: "00001_users_table.go", Registered: true,
|
|
DownFnContext: func(context.Context, *sql.Tx) error { return nil },
|
|
DownFnNoTxContext: func(ctx context.Context, db *sql.DB) error { return nil },
|
|
},
|
|
})
|
|
t.Cleanup(provider.ResetGlobalGoMigrations)
|
|
check.HasError(t, err)
|
|
check.Contains(t, err.Error(), "must specify exactly one of DownFnContext or DownFnNoTxContext")
|
|
})
|
|
t.Run("not_registered", func(t *testing.T) {
|
|
err := provider.SetGlobalGoMigrations([]*provider.MigrationCopy{
|
|
{
|
|
Version: 1, Source: "00001_users_table.go",
|
|
},
|
|
})
|
|
t.Cleanup(provider.ResetGlobalGoMigrations)
|
|
check.HasError(t, err)
|
|
check.Contains(t, err.Error(), "migration must be registered")
|
|
})
|
|
t.Run("zero_not_allowed", func(t *testing.T) {
|
|
err := provider.SetGlobalGoMigrations([]*provider.MigrationCopy{
|
|
{
|
|
Version: 0,
|
|
},
|
|
})
|
|
t.Cleanup(provider.ResetGlobalGoMigrations)
|
|
check.HasError(t, err)
|
|
check.Contains(t, err.Error(), "migration versions must be greater than zero")
|
|
})
|
|
}
|
|
|
|
var (
|
|
migration1 = `
|
|
-- +goose Up
|
|
CREATE TABLE foo (id INTEGER PRIMARY KEY);
|
|
-- +goose Down
|
|
DROP TABLE foo;
|
|
`
|
|
migration2 = `
|
|
-- +goose Up
|
|
ALTER TABLE foo ADD COLUMN name TEXT;
|
|
-- +goose Down
|
|
ALTER TABLE foo DROP COLUMN name;
|
|
`
|
|
migration3 = `
|
|
-- +goose Up
|
|
CREATE TABLE bar (
|
|
id INTEGER PRIMARY KEY,
|
|
description TEXT
|
|
);
|
|
-- +goose Down
|
|
DROP TABLE bar;
|
|
`
|
|
migration4 = `
|
|
-- +goose Up
|
|
-- Rename the 'foo' table to 'my_foo'
|
|
ALTER TABLE foo RENAME TO my_foo;
|
|
|
|
-- Add a new column 'timestamp' to 'my_foo'
|
|
ALTER TABLE my_foo ADD COLUMN timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
|
|
|
|
-- +goose Down
|
|
-- Remove the 'timestamp' column from 'my_foo'
|
|
ALTER TABLE my_foo DROP COLUMN timestamp;
|
|
|
|
-- Rename the 'my_foo' table back to 'foo'
|
|
ALTER TABLE my_foo RENAME TO foo;
|
|
`
|
|
)
|