github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/ingester/index/index_test.go (about) 1 package index 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 "testing" 8 9 "github.com/prometheus/common/model" 10 "github.com/prometheus/prometheus/pkg/labels" 11 "github.com/prometheus/prometheus/promql/parser" 12 "github.com/stretchr/testify/assert" 13 14 "github.com/cortexproject/cortex/pkg/cortexpb" 15 ) 16 17 func TestIndex(t *testing.T) { 18 index := New() 19 20 for _, entry := range []struct { 21 m model.Metric 22 fp model.Fingerprint 23 }{ 24 {model.Metric{"foo": "bar", "flip": "flop"}, 3}, 25 {model.Metric{"foo": "bar", "flip": "flap"}, 2}, 26 {model.Metric{"foo": "baz", "flip": "flop"}, 1}, 27 {model.Metric{"foo": "baz", "flip": "flap"}, 0}, 28 } { 29 index.Add(cortexpb.FromMetricsToLabelAdapters(entry.m), entry.fp) 30 } 31 32 for _, tc := range []struct { 33 matchers []*labels.Matcher 34 fps []model.Fingerprint 35 }{ 36 {nil, nil}, 37 {mustParseMatcher(`{fizz="buzz"}`), []model.Fingerprint{}}, 38 39 {mustParseMatcher(`{foo="bar"}`), []model.Fingerprint{2, 3}}, 40 {mustParseMatcher(`{foo="baz"}`), []model.Fingerprint{0, 1}}, 41 {mustParseMatcher(`{flip="flop"}`), []model.Fingerprint{1, 3}}, 42 {mustParseMatcher(`{flip="flap"}`), []model.Fingerprint{0, 2}}, 43 44 {mustParseMatcher(`{foo="bar", flip="flop"}`), []model.Fingerprint{3}}, 45 {mustParseMatcher(`{foo="bar", flip="flap"}`), []model.Fingerprint{2}}, 46 {mustParseMatcher(`{foo="baz", flip="flop"}`), []model.Fingerprint{1}}, 47 {mustParseMatcher(`{foo="baz", flip="flap"}`), []model.Fingerprint{0}}, 48 49 {mustParseMatcher(`{fizz=~"b.*"}`), []model.Fingerprint{}}, 50 51 {mustParseMatcher(`{foo=~"bar.*"}`), []model.Fingerprint{2, 3}}, 52 {mustParseMatcher(`{foo=~"ba.*"}`), []model.Fingerprint{0, 1, 2, 3}}, 53 {mustParseMatcher(`{flip=~"flop|flap"}`), []model.Fingerprint{0, 1, 2, 3}}, 54 {mustParseMatcher(`{flip=~"flaps"}`), []model.Fingerprint{}}, 55 56 {mustParseMatcher(`{foo=~"bar|bax", flip="flop"}`), []model.Fingerprint{3}}, 57 {mustParseMatcher(`{foo=~"bar|baz", flip="flap"}`), []model.Fingerprint{0, 2}}, 58 {mustParseMatcher(`{foo=~"baz.+", flip="flop"}`), []model.Fingerprint{}}, 59 {mustParseMatcher(`{foo=~"baz", flip="flap"}`), []model.Fingerprint{0}}, 60 } { 61 assert.Equal(t, tc.fps, index.Lookup(tc.matchers)) 62 } 63 64 assert.Equal(t, []string{"flip", "foo"}, index.LabelNames()) 65 assert.Equal(t, []string{"bar", "baz"}, index.LabelValues("foo")) 66 assert.Equal(t, []string{"flap", "flop"}, index.LabelValues("flip")) 67 } 68 69 func BenchmarkSetRegexLookup(b *testing.B) { 70 // Prepare the benchmark. 71 seriesLabels := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"} 72 seriesPerLabel := 100000 73 74 idx := New() 75 for _, l := range seriesLabels { 76 for i := 0; i < seriesPerLabel; i++ { 77 lbls := labels.FromStrings("foo", l, "bar", strconv.Itoa(i)) 78 idx.Add(cortexpb.FromLabelsToLabelAdapters(lbls), model.Fingerprint(lbls.Hash())) 79 } 80 } 81 82 selectionLabels := []string{} 83 for i := 0; i < 100; i++ { 84 selectionLabels = append(selectionLabels, strconv.Itoa(i)) 85 } 86 87 tests := []struct { 88 name string 89 matcher string 90 }{ 91 { 92 name: "select all", 93 matcher: fmt.Sprintf(`{bar=~"%s"}`, strings.Join(selectionLabels, "|")), 94 }, 95 { 96 name: "select two", 97 matcher: fmt.Sprintf(`{bar=~"%s"}`, strings.Join(selectionLabels[:2], "|")), 98 }, 99 { 100 name: "select half", 101 matcher: fmt.Sprintf(`{bar=~"%s"}`, strings.Join(selectionLabels[:len(selectionLabels)/2], "|")), 102 }, 103 { 104 name: "select none", 105 matcher: `{bar=~"bleep|bloop"}`, 106 }, 107 { 108 name: "equality matcher", 109 matcher: `{bar="1"}`, 110 }, 111 { 112 name: "regex (non-set) matcher", 113 matcher: `{bar=~"1.*"}`, 114 }, 115 } 116 117 b.ResetTimer() 118 119 for _, tc := range tests { 120 b.Run(fmt.Sprintf("%s:%s", tc.name, tc.matcher), func(b *testing.B) { 121 matcher := mustParseMatcher(tc.matcher) 122 for n := 0; n < b.N; n++ { 123 idx.Lookup(matcher) 124 } 125 }) 126 } 127 128 } 129 130 func mustParseMatcher(s string) []*labels.Matcher { 131 ms, err := parser.ParseMetricSelector(s) 132 if err != nil { 133 panic(err) 134 } 135 return ms 136 } 137 138 func TestIndex_Delete(t *testing.T) { 139 index := New() 140 141 testData := []struct { 142 m model.Metric 143 fp model.Fingerprint 144 }{ 145 {model.Metric{"common": "label", "foo": "bar", "flip": "flop"}, 0}, 146 {model.Metric{"common": "label", "foo": "bar", "flip": "flap"}, 1}, 147 {model.Metric{"common": "label", "foo": "baz", "flip": "flop"}, 2}, 148 {model.Metric{"common": "label", "foo": "baz", "flip": "flap"}, 3}, 149 } 150 for _, entry := range testData { 151 index.Add(cortexpb.FromMetricsToLabelAdapters(entry.m), entry.fp) 152 } 153 154 for _, tc := range []struct { 155 name string 156 labelsToDelete labels.Labels 157 fpToDelete model.Fingerprint 158 expectedFPs []model.Fingerprint 159 }{ 160 { 161 name: "existing labels and fp", 162 labelsToDelete: metricToLabels(testData[0].m), 163 fpToDelete: testData[0].fp, 164 expectedFPs: []model.Fingerprint{1, 2, 3}, 165 }, 166 { 167 name: "non-existing labels", 168 labelsToDelete: metricToLabels(model.Metric{"app": "fizz"}), 169 fpToDelete: testData[1].fp, 170 expectedFPs: []model.Fingerprint{1, 2, 3}, 171 }, 172 { 173 name: "non-existing fp", 174 labelsToDelete: metricToLabels(testData[1].m), 175 fpToDelete: 99, 176 expectedFPs: []model.Fingerprint{1, 2, 3}, 177 }, 178 } { 179 t.Run(tc.name, func(t *testing.T) { 180 index.Delete(tc.labelsToDelete, tc.fpToDelete) 181 assert.Equal(t, tc.expectedFPs, index.Lookup(mustParseMatcher(`{common="label"}`))) 182 }) 183 } 184 185 assert.Equal(t, []string{"common", "flip", "foo"}, index.LabelNames()) 186 assert.Equal(t, []string{"label"}, index.LabelValues("common")) 187 assert.Equal(t, []string{"bar", "baz"}, index.LabelValues("foo")) 188 assert.Equal(t, []string{"flap", "flop"}, index.LabelValues("flip")) 189 } 190 191 func metricToLabels(m model.Metric) labels.Labels { 192 ls := make(labels.Labels, 0, len(m)) 193 for k, v := range m { 194 ls = append(ls, labels.Label{ 195 Name: string(k), 196 Value: string(v), 197 }) 198 } 199 200 return ls 201 }