github.com/grafana/pyroscope@v1.18.0/pkg/frontend/readpath/queryfrontend/compat_test.go (about) 1 package queryfrontend 2 3 import ( 4 "testing" 5 6 "github.com/prometheus/prometheus/model/labels" 7 "github.com/stretchr/testify/require" 8 ) 9 10 func Test_matchersToLabelSelector(t *testing.T) { 11 tests := []struct { 12 name string 13 matchers []*labels.Matcher 14 expected string 15 }{ 16 { 17 name: "empty matchers", 18 matchers: []*labels.Matcher{}, 19 expected: "{}", 20 }, 21 { 22 name: "single standard label name with equals", 23 matchers: []*labels.Matcher{ 24 labels.MustNewMatcher(labels.MatchEqual, "service_name", "my-service"), 25 }, 26 expected: `{service_name="my-service"}`, 27 }, 28 { 29 name: "label name with dots", 30 matchers: []*labels.Matcher{ 31 labels.MustNewMatcher(labels.MatchEqual, "service.name", "test"), 32 }, 33 expected: `{"service.name"="test"}`, 34 }, 35 { 36 name: "label name with hyphen", 37 matchers: []*labels.Matcher{ 38 labels.MustNewMatcher(labels.MatchEqual, "service-name", "value"), 39 }, 40 expected: `{"service-name"="value"}`, 41 }, 42 { 43 name: "label name with special character (√)", 44 matchers: []*labels.Matcher{ 45 labels.MustNewMatcher(labels.MatchEqual, "my√label", "value"), 46 }, 47 expected: `{"my√label"="value"}`, 48 }, 49 { 50 name: "label name with unicode (世界)", 51 matchers: []*labels.Matcher{ 52 labels.MustNewMatcher(labels.MatchEqual, "世界", "value"), 53 }, 54 expected: `{"世界"="value"}`, 55 }, 56 { 57 name: "label name starting with number", 58 matchers: []*labels.Matcher{ 59 labels.MustNewMatcher(labels.MatchEqual, "123label", "value"), 60 }, 61 expected: `{"123label"="value"}`, 62 }, 63 { 64 name: "not equal matcher", 65 matchers: []*labels.Matcher{ 66 labels.MustNewMatcher(labels.MatchNotEqual, "service_name", "test"), 67 }, 68 expected: `{service_name!="test"}`, 69 }, 70 { 71 name: "regex match matcher", 72 matchers: []*labels.Matcher{ 73 labels.MustNewMatcher(labels.MatchRegexp, "service_name", ".*test.*"), 74 }, 75 expected: `{service_name=~".*test.*"}`, 76 }, 77 { 78 name: "regex not match matcher", 79 matchers: []*labels.Matcher{ 80 labels.MustNewMatcher(labels.MatchNotRegexp, "service_name", "test.*"), 81 }, 82 expected: `{service_name!~"test.*"}`, 83 }, 84 { 85 name: "multiple standard matchers", 86 matchers: []*labels.Matcher{ 87 labels.MustNewMatcher(labels.MatchEqual, "service_name", "my-service"), 88 labels.MustNewMatcher(labels.MatchEqual, "environment", "production"), 89 labels.MustNewMatcher(labels.MatchEqual, "region", "us-west-2"), 90 }, 91 expected: `{service_name="my-service",environment="production",region="us-west-2"}`, 92 }, 93 { 94 name: "multiple matchers with special characters", 95 matchers: []*labels.Matcher{ 96 labels.MustNewMatcher(labels.MatchEqual, "service.name", "my-service"), 97 labels.MustNewMatcher(labels.MatchEqual, "app-version", "v1.0"), 98 labels.MustNewMatcher(labels.MatchEqual, "my√label", "value"), 99 }, 100 expected: `{"service.name"="my-service","app-version"="v1.0","my√label"="value"}`, 101 }, 102 { 103 name: "mixed matcher types", 104 matchers: []*labels.Matcher{ 105 labels.MustNewMatcher(labels.MatchEqual, "service_name", "test"), 106 labels.MustNewMatcher(labels.MatchNotEqual, "environment", "dev"), 107 labels.MustNewMatcher(labels.MatchRegexp, "region", "us-.*"), 108 }, 109 expected: `{service_name="test",environment!="dev",region=~"us-.*"}`, 110 }, 111 { 112 name: "value with quotes needs escaping", 113 matchers: []*labels.Matcher{ 114 labels.MustNewMatcher(labels.MatchEqual, "label", `value"with"quotes`), 115 }, 116 expected: `{label="value\"with\"quotes"}`, 117 }, 118 { 119 name: "label name and value with special characters", 120 matchers: []*labels.Matcher{ 121 labels.MustNewMatcher(labels.MatchEqual, "label-name.special", "value/with\\special"), 122 }, 123 expected: `{"label-name.special"="value/with\\special"}`, 124 }, 125 { 126 name: "standard alphanumeric labels don't get quoted", 127 matchers: []*labels.Matcher{ 128 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 129 labels.MustNewMatcher(labels.MatchEqual, "foo123", "bar456"), 130 labels.MustNewMatcher(labels.MatchEqual, "__internal__", "value"), 131 }, 132 expected: `{foo="bar",foo123="bar456",__internal__="value"}`, 133 }, 134 } 135 136 for _, tt := range tests { 137 t.Run(tt.name, func(t *testing.T) { 138 result := matchersToLabelSelector(tt.matchers) 139 require.Equal(t, tt.expected, result, "matchersToLabelSelector output mismatch") 140 }) 141 } 142 } 143 144 func Test_buildLabelSelectorFromMatchers(t *testing.T) { 145 tests := []struct { 146 name string 147 matchers []string 148 expected string 149 wantErr bool 150 }{ 151 { 152 name: "single matcher", 153 matchers: []string{`{service_name="test"}`}, 154 expected: `{service_name="test"}`, 155 wantErr: false, 156 }, 157 { 158 name: "matcher with special characters in label name", 159 matchers: []string{`{"service.name"="test"}`}, 160 expected: `{"service.name"="test"}`, 161 wantErr: false, 162 }, 163 { 164 name: "multiple matchers", 165 matchers: []string{`{service_name="test"}`, `{environment="prod"}`}, 166 expected: `{service_name="test",environment="prod"}`, 167 wantErr: false, 168 }, 169 { 170 name: "invalid matcher syntax", 171 matchers: []string{`{unclosed`}, 172 expected: "", 173 wantErr: true, 174 }, 175 { 176 name: "empty matchers", 177 matchers: []string{}, 178 expected: `{}`, 179 wantErr: false, 180 }, 181 } 182 183 for _, tt := range tests { 184 t.Run(tt.name, func(t *testing.T) { 185 result, err := buildLabelSelectorFromMatchers(tt.matchers) 186 if tt.wantErr { 187 require.Error(t, err) 188 } else { 189 require.NoError(t, err) 190 require.Equal(t, tt.expected, result) 191 } 192 }) 193 } 194 }