Files
app/lifecycle_integration_test.go
T
end 4cd218f658 fix: correct lifecycle setup and teardown semantics
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>
2026-06-29 17:58:00 -07:00

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)
}