7 tea "charm.land/bubbletea/v2"
8 "github.com/charmbracelet/crush/internal/agent/notify"
9 "github.com/charmbracelet/crush/internal/permission"
10 "github.com/charmbracelet/crush/internal/pubsub"
13// NewForTest constructs a minimal [App] suitable for in-process tests
14// that need a working event broker and permission service without
15// booting a real config, database, LSP, MCP, or agent coordinator.
17// The returned App has:
19// - A live `events` broker that [App.SendEvent] publishes to and
20// [App.Events] subscribes from.
21// - A real [permission.Service] whose request and notification
22// brokers are fanned into the events broker, so subscribers to
23// [App.Events] observe the same permission events the production
24// wiring would deliver to SSE clients.
25// - An [App.agentNotifications] broker.
27// The caller owns lifetime: cancel ctx (or call [App.Shutdown]) to
28// tear down the fan-in goroutines and the events broker.
29func NewForTest(ctx context.Context) *App {
31 Permissions: permission.NewPermissionService("", false, nil),
33 events: pubsub.NewBroker[tea.Msg](),
34 serviceEventsWG: &sync.WaitGroup{},
35 tuiWG: &sync.WaitGroup{},
36 agentNotifications: pubsub.NewBroker[notify.Notification](),
37 runCompletions: pubsub.NewBroker[notify.RunComplete](),
40 eventsCtx, cancel := context.WithCancel(ctx)
41 app.eventsCtx = eventsCtx
42 setupSubscriber(eventsCtx, app.serviceEventsWG, "permissions",
43 app.Permissions.Subscribe, app.events)
44 setupSubscriber(eventsCtx, app.serviceEventsWG, "permissions-notifications",
45 app.Permissions.SubscribeNotifications, app.events)
46 setupSubscriber(eventsCtx, app.serviceEventsWG, "agent-notifications",
47 app.agentNotifications.Subscribe, app.events)
48 setupSubscriber(eventsCtx, app.serviceEventsWG, "run-completions",
49 app.runCompletions.Subscribe, app.events)
50 app.cleanupFuncs = append(app.cleanupFuncs, func(context.Context) error {
52 app.serviceEventsWG.Wait()
59// ShutdownForTest tears down the App's event broker and fan-in
60// goroutines. It is safe to call multiple times.
62// Use this in tests instead of [App.Shutdown], which drives a full
63// production shutdown path (database release, LSP teardown, MCP
64// shutdown) that synthetic test apps cannot satisfy.
65func (app *App) ShutdownForTest() {
66 for _, cleanup := range app.cleanupFuncs {
68 _ = cleanup(context.Background())
71 app.cleanupFuncs = nil
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list