From 0bfc18f7353837b389a19dd7356e1e1a56fde4c1 Mon Sep 17 00:00:00 2001 From: Miguel de la Cruz Date: Fri, 12 Aug 2022 16:34:23 +0200 Subject: [PATCH 1/2] Add RunInterceptor test helper and update MigrateToStep ones --- foundation.go | 59 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/foundation.go b/foundation.go index 427d06d..1587bd7 100644 --- a/foundation.go +++ b/foundation.go @@ -22,6 +22,7 @@ type Migrator interface { DriverName() string Setup() error MigrateToStep(step int) error + Interceptors() map[int]Interceptor TearDown() error } @@ -40,12 +41,15 @@ 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, - db: db, + stepByStep: false, + migrator: migrator, + interceptors: migrator.Interceptors(), + 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 @@ -83,7 +87,7 @@ func (f *Foundation) calculateNextStep(step int) int { return i } -func (f *Foundation) MigrateToStep(step int) *Foundation { +func (f *Foundation) migrateToStep(step int, skipLastInterceptor bool) *Foundation { if step == f.currentStep { // log nothing to do return f @@ -95,7 +99,7 @@ func (f *Foundation) MigrateToStep(step int) *Foundation { // if there are no interceptors, just migrate to the last step if f.interceptors == nil { - if err := f.migrateToStep(step); err != nil { + if err := f.doMigrateToStep(step); err != nil { f.t.Fatalf("migration to step %d failed: %s", step, err) } @@ -105,14 +109,20 @@ func (f *Foundation) MigrateToStep(step int) *Foundation { for f.currentStep < step { nextStep := f.calculateNextStep(step) - if err := f.migrateToStep(nextStep); err != nil { + if err := f.doMigrateToStep(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", nextStep) + f.t.Fatalf("interceptor function for step %d failed: %s", nextStep, err) } } } @@ -120,11 +130,42 @@ func (f *Foundation) MigrateToStep(step int) *Foundation { return f } -// migrateToStep executes the migrator function to migrate to a +// 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 // 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) migrateToStep(step int) error { +func (f *Foundation) doMigrateToStep(step int) error { if f.stepByStep { for f.currentStep < step { if err := f.migrator.MigrateToStep(f.currentStep + 1); err != nil { From 29ac8f6f33a3de34ff906b0b46954a112389956a Mon Sep 17 00:00:00 2001 From: Miguel de la Cruz Date: Fri, 12 Aug 2022 16:55:21 +0200 Subject: [PATCH 2/2] Update README with the new library API --- README.md | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 79d03a7..3f93520 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ type Migrator interface { DriverName() string Setup() error MigrateToStep(step int) error + Interceptors() map[int]Interceptor TearDown() error } @@ -39,7 +40,6 @@ your assertions: ```go t.Run("migration should link book 1 with its author", func(t *testing.T) { f := foundation.New(t, migrator). - RegisterInterceptors(interceptors). // runs migrations up to and including 5 MigrateToStep(5). // loads the SQL of the file @@ -48,14 +48,21 @@ t.Run("migration should link book 1 with its author", func(t *testing.T) { MigrateToStep(6) defer f.TearDown() - book := struct{ - ID int - AuthorID int - }{} + book := struct{ID int; AuthorID int}{} - err = f.DB().Get(&book, "SELECT id, authorID FROM books") + 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() + + // ... +}) ```