test: Add comprehensive tests for HandleDockerHostOffline
HandleDockerHostOffline (0%→100%): - Empty host ID is no-op - Disabled alerts is no-op - DisableAllDockerHostsOffline clears tracking and alert - Override DisableConnectivity clears tracking and alert - Existing alert updates LastSeen - Requires 3 confirmations before alert - Alert has correct metadata (resourceType, hostId, agentId) Coverage: 55.6% → 56.9%
This commit is contained in:
parent
7bac96d60b
commit
5c584b9eee
1 changed files with 213 additions and 0 deletions
|
|
@ -5478,3 +5478,216 @@ func TestReevaluateGuestAlert(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestHandleDockerHostOffline(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("empty host ID is no-op", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
initialCount := len(m.activeAlerts)
|
||||
m.mu.Unlock()
|
||||
|
||||
m.HandleDockerHostOffline(models.DockerHost{ID: ""})
|
||||
|
||||
m.mu.RLock()
|
||||
finalCount := len(m.activeAlerts)
|
||||
m.mu.RUnlock()
|
||||
if finalCount != initialCount {
|
||||
t.Error("expected no change when empty host ID passed")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("disabled alerts is no-op", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = false
|
||||
m.mu.Unlock()
|
||||
|
||||
m.HandleDockerHostOffline(models.DockerHost{ID: "docker1", DisplayName: "Docker Host 1"})
|
||||
|
||||
m.mu.RLock()
|
||||
_, exists := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
if exists {
|
||||
t.Error("expected no alert when alerts are disabled")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DisableAllDockerHostsOffline clears tracking and alert", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.config.DisableAllDockerHostsOffline = true
|
||||
m.dockerOfflineCount["docker1"] = 5
|
||||
m.activeAlerts["docker-host-offline-docker1"] = &Alert{ID: "docker-host-offline-docker1"}
|
||||
m.mu.Unlock()
|
||||
|
||||
m.HandleDockerHostOffline(models.DockerHost{ID: "docker1", DisplayName: "Docker Host 1"})
|
||||
|
||||
m.mu.RLock()
|
||||
_, alertExists := m.activeAlerts["docker-host-offline-docker1"]
|
||||
_, countExists := m.dockerOfflineCount["docker1"]
|
||||
m.mu.RUnlock()
|
||||
if alertExists {
|
||||
t.Error("expected alert to be cleared")
|
||||
}
|
||||
if countExists {
|
||||
t.Error("expected offline count to be cleared")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("override DisableConnectivity clears tracking and alert", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.config.Overrides = map[string]ThresholdConfig{
|
||||
"docker1": {DisableConnectivity: true},
|
||||
}
|
||||
m.dockerOfflineCount["docker1"] = 3
|
||||
m.activeAlerts["docker-host-offline-docker1"] = &Alert{ID: "docker-host-offline-docker1"}
|
||||
m.mu.Unlock()
|
||||
|
||||
m.HandleDockerHostOffline(models.DockerHost{ID: "docker1", DisplayName: "Docker Host 1"})
|
||||
|
||||
m.mu.RLock()
|
||||
_, alertExists := m.activeAlerts["docker-host-offline-docker1"]
|
||||
_, countExists := m.dockerOfflineCount["docker1"]
|
||||
m.mu.RUnlock()
|
||||
if alertExists {
|
||||
t.Error("expected alert to be cleared with override")
|
||||
}
|
||||
if countExists {
|
||||
t.Error("expected offline count to be cleared with override")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("existing alert updates LastSeen", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
oldTime := time.Now().Add(-1 * time.Hour)
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.activeAlerts["docker-host-offline-docker1"] = &Alert{
|
||||
ID: "docker-host-offline-docker1",
|
||||
LastSeen: oldTime,
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
m.HandleDockerHostOffline(models.DockerHost{ID: "docker1", DisplayName: "Docker Host 1"})
|
||||
|
||||
m.mu.RLock()
|
||||
alert := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
if alert == nil {
|
||||
t.Fatal("expected alert to exist")
|
||||
}
|
||||
if !alert.LastSeen.After(oldTime) {
|
||||
t.Error("expected LastSeen to be updated")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("requires 3 confirmations before alert", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.mu.Unlock()
|
||||
|
||||
host := models.DockerHost{ID: "docker1", DisplayName: "Docker Host 1", Hostname: "docker-server"}
|
||||
|
||||
// First call - confirmation 1
|
||||
m.HandleDockerHostOffline(host)
|
||||
m.mu.RLock()
|
||||
count1 := m.dockerOfflineCount["docker1"]
|
||||
alert1 := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
if count1 != 1 {
|
||||
t.Errorf("expected count 1, got %d", count1)
|
||||
}
|
||||
if alert1 != nil {
|
||||
t.Error("expected no alert after 1 confirmation")
|
||||
}
|
||||
|
||||
// Second call - confirmation 2
|
||||
m.HandleDockerHostOffline(host)
|
||||
m.mu.RLock()
|
||||
count2 := m.dockerOfflineCount["docker1"]
|
||||
alert2 := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
if count2 != 2 {
|
||||
t.Errorf("expected count 2, got %d", count2)
|
||||
}
|
||||
if alert2 != nil {
|
||||
t.Error("expected no alert after 2 confirmations")
|
||||
}
|
||||
|
||||
// Third call - confirmation 3 - should create alert
|
||||
m.HandleDockerHostOffline(host)
|
||||
m.mu.RLock()
|
||||
count3 := m.dockerOfflineCount["docker1"]
|
||||
alert3 := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
if count3 != 3 {
|
||||
t.Errorf("expected count 3, got %d", count3)
|
||||
}
|
||||
if alert3 == nil {
|
||||
t.Fatal("expected alert after 3 confirmations")
|
||||
}
|
||||
if alert3.Type != "docker-host-offline" {
|
||||
t.Errorf("expected type docker-host-offline, got %s", alert3.Type)
|
||||
}
|
||||
if alert3.Level != AlertLevelCritical {
|
||||
t.Errorf("expected critical level, got %s", alert3.Level)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("alert has correct metadata", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.dockerOfflineCount["docker1"] = 2 // Pre-set to trigger on next call
|
||||
m.mu.Unlock()
|
||||
|
||||
host := models.DockerHost{
|
||||
ID: "docker1",
|
||||
DisplayName: "My Docker Host",
|
||||
Hostname: "docker-server.local",
|
||||
AgentID: "agent-123",
|
||||
}
|
||||
|
||||
m.HandleDockerHostOffline(host)
|
||||
|
||||
m.mu.RLock()
|
||||
alert := m.activeAlerts["docker-host-offline-docker1"]
|
||||
m.mu.RUnlock()
|
||||
|
||||
if alert == nil {
|
||||
t.Fatal("expected alert to be created")
|
||||
}
|
||||
if alert.ResourceID != "docker:docker1" {
|
||||
t.Errorf("expected resourceID docker:docker1, got %s", alert.ResourceID)
|
||||
}
|
||||
if alert.ResourceName != "My Docker Host" {
|
||||
t.Errorf("expected resourceName 'My Docker Host', got %s", alert.ResourceName)
|
||||
}
|
||||
if alert.Node != "docker-server.local" {
|
||||
t.Errorf("expected node docker-server.local, got %s", alert.Node)
|
||||
}
|
||||
if alert.Metadata["resourceType"] != "DockerHost" {
|
||||
t.Errorf("expected metadata resourceType DockerHost, got %v", alert.Metadata["resourceType"])
|
||||
}
|
||||
if alert.Metadata["hostId"] != "docker1" {
|
||||
t.Errorf("expected metadata hostId docker1, got %v", alert.Metadata["hostId"])
|
||||
}
|
||||
if alert.Metadata["agentId"] != "agent-123" {
|
||||
t.Errorf("expected metadata agentId agent-123, got %v", alert.Metadata["agentId"])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue