mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
531 lines
12 KiB
Go
531 lines
12 KiB
Go
package models_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/pmezard/go-difflib/difflib"
|
|
|
|
"github.com/prymitive/karma/internal/models"
|
|
)
|
|
|
|
func TestDedupSharedMaps(t *testing.T) {
|
|
am := models.AlertmanagerInstance{
|
|
Fingerprint: "1",
|
|
Name: "am",
|
|
Cluster: "fakeCluster",
|
|
SilencedBy: []string{"fakeSilence1", "fakeSilence2"},
|
|
Source: "https://am.example.com/graph",
|
|
}
|
|
ag := models.APIAlertGroup{
|
|
AlertGroup: models.AlertGroup{
|
|
Labels: map[string]string{
|
|
"alertname": "FakeAlert",
|
|
},
|
|
Alerts: models.AlertList{
|
|
models.Alert{
|
|
State: models.AlertStateSuppressed,
|
|
Annotations: models.Annotations{
|
|
models.Annotation{
|
|
Name: "summary",
|
|
Value: "this is summary",
|
|
},
|
|
models.Annotation{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
Labels: map[string]string{
|
|
"alertname": "FakeAlert",
|
|
"job": "node_exporter",
|
|
"instance": "1",
|
|
},
|
|
Alertmanager: []models.AlertmanagerInstance{am, am},
|
|
},
|
|
models.Alert{
|
|
State: models.AlertStateSuppressed,
|
|
Annotations: models.Annotations{
|
|
models.Annotation{
|
|
Name: "summary",
|
|
Value: "this is summary",
|
|
},
|
|
},
|
|
Labels: map[string]string{
|
|
"alertname": "FakeAlert",
|
|
"job": "node_exporter",
|
|
"instance": "2",
|
|
},
|
|
Alertmanager: []models.AlertmanagerInstance{am, am},
|
|
},
|
|
models.Alert{
|
|
State: models.AlertStateSuppressed,
|
|
Annotations: models.Annotations{
|
|
models.Annotation{
|
|
Name: "summary",
|
|
Value: "this is summary",
|
|
},
|
|
},
|
|
Labels: map[string]string{
|
|
"alertname": "FakeAlert",
|
|
"job": "blackbox",
|
|
"instance": "3",
|
|
},
|
|
Alertmanager: []models.AlertmanagerInstance{am, am},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ag.DedupSharedMaps()
|
|
|
|
expectedJSON := `{
|
|
"receiver": "",
|
|
"labels": {
|
|
"alertname": "FakeAlert"
|
|
},
|
|
"alerts": [
|
|
{
|
|
"annotations": [
|
|
{
|
|
"name": "foo",
|
|
"value": "bar",
|
|
"visible": false,
|
|
"isLink": false,
|
|
"isAction": false
|
|
}
|
|
],
|
|
"labels": {
|
|
"instance": "1",
|
|
"job": "node_exporter"
|
|
},
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"state": "suppressed",
|
|
"alertmanager": [
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
},
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
}
|
|
],
|
|
"receiver": "",
|
|
"id": ""
|
|
},
|
|
{
|
|
"annotations": [],
|
|
"labels": {
|
|
"instance": "2",
|
|
"job": "node_exporter"
|
|
},
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"state": "suppressed",
|
|
"alertmanager": [
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
},
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
}
|
|
],
|
|
"receiver": "",
|
|
"id": ""
|
|
},
|
|
{
|
|
"annotations": [],
|
|
"labels": {
|
|
"instance": "3",
|
|
"job": "blackbox"
|
|
},
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"state": "suppressed",
|
|
"alertmanager": [
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
},
|
|
{
|
|
"fingerprint": "1",
|
|
"name": "am",
|
|
"cluster": "fakeCluster",
|
|
"state": "",
|
|
"startsAt": "0001-01-01T00:00:00Z",
|
|
"source": "https://am.example.com/graph",
|
|
"silencedBy": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
],
|
|
"inhibitedBy": null
|
|
}
|
|
],
|
|
"receiver": "",
|
|
"id": ""
|
|
}
|
|
],
|
|
"id": "",
|
|
"alertmanagerCount": null,
|
|
"stateCount": null,
|
|
"shared": {
|
|
"annotations": [
|
|
{
|
|
"name": "summary",
|
|
"value": "this is summary",
|
|
"visible": false,
|
|
"isLink": false,
|
|
"isAction": false
|
|
}
|
|
],
|
|
"labels": {},
|
|
"silences": {
|
|
"fakeCluster": [
|
|
"fakeSilence1",
|
|
"fakeSilence2"
|
|
]
|
|
},
|
|
"sources": [
|
|
"https://am.example.com"
|
|
],
|
|
"clusters": [
|
|
"fakeCluster"
|
|
]
|
|
}
|
|
}`
|
|
|
|
agJSON, _ := json.MarshalIndent(ag, "", " ")
|
|
if string(agJSON) != expectedJSON {
|
|
diff := difflib.UnifiedDiff{
|
|
A: difflib.SplitLines(expectedJSON),
|
|
B: difflib.SplitLines(string(agJSON)),
|
|
FromFile: "Expected",
|
|
ToFile: "Current",
|
|
Context: 3,
|
|
}
|
|
text, err := difflib.GetUnifiedDiffString(diff)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
t.Errorf("JSON mismatch:\n%s", text)
|
|
}
|
|
}
|
|
|
|
func TestDedupSharedMapsSingleGroup(t *testing.T) {
|
|
ag := models.APIAlertGroup{
|
|
AlertGroup: models.AlertGroup{
|
|
Alerts: models.AlertList{
|
|
models.Alert{Labels: map[string]string{"foo": "bar"}},
|
|
models.Alert{Labels: map[string]string{"foo": "bar"}},
|
|
},
|
|
},
|
|
}
|
|
ag.DedupSharedMaps()
|
|
if len(ag.Shared.Annotations) > 0 {
|
|
t.Errorf("Expected empty shared annotations, got %v", ag.Shared.Annotations)
|
|
}
|
|
if len(ag.Shared.Labels) == 0 {
|
|
t.Errorf("Expected non-empty shared labels, got %v", ag.Shared.Labels)
|
|
}
|
|
}
|
|
|
|
func TestDedupSharedMapsWithSingleAlert(t *testing.T) {
|
|
ag := models.APIAlertGroup{
|
|
AlertGroup: models.AlertGroup{
|
|
Alerts: models.AlertList{
|
|
models.Alert{},
|
|
},
|
|
},
|
|
}
|
|
ag.DedupSharedMaps()
|
|
if len(ag.Shared.Annotations) > 0 {
|
|
t.Errorf("Expected empty shared annotations, got %v", ag.Shared.Annotations)
|
|
}
|
|
if len(ag.Shared.Labels) > 0 {
|
|
t.Errorf("Expected empty shared labels, got %v", ag.Shared.Labels)
|
|
}
|
|
}
|
|
|
|
func TestDedupWithBadSource(t *testing.T) {
|
|
ag := models.APIAlertGroup{
|
|
AlertGroup: models.AlertGroup{
|
|
Alerts: models.AlertList{
|
|
models.Alert{Alertmanager: []models.AlertmanagerInstance{{Source: "%gh&%ij"}}},
|
|
models.Alert{Alertmanager: []models.AlertmanagerInstance{{Source: ""}}},
|
|
},
|
|
},
|
|
}
|
|
ag.DedupSharedMaps()
|
|
if len(ag.Shared.Sources) > 0 {
|
|
t.Errorf("Expected empty sources list, got %v", ag.Shared.Sources)
|
|
}
|
|
}
|
|
|
|
func TestNameStatsSort(t *testing.T) {
|
|
var nameStats = models.LabelNameStatsList{
|
|
{
|
|
Name: "@state",
|
|
Hits: 24,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "suppressed",
|
|
Raw: "@state=suppressed",
|
|
Hits: 8,
|
|
Percent: 33,
|
|
Offset: 67,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "active",
|
|
Raw: "@state=actuve",
|
|
Hits: 16,
|
|
Percent: 67,
|
|
Offset: 0,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "cluster",
|
|
Hits: 24,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "dev",
|
|
Raw: "cluster=dev",
|
|
Hits: 10,
|
|
Percent: 42,
|
|
Offset: 0,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "prod",
|
|
Raw: "cluster=prod",
|
|
Hits: 6,
|
|
Percent: 25,
|
|
Offset: 42,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "staging",
|
|
Raw: "cluster=staging",
|
|
Hits: 8,
|
|
Percent: 33,
|
|
Offset: 67,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "alertname",
|
|
Hits: 24,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "HTTP_Probe_Failed",
|
|
Raw: "alertname=HTTP_Probe_Failed",
|
|
Hits: 4,
|
|
Percent: 17,
|
|
Offset: 0,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "Host_Down",
|
|
Raw: "alertname=Host_Down",
|
|
Hits: 16,
|
|
Percent: 67,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "Free_Disk_Space_Too_Low",
|
|
Raw: "alertname=Free_Disk_Space_Too_Low",
|
|
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 84,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "Memory_Usage_Too_High",
|
|
Raw: "alertname=Memory_Usage_Too_High",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 92,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "instance",
|
|
Hits: 24,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "server4",
|
|
Raw: "instance=server4",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server5",
|
|
Raw: "instance=server5",
|
|
Hits: 4,
|
|
Percent: 17,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server6",
|
|
Raw: "instance=server6",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server1",
|
|
Raw: "instance=server1",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server2",
|
|
Raw: "instance=server2",
|
|
Hits: 4,
|
|
Percent: 17,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server3",
|
|
Raw: "instance=server3",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server7",
|
|
Raw: "instance=server7",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "server8",
|
|
Raw: "instance=server8",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "web1",
|
|
Raw: "instance=web1",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "web2",
|
|
Raw: "instance=web2",
|
|
Hits: 2,
|
|
Percent: 8,
|
|
Offset: 17,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "@receiver",
|
|
Hits: 24,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "by-name",
|
|
Raw: "@receiver=by-name",
|
|
Hits: 12,
|
|
Percent: 50,
|
|
Offset: 0,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "by-cluster-service",
|
|
Raw: "@receiver=by-cluster-service",
|
|
Hits: 12,
|
|
Percent: 50,
|
|
Offset: 50,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Name: "job",
|
|
Hits: 16,
|
|
Values: models.LabelValueStatsList{
|
|
models.LabelValueStats{
|
|
Value: "node_exporter",
|
|
Raw: "job=node_exporter",
|
|
Hits: 8,
|
|
Percent: 50,
|
|
Offset: 0,
|
|
},
|
|
models.LabelValueStats{
|
|
Value: "node_ping",
|
|
Raw: "job=node_ping",
|
|
Hits: 8,
|
|
Percent: 50,
|
|
Offset: 50,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
b, err := json.Marshal(nameStats)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
before := string(b)
|
|
|
|
for _, n := range nameStats {
|
|
sort.Sort(n.Values)
|
|
}
|
|
sort.Sort(nameStats)
|
|
|
|
a, err := json.Marshal(nameStats)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
after := string(a)
|
|
|
|
if after == before {
|
|
t.Errorf("Sorting LabelNameStatsList produces the same output as unsorted instance")
|
|
}
|
|
}
|