diff --git a/README.md b/README.md index 3f93520..3a2e811 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,3 @@ # Foundation -A framework to write simple database migration tests. - -## Install - -``` -go get github.com/mgdelacroix/foundation -``` - -## Usage - -To start using foundation, you need to implement the `Migrator` -interface, describing how your tool manages migrations and what are -the intermediate steps (generally data migrations), if any, that need -to run at the end of each migration step: - -```go -type Migrator interface { - DB() *sql.DB - DriverName() string - Setup() error - MigrateToStep(step int) error - Interceptors() map[int]Interceptor - TearDown() error -} - -interceptors := map[int]Interceptor{ - // function that will run after step 6 - 6: func() err { - return myStore.RunDataMigration() - }, -} -``` - -With the interface implemented, you can use `foundation` in your tests -to load fixtures, set the database on a specific state and then run -your assertions: - -```go -t.Run("migration should link book 1 with its author", func(t *testing.T) { - f := foundation.New(t, migrator). - // runs migrations up to and including 5 - MigrateToStep(5). - // loads the SQL of the file - ExecFile("./myfixtures.sql"). - // runs migration 6 and its interceptor function - MigrateToStep(6) - defer f.TearDown() - - book := struct{ID int; AuthorID int}{} - - err := f.DB().Get(&book, "SELECT id, authorID FROM books") - require.NoError(t, err) - require.Equal(t, 1, book.ID) - require.Equal(t, 3, book.AuthorID) -}) - -t.Run("test specifically the interceptor 6", func(t *testing.T) { - f := foundation.New(t, migrator). - MigrateToStepSkippingLastInterceptor(6). - ExecFile("./myfixtures.sql"). - RunInterceptor(6) - defer f.TearDown() - - // ... -}) -``` +A set of helpers to help to create and manage database migration tests. diff --git a/foundation.go b/foundation.go index 1587bd7..ced5b81 100644 --- a/foundation.go +++ b/foundation.go @@ -1,4 +1,4 @@ -package foundation +package main import ( "database/sql" @@ -22,7 +22,6 @@ type Migrator interface { DriverName() string Setup() error MigrateToStep(step int) error - Interceptors() map[int]Interceptor TearDown() error } @@ -41,15 +40,12 @@ func New(t *testing.T, migrator Migrator) *Foundation { currentStep: 0, // if true, will run the migrator Step function once per step // instead of just once with the final step - stepByStep: false, - migrator: migrator, - interceptors: migrator.Interceptors(), - db: db, + stepByStep: false, + migrator: migrator, + db: db, } } -// RegisterInterceptors replaced the migrator interceptors with new -// ones, in case we want to check a special case for a given test func (f *Foundation) RegisterInterceptors(interceptors map[int]Interceptor) *Foundation { f.interceptors = interceptors return f @@ -76,18 +72,22 @@ func (f *Foundation) calculateNextStep(step int) int { } i := f.currentStep - for i < step { + for { i++ if _, ok := f.interceptors[i]; ok { break } + + if step == i { + break + } } return i } -func (f *Foundation) migrateToStep(step int, skipLastInterceptor bool) *Foundation { +func (f *Foundation) MigrateToStep(step int) *Foundation { if step == f.currentStep { // log nothing to do return f @@ -99,7 +99,7 @@ func (f *Foundation) migrateToStep(step int, skipLastInterceptor bool) *Foundati // if there are no interceptors, just migrate to the last step if f.interceptors == nil { - if err := f.doMigrateToStep(step); err != nil { + if err := f.migrateToStep(step); err != nil { f.t.Fatalf("migration to step %d failed: %s", step, err) } @@ -109,20 +109,14 @@ func (f *Foundation) migrateToStep(step int, skipLastInterceptor bool) *Foundati for f.currentStep < step { nextStep := f.calculateNextStep(step) - if err := f.doMigrateToStep(nextStep); err != nil { + if err := f.migrateToStep(nextStep); err != nil { f.t.Fatalf("migration to step %d failed: %s", nextStep, err) } - // if we want to skip the last interceptor and we're in the - // last step, just continue - if skipLastInterceptor && nextStep == step { - continue - } - interceptorFn, ok := f.interceptors[nextStep] if ok { if err := interceptorFn(); err != nil { - f.t.Fatalf("interceptor function for step %d failed: %s", nextStep, err) + f.t.Fatalf("interceptor function for step %d failed", nextStep) } } } @@ -130,42 +124,11 @@ func (f *Foundation) migrateToStep(step int, skipLastInterceptor bool) *Foundati return f } -// MigrateToStep instructs the migrator to move forward until step is -// reached. While migrating, it will run the interceptors after the -// step they're defined for -func (f *Foundation) MigrateToStep(step int) *Foundation { - return f.migrateToStep(step, false) -} - -// MigrateToStepSkippingLastInterceptor instructs the migrator to move -// forward until step is reached, skipping the last interceptor. This -// is useful if we want to load fixtures on the last step but before -// running the interceptor code, so we can check how that data is -// modified by the interceptor -func (f *Foundation) MigrateToStepSkippingLastInterceptor(step int) *Foundation { - return f.migrateToStep(step, true) -} - -// RunInterceptor executes the code of the interceptor corresponding -// to step -func (f *Foundation) RunInterceptor(step int) *Foundation { - interceptorFn, ok := f.interceptors[step] - if !ok { - f.t.Fatalf("no interceptor found for step %d", step) - } - - if err := interceptorFn(); err != nil { - f.t.Fatalf("interceptor function for step %d failed: %s", step, err) - } - - return f -} - -// doMigrateToStep executes the migrator function to migrate to a +// migrateToStep executes the migrator function to migrate to a // specific step and updates the foundation currentStep to reflect the // result. This function doesn't take into account interceptors, that // happens on MigrateToStep -func (f *Foundation) doMigrateToStep(step int) error { +func (f *Foundation) migrateToStep(step int) error { if f.stepByStep { for f.currentStep < step { if err := f.migrator.MigrateToStep(f.currentStep + 1); err != nil { diff --git a/foundation_test.go b/foundation_test.go index 3cd7c8b..6e825b7 100644 --- a/foundation_test.go +++ b/foundation_test.go @@ -1,4 +1,4 @@ -package foundation +package main import ( "testing" diff --git a/go.mod b/go.mod index b1c9fb4..878bd52 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/mgdelacroix/foundation +module git.ctrlz.es/mgdelacroix/foundation go 1.18 diff --git a/helpers_test.go b/helpers_test.go index 4430949..d1a9d47 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -1,4 +1,4 @@ -package foundation +package main import "database/sql"