From ae6fcbeeeee4414426d9d34e5b7584736b30fbdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Mon, 17 Jul 2017 18:53:00 -0700 Subject: [PATCH 1/2] Add basic alertmanager package tests & benchmarks --- alertmanager/benchmark_test.go | 39 ++++++++++++++++++++ alertmanager/dedup_test.go | 65 ++++++++++++++++++++++++++++++++++ mock/mock.go | 11 ++++++ 3 files changed, 115 insertions(+) create mode 100644 alertmanager/benchmark_test.go create mode 100644 alertmanager/dedup_test.go diff --git a/alertmanager/benchmark_test.go b/alertmanager/benchmark_test.go new file mode 100644 index 000000000..94e9e18b9 --- /dev/null +++ b/alertmanager/benchmark_test.go @@ -0,0 +1,39 @@ +package alertmanager_test + +import ( + "os" + "testing" + + "github.com/cloudflare/unsee/alertmanager" + "github.com/cloudflare/unsee/config" +) + +func BenchmarkDedupAlerts(b *testing.B) { + if err := pullAlerts(); err != nil { + b.Error(err) + } + for n := 0; n < b.N; n++ { + alertmanager.DedupAlerts() + } +} + +func BenchmarkDedupAutocomplete(b *testing.B) { + if err := pullAlerts(); err != nil { + b.Error(err) + } + for n := 0; n < b.N; n++ { + alertmanager.DedupAutocomplete() + } +} + +func BenchmarkDedupColors(b *testing.B) { + os.Setenv("COLOR_LABELS_UNIQUE", "cluster instance @receiver") + os.Setenv("ALERTMANAGER_URIS", "default:http://localhost") + config.Config.Read() + if err := pullAlerts(); err != nil { + b.Error(err) + } + for n := 0; n < b.N; n++ { + alertmanager.DedupColors() + } +} diff --git a/alertmanager/dedup_test.go b/alertmanager/dedup_test.go new file mode 100644 index 000000000..4ff9e06b2 --- /dev/null +++ b/alertmanager/dedup_test.go @@ -0,0 +1,65 @@ +package alertmanager_test + +import ( + "os" + "testing" + "time" + + "github.com/cloudflare/unsee/alertmanager" + "github.com/cloudflare/unsee/config" + "github.com/cloudflare/unsee/mock" + + log "github.com/sirupsen/logrus" +) + +func init() { + log.SetLevel(log.ErrorLevel) + for i, uri := range mock.ListAllMockURIs() { + alertmanager.NewAlertmanager(string(i), uri, time.Second) + } +} + +func pullAlerts() error { + for _, am := range alertmanager.GetAlertmanagers() { + err := am.Pull() + if err != nil { + return err + } + } + return nil +} + +func TestDedupAlerts(t *testing.T) { + if err := pullAlerts(); err != nil { + t.Error(err) + } + alertGroups := alertmanager.DedupAlerts() + if len(alertGroups) != 10 { + t.Errorf("Expected %d alert groups, got %d", 10, len(alertGroups)) + } +} + +func TestDedupAutocomplete(t *testing.T) { + if err := pullAlerts(); err != nil { + t.Error(err) + } + ac := alertmanager.DedupAutocomplete() + expected := 74 + if len(ac) != expected { + t.Errorf("Expected %d autocomplete hints, got %d", expected, len(ac)) + } +} + +func TestDedupColors(t *testing.T) { + os.Setenv("COLOR_LABELS_UNIQUE", "cluster instance @receiver") + os.Setenv("ALERTMANAGER_URIS", "default:http://localhost") + config.Config.Read() + if err := pullAlerts(); err != nil { + t.Error(err) + } + colors := alertmanager.DedupColors() + expected := 3 + if len(colors) != expected { + t.Errorf("Expected %d color keys, got %d", expected, len(colors)) + } +} diff --git a/mock/mock.go b/mock/mock.go index 159c25bd8..dc6ec1484 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -52,3 +52,14 @@ func ListAllMocks() []string { } return dirs } + +// ListAllMockURIs returns a list of mock APIs as file:// URIs +func ListAllMockURIs() []string { + uris := []string{} + _, f, _, _ := runtime.Caller(0) + cwd := filepath.Dir(f) + for _, version := range ListAllMocks() { + uris = append(uris, "file://"+path.Join(cwd, version)) + } + return uris +} From d02e8569aaab9f8d450e9bf69d4f82408ba81d75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Mon, 17 Jul 2017 19:04:54 -0700 Subject: [PATCH 2/2] Refactor group fingerpint tests Depending on exact value breaks when testing with a different Go version since implementation details might cause structhash to return a different hash. We don't depend on exact values in the UI, we only require that those values are unique to a unique set of labels and selected attributes, so that's what we should test rather than hardcoded values. This PR allows unsee to pass tests under Go 1.9beta2 --- models/alertgroup_test.go | 94 ++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 25 deletions(-) diff --git a/models/alertgroup_test.go b/models/alertgroup_test.go index 8a2edd868..1e9e05ed2 100644 --- a/models/alertgroup_test.go +++ b/models/alertgroup_test.go @@ -69,42 +69,42 @@ func TestUnseeAlertListSort(t *testing.T) { } type agFPTest struct { - ag models.AlertGroup - fingerprint string + name string // name of the test + ag models.AlertGroup // alert group data + fpChange bool // true if fingerprint should change vs previous run } var agFPTests = []agFPTest{ - // empty group fingerprint agFPTest{ - ag: models.AlertGroup{}, - fingerprint: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + name: "empty group fingerprint", + ag: models.AlertGroup{}, }, - // different Receiver shouldn't change content fingerprint agFPTest{ + name: "different Receiver shouldn't change content fingerprint", ag: models.AlertGroup{ Receiver: "default", }, - fingerprint: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + fpChange: false, }, - // different StateCount shouldn't change content fingerprint agFPTest{ + name: "different StateCount shouldn't change content fingerprint", ag: models.AlertGroup{ Receiver: "default", StateCount: map[string]int{"default": 0}, }, - fingerprint: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + fpChange: false, }, - // different Labels shouldn't change content fingerprint agFPTest{ + name: "different Labels shouldn't change content fingerprint", ag: models.AlertGroup{ Receiver: "default", Labels: map[string]string{"foo": "bar"}, StateCount: map[string]int{"default": 0}, }, - fingerprint: "da39a3ee5e6b4b0d3255bfef95601890afd80709", + fpChange: false, }, - // different set of alerts should change content fingerprint agFPTest{ + name: "different set of alerts should change content fingerprint", ag: models.AlertGroup{ Receiver: "default", Labels: map[string]string{"foo": "bar"}, @@ -116,22 +116,66 @@ var agFPTests = []agFPTest{ }, StateCount: map[string]int{"default": 0}, }, - fingerprint: "87e79b3d507d26f21bc5e82b8db19f87ce46c1ad", + fpChange: true, + }, + agFPTest{ + name: "another different set of alerts should change content fingerprint", + ag: models.AlertGroup{ + Receiver: "default", + Labels: map[string]string{"bar": "foo"}, + Alerts: models.AlertList{ + models.Alert{ + Labels: map[string]string{"bar": "foo"}, + State: models.AlertStateActive, + }, + }, + StateCount: map[string]int{"default": 0}, + }, + fpChange: true, + }, + agFPTest{ + name: "repeating last set of alerts shouldn't change content fingerprint", + ag: models.AlertGroup{ + Receiver: "default", + Labels: map[string]string{"bar": "foo"}, + Alerts: models.AlertList{ + models.Alert{ + Labels: map[string]string{"bar": "foo"}, + State: models.AlertStateActive, + }, + }, + StateCount: map[string]int{"default": 0}, + }, + fpChange: false, }, } func TestAlertGroupContentFingerprint(t *testing.T) { - for _, testCase := range agFPTests { - alerts := models.AlertList{} - for _, alert := range testCase.ag.Alerts { - alert.UpdateFingerprints() - alerts = append(alerts, alert) - } - sort.Sort(alerts) - testCase.ag.Alerts = alerts - if testCase.ag.ContentFingerprint() != testCase.fingerprint { - t.Errorf("Invalid AlertGroup ContentFingerprint(), expected '%s', got '%s', AlertGroup: %v", - testCase.fingerprint, testCase.ag.ContentFingerprint(), testCase.ag) - } + fps := []string{} + for i, testCase := range agFPTests { + t.Run(testCase.name, func(t *testing.T) { + alerts := models.AlertList{} + for _, alert := range testCase.ag.Alerts { + alert.UpdateFingerprints() + alerts = append(alerts, alert) + } + sort.Sort(alerts) + testCase.ag.Alerts = alerts + // get alert group fingerprint + fp := testCase.ag.ContentFingerprint() + // add it to the list + fps = append(fps, fp) + // skip first test case since there's nothing to compare it with + if i > 0 { + // check if current test case generated fingerprint that is different + // from the previous one + fpChange := fp != fps[i-1] + // check if we expected a change or not + if fpChange != testCase.fpChange { + t.Errorf("Fingerprint changed=%t while expected change=%t, alertgroup: %v", + fpChange, testCase.fpChange, testCase.ag) + } + } + }) } }