diff --git a/zipper/protocols/prometheus/helpers/helpers.go b/zipper/protocols/prometheus/helpers/helpers.go index b61f21f08..48c590642 100644 --- a/zipper/protocols/prometheus/helpers/helpers.go +++ b/zipper/protocols/prometheus/helpers/helpers.go @@ -139,29 +139,42 @@ func AdjustStep(start, stop, maxPointsPerQuery, minStep int64, forceMinStepInter // PromethizeTagValue - accept 'Tag=value' or 'Tag=~value' string and return sanitized version of it func PromethizeTagValue(tagValue string) (string, types.Tag) { // Handle = and =~ - t := types.Tag{} - idx := strings.Index(tagValue, "=") - if idx != -1 { - if tagValue[idx+1] == '~' { + var ( + t types.Tag + tagName string + idx = strings.Index(tagValue, "=") + ) + + if idx < 0 { + return tagName, t + } + + if idx > 0 && tagValue[idx-1] == '!' { + t.OP = "!" + tagName = tagValue[:idx-1] + } else { + tagName = tagValue[:idx] + } + + switch { + case idx+1 == len(tagValue): // != or = with empty value + t.OP += "=" + case tagValue[idx+1] == '~': + if len(t.OP) > 0 { // !=~ + t.OP += "~" + } else { // =~ t.OP = "=~" - t.TagValue = tagValue[idx+2:] - } else { - t.OP = "=" - t.TagValue = tagValue[idx+1:] } - } else { - // Handle != and !=~ - idx = strings.Index(tagValue, "!") - if tagValue[idx+2] == '~' { - t.OP = "!~" - t.TagValue = tagValue[idx+3:] - } else { - t.OP = "!=" + + if idx+2 < len(tagValue) { // check is not empty value t.TagValue = tagValue[idx+2:] } + default: // != or = with value + t.OP += "=" + t.TagValue = tagValue[idx+1:] } - return tagValue[:idx], t + return tagName, t } // SplitTagValues - For given tag-value list converts it to more usable map[string]Tag, where string is TagName diff --git a/zipper/protocols/prometheus/helpers/helpers_test.go b/zipper/protocols/prometheus/helpers/helpers_test.go index ee0ac3d64..f0df54ce8 100644 --- a/zipper/protocols/prometheus/helpers/helpers_test.go +++ b/zipper/protocols/prometheus/helpers/helpers_test.go @@ -7,6 +7,7 @@ import ( "github.com/go-graphite/carbonapi/tests/compare" "github.com/go-graphite/carbonapi/zipper/protocols/prometheus/types" + "github.com/stretchr/testify/assert" ) func TestAlignValues(t *testing.T) { @@ -161,3 +162,91 @@ func TestAdjustStep(t *testing.T) { }) } } + +func TestPromethizeTagValue(t *testing.T) { + testCases := []struct { + name string + tagValue string + wantName string + wantTag types.Tag + }{ + { + name: "empty string", + }, + { + name: "string without '='", + tagValue: "test>test", + }, + { + name: "check '='", + tagValue: "name=1", + wantName: "name", + wantTag: types.Tag{OP: "=", TagValue: "1"}, + }, + { + name: "check '!='", + tagValue: "name!=1", + wantName: "name", + wantTag: types.Tag{OP: "!=", TagValue: "1"}, + }, + { + name: "check '=~'", + tagValue: "name=~1", + wantName: "name", + wantTag: types.Tag{OP: "=~", TagValue: "1"}, + }, + { + name: "check '!=~'", + tagValue: "name!=~1", + wantName: "name", + wantTag: types.Tag{OP: "!~", TagValue: "1"}, + }, + { + name: "check '!=~' with empty name", + tagValue: "!=~1", + wantName: "", + wantTag: types.Tag{OP: "!~", TagValue: "1"}, + }, + { + name: "check '=~' with empty name", + tagValue: "=~1", + wantName: "", + wantTag: types.Tag{OP: "=~", TagValue: "1"}, + }, + { + name: "check '=' with empty value", + tagValue: "name=", + wantName: "name", + wantTag: types.Tag{OP: "="}, + }, + { + name: "check '!=' with empty value", + tagValue: "name!=", + wantName: "name", + wantTag: types.Tag{OP: "!="}, + }, + { + name: "check '!=~' with empty value", + tagValue: "name!=~", + wantName: "name", + wantTag: types.Tag{OP: "!~"}, + }, + { + name: "check '=~' with empty value", + tagValue: "name=~", + wantName: "name", + wantTag: types.Tag{OP: "=~"}, + }, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + gotName, gotTag := PromethizeTagValue(tt.tagValue) + + assert.Equal(t, tt.wantName, gotName) + assert.Equal(t, tt.wantTag, gotTag) + }) + + } + +}