github.com/thanos-io/thanos@v0.32.5/pkg/store/prometheus_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package store 5 6 import ( 7 "context" 8 "fmt" 9 "math" 10 "net/url" 11 "testing" 12 "time" 13 14 "github.com/cespare/xxhash" 15 16 "github.com/pkg/errors" 17 "github.com/prometheus/prometheus/model/labels" 18 "github.com/prometheus/prometheus/model/timestamp" 19 "github.com/prometheus/prometheus/storage" 20 "github.com/prometheus/prometheus/tsdb/chunkenc" 21 22 "github.com/efficientgo/core/testutil" 23 24 "github.com/thanos-io/thanos/pkg/component" 25 "github.com/thanos-io/thanos/pkg/promclient" 26 "github.com/thanos-io/thanos/pkg/store/labelpb" 27 "github.com/thanos-io/thanos/pkg/store/storepb" 28 "github.com/thanos-io/thanos/pkg/store/storepb/prompb" 29 "github.com/thanos-io/thanos/pkg/testutil/custom" 30 "github.com/thanos-io/thanos/pkg/testutil/e2eutil" 31 ) 32 33 func TestPrometheusStore_Series_e2e(t *testing.T) { 34 testPrometheusStoreSeriesE2e(t, "") 35 } 36 37 // Regression test for https://github.com/thanos-io/thanos/issues/478. 38 func TestPrometheusStore_Series_promOnPath_e2e(t *testing.T) { 39 testPrometheusStoreSeriesE2e(t, "/prometheus/sub/path") 40 } 41 42 func testPrometheusStoreSeriesE2e(t *testing.T, prefix string) { 43 defer custom.TolerantVerifyLeak(t) 44 45 p, err := e2eutil.NewPrometheusOnPath(prefix) 46 testutil.Ok(t, err) 47 defer func() { testutil.Ok(t, p.Stop()) }() 48 49 baseT := timestamp.FromTime(time.Now()) / 1000 * 1000 50 51 // region is an external label; by adding it as an internal label too we also trigger 52 // the resorting code paths 53 a := p.Appender() 54 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "local"), baseT+100, 1) 55 testutil.Ok(t, err) 56 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "local"), baseT+200, 2) 57 testutil.Ok(t, err) 58 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "local"), baseT+300, 3) 59 testutil.Ok(t, err) 60 testutil.Ok(t, a.Commit()) 61 62 ctx, cancel := context.WithCancel(context.Background()) 63 defer cancel() 64 65 testutil.Ok(t, p.Start()) 66 67 u, err := url.Parse(fmt.Sprintf("http://%s", p.Addr())) 68 testutil.Ok(t, err) 69 70 limitMinT := int64(0) 71 proxy, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), u, component.Sidecar, 72 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 73 func() (int64, int64) { return limitMinT, -1 }, 74 nil, 75 ) // MaxTime does not matter. 76 testutil.Ok(t, err) 77 78 // Query all three samples except for the first one. Since we round up queried data 79 // to seconds, we can test whether the extra sample gets stripped properly. 80 { 81 srv := newStoreSeriesServer(ctx) 82 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 83 MinTime: baseT + 101, 84 MaxTime: baseT + 300, 85 Matchers: []storepb.LabelMatcher{ 86 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 87 }, 88 }, srv)) 89 90 testutil.Equals(t, 1, len(srv.SeriesSet)) 91 92 testutil.Equals(t, []labelpb.ZLabel{ 93 {Name: "a", Value: "b"}, 94 {Name: "region", Value: "eu-west"}, 95 }, srv.SeriesSet[0].Labels) 96 testutil.Equals(t, []string(nil), srv.Warnings) 97 testutil.Equals(t, 1, len(srv.SeriesSet[0].Chunks)) 98 99 c := srv.SeriesSet[0].Chunks[0] 100 testutil.Equals(t, storepb.Chunk_XOR, c.Raw.Type) 101 102 chk, err := chunkenc.FromData(chunkenc.EncXOR, c.Raw.Data) 103 testutil.Ok(t, err) 104 105 samples := expandChunk(chk.Iterator(nil)) 106 testutil.Equals(t, []sample{{baseT + 200, 2}, {baseT + 300, 3}}, samples) 107 108 } 109 // Query all samples, but limit mint time to exclude the first one. 110 { 111 limitMinT = baseT + 101 112 srv := newStoreSeriesServer(ctx) 113 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 114 MinTime: 0, 115 MaxTime: baseT + 300, 116 Matchers: []storepb.LabelMatcher{ 117 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 118 }, 119 }, srv)) 120 // Revert for next cases. 121 limitMinT = 0 122 123 testutil.Equals(t, 1, len(srv.SeriesSet)) 124 125 testutil.Equals(t, []labelpb.ZLabel{ 126 {Name: "a", Value: "b"}, 127 {Name: "region", Value: "eu-west"}, 128 }, srv.SeriesSet[0].Labels) 129 130 testutil.Equals(t, 1, len(srv.SeriesSet[0].Chunks)) 131 132 c := srv.SeriesSet[0].Chunks[0] 133 testutil.Equals(t, []string(nil), srv.Warnings) 134 testutil.Equals(t, storepb.Chunk_XOR, c.Raw.Type) 135 136 chk, err := chunkenc.FromData(chunkenc.EncXOR, c.Raw.Data) 137 testutil.Ok(t, err) 138 139 samples := expandChunk(chk.Iterator(nil)) 140 testutil.Equals(t, []sample{{baseT + 200, 2}, {baseT + 300, 3}}, samples) 141 } 142 // Querying by external labels only. 143 { 144 srv := newStoreSeriesServer(ctx) 145 146 err = proxy.Series(&storepb.SeriesRequest{ 147 MinTime: baseT + 101, 148 MaxTime: baseT + 300, 149 Matchers: []storepb.LabelMatcher{ 150 {Type: storepb.LabelMatcher_EQ, Name: "region", Value: "eu-west"}, 151 }, 152 }, srv) 153 testutil.NotOk(t, err) 154 testutil.Equals(t, []string(nil), srv.Warnings) 155 testutil.Equals(t, "rpc error: code = InvalidArgument desc = no matchers specified (excluding external labels)", err.Error()) 156 } 157 // Querying with pushdown. 158 { 159 srv := newStoreSeriesServer(ctx) 160 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 161 MinTime: baseT + 101, 162 MaxTime: baseT + 300, 163 Matchers: []storepb.LabelMatcher{ 164 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 165 }, 166 QueryHints: &storepb.QueryHints{Func: &storepb.Func{Name: "min_over_time"}, Range: &storepb.Range{Millis: 300}}, 167 }, srv)) 168 169 testutil.Equals(t, 1, len(srv.SeriesSet)) 170 171 testutil.Equals(t, []labelpb.ZLabel{ 172 {Name: "a", Value: "b"}, 173 {Name: "region", Value: "eu-west"}, 174 {Name: "__thanos_pushed_down", Value: "true"}, 175 }, srv.SeriesSet[0].Labels) 176 testutil.Equals(t, []string(nil), srv.Warnings) 177 testutil.Equals(t, 1, len(srv.SeriesSet[0].Chunks)) 178 179 c := srv.SeriesSet[0].Chunks[0] 180 testutil.Equals(t, storepb.Chunk_XOR, c.Raw.Type) 181 182 chk, err := chunkenc.FromData(chunkenc.EncXOR, c.Raw.Data) 183 testutil.Ok(t, err) 184 185 samples := expandChunk(chk.Iterator(nil)) 186 testutil.Equals(t, []sample{{baseT + 300, 1}}, samples) 187 188 } 189 } 190 191 type sample struct { 192 t int64 193 v float64 194 } 195 196 func expandChunk(cit chunkenc.Iterator) (res []sample) { 197 for cit.Next() != chunkenc.ValNone { 198 t, v := cit.At() 199 res = append(res, sample{t, v}) 200 } 201 return res 202 } 203 204 func TestPrometheusStore_SeriesLabels_e2e(t *testing.T) { 205 defer custom.TolerantVerifyLeak(t) 206 207 p, err := e2eutil.NewPrometheus() 208 testutil.Ok(t, err) 209 defer func() { testutil.Ok(t, p.Stop()) }() 210 211 baseT := timestamp.FromTime(time.Now()) / 1000 * 1000 212 213 a := p.Appender() 214 _, err = a.Append(0, labels.FromStrings("a", "b", "b", "d"), baseT+100, 1) 215 testutil.Ok(t, err) 216 _, err = a.Append(0, labels.FromStrings("a", "c", "b", "d", "job", "test"), baseT+200, 2) 217 testutil.Ok(t, err) 218 _, err = a.Append(0, labels.FromStrings("a", "d", "b", "d", "job", "test"), baseT+300, 3) 219 testutil.Ok(t, err) 220 _, err = a.Append(0, labels.FromStrings("b", "d", "job", "test"), baseT+400, 4) 221 testutil.Ok(t, err) 222 testutil.Ok(t, a.Commit()) 223 224 ctx, cancel := context.WithCancel(context.Background()) 225 defer cancel() 226 227 testutil.Ok(t, p.Start()) 228 229 u, err := url.Parse(fmt.Sprintf("http://%s", p.Addr())) 230 testutil.Ok(t, err) 231 232 promStore, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), u, component.Sidecar, 233 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 234 func() (int64, int64) { return math.MinInt64/1000 + 62135596801, math.MaxInt64/1000 - 62135596801 }, 235 nil, 236 ) 237 testutil.Ok(t, err) 238 239 for _, tcase := range []struct { 240 req *storepb.SeriesRequest 241 expected []storepb.Series 242 expectedErr error 243 }{ 244 { 245 req: &storepb.SeriesRequest{ 246 SkipChunks: true, 247 Matchers: []storepb.LabelMatcher{}, 248 MinTime: baseT - 10000000000, 249 MaxTime: baseT + 10000000000, 250 }, 251 expectedErr: errors.New("rpc error: code = InvalidArgument desc = no matchers specified (excluding external labels)"), 252 }, 253 { 254 req: &storepb.SeriesRequest{ 255 SkipChunks: true, 256 Matchers: []storepb.LabelMatcher{ 257 {Type: storepb.LabelMatcher_RE, Name: "wrong-chars-in-label-name(hyphen)", Value: "adsf"}, 258 }, 259 MinTime: baseT - 10000000000, 260 MaxTime: baseT + 10000000000, 261 }, 262 expectedErr: errors.New("rpc error: code = InvalidArgument desc = expected 2xx response, got 400. Body: {\"status\":\"error\",\"errorType\":\"bad_data\",\"error\":\"invalid parameter \\\"match[]\\\": 1:7: parse error: unexpected character inside braces: '-'\"}"), 263 }, 264 { 265 req: &storepb.SeriesRequest{ 266 SkipChunks: true, 267 Matchers: []storepb.LabelMatcher{ 268 {Type: storepb.LabelMatcher_EQ, Name: "non_existing", Value: "something"}, 269 }, 270 MinTime: baseT - 10000000000, 271 MaxTime: baseT + 10000000000, 272 }, 273 }, 274 { 275 req: &storepb.SeriesRequest{ 276 SkipChunks: true, 277 Matchers: []storepb.LabelMatcher{ 278 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 279 }, 280 MinTime: baseT, 281 MaxTime: baseT + 300, 282 }, 283 expected: []storepb.Series{ 284 { 285 Labels: []labelpb.ZLabel{{Name: "a", Value: "b"}, {Name: "b", Value: "d"}, {Name: "region", Value: "eu-west"}}, 286 }, 287 }, 288 }, 289 { 290 req: &storepb.SeriesRequest{ 291 SkipChunks: true, 292 Matchers: []storepb.LabelMatcher{ 293 {Type: storepb.LabelMatcher_EQ, Name: "job", Value: "foo"}, 294 }, 295 MinTime: baseT, 296 MaxTime: baseT + 300, 297 }, 298 }, 299 { 300 req: &storepb.SeriesRequest{ 301 SkipChunks: true, 302 Matchers: []storepb.LabelMatcher{ 303 {Type: storepb.LabelMatcher_NEQ, Name: "a", Value: "b"}, 304 {Type: storepb.LabelMatcher_EQ, Name: "job", Value: "test"}, 305 }, 306 MinTime: baseT, 307 MaxTime: baseT + 300, 308 }, 309 expected: []storepb.Series{ 310 { 311 Labels: []labelpb.ZLabel{{Name: "a", Value: "c"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 312 }, 313 { 314 Labels: []labelpb.ZLabel{{Name: "a", Value: "d"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 315 }, 316 }, 317 }, 318 { 319 req: &storepb.SeriesRequest{ 320 SkipChunks: true, 321 Matchers: []storepb.LabelMatcher{ 322 {Type: storepb.LabelMatcher_EQ, Name: "job", Value: "test"}, 323 }, 324 MinTime: baseT, 325 MaxTime: baseT + 300, 326 }, 327 expected: []storepb.Series{ 328 { 329 Labels: []labelpb.ZLabel{{Name: "a", Value: "c"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 330 }, 331 { 332 Labels: []labelpb.ZLabel{{Name: "a", Value: "d"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 333 }, 334 }, 335 }, 336 { 337 req: &storepb.SeriesRequest{ 338 SkipChunks: true, 339 Matchers: []storepb.LabelMatcher{ 340 {Type: storepb.LabelMatcher_EQ, Name: "job", Value: "test"}, 341 }, 342 MinTime: baseT + 400, 343 MaxTime: baseT + 400, 344 }, 345 expected: []storepb.Series{ 346 { 347 Labels: []labelpb.ZLabel{{Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 348 }, 349 }, 350 }, 351 { 352 req: &storepb.SeriesRequest{ 353 SkipChunks: true, 354 Matchers: []storepb.LabelMatcher{ 355 {Type: storepb.LabelMatcher_EQ, Name: "job", Value: "test"}, 356 }, 357 MinTime: func() int64 { minTime, _ := promStore.timestamps(); return minTime }(), 358 MaxTime: func() int64 { _, maxTime := promStore.timestamps(); return maxTime }(), 359 }, 360 expected: []storepb.Series{ 361 { 362 Labels: []labelpb.ZLabel{{Name: "a", Value: "c"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 363 }, 364 { 365 Labels: []labelpb.ZLabel{{Name: "a", Value: "d"}, {Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 366 }, 367 { 368 Labels: []labelpb.ZLabel{{Name: "b", Value: "d"}, {Name: "job", Value: "test"}, {Name: "region", Value: "eu-west"}}, 369 }, 370 }, 371 }, 372 } { 373 t.Run("", func(t *testing.T) { 374 srv := newStoreSeriesServer(ctx) 375 err = promStore.Series(tcase.req, srv) 376 if tcase.expectedErr != nil { 377 testutil.NotOk(t, err) 378 testutil.Equals(t, tcase.expectedErr.Error(), err.Error()) 379 return 380 } 381 testutil.Ok(t, err) 382 testutil.Equals(t, []string(nil), srv.Warnings) 383 testutil.Equals(t, tcase.expected, srv.SeriesSet) 384 }) 385 } 386 } 387 388 func TestPrometheusStore_Series_MatchExternalLabel(t *testing.T) { 389 defer custom.TolerantVerifyLeak(t) 390 391 p, err := e2eutil.NewPrometheus() 392 testutil.Ok(t, err) 393 defer func() { testutil.Ok(t, p.Stop()) }() 394 395 baseT := timestamp.FromTime(time.Now()) / 1000 * 1000 396 397 a := p.Appender() 398 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "eu-west"), baseT+100, 1) 399 testutil.Ok(t, err) 400 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "eu-west"), baseT+200, 2) 401 testutil.Ok(t, err) 402 _, err = a.Append(0, labels.FromStrings("a", "b", "region", "eu-west"), baseT+300, 3) 403 testutil.Ok(t, err) 404 testutil.Ok(t, a.Commit()) 405 406 ctx, cancel := context.WithCancel(context.Background()) 407 defer cancel() 408 409 testutil.Ok(t, p.Start()) 410 411 u, err := url.Parse(fmt.Sprintf("http://%s", p.Addr())) 412 testutil.Ok(t, err) 413 414 proxy, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), u, component.Sidecar, 415 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 416 func() (int64, int64) { return 0, math.MaxInt64 }, 417 nil) 418 testutil.Ok(t, err) 419 srv := newStoreSeriesServer(ctx) 420 421 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 422 MinTime: baseT + 101, 423 MaxTime: baseT + 300, 424 Matchers: []storepb.LabelMatcher{ 425 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 426 {Type: storepb.LabelMatcher_EQ, Name: "region", Value: "eu-west"}, 427 }, 428 }, srv)) 429 testutil.Equals(t, 1, len(srv.SeriesSet)) 430 431 testutil.Equals(t, []labelpb.ZLabel{ 432 {Name: "a", Value: "b"}, 433 {Name: "region", Value: "eu-west"}, 434 }, srv.SeriesSet[0].Labels) 435 436 srv = newStoreSeriesServer(ctx) 437 // However, it should not match wrong external label. 438 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 439 MinTime: baseT + 101, 440 MaxTime: baseT + 300, 441 Matchers: []storepb.LabelMatcher{ 442 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 443 {Type: storepb.LabelMatcher_EQ, Name: "region", Value: "eu-west2"}, // Non existing label value. 444 }, 445 }, srv)) 446 447 // No series. 448 testutil.Equals(t, 0, len(srv.SeriesSet)) 449 } 450 451 func TestPrometheusStore_Series_ChunkHashCalculation_Integration(t *testing.T) { 452 defer custom.TolerantVerifyLeak(t) 453 454 p, err := e2eutil.NewPrometheus() 455 testutil.Ok(t, err) 456 defer func() { testutil.Ok(t, p.Stop()) }() 457 458 baseT := timestamp.FromTime(time.Now()) / 1000 * 1000 459 460 a := p.Appender() 461 _, err = a.Append(0, labels.FromStrings("a", "b"), baseT+100, 1) 462 testutil.Ok(t, err) 463 _, err = a.Append(0, labels.FromStrings("a", "b"), baseT+200, 2) 464 testutil.Ok(t, err) 465 _, err = a.Append(0, labels.FromStrings("a", "b"), baseT+300, 3) 466 testutil.Ok(t, err) 467 testutil.Ok(t, a.Commit()) 468 469 ctx, cancel := context.WithCancel(context.Background()) 470 defer cancel() 471 472 testutil.Ok(t, p.Start()) 473 474 u, err := url.Parse(fmt.Sprintf("http://%s", p.Addr())) 475 testutil.Ok(t, err) 476 477 proxy, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), u, component.Sidecar, 478 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 479 func() (int64, int64) { return 0, math.MaxInt64 }, 480 nil) 481 testutil.Ok(t, err) 482 srv := newStoreSeriesServer(ctx) 483 484 testutil.Ok(t, proxy.Series(&storepb.SeriesRequest{ 485 MinTime: baseT + 101, 486 MaxTime: baseT + 300, 487 Matchers: []storepb.LabelMatcher{ 488 {Name: "a", Value: "b"}, 489 {Type: storepb.LabelMatcher_EQ, Name: "region", Value: "eu-west"}, 490 }, 491 }, srv)) 492 testutil.Equals(t, 1, len(srv.SeriesSet)) 493 494 for _, chunk := range srv.SeriesSet[0].Chunks { 495 got := chunk.Raw.Hash 496 want := xxhash.Sum64(chunk.Raw.Data) 497 testutil.Equals(t, want, got) 498 } 499 } 500 501 func TestPrometheusStore_Info(t *testing.T) { 502 defer custom.TolerantVerifyLeak(t) 503 504 ctx, cancel := context.WithCancel(context.Background()) 505 defer cancel() 506 507 proxy, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), nil, component.Sidecar, 508 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 509 func() (int64, int64) { return 123, 456 }, 510 nil) 511 testutil.Ok(t, err) 512 513 resp, err := proxy.Info(ctx, &storepb.InfoRequest{}) 514 testutil.Ok(t, err) 515 516 testutil.Equals(t, []labelpb.ZLabel{{Name: "region", Value: "eu-west"}}, resp.Labels) 517 testutil.Equals(t, storepb.StoreType_SIDECAR, resp.StoreType) 518 testutil.Equals(t, int64(123), resp.MinTime) 519 testutil.Equals(t, int64(456), resp.MaxTime) 520 } 521 522 func testSeries_SplitSamplesIntoChunksWithMaxSizeOf120(t *testing.T, appender storage.Appender, newStore func() storepb.StoreServer) { 523 baseT := timestamp.FromTime(time.Now().AddDate(0, 0, -2)) / 1000 * 1000 524 525 offset := int64(2*math.MaxUint16 + 5) 526 for i := int64(0); i < offset; i++ { 527 _, err := appender.Append(0, labels.FromStrings("a", "b", "region", "eu-west"), baseT+i, 1) 528 testutil.Ok(t, err) 529 } 530 531 testutil.Ok(t, appender.Commit()) 532 533 ctx, cancel := context.WithCancel(context.Background()) 534 defer cancel() 535 536 client := newStore() 537 srv := newStoreSeriesServer(ctx) 538 539 testutil.Ok(t, client.Series(&storepb.SeriesRequest{ 540 MinTime: baseT, 541 MaxTime: baseT + offset, 542 Matchers: []storepb.LabelMatcher{ 543 {Type: storepb.LabelMatcher_EQ, Name: "a", Value: "b"}, 544 {Type: storepb.LabelMatcher_EQ, Name: "region", Value: "eu-west"}, 545 }, 546 }, srv)) 547 548 testutil.Equals(t, 1, len(srv.SeriesSet)) 549 550 firstSeries := srv.SeriesSet[0] 551 552 testutil.Equals(t, []labelpb.ZLabel{ 553 {Name: "a", Value: "b"}, 554 {Name: "region", Value: "eu-west"}, 555 }, firstSeries.Labels) 556 557 testutil.Equals(t, 1093, len(firstSeries.Chunks)) 558 559 chunk, err := chunkenc.FromData(chunkenc.EncXOR, firstSeries.Chunks[0].Raw.Data) 560 testutil.Ok(t, err) 561 testutil.Equals(t, 120, chunk.NumSamples()) 562 563 chunk, err = chunkenc.FromData(chunkenc.EncXOR, firstSeries.Chunks[1].Raw.Data) 564 testutil.Ok(t, err) 565 testutil.Equals(t, 120, chunk.NumSamples()) 566 567 chunk, err = chunkenc.FromData(chunkenc.EncXOR, firstSeries.Chunks[len(firstSeries.Chunks)-1].Raw.Data) 568 testutil.Ok(t, err) 569 testutil.Equals(t, 35, chunk.NumSamples()) 570 } 571 572 // Regression test for https://github.com/thanos-io/thanos/issues/396. 573 func TestPrometheusStore_Series_SplitSamplesIntoChunksWithMaxSizeOf120(t *testing.T) { 574 defer custom.TolerantVerifyLeak(t) 575 576 p, err := e2eutil.NewPrometheus() 577 testutil.Ok(t, err) 578 defer func() { testutil.Ok(t, p.Stop()) }() 579 580 testSeries_SplitSamplesIntoChunksWithMaxSizeOf120(t, p.Appender(), func() storepb.StoreServer { 581 testutil.Ok(t, p.Start()) 582 583 u, err := url.Parse(fmt.Sprintf("http://%s", p.Addr())) 584 testutil.Ok(t, err) 585 586 proxy, err := NewPrometheusStore(nil, nil, promclient.NewDefaultClient(), u, component.Sidecar, 587 func() labels.Labels { return labels.FromStrings("region", "eu-west") }, 588 func() (int64, int64) { return 0, math.MaxInt64 }, 589 nil) 590 testutil.Ok(t, err) 591 592 // We build chunks only for SAMPLES method. Make sure we ask for SAMPLES only. 593 proxy.remoteReadAcceptableResponses = []prompb.ReadRequest_ResponseType{prompb.ReadRequest_SAMPLES} 594 595 return proxy 596 }) 597 }