From 442bd52013f2ffd86877ae58512f6756e8316336 Mon Sep 17 00:00:00 2001 From: Jay Pipes Date: Tue, 18 Jun 2024 10:51:00 -0400 Subject: [PATCH] add `error` return to `Fixture.Start()` In order to better handle setup failures in fixtures, the `fixture.Start()` interface method should return `error`. Issue #28 Signed-off-by: Jay Pipes --- context/context_test.go | 2 +- fixture/generic.go | 9 +++++---- fixture/generic_test.go | 3 ++- fixture/json/json.go | 2 +- scenario/run.go | 4 +++- scenario/run_test.go | 20 ++++++++++++++++++++ scenario/stub_fixtures_test.go | 22 ++++++++++++++++++++++ scenario/testdata/fixture-start-error.yaml | 7 +++++++ types/fixture.go | 2 +- 9 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 scenario/stub_fixtures_test.go create mode 100644 scenario/testdata/fixture-start-error.yaml diff --git a/context/context_test.go b/context/context_test.go index 82fe57f..6259926 100644 --- a/context/context_test.go +++ b/context/context_test.go @@ -16,7 +16,7 @@ import ( "gopkg.in/yaml.v3" ) -func fooStart(_ context.Context) {} +func fooStart(_ context.Context) error { return nil } type fooDefaults struct { Foo string `yaml:"foo"` diff --git a/fixture/generic.go b/fixture/generic.go index 84c455b..f1102ff 100644 --- a/fixture/generic.go +++ b/fixture/generic.go @@ -13,16 +13,17 @@ import ( // genericFixture adapts functions and state dicts into the Fixture type type genericFixture struct { - starter func(context.Context) + starter func(context.Context) error stopper func(context.Context) state map[string]interface{} } // Start sets up any resources the fixture uses -func (f *genericFixture) Start(ctx context.Context) { +func (f *genericFixture) Start(ctx context.Context) error { if f.starter != nil { - f.starter(ctx) + return f.starter(ctx) } + return nil } // Stop cleans up any resources the fixture uses @@ -55,7 +56,7 @@ func (f *genericFixture) State(key string) interface{} { type genericFixtureModifier func(s *genericFixture) // WithStarter allows a starter functor to be adapted into a fixture -func WithStarter(starter func(context.Context)) genericFixtureModifier { +func WithStarter(starter func(context.Context) error) genericFixtureModifier { return func(f *genericFixture) { f.starter = starter } diff --git a/fixture/generic_test.go b/fixture/generic_test.go index 48c73ac..95e2b37 100644 --- a/fixture/generic_test.go +++ b/fixture/generic_test.go @@ -36,8 +36,9 @@ func TestStarter(t *testing.T) { started := false - starter := func(_ context.Context) { + starter := func(_ context.Context) error { started = true + return nil } f := fixture.New( diff --git a/fixture/json/json.go b/fixture/json/json.go index 1a4629f..b034106 100644 --- a/fixture/json/json.go +++ b/fixture/json/json.go @@ -19,7 +19,7 @@ type jsonFixture struct { data interface{} } -func (f *jsonFixture) Start(_ context.Context) {} +func (f *jsonFixture) Start(_ context.Context) error { return nil } func (f *jsonFixture) Stop(_ context.Context) {} diff --git a/scenario/run.go b/scenario/run.go index c31f796..7d0948b 100644 --- a/scenario/run.go +++ b/scenario/run.go @@ -32,7 +32,9 @@ func (s *Scenario) Run(ctx context.Context, t *testing.T) error { if !found { return gdterrors.RequiredFixtureMissing(fname) } - fix.Start(ctx) + if err := fix.Start(ctx); err != nil { + return err + } defer fix.Stop(ctx) } } diff --git a/scenario/run_test.go b/scenario/run_test.go index 842461d..7d98d23 100644 --- a/scenario/run_test.go +++ b/scenario/run_test.go @@ -67,6 +67,26 @@ func TestMissingFixtures(t *testing.T) { assert.ErrorIs(err, gdterrors.RuntimeError) } +func TestFixtureStartError(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + + fp := filepath.Join("testdata", "fixture-start-error.yaml") + f, err := os.Open(fp) + require.Nil(err) + + s, err := scenario.FromReader(f, scenario.WithPath(fp)) + require.Nil(err) + require.NotNil(s) + + ctx := gdtcontext.New() + ctx = gdtcontext.RegisterFixture(ctx, "start-error", errStarterFixture) + + err = s.Run(ctx, t) + assert.NotNil(err) + assert.ErrorContains(err, "error starting fixture!") +} + func TestDebugFlushing(t *testing.T) { require := require.New(t) diff --git a/scenario/stub_fixtures_test.go b/scenario/stub_fixtures_test.go new file mode 100644 index 0000000..4875b46 --- /dev/null +++ b/scenario/stub_fixtures_test.go @@ -0,0 +1,22 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. + +package scenario_test + +import ( + "context" + "fmt" + + "github.com/gdt-dev/gdt/fixture" +) + +var ( + errStarter = func(_ context.Context) error { + return fmt.Errorf("error starting fixture!") + } + + errStarterFixture = fixture.New( + fixture.WithStarter(errStarter), + ) +) diff --git a/scenario/testdata/fixture-start-error.yaml b/scenario/testdata/fixture-start-error.yaml new file mode 100644 index 0000000..2c625a0 --- /dev/null +++ b/scenario/testdata/fixture-start-error.yaml @@ -0,0 +1,7 @@ +name: fixture-start-error +description: a scenario with a fixture that errors in start +fixtures: + - start-error +tests: + - foo: bar + diff --git a/types/fixture.go b/types/fixture.go index d421d78..8cb4b7a 100644 --- a/types/fixture.go +++ b/types/fixture.go @@ -9,7 +9,7 @@ import "context" // A Fixture allows state to be passed from setups type Fixture interface { // Start sets up the fixture - Start(context.Context) + Start(context.Context) error // Stop tears down the fixture, cleaning up any owned resources Stop(context.Context) // HasState returns true if the fixture contains some state with the given