From f32ec95722c64eb3c74c7fd6dc2ef02d9d7ac7c7 Mon Sep 17 00:00:00 2001 From: Cyril Tovena Date: Wed, 6 Oct 2021 16:22:48 +0200 Subject: [PATCH] Add more tests and support begin/end text. Signed-off-by: Cyril Tovena --- pkg/labels/regexp.go | 20 ++++++++++++++++++++ pkg/labels/regexp_test.go | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/pkg/labels/regexp.go b/pkg/labels/regexp.go index 7fd227e0b5..57544fa000 100644 --- a/pkg/labels/regexp.go +++ b/pkg/labels/regexp.go @@ -117,6 +117,7 @@ func findSetMatchesFromConcat(re *syntax.Regexp, base string) []string { if len(re.Sub) == 0 { return nil } + clearBeginEndText(re) clearCapture(re.Sub...) matches := findSetMatches(re.Sub[0], base) if matches == nil { @@ -165,6 +166,25 @@ func clearCapture(regs ...*syntax.Regexp) { } } +// clearBeginEndText removes the begin and end text from the regexp. Prometheus regexp are anchored to the beginning and end of the string. +func clearBeginEndText(re *syntax.Regexp) { + if len(re.Sub) == 0 { + return + } + if len(re.Sub) == 1 { + if re.Sub[0].Op == syntax.OpBeginText || re.Sub[0].Op == syntax.OpEndText { + re.Sub = nil + return + } + } + if re.Sub[0].Op == syntax.OpBeginText { + re.Sub = re.Sub[1:] + } + if re.Sub[len(re.Sub)-1].Op == syntax.OpEndText { + re.Sub = re.Sub[:len(re.Sub)-1] + } +} + // isCaseInsensitive tells if a regexp is case insensitive. // The flag should be check at each level of the syntax tree. func isCaseInsensitive(reg *syntax.Regexp) bool { diff --git a/pkg/labels/regexp_test.go b/pkg/labels/regexp_test.go index f3d8cc5ebf..9eca3afb0e 100644 --- a/pkg/labels/regexp_test.go +++ b/pkg/labels/regexp_test.go @@ -105,6 +105,8 @@ func TestFindSetMatches(t *testing.T) { }{ // Single value, coming from a `bar=~"foo"` selector. {"foo", []string{"foo"}}, + {"^foo", []string{"foo"}}, + {"^foo$", []string{"foo"}}, // Simple sets alternates. {"foo|bar|zz", []string{"foo", "bar", "zz"}}, // Simple sets alternate and concat (bar|baz is parsed as ba(r|z)). @@ -114,6 +116,8 @@ func TestFindSetMatches(t *testing.T) { // Simple sets alternate and concat and alternates with empty matches // parsed as b(ar|(?:)|uzz) where b(?:) means literal b. {"bar|b|buzz", []string{"bar", "b", "buzz"}}, + // Skip anchors it's enforced anyway at the root. + {"(^bar$)|(b$)|(^buzz)", []string{"bar", "b", "buzz"}}, // Simple sets containing escaped characters. {"fo\\.o|bar\\?|\\^baz", []string{"fo.o", "bar?", "^baz"}}, // using charclass @@ -125,6 +129,9 @@ func TestFindSetMatches(t *testing.T) { // triple concat with multiple alternates {"(api|rpc)_(v1|prom)_push", []string{"api_v1_push", "api_prom_push", "rpc_v1_push", "rpc_prom_push"}}, {"(api|rpc)_(v1|prom)_(push|query)", []string{"api_v1_push", "api_v1_query", "api_prom_push", "api_prom_query", "rpc_v1_push", "rpc_v1_query", "rpc_prom_push", "rpc_prom_query"}}, + // class starting with "-" + {"[-1-2][a-c]", []string{"-a", "-b", "-c", "1a", "1b", "1c", "2a", "2b", "2c"}}, + {"[1^3]", []string{"1", "3", "^"}}, // OpPlus with concat {"(.+)/(foo|bar)", nil}, // Simple sets containing special characters without escaping.