github.com/thanos-io/thanos@v0.32.5/pkg/store/proxy_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  
    10  	"math"
    11  	"math/rand"
    12  	"os"
    13  	"path/filepath"
    14  	"sync"
    15  	"testing"
    16  	"time"
    17  
    18  	"github.com/cespare/xxhash/v2"
    19  	"github.com/go-kit/log"
    20  	"github.com/gogo/protobuf/proto"
    21  	"github.com/gogo/protobuf/types"
    22  	"github.com/pkg/errors"
    23  	"github.com/prometheus/prometheus/model/labels"
    24  	"github.com/prometheus/prometheus/model/timestamp"
    25  	"github.com/prometheus/prometheus/tsdb"
    26  	"github.com/prometheus/prometheus/tsdb/chunkenc"
    27  	"google.golang.org/grpc"
    28  	"google.golang.org/grpc/codes"
    29  	"google.golang.org/grpc/status"
    30  
    31  	"github.com/efficientgo/core/testutil"
    32  
    33  	"github.com/thanos-io/thanos/pkg/component"
    34  	"github.com/thanos-io/thanos/pkg/info/infopb"
    35  	"github.com/thanos-io/thanos/pkg/store/labelpb"
    36  	"github.com/thanos-io/thanos/pkg/store/storepb"
    37  	storetestutil "github.com/thanos-io/thanos/pkg/store/storepb/testutil"
    38  	"github.com/thanos-io/thanos/pkg/testutil/custom"
    39  )
    40  
    41  type mockedSeriesServer struct {
    42  	storepb.Store_SeriesServer
    43  	ctx context.Context
    44  
    45  	send func(*storepb.SeriesResponse) error
    46  }
    47  
    48  func (s *mockedSeriesServer) Send(r *storepb.SeriesResponse) error {
    49  	return s.send(r)
    50  }
    51  func (s *mockedSeriesServer) Context() context.Context { return s.ctx }
    52  
    53  type mockedStartTimeDB struct {
    54  	*tsdb.DBReadOnly
    55  	startTime int64
    56  }
    57  
    58  func (db *mockedStartTimeDB) StartTime() (int64, error) { return db.startTime, nil }
    59  
    60  func TestProxyStore_Info(t *testing.T) {
    61  	defer custom.TolerantVerifyLeak(t)
    62  
    63  	ctx, cancel := context.WithCancel(context.Background())
    64  	defer cancel()
    65  
    66  	q := NewProxyStore(nil,
    67  		nil,
    68  		func() []Client { return nil },
    69  		component.Query,
    70  		nil, 0*time.Second, RetrievalStrategy(EagerRetrieval),
    71  	)
    72  
    73  	resp, err := q.Info(ctx, &storepb.InfoRequest{})
    74  	testutil.Ok(t, err)
    75  	testutil.Equals(t, []labelpb.ZLabelSet(nil), resp.LabelSets)
    76  	testutil.Equals(t, storepb.StoreType_QUERY, resp.StoreType)
    77  	testutil.Equals(t, int64(0), resp.MinTime)
    78  	testutil.Equals(t, int64(0), resp.MaxTime)
    79  }
    80  
    81  func TestProxyStore_TSDBInfos(t *testing.T) {
    82  	stores := []Client{
    83  		&storetestutil.TestClient{
    84  			StoreTSDBInfos: nil,
    85  		},
    86  		&storetestutil.TestClient{
    87  			StoreTSDBInfos: []infopb.TSDBInfo{
    88  				infopb.NewTSDBInfo(0, 10, []labelpb.ZLabel{{Name: "lbl", Value: "val1"}}),
    89  			},
    90  		},
    91  		&storetestutil.TestClient{
    92  			StoreTSDBInfos: []infopb.TSDBInfo{
    93  				infopb.NewTSDBInfo(0, 20, []labelpb.ZLabel{{Name: "lbl", Value: "val2"}}),
    94  			},
    95  		},
    96  	}
    97  	q := NewProxyStore(nil, nil,
    98  		func() []Client { return stores },
    99  		component.Query, nil, 0*time.Second, EagerRetrieval,
   100  	)
   101  
   102  	expected := []infopb.TSDBInfo{
   103  		infopb.NewTSDBInfo(0, 10, []labelpb.ZLabel{{Name: "lbl", Value: "val1"}}),
   104  		infopb.NewTSDBInfo(0, 20, []labelpb.ZLabel{{Name: "lbl", Value: "val2"}}),
   105  	}
   106  	testutil.Equals(t, expected, q.TSDBInfos())
   107  }
   108  
   109  func TestProxyStore_Series(t *testing.T) {
   110  	defer custom.TolerantVerifyLeak(t)
   111  
   112  	for _, tc := range []struct {
   113  		title          string
   114  		storeAPIs      []Client
   115  		selectorLabels labels.Labels
   116  
   117  		req                *storepb.SeriesRequest
   118  		storeDebugMatchers [][]*labels.Matcher
   119  
   120  		expectedSeries      []rawSeries
   121  		expectedErr         error
   122  		expectedWarningsLen int
   123  	}{
   124  		{
   125  			title: "no storeAPI available",
   126  			req: &storepb.SeriesRequest{
   127  				MinTime:  1,
   128  				MaxTime:  300,
   129  				Matchers: []storepb.LabelMatcher{{Name: "a", Value: "a", Type: storepb.LabelMatcher_EQ}},
   130  			},
   131  			expectedWarningsLen: 0, // No store matched for this query.
   132  		},
   133  		{
   134  			title: "no storeAPI available for 301-302 time range",
   135  			storeAPIs: []Client{
   136  				&storetestutil.TestClient{
   137  					StoreClient: &mockedStoreAPI{
   138  						RespSeries: []*storepb.SeriesResponse{
   139  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   140  						},
   141  					},
   142  					MinTime: 1,
   143  					MaxTime: 300,
   144  				},
   145  			},
   146  			req: &storepb.SeriesRequest{
   147  				MinTime:  301,
   148  				MaxTime:  400,
   149  				Matchers: []storepb.LabelMatcher{{Name: "a", Value: "a", Type: storepb.LabelMatcher_EQ}},
   150  			},
   151  			expectedWarningsLen: 0, // No store matched for this query.
   152  		},
   153  		{
   154  			title: "storeAPI available for time range; no series for ext=2 external label matcher",
   155  			storeAPIs: []Client{
   156  				&storetestutil.TestClient{
   157  					StoreClient: &mockedStoreAPI{
   158  						RespSeries: []*storepb.SeriesResponse{
   159  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   160  						},
   161  					},
   162  					MinTime: 1,
   163  					MaxTime: 300,
   164  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   165  				},
   166  			},
   167  			req: &storepb.SeriesRequest{
   168  				MinTime:  1,
   169  				MaxTime:  300,
   170  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "2", Type: storepb.LabelMatcher_EQ}},
   171  			},
   172  			expectedWarningsLen: 0, // No store matched for this query.
   173  		},
   174  		{
   175  			title: "storeAPI available for time range; available series for ext=1 external label matcher",
   176  			storeAPIs: []Client{
   177  				&storetestutil.TestClient{
   178  					StoreClient: &mockedStoreAPI{
   179  						RespSeries: []*storepb.SeriesResponse{
   180  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   181  						},
   182  					},
   183  					MinTime: 1,
   184  					MaxTime: 300,
   185  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   186  				},
   187  			},
   188  			req: &storepb.SeriesRequest{
   189  				MinTime:  1,
   190  				MaxTime:  300,
   191  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   192  			},
   193  			expectedSeries: []rawSeries{
   194  				{
   195  					lset:   labels.FromStrings("a", "a"),
   196  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}},
   197  				},
   198  			},
   199  		},
   200  		{
   201  			title: "storeAPI available for time range; available series for any external label matcher",
   202  			storeAPIs: []Client{
   203  				&storetestutil.TestClient{
   204  					StoreClient: &mockedStoreAPI{
   205  						RespSeries: []*storepb.SeriesResponse{
   206  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{4, 3}}, []sample{{0, 0}, {2, 1}, {3, 2}}),
   207  						},
   208  					},
   209  					MinTime: 1,
   210  					MaxTime: 300,
   211  				},
   212  			},
   213  			req: &storepb.SeriesRequest{
   214  				MinTime:  1,
   215  				MaxTime:  300,
   216  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   217  			},
   218  			expectedSeries: []rawSeries{
   219  				{
   220  					lset:   labels.FromStrings("a", "a"),
   221  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}, {{4, 3}}},
   222  				},
   223  			},
   224  		},
   225  		{
   226  			title: "storeAPI available for time range; available series for any external label matcher, but selector blocks",
   227  			storeAPIs: []Client{
   228  				&storetestutil.TestClient{
   229  					StoreClient: &mockedStoreAPI{
   230  						RespSeries: []*storepb.SeriesResponse{
   231  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   232  						},
   233  					},
   234  					MinTime: 1,
   235  					MaxTime: 300,
   236  				},
   237  			},
   238  			selectorLabels: labels.FromStrings("ext", "2"),
   239  			req: &storepb.SeriesRequest{
   240  				MinTime:  1,
   241  				MaxTime:  300,
   242  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   243  			},
   244  		},
   245  		{
   246  			title: "no validation if storeAPI follow matching contract",
   247  			storeAPIs: []Client{
   248  				&storetestutil.TestClient{
   249  					StoreClient: &mockedStoreAPI{
   250  						RespSeries: []*storepb.SeriesResponse{
   251  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   252  						},
   253  					},
   254  					MinTime: 1,
   255  					MaxTime: 300,
   256  				},
   257  			},
   258  			req: &storepb.SeriesRequest{
   259  				MinTime:  1,
   260  				MaxTime:  300,
   261  				Matchers: []storepb.LabelMatcher{{Name: "a", Value: "b", Type: storepb.LabelMatcher_EQ}},
   262  			},
   263  			expectedSeries: []rawSeries{
   264  				{
   265  					// We did not ask for a=a, but we trust StoreAPI will match correctly, so proxy does check any of this.
   266  					lset:   labels.FromStrings("a", "a"),
   267  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}},
   268  				},
   269  			},
   270  		},
   271  		{
   272  			title: "complex scenario with storeAPIs warnings",
   273  			storeAPIs: []Client{
   274  				&storetestutil.TestClient{
   275  					StoreClient: &mockedStoreAPI{
   276  						RespSeries: []*storepb.SeriesResponse{
   277  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}, []sample{{4, 3}}),
   278  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{5, 4}}), // Continuations of the same series.
   279  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   280  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{2, 2}, {3, 3}, {4, 4}}),
   281  						},
   282  					},
   283  					MinTime: 1,
   284  					MaxTime: 300,
   285  				},
   286  				&storetestutil.TestClient{
   287  					StoreClient: &mockedStoreAPI{
   288  						RespSeries: []*storepb.SeriesResponse{
   289  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   290  						},
   291  					},
   292  					MinTime: 1,
   293  					MaxTime: 300,
   294  				},
   295  				&storetestutil.TestClient{
   296  					StoreClient: &mockedStoreAPI{
   297  						RespSeries: []*storepb.SeriesResponse{
   298  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   299  						},
   300  					},
   301  					MinTime: 1,
   302  					MaxTime: 300,
   303  				},
   304  				&storetestutil.TestClient{
   305  					StoreClient: &mockedStoreAPI{
   306  						RespSeries: []*storepb.SeriesResponse{
   307  							storeSeriesResponse(t, labels.FromStrings("a", "c"), []sample{{100, 1}, {300, 3}, {400, 4}}),
   308  						},
   309  					},
   310  					MinTime: 1,
   311  					MaxTime: 300,
   312  				},
   313  				&storetestutil.TestClient{
   314  					StoreClient: &mockedStoreAPI{
   315  						RespSeries: []*storepb.SeriesResponse{
   316  							storeSeriesResponse(t, labels.FromStrings("a", "outside"), []sample{{1, 1}}),
   317  						},
   318  					},
   319  					// Outside range for store itself.
   320  					MinTime: 301,
   321  					MaxTime: 302,
   322  				},
   323  			},
   324  			req: &storepb.SeriesRequest{
   325  				MinTime:  1,
   326  				MaxTime:  300,
   327  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   328  			},
   329  			expectedSeries: []rawSeries{
   330  				{
   331  					lset:   labels.FromStrings("a", "a"),
   332  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}, {{4, 3}}, {{5, 4}}},
   333  				},
   334  				{
   335  					lset:   labels.FromStrings("a", "b"),
   336  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}, {{2, 2}, {3, 3}, {4, 4}}},
   337  				},
   338  				{
   339  					lset:   labels.FromStrings("a", "c"),
   340  					chunks: [][]sample{{{100, 1}, {300, 3}, {400, 4}}},
   341  				},
   342  			},
   343  			expectedWarningsLen: 2,
   344  		},
   345  		{
   346  			title: "storeAPI available for time range; available two duplicated series for ext=1 external label matcher from 2 storeAPIs",
   347  			storeAPIs: []Client{
   348  				&storetestutil.TestClient{
   349  					StoreClient: &mockedStoreAPI{
   350  						RespSeries: []*storepb.SeriesResponse{
   351  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   352  						},
   353  					},
   354  					MinTime: 1,
   355  					MaxTime: 300,
   356  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   357  				},
   358  				&storetestutil.TestClient{
   359  					StoreClient: &mockedStoreAPI{
   360  						RespSeries: []*storepb.SeriesResponse{
   361  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{1, 4}, {2, 5}, {3, 6}}),
   362  						},
   363  					},
   364  					MinTime: 1,
   365  					MaxTime: 300,
   366  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   367  				},
   368  			},
   369  			req: &storepb.SeriesRequest{
   370  				MinTime:  1,
   371  				MaxTime:  300,
   372  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   373  			},
   374  			expectedSeries: []rawSeries{
   375  				{
   376  					lset:   labels.FromStrings("a", "a"),
   377  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}, {{1, 4}, {2, 5}, {3, 6}}},
   378  				},
   379  			},
   380  		},
   381  		{
   382  			title: "storeAPI available for time range; available a few duplicated series for ext=1 external label matcher, mixed storeAPIs",
   383  			storeAPIs: []Client{
   384  				&storetestutil.TestClient{
   385  					StoreClient: &mockedStoreAPI{
   386  						RespSeries: []*storepb.SeriesResponse{
   387  							storeSeriesResponse(t, labels.FromStrings("a", "1", "w", "1"), []sample{{5, 5}, {7, 7}}),
   388  							storeSeriesResponse(t, labels.FromStrings("a", "1", "w", "1"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   389  							storeSeriesResponse(t, labels.FromStrings("a", "1", "w", "1"), []sample{{5, 5}, {6, 6}, {7, 7}}),
   390  							storeSeriesResponse(t, labels.FromStrings("a", "1", "x", "1"), []sample{{2, 2}, {3, 3}, {4, 4}}, []sample{{1, 1}, {2, 2}, {3, 3}}),
   391  							storeSeriesResponse(t, labels.FromStrings("a", "1", "x", "1"), []sample{{100, 1}, {300, 3}, {400, 4}}),
   392  						},
   393  					},
   394  					MinTime: 1,
   395  					MaxTime: 300,
   396  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   397  				},
   398  				&storetestutil.TestClient{
   399  					StoreClient: &mockedStoreAPI{
   400  						RespSeries: []*storepb.SeriesResponse{
   401  							storeSeriesResponse(t, labels.FromStrings("a", "1", "w", "1"), []sample{{2, 1}}),
   402  							storeSeriesResponse(t, labels.FromStrings("a", "1", "w", "1"), []sample{{5, 5}, {6, 6}, {7, 7}}),
   403  							storeSeriesResponse(t, labels.FromStrings("a", "1", "x", "2"), []sample{{10, 10}, {30, 30}, {40, 40}}),
   404  						},
   405  					},
   406  					MinTime: 1,
   407  					MaxTime: 300,
   408  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   409  				},
   410  			},
   411  			req: &storepb.SeriesRequest{
   412  				MinTime:  1,
   413  				MaxTime:  300,
   414  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   415  			},
   416  			expectedSeries: []rawSeries{
   417  				{
   418  					lset:   labels.FromStrings("a", "1", "w", "1"),
   419  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}, {{2, 1}}, {{5, 5}, {6, 6}, {7, 7}}, {{5, 5}, {7, 7}}},
   420  				},
   421  				{
   422  					lset:   labels.FromStrings("a", "1", "x", "1"),
   423  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}, {{2, 2}, {3, 3}, {4, 4}}, {{100, 1}, {300, 3}, {400, 4}}},
   424  				},
   425  				{
   426  					lset:   labels.FromStrings("a", "1", "x", "2"),
   427  					chunks: [][]sample{{{10, 10}, {30, 30}, {40, 40}}},
   428  				},
   429  			},
   430  		},
   431  		{
   432  			title: "same external labels are validated during upload and on querier storeset, proxy does not care",
   433  			storeAPIs: []Client{
   434  				&storetestutil.TestClient{
   435  					StoreClient: &mockedStoreAPI{
   436  						RespSeries: []*storepb.SeriesResponse{
   437  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   438  						},
   439  					},
   440  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   441  					MinTime: 1,
   442  					MaxTime: 300,
   443  				},
   444  				&storetestutil.TestClient{
   445  					StoreClient: &mockedStoreAPI{
   446  						RespSeries: []*storepb.SeriesResponse{
   447  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 11}, {2, 22}, {3, 33}}),
   448  						},
   449  					},
   450  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   451  					MinTime: 1,
   452  					MaxTime: 300,
   453  				},
   454  			},
   455  			req: &storepb.SeriesRequest{
   456  				MinTime:  1,
   457  				MaxTime:  300,
   458  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   459  			},
   460  			expectedSeries: []rawSeries{
   461  				{
   462  					lset:   labels.FromStrings("a", "b"),
   463  					chunks: [][]sample{{{1, 11}, {2, 22}, {3, 33}}, {{1, 1}, {2, 2}, {3, 3}}},
   464  				},
   465  			},
   466  		},
   467  		{
   468  			title: "partial response enabled",
   469  			storeAPIs: []Client{
   470  				&storetestutil.TestClient{
   471  					StoreClient: &mockedStoreAPI{
   472  						RespSeries: []*storepb.SeriesResponse{
   473  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   474  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   475  						},
   476  					},
   477  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   478  					MinTime: 1,
   479  					MaxTime: 300,
   480  				},
   481  				&storetestutil.TestClient{
   482  					StoreClient: &mockedStoreAPI{
   483  						RespError: errors.New("error!"),
   484  					},
   485  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   486  					MinTime: 1,
   487  					MaxTime: 300,
   488  				},
   489  			},
   490  			req: &storepb.SeriesRequest{
   491  				MinTime:  1,
   492  				MaxTime:  300,
   493  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   494  			},
   495  			expectedSeries: []rawSeries{
   496  				{
   497  					lset:   labels.FromStrings("a", "b"),
   498  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
   499  				},
   500  			},
   501  			expectedWarningsLen: 2,
   502  		},
   503  		{
   504  			title: "partial response disabled",
   505  			storeAPIs: []Client{
   506  				&storetestutil.TestClient{
   507  					StoreClient: &mockedStoreAPI{
   508  						RespSeries: []*storepb.SeriesResponse{
   509  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   510  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   511  						},
   512  					},
   513  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   514  					MinTime: 1,
   515  					MaxTime: 300,
   516  				},
   517  				&storetestutil.TestClient{
   518  					StoreClient: &mockedStoreAPI{
   519  						RespError: errors.New("error!"),
   520  					},
   521  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   522  					MinTime: 1,
   523  					MaxTime: 300,
   524  				},
   525  			},
   526  			req: &storepb.SeriesRequest{
   527  				MinTime:                 1,
   528  				MaxTime:                 300,
   529  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   530  				PartialResponseDisabled: true,
   531  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   532  			},
   533  			expectedErr: errors.New("fetch series for {ext=\"1\"} : error!"),
   534  		},
   535  		{
   536  			title: "storeAPI available for time range; available series for ext=1 external label matcher; allowed by store debug matcher",
   537  			storeAPIs: []Client{
   538  				&storetestutil.TestClient{
   539  					StoreClient: &mockedStoreAPI{
   540  						RespSeries: []*storepb.SeriesResponse{
   541  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   542  						},
   543  					},
   544  					MinTime: 1,
   545  					MaxTime: 300,
   546  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   547  					Name:    "testaddr",
   548  				},
   549  			},
   550  			req: &storepb.SeriesRequest{
   551  				MinTime:  1,
   552  				MaxTime:  300,
   553  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   554  			},
   555  			storeDebugMatchers: [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "testaddr")}},
   556  
   557  			expectedSeries: []rawSeries{
   558  				{
   559  					lset:   labels.FromStrings("a", "a"),
   560  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}},
   561  				},
   562  			},
   563  		},
   564  		{
   565  			title: "storeAPI available for time range; available series for ext=1 external label matcher; blocked by store debug matcher.",
   566  			storeAPIs: []Client{
   567  				&storetestutil.TestClient{
   568  					StoreClient: &mockedStoreAPI{
   569  						RespSeries: []*storepb.SeriesResponse{
   570  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   571  						},
   572  					},
   573  					MinTime: 1,
   574  					MaxTime: 300,
   575  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   576  					Name:    "testaddr",
   577  				},
   578  			},
   579  			req: &storepb.SeriesRequest{
   580  				MinTime:  1,
   581  				MaxTime:  300,
   582  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   583  			},
   584  			storeDebugMatchers:  [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "foo")}},
   585  			expectedWarningsLen: 0, // No stores match.
   586  		},
   587  		{
   588  			title: "sharded series response",
   589  			storeAPIs: []Client{
   590  				&storetestutil.TestClient{
   591  					StoreClient: &mockedStoreAPI{
   592  						RespSeries: []*storepb.SeriesResponse{
   593  							storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   594  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   595  							storeSeriesResponse(t, labels.FromStrings("a", "c"), []sample{{0, 0}, {2, 1}, {3, 2}}),
   596  						},
   597  					},
   598  					MinTime: 1,
   599  					MaxTime: 300,
   600  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   601  				},
   602  			},
   603  			req: &storepb.SeriesRequest{
   604  				MinTime:  1,
   605  				MaxTime:  300,
   606  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   607  				ShardInfo: &storepb.ShardInfo{
   608  					ShardIndex:  0,
   609  					TotalShards: 2,
   610  					By:          true,
   611  					Labels:      []string{"a"},
   612  				},
   613  			},
   614  			expectedSeries: []rawSeries{
   615  				{
   616  					lset:   labels.FromStrings("a", "a"),
   617  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}},
   618  				},
   619  				{
   620  					lset:   labels.FromStrings("a", "b"),
   621  					chunks: [][]sample{{{0, 0}, {2, 1}, {3, 2}}},
   622  				},
   623  			},
   624  		},
   625  	} {
   626  		t.Run(tc.title, func(t *testing.T) {
   627  			for _, replicaLabelSupport := range []bool{false, true} {
   628  				t.Run(fmt.Sprintf("replica_support=%v", replicaLabelSupport), func(t *testing.T) {
   629  					for _, s := range tc.storeAPIs {
   630  						cl := s.(*storetestutil.TestClient)
   631  						cl.WithoutReplicaLabelsEnabled = replicaLabelSupport
   632  					}
   633  					for _, strategy := range []RetrievalStrategy{EagerRetrieval, LazyRetrieval} {
   634  						t.Run(string(strategy), func(t *testing.T) {
   635  							q := NewProxyStore(nil,
   636  								nil,
   637  								func() []Client { return tc.storeAPIs },
   638  								component.Query,
   639  								tc.selectorLabels,
   640  								5*time.Second, strategy,
   641  							)
   642  
   643  							ctx := context.Background()
   644  							if len(tc.storeDebugMatchers) > 0 {
   645  								ctx = context.WithValue(ctx, StoreMatcherKey, tc.storeDebugMatchers)
   646  							}
   647  
   648  							s := newStoreSeriesServer(ctx)
   649  							err := q.Series(tc.req, s)
   650  							if tc.expectedErr != nil {
   651  								testutil.NotOk(t, err)
   652  								testutil.Equals(t, tc.expectedErr.Error(), err.Error())
   653  								return
   654  							}
   655  							testutil.Ok(t, err)
   656  
   657  							seriesEquals(t, tc.expectedSeries, s.SeriesSet)
   658  							testutil.Equals(t, tc.expectedWarningsLen, len(s.Warnings), "got %v warnings", s.Warnings)
   659  						})
   660  					}
   661  				})
   662  			}
   663  		})
   664  	}
   665  }
   666  
   667  func TestProxyStore_SeriesSlowStores(t *testing.T) {
   668  	enable := os.Getenv("THANOS_ENABLE_STORE_READ_TIMEOUT_TESTS")
   669  	if enable == "" {
   670  		t.Skip("enable THANOS_ENABLE_STORE_READ_TIMEOUT_TESTS to run store-read-timeout tests")
   671  	}
   672  
   673  	defer custom.TolerantVerifyLeak(t)
   674  
   675  	for _, tc := range []struct {
   676  		title          string
   677  		storeAPIs      []Client
   678  		selectorLabels labels.Labels
   679  
   680  		req *storepb.SeriesRequest
   681  
   682  		expectedSeries      []rawSeries
   683  		expectedErr         error
   684  		expectedWarningsLen int
   685  	}{
   686  		{
   687  			title: "partial response disabled; 1st errors out after some delay; 2nd store is fast",
   688  			storeAPIs: []Client{
   689  				&storetestutil.TestClient{
   690  					StoreClient: &mockedStoreAPI{
   691  						RespSeries: []*storepb.SeriesResponse{
   692  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   693  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   694  						},
   695  						RespDuration:       2 * time.Second,
   696  						SlowSeriesIndex:    1,
   697  						injectedError:      errors.New("test"),
   698  						injectedErrorIndex: 1,
   699  					},
   700  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   701  					MinTime: 1,
   702  					MaxTime: 300,
   703  				},
   704  				&storetestutil.TestClient{
   705  					StoreClient: &mockedStoreAPI{
   706  						RespSeries: []*storepb.SeriesResponse{
   707  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   708  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   709  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   710  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   711  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   712  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   713  
   714  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   715  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   716  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   717  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   718  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   719  
   720  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   721  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   722  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   723  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   724  							storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{4, 1}, {5, 2}, {6, 3}}),
   725  						},
   726  					},
   727  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   728  					MinTime: 1,
   729  					MaxTime: 300,
   730  				},
   731  			},
   732  			req: &storepb.SeriesRequest{
   733  				MinTime:                 1,
   734  				MaxTime:                 300,
   735  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   736  				PartialResponseDisabled: true,
   737  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   738  			},
   739  			expectedErr: errors.New(`rpc error: code = Aborted desc = warning`),
   740  		},
   741  		{
   742  			title: "partial response disabled; 1st store is slow, 2nd store is fast;",
   743  			storeAPIs: []Client{
   744  				&storetestutil.TestClient{
   745  					StoreClient: &mockedStoreAPI{
   746  						RespSeries: []*storepb.SeriesResponse{
   747  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   748  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   749  						},
   750  						RespDuration: 10 * time.Second,
   751  					},
   752  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   753  					MinTime: 1,
   754  					MaxTime: 300,
   755  				},
   756  				&storetestutil.TestClient{
   757  					StoreClient: &mockedStoreAPI{
   758  						RespSeries: []*storepb.SeriesResponse{
   759  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   760  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   761  						},
   762  					},
   763  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   764  					MinTime: 1,
   765  					MaxTime: 300,
   766  				},
   767  			},
   768  			req: &storepb.SeriesRequest{
   769  				MinTime:                 1,
   770  				MaxTime:                 300,
   771  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   772  				PartialResponseDisabled: true,
   773  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   774  			},
   775  			expectedErr: errors.New("rpc error: code = Aborted desc = failed to receive any data in 4s from test: context canceled"),
   776  		},
   777  		{
   778  			title: "partial response disabled; 1st store is fast, 2nd store is slow;",
   779  			storeAPIs: []Client{
   780  				&storetestutil.TestClient{
   781  					StoreClient: &mockedStoreAPI{
   782  						RespSeries: []*storepb.SeriesResponse{
   783  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   784  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   785  						},
   786  					},
   787  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   788  					MinTime: 1,
   789  					MaxTime: 300,
   790  				},
   791  				&storetestutil.TestClient{
   792  					StoreClient: &mockedStoreAPI{
   793  						RespSeries: []*storepb.SeriesResponse{
   794  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   795  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   796  						},
   797  						RespDuration: 10 * time.Second,
   798  					},
   799  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   800  					MinTime: 1,
   801  					MaxTime: 300,
   802  				},
   803  			},
   804  			req: &storepb.SeriesRequest{
   805  				MinTime:                 1,
   806  				MaxTime:                 300,
   807  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   808  				PartialResponseDisabled: true,
   809  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   810  			},
   811  			expectedErr: errors.New("rpc error: code = Aborted desc = warning"),
   812  		},
   813  		{
   814  			title: "partial response disabled; 1st store is slow on 2nd series, 2nd store is fast;",
   815  			storeAPIs: []Client{
   816  				&storetestutil.TestClient{
   817  					StoreClient: &mockedStoreAPI{
   818  						RespSeries: []*storepb.SeriesResponse{
   819  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   820  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   821  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{3, 1}, {4, 2}, {5, 3}}),
   822  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{6, 1}, {7, 2}, {8, 3}}),
   823  						},
   824  						RespDuration:    10 * time.Second,
   825  						SlowSeriesIndex: 2,
   826  					},
   827  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   828  					MinTime: 1,
   829  					MaxTime: 300,
   830  				},
   831  				&storetestutil.TestClient{
   832  					StoreClient: &mockedStoreAPI{
   833  						RespSeries: []*storepb.SeriesResponse{
   834  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   835  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   836  						},
   837  					},
   838  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   839  					MinTime: 1,
   840  					MaxTime: 300,
   841  				},
   842  			},
   843  			req: &storepb.SeriesRequest{
   844  				MinTime:                 1,
   845  				MaxTime:                 300,
   846  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   847  				PartialResponseDisabled: true,
   848  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   849  			},
   850  			expectedErr: errors.New("rpc error: code = Aborted desc = warning"),
   851  		},
   852  		{
   853  			title: "partial response disabled; 1st store is fast to respond, 2nd store is slow on 2nd series;",
   854  			storeAPIs: []Client{
   855  				&storetestutil.TestClient{
   856  					StoreClient: &mockedStoreAPI{
   857  						RespSeries: []*storepb.SeriesResponse{
   858  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   859  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   860  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{3, 1}, {4, 2}, {5, 3}}),
   861  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{6, 1}, {7, 2}, {8, 3}}),
   862  						},
   863  					},
   864  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   865  					MinTime: 1,
   866  					MaxTime: 300,
   867  				},
   868  				&storetestutil.TestClient{
   869  					StoreClient: &mockedStoreAPI{
   870  						RespSeries: []*storepb.SeriesResponse{
   871  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   872  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   873  						},
   874  						RespDuration:    10 * time.Second,
   875  						SlowSeriesIndex: 2,
   876  					},
   877  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   878  					MinTime: 1,
   879  					MaxTime: 300,
   880  				},
   881  			},
   882  			req: &storepb.SeriesRequest{
   883  				MinTime:                 1,
   884  				MaxTime:                 300,
   885  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   886  				PartialResponseDisabled: true,
   887  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
   888  			},
   889  			expectedErr: errors.New("rpc error: code = Aborted desc = warning"),
   890  		},
   891  		{
   892  			title: "partial response enabled; 1st store is slow to respond, 2nd store is fast;",
   893  			storeAPIs: []Client{
   894  				&storetestutil.TestClient{
   895  					StoreClient: &mockedStoreAPI{
   896  						RespSeries: []*storepb.SeriesResponse{
   897  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   898  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   899  						},
   900  						RespDuration: 10 * time.Second,
   901  					},
   902  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   903  					MinTime: 1,
   904  					MaxTime: 300,
   905  				},
   906  				&storetestutil.TestClient{
   907  					StoreClient: &mockedStoreAPI{
   908  						RespSeries: []*storepb.SeriesResponse{
   909  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   910  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   911  						},
   912  					},
   913  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   914  					MinTime: 1,
   915  					MaxTime: 300,
   916  				},
   917  			},
   918  			req: &storepb.SeriesRequest{
   919  				MinTime:  1,
   920  				MaxTime:  300,
   921  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   922  			},
   923  			expectedSeries: []rawSeries{
   924  				{
   925  					lset:   labels.FromStrings("b", "c"),
   926  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
   927  				},
   928  			},
   929  			expectedWarningsLen: 2,
   930  		},
   931  		{
   932  			title: "partial response enabled; 1st store is fast, 2nd store is slow;",
   933  			storeAPIs: []Client{
   934  				&storetestutil.TestClient{
   935  					StoreClient: &mockedStoreAPI{
   936  						RespSeries: []*storepb.SeriesResponse{
   937  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   938  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   939  						},
   940  					},
   941  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   942  					MinTime: 1,
   943  					MaxTime: 300,
   944  				},
   945  				&storetestutil.TestClient{
   946  					StoreClient: &mockedStoreAPI{
   947  						RespSeries: []*storepb.SeriesResponse{
   948  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   949  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   950  						},
   951  						RespDuration: 10 * time.Second,
   952  					},
   953  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   954  					MinTime: 1,
   955  					MaxTime: 300,
   956  				},
   957  			},
   958  			req: &storepb.SeriesRequest{
   959  				MinTime:  1,
   960  				MaxTime:  300,
   961  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
   962  			},
   963  			expectedSeries: []rawSeries{
   964  				{
   965  					lset:   labels.FromStrings("a", "b"),
   966  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
   967  				},
   968  			},
   969  			expectedWarningsLen: 2,
   970  		},
   971  		{
   972  			title: "partial response enabled; 1st store is fast, 2-3 is slow, 4th is fast;",
   973  			storeAPIs: []Client{
   974  				&storetestutil.TestClient{
   975  					StoreClient: &mockedStoreAPI{
   976  						RespSeries: []*storepb.SeriesResponse{
   977  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   978  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   979  						},
   980  					},
   981  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   982  					MinTime: 1,
   983  					MaxTime: 300,
   984  				},
   985  				&storetestutil.TestClient{
   986  					StoreClient: &mockedStoreAPI{
   987  						RespSeries: []*storepb.SeriesResponse{
   988  							storepb.NewWarnSeriesResponse(errors.New("warning")),
   989  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{1, 1}, {2, 2}, {3, 3}}),
   990  						},
   991  						RespDuration: 10 * time.Second,
   992  					},
   993  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
   994  					MinTime: 1,
   995  					MaxTime: 300,
   996  				},
   997  				&storetestutil.TestClient{
   998  					StoreClient: &mockedStoreAPI{
   999  						RespSeries: []*storepb.SeriesResponse{
  1000  							storepb.NewWarnSeriesResponse(errors.New("warning")),
  1001  							storeSeriesResponse(t, labels.FromStrings("c", "d"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1002  						},
  1003  						RespDuration: 10 * time.Second,
  1004  					},
  1005  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1006  					MinTime: 1,
  1007  					MaxTime: 300,
  1008  				},
  1009  				&storetestutil.TestClient{
  1010  					StoreClient: &mockedStoreAPI{
  1011  						RespSeries: []*storepb.SeriesResponse{
  1012  							storepb.NewWarnSeriesResponse(errors.New("warning")),
  1013  							storeSeriesResponse(t, labels.FromStrings("d", "f"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1014  						},
  1015  					},
  1016  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1017  					MinTime: 1,
  1018  					MaxTime: 300,
  1019  				},
  1020  			},
  1021  			req: &storepb.SeriesRequest{
  1022  				MinTime:  1,
  1023  				MaxTime:  300,
  1024  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
  1025  			},
  1026  			expectedSeries: []rawSeries{
  1027  				{
  1028  					lset:   labels.FromStrings("a", "b"),
  1029  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1030  				},
  1031  				{
  1032  					lset:   labels.FromStrings("d", "f"),
  1033  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1034  				},
  1035  			},
  1036  			expectedWarningsLen: 4,
  1037  		},
  1038  		{
  1039  			title: "partial response enabled; 1st store is slow on 2nd series, 2nd store is fast",
  1040  			storeAPIs: []Client{
  1041  				&storetestutil.TestClient{
  1042  					StoreClient: &mockedStoreAPI{
  1043  						RespSeries: []*storepb.SeriesResponse{
  1044  							storepb.NewWarnSeriesResponse(errors.New("warning")),
  1045  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1046  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{4, 1}, {5, 2}, {6, 3}}),
  1047  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{7, 1}, {8, 2}, {9, 3}}),
  1048  						},
  1049  						RespDuration:    10 * time.Second,
  1050  						SlowSeriesIndex: 2,
  1051  					},
  1052  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1053  					MinTime: 1,
  1054  					MaxTime: 300,
  1055  				},
  1056  				&storetestutil.TestClient{
  1057  					StoreClient: &mockedStoreAPI{
  1058  						RespSeries: []*storepb.SeriesResponse{
  1059  							storepb.NewWarnSeriesResponse(errors.New("warning")),
  1060  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1061  						},
  1062  					},
  1063  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1064  					MinTime: 1,
  1065  					MaxTime: 300,
  1066  				},
  1067  			},
  1068  			req: &storepb.SeriesRequest{
  1069  				MinTime:  1,
  1070  				MaxTime:  300,
  1071  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
  1072  			},
  1073  			expectedSeries: []rawSeries{
  1074  				{
  1075  					lset:   labels.FromStrings("a", "b"),
  1076  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1077  				},
  1078  				{
  1079  					lset:   labels.FromStrings("b", "c"),
  1080  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1081  				},
  1082  			},
  1083  			expectedWarningsLen: 3,
  1084  		},
  1085  		{
  1086  			title: "partial response disabled; all stores respond 3s",
  1087  			storeAPIs: []Client{
  1088  				&storetestutil.TestClient{
  1089  					StoreClient: &mockedStoreAPI{
  1090  						RespSeries: []*storepb.SeriesResponse{
  1091  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1092  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{4, 1}, {5, 2}, {6, 3}}),
  1093  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{7, 1}, {8, 2}, {9, 3}}),
  1094  						},
  1095  						RespDuration: 3 * time.Second,
  1096  					},
  1097  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1098  					MinTime: 1,
  1099  					MaxTime: 300,
  1100  				},
  1101  			},
  1102  			req: &storepb.SeriesRequest{
  1103  				MinTime:                 1,
  1104  				MaxTime:                 300,
  1105  				Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
  1106  				PartialResponseDisabled: true,
  1107  				PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT,
  1108  			},
  1109  			expectedSeries: []rawSeries{
  1110  				{
  1111  					lset:   labels.FromStrings("a", "b"),
  1112  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1113  				},
  1114  			},
  1115  			expectedErr: errors.New("rpc error: code = Aborted desc = receive series from test: context deadline exceeded"),
  1116  		},
  1117  		{
  1118  			title: "partial response enabled; all stores respond 3s",
  1119  			storeAPIs: []Client{
  1120  				&storetestutil.TestClient{
  1121  					StoreClient: &mockedStoreAPI{
  1122  						RespSeries: []*storepb.SeriesResponse{
  1123  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1124  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{4, 1}, {5, 2}, {6, 3}}),
  1125  							storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{7, 1}, {8, 2}, {9, 3}}),
  1126  						},
  1127  						RespDuration: 3 * time.Second,
  1128  					},
  1129  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1130  					MinTime: 1,
  1131  					MaxTime: 300,
  1132  				},
  1133  				&storetestutil.TestClient{
  1134  					StoreClient: &mockedStoreAPI{
  1135  						RespSeries: []*storepb.SeriesResponse{
  1136  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{1, 1}, {2, 2}, {3, 3}}),
  1137  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{4, 1}, {5, 2}, {6, 3}}),
  1138  							storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{7, 1}, {8, 2}, {9, 3}}),
  1139  						},
  1140  						RespDuration: 3 * time.Second,
  1141  					},
  1142  					ExtLset: []labels.Labels{labels.FromStrings("ext", "1")},
  1143  					MinTime: 1,
  1144  					MaxTime: 300,
  1145  				},
  1146  			},
  1147  			req: &storepb.SeriesRequest{
  1148  				MinTime:  1,
  1149  				MaxTime:  300,
  1150  				Matchers: []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
  1151  			},
  1152  			expectedSeries: []rawSeries{
  1153  				{
  1154  					lset:   labels.FromStrings("a", "b"),
  1155  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1156  				},
  1157  				{
  1158  					lset:   labels.FromStrings("b", "c"),
  1159  					chunks: [][]sample{{{1, 1}, {2, 2}, {3, 3}}},
  1160  				},
  1161  			},
  1162  			expectedWarningsLen: 2,
  1163  		},
  1164  	} {
  1165  		if ok := t.Run(tc.title, func(t *testing.T) {
  1166  			for _, strategy := range []RetrievalStrategy{EagerRetrieval, LazyRetrieval} {
  1167  				if ok := t.Run(string(strategy), func(t *testing.T) {
  1168  					q := NewProxyStore(nil,
  1169  						nil,
  1170  						func() []Client { return tc.storeAPIs },
  1171  						component.Query,
  1172  						tc.selectorLabels,
  1173  						4*time.Second, strategy,
  1174  					)
  1175  
  1176  					ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  1177  					defer cancel()
  1178  					s := newStoreSeriesServer(ctx)
  1179  
  1180  					t0 := time.Now()
  1181  					err := q.Series(tc.req, s)
  1182  					elapsedTime := time.Since(t0)
  1183  					if tc.expectedErr != nil {
  1184  						testutil.NotOk(t, err)
  1185  						testutil.Equals(t, tc.expectedErr.Error(), err.Error())
  1186  						return
  1187  					}
  1188  
  1189  					testutil.Ok(t, err)
  1190  
  1191  					seriesEquals(t, tc.expectedSeries, s.SeriesSet)
  1192  					testutil.Equals(t, tc.expectedWarningsLen, len(s.Warnings), "got %v", s.Warnings)
  1193  
  1194  					testutil.Assert(t, elapsedTime < 5010*time.Millisecond, fmt.Sprintf("Request has taken %f, expected: <%d, it seems that responseTimeout doesn't work properly.", elapsedTime.Seconds(), 5))
  1195  
  1196  				}); !ok {
  1197  					return
  1198  				}
  1199  			}
  1200  		}); !ok {
  1201  			return
  1202  		}
  1203  	}
  1204  
  1205  	// Wait until the last goroutine exits which is stuck on time.Sleep().
  1206  	// Otherwise, goleak complains.
  1207  	time.Sleep(5 * time.Second)
  1208  }
  1209  
  1210  func TestProxyStore_Series_RequestParamsProxied(t *testing.T) {
  1211  	defer custom.TolerantVerifyLeak(t)
  1212  
  1213  	m := &mockedStoreAPI{
  1214  		RespSeries: []*storepb.SeriesResponse{
  1215  			storepb.NewWarnSeriesResponse(errors.New("warning")),
  1216  		},
  1217  	}
  1218  	cls := []Client{
  1219  		&storetestutil.TestClient{
  1220  			StoreClient: m,
  1221  			ExtLset:     []labels.Labels{labels.FromStrings("ext", "1")},
  1222  			MinTime:     1,
  1223  			MaxTime:     300,
  1224  		},
  1225  	}
  1226  	q := NewProxyStore(nil,
  1227  		nil,
  1228  		func() []Client { return cls },
  1229  		component.Query,
  1230  		nil,
  1231  		1*time.Second, EagerRetrieval,
  1232  	)
  1233  
  1234  	ctx := context.Background()
  1235  	s := newStoreSeriesServer(ctx)
  1236  
  1237  	req := &storepb.SeriesRequest{
  1238  		MinTime:                 1,
  1239  		MaxTime:                 300,
  1240  		Matchers:                []storepb.LabelMatcher{{Name: "ext", Value: "1", Type: storepb.LabelMatcher_EQ}},
  1241  		PartialResponseDisabled: false,
  1242  		Aggregates: []storepb.Aggr{
  1243  			storepb.Aggr_COUNTER,
  1244  			storepb.Aggr_COUNT,
  1245  		},
  1246  		PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
  1247  		MaxResolutionWindow:     1234,
  1248  	}
  1249  	testutil.Ok(t, q.Series(req, s))
  1250  
  1251  	testutil.Assert(t, proto.Equal(req, m.LastSeriesReq), "request was not proxied properly to underlying storeAPI: %s vs %s", req, m.LastSeriesReq)
  1252  }
  1253  
  1254  func TestProxyStore_Series_RegressionFillResponseChannel(t *testing.T) {
  1255  	defer custom.TolerantVerifyLeak(t)
  1256  
  1257  	var cls []Client
  1258  	for i := 0; i < 10; i++ {
  1259  		cls = append(cls, &storetestutil.TestClient{
  1260  			StoreClient: &mockedStoreAPI{
  1261  				RespError: errors.New("test error"),
  1262  			},
  1263  			MinTime: 1,
  1264  			MaxTime: 300,
  1265  		})
  1266  		cls = append(cls, &storetestutil.TestClient{
  1267  			StoreClient: &mockedStoreAPI{
  1268  				RespSeries: []*storepb.SeriesResponse{
  1269  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1270  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1271  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1272  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1273  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1274  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1275  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1276  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1277  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1278  					storepb.NewWarnSeriesResponse(errors.New("warning")),
  1279  				},
  1280  			},
  1281  			MinTime: 1,
  1282  			MaxTime: 300,
  1283  		})
  1284  
  1285  	}
  1286  
  1287  	q := NewProxyStore(nil,
  1288  		nil,
  1289  		func() []Client { return cls },
  1290  		component.Query,
  1291  		labels.FromStrings("fed", "a"),
  1292  		5*time.Second, EagerRetrieval,
  1293  	)
  1294  
  1295  	ctx := context.Background()
  1296  	s := newStoreSeriesServer(ctx)
  1297  
  1298  	testutil.Ok(t, q.Series(
  1299  		&storepb.SeriesRequest{
  1300  			MinTime:                 1,
  1301  			MaxTime:                 300,
  1302  			Matchers:                []storepb.LabelMatcher{{Name: "any", Value: ".*", Type: storepb.LabelMatcher_RE}},
  1303  			PartialResponseStrategy: storepb.PartialResponseStrategy_WARN,
  1304  		}, s,
  1305  	))
  1306  	testutil.Equals(t, 0, len(s.SeriesSet))
  1307  	testutil.Equals(t, 110, len(s.Warnings))
  1308  }
  1309  
  1310  func TestProxyStore_LabelValues(t *testing.T) {
  1311  	defer custom.TolerantVerifyLeak(t)
  1312  
  1313  	m1 := &mockedStoreAPI{
  1314  		RespLabelValues: &storepb.LabelValuesResponse{
  1315  			Values:   []string{"1", "2"},
  1316  			Warnings: []string{"warning"},
  1317  		},
  1318  	}
  1319  	cls := []Client{
  1320  		&storetestutil.TestClient{StoreClient: m1},
  1321  		&storetestutil.TestClient{StoreClient: &mockedStoreAPI{
  1322  			RespLabelValues: &storepb.LabelValuesResponse{
  1323  				Values: []string{"3", "4"},
  1324  			},
  1325  		}},
  1326  		&storetestutil.TestClient{StoreClient: &mockedStoreAPI{
  1327  			RespLabelValues: &storepb.LabelValuesResponse{
  1328  				Values: []string{"5", "6"},
  1329  			}},
  1330  			MinTime: timestamp.FromTime(time.Now().Add(-1 * time.Minute)),
  1331  			MaxTime: timestamp.FromTime(time.Now()),
  1332  		},
  1333  	}
  1334  	q := NewProxyStore(nil,
  1335  		nil,
  1336  		func() []Client { return cls },
  1337  		component.Query,
  1338  		nil,
  1339  		0*time.Second, EagerRetrieval,
  1340  	)
  1341  
  1342  	ctx := context.Background()
  1343  	req := &storepb.LabelValuesRequest{
  1344  		Label:                   "a",
  1345  		PartialResponseDisabled: true,
  1346  		Start:                   timestamp.FromTime(minTime),
  1347  		End:                     timestamp.FromTime(maxTime),
  1348  	}
  1349  	resp, err := q.LabelValues(ctx, req)
  1350  	testutil.Ok(t, err)
  1351  	testutil.Assert(t, proto.Equal(req, m1.LastLabelValuesReq), "request was not proxied properly to underlying storeAPI: %s vs %s", req, m1.LastLabelValuesReq)
  1352  
  1353  	testutil.Equals(t, []string{"1", "2", "3", "4", "5", "6"}, resp.Values)
  1354  	testutil.Equals(t, 1, len(resp.Warnings))
  1355  
  1356  	// Request outside the time range of the last store client.
  1357  	req = &storepb.LabelValuesRequest{
  1358  		Label:                   "a",
  1359  		PartialResponseDisabled: true,
  1360  		Start:                   timestamp.FromTime(minTime),
  1361  		End:                     timestamp.FromTime(time.Now().Add(-1 * time.Hour)),
  1362  	}
  1363  	resp, err = q.LabelValues(ctx, req)
  1364  	testutil.Ok(t, err)
  1365  	testutil.Assert(t, proto.Equal(req, m1.LastLabelValuesReq), "request was not proxied properly to underlying storeAPI: %s vs %s", req, m1.LastLabelValuesReq)
  1366  
  1367  	testutil.Equals(t, []string{"1", "2", "3", "4"}, resp.Values)
  1368  	testutil.Equals(t, 1, len(resp.Warnings))
  1369  }
  1370  
  1371  func TestProxyStore_LabelNames(t *testing.T) {
  1372  	defer custom.TolerantVerifyLeak(t)
  1373  
  1374  	for _, tc := range []struct {
  1375  		title     string
  1376  		storeAPIs []Client
  1377  
  1378  		req                *storepb.LabelNamesRequest
  1379  		storeDebugMatchers [][]*labels.Matcher
  1380  
  1381  		expectedNames       []string
  1382  		expectedErr         error
  1383  		expectedWarningsLen int
  1384  	}{
  1385  		{
  1386  			title: "label_names partial response disabled",
  1387  			storeAPIs: []Client{
  1388  				&storetestutil.TestClient{
  1389  					StoreClient: &mockedStoreAPI{
  1390  						RespLabelNames: &storepb.LabelNamesResponse{
  1391  							Names: []string{"a", "b"},
  1392  						},
  1393  					},
  1394  				},
  1395  				&storetestutil.TestClient{
  1396  					StoreClient: &mockedStoreAPI{
  1397  						RespLabelNames: &storepb.LabelNamesResponse{
  1398  							Names: []string{"a", "c", "d"},
  1399  						},
  1400  					},
  1401  				},
  1402  			},
  1403  			req: &storepb.LabelNamesRequest{
  1404  				Start:                   timestamp.FromTime(minTime),
  1405  				End:                     timestamp.FromTime(maxTime),
  1406  				PartialResponseDisabled: true,
  1407  			},
  1408  			expectedNames:       []string{"a", "b", "c", "d"},
  1409  			expectedWarningsLen: 0,
  1410  		},
  1411  		{
  1412  			title: "label_names partial response disabled, but returns error",
  1413  			storeAPIs: []Client{
  1414  				&storetestutil.TestClient{
  1415  					StoreClient: &mockedStoreAPI{
  1416  						RespLabelNames: &storepb.LabelNamesResponse{
  1417  							Names: []string{"a", "b"},
  1418  						},
  1419  					},
  1420  				},
  1421  				&storetestutil.TestClient{
  1422  					StoreClient: &mockedStoreAPI{
  1423  						RespError: errors.New("error!"),
  1424  					},
  1425  					Name: "test",
  1426  				},
  1427  			},
  1428  			req: &storepb.LabelNamesRequest{
  1429  				Start:                   timestamp.FromTime(minTime),
  1430  				End:                     timestamp.FromTime(maxTime),
  1431  				PartialResponseDisabled: true,
  1432  			},
  1433  			expectedErr: errors.New("fetch label names from store test: error!"),
  1434  		},
  1435  		{
  1436  			title: "label_names partial response enabled",
  1437  			storeAPIs: []Client{
  1438  				&storetestutil.TestClient{
  1439  					StoreClient: &mockedStoreAPI{
  1440  						RespLabelNames: &storepb.LabelNamesResponse{
  1441  							Names: []string{"a", "b"},
  1442  						},
  1443  					},
  1444  				},
  1445  				&storetestutil.TestClient{
  1446  					StoreClient: &mockedStoreAPI{
  1447  						RespError: errors.New("error!"),
  1448  					},
  1449  				},
  1450  			},
  1451  			req: &storepb.LabelNamesRequest{
  1452  				Start:                   timestamp.FromTime(minTime),
  1453  				End:                     timestamp.FromTime(maxTime),
  1454  				PartialResponseDisabled: false,
  1455  			},
  1456  			expectedNames:       []string{"a", "b"},
  1457  			expectedWarningsLen: 1,
  1458  		},
  1459  		{
  1460  			title: "stores filtered by time range",
  1461  			storeAPIs: []Client{
  1462  				&storetestutil.TestClient{
  1463  					StoreClient: &mockedStoreAPI{
  1464  						RespLabelNames: &storepb.LabelNamesResponse{
  1465  							Names: []string{"a", "b"},
  1466  						},
  1467  					},
  1468  					MinTime: timestamp.FromTime(time.Now().Add(-4 * time.Hour)),
  1469  					MaxTime: timestamp.FromTime(time.Now().Add(-3 * time.Hour)),
  1470  				},
  1471  				&storetestutil.TestClient{
  1472  					StoreClient: &mockedStoreAPI{
  1473  						RespLabelNames: &storepb.LabelNamesResponse{
  1474  							Names: []string{"c", "d"},
  1475  						},
  1476  					},
  1477  					MinTime: timestamp.FromTime(time.Now().Add(-2 * time.Hour)),
  1478  					MaxTime: timestamp.FromTime(time.Now().Add(-1 * time.Hour)),
  1479  				},
  1480  			},
  1481  			req: &storepb.LabelNamesRequest{
  1482  				Start:                   timestamp.FromTime(time.Now().Add(-1 * time.Minute)),
  1483  				End:                     timestamp.FromTime(time.Now()),
  1484  				PartialResponseDisabled: false,
  1485  			},
  1486  			expectedNames:       nil,
  1487  			expectedWarningsLen: 0,
  1488  		},
  1489  		{
  1490  			title: "store matchers blocks",
  1491  			storeAPIs: []Client{
  1492  				&storetestutil.TestClient{
  1493  					StoreClient: &mockedStoreAPI{
  1494  						RespLabelNames: &storepb.LabelNamesResponse{
  1495  							Names: []string{"a", "b"},
  1496  						},
  1497  					},
  1498  					Name: "testaddr",
  1499  				},
  1500  			},
  1501  			req: &storepb.LabelNamesRequest{
  1502  				Start:                   timestamp.FromTime(minTime),
  1503  				End:                     timestamp.FromTime(maxTime),
  1504  				PartialResponseDisabled: false,
  1505  			},
  1506  			storeDebugMatchers:  [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "foo")}},
  1507  			expectedNames:       nil,
  1508  			expectedWarningsLen: 0,
  1509  		},
  1510  		{
  1511  			title: "store matchers allows",
  1512  			storeAPIs: []Client{
  1513  				&storetestutil.TestClient{
  1514  					StoreClient: &mockedStoreAPI{
  1515  						RespLabelNames: &storepb.LabelNamesResponse{
  1516  							Names: []string{"a", "b"},
  1517  						},
  1518  					},
  1519  					Name: "testaddr",
  1520  				},
  1521  			},
  1522  			req: &storepb.LabelNamesRequest{
  1523  				Start:                   timestamp.FromTime(minTime),
  1524  				End:                     timestamp.FromTime(maxTime),
  1525  				PartialResponseDisabled: false,
  1526  			},
  1527  			storeDebugMatchers:  [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "testaddr")}},
  1528  			expectedNames:       []string{"a", "b"},
  1529  			expectedWarningsLen: 0,
  1530  		},
  1531  	} {
  1532  		if ok := t.Run(tc.title, func(t *testing.T) {
  1533  			q := NewProxyStore(
  1534  				nil,
  1535  				nil,
  1536  				func() []Client { return tc.storeAPIs },
  1537  				component.Query,
  1538  				nil,
  1539  				5*time.Second, EagerRetrieval,
  1540  			)
  1541  
  1542  			ctx := context.Background()
  1543  			if len(tc.storeDebugMatchers) > 0 {
  1544  				ctx = context.WithValue(ctx, StoreMatcherKey, tc.storeDebugMatchers)
  1545  			}
  1546  			resp, err := q.LabelNames(ctx, tc.req)
  1547  			if tc.expectedErr != nil {
  1548  				testutil.NotOk(t, err)
  1549  				testutil.Equals(t, tc.expectedErr.Error(), err.Error())
  1550  				return
  1551  			}
  1552  			testutil.Ok(t, err)
  1553  
  1554  			testutil.Equals(t, tc.expectedNames, resp.Names)
  1555  			testutil.Equals(t, tc.expectedWarningsLen, len(resp.Warnings), "got %v", resp.Warnings)
  1556  		}); !ok {
  1557  			return
  1558  		}
  1559  	}
  1560  }
  1561  
  1562  type rawSeries struct {
  1563  	lset   labels.Labels
  1564  	chunks [][]sample
  1565  }
  1566  
  1567  func seriesEquals(t *testing.T, expected []rawSeries, got []storepb.Series) {
  1568  	testutil.Equals(t, len(expected), len(got), "got unexpected number of series: \n %v", got)
  1569  
  1570  	ret := make([]rawSeries, len(got))
  1571  	for i, s := range got {
  1572  		r := rawSeries{
  1573  			lset: labelpb.ZLabelsToPromLabels(s.Labels),
  1574  		}
  1575  		for _, chk := range s.Chunks {
  1576  			var samples []sample
  1577  
  1578  			c, err := chunkenc.FromData(chunkenc.EncXOR, chk.Raw.Data)
  1579  			testutil.Ok(t, err)
  1580  
  1581  			iter := c.Iterator(nil)
  1582  			for iter.Next() != chunkenc.ValNone {
  1583  				tv, v := iter.At()
  1584  				samples = append(samples, sample{tv, v})
  1585  			}
  1586  			testutil.Ok(t, iter.Err())
  1587  
  1588  			r.chunks = append(r.chunks, samples)
  1589  		}
  1590  		ret[i] = r
  1591  	}
  1592  
  1593  	for i := range ret {
  1594  		testutil.Equals(t, expected[i], ret[i])
  1595  	}
  1596  }
  1597  
  1598  func TestStoreMatches(t *testing.T) {
  1599  	for _, c := range []struct {
  1600  		s          Client
  1601  		mint, maxt int64
  1602  		ms         []*labels.Matcher
  1603  
  1604  		expectedMatch  bool
  1605  		expectedReason string
  1606  	}{
  1607  		{
  1608  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1609  			ms: []*labels.Matcher{
  1610  				labels.MustNewMatcher(labels.MatchEqual, "b", "1"),
  1611  			},
  1612  			maxt:           -1,
  1613  			expectedMatch:  false,
  1614  			expectedReason: "does not have data within this time period: [0,-1]. Store time ranges: [0,0]",
  1615  		},
  1616  		{
  1617  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1618  			ms: []*labels.Matcher{
  1619  				labels.MustNewMatcher(labels.MatchEqual, "b", "1"),
  1620  			},
  1621  			maxt:          1,
  1622  			expectedMatch: true,
  1623  		},
  1624  		{
  1625  			s:              &storetestutil.TestClient{MinTime: 100, MaxTime: 200},
  1626  			mint:           201,
  1627  			maxt:           300,
  1628  			expectedMatch:  false,
  1629  			expectedReason: "does not have data within this time period: [201,300]. Store time ranges: [100,200]",
  1630  		},
  1631  		{
  1632  			s:             &storetestutil.TestClient{MinTime: 100, MaxTime: 200},
  1633  			mint:          200,
  1634  			maxt:          300,
  1635  			expectedMatch: true,
  1636  		},
  1637  		{
  1638  			s:              &storetestutil.TestClient{MinTime: 100, MaxTime: 200},
  1639  			mint:           50,
  1640  			maxt:           99,
  1641  			expectedMatch:  false,
  1642  			expectedReason: "does not have data within this time period: [50,99]. Store time ranges: [100,200]",
  1643  		},
  1644  		{
  1645  			s:             &storetestutil.TestClient{MinTime: 100, MaxTime: 200},
  1646  			mint:          50,
  1647  			maxt:          101,
  1648  			expectedMatch: true,
  1649  		},
  1650  		{
  1651  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1652  			ms: []*labels.Matcher{
  1653  				labels.MustNewMatcher(labels.MatchEqual, "a", "b"),
  1654  			},
  1655  			maxt:          1,
  1656  			expectedMatch: true,
  1657  		},
  1658  		{
  1659  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1660  			ms: []*labels.Matcher{
  1661  				labels.MustNewMatcher(labels.MatchEqual, "a", "c"),
  1662  			},
  1663  			maxt:           1,
  1664  			expectedMatch:  false,
  1665  			expectedReason: "external labels [{a=\"b\"}] does not match request label matchers: [a=\"c\"]",
  1666  		},
  1667  		{
  1668  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1669  			ms: []*labels.Matcher{
  1670  				labels.MustNewMatcher(labels.MatchRegexp, "a", "b|c"),
  1671  			},
  1672  			maxt:          1,
  1673  			expectedMatch: true,
  1674  		},
  1675  		{
  1676  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{labels.FromStrings("a", "b")}},
  1677  			ms: []*labels.Matcher{
  1678  				labels.MustNewMatcher(labels.MatchNotRegexp, "a", ""),
  1679  			},
  1680  			maxt:          1,
  1681  			expectedMatch: true,
  1682  		},
  1683  		{
  1684  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{
  1685  				labels.FromStrings("a", "b"),
  1686  				labels.FromStrings("a", "c"),
  1687  				labels.FromStrings("a", "d"),
  1688  			}},
  1689  			ms: []*labels.Matcher{
  1690  				labels.MustNewMatcher(labels.MatchEqual, "a", "e"),
  1691  			},
  1692  			maxt:           1,
  1693  			expectedMatch:  false,
  1694  			expectedReason: "external labels [{a=\"b\"} {a=\"c\"} {a=\"d\"}] does not match request label matchers: [a=\"e\"]",
  1695  		},
  1696  		{
  1697  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{
  1698  				labels.FromStrings("a", "b"),
  1699  				labels.FromStrings("a", "c"),
  1700  				labels.FromStrings("a", "d"),
  1701  			}},
  1702  			ms: []*labels.Matcher{
  1703  				labels.MustNewMatcher(labels.MatchEqual, "a", "c"),
  1704  			},
  1705  			maxt:          1,
  1706  			expectedMatch: true,
  1707  		},
  1708  		{
  1709  			s: &storetestutil.TestClient{ExtLset: []labels.Labels{
  1710  				labels.FromStrings("a", "b"),
  1711  				labels.FromStrings("a", "c"),
  1712  				labels.FromStrings("a", "d"),
  1713  			}},
  1714  			ms: []*labels.Matcher{
  1715  				labels.MustNewMatcher(labels.MatchNotRegexp, "a", ""),
  1716  			},
  1717  			maxt:          1,
  1718  			expectedMatch: true,
  1719  		},
  1720  	} {
  1721  		t.Run("", func(t *testing.T) {
  1722  			ok, reason := storeMatches(context.TODO(), c.s, true, c.mint, c.maxt, c.ms...)
  1723  			testutil.Equals(t, c.expectedMatch, ok)
  1724  			testutil.Equals(t, c.expectedReason, reason)
  1725  
  1726  		})
  1727  	}
  1728  }
  1729  
  1730  // storeSeriesServer is test gRPC storeAPI series server.
  1731  type storeSeriesServer struct {
  1732  	// This field just exist to pseudo-implement the unused methods of the interface.
  1733  	storepb.Store_SeriesServer
  1734  
  1735  	ctx context.Context
  1736  
  1737  	SeriesSet []storepb.Series
  1738  	Warnings  []string
  1739  	HintsSet  []*types.Any
  1740  
  1741  	Size int64
  1742  }
  1743  
  1744  func newStoreSeriesServer(ctx context.Context) *storeSeriesServer {
  1745  	return &storeSeriesServer{ctx: ctx}
  1746  }
  1747  
  1748  func (s *storeSeriesServer) Send(r *storepb.SeriesResponse) error {
  1749  	s.Size += int64(r.Size())
  1750  
  1751  	if r.GetWarning() != "" {
  1752  		s.Warnings = append(s.Warnings, r.GetWarning())
  1753  		return nil
  1754  	}
  1755  
  1756  	if r.GetSeries() != nil {
  1757  		s.SeriesSet = append(s.SeriesSet, *r.GetSeries())
  1758  		return nil
  1759  	}
  1760  
  1761  	if r.GetHints() != nil {
  1762  		s.HintsSet = append(s.HintsSet, r.GetHints())
  1763  		return nil
  1764  	}
  1765  
  1766  	// Unsupported field, skip.
  1767  	return nil
  1768  }
  1769  
  1770  func (s *storeSeriesServer) Context() context.Context {
  1771  	return s.ctx
  1772  }
  1773  
  1774  // mockedStoreAPI is test gRPC store API client.
  1775  type mockedStoreAPI struct {
  1776  	RespSeries      []*storepb.SeriesResponse
  1777  	RespLabelValues *storepb.LabelValuesResponse
  1778  	RespLabelNames  *storepb.LabelNamesResponse
  1779  	RespError       error
  1780  	RespDuration    time.Duration
  1781  	// Index of series in store to slow response.
  1782  	SlowSeriesIndex int
  1783  
  1784  	LastSeriesReq      *storepb.SeriesRequest
  1785  	LastLabelValuesReq *storepb.LabelValuesRequest
  1786  	LastLabelNamesReq  *storepb.LabelNamesRequest
  1787  
  1788  	// injectedError will be injected into Recv() if not nil.
  1789  	injectedError      error
  1790  	injectedErrorIndex int
  1791  }
  1792  
  1793  func (s *mockedStoreAPI) Info(context.Context, *storepb.InfoRequest, ...grpc.CallOption) (*storepb.InfoResponse, error) {
  1794  	return nil, status.Error(codes.Unimplemented, "not implemented")
  1795  }
  1796  
  1797  func (s *mockedStoreAPI) Series(ctx context.Context, req *storepb.SeriesRequest, _ ...grpc.CallOption) (storepb.Store_SeriesClient, error) {
  1798  	s.LastSeriesReq = req
  1799  	return &storetestutil.StoreSeriesClient{InjectedErrorIndex: s.injectedErrorIndex, InjectedError: s.injectedError, Ctx: ctx, RespSet: s.RespSeries, RespDur: s.RespDuration, SlowSeriesIndex: s.SlowSeriesIndex}, s.RespError
  1800  }
  1801  
  1802  func (s *mockedStoreAPI) LabelNames(_ context.Context, req *storepb.LabelNamesRequest, _ ...grpc.CallOption) (*storepb.LabelNamesResponse, error) {
  1803  	s.LastLabelNamesReq = req
  1804  
  1805  	return s.RespLabelNames, s.RespError
  1806  }
  1807  
  1808  func (s *mockedStoreAPI) LabelValues(_ context.Context, req *storepb.LabelValuesRequest, _ ...grpc.CallOption) (*storepb.LabelValuesResponse, error) {
  1809  	s.LastLabelValuesReq = req
  1810  
  1811  	return s.RespLabelValues, s.RespError
  1812  }
  1813  
  1814  // storeSeriesResponse creates test storepb.SeriesResponse that includes series with single chunk that stores all the given samples.
  1815  func storeSeriesResponse(t testing.TB, lset labels.Labels, smplChunks ...[]sample) *storepb.SeriesResponse {
  1816  	var s storepb.Series
  1817  
  1818  	s.Labels = append(s.Labels, labelpb.ZLabelsFromPromLabels(lset)...)
  1819  
  1820  	for _, smpls := range smplChunks {
  1821  		c := chunkenc.NewXORChunk()
  1822  		a, err := c.Appender()
  1823  		testutil.Ok(t, err)
  1824  
  1825  		for _, smpl := range smpls {
  1826  			a.Append(smpl.t, smpl.v)
  1827  		}
  1828  
  1829  		ch := storepb.AggrChunk{
  1830  			MinTime: smpls[0].t,
  1831  			MaxTime: smpls[len(smpls)-1].t,
  1832  			Raw:     &storepb.Chunk{Type: storepb.Chunk_XOR, Data: c.Bytes()},
  1833  		}
  1834  
  1835  		s.Chunks = append(s.Chunks, ch)
  1836  	}
  1837  	return storepb.NewSeriesResponse(&s)
  1838  }
  1839  
  1840  func TestProxySeries(t *testing.T) {
  1841  	tb := testutil.NewTB(t)
  1842  	storetestutil.RunSeriesInterestingCases(tb, 200e3, 200e3, func(t testutil.TB, samplesPerSeries, series int) {
  1843  		benchProxySeries(t, samplesPerSeries, series)
  1844  	})
  1845  }
  1846  
  1847  func BenchmarkProxySeries(b *testing.B) {
  1848  	tb := testutil.NewTB(b)
  1849  	storetestutil.RunSeriesInterestingCases(tb, 10e6, 10e5, func(t testutil.TB, samplesPerSeries, series int) {
  1850  		benchProxySeries(t, samplesPerSeries, series)
  1851  	})
  1852  }
  1853  
  1854  func benchProxySeries(t testutil.TB, totalSamples, totalSeries int) {
  1855  	tmpDir := t.TempDir()
  1856  
  1857  	const numOfClients = 4
  1858  
  1859  	samplesPerSeriesPerClient := totalSamples / numOfClients
  1860  	if samplesPerSeriesPerClient == 0 {
  1861  		samplesPerSeriesPerClient = 1
  1862  	}
  1863  	seriesPerClient := totalSeries / numOfClients
  1864  	if seriesPerClient == 0 {
  1865  		seriesPerClient = 1
  1866  	}
  1867  
  1868  	random := rand.New(rand.NewSource(120))
  1869  	clients := make([]Client, numOfClients)
  1870  	for j := range clients {
  1871  		var resps []*storepb.SeriesResponse
  1872  
  1873  		head, created := storetestutil.CreateHeadWithSeries(t, j, storetestutil.HeadGenOptions{
  1874  			TSDBDir:          filepath.Join(tmpDir, fmt.Sprintf("%d", j)),
  1875  			SamplesPerSeries: samplesPerSeriesPerClient,
  1876  			Series:           seriesPerClient,
  1877  			Random:           random,
  1878  			SkipChunks:       t.IsBenchmark(),
  1879  		})
  1880  		testutil.Ok(t, head.Close())
  1881  
  1882  		for i := 0; i < len(created); i++ {
  1883  			resps = append(resps, storepb.NewSeriesResponse(created[i]))
  1884  		}
  1885  
  1886  		clients[j] = &storetestutil.TestClient{
  1887  			StoreClient: &mockedStoreAPI{
  1888  				RespSeries: resps,
  1889  			},
  1890  			MinTime:                     math.MinInt64,
  1891  			MaxTime:                     math.MaxInt64,
  1892  			WithoutReplicaLabelsEnabled: true,
  1893  		}
  1894  	}
  1895  
  1896  	logger := log.NewNopLogger()
  1897  	store := &ProxyStore{
  1898  		logger:            logger,
  1899  		stores:            func() []Client { return clients },
  1900  		metrics:           newProxyStoreMetrics(nil),
  1901  		responseTimeout:   5 * time.Second,
  1902  		retrievalStrategy: EagerRetrieval,
  1903  	}
  1904  
  1905  	var allResps []*storepb.SeriesResponse
  1906  	var expected []*storepb.Series
  1907  	lastLabels := storepb.Series{}
  1908  	for _, c := range clients {
  1909  		m := c.(*storetestutil.TestClient).StoreClient.(*mockedStoreAPI)
  1910  
  1911  		// NOTE: Proxy will merge all series with same labels without any frame limit (https://github.com/thanos-io/thanos/issues/2332).
  1912  		for _, r := range m.RespSeries {
  1913  			allResps = append(allResps, r)
  1914  
  1915  			x := storepb.Series{Labels: r.GetSeries().Labels}
  1916  			if x.String() == lastLabels.String() {
  1917  				expected[len(expected)-1].Chunks = append(expected[len(expected)-1].Chunks, r.GetSeries().Chunks...)
  1918  				continue
  1919  			}
  1920  			lastLabels = x
  1921  			expected = append(expected, r.GetSeries())
  1922  		}
  1923  
  1924  	}
  1925  
  1926  	chunkLen := len(allResps[len(allResps)-1].GetSeries().Chunks)
  1927  	var maxTime int64
  1928  	if len(allResps[len(allResps)-1].GetSeries().Chunks) == 0 {
  1929  		maxTime = math.MaxInt64
  1930  	} else {
  1931  		maxTime = allResps[len(allResps)-1].GetSeries().Chunks[chunkLen-1].MaxTime
  1932  	}
  1933  	storetestutil.TestServerSeries(t, store,
  1934  		&storetestutil.SeriesCase{
  1935  			Name: fmt.Sprintf("%d client with %d samples, %d series each", numOfClients, samplesPerSeriesPerClient, seriesPerClient),
  1936  			Req: &storepb.SeriesRequest{
  1937  				MinTime: 0,
  1938  				MaxTime: maxTime,
  1939  				Matchers: []storepb.LabelMatcher{
  1940  					{Type: storepb.LabelMatcher_EQ, Name: "foo", Value: "bar"},
  1941  				},
  1942  			},
  1943  			ExpectedSeries: expected,
  1944  		},
  1945  	)
  1946  
  1947  	// Change client to one, containing all series.
  1948  	store.stores = func() []Client {
  1949  		return []Client{&storetestutil.TestClient{
  1950  			StoreClient: &mockedStoreAPI{
  1951  				// All responses.
  1952  				RespSeries: allResps,
  1953  			},
  1954  			ExtLset:                     []labels.Labels{labels.FromStrings("ext1", "1")},
  1955  			MinTime:                     math.MinInt64,
  1956  			MaxTime:                     math.MaxInt64,
  1957  			WithoutReplicaLabelsEnabled: true,
  1958  		}}
  1959  	}
  1960  
  1961  	// In this we expect exactly the same response as input.
  1962  	expected = expected[:0]
  1963  	for _, r := range allResps {
  1964  		expected = append(expected, r.GetSeries())
  1965  	}
  1966  	storetestutil.TestServerSeries(t, store,
  1967  		&storetestutil.SeriesCase{
  1968  			Name: fmt.Sprintf("single client with %d samples, %d series", totalSamples, totalSeries),
  1969  			Req: &storepb.SeriesRequest{
  1970  				MinTime: 0,
  1971  				MaxTime: maxTime,
  1972  				Matchers: []storepb.LabelMatcher{
  1973  					{Type: storepb.LabelMatcher_EQ, Name: "foo", Value: "bar"},
  1974  				},
  1975  			},
  1976  			ExpectedSeries: expected,
  1977  		},
  1978  	)
  1979  }
  1980  
  1981  func TestProxyStore_NotLeakingOnPrematureFinish(t *testing.T) {
  1982  	defer custom.TolerantVerifyLeak(t)
  1983  
  1984  	clients := []Client{
  1985  		&storetestutil.TestClient{
  1986  			StoreClient: &mockedStoreAPI{
  1987  				RespSeries: []*storepb.SeriesResponse{
  1988  					// Ensure more than 10 (internal respCh channel).
  1989  					storeSeriesResponse(t, labels.FromStrings("a", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1990  					storeSeriesResponse(t, labels.FromStrings("a", "b"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1991  					storeSeriesResponse(t, labels.FromStrings("a", "c"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1992  					storeSeriesResponse(t, labels.FromStrings("a", "d"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1993  					storeSeriesResponse(t, labels.FromStrings("a", "e"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1994  					storeSeriesResponse(t, labels.FromStrings("a", "f"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1995  					storeSeriesResponse(t, labels.FromStrings("a", "g"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1996  					storeSeriesResponse(t, labels.FromStrings("a", "h"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1997  					storeSeriesResponse(t, labels.FromStrings("a", "i"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1998  					storeSeriesResponse(t, labels.FromStrings("a", "j"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  1999  				},
  2000  			},
  2001  			MinTime: math.MinInt64,
  2002  			MaxTime: math.MaxInt64,
  2003  		},
  2004  		&storetestutil.TestClient{
  2005  			StoreClient: &mockedStoreAPI{
  2006  				RespSeries: []*storepb.SeriesResponse{
  2007  					storeSeriesResponse(t, labels.FromStrings("b", "a"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2008  					storeSeriesResponse(t, labels.FromStrings("b", "b"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2009  					storeSeriesResponse(t, labels.FromStrings("b", "c"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2010  					storeSeriesResponse(t, labels.FromStrings("b", "d"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2011  					storeSeriesResponse(t, labels.FromStrings("b", "e"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2012  					storeSeriesResponse(t, labels.FromStrings("b", "f"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2013  					storeSeriesResponse(t, labels.FromStrings("b", "g"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2014  					storeSeriesResponse(t, labels.FromStrings("b", "h"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2015  					storeSeriesResponse(t, labels.FromStrings("b", "i"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2016  					storeSeriesResponse(t, labels.FromStrings("b", "j"), []sample{{0, 0}, {2, 1}, {3, 2}}),
  2017  				},
  2018  			},
  2019  			MinTime: math.MinInt64,
  2020  			MaxTime: math.MaxInt64,
  2021  		},
  2022  	}
  2023  
  2024  	logger := log.NewNopLogger()
  2025  	p := &ProxyStore{
  2026  		logger:            logger,
  2027  		stores:            func() []Client { return clients },
  2028  		metrics:           newProxyStoreMetrics(nil),
  2029  		responseTimeout:   0,
  2030  		retrievalStrategy: EagerRetrieval,
  2031  	}
  2032  
  2033  	t.Run("failling send", func(t *testing.T) {
  2034  		ctx, cancel := context.WithCancel(context.Background())
  2035  		// We mimic failing series server, but practically context cancel will do the same.
  2036  		testutil.NotOk(t, p.Series(&storepb.SeriesRequest{Matchers: []storepb.LabelMatcher{{}}, PartialResponseStrategy: storepb.PartialResponseStrategy_ABORT}, &mockedSeriesServer{
  2037  			ctx: ctx,
  2038  			send: func(*storepb.SeriesResponse) error {
  2039  				cancel()
  2040  				return ctx.Err()
  2041  			},
  2042  		}))
  2043  		testutil.NotOk(t, ctx.Err())
  2044  	})
  2045  }
  2046  
  2047  func TestProxyStore_storeMatchMetadata(t *testing.T) {
  2048  	c := storetestutil.TestClient{Name: "testaddr"}
  2049  	c.IsLocalStore = true
  2050  
  2051  	ok, reason := storeMatchDebugMetadata(c, [][]*labels.Matcher{{}})
  2052  	testutil.Assert(t, !ok)
  2053  	testutil.Equals(t, "the store is not remote, cannot match __address__", reason)
  2054  
  2055  	// Change client to remote.
  2056  	c.IsLocalStore = false
  2057  
  2058  	ok, reason = storeMatchDebugMetadata(c, [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "wrong")}})
  2059  	testutil.Assert(t, !ok)
  2060  	testutil.Equals(t, "__address__ testaddr does not match debug store metadata matchers: [[__address__=\"wrong\"]]", reason)
  2061  
  2062  	ok, reason = storeMatchDebugMetadata(c, [][]*labels.Matcher{{labels.MustNewMatcher(labels.MatchEqual, "__address__", "testaddr")}})
  2063  	testutil.Assert(t, ok)
  2064  	testutil.Equals(t, "", reason)
  2065  }
  2066  
  2067  func TestDedupRespHeap_Deduplication(t *testing.T) {
  2068  	t.Parallel()
  2069  
  2070  	for _, tcase := range []struct {
  2071  		responses []*storepb.SeriesResponse
  2072  		testFn    func(responses []*storepb.SeriesResponse, h *dedupResponseHeap)
  2073  		tname     string
  2074  	}{
  2075  		{
  2076  			tname:     "edge case with zero responses",
  2077  			responses: []*storepb.SeriesResponse{},
  2078  			testFn: func(responses []*storepb.SeriesResponse, h *dedupResponseHeap) {
  2079  				testutil.Equals(t, false, h.Next())
  2080  
  2081  				callAtExpectPanic := func() {
  2082  					defer func() {
  2083  						testutil.Assert(t, recover() != nil, "expected a panic from At()")
  2084  					}()
  2085  
  2086  					h.At()
  2087  				}
  2088  				callAtExpectPanic()
  2089  			},
  2090  		},
  2091  		{
  2092  			tname: "edge case with only one response",
  2093  			responses: []*storepb.SeriesResponse{
  2094  				{
  2095  					Result: &storepb.SeriesResponse_Series{
  2096  						Series: &storepb.Series{
  2097  							Labels: labelpb.ZLabelsFromPromLabels(labels.FromStrings("foo", "bar")),
  2098  							Chunks: []storepb.AggrChunk{
  2099  								{
  2100  									Raw: &storepb.Chunk{
  2101  										Type: storepb.Chunk_XOR,
  2102  										Data: []byte(`abcdefgh`),
  2103  									},
  2104  								},
  2105  							},
  2106  						},
  2107  					},
  2108  				},
  2109  			},
  2110  			testFn: func(responses []*storepb.SeriesResponse, h *dedupResponseHeap) {
  2111  				testutil.Equals(t, true, h.Next())
  2112  				resp := h.At()
  2113  				testutil.Equals(t, responses[0], resp)
  2114  				testutil.Equals(t, false, h.Next())
  2115  			},
  2116  		},
  2117  		{
  2118  			tname: "dedups identical series",
  2119  			responses: []*storepb.SeriesResponse{
  2120  				{
  2121  					Result: &storepb.SeriesResponse_Series{
  2122  						Series: &storepb.Series{
  2123  							Labels: labelpb.ZLabelsFromPromLabels(labels.FromStrings("foo", "bar")),
  2124  							Chunks: []storepb.AggrChunk{
  2125  								{
  2126  									Raw: &storepb.Chunk{
  2127  										Type: storepb.Chunk_XOR,
  2128  										Data: []byte(`abcdefgh`),
  2129  									},
  2130  								},
  2131  							},
  2132  						},
  2133  					},
  2134  				},
  2135  				{
  2136  					Result: &storepb.SeriesResponse_Series{
  2137  						Series: &storepb.Series{
  2138  							Labels: labelpb.ZLabelsFromPromLabels(labels.FromStrings("foo", "bar")),
  2139  							Chunks: []storepb.AggrChunk{
  2140  								{
  2141  									Raw: &storepb.Chunk{
  2142  										Type: storepb.Chunk_XOR,
  2143  										Hash: xxhash.Sum64([]byte(`abcdefgh`)),
  2144  										Data: []byte(`abcdefgh`),
  2145  									},
  2146  								},
  2147  							},
  2148  						},
  2149  					},
  2150  				},
  2151  			},
  2152  			testFn: func(responses []*storepb.SeriesResponse, h *dedupResponseHeap) {
  2153  				testutil.Equals(t, true, h.Next())
  2154  				resp := h.At()
  2155  				testutil.Equals(t, responses[0], resp)
  2156  				testutil.Equals(t, false, h.Next())
  2157  			},
  2158  		},
  2159  	} {
  2160  		t.Run(tcase.tname, func(t *testing.T) {
  2161  			h := NewDedupResponseHeap(NewProxyResponseHeap(
  2162  				&eagerRespSet{
  2163  					wg:                &sync.WaitGroup{},
  2164  					bufferedResponses: tcase.responses,
  2165  				},
  2166  			))
  2167  			tcase.testFn(tcase.responses, h)
  2168  		})
  2169  	}
  2170  
  2171  }