Skip to content

Commit

Permalink
e2e: add
Browse files Browse the repository at this point in the history
fixes: classic down now is working
  • Loading branch information
alexisvisco committed May 19, 2024
1 parent 013406d commit eb04052
Show file tree
Hide file tree
Showing 26 changed files with 1,389 additions and 122 deletions.
257 changes: 257 additions & 0 deletions e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package main

import (
"database/sql"
"fmt"
"github.com/alexisvisco/amigo/pkg/amigo"
"github.com/alexisvisco/amigo/pkg/schema"
"github.com/alexisvisco/amigo/pkg/types"
"github.com/alexisvisco/amigo/pkg/utils"
"github.com/alexisvisco/amigo/pkg/utils/testutils"
migrationswithchange "github.com/alexisvisco/amigo/testdata/e2e/pg/migrations_with_change"
migrationwithclassic "github.com/alexisvisco/amigo/testdata/e2e/pg/migrations_with_classic"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"path"
"testing"
"time"
)

var (
greenColor = "\033[32m"
resetColor = "\033[0m"
)

func Test_2e2_postgres(t *testing.T) {
var (
postgresUser = testutils.EnvOrDefault("POSTGRES_USER", "postgres")
postgresPass = testutils.EnvOrDefault("POSTGRES_PASS", "postgres")
postgresHost = testutils.EnvOrDefault("POSTGRES_HOST", "localhost")
postgresPort = testutils.EnvOrDefault("POSTGRES_PORT", "6666")
postgresDB = testutils.EnvOrDefault("POSTGRES_DB", "postgres")

db = schema.DatabaseCredentials{
User: postgresUser,
Pass: postgresPass,
Host: postgresHost,
Port: postgresPort,
DB: postgresDB,
}

conn = fmt.Sprintf("postgres://%s:%s@%s:%s/%s", postgresUser, postgresPass, postgresHost, postgresPort,
postgresDB)
)

connection, _, _ := amigo.GetConnection(conn)
defer connection.Close()

t.Run("migration_with_change", func(t *testing.T) {
s := "migrations_with_change"

base := amigo.RunMigrationOptions{
DSN: conn,
SchemaVersionTable: "migrations_with_change.mig_schema_versions",
Timeout: time.Minute * 2,
Migrations: migrationswithchange.Migrations,
//ShowSQL: true,
}

createSchema(t, connection, s)

ensureMigrationsAreReversible(t, base, db, s)
})

t.Run("migration_with_classic", func(t *testing.T) {
s := "migrations_with_classic"

base := amigo.RunMigrationOptions{
DSN: conn,
SchemaVersionTable: "migrations_with_classic.mig_schema_versions",
Timeout: time.Minute * 2,
Migrations: migrationwithclassic.Migrations,
//ShowSQL: true,
}

createSchema(t, connection, s)

ensureMigrationsAreReversible(t, base, db, s)
})

}

func createSchema(t *testing.T, connection *sql.DB, s string) {
_, err := connection.Exec("DROP SCHEMA IF EXISTS " + s + " CASCADE")
require.NoError(t, err)
_, err = connection.Exec("CREATE SCHEMA " + s)
require.NoError(t, err)
}

// ensureMigrationsAreReversible ensures that all migrations are reversible and works nice.
// for each migrations :
// up then do a snapshot
// rollback if it's not the first migration, check with the previous snapshot
// up again and compare the snapshot with the captured snapshot
// this until the last migration
//
// then rollback all migrations, check the snapshot with the first one
// then up all migrations, check the snapshot with the last one
func ensureMigrationsAreReversible(t *testing.T, base amigo.RunMigrationOptions, db schema.DatabaseCredentials, s string) {
for i := 0; i < len(migrationswithchange.Migrations); i++ {

fmt.Println()
fmt.Println(greenColor, "Running migration", migrationswithchange.Migrations[i].Name(), resetColor)
fmt.Println()

version := migrationswithchange.Migrations[i].Date().UTC().Format(utils.FormatTime)
id := path.Join(s, fmt.Sprintf("%s_%s", version, migrationswithchange.Migrations[i].Name()))

ok, err := amigo.RunPostgresMigrations(mergeOptions(base, amigo.RunMigrationOptions{
MigrationDirection: types.MigrationDirectionUp,
Version: utils.Ptr(version),
}))

assert.True(t, ok, "migration %s failed", migrationswithchange.Migrations[i].Name())
assert.NoError(t, err, "migration %s failed", migrationswithchange.Migrations[i].Name())

testutils.MaySnapshotSavePgDump(t, s, db, id, false)

if i == 0 {
continue
}

ok, err = amigo.RunPostgresMigrations(mergeOptions(base, amigo.RunMigrationOptions{
MigrationDirection: types.MigrationDirectionDown,
}))

assert.True(t, ok, "rollback migration %s failed", migrationswithchange.Migrations[i].Name())
assert.NoError(t, err, "rollback migration %s failed", migrationswithchange.Migrations[i].Name())

oldVersion := migrationswithchange.Migrations[i-1].Date().UTC().Format(utils.FormatTime)
oldId := path.Join(s, fmt.Sprintf("%s_%s", oldVersion, migrationswithchange.Migrations[i-1].Name()))

testutils.AssertSnapshotPgDumpDiff(t, s, db, oldId)

// here we have verified that the rollback is correct

ok, err = amigo.RunPostgresMigrations(mergeOptions(base, amigo.RunMigrationOptions{
MigrationDirection: types.MigrationDirectionUp,
Version: utils.Ptr(migrationswithchange.Migrations[i].Date().UTC().Format(utils.FormatTime)),
}))

assert.True(t, ok, "migration %s failed", migrationswithchange.Migrations[i].Name())
assert.NoError(t, err, "migration %s failed", migrationswithchange.Migrations[i].Name())

testutils.AssertSnapshotPgDumpDiff(t, s, db, id)

// here we have verified that the up is correct with the previous rollback
}

fmt.Println()
fmt.Println(greenColor, "Rollback all migrations", resetColor)
fmt.Println()

ok, err := amigo.RunPostgresMigrations(mergeOptions(base, amigo.RunMigrationOptions{
MigrationDirection: types.MigrationDirectionDown,
Steps: utils.Ptr(len(migrationswithchange.Migrations) - 1),
}))

assert.True(t, ok, "rollback all migrations failed")
assert.NoError(t, err, "rollback all migrations failed")

firstVersion := migrationswithchange.Migrations[0].Date().UTC().Format(utils.FormatTime)
firstId := path.Join(s, fmt.Sprintf("%s_%s", firstVersion, migrationswithchange.Migrations[0].Name()))
testutils.AssertSnapshotPgDumpDiff(t, s, db, firstId)

fmt.Println()
fmt.Println(greenColor, "Up all migrations", resetColor)
fmt.Println()

ok, err = amigo.RunPostgresMigrations(mergeOptions(base, amigo.RunMigrationOptions{
MigrationDirection: types.MigrationDirectionUp,
}))

assert.True(t, ok, "up all migrations failed")
assert.NoError(t, err, "up all migrations failed")

lastVersion := migrationswithchange.Migrations[len(migrationswithchange.Migrations)-1].Date().UTC().Format(utils.FormatTime)
lastId := path.Join(s, fmt.Sprintf("%s_%s", lastVersion,
migrationswithchange.Migrations[len(migrationswithchange.Migrations)-1].Name()))

testutils.AssertSnapshotPgDumpDiff(t, s, db, lastId)

// here we have verified that the up all is correct
}

func mergeOptions(b amigo.RunMigrationOptions, options ...amigo.RunMigrationOptions) *amigo.RunMigrationOptions {
base := amigo.RunMigrationOptions{
DSN: b.DSN,
MigrationDirection: b.MigrationDirection,
Version: b.Version,
Steps: b.Steps,
SchemaVersionTable: b.SchemaVersionTable,
DryRun: b.DryRun,
ContinueOnError: b.ContinueOnError,
Timeout: b.Timeout,
Migrations: b.Migrations,
JSON: b.JSON,
ShowSQL: b.ShowSQL,
Debug: b.Debug,
Shell: b.Shell,
}

for _, opt := range options {
if opt.DSN != "" {
base.DSN = opt.DSN
}

if opt.SchemaVersionTable != "" {
base.SchemaVersionTable = opt.SchemaVersionTable
}

if opt.Timeout != 0 {
base.Timeout = opt.Timeout
}

if opt.Migrations != nil {
base.Migrations = opt.Migrations
}

if opt.ShowSQL {
base.ShowSQL = opt.ShowSQL
}

if opt.Debug {
base.Debug = opt.Debug
}

if opt.JSON {
base.JSON = opt.JSON
}

if opt.DryRun {
base.DryRun = opt.DryRun
}

if opt.ContinueOnError {
base.ContinueOnError = opt.ContinueOnError
}

if opt.Version != nil {
base.Version = opt.Version
}

if opt.Steps != nil {
base.Steps = opt.Steps
}

if opt.Shell != "" {
base.Shell = opt.Shell
}

if opt.MigrationDirection != "" {
base.MigrationDirection = opt.MigrationDirection
}
}

return &base
}
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ require (
github.com/georgysavva/scany/v2 v2.1.3
github.com/gobuffalo/flect v1.0.2
github.com/jackc/pgx/v5 v5.5.5
github.com/lmittmann/tint v1.0.4
github.com/sergi/go-diff v1.3.1
github.com/simukti/sqldb-logger v0.0.0-20230108155151-646c1a075551
github.com/spf13/cobra v1.8.0
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
Expand Down
7 changes: 7 additions & 0 deletions pkg/amigo/run_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ func RunPostgresMigrations(options *RunMigrationOptions) (bool, error) {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(options.Timeout))
defer cancel()

oldLogger := slog.Default()
defer func() {
slog.SetDefault(oldLogger)
}()

SetupSlog(options.ShowSQL, options.Debug, options.JSON, os.Stdout)

migrator := schema.NewMigrator(ctx, conn, pg.NewPostgres, &schema.MigratorOption{
DryRun: options.DryRun,
ContinueOnError: options.ContinueOnError,
Expand Down
24 changes: 14 additions & 10 deletions pkg/schema/migrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,22 +49,22 @@ type SimpleMigration[T Schema] interface {
Date() time.Time
}

type SchemaFactory[T Schema] func(*MigratorContext, DB) T
type Factory[T Schema] func(*MigratorContext, DB) T

// Migrator applies the migrations.
type Migrator[T Schema] struct {
db *sql.DB
ctx *MigratorContext

schemaFactory SchemaFactory[T]
schemaFactory Factory[T]
migrations []func(T)
}

// NewMigrator creates a new migrator.
func NewMigrator[T Schema](
ctx context.Context,
db *sql.DB,
schemaFactory SchemaFactory[T],
schemaFactory Factory[T],
opts *MigratorOption,
) *Migrator[T] {
return &Migrator[T]{
Expand Down Expand Up @@ -109,7 +109,7 @@ func (m *Migrator[T]) Apply(direction types.MigrationDirection, version *string,
switch direction {
case types.MigrationDirectionUp:
migrationFunc = t.Up
case types.MigrationDirectionDown:
case types.MigrationDirectionDown, types.MigrationDirectionNotReversible:
direction = types.MigrationDirectionNotReversible
migrationFunc = t.Down
}
Expand All @@ -124,10 +124,16 @@ func (m *Migrator[T]) Apply(direction types.MigrationDirection, version *string,
switch direction {
case types.MigrationDirectionUp:
logger.Info(events.MigrateUpEvent{MigrationName: migration.Name(), Time: migration.Date()})
case types.MigrationDirectionDown:
case types.MigrationDirectionDown, types.MigrationDirectionNotReversible:
logger.Info(events.MigrateDownEvent{MigrationName: migration.Name(), Time: migration.Date()})
}

if migrationFunc == nil {
logger.Error(events.MessageEvent{Message: fmt.Sprintf("Migration %s is not a valid migration",
migration.Name())})
return false
}

if !m.run(direction, fmt.Sprint(migration.Date().UTC().Format(utils.FormatTime)), migrationFunc) {
return false
}
Expand Down Expand Up @@ -156,7 +162,7 @@ func (m *Migrator[T]) findMigrationsToExecute(
switch migrationDirection {
case types.MigrationDirectionUp:
if version != nil && *version != "" {
if versionToMigration[*version] == nil {
if _, ok := versionToMigration[*version]; !ok {
m.ctx.RaiseError(fmt.Errorf("version %s not found", *version))
}

Expand All @@ -175,7 +181,7 @@ func (m *Migrator[T]) findMigrationsToExecute(
}
case types.MigrationDirectionDown:
if version != nil && *version != "" {
if versionToMigration[*version] == nil {
if _, ok := versionToMigration[*version]; !ok {
m.ctx.RaiseError(fmt.Errorf("version %s not found", *version))
}

Expand Down Expand Up @@ -208,7 +214,6 @@ func (m *Migrator[T]) findMigrationsToExecute(

// run runs the migration.
func (m *Migrator[T]) run(migrationType types.MigrationDirection, version string, f func(T)) (ok bool) {

currentContext := m.ctx
currentContext.MigrationDirection = migrationType

Expand Down Expand Up @@ -241,11 +246,10 @@ func (m *Migrator[T]) run(migrationType types.MigrationDirection, version string

f(schema)

fmt.Println("Migration type ", migrationType)
switch migrationType {
case types.MigrationDirectionUp:
schema.AddVersion(version)
case types.MigrationDirectionDown:
case types.MigrationDirectionDown, types.MigrationDirectionNotReversible:
schema.RemoveVersion(version)
}

Expand Down
8 changes: 7 additions & 1 deletion pkg/schema/pg/postgres_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,13 @@ func (p *Schema) DropIndex(table schema.TableName, columns []string, opt ...sche
return ""
},

"index_name": utils.StrFunc(options.IndexName),
"index_name": func() string {
if table.HasSchema() {
return fmt.Sprintf(`%s.%s`, table.Schema(), options.IndexName)
}

return options.IndexName
},
}

_, err := p.DB.ExecContext(p.Context.Context, replacer.Replace(sql))
Expand Down
Loading

0 comments on commit eb04052

Please sign in to comment.