github.com/grafana/pyroscope@v1.18.0/pkg/block/metadata/metadata_labels_test.go (about) 1 package metadata 2 3 import ( 4 "slices" 5 "testing" 6 7 "github.com/prometheus/prometheus/model/labels" 8 "github.com/stretchr/testify/assert" 9 10 metastorev1 "github.com/grafana/pyroscope/api/gen/proto/go/metastore/v1" 11 typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1" 12 "github.com/grafana/pyroscope/pkg/model" 13 ) 14 15 func TestLabelBuilder_Put(t *testing.T) { 16 strings := NewStringTable() 17 b := NewLabelBuilder(strings) 18 19 // a=b, a=b; a=b, a=b; 20 b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "a", "b"}) 21 b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "a", "b"}) 22 23 // c=d, c=d; c=d, c=d; 24 b.Put([]int32{2, 1, 2, 1, 2, 2, 1, 2, 1, 2}, []string{"", "c", "d"}) 25 b.Put([]int32{2, 1, 2, 1, 2}, []string{"", "c", "d"}) 26 27 assert.Equal(t, []int32{ 28 2, 1, 2, 1, 2, 29 2, 3, 4, 3, 4, 30 }, b.Build()) 31 } 32 33 func labelStrings(v []int32, s *StringTable) []string { 34 var ls []string 35 pairs := LabelPairs(v) 36 for pairs.Next() { 37 p := pairs.At() 38 var l string 39 for len(p) > 0 { 40 l += s.Lookup(p[0]) + "=" + s.Lookup(p[1]) + ";" 41 p = p[2:] 42 } 43 ls = append(ls, l) 44 } 45 return ls 46 } 47 48 func TestLabelMatcher_Matches(t *testing.T) { 49 strings := NewStringTable() 50 setA := NewLabelBuilder(strings). 51 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). 52 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). 53 WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). 54 Build() 55 assert.Equal(t, []string{ 56 "service_name=service_a;__profile_type__=cpu:a;", 57 "service_name=service_a;__profile_type__=cpu:b;", 58 "service_name=service_a;__profile_type__=memory;", 59 }, labelStrings(setA, strings)) 60 61 setB := NewLabelBuilder(strings). 62 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). 63 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). 64 Build() 65 assert.Equal(t, []string{ 66 "service_name=service_b;__profile_type__=cpu:a;", 67 "service_name=service_b;__profile_type__=cpu:b;", 68 }, labelStrings(setB, strings)) 69 70 keepLabels := []string{"service_name", "__profile_type__", "none"} 71 m := NewLabelMatcher(strings.Strings, []*labels.Matcher{ 72 labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "cpu:a")}, 73 keepLabels...) 74 assert.True(t, m.IsValid()) 75 76 expected := []bool{true, false, false, true, false} 77 matches := make([]bool, 0, len(expected)) 78 79 pairs := LabelPairs(setA) 80 for pairs.Next() { 81 matches = append(matches, m.MatchesPairs(pairs.At())) 82 } 83 84 pairs = LabelPairs(setB) 85 for pairs.Next() { 86 matches = append(matches, m.MatchesPairs(pairs.At())) 87 } 88 assert.Equal(t, expected, matches) 89 90 t.Run("LabelCollector", func(t *testing.T) { 91 c := NewLabelsCollector(keepLabels...) 92 c.CollectMatches(m) 93 94 collected := slices.Collect(c.Unique()) 95 slices.SortFunc(collected, model.CompareLabels) 96 97 // The label order matches the input. 98 assert.Equal(t, []*typesv1.Labels{ 99 { 100 Labels: []*typesv1.LabelPair{ 101 {Name: "service_name", Value: "service_a"}, 102 {Name: "__profile_type__", Value: "cpu:a"}, 103 {Name: "none", Value: ""}, 104 }, 105 }, 106 { 107 Labels: []*typesv1.LabelPair{ 108 {Name: "service_name", Value: "service_b"}, 109 {Name: "__profile_type__", Value: "cpu:a"}, 110 {Name: "none", Value: ""}, 111 }, 112 }, 113 }, collected) 114 }) 115 } 116 117 func TestLabelMatcher_Collect(t *testing.T) { 118 strings := NewStringTable() 119 setA := NewLabelBuilder(strings). 120 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). 121 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). 122 WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). 123 Build() 124 125 setB := NewLabelBuilder(strings). 126 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). 127 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). 128 Build() 129 130 m := NewLabelMatcher(strings.Strings, []*labels.Matcher{ 131 labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a"), 132 labels.MustNewMatcher(labels.MatchRegexp, "__profile_type__", "cpu.*")}, 133 "service_name", 134 "none") 135 assert.True(t, m.IsValid()) 136 137 matches, ok := m.CollectMatches(nil, setA) 138 assert.True(t, ok) 139 assert.Equal(t, []string{ 140 "service_name=service_a;", 141 "service_name=service_a;", 142 }, labelStrings(matches, strings)) 143 144 matches = matches[:0] 145 matches, ok = m.CollectMatches(matches, setB) 146 assert.False(t, ok) 147 assert.Len(t, matches, 0) 148 } 149 150 func Benchmark_LabelMatcher_Matches(b *testing.B) { 151 strings := NewStringTable() 152 153 ls := NewLabelBuilder(strings). 154 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu"). 155 Build() 156 157 m := NewLabelMatcher(strings.Strings, 158 []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a")}, 159 "service_name", "__profile_type__") 160 161 assert.True(b, m.IsValid()) 162 b.ReportAllocs() 163 164 for i := 0; i < b.N; i++ { 165 pairs := LabelPairs(ls) 166 for pairs.Next() { 167 m.MatchesPairs(pairs.At()) 168 } 169 } 170 } 171 172 func TestFindDatasets(t *testing.T) { 173 strings := NewStringTable() 174 setA := NewLabelBuilder(strings). 175 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:a"). 176 WithLabelSet("service_name", "service_a", "__profile_type__", "cpu:b"). 177 WithLabelSet("service_name", "service_a", "__profile_type__", "memory"). 178 Build() 179 180 setB := NewLabelBuilder(strings). 181 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:a"). 182 WithLabelSet("service_name", "service_b", "__profile_type__", "cpu:b"). 183 Build() 184 185 md := &metastorev1.BlockMeta{ 186 Datasets: []*metastorev1.Dataset{ 187 {Name: 3, Labels: setA}, 188 {Name: 4, Labels: setB}, 189 }, 190 StringTable: strings.Strings, 191 } 192 193 for _, test := range []struct { 194 matchers []*labels.Matcher 195 expected []int32 196 }{ 197 { 198 expected: []int32{3, 4}, 199 }, 200 { 201 matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "foo", "bar")}, 202 }, 203 { 204 matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_b")}, 205 expected: []int32{4}, 206 }, 207 { 208 matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchNotEqual, "service_name", "service_b")}, 209 expected: []int32{3}, 210 }, 211 { 212 matchers: []*labels.Matcher{labels.MustNewMatcher(labels.MatchRegexp, "service_name", ".*")}, 213 expected: []int32{3, 4}, 214 }, 215 { 216 matchers: []*labels.Matcher{ 217 labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), 218 }, 219 expected: []int32{3}, 220 }, 221 { 222 matchers: []*labels.Matcher{ 223 labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), 224 labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_a"), 225 }, 226 expected: []int32{3}, 227 }, 228 { 229 matchers: []*labels.Matcher{ 230 labels.MustNewMatcher(labels.MatchEqual, "__profile_type__", "memory"), 231 labels.MustNewMatcher(labels.MatchEqual, "service_name", "service_b"), 232 }, 233 }, 234 } { 235 var actual []int32 236 FindDatasets(md, test.matchers...)(func(v *metastorev1.Dataset) bool { 237 actual = append(actual, v.Name) 238 return true 239 }) 240 assert.Equal(t, test.expected, actual) 241 } 242 } 243 244 func Test_LabelMatcher_Skip(t *testing.T) { 245 strings := []string{"", "foo", "bar", "baz", "qux"} 246 247 type testCase struct { 248 valid bool 249 matches []*labels.Matcher 250 } 251 252 for _, test := range []testCase{ 253 {true, []*labels.Matcher{}}, 254 {true, []*labels.Matcher{ 255 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 256 }}, 257 {true, []*labels.Matcher{ 258 labels.MustNewMatcher(labels.MatchRegexp, "foo", "b.*"), 259 }}, 260 {true, []*labels.Matcher{ 261 labels.MustNewMatcher(labels.MatchRegexp, "fee", ""), 262 }}, 263 {true, []*labels.Matcher{ 264 labels.MustNewMatcher(labels.MatchNotEqual, "foo", ""), 265 }}, 266 {true, []*labels.Matcher{ 267 labels.MustNewMatcher(labels.MatchNotRegexp, "far", ""), 268 }}, 269 {false, []*labels.Matcher{ 270 labels.MustNewMatcher(labels.MatchEqual, "foo", "bar"), 271 labels.MustNewMatcher(labels.MatchEqual, "har", "bor"), 272 }}, 273 } { 274 assert.Equal(t, test.valid, NewLabelMatcher(strings, test.matches).IsValid()) 275 } 276 }