fix(api): snapshot engine iterator views

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-01 21:23:19 +00:00
parent 4ce697189a
commit e0bdca7889
2 changed files with 46 additions and 2 deletions

6
api.go
View file

@ -72,7 +72,8 @@ func (e *Engine) Groups() []RouteGroup {
// GroupsIter returns an iterator over all registered route groups.
func (e *Engine) GroupsIter() iter.Seq[RouteGroup] {
return slices.Values(e.groups)
groups := slices.Clone(e.groups)
return slices.Values(groups)
}
// Register adds a route group to the engine.
@ -94,8 +95,9 @@ func (e *Engine) Channels() []string {
// ChannelsIter returns an iterator over WebSocket channel names from registered StreamGroups.
func (e *Engine) ChannelsIter() iter.Seq[string] {
groups := slices.Clone(e.groups)
return func(yield func(string) bool) {
for _, g := range e.groups {
for _, g := range groups {
if sg, ok := g.(StreamGroup); ok {
for _, c := range sg.Channels() {
if !yield(c) {

View file

@ -27,6 +27,28 @@ func TestEngine_GroupsIter(t *testing.T) {
}
}
func TestEngine_GroupsIter_Good_SnapshotsCurrentGroups(t *testing.T) {
e, _ := api.New()
g1 := &healthGroup{}
g2 := &stubGroup{}
e.Register(g1)
iter := e.GroupsIter()
e.Register(g2)
var groups []api.RouteGroup
for g := range iter {
groups = append(groups, g)
}
if len(groups) != 1 {
t.Fatalf("expected iterator snapshot to contain 1 group, got %d", len(groups))
}
if groups[0].Name() != "health-extra" {
t.Fatalf("expected snapshot to preserve original group, got %q", groups[0].Name())
}
}
type streamGroupStub struct {
healthGroup
channels []string
@ -52,6 +74,26 @@ func TestEngine_ChannelsIter(t *testing.T) {
}
}
func TestEngine_ChannelsIter_Good_SnapshotsCurrentChannels(t *testing.T) {
e, _ := api.New()
g1 := &streamGroupStub{channels: []string{"ch1", "ch2"}}
g2 := &streamGroupStub{channels: []string{"ch3"}}
e.Register(g1)
iter := e.ChannelsIter()
e.Register(g2)
var channels []string
for ch := range iter {
channels = append(channels, ch)
}
expected := []string{"ch1", "ch2"}
if !slices.Equal(channels, expected) {
t.Fatalf("expected snapshot channels %v, got %v", expected, channels)
}
}
func TestToolBridge_Iterators(t *testing.T) {
b := api.NewToolBridge("/tools")
desc := api.ToolDescriptor{Name: "test", Group: "g1"}