Pulse/internal/metrics/incident_recorder_additional_test.go
2026-01-25 21:08:44 +00:00

127 lines
3.3 KiB
Go

package metrics
import (
"sync/atomic"
"testing"
"time"
)
type countingProvider struct {
ids []string
metrics map[string]map[string]float64
calls int32
}
func (c *countingProvider) GetCurrentMetrics(resourceID string) (map[string]float64, error) {
atomic.AddInt32(&c.calls, 1)
metrics, ok := c.metrics[resourceID]
if !ok {
return nil, errNoMetrics(resourceID)
}
copied := make(map[string]float64, len(metrics))
for k, v := range metrics {
copied[k] = v
}
return copied, nil
}
func (c *countingProvider) GetMonitoredResourceIDs() []string {
return append([]string{}, c.ids...)
}
func waitForCalls(t *testing.T, provider *countingProvider, timeout time.Duration) {
t.Helper()
deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
if atomic.LoadInt32(&provider.calls) > 0 {
return
}
time.Sleep(5 * time.Millisecond)
}
t.Fatal("expected provider to be called")
}
func TestDefaultIncidentRecorderConfig(t *testing.T) {
cfg := DefaultIncidentRecorderConfig()
if cfg.SampleInterval == 0 || cfg.PreIncidentWindow == 0 || cfg.PostIncidentWindow == 0 {
t.Fatalf("default config should be non-zero, got %+v", cfg)
}
if cfg.MaxDataPointsPerWindow == 0 || cfg.MaxWindows == 0 || cfg.RetentionDuration == 0 {
t.Fatalf("default config should be non-zero, got %+v", cfg)
}
}
func TestIncidentRecorderStartStop(t *testing.T) {
recorder := NewIncidentRecorder(IncidentRecorderConfig{
SampleInterval: 5 * time.Millisecond,
PreIncidentWindow: 10 * time.Millisecond,
PostIncidentWindow: 10 * time.Millisecond,
MaxDataPointsPerWindow: 5,
})
provider := &countingProvider{
ids: []string{"res-1"},
metrics: map[string]map[string]float64{
"res-1": {"cpu": 1},
},
}
recorder.SetMetricsProvider(provider)
recorder.Start()
waitForCalls(t, provider, 200*time.Millisecond)
recorder.Stop()
if recorder.running {
t.Fatalf("expected recorder to be stopped")
}
}
func TestGetWindowsForResource(t *testing.T) {
recorder := NewIncidentRecorder(IncidentRecorderConfig{})
active := &IncidentWindow{ID: "active-1", ResourceID: "res-1"}
recorder.activeWindows["active-1"] = active
got := recorder.GetWindowsForResource("res-1", 0)
if len(got) != 1 || got[0].ID != "active-1" {
t.Fatalf("expected active window, got %+v", got)
}
recorder.activeWindows = map[string]*IncidentWindow{}
recorder.completedWindows = []*IncidentWindow{
{ID: "old", ResourceID: "res-1"},
{ID: "new", ResourceID: "res-1"},
}
limited := recorder.GetWindowsForResource("res-1", 1)
if len(limited) != 1 || limited[0].ID != "new" {
t.Fatalf("expected most recent completed window, got %+v", limited)
}
}
func TestGetRecentWindows(t *testing.T) {
recorder := NewIncidentRecorder(IncidentRecorderConfig{})
recorder.activeWindows["active"] = &IncidentWindow{ID: "active", ResourceID: "res-1"}
recorder.completedWindows = []*IncidentWindow{
{ID: "old", ResourceID: "res-2"},
{ID: "new", ResourceID: "res-3"},
}
recent := recorder.GetRecentWindows(2)
if len(recent) != 2 {
t.Fatalf("expected 2 windows, got %d", len(recent))
}
var sawActive, sawNew bool
for _, window := range recent {
if window.ID == "active" {
sawActive = true
}
if window.ID == "new" {
sawNew = true
}
}
if !sawActive || !sawNew {
t.Fatalf("expected active and newest completed windows, got %+v", recent)
}
}