github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/ingester/client/compat_test.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "strconv" 8 "testing" 9 10 "github.com/prometheus/common/model" 11 "github.com/prometheus/prometheus/pkg/labels" 12 ) 13 14 func TestQueryRequest(t *testing.T) { 15 from, to := model.Time(int64(0)), model.Time(int64(10)) 16 matchers := []*labels.Matcher{} 17 matcher1, err := labels.NewMatcher(labels.MatchEqual, "foo", "1") 18 if err != nil { 19 t.Fatal(err) 20 } 21 matchers = append(matchers, matcher1) 22 23 matcher2, err := labels.NewMatcher(labels.MatchNotEqual, "bar", "2") 24 if err != nil { 25 t.Fatal(err) 26 } 27 matchers = append(matchers, matcher2) 28 29 matcher3, err := labels.NewMatcher(labels.MatchRegexp, "baz", "3") 30 if err != nil { 31 t.Fatal(err) 32 } 33 matchers = append(matchers, matcher3) 34 35 matcher4, err := labels.NewMatcher(labels.MatchNotRegexp, "bop", "4") 36 if err != nil { 37 t.Fatal(err) 38 } 39 matchers = append(matchers, matcher4) 40 41 req, err := ToQueryRequest(from, to, matchers) 42 if err != nil { 43 t.Fatal(err) 44 } 45 46 haveFrom, haveTo, haveMatchers, err := FromQueryRequest(req) 47 if err != nil { 48 t.Fatal(err) 49 } 50 51 if !reflect.DeepEqual(haveFrom, from) { 52 t.Fatalf("Bad from FromQueryRequest(ToQueryRequest) round trip") 53 } 54 if !reflect.DeepEqual(haveTo, to) { 55 t.Fatalf("Bad to FromQueryRequest(ToQueryRequest) round trip") 56 } 57 if !reflect.DeepEqual(haveMatchers, matchers) { 58 t.Fatalf("Bad have FromQueryRequest(ToQueryRequest) round trip - %v != %v", haveMatchers, matchers) 59 } 60 } 61 62 func buildTestMatrix(numSeries int, samplesPerSeries int, offset int) model.Matrix { 63 m := make(model.Matrix, 0, numSeries) 64 for i := 0; i < numSeries; i++ { 65 ss := model.SampleStream{ 66 Metric: model.Metric{ 67 model.MetricNameLabel: model.LabelValue(fmt.Sprintf("testmetric_%d", i)), 68 model.JobLabel: "testjob", 69 }, 70 Values: make([]model.SamplePair, 0, samplesPerSeries), 71 } 72 for j := 0; j < samplesPerSeries; j++ { 73 ss.Values = append(ss.Values, model.SamplePair{ 74 Timestamp: model.Time(i + j + offset), 75 Value: model.SampleValue(i + j + offset), 76 }) 77 } 78 m = append(m, &ss) 79 } 80 sort.Sort(m) 81 return m 82 } 83 84 func TestQueryResponse(t *testing.T) { 85 want := buildTestMatrix(10, 10, 10) 86 have := FromQueryResponse(ToQueryResponse(want)) 87 if !reflect.DeepEqual(have, want) { 88 t.Fatalf("Bad FromQueryResponse(ToQueryResponse) round trip") 89 } 90 } 91 92 // This test shows label sets with same fingerprints, and also shows how to easily create new collisions 93 // (by adding "_" or "A" label with specific values, see below). 94 func TestFingerprintCollisions(t *testing.T) { 95 // "8yn0iYCKYHlIj4-BwPqk" and "GReLUrM4wMqfg9yzV3KQ" have same FNV-1a hash. 96 // If we use it as a single label name (for labels that have same value), we get colliding labels. 97 c1 := labels.FromStrings("8yn0iYCKYHlIj4-BwPqk", "hello") 98 c2 := labels.FromStrings("GReLUrM4wMqfg9yzV3KQ", "hello") 99 verifyCollision(t, true, c1, c2) 100 101 // Adding _="ypfajYg2lsv" or _="KiqbryhzUpn" respectively to most metrics will produce collision. 102 // It's because "_\xffypfajYg2lsv" and "_\xffKiqbryhzUpn" have same FNV-1a hash, and "_" label is sorted before 103 // most other labels (except labels starting with upper-case letter) 104 105 const _label1 = "ypfajYg2lsv" 106 const _label2 = "KiqbryhzUpn" 107 108 metric := labels.NewBuilder(labels.FromStrings("__name__", "logs")) 109 c1 = metric.Set("_", _label1).Labels() 110 c2 = metric.Set("_", _label2).Labels() 111 verifyCollision(t, true, c1, c2) 112 113 metric = labels.NewBuilder(labels.FromStrings("__name__", "up", "instance", "hello")) 114 c1 = metric.Set("_", _label1).Labels() 115 c2 = metric.Set("_", _label2).Labels() 116 verifyCollision(t, true, c1, c2) 117 118 // here it breaks, because "Z" label is sorted before "_" label. 119 metric = labels.NewBuilder(labels.FromStrings("__name__", "up", "Z", "hello")) 120 c1 = metric.Set("_", _label1).Labels() 121 c2 = metric.Set("_", _label2).Labels() 122 verifyCollision(t, false, c1, c2) 123 124 // A="K6sjsNNczPl" and A="cswpLMIZpwt" label has similar property. 125 // (Again, because "A\xffK6sjsNNczPl" and "A\xffcswpLMIZpwt" have same FNV-1a hash) 126 // This time, "A" is the smallest possible label name, and is always sorted first. 127 128 const Alabel1 = "K6sjsNNczPl" 129 const Alabel2 = "cswpLMIZpwt" 130 131 metric = labels.NewBuilder(labels.FromStrings("__name__", "up", "Z", "hello")) 132 c1 = metric.Set("A", Alabel1).Labels() 133 c2 = metric.Set("A", Alabel2).Labels() 134 verifyCollision(t, true, c1, c2) 135 136 // Adding the same suffix to the "A" label also works. 137 metric = labels.NewBuilder(labels.FromStrings("__name__", "up", "Z", "hello")) 138 c1 = metric.Set("A", Alabel1+"suffix").Labels() 139 c2 = metric.Set("A", Alabel2+"suffix").Labels() 140 verifyCollision(t, true, c1, c2) 141 } 142 143 func verifyCollision(t *testing.T, collision bool, ls1 labels.Labels, ls2 labels.Labels) { 144 if collision && Fingerprint(ls1) != Fingerprint(ls2) { 145 t.Errorf("expected same fingerprints for %v (%016x) and %v (%016x)", ls1.String(), Fingerprint(ls1), ls2.String(), Fingerprint(ls2)) 146 } else if !collision && Fingerprint(ls1) == Fingerprint(ls2) { 147 t.Errorf("expected different fingerprints for %v (%016x) and %v (%016x)", ls1.String(), Fingerprint(ls1), ls2.String(), Fingerprint(ls2)) 148 } 149 } 150 151 // The main usecase for `LabelsToKeyString` is to generate hashKeys 152 // for maps. We are benchmarking that here. 153 func BenchmarkSeriesMap(b *testing.B) { 154 benchmarkSeriesMap(100000, b) 155 } 156 157 func benchmarkSeriesMap(numSeries int, b *testing.B) { 158 series := makeSeries(numSeries) 159 sm := make(map[string]int, numSeries) 160 161 b.ReportAllocs() 162 b.ResetTimer() 163 for n := 0; n < b.N; n++ { 164 for i, s := range series { 165 sm[LabelsToKeyString(s)] = i 166 } 167 168 for _, s := range series { 169 _, ok := sm[LabelsToKeyString(s)] 170 if !ok { 171 b.Fatal("element missing") 172 } 173 } 174 175 if len(sm) != numSeries { 176 b.Fatal("the number of series expected:", numSeries, "got:", len(sm)) 177 } 178 } 179 } 180 181 func makeSeries(n int) []labels.Labels { 182 series := make([]labels.Labels, 0, n) 183 for i := 0; i < n; i++ { 184 series = append(series, labels.FromMap(map[string]string{ 185 "label0": "value0", 186 "label1": "value1", 187 "label2": "value2", 188 "label3": "value3", 189 "label4": "value4", 190 "label5": "value5", 191 "label6": "value6", 192 "label7": "value7", 193 "label8": "value8", 194 "label9": strconv.Itoa(i), 195 })) 196 } 197 198 return series 199 }