4cd218f658
Guard against double setup when autoload runs dependencies early, tear down in reverse setup order, roll back on partial failure, and detect circular Depends chains. Co-authored-by: Cursor <cursoragent@cursor.com>
82 lines
2.3 KiB
Go
82 lines
2.3 KiB
Go
package app_test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"gitea.auvem.com/go-toolkit/app"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSetupTeardownIntegration(t *testing.T) {
|
|
var order []string
|
|
modA := app.NewModule("a", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { order = append(order, "setup:a"); return nil },
|
|
Teardown: func(m *app.Module) error { order = append(order, "teardown:a"); return nil },
|
|
})
|
|
modB := app.NewModule("b", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { order = append(order, "setup:b"); return nil },
|
|
Teardown: func(m *app.Module) error { order = append(order, "teardown:b"); return nil },
|
|
Depends: []string{"a"},
|
|
})
|
|
|
|
lc := app.NewLifecycle(modB, modA)
|
|
assert.NoError(t, lc.Setup())
|
|
assert.Equal(t, []string{"setup:a", "setup:b"}, order)
|
|
|
|
order = nil
|
|
assert.NoError(t, lc.Teardown())
|
|
assert.Equal(t, []string{"teardown:b", "teardown:a"}, order)
|
|
}
|
|
|
|
func TestSetupNoDoubleSetupWithAutoload(t *testing.T) {
|
|
var count int
|
|
modA := app.NewModule("a", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { count++; return nil },
|
|
})
|
|
modB := app.NewModule("b", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { count++; return nil },
|
|
Depends: []string{"a"},
|
|
})
|
|
|
|
lc := app.NewLifecycle(modB, modA)
|
|
assert.NoError(t, lc.Setup())
|
|
assert.Equal(t, 2, count)
|
|
}
|
|
|
|
func TestSetupPartialFailureRollback(t *testing.T) {
|
|
var tornDown bool
|
|
modA := app.NewModule("a", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { return nil },
|
|
Teardown: func(m *app.Module) error { tornDown = true; return nil },
|
|
})
|
|
modB := app.NewModule("b", app.ModuleOpts{
|
|
Setup: func(m *app.Module) error { return fmt.Errorf("fail b") },
|
|
})
|
|
|
|
lc := app.NewLifecycle(modA, modB)
|
|
err := lc.Setup()
|
|
assert.Error(t, err)
|
|
assert.True(t, tornDown)
|
|
assert.False(t, modA.Loaded())
|
|
}
|
|
|
|
func TestSetupCircularDependency(t *testing.T) {
|
|
modA := app.NewModule("a", app.ModuleOpts{Depends: []string{"b"}})
|
|
modB := app.NewModule("b", app.ModuleOpts{Depends: []string{"a"}})
|
|
lc := app.NewLifecycle(modA, modB)
|
|
err := lc.Setup()
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "circular dependency")
|
|
}
|
|
|
|
func TestGetModule(t *testing.T) {
|
|
mod := app.NewModule("db", app.ModuleOpts{})
|
|
lc := app.NewLifecycle(mod)
|
|
got, err := lc.GetModule("db")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, mod, got)
|
|
_, err = lc.GetModule("missing")
|
|
assert.Error(t, err)
|
|
}
|