diff --git a/matcher/compat/parse.go b/matcher/compat/parse.go index 14aeb5a2ae..06c747e092 100644 --- a/matcher/compat/parse.go +++ b/matcher/compat/parse.go @@ -24,6 +24,7 @@ import ( "github.com/prometheus/common/model" "github.com/prometheus/alertmanager/featurecontrol" + "github.com/prometheus/alertmanager/matcher/oldparse" "github.com/prometheus/alertmanager/matcher/parse" "github.com/prometheus/alertmanager/pkg/labels" ) @@ -77,7 +78,7 @@ func InitFromFlags(l log.Logger, f featurecontrol.Flagger) { func ClassicMatcherParser(l log.Logger) ParseMatcher { return func(input, origin string) (matcher *labels.Matcher, err error) { level.Debug(l).Log("msg", "Parsing with classic matchers parser", "input", input, "origin", origin) - return labels.ParseMatcher(input) + return oldparse.ParseMatcher(input) } } @@ -86,7 +87,7 @@ func ClassicMatcherParser(l log.Logger) ParseMatcher { func ClassicMatchersParser(l log.Logger) ParseMatchers { return func(input, origin string) (matchers labels.Matchers, err error) { level.Debug(l).Log("msg", "Parsing with classic matchers parser", "input", input, "origin", origin) - return labels.ParseMatchers(input) + return oldparse.ParseMatchers(input) } } @@ -124,7 +125,7 @@ func FallbackMatcherParser(l log.Logger) ParseMatcher { // Parse the input in both parsers to look for disagreement and incompatible // inputs. nMatcher, nErr := parse.Matcher(input) - cMatcher, cErr := labels.ParseMatcher(input) + cMatcher, cErr := oldparse.ParseMatcher(input) if nErr != nil { // If the input is invalid in both parsers, return the error. if cErr != nil { @@ -155,7 +156,7 @@ func FallbackMatchersParser(l log.Logger) ParseMatchers { // Parse the input in both parsers to look for disagreement and incompatible // inputs. nMatchers, nErr := parse.Matchers(input) - cMatchers, cErr := labels.ParseMatchers(input) + cMatchers, cErr := oldparse.ParseMatchers(input) if nErr != nil { // If the input is invalid in both parsers, return the error. if cErr != nil { diff --git a/pkg/labels/parse.go b/matcher/oldparse/parse.go similarity index 91% rename from pkg/labels/parse.go rename to matcher/oldparse/parse.go index f84b29e84b..492f8e0bb4 100644 --- a/pkg/labels/parse.go +++ b/matcher/oldparse/parse.go @@ -11,24 +11,26 @@ // See the License for the specific language governing permissions and // limitations under the License. -package labels +package oldparse import ( "fmt" "regexp" "strings" "unicode/utf8" + + "github.com/prometheus/alertmanager/pkg/labels" ) var ( // '=~' has to come before '=' because otherwise only the '=' // will be consumed, and the '~' will be part of the 3rd token. re = regexp.MustCompile(`^\s*([a-zA-Z_:][a-zA-Z0-9_:]*)\s*(=~|=|!=|!~)\s*((?s).*?)\s*$`) - typeMap = map[string]MatchType{ - "=": MatchEqual, - "!=": MatchNotEqual, - "=~": MatchRegexp, - "!~": MatchNotRegexp, + typeMap = map[string]labels.MatchType{ + "=": labels.MatchEqual, + "!=": labels.MatchNotEqual, + "=~": labels.MatchRegexp, + "!~": labels.MatchNotRegexp, } ) @@ -52,8 +54,8 @@ var ( // statuscode=~"5.." // // See ParseMatcher for details on how an individual Matcher is parsed. -func ParseMatchers(s string) ([]*Matcher, error) { - matchers := []*Matcher{} +func ParseMatchers(s string) ([]*labels.Matcher, error) { + matchers := []*labels.Matcher{} s = strings.TrimPrefix(s, "{") s = strings.TrimSuffix(s, "}") @@ -114,7 +116,7 @@ func ParseMatchers(s string) ([]*Matcher, error) { // character). However, literal line feed characters are tolerated, as are // single '\' characters not followed by '\', 'n', or '"'. They act as a literal // backslash in that case. -func ParseMatcher(s string) (_ *Matcher, err error) { +func ParseMatcher(s string) (_ *labels.Matcher, err error) { ms := re.FindStringSubmatch(s) if len(ms) == 0 { return nil, fmt.Errorf("bad matcher format: %s", s) @@ -174,5 +176,5 @@ func ParseMatcher(s string) (_ *Matcher, err error) { return nil, fmt.Errorf("matcher value contains unescaped double quote: %s", ms[3]) } - return NewMatcher(typeMap[ms[2]], ms[1], value.String()) + return labels.NewMatcher(typeMap[ms[2]], ms[1], value.String()) } diff --git a/matcher/oldparse/parse_test.go b/matcher/oldparse/parse_test.go new file mode 100644 index 0000000000..0b9adc19be --- /dev/null +++ b/matcher/oldparse/parse_test.go @@ -0,0 +1,420 @@ +// Copyright 2018 Prometheus Team +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package oldparse + +import ( + "reflect" + "testing" + + "github.com/prometheus/alertmanager/pkg/labels" +) + +func TestMatchers(t *testing.T) { + for _, tc := range []struct { + input string + want []*labels.Matcher + err string + }{ + { + input: `{}`, + want: make([]*labels.Matcher, 0), + }, + { + input: `,`, + err: "bad matcher format: ", + }, + { + input: `{,}`, + err: "bad matcher format: ", + }, + { + input: `{foo='}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "'") + return append(ms, m) + }(), + }, + { + input: "{foo=`}", + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "`") + return append(ms, m) + }(), + }, + { + input: "{foo=\\\"}", + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "\"") + return append(ms, m) + }(), + }, + { + input: `{foo=bar}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + return append(ms, m) + }(), + }, + { + input: `{foo="bar"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + return append(ms, m) + }(), + }, + { + input: `{foo=~bar.*}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchRegexp, "foo", "bar.*") + return append(ms, m) + }(), + }, + { + input: `{foo=~"bar.*"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchRegexp, "foo", "bar.*") + return append(ms, m) + }(), + }, + { + input: `{foo!=bar}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchNotEqual, "foo", "bar") + return append(ms, m) + }(), + }, + { + input: `{foo!="bar"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchNotEqual, "foo", "bar") + return append(ms, m) + }(), + }, + { + input: `{foo!~bar.*}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchNotRegexp, "foo", "bar.*") + return append(ms, m) + }(), + }, + { + input: `{foo!~"bar.*"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchNotRegexp, "foo", "bar.*") + return append(ms, m) + }(), + }, + { + input: `{foo="bar", baz!="quux"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotEqual, "baz", "quux") + return append(ms, m, m2) + }(), + }, + { + input: `{foo="bar", baz!~"quux.*"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotRegexp, "baz", "quux.*") + return append(ms, m, m2) + }(), + }, + { + input: `{foo="bar",baz!~".*quux", derp="wat"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotRegexp, "baz", ".*quux") + m3, _ := labels.NewMatcher(labels.MatchEqual, "derp", "wat") + return append(ms, m, m2, m3) + }(), + }, + { + input: `{foo="bar", baz!="quux", derp="wat"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotEqual, "baz", "quux") + m3, _ := labels.NewMatcher(labels.MatchEqual, "derp", "wat") + return append(ms, m, m2, m3) + }(), + }, + { + input: `{foo="bar", baz!~".*quux.*", derp="wat"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotRegexp, "baz", ".*quux.*") + m3, _ := labels.NewMatcher(labels.MatchEqual, "derp", "wat") + return append(ms, m, m2, m3) + }(), + }, + { + input: `{foo="bar", instance=~"some-api.*"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchRegexp, "instance", "some-api.*") + return append(ms, m, m2) + }(), + }, + { + input: `{foo=""}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "") + return append(ms, m) + }(), + }, + { + input: `{foo="bar,quux", job="job1"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar,quux") + m2, _ := labels.NewMatcher(labels.MatchEqual, "job", "job1") + return append(ms, m, m2) + }(), + }, + { + input: `{foo = "bar", dings != "bums", }`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotEqual, "dings", "bums") + return append(ms, m, m2) + }(), + }, + { + input: `foo=bar,dings!=bums`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar") + m2, _ := labels.NewMatcher(labels.MatchNotEqual, "dings", "bums") + return append(ms, m, m2) + }(), + }, + { + input: `{quote="She said: \"Hi, ladies! That's gender-neutral…\""}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "quote", `She said: "Hi, ladies! That's gender-neutral…"`) + return append(ms, m) + }(), + }, + { + input: `statuscode=~"5.."`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchRegexp, "statuscode", "5..") + return append(ms, m) + }(), + }, + { + input: `tricky=~~~`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchRegexp, "tricky", "~~") + return append(ms, m) + }(), + }, + { + input: `trickier==\\=\=\"`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "trickier", `=\=\="`) + return append(ms, m) + }(), + }, + { + input: `contains_quote != "\"" , contains_comma !~ "foo,bar" , `, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchNotEqual, "contains_quote", `"`) + m2, _ := labels.NewMatcher(labels.MatchNotRegexp, "contains_comma", "foo,bar") + return append(ms, m, m2) + }(), + }, + { + input: `{foo=bar}}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar}") + return append(ms, m) + }(), + }, + { + input: `{foo=bar}},}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar}}") + return append(ms, m) + }(), + }, + { + input: `{foo=,bar=}}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m1, _ := labels.NewMatcher(labels.MatchEqual, "foo", "") + m2, _ := labels.NewMatcher(labels.MatchEqual, "bar", "}") + return append(ms, m1, m2) + }(), + }, + { + input: `{foo=bar\t}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar\\t") + return append(ms, m) + }(), + }, + { + input: `{foo=bar\n}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar\n") + return append(ms, m) + }(), + }, + { + input: `{foo=bar\}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar\\") + return append(ms, m) + }(), + }, + { + input: `{foo=bar\\}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar\\") + return append(ms, m) + }(), + }, + { + input: `{foo=bar\"}`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "bar\"") + return append(ms, m) + }(), + }, + { + input: `job=`, + want: func() []*labels.Matcher { + m, _ := labels.NewMatcher(labels.MatchEqual, "job", "") + return []*labels.Matcher{m} + }(), + }, + { + input: `job="value`, + err: `matcher value contains unescaped double quote: "value`, + }, + { + input: `job=value"`, + err: `matcher value contains unescaped double quote: value"`, + }, + { + input: `trickier==\\=\=\""`, + err: `matcher value contains unescaped double quote: =\\=\=\""`, + }, + { + input: `contains_unescaped_quote = foo"bar`, + err: `matcher value contains unescaped double quote: foo"bar`, + }, + { + input: `{invalid-name = "valid label"}`, + err: `bad matcher format: invalid-name = "valid label"`, + }, + { + input: `{foo=~"invalid[regexp"}`, + err: "error parsing regexp: missing closing ]: `[regexp)$`", + }, + // Double escaped strings. + { + input: `"{foo=\"bar"}`, + err: `bad matcher format: "{foo=\"bar"`, + }, + { + input: `"foo=\"bar"`, + err: `bad matcher format: "foo=\"bar"`, + }, + { + input: `"foo=\"bar\""`, + err: `bad matcher format: "foo=\"bar\""`, + }, + { + input: `"foo=\"bar\"`, + err: `bad matcher format: "foo=\"bar\"`, + }, + { + input: `"{foo=\"bar\"}"`, + err: `bad matcher format: "{foo=\"bar\"}"`, + }, + { + input: `"foo="bar""`, + err: `bad matcher format: "foo="bar""`, + }, + { + input: `{{foo=`, + err: `bad matcher format: {foo=`, + }, + { + input: `{foo=`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "") + return append(ms, m) + }(), + }, + { + input: `{foo=}b`, + want: func() []*labels.Matcher { + ms := []*labels.Matcher{} + m, _ := labels.NewMatcher(labels.MatchEqual, "foo", "}b") + return append(ms, m) + }(), + }, + } { + t.Run(tc.input, func(t *testing.T) { + got, err := ParseMatchers(tc.input) + if err != nil && tc.err == "" { + t.Fatalf("got error where none expected: %v", err) + } + if err == nil && tc.err != "" { + t.Fatalf("expected error but got none: %v", tc.err) + } + if err != nil && err.Error() != tc.err { + t.Fatalf("error not equal:\ngot %v\nwant %v", err, tc.err) + } + if !reflect.DeepEqual(got, tc.want) { + t.Fatalf("labels not equal:\ngot %v\nwant %v", got, tc.want) + } + }) + } +} diff --git a/pkg/labels/parse_test.go b/pkg/labels/parse_test.go deleted file mode 100644 index dd1731c9b7..0000000000 --- a/pkg/labels/parse_test.go +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2018 Prometheus Team -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package labels - -import ( - "reflect" - "testing" -) - -func TestMatchers(t *testing.T) { - for _, tc := range []struct { - input string - want []*Matcher - err string - }{ - { - input: `{}`, - want: make([]*Matcher, 0), - }, - { - input: `,`, - err: "bad matcher format: ", - }, - { - input: `{,}`, - err: "bad matcher format: ", - }, - { - input: `{foo='}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "'") - return append(ms, m) - }(), - }, - { - input: "{foo=`}", - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "`") - return append(ms, m) - }(), - }, - { - input: "{foo=\\\"}", - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "\"") - return append(ms, m) - }(), - }, - { - input: `{foo=bar}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - return append(ms, m) - }(), - }, - { - input: `{foo="bar"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - return append(ms, m) - }(), - }, - { - input: `{foo=~bar.*}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchRegexp, "foo", "bar.*") - return append(ms, m) - }(), - }, - { - input: `{foo=~"bar.*"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchRegexp, "foo", "bar.*") - return append(ms, m) - }(), - }, - { - input: `{foo!=bar}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchNotEqual, "foo", "bar") - return append(ms, m) - }(), - }, - { - input: `{foo!="bar"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchNotEqual, "foo", "bar") - return append(ms, m) - }(), - }, - { - input: `{foo!~bar.*}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchNotRegexp, "foo", "bar.*") - return append(ms, m) - }(), - }, - { - input: `{foo!~"bar.*"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchNotRegexp, "foo", "bar.*") - return append(ms, m) - }(), - }, - { - input: `{foo="bar", baz!="quux"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotEqual, "baz", "quux") - return append(ms, m, m2) - }(), - }, - { - input: `{foo="bar", baz!~"quux.*"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotRegexp, "baz", "quux.*") - return append(ms, m, m2) - }(), - }, - { - input: `{foo="bar",baz!~".*quux", derp="wat"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotRegexp, "baz", ".*quux") - m3, _ := NewMatcher(MatchEqual, "derp", "wat") - return append(ms, m, m2, m3) - }(), - }, - { - input: `{foo="bar", baz!="quux", derp="wat"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotEqual, "baz", "quux") - m3, _ := NewMatcher(MatchEqual, "derp", "wat") - return append(ms, m, m2, m3) - }(), - }, - { - input: `{foo="bar", baz!~".*quux.*", derp="wat"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotRegexp, "baz", ".*quux.*") - m3, _ := NewMatcher(MatchEqual, "derp", "wat") - return append(ms, m, m2, m3) - }(), - }, - { - input: `{foo="bar", instance=~"some-api.*"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchRegexp, "instance", "some-api.*") - return append(ms, m, m2) - }(), - }, - { - input: `{foo=""}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "") - return append(ms, m) - }(), - }, - { - input: `{foo="bar,quux", job="job1"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar,quux") - m2, _ := NewMatcher(MatchEqual, "job", "job1") - return append(ms, m, m2) - }(), - }, - { - input: `{foo = "bar", dings != "bums", }`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotEqual, "dings", "bums") - return append(ms, m, m2) - }(), - }, - { - input: `foo=bar,dings!=bums`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar") - m2, _ := NewMatcher(MatchNotEqual, "dings", "bums") - return append(ms, m, m2) - }(), - }, - { - input: `{quote="She said: \"Hi, ladies! That's gender-neutral…\""}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "quote", `She said: "Hi, ladies! That's gender-neutral…"`) - return append(ms, m) - }(), - }, - { - input: `statuscode=~"5.."`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchRegexp, "statuscode", "5..") - return append(ms, m) - }(), - }, - { - input: `tricky=~~~`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchRegexp, "tricky", "~~") - return append(ms, m) - }(), - }, - { - input: `trickier==\\=\=\"`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "trickier", `=\=\="`) - return append(ms, m) - }(), - }, - { - input: `contains_quote != "\"" , contains_comma !~ "foo,bar" , `, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchNotEqual, "contains_quote", `"`) - m2, _ := NewMatcher(MatchNotRegexp, "contains_comma", "foo,bar") - return append(ms, m, m2) - }(), - }, - { - input: `{foo=bar}}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar}") - return append(ms, m) - }(), - }, - { - input: `{foo=bar}},}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar}}") - return append(ms, m) - }(), - }, - { - input: `{foo=,bar=}}`, - want: func() []*Matcher { - ms := []*Matcher{} - m1, _ := NewMatcher(MatchEqual, "foo", "") - m2, _ := NewMatcher(MatchEqual, "bar", "}") - return append(ms, m1, m2) - }(), - }, - { - input: `{foo=bar\t}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar\\t") - return append(ms, m) - }(), - }, - { - input: `{foo=bar\n}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar\n") - return append(ms, m) - }(), - }, - { - input: `{foo=bar\}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar\\") - return append(ms, m) - }(), - }, - { - input: `{foo=bar\\}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar\\") - return append(ms, m) - }(), - }, - { - input: `{foo=bar\"}`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "bar\"") - return append(ms, m) - }(), - }, - { - input: `job=`, - want: func() []*Matcher { - m, _ := NewMatcher(MatchEqual, "job", "") - return []*Matcher{m} - }(), - }, - { - input: `job="value`, - err: `matcher value contains unescaped double quote: "value`, - }, - { - input: `job=value"`, - err: `matcher value contains unescaped double quote: value"`, - }, - { - input: `trickier==\\=\=\""`, - err: `matcher value contains unescaped double quote: =\\=\=\""`, - }, - { - input: `contains_unescaped_quote = foo"bar`, - err: `matcher value contains unescaped double quote: foo"bar`, - }, - { - input: `{invalid-name = "valid label"}`, - err: `bad matcher format: invalid-name = "valid label"`, - }, - { - input: `{foo=~"invalid[regexp"}`, - err: "error parsing regexp: missing closing ]: `[regexp)$`", - }, - // Double escaped strings. - { - input: `"{foo=\"bar"}`, - err: `bad matcher format: "{foo=\"bar"`, - }, - { - input: `"foo=\"bar"`, - err: `bad matcher format: "foo=\"bar"`, - }, - { - input: `"foo=\"bar\""`, - err: `bad matcher format: "foo=\"bar\""`, - }, - { - input: `"foo=\"bar\"`, - err: `bad matcher format: "foo=\"bar\"`, - }, - { - input: `"{foo=\"bar\"}"`, - err: `bad matcher format: "{foo=\"bar\"}"`, - }, - { - input: `"foo="bar""`, - err: `bad matcher format: "foo="bar""`, - }, - { - input: `{{foo=`, - err: `bad matcher format: {foo=`, - }, - { - input: `{foo=`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "") - return append(ms, m) - }(), - }, - { - input: `{foo=}b`, - want: func() []*Matcher { - ms := []*Matcher{} - m, _ := NewMatcher(MatchEqual, "foo", "}b") - return append(ms, m) - }(), - }, - } { - t.Run(tc.input, func(t *testing.T) { - got, err := ParseMatchers(tc.input) - if err != nil && tc.err == "" { - t.Fatalf("got error where none expected: %v", err) - } - if err == nil && tc.err != "" { - t.Fatalf("expected error but got none: %v", tc.err) - } - if err != nil && err.Error() != tc.err { - t.Fatalf("error not equal:\ngot %v\nwant %v", err, tc.err) - } - if !reflect.DeepEqual(got, tc.want) { - t.Fatalf("labels not equal:\ngot %v\nwant %v", got, tc.want) - } - }) - } -}