From d8fc2ec5580fd10980d91e76293e294a7fa6beaf Mon Sep 17 00:00:00 2001 From: rcourtman Date: Mon, 1 Dec 2025 16:23:45 +0000 Subject: [PATCH] test: Add comprehensive tests for applyGlobalOfflineSettingsLocked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests all 7 disable settings branches: - DisableAllNodesOffline: clears node-offline-* alerts and nodeOfflineCount - DisableAllPBSOffline: clears pbs-offline-* alerts and offlineConfirmations - DisableAllGuestsOffline: clears guest-powered-off-* alerts and offlineConfirmations - DisableAllDockerHostsOffline: clears docker-host-offline-* alerts and dockerOfflineCount - DisableAllDockerContainers: clears docker-container-* alerts and tracking state - DisableAllDockerServices: clears docker-service-* alerts - No settings enabled: verifies no-op behavior Coverage improvement: - applyGlobalOfflineSettingsLocked: 57.1% → 100% - alerts package: 53.0% → 53.5% --- internal/alerts/alerts_test.go | 222 +++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/internal/alerts/alerts_test.go b/internal/alerts/alerts_test.go index 07f5f533c..0a22a110a 100644 --- a/internal/alerts/alerts_test.go +++ b/internal/alerts/alerts_test.go @@ -4374,3 +4374,225 @@ func TestClearSnapshotAlertsForInstance(t *testing.T) { t.Errorf("expected 0 alerts remaining, got %d", len(m.activeAlerts)) } } + +func TestApplyGlobalOfflineSettingsLocked(t *testing.T) { + t.Parallel() + + t.Run("DisableAllNodesOffline clears node offline alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add node offline alerts + m.activeAlerts["node-offline-node1"] = &Alert{ID: "node-offline-node1", Type: "offline"} + m.activeAlerts["node-offline-node2"] = &Alert{ID: "node-offline-node2", Type: "offline"} + // Add non-node alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + // Add to nodeOfflineCount + m.nodeOfflineCount["node1"] = 3 + m.nodeOfflineCount["node2"] = 2 + + m.config.DisableAllNodesOffline = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // Node alerts should be cleared + if _, exists := m.activeAlerts["node-offline-node1"]; exists { + t.Error("expected node-offline-node1 to be cleared") + } + if _, exists := m.activeAlerts["node-offline-node2"]; exists { + t.Error("expected node-offline-node2 to be cleared") + } + // Non-node alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + // nodeOfflineCount should be reset + if len(m.nodeOfflineCount) != 0 { + t.Errorf("expected nodeOfflineCount to be empty, got %d entries", len(m.nodeOfflineCount)) + } + }) + + t.Run("DisableAllPBSOffline clears PBS offline alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add PBS offline alerts + m.activeAlerts["pbs-offline-pbs1"] = &Alert{ID: "pbs-offline-pbs1", ResourceID: "pbs1", Type: "offline"} + // Add non-PBS alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + // Add to offlineConfirmations + m.offlineConfirmations["pbs1"] = 3 + + m.config.DisableAllPBSOffline = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // PBS alert should be cleared + if _, exists := m.activeAlerts["pbs-offline-pbs1"]; exists { + t.Error("expected pbs-offline-pbs1 to be cleared") + } + // Non-PBS alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + // offlineConfirmations for PBS should be removed + if _, exists := m.offlineConfirmations["pbs1"]; exists { + t.Error("expected offlineConfirmations for pbs1 to be removed") + } + }) + + t.Run("DisableAllGuestsOffline clears guest powered off alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add guest powered off alerts + m.activeAlerts["guest-powered-off-vm1"] = &Alert{ID: "guest-powered-off-vm1", ResourceID: "vm1", Type: "powered-off"} + // Add non-guest alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + // Add to offlineConfirmations + m.offlineConfirmations["vm1"] = 2 + + m.config.DisableAllGuestsOffline = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // Guest alert should be cleared + if _, exists := m.activeAlerts["guest-powered-off-vm1"]; exists { + t.Error("expected guest-powered-off-vm1 to be cleared") + } + // Non-guest alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + // offlineConfirmations for guest should be removed + if _, exists := m.offlineConfirmations["vm1"]; exists { + t.Error("expected offlineConfirmations for vm1 to be removed") + } + }) + + t.Run("DisableAllDockerHostsOffline clears docker host alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add docker host offline alerts + m.activeAlerts["docker-host-offline-host1"] = &Alert{ID: "docker-host-offline-host1", Type: "offline"} + // Add non-docker host alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + // Add to dockerOfflineCount + m.dockerOfflineCount["host1"] = 3 + + m.config.DisableAllDockerHostsOffline = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // Docker host alert should be cleared + if _, exists := m.activeAlerts["docker-host-offline-host1"]; exists { + t.Error("expected docker-host-offline-host1 to be cleared") + } + // Non-docker host alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + // dockerOfflineCount should be reset + if len(m.dockerOfflineCount) != 0 { + t.Errorf("expected dockerOfflineCount to be empty, got %d entries", len(m.dockerOfflineCount)) + } + }) + + t.Run("DisableAllDockerContainers clears docker container alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add docker container alerts + m.activeAlerts["docker-container-unhealthy-c1"] = &Alert{ID: "docker-container-unhealthy-c1", Type: "unhealthy"} + m.activeAlerts["docker-container-exited-c2"] = &Alert{ID: "docker-container-exited-c2", Type: "exited"} + // Add non-container alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + // Add tracking state + m.dockerStateConfirm["c1"] = 2 + m.dockerRestartTracking["c1"] = &dockerRestartRecord{count: 5} + m.dockerLastExitCode["c1"] = 137 + + m.config.DisableAllDockerContainers = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // Docker container alerts should be cleared + if _, exists := m.activeAlerts["docker-container-unhealthy-c1"]; exists { + t.Error("expected docker-container-unhealthy-c1 to be cleared") + } + if _, exists := m.activeAlerts["docker-container-exited-c2"]; exists { + t.Error("expected docker-container-exited-c2 to be cleared") + } + // Non-container alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + // Tracking state should be reset + if len(m.dockerStateConfirm) != 0 { + t.Errorf("expected dockerStateConfirm to be empty, got %d entries", len(m.dockerStateConfirm)) + } + if len(m.dockerRestartTracking) != 0 { + t.Errorf("expected dockerRestartTracking to be empty, got %d entries", len(m.dockerRestartTracking)) + } + if len(m.dockerLastExitCode) != 0 { + t.Errorf("expected dockerLastExitCode to be empty, got %d entries", len(m.dockerLastExitCode)) + } + }) + + t.Run("DisableAllDockerServices clears docker service alerts", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add docker service alerts + m.activeAlerts["docker-service-unhealthy-svc1"] = &Alert{ID: "docker-service-unhealthy-svc1", Type: "unhealthy"} + // Add non-service alert + m.activeAlerts["cpu-alert"] = &Alert{ID: "cpu-alert", Type: "cpu"} + + m.config.DisableAllDockerServices = true + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // Docker service alert should be cleared + if _, exists := m.activeAlerts["docker-service-unhealthy-svc1"]; exists { + t.Error("expected docker-service-unhealthy-svc1 to be cleared") + } + // Non-service alert should remain + if _, exists := m.activeAlerts["cpu-alert"]; !exists { + t.Error("expected cpu-alert to remain") + } + }) + + t.Run("no settings enabled does nothing", func(t *testing.T) { + t.Parallel() + m := NewManager() + + // Add various alerts + m.activeAlerts["node-offline-node1"] = &Alert{ID: "node-offline-node1", Type: "offline"} + m.activeAlerts["pbs-offline-pbs1"] = &Alert{ID: "pbs-offline-pbs1", Type: "offline"} + m.activeAlerts["docker-container-unhealthy-c1"] = &Alert{ID: "docker-container-unhealthy-c1", Type: "unhealthy"} + + // All disable settings are false by default + + m.mu.Lock() + m.applyGlobalOfflineSettingsLocked() + m.mu.Unlock() + + // All alerts should remain + if len(m.activeAlerts) != 3 { + t.Errorf("expected 3 alerts to remain, got %d", len(m.activeAlerts)) + } + }) +}