fix unit tests and error messages
This commit is contained in:
@@ -87,6 +87,9 @@ func (app *Lifecycle) WithLogger(logger *slog.Logger) *Lifecycle {
|
|||||||
|
|
||||||
// Logger returns the logger for the lifecycle.
|
// Logger returns the logger for the lifecycle.
|
||||||
func (app *Lifecycle) Logger() *slog.Logger {
|
func (app *Lifecycle) Logger() *slog.Logger {
|
||||||
|
if app == nil {
|
||||||
|
panic("lifecycle is nil, cannot get logger")
|
||||||
|
}
|
||||||
if app.opts.Logger == nil {
|
if app.opts.Logger == nil {
|
||||||
app.opts.Logger = slog.Default()
|
app.opts.Logger = slog.Default()
|
||||||
}
|
}
|
||||||
@@ -182,12 +185,16 @@ func (app *Lifecycle) require(logger *slog.Logger, unique bool, modules ...*Modu
|
|||||||
// Check if the module has already been set up
|
// Check if the module has already been set up
|
||||||
if _, ok := app.setupTracker[mod.name]; ok {
|
if _, ok := app.setupTracker[mod.name]; ok {
|
||||||
if unique {
|
if unique {
|
||||||
return fmt.Errorf("module %s is already set up, cannot require it again", mod)
|
return fmt.Errorf("module %s is already set up, cannot require again", mod)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Logger().Warn("module already set up, ignoring", "module", mod)
|
app.Logger().Warn("module already set up, ignoring", "module", mod)
|
||||||
|
|
||||||
|
// Mark duplicate module as loaded
|
||||||
mod.loaded = true
|
mod.loaded = true
|
||||||
|
mod.lifecycle = app
|
||||||
mod.logger = logger
|
mod.logger = logger
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
@@ -46,6 +47,27 @@ func TestNewLifecycle(t *testing.T) {
|
|||||||
}, "expected panic on duplicate module names")
|
}, "expected panic on duplicate module names")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLifecycleToFromContext(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Create a Lifecycle instance
|
||||||
|
lc := NewLifecycle()
|
||||||
|
|
||||||
|
// Add the Lifecycle to the context
|
||||||
|
ctx := LifecycleToContext(context.Background(), lc)
|
||||||
|
|
||||||
|
// Retrieve the Lifecycle from the context
|
||||||
|
retrievedLC := LifecycleFromContext(ctx)
|
||||||
|
|
||||||
|
assert.NotNil(retrievedLC, "expected Lifecycle to be retrieved from context")
|
||||||
|
assert.Equal(lc, retrievedLC, "expected retrieved Lifecycle to match original")
|
||||||
|
|
||||||
|
// Test with nil Lifecycle
|
||||||
|
nilCtx := LifecycleToContext(context.Background(), nil)
|
||||||
|
retrievedNilLC := LifecycleFromContext(nilCtx)
|
||||||
|
assert.Nil(retrievedNilLC, "expected nil Lifecycle to return nil from context")
|
||||||
|
}
|
||||||
|
|
||||||
func TestLifecycle_WithOpts(t *testing.T) {
|
func TestLifecycle_WithOpts(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
@@ -65,6 +87,10 @@ func TestLifecycle_WithLogger(t *testing.T) {
|
|||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
lc.WithLogger(logger)
|
lc.WithLogger(logger)
|
||||||
assert.Equal(logger, lc.Logger(), "expected Lifecycle to have the provided logger")
|
assert.Equal(logger, lc.Logger(), "expected Lifecycle to have the provided logger")
|
||||||
|
|
||||||
|
assert.PanicsWithValue("logger cannot be nil", func() {
|
||||||
|
lc.WithLogger(nil)
|
||||||
|
}, "expected panic when setting nil logger")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLifecycle_Logger(t *testing.T) {
|
func TestLifecycle_Logger(t *testing.T) {
|
||||||
@@ -77,6 +103,12 @@ func TestLifecycle_Logger(t *testing.T) {
|
|||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
lc.opts.Logger = logger
|
lc.opts.Logger = logger
|
||||||
assert.Equal(logger, lc.Logger())
|
assert.Equal(logger, lc.Logger())
|
||||||
|
|
||||||
|
// Test with nil Lifecycle
|
||||||
|
assert.PanicsWithValue("lifecycle is nil, cannot get logger", func() {
|
||||||
|
var nilLC *Lifecycle
|
||||||
|
nilLC.Logger()
|
||||||
|
}, "expected panic when calling Logger on nil Lifecycle")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLifecycle_Setup(t *testing.T) {
|
func TestLifecycle_Setup(t *testing.T) {
|
||||||
@@ -225,15 +257,17 @@ func TestLifecycle_Teardown(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLifecycle_Require(t *testing.T) {
|
func TestLifecycle_Require(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
lc := NewLifecycle()
|
lc := NewLifecycle()
|
||||||
mod := NewModule("module1", ModuleOpts{
|
|
||||||
Setup: func(m *Module) error { return nil },
|
// Test that duplicate modules are allowed
|
||||||
})
|
mod1 := NewModule("module1", ModuleOpts{})
|
||||||
err := lc.Require(mod)
|
mod2 := NewModule("module1", ModuleOpts{})
|
||||||
assert.NoError(t, err, "expected Require to succeed")
|
err := lc.Require(mod1, mod2)
|
||||||
assert.Contains(t, lc.setupTracker, mod.name, "expected module to be marked as set up")
|
assert.NoError(err, "expected Require to succeed with duplicate modules")
|
||||||
assert.Nil(t, mod.logger, "expected module logger to be nil")
|
assert.Len(lc.modules, 1, "expected only one instance of the module to be added")
|
||||||
assert.Equal(t, lc.Logger(), mod.Logger(), "expected module logger to match lifecycle logger")
|
assert.Equal(lc.Logger(), mod1.Logger(), "expected module logger to match lifecycle logger")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLifecycle_RequireUnique(t *testing.T) {
|
func TestLifecycle_RequireUnique(t *testing.T) {
|
||||||
@@ -241,24 +275,59 @@ func TestLifecycle_RequireUnique(t *testing.T) {
|
|||||||
lc := NewLifecycle()
|
lc := NewLifecycle()
|
||||||
|
|
||||||
mod := NewModule("module1", ModuleOpts{})
|
mod := NewModule("module1", ModuleOpts{})
|
||||||
err := lc.RequireUnique(mod)
|
err := lc.RequireUnique(mod, mod)
|
||||||
assert.NoError(err, "expected RequireL to succeed")
|
|
||||||
assert.Nil(mod.logger, "expected module logger to be nil")
|
|
||||||
|
|
||||||
// Requiring the same module again should fail
|
|
||||||
err = lc.RequireUnique(mod)
|
|
||||||
assert.Error(err, "expected RequireUnique to fail on duplicate module")
|
assert.Error(err, "expected RequireUnique to fail on duplicate module")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLifecycle_RequireL(t *testing.T) {
|
func TestLifecycle_RequireL(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
// Create a logger for the test cases
|
// Create a logger for the test cases
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
|
|
||||||
|
lc := NewLifecycle()
|
||||||
|
|
||||||
|
// Test that duplicate modules are allowed with RequireL
|
||||||
|
mod1 := NewModule("module1", ModuleOpts{})
|
||||||
|
mod2 := NewModule("module1", ModuleOpts{})
|
||||||
|
err := lc.RequireL(logger, mod1, mod2)
|
||||||
|
assert.NoError(err, "expected RequireL to succeed with duplicate modules")
|
||||||
|
assert.Len(lc.modules, 1, "expected only one instance of the module to be added")
|
||||||
|
assert.Equal(logger, mod1.Logger(), "expected module logger to match provided logger")
|
||||||
|
|
||||||
|
// Test with nil logger
|
||||||
|
err = lc.RequireL(nil, mod1)
|
||||||
|
assert.Error(err, "expected RequireL to fail with nil logger")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLifecycle_RequireUniqueL(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
// Create a logger for the test cases
|
||||||
|
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
|
|
||||||
|
lc := NewLifecycle()
|
||||||
|
|
||||||
|
// Test that duplicate modules are not allowed with RequireUniqueL
|
||||||
|
mod1 := NewModule("module1", ModuleOpts{})
|
||||||
|
mod2 := NewModule("module1", ModuleOpts{})
|
||||||
|
err := lc.RequireUniqueL(logger, mod1, mod2)
|
||||||
|
assert.Error(err, "expected RequireUniqueL to fail on duplicate module")
|
||||||
|
assert.Contains(err.Error(), "cannot require again", "expected error message to match")
|
||||||
|
|
||||||
|
// Test with nil logger
|
||||||
|
err = lc.RequireUniqueL(nil, mod1)
|
||||||
|
assert.Error(err, "expected RequireUniqueL to fail with nil logger")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLifecycle_require(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
name string
|
name string
|
||||||
|
logger *slog.Logger
|
||||||
|
unique bool
|
||||||
modules []*Module
|
modules []*Module
|
||||||
existingModules []*Module
|
|
||||||
expectedErr string
|
expectedErr string
|
||||||
|
length int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "no modules",
|
name: "no modules",
|
||||||
@@ -266,31 +335,17 @@ func TestLifecycle_RequireL(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nil module",
|
name: "nil module",
|
||||||
modules: []*Module{nil},
|
modules: []*Module{
|
||||||
expectedErr: "is nil",
|
NewModule("", ModuleOpts{}),
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
expectedErr: "module 1 is nil",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "basic module",
|
name: "basic modules",
|
||||||
modules: []*Module{
|
modules: []*Module{
|
||||||
NewModule("testModule", ModuleOpts{
|
NewModule("module1", ModuleOpts{}),
|
||||||
Setup: func(m *Module) error {
|
NewModule("module2", ModuleOpts{}),
|
||||||
if m.name != "testModule" {
|
|
||||||
return errors.New("module name mismatch")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "several modules",
|
|
||||||
modules: []*Module{
|
|
||||||
NewModule("module1", ModuleOpts{
|
|
||||||
Setup: func(m *Module) error { return nil },
|
|
||||||
}),
|
|
||||||
NewModule("module2", ModuleOpts{
|
|
||||||
Setup: func(m *Module) error { return nil },
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -300,21 +355,7 @@ func TestLifecycle_RequireL(t *testing.T) {
|
|||||||
Setup: func(m *Module) error { return errors.New("setup failed") },
|
Setup: func(m *Module) error { return errors.New("setup failed") },
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
expectedErr: "setup failed",
|
expectedErr: "error setting up required module",
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "module with dependency",
|
|
||||||
modules: []*Module{
|
|
||||||
NewModule("dependentModule", ModuleOpts{
|
|
||||||
Setup: func(m *Module) error { return nil },
|
|
||||||
Depends: []string{"dependencyModule"},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
existingModules: []*Module{
|
|
||||||
NewModule("dependencyModule", ModuleOpts{
|
|
||||||
Setup: func(m *Module) error { return nil },
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "duplicate module names",
|
name: "duplicate module names",
|
||||||
@@ -322,6 +363,16 @@ func TestLifecycle_RequireL(t *testing.T) {
|
|||||||
NewModule("duplicateModule", ModuleOpts{}),
|
NewModule("duplicateModule", ModuleOpts{}),
|
||||||
NewModule("duplicateModule", ModuleOpts{}),
|
NewModule("duplicateModule", ModuleOpts{}),
|
||||||
},
|
},
|
||||||
|
length: 1, // Expect only one instance to be added
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "duplicate module names with unique",
|
||||||
|
unique: true,
|
||||||
|
modules: []*Module{
|
||||||
|
NewModule("duplicateModule", ModuleOpts{}),
|
||||||
|
NewModule("duplicateModule", ModuleOpts{}),
|
||||||
|
},
|
||||||
|
expectedErr: "cannot require again",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,75 +380,34 @@ func TestLifecycle_RequireL(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
lc := NewLifecycle(tc.existingModules...)
|
lc := NewLifecycle()
|
||||||
|
err := lc.require(tc.logger, tc.unique, tc.modules...)
|
||||||
err := lc.RequireL(logger, tc.modules...)
|
|
||||||
|
|
||||||
if tc.expectedErr == "" {
|
if tc.expectedErr == "" {
|
||||||
assert.NoError(err, "expected RequireL to succeed")
|
assert.NoError(err, "expected require to succeed")
|
||||||
for i, mod := range tc.modules {
|
|
||||||
|
expectedLength := tc.length
|
||||||
|
if expectedLength == 0 {
|
||||||
|
expectedLength = len(tc.modules)
|
||||||
|
}
|
||||||
|
assert.Equal(expectedLength, len(lc.modules), "expected all modules to be added to lifecycle")
|
||||||
|
|
||||||
|
for _, mod := range tc.modules {
|
||||||
if mod != nil {
|
if mod != nil {
|
||||||
_, ok := lc.setupTracker[mod.name]
|
_, ok := lc.setupTracker[mod.name]
|
||||||
assert.Truef(ok, "expected module %d %s to be marked as set up", i, mod)
|
assert.Truef(ok, "expected module %s to be marked as set up", mod)
|
||||||
assert.Truef(mod.loaded, "expected module %d %s to be loaded", i, mod)
|
assert.Truef(mod.loaded, "expected module %s to be loaded", mod)
|
||||||
assert.Equalf(logger, mod.logger, "expected module %d %s logger to match", i, mod)
|
assert.Equalf(lc, mod.lifecycle, "expected module %s lifecycle to match", mod)
|
||||||
|
|
||||||
|
if tc.logger != nil {
|
||||||
|
assert.Equalf(tc.logger, mod.Logger(), "expected module %s logger to match", mod)
|
||||||
|
} else {
|
||||||
|
assert.Equalf(lc.Logger(), mod.Logger(), "expected module %s logger to match lifecycle logger", mod)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert.Error(err, "expected RequireL to fail")
|
assert.Error(err, "expected require to fail")
|
||||||
assert.Contains(err.Error(), tc.expectedErr, "expected error message to match")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLifecycle_RequireUniqueL(t *testing.T) {
|
|
||||||
// Create a logger for the test cases
|
|
||||||
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
name string
|
|
||||||
modules []*Module
|
|
||||||
existingModules []string
|
|
||||||
expectedErr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "no existing modules",
|
|
||||||
modules: []*Module{
|
|
||||||
NewModule("module1", ModuleOpts{}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "module already set up",
|
|
||||||
modules: []*Module{
|
|
||||||
NewModule("module1", ModuleOpts{}),
|
|
||||||
NewModule("module2", ModuleOpts{}),
|
|
||||||
},
|
|
||||||
existingModules: []string{"module1"},
|
|
||||||
expectedErr: "module [module1] is already set up, cannot require it again",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "nil module",
|
|
||||||
modules: []*Module{nil},
|
|
||||||
expectedErr: "is nil",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
assert := assert.New(t)
|
|
||||||
lc := NewLifecycle()
|
|
||||||
|
|
||||||
// Fake existing modules
|
|
||||||
for _, modName := range tc.existingModules {
|
|
||||||
lc.setupTracker[modName] = 0 // Mark as set up
|
|
||||||
}
|
|
||||||
|
|
||||||
err := lc.RequireUniqueL(logger, tc.modules...)
|
|
||||||
if tc.expectedErr == "" {
|
|
||||||
assert.NoError(err, "expected RequireUniqueL to succeed")
|
|
||||||
} else {
|
|
||||||
assert.Error(err, "expected RequireUniqueL to fail")
|
|
||||||
assert.Contains(err.Error(), tc.expectedErr, "expected error message to match")
|
assert.Contains(err.Error(), tc.expectedErr, "expected error message to match")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user