Files
pulse/internal/api/router_set_monitor_agents_test.go
T
rcourtman 15dbabfe9a Preserve resource URLs across runtime identity changes
Contract-Neutral: Docker URL migration touches shared monitor ingest files without changing the host deletion or re-enrollment contract.
2026-07-23 22:33:07 +01:00

85 lines
3.3 KiB
Go

package api
import (
"context"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
)
// TestRouterSetMonitor_UpdatesAgentHandlers verifies the fix for issue #1558:
// Router.SetMonitor must repoint the kubernetes agent handlers at the new
// monitor, exactly as it does for the docker agent handlers. Without this,
// kubernetes agent reports resolved through the single-tenant fallback keep
// landing in the orphaned pre-reload monitor after a config reload, so the
// cluster flaps in the UI.
func TestRouterSetMonitor_UpdatesAgentHandlers(t *testing.T) {
tempDir := t.TempDir()
cfg := &config.Config{
DataPath: tempDir,
ConfigPath: tempDir,
}
monitor1, err := monitoring.New(cfg)
if err != nil {
t.Fatalf("monitoring.New (initial): %v", err)
}
t.Cleanup(func() { monitor1.Stop() })
monitor2, err := monitoring.New(cfg)
if err != nil {
t.Fatalf("monitoring.New (reload): %v", err)
}
t.Cleanup(func() { monitor2.Stop() })
// No multi-tenant monitor: getMonitor resolves via the defaultMonitor
// fallback, which is exactly the field SetMonitor must refresh.
kubernetesHandlers := NewKubernetesAgentHandlers(nil, monitor1, nil)
dockerHandlers := NewDockerAgentHandlers(nil, monitor1, nil, cfg)
multiTenantPersistence := config.NewMultiTenantPersistence(tempDir)
// Minimal router, as in TestReloadSystemSettings_AppliesWebhookCIDRsToNewMonitor:
// SetMonitor only touches the handlers that are non-nil.
router := &Router{
config: cfg,
persistence: config.NewConfigPersistence(tempDir),
multiTenant: multiTenantPersistence,
kubernetesAgentHandlers: kubernetesHandlers,
dockerAgentHandlers: dockerHandlers,
aiSettingsHandler: NewAISettingsHandler(multiTenantPersistence, nil, nil),
}
router.SetMonitor(monitor2)
ctx := context.Background()
if got := kubernetesHandlers.getMonitor(ctx); got != monitor2 {
t.Fatal("kubernetes agent handlers still resolve the pre-reload monitor after Router.SetMonitor")
}
if got := dockerHandlers.getMonitor(ctx); got != monitor2 {
t.Fatal("docker agent handlers still resolve the pre-reload monitor after Router.SetMonitor")
}
if got := router.persistence.GetGuestMetadataStore(); got != monitor2.GuestMetadataStore() {
t.Fatal("config persistence still resolves the pre-reload guest metadata store")
}
if got := router.persistence.GetDockerMetadataStore(); got != monitor2.DockerMetadataStore() {
t.Fatal("config persistence still resolves the pre-reload Docker metadata store")
}
if got := router.persistence.GetHostMetadataStore(); got != monitor2.HostMetadataStore() {
t.Fatal("config persistence still resolves the pre-reload host metadata store")
}
if err := router.aiSettingsHandler.GetAIService(ctx).SetResourceURL(
"vm",
"instance:node:100",
"https://guest.internal",
); err != nil {
t.Fatalf("AI metadata update after monitor reload: %v", err)
}
if meta := monitor2.GuestMetadataStore().Get("instance:node:100"); meta == nil || meta.CustomURL != "https://guest.internal" {
t.Fatalf("replacement monitor guest metadata = %#v", meta)
}
if meta := monitor1.GuestMetadataStore().Get("instance:node:100"); meta != nil {
t.Fatalf("pre-reload monitor received URL update: %#v", meta)
}
}