167 lines
4.7 KiB
Go
167 lines
4.7 KiB
Go
package ai
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type stubAlertProvider struct {
|
|
active []AlertInfo
|
|
resolved []ResolvedAlertInfo
|
|
}
|
|
|
|
func (s *stubAlertProvider) GetActiveAlerts() []AlertInfo { return s.active }
|
|
func (s *stubAlertProvider) GetRecentlyResolved(minutes int) []ResolvedAlertInfo { return s.resolved }
|
|
func (s *stubAlertProvider) GetAlertsByResource(resourceID string) []AlertInfo {
|
|
out := make([]AlertInfo, 0)
|
|
for _, a := range s.active {
|
|
if a.ResourceID == resourceID {
|
|
out = append(out, a)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
func (s *stubAlertProvider) GetAlertHistory(resourceID string, limit int) []ResolvedAlertInfo {
|
|
out := make([]ResolvedAlertInfo, 0)
|
|
for _, a := range s.resolved {
|
|
if a.ResourceID == resourceID {
|
|
out = append(out, a)
|
|
if len(out) >= limit {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestService_buildAlertContext(t *testing.T) {
|
|
now := time.Now()
|
|
|
|
s := &Service{}
|
|
s.SetAlertProvider(&stubAlertProvider{
|
|
active: []AlertInfo{
|
|
{
|
|
ID: "a1",
|
|
Type: "cpu",
|
|
Level: "critical",
|
|
ResourceID: "node:pve1",
|
|
ResourceName: "pve1",
|
|
ResourceType: "node",
|
|
Node: "pve1",
|
|
Message: "cpu high",
|
|
Value: 95,
|
|
Threshold: 80,
|
|
StartTime: now.Add(-5 * time.Minute),
|
|
Duration: "5 mins",
|
|
Acknowledged: true,
|
|
},
|
|
{
|
|
ID: "a2",
|
|
Type: "memory",
|
|
Level: "warning",
|
|
ResourceID: "guest:100",
|
|
ResourceName: "vm-100",
|
|
ResourceType: "guest",
|
|
Message: "mem high",
|
|
Value: 80,
|
|
Threshold: 75,
|
|
StartTime: now.Add(-2 * time.Minute),
|
|
Duration: "2 mins",
|
|
},
|
|
},
|
|
resolved: []ResolvedAlertInfo{
|
|
{
|
|
AlertInfo: AlertInfo{
|
|
ID: "r1",
|
|
Type: "disk",
|
|
Level: "warning",
|
|
ResourceID: "storage:local",
|
|
ResourceName: "local",
|
|
Message: "disk ok",
|
|
Duration: "10 mins",
|
|
},
|
|
ResolvedTime: now.Add(-2 * time.Minute),
|
|
Duration: "10 mins",
|
|
},
|
|
},
|
|
})
|
|
|
|
ctx := s.buildAlertContext()
|
|
if !strings.Contains(ctx, "## Alert Status") {
|
|
t.Fatalf("expected alert status header, got: %s", ctx)
|
|
}
|
|
if !strings.Contains(ctx, "### Active Alerts") || !strings.Contains(ctx, "**Critical:**") || !strings.Contains(ctx, "**Warning:**") {
|
|
t.Fatalf("expected active alert sections, got: %s", ctx)
|
|
}
|
|
if !strings.Contains(ctx, "[ACKNOWLEDGED]") || !strings.Contains(ctx, "on node pve1") {
|
|
t.Fatalf("expected acknowledged/node formatting, got: %s", ctx)
|
|
}
|
|
if !strings.Contains(ctx, "### Recently Resolved") {
|
|
t.Fatalf("expected recently resolved section, got: %s", ctx)
|
|
}
|
|
}
|
|
|
|
func TestService_buildAlertContext_Empty(t *testing.T) {
|
|
s := &Service{}
|
|
if got := s.buildAlertContext(); got != "" {
|
|
t.Fatalf("expected empty string, got: %q", got)
|
|
}
|
|
s.SetAlertProvider(&stubAlertProvider{})
|
|
if got := s.buildAlertContext(); got != "" {
|
|
t.Fatalf("expected empty string when no alerts, got: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestService_buildTargetAlertContext(t *testing.T) {
|
|
s := &Service{}
|
|
s.SetAlertProvider(&stubAlertProvider{
|
|
active: []AlertInfo{
|
|
{ID: "a1", Level: "critical", Type: "cpu", ResourceID: "node:pve1", ResourceName: "pve1", Duration: "1 min", Value: 90, Threshold: 80},
|
|
{ID: "a2", Level: "warning", Type: "memory", ResourceID: "node:pve2", ResourceName: "pve2", Duration: "1 min", Value: 80, Threshold: 70},
|
|
},
|
|
})
|
|
|
|
got := s.buildTargetAlertContext("node:pve1")
|
|
if !strings.Contains(got, "Active Alerts for This Resource") || !strings.Contains(got, "pve1") {
|
|
t.Fatalf("unexpected context: %s", got)
|
|
}
|
|
if strings.Contains(got, "pve2") {
|
|
t.Fatalf("unexpected extra resource: %s", got)
|
|
}
|
|
}
|
|
|
|
func TestFormatTimeAgo(t *testing.T) {
|
|
now := time.Now()
|
|
if got := formatTimeAgo(now.Add(-10 * time.Second)); got != "just now" {
|
|
t.Fatalf("formatTimeAgo(<1m) = %q", got)
|
|
}
|
|
if got := formatTimeAgo(now.Add(-2 * time.Minute)); got != "2 minutes" {
|
|
t.Fatalf("formatTimeAgo(2m) = %q", got)
|
|
}
|
|
if got := formatTimeAgo(now.Add(-2 * time.Hour)); got != "2 hours" {
|
|
t.Fatalf("formatTimeAgo(2h) = %q", got)
|
|
}
|
|
if got := formatTimeAgo(now.Add(-48 * time.Hour)); got != "2 days" {
|
|
t.Fatalf("formatTimeAgo(2d) = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestGenerateAlertInvestigationPrompt(t *testing.T) {
|
|
out := GenerateAlertInvestigationPrompt(AlertInvestigationRequest{
|
|
Level: "critical",
|
|
ResourceName: "pve1",
|
|
ResourceType: "node",
|
|
AlertType: "cpu",
|
|
Value: 95,
|
|
Threshold: 80,
|
|
Duration: "5 mins",
|
|
Node: "pve1",
|
|
})
|
|
if !strings.Contains(out, "Investigate this CRITICAL alert") ||
|
|
!strings.Contains(out, "**Resource:** pve1 (node)") ||
|
|
!strings.Contains(out, "**Node:** pve1") {
|
|
t.Fatalf("unexpected prompt: %s", out)
|
|
}
|
|
}
|
|
|