Files
ITWorx-Pulse-Public/internal/alert/grouping_test.go
T
ITWorx Pulse release export bd774932d5
Public source validation / validate (push) Failing after 3m8s
Publish ITWorx Pulse source
2026-09-03 02:09:19 +02:00

101 lines
4.0 KiB
Go

package alert
import (
"errors"
"testing"
"time"
)
func signal(id, rule, evaluation string, state State, labels map[string]string) Signal {
return Signal{InstanceID: id, RuleID: rule, RuleVersionID: "version-1", Severity: SeverityDegraded, State: state, EvaluationKey: evaluation, ObservedAt: time.Date(2026, time.January, 1, 12, 0, 0, 0, time.UTC), Labels: labels, GroupBy: []string{"host", "application"}, SuppressWhen: []string{"host.unreachable", "dns.failure", "source.unavailable"}}
}
func TestBuildFingerprintIsStableAndIncludesRuleBehavior(t *testing.T) {
first, err := BuildFingerprint("rule-1", "version-1", "entity-1", map[string]string{"application": "media", "host": "pulse"})
if err != nil {
t.Fatal(err)
}
second, err := BuildFingerprint("rule-1", "version-1", "entity-1", map[string]string{"host": "pulse", "application": "media"})
if err != nil {
t.Fatal(err)
}
if first != second || len(first) != 64 {
t.Fatalf("fingerprint instability: %q %q", first, second)
}
changedVersion, err := BuildFingerprint("rule-1", "version-2", "entity-1", map[string]string{"host": "pulse", "application": "media"})
if err != nil {
t.Fatal(err)
}
if changedVersion == first {
t.Fatal("rule version did not affect fingerprint")
}
tooMany := make(map[string]string, MaxFingerprintLabels+1)
for i := 0; i <= MaxFingerprintLabels; i++ {
tooMany["label"+string(rune('a'+i))] = "value"
}
if _, err := BuildFingerprint("rule-1", "version-1", "entity-1", tooMany); !errors.Is(err, ErrInvalidAlertIdentity) {
t.Fatalf("too many labels error = %v", err)
}
}
func TestGroupAndDeduplicateSignalsAreDeterministic(t *testing.T) {
inputs := []Signal{
signal("instance-b", "rule-1", "slot-1", StateFiring, map[string]string{"host": "pulse", "application": "media"}),
signal("instance-a", "rule-1", "slot-1", StateFiring, map[string]string{"host": "pulse", "application": "media"}),
signal("instance-a", "rule-1", "slot-1", StateFiring, map[string]string{"host": "pulse", "application": "media"}),
signal("instance-c", "rule-1", "slot-1", StateFiring, map[string]string{"host": "other", "application": "media"}),
}
deduplicated, err := DeduplicateSignals(inputs)
if err != nil {
t.Fatal(err)
}
if len(deduplicated) != 3 {
t.Fatalf("deduplicated signals = %d, want 3", len(deduplicated))
}
groups, err := GroupSignals(deduplicated)
if err != nil {
t.Fatal(err)
}
if len(groups) != 2 || len(groups[0].Signals) != 1 || len(groups[1].Signals) != 2 {
t.Fatalf("unexpected groups: %#v", groups)
}
if groups[0].Key > groups[1].Key {
t.Fatal("groups are not sorted")
}
}
func TestSuppressionScenariosRemainInspectablyBounded(t *testing.T) {
base := signal("instance-1", "rule-service", "slot-1", StateFiring, map[string]string{"host": "pulse", "application": "web"})
tests := []struct {
name string
cause Cause
want bool
reason string
}{
{name: "host outage", cause: Cause{Key: "host.unreachable", State: StateFiring, Confirmed: true}, want: true, reason: "dependency_failure"},
{name: "dns outage", cause: Cause{Key: "dns.failure", State: StateAcknowledged, Confidence: .9}, want: true, reason: "dependency_failure"},
{name: "source outage", cause: Cause{Key: "source.unavailable", State: StateUnknown, Confirmed: true}, want: true, reason: "source_outage"},
{name: "low confidence", cause: Cause{Key: "host.unreachable", State: StateFiring, Confidence: .5}, want: false, reason: "no_active_suppression_cause"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
decision, err := EvaluateSuppression(base, []Cause{test.cause})
if err != nil {
t.Fatal(err)
}
if decision.Suppressed != test.want || decision.Reason != test.reason {
t.Fatalf("decision = %#v, want suppressed=%v reason=%s", decision, test.want, test.reason)
}
})
}
resolved := base
resolved.State = StateResolved
decision, err := EvaluateSuppression(resolved, []Cause{{Key: "host.unreachable", State: StateFiring, Confirmed: true}})
if err != nil {
t.Fatal(err)
}
if decision.Suppressed {
t.Fatal("resolved alert was suppressed")
}
}