mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-04-27 21:36:21 +02:00
101 lines
2.4 KiB
Go
101 lines
2.4 KiB
Go
package soc
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestAnomalyDetector_NoAlertDuringWarmup(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
// First 10 observations are warmup — should never alert
|
|
for i := 0; i < 10; i++ {
|
|
alert := d.Observe("cpu", 50.0)
|
|
if alert != nil {
|
|
t.Fatalf("should not alert during warmup, got alert at observation %d", i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_NormalValues(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
// Build baseline with consistent values
|
|
for i := 0; i < 20; i++ {
|
|
d.Observe("rps", 100.0+float64(i%3)) // values: 100, 101, 102
|
|
}
|
|
|
|
// Normal value should not trigger
|
|
alert := d.Observe("rps", 103.0)
|
|
if alert != nil {
|
|
t.Fatal("normal value should not trigger anomaly")
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_ExtremeValue(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
// Build tight baseline
|
|
for i := 0; i < 30; i++ {
|
|
d.Observe("latency_ms", 10.0)
|
|
}
|
|
|
|
// Extreme spike should trigger
|
|
alert := d.Observe("latency_ms", 1000.0)
|
|
if alert == nil {
|
|
t.Fatal("extreme value should trigger anomaly")
|
|
}
|
|
if alert.Severity != "CRITICAL" {
|
|
t.Fatalf("extreme deviation should be CRITICAL, got %s", alert.Severity)
|
|
}
|
|
if alert.ZScore < 3.0 {
|
|
t.Fatalf("Z-score should be >= 3.0, got %f", alert.ZScore)
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_CustomThreshold(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
d.SetThreshold(2.0) // More sensitive
|
|
|
|
for i := 0; i < 30; i++ {
|
|
d.Observe("mem", 50.0)
|
|
}
|
|
|
|
// Moderate deviation should trigger with lower threshold
|
|
alert := d.Observe("mem", 80.0)
|
|
if alert == nil {
|
|
t.Fatal("moderate deviation should trigger with Z=2.0 threshold")
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_Baselines(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
d.Observe("metric_a", 10.0)
|
|
d.Observe("metric_b", 20.0)
|
|
|
|
baselines := d.Baselines()
|
|
if len(baselines) != 2 {
|
|
t.Fatalf("expected 2 baselines, got %d", len(baselines))
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_Alerts(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
for i := 0; i < 30; i++ {
|
|
d.Observe("test", 10.0)
|
|
}
|
|
d.Observe("test", 10000.0) // trigger alert
|
|
|
|
alerts := d.Alerts(10)
|
|
if len(alerts) != 1 {
|
|
t.Fatalf("expected 1 alert, got %d", len(alerts))
|
|
}
|
|
}
|
|
|
|
func TestAnomalyDetector_Stats(t *testing.T) {
|
|
d := NewAnomalyDetector()
|
|
d.Observe("x", 1.0)
|
|
stats := d.Stats()
|
|
if stats["metrics_tracked"].(int) != 1 {
|
|
t.Fatal("should track 1 metric")
|
|
}
|
|
if stats["z_threshold"].(float64) != 3.0 {
|
|
t.Fatal("default threshold should be 3.0")
|
|
}
|
|
}
|