diff --git a/alertmanager/dedup.go b/alertmanager/dedup.go index 2f6646f57..b5281df13 100644 --- a/alertmanager/dedup.go +++ b/alertmanager/dedup.go @@ -4,6 +4,7 @@ import ( "sort" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" ) // DedupAlerts will collect alert groups from all defined Alertmanager @@ -91,7 +92,7 @@ func DedupAutocomplete() []models.Autocomplete { h, found := uniqueAutocomplete[hint.Value] if found { for _, token := range hint.Tokens { - if !stringInSlice(h.Tokens, token) { + if !slices.StringInSlice(h.Tokens, token) { h.Tokens = append(h.Tokens, token) } } diff --git a/alertmanager/slices.go b/alertmanager/slices.go deleted file mode 100644 index f74dea2e0..000000000 --- a/alertmanager/slices.go +++ /dev/null @@ -1,19 +0,0 @@ -package alertmanager - -func boolInSlice(boolArray []bool, value bool) bool { - for _, s := range boolArray { - if s == value { - return true - } - } - return false -} - -func stringInSlice(stringArray []string, value string) bool { - for _, s := range stringArray { - if s == value { - return true - } - } - return false -} diff --git a/config/config_test.go b/config/config_test.go index 6e818fd48..b801b366e 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -4,6 +4,8 @@ import ( "os" "testing" "time" + + "github.com/cloudflare/unsee/slices" ) type flagNameTest struct { @@ -26,15 +28,6 @@ func TestMakeFlagName(t *testing.T) { } } -func stringInSlice(stringArray []string, value string) bool { - for _, s := range stringArray { - if s == value { - return true - } - } - return false -} - func TestReadConfig(t *testing.T) { os.Setenv("ALERTMANAGER_TTL", "1s") os.Setenv("ALERTMANAGER_URI", "http://localhost") @@ -47,13 +40,13 @@ func TestReadConfig(t *testing.T) { if Config.Debug != true { t.Errorf("Config.Debug is %v with env DEBUG=true set", Config.Debug) } - if !stringInSlice(Config.ColorLabelsStatic, "a") { + if !slices.StringInSlice(Config.ColorLabelsStatic, "a") { t.Errorf("Config.ColorLabelsStatic is missing value 'a': %v", Config.ColorLabelsStatic) } - if !stringInSlice(Config.ColorLabelsStatic, "bb") { + if !slices.StringInSlice(Config.ColorLabelsStatic, "bb") { t.Errorf("Config.ColorLabelsStatic is missing value 'bb': %v", Config.ColorLabelsStatic) } - if !stringInSlice(Config.ColorLabelsStatic, "ccc") { + if !slices.StringInSlice(Config.ColorLabelsStatic, "ccc") { t.Errorf("Config.ColorLabelsStatic is missing value 'ccc': %v", Config.ColorLabelsStatic) } if Config.Port != 8080 { diff --git a/filters/filter.go b/filters/filter.go index 77ccb2c41..7f4e80ab1 100644 --- a/filters/filter.go +++ b/filters/filter.go @@ -5,6 +5,7 @@ import ( "regexp" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" ) // FilterT provides methods for interacting with alert filters @@ -100,7 +101,7 @@ func NewFilter(expression string) FilterT { // filter name doesn't match, keep searching continue } - if !stringInSlice(fc.SupportedOperators, operator) { + if !slices.StringInSlice(fc.SupportedOperators, operator) { return &invalid } matcher, err := newMatcher(operator) diff --git a/filters/filter_state.go b/filters/filter_state.go index 1b23fa03a..77c424d1c 100644 --- a/filters/filter_state.go +++ b/filters/filter_state.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" ) type stateFilter struct { @@ -19,7 +20,7 @@ func (filter *stateFilter) init(name string, matcher *matcherT, rawText string, filter.RawText = rawText filter.IsValid = isValid filter.Value = value - if !stringInSlice(models.AlertStateList, value) { + if !slices.StringInSlice(models.AlertStateList, value) { filter.IsValid = false } } diff --git a/filters/slices.go b/filters/slices.go deleted file mode 100644 index 218e4d991..000000000 --- a/filters/slices.go +++ /dev/null @@ -1,10 +0,0 @@ -package filters - -func stringInSlice(stringArray []string, value string) bool { - for _, s := range stringArray { - if s == value { - return true - } - } - return false -} diff --git a/slices/slices.go b/slices/slices.go new file mode 100644 index 000000000..a18d400e3 --- /dev/null +++ b/slices/slices.go @@ -0,0 +1,21 @@ +package slices + +// BoolInSlice returns true if given bool is found in a slice of bools +func BoolInSlice(boolArray []bool, value bool) bool { + for _, s := range boolArray { + if s == value { + return true + } + } + return false +} + +// StringInSlice returns true if given string is found in a slice of strings +func StringInSlice(stringArray []string, value string) bool { + for _, s := range stringArray { + if s == value { + return true + } + } + return false +} diff --git a/slices/slices_test.go b/slices/slices_test.go new file mode 100644 index 000000000..1afc117d3 --- /dev/null +++ b/slices/slices_test.go @@ -0,0 +1,113 @@ +package slices_test + +import ( + "testing" + + "github.com/cloudflare/unsee/slices" +) + +type stringSliceTest struct { + array []string + value string + found bool +} + +var stringSliceTests = []stringSliceTest{ + stringSliceTest{ + array: []string{}, + value: "aa", + found: false, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "aa", + found: true, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "bb", + found: true, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "cc", + found: true, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "dd", + found: true, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "bbcc", + found: false, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "b", + found: false, + }, + stringSliceTest{ + array: []string{"aa", "bb", "cc", "dd"}, + value: "", + found: false, + }, +} + +func TestStringInSlice(t *testing.T) { + for _, testCase := range stringSliceTests { + found := slices.StringInSlice(testCase.array, testCase.value) + if found != testCase.found { + t.Errorf("Check if '%s' in slice %v returned %t, expected %t", testCase.value, testCase.array, found, testCase.found) + } + } +} + +type boolSliceTest struct { + array []bool + value bool + found bool +} + +var boolSliceTests = []boolSliceTest{ + boolSliceTest{ + array: []bool{}, + value: true, + found: false, + }, + boolSliceTest{ + array: []bool{}, + value: false, + found: false, + }, + boolSliceTest{ + array: []bool{true, false}, + value: true, + found: true, + }, + boolSliceTest{ + array: []bool{true, false}, + value: false, + found: true, + }, + boolSliceTest{ + array: []bool{false}, + value: true, + found: false, + }, + boolSliceTest{ + array: []bool{true}, + value: false, + found: false, + }, +} + +func TestBoolInSlice(t *testing.T) { + for _, testCase := range boolSliceTests { + found := slices.BoolInSlice(testCase.array, testCase.value) + if found != testCase.found { + t.Errorf("Check if '%t' in slice %v returned %t, expected %t", testCase.value, testCase.array, found, testCase.found) + } + } +} diff --git a/transform/colors.go b/transform/colors.go index 0c347c055..29f9da76f 100644 --- a/transform/colors.go +++ b/transform/colors.go @@ -7,6 +7,7 @@ import ( "github.com/cloudflare/unsee/config" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" "github.com/hansrodtang/randomcolor" ) @@ -26,7 +27,7 @@ func labelToSeed(key string, val string) int64 { // from label key and value passed here // It's used to generate unique colors for configured labels func ColorLabel(colorStore models.LabelsColorMap, key string, val string) { - if stringInSlice(config.Config.ColorLabelsUnique, key) == true { + if slices.StringInSlice(config.Config.ColorLabelsUnique, key) == true { if _, found := colorStore[key]; !found { colorStore[key] = make(map[string]models.LabelColors) } diff --git a/transform/links.go b/transform/links.go index 99d1c482c..a6e0dc80a 100644 --- a/transform/links.go +++ b/transform/links.go @@ -1,6 +1,10 @@ package transform -import "net/url" +import ( + "net/url" + + "github.com/cloudflare/unsee/slices" +) // list of URI schema which we turn into links in the UI var schemes = []string{ @@ -20,7 +24,7 @@ func DetectLinks(sourceAnnotations map[string]string) (map[string]string, map[st u, err := url.Parse(v) if err != nil { annotations[k] = v - } else if stringInSlice(schemes, u.Scheme) { + } else if slices.StringInSlice(schemes, u.Scheme) { links[k] = v } else { annotations[k] = v diff --git a/transform/slices.go b/transform/slices.go deleted file mode 100644 index b57730d9e..000000000 --- a/transform/slices.go +++ /dev/null @@ -1,10 +0,0 @@ -package transform - -func stringInSlice(stringArray []string, value string) bool { - for _, s := range stringArray { - if s == value { - return true - } - } - return false -} diff --git a/transform/slices_test.go b/transform/slices_test.go deleted file mode 100644 index b9a5355f7..000000000 --- a/transform/slices_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package transform - -import "testing" - -type sliceTest struct { - array []string - value string - found bool -} - -var sliceTests = []sliceTest{ - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "aa", - found: true, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "bb", - found: true, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "cc", - found: true, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "dd", - found: true, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "bbcc", - found: false, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "b", - found: false, - }, - sliceTest{ - array: []string{"aa", "bb", "cc", "dd"}, - value: "", - found: false, - }, -} - -func TestStringInSlice(t *testing.T) { - for _, testCase := range sliceTests { - found := stringInSlice(testCase.array, testCase.value) - if found != testCase.found { - t.Errorf("Check if '%s' in slice %v returned %v, expected %v", testCase.value, testCase.array, found, testCase.found) - } - } -} diff --git a/transform/strip.go b/transform/strip.go index 464e10086..db03a37de 100644 --- a/transform/strip.go +++ b/transform/strip.go @@ -2,6 +2,8 @@ package transform import ( "strings" + + "github.com/cloudflare/unsee/slices" ) // StripLables allows filtering out some labels from alerts @@ -10,7 +12,7 @@ import ( func StripLables(ignoredLabels []string, sourceLabels map[string]string) map[string]string { labels := map[string]string{} for label, value := range sourceLabels { - if !stringInSlice(ignoredLabels, label) { + if !slices.StringInSlice(ignoredLabels, label) { // strip leading and trailung space in label value // this is to normalize values in case space is added by Alertmanager rules labels[label] = strings.TrimSpace(value) diff --git a/views.go b/views.go index 6cbebd17a..089036841 100644 --- a/views.go +++ b/views.go @@ -10,6 +10,7 @@ import ( "github.com/cloudflare/unsee/alertmanager" "github.com/cloudflare/unsee/config" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" log "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" @@ -20,15 +21,6 @@ var ( faviconFileServer = http.FileServer(newBinaryFileSystem("static")) ) -func boolInSlice(boolArray []bool, value bool) bool { - for _, s := range boolArray { - if s == value { - return true - } - } - return false -} - func noCache(c *gin.Context) { c.Header("Cache-Control", "no-cache, no-store, must-revalidate") } @@ -151,7 +143,7 @@ func alerts(c *gin.Context) { } } } - if !validFilters || (boolInSlice(results, true) && !boolInSlice(results, false)) { + if !validFilters || (slices.BoolInSlice(results, true) && !slices.BoolInSlice(results, false)) { matches++ agCopy.Alerts = append(agCopy.Alerts, alert) diff --git a/views_test.go b/views_test.go index 899ce90f1..41a1fe725 100644 --- a/views_test.go +++ b/views_test.go @@ -12,6 +12,7 @@ import ( "github.com/cloudflare/unsee/config" "github.com/cloudflare/unsee/mock" "github.com/cloudflare/unsee/models" + "github.com/cloudflare/unsee/slices" log "github.com/Sirupsen/logrus" "github.com/gin-gonic/gin" @@ -20,15 +21,6 @@ import ( "gopkg.in/jarcoal/httpmock.v1" ) -func stringInSlice(stringArray []string, value string) bool { - for _, s := range stringArray { - if s == value { - return true - } - } - return false -} - func mockConfig() { log.SetLevel(log.ErrorLevel) os.Setenv("ALERTMANAGER_URI", "default:http://localhost") @@ -48,7 +40,7 @@ func ginTestEngine() *gin.Engine { func TestIndex(t *testing.T) { mockConfig() r := ginTestEngine() - req, _ := http.NewRequest("GET", "/", nil) + req, _ := http.NewRequest("GET", "/?q=", nil) resp := httptest.NewRecorder() r.ServeHTTP(resp, req) if resp.Code != http.StatusOK { @@ -181,7 +173,7 @@ func TestValidateAllAlerts(t *testing.T) { json.Unmarshal(resp.Body.Bytes(), &ur) for _, ag := range ur.AlertGroups { for _, a := range ag.Alerts { - if !stringInSlice(models.AlertStateList, a.State) { + if !slices.StringInSlice(models.AlertStateList, a.State) { t.Errorf("Invalid alert status '%s', not in %v", a.State, models.AlertStateList) } if a.InhibitedBy == nil {