mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 11:30:15 +00:00
219 lines
5.3 KiB
Go
219 lines
5.3 KiB
Go
package ai
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestSemanticSimilarity(t *testing.T) {
|
|
// Base finding
|
|
f1 := &Finding{
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU Usage",
|
|
Description: "CPU is at 99%",
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
f2 *Finding
|
|
minScore float64 // Expected minimum similarity score
|
|
maxScore float64 // Expected maximum similarity score
|
|
}{
|
|
{
|
|
name: "Nil finding",
|
|
f2: nil,
|
|
minScore: 0.0,
|
|
maxScore: 0.0,
|
|
},
|
|
{
|
|
name: "Different resource and category",
|
|
f2: &Finding{
|
|
ResourceID: "res-2",
|
|
Category: FindingCategorySecurity,
|
|
Title: "Login failed",
|
|
Description: "Auth error",
|
|
},
|
|
minScore: 0.0,
|
|
maxScore: 0.1, // Maybe some keyword overlap
|
|
},
|
|
{
|
|
name: "Same resource, different category",
|
|
f2: &Finding{
|
|
ResourceID: "res-1",
|
|
Category: FindingCategorySecurity,
|
|
Title: "Login failed",
|
|
Description: "Auth error",
|
|
},
|
|
minScore: 0.3, // 0.3 for resource
|
|
maxScore: 0.4,
|
|
},
|
|
{
|
|
name: "Different resource, same category",
|
|
f2: &Finding{
|
|
ResourceID: "res-2",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High Memory Usage",
|
|
Description: "RAM is full",
|
|
},
|
|
minScore: 0.2, // 0.2 for category
|
|
maxScore: 0.4, // float precision might nudge it slightly over 0.2
|
|
},
|
|
{
|
|
name: "Same resource and category",
|
|
f2: &Finding{
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "Different Issue",
|
|
Description: "Something else",
|
|
},
|
|
minScore: 0.5, // 0.3 + 0.2
|
|
maxScore: 0.6,
|
|
},
|
|
{
|
|
name: "Similar title and description",
|
|
f2: &Finding{
|
|
ResourceID: "res-2",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU Usage",
|
|
Description: "CPU is at 99%",
|
|
},
|
|
minScore: 0.4, // Title/description boost
|
|
maxScore: 1.0,
|
|
},
|
|
{
|
|
name: "Exact duplicate",
|
|
f2: &Finding{
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU Usage",
|
|
Description: "CPU is at 99%",
|
|
},
|
|
minScore: 0.7, // Max is 0.8 without Key (0.3+0.2+0.2+0.1)
|
|
maxScore: 0.9,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
score := SemanticSimilarity(f1, tt.f2)
|
|
if score < tt.minScore || score > tt.maxScore {
|
|
t.Errorf("SemanticSimilarity() = %v, want between %v and %v", score, tt.minScore, tt.maxScore)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFindingsStore_SemanticDeduplication(t *testing.T) {
|
|
store := NewFindingsStore()
|
|
|
|
f1 := &Finding{
|
|
ID: "f1",
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU detected",
|
|
Description: "CPU usage is consistently above 90%",
|
|
Severity: FindingSeverityWarning,
|
|
TimesRaised: 1,
|
|
}
|
|
|
|
// Add first finding
|
|
id1, isNew := store.AddWithDeduplication(f1, 0.75)
|
|
if !isNew {
|
|
t.Error("Expected first finding to be new")
|
|
}
|
|
if id1 != "f1" {
|
|
t.Errorf("Expected ID f1, got %s", id1)
|
|
}
|
|
|
|
// Add second finding (very similar)
|
|
f2 := &Finding{
|
|
ID: "f2",
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU detected",
|
|
Description: "CPU usage is consistently above 90%",
|
|
Severity: FindingSeverityCritical, // Escalation
|
|
TimesRaised: 1,
|
|
}
|
|
|
|
id2, isNew := store.AddWithDeduplication(f2, 0.75)
|
|
if isNew {
|
|
t.Error("Expected similar finding to be deduplicated (not new)")
|
|
}
|
|
if id2 != "f1" { // Should return ID of existing finding
|
|
t.Errorf("Expected deduplication to existing ID f1, got %s", id2)
|
|
}
|
|
|
|
// Verify merged state
|
|
merged := store.Get("f1")
|
|
if merged.TimesRaised != 2 {
|
|
t.Errorf("Expected TimesRaised to increment to 2, got %d", merged.TimesRaised)
|
|
}
|
|
if merged.Severity != FindingSeverityCritical {
|
|
t.Errorf("Expected severity to escalate to Critical, got %v", merged.Severity)
|
|
}
|
|
|
|
// Add distinct finding
|
|
f3 := &Finding{
|
|
ID: "f3",
|
|
ResourceID: "res-2", // Different resource
|
|
Category: FindingCategorySecurity,
|
|
Title: "SSH Login Failed",
|
|
Severity: FindingSeverityWarning,
|
|
}
|
|
|
|
id3, isNew := store.AddWithDeduplication(f3, 0.8)
|
|
if !isNew {
|
|
t.Error("Expected distinct finding to be new")
|
|
}
|
|
if id3 != "f3" {
|
|
t.Errorf("Expected ID f3, got %s", id3)
|
|
}
|
|
}
|
|
|
|
func TestFindingsStore_FindSimilarFindings(t *testing.T) {
|
|
store := NewFindingsStore()
|
|
|
|
store.Add(&Finding{
|
|
ID: "f1",
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU",
|
|
Description: "High CPU usage detected",
|
|
})
|
|
|
|
store.Add(&Finding{
|
|
ID: "f2",
|
|
ResourceID: "res-2",
|
|
Category: FindingCategorySecurity,
|
|
Title: "Login Failed",
|
|
Description: "Auth failure",
|
|
})
|
|
|
|
// Search for similar to f1
|
|
query := &Finding{
|
|
ResourceID: "res-1",
|
|
Category: FindingCategoryPerformance,
|
|
Title: "High CPU",
|
|
Description: "High CPU usage detected",
|
|
}
|
|
|
|
similar := store.FindSimilarFindings(query, 0.75)
|
|
if len(similar) != 1 {
|
|
t.Fatalf("Expected 1 similar finding, got %d", len(similar))
|
|
}
|
|
if similar[0].ID != "f1" {
|
|
t.Errorf("Expected similarity to f1, got %s", similar[0].ID)
|
|
}
|
|
|
|
// Search for unrelated
|
|
queryUnsupported := &Finding{
|
|
ResourceID: "res-3",
|
|
Category: FindingCategoryCapacity, // Capacity != Performance
|
|
}
|
|
|
|
similar = store.FindSimilarFindings(queryUnsupported, 0.75)
|
|
if len(similar) != 0 {
|
|
t.Errorf("Expected 0 similar findings, got %d", len(similar))
|
|
}
|
|
}
|