test: Add tests for alert utility functions
SetMetricHooks (0%→100%): - Sets all four hooks correctly - Nil hooks are safely handled - Properly saves/restores state to avoid test pollution NotifyExistingAlert (0%→100%): - Non-existent alert is no-op - Existing alert dispatches async notification GetResolvedAlert (0%→100%): - Returns nil for non-existent alert - Returns nil for nil resolved entry - Returns nil when Alert is nil - Returns cloned alert with resolved time GetAlertHistory/GetAlertHistorySince (0%→100%): - Returns history from history manager - Respects limit parameter - Zero time returns all history - Filters by time correctly ClearAlertHistory (0%→100%): - Clears all history entries Coverage: 56.9% → 57.4%
This commit is contained in:
parent
5c584b9eee
commit
b9e49a26c4
1 changed files with 261 additions and 0 deletions
|
|
@ -5691,3 +5691,264 @@ func TestHandleDockerHostOffline(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSetMetricHooks(t *testing.T) {
|
||||
// NOT parallel - modifies package-level state
|
||||
// Save existing state and restore after test
|
||||
oldFired := recordAlertFired
|
||||
oldResolved := recordAlertResolved
|
||||
oldSuppressed := recordAlertSuppressed
|
||||
oldAcknowledged := recordAlertAcknowledged
|
||||
defer func() {
|
||||
recordAlertFired = oldFired
|
||||
recordAlertResolved = oldResolved
|
||||
recordAlertSuppressed = oldSuppressed
|
||||
recordAlertAcknowledged = oldAcknowledged
|
||||
}()
|
||||
|
||||
t.Run("sets all hooks", func(t *testing.T) {
|
||||
var firedCalled, resolvedCalled, suppressedCalled, acknowledgedCalled bool
|
||||
|
||||
SetMetricHooks(
|
||||
func(a *Alert) { firedCalled = true },
|
||||
func(a *Alert) { resolvedCalled = true },
|
||||
func(s string) { suppressedCalled = true },
|
||||
func() { acknowledgedCalled = true },
|
||||
)
|
||||
|
||||
// Verify hooks are set by calling them (if they were nil, this would panic)
|
||||
if recordAlertFired != nil {
|
||||
recordAlertFired(&Alert{})
|
||||
}
|
||||
if recordAlertResolved != nil {
|
||||
recordAlertResolved(&Alert{})
|
||||
}
|
||||
if recordAlertSuppressed != nil {
|
||||
recordAlertSuppressed("test")
|
||||
}
|
||||
if recordAlertAcknowledged != nil {
|
||||
recordAlertAcknowledged()
|
||||
}
|
||||
|
||||
if !firedCalled {
|
||||
t.Error("expected fired hook to be called")
|
||||
}
|
||||
if !resolvedCalled {
|
||||
t.Error("expected resolved hook to be called")
|
||||
}
|
||||
if !suppressedCalled {
|
||||
t.Error("expected suppressed hook to be called")
|
||||
}
|
||||
if !acknowledgedCalled {
|
||||
t.Error("expected acknowledged hook to be called")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nil hooks are safe", func(t *testing.T) {
|
||||
SetMetricHooks(nil, nil, nil, nil)
|
||||
|
||||
// Should not panic
|
||||
if recordAlertFired != nil {
|
||||
t.Error("expected fired hook to be nil")
|
||||
}
|
||||
if recordAlertResolved != nil {
|
||||
t.Error("expected resolved hook to be nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNotifyExistingAlert(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("non-existent alert is no-op", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
// Should not panic
|
||||
m.NotifyExistingAlert("non-existent-alert")
|
||||
})
|
||||
|
||||
t.Run("existing alert dispatches notification", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
dispatchedCh := make(chan bool, 1)
|
||||
m.SetAlertCallback(func(a *Alert) {
|
||||
dispatchedCh <- true
|
||||
})
|
||||
|
||||
m.mu.Lock()
|
||||
m.config.Enabled = true
|
||||
m.config.ActivationState = ActivationActive // Must be active to dispatch
|
||||
m.activeAlerts["test-alert"] = &Alert{
|
||||
ID: "test-alert",
|
||||
Type: "test",
|
||||
Level: AlertLevelWarning,
|
||||
}
|
||||
m.mu.Unlock()
|
||||
|
||||
m.NotifyExistingAlert("test-alert")
|
||||
|
||||
// Wait for async dispatch with timeout
|
||||
select {
|
||||
case <-dispatchedCh:
|
||||
// Success
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Error("expected alert callback to be called (timeout)")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetResolvedAlert(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("returns nil for non-existent alert", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
result := m.GetResolvedAlert("non-existent")
|
||||
if result != nil {
|
||||
t.Error("expected nil for non-existent alert")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns nil for nil resolved entry", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.resolvedMutex.Lock()
|
||||
m.recentlyResolved["test"] = nil
|
||||
m.resolvedMutex.Unlock()
|
||||
|
||||
result := m.GetResolvedAlert("test")
|
||||
if result != nil {
|
||||
t.Error("expected nil for nil resolved entry")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns nil when Alert is nil", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.resolvedMutex.Lock()
|
||||
m.recentlyResolved["test"] = &ResolvedAlert{Alert: nil}
|
||||
m.resolvedMutex.Unlock()
|
||||
|
||||
result := m.GetResolvedAlert("test")
|
||||
if result != nil {
|
||||
t.Error("expected nil when Alert is nil")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("returns cloned alert", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
resolvedTime := time.Now()
|
||||
m.resolvedMutex.Lock()
|
||||
m.recentlyResolved["test"] = &ResolvedAlert{
|
||||
Alert: &Alert{
|
||||
ID: "test",
|
||||
Type: "cpu",
|
||||
Level: AlertLevelWarning,
|
||||
ResourceID: "res1",
|
||||
ResourceName: "Resource 1",
|
||||
},
|
||||
ResolvedTime: resolvedTime,
|
||||
}
|
||||
m.resolvedMutex.Unlock()
|
||||
|
||||
result := m.GetResolvedAlert("test")
|
||||
if result == nil {
|
||||
t.Fatal("expected non-nil result")
|
||||
}
|
||||
if result.Alert.ID != "test" {
|
||||
t.Errorf("expected ID test, got %s", result.Alert.ID)
|
||||
}
|
||||
if result.ResolvedTime != resolvedTime {
|
||||
t.Error("expected resolved time to match")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAlertHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("returns history from history manager", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
// Add some alerts to history
|
||||
m.historyManager.AddAlert(Alert{ID: "alert1", Type: "cpu"})
|
||||
m.historyManager.AddAlert(Alert{ID: "alert2", Type: "memory"})
|
||||
|
||||
history := m.GetAlertHistory(10)
|
||||
if len(history) < 2 {
|
||||
t.Errorf("expected at least 2 history entries, got %d", len(history))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("respects limit", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
// Add alerts
|
||||
for i := 0; i < 5; i++ {
|
||||
m.historyManager.AddAlert(Alert{ID: fmt.Sprintf("alert%d", i), Type: "test"})
|
||||
}
|
||||
|
||||
history := m.GetAlertHistory(2)
|
||||
if len(history) > 2 {
|
||||
t.Errorf("expected max 2 entries, got %d", len(history))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAlertHistorySince(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("zero time returns all history", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
m.historyManager.AddAlert(Alert{ID: "alert1", Type: "cpu"})
|
||||
|
||||
history := m.GetAlertHistorySince(time.Time{}, 10)
|
||||
if len(history) == 0 {
|
||||
t.Error("expected history entries for zero time")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("filters by time", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
// Add an alert
|
||||
m.historyManager.AddAlert(Alert{ID: "alert1", Type: "cpu", StartTime: time.Now()})
|
||||
|
||||
// Query for alerts after now + 1 hour (should return none)
|
||||
future := time.Now().Add(1 * time.Hour)
|
||||
history := m.GetAlertHistorySince(future, 10)
|
||||
if len(history) != 0 {
|
||||
t.Errorf("expected 0 entries for future time, got %d", len(history))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestClearAlertHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("clears all history", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := NewManager()
|
||||
|
||||
// Add some alerts
|
||||
m.historyManager.AddAlert(Alert{ID: "alert1", Type: "cpu"})
|
||||
m.historyManager.AddAlert(Alert{ID: "alert2", Type: "memory"})
|
||||
|
||||
err := m.ClearAlertHistory()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
history := m.GetAlertHistory(10)
|
||||
if len(history) != 0 {
|
||||
t.Errorf("expected 0 entries after clear, got %d", len(history))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue