github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/querier/querier_test.go (about)

     1  package querier
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io"
     7  	"net/http"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/grafana/dskit/flagext"
    12  	"github.com/grafana/dskit/ring"
    13  	ring_client "github.com/grafana/dskit/ring/client"
    14  	"github.com/prometheus/common/model"
    15  	"github.com/stretchr/testify/assert"
    16  	"github.com/stretchr/testify/mock"
    17  	"github.com/stretchr/testify/require"
    18  	"github.com/weaveworks/common/httpgrpc"
    19  	"github.com/weaveworks/common/user"
    20  
    21  	"github.com/grafana/loki/pkg/ingester/client"
    22  	"github.com/grafana/loki/pkg/logproto"
    23  	"github.com/grafana/loki/pkg/logql"
    24  	"github.com/grafana/loki/pkg/storage"
    25  	"github.com/grafana/loki/pkg/storage/stores/indexshipper/compactor/deletion"
    26  	"github.com/grafana/loki/pkg/validation"
    27  )
    28  
    29  const (
    30  	// Custom query timeout used in tests
    31  	queryTimeout = 12 * time.Second
    32  )
    33  
    34  func TestQuerier_Label_QueryTimeoutConfigFlag(t *testing.T) {
    35  	startTime := time.Now().Add(-1 * time.Minute)
    36  	endTime := time.Now()
    37  
    38  	request := logproto.LabelRequest{
    39  		Name:   "test",
    40  		Values: true,
    41  		Start:  &startTime,
    42  		End:    &endTime,
    43  	}
    44  
    45  	ingesterClient := newQuerierClientMock()
    46  	ingesterClient.On("Label", mock.Anything, &request, mock.Anything).Return(mockLabelResponse([]string{}), nil)
    47  
    48  	store := newStoreMock()
    49  	store.On("LabelValuesForMetricName", mock.Anything, "test", model.TimeFromUnixNano(startTime.UnixNano()), model.TimeFromUnixNano(endTime.UnixNano()), "logs", "test").Return([]string{"foo", "bar"}, nil)
    50  
    51  	limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
    52  	require.NoError(t, err)
    53  
    54  	q, err := newQuerier(
    55  		mockQuerierConfig(),
    56  		mockIngesterClientConfig(),
    57  		newIngesterClientMockFactory(ingesterClient),
    58  		mockReadRingWithOneActiveIngester(),
    59  		&mockDeleteGettter{},
    60  		store, limits)
    61  	require.NoError(t, err)
    62  
    63  	ctx := user.InjectOrgID(context.Background(), "test")
    64  	_, err = q.Label(ctx, &request)
    65  	require.NoError(t, err)
    66  
    67  	calls := ingesterClient.GetMockedCallsByMethod("Label")
    68  	assert.Equal(t, 1, len(calls))
    69  	deadline, ok := calls[0].Arguments.Get(0).(context.Context).Deadline()
    70  	assert.True(t, ok)
    71  	assert.WithinDuration(t, deadline, time.Now().Add(queryTimeout), 1*time.Second)
    72  
    73  	calls = store.GetMockedCallsByMethod("LabelValuesForMetricName")
    74  	assert.Equal(t, 1, len(calls))
    75  	deadline, ok = calls[0].Arguments.Get(0).(context.Context).Deadline()
    76  	assert.True(t, ok)
    77  	assert.WithinDuration(t, deadline, time.Now().Add(queryTimeout), 1*time.Second)
    78  
    79  	store.AssertExpectations(t)
    80  }
    81  
    82  func TestQuerier_Tail_QueryTimeoutConfigFlag(t *testing.T) {
    83  	request := logproto.TailRequest{
    84  		Query:    "{type=\"test\"}",
    85  		DelayFor: 0,
    86  		Limit:    10,
    87  		Start:    time.Now(),
    88  	}
    89  
    90  	store := newStoreMock()
    91  	store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(1, 2), nil)
    92  
    93  	queryClient := newQueryClientMock()
    94  	queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 2)}), nil)
    95  
    96  	tailClient := newTailClientMock()
    97  	tailClient.On("Recv").Return(mockTailResponse(mockStream(1, 2)), nil)
    98  
    99  	ingesterClient := newQuerierClientMock()
   100  	ingesterClient.On("Query", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
   101  	ingesterClient.On("Tail", mock.Anything, &request, mock.Anything).Return(tailClient, nil)
   102  	ingesterClient.On("TailersCount", mock.Anything, mock.Anything, mock.Anything).Return(&logproto.TailersCountResponse{}, nil)
   103  
   104  	limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
   105  	require.NoError(t, err)
   106  
   107  	q, err := newQuerier(
   108  		mockQuerierConfig(),
   109  		mockIngesterClientConfig(),
   110  		newIngesterClientMockFactory(ingesterClient),
   111  		mockReadRingWithOneActiveIngester(),
   112  		&mockDeleteGettter{},
   113  		store, limits)
   114  	require.NoError(t, err)
   115  
   116  	ctx := user.InjectOrgID(context.Background(), "test")
   117  	_, err = q.Tail(ctx, &request)
   118  	require.NoError(t, err)
   119  
   120  	calls := ingesterClient.GetMockedCallsByMethod("Query")
   121  	assert.Equal(t, 1, len(calls))
   122  	deadline, ok := calls[0].Arguments.Get(0).(context.Context).Deadline()
   123  	assert.True(t, ok)
   124  	assert.WithinDuration(t, deadline, time.Now().Add(queryTimeout), 1*time.Second)
   125  
   126  	calls = ingesterClient.GetMockedCallsByMethod("Tail")
   127  	assert.Equal(t, 1, len(calls))
   128  	_, ok = calls[0].Arguments.Get(0).(context.Context).Deadline()
   129  	assert.False(t, ok)
   130  
   131  	calls = store.GetMockedCallsByMethod("SelectLogs")
   132  	assert.Equal(t, 1, len(calls))
   133  	deadline, ok = calls[0].Arguments.Get(0).(context.Context).Deadline()
   134  	assert.True(t, ok)
   135  	assert.WithinDuration(t, deadline, time.Now().Add(queryTimeout), 1*time.Second)
   136  
   137  	store.AssertExpectations(t)
   138  }
   139  
   140  func mockQuerierConfig() Config {
   141  	return Config{
   142  		TailMaxDuration: 1 * time.Minute,
   143  		QueryTimeout:    queryTimeout,
   144  	}
   145  }
   146  
   147  func mockQueryResponse(streams []logproto.Stream) *logproto.QueryResponse {
   148  	return &logproto.QueryResponse{
   149  		Streams: streams,
   150  	}
   151  }
   152  
   153  func mockLabelResponse(values []string) *logproto.LabelResponse {
   154  	return &logproto.LabelResponse{
   155  		Values: values,
   156  	}
   157  }
   158  
   159  func defaultLimitsTestConfig() validation.Limits {
   160  	limits := validation.Limits{}
   161  	flagext.DefaultValues(&limits)
   162  	return limits
   163  }
   164  
   165  func TestQuerier_validateQueryRequest(t *testing.T) {
   166  	request := logproto.QueryRequest{
   167  		Selector:  "{type=\"test\", fail=\"yes\"} |= \"foo\"",
   168  		Limit:     10,
   169  		Start:     time.Now().Add(-1 * time.Minute),
   170  		End:       time.Now(),
   171  		Direction: logproto.FORWARD,
   172  	}
   173  
   174  	store := newStoreMock()
   175  	store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(1, 2), nil)
   176  
   177  	queryClient := newQueryClientMock()
   178  	queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 2)}), nil)
   179  
   180  	ingesterClient := newQuerierClientMock()
   181  	ingesterClient.On("Query", mock.Anything, &request, mock.Anything).Return(queryClient, nil)
   182  
   183  	defaultLimits := defaultLimitsTestConfig()
   184  	defaultLimits.MaxStreamsMatchersPerQuery = 1
   185  	defaultLimits.MaxQueryLength = model.Duration(2 * time.Minute)
   186  
   187  	limits, err := validation.NewOverrides(defaultLimits, nil)
   188  	require.NoError(t, err)
   189  
   190  	q, err := newQuerier(
   191  		mockQuerierConfig(),
   192  		mockIngesterClientConfig(),
   193  		newIngesterClientMockFactory(ingesterClient),
   194  		mockReadRingWithOneActiveIngester(),
   195  		&mockDeleteGettter{},
   196  		store, limits)
   197  	require.NoError(t, err)
   198  
   199  	ctx := user.InjectOrgID(context.Background(), "test")
   200  
   201  	_, err = q.SelectLogs(ctx, logql.SelectLogParams{QueryRequest: &request})
   202  	require.Equal(t, httpgrpc.Errorf(http.StatusBadRequest, "max streams matchers per query exceeded, matchers-count > limit (2 > 1)"), err)
   203  
   204  	request.Selector = "{type=\"test\"}"
   205  	_, err = q.SelectLogs(ctx, logql.SelectLogParams{QueryRequest: &request})
   206  	require.NoError(t, err)
   207  
   208  	request.Start = request.End.Add(-3 * time.Minute)
   209  	_, err = q.SelectLogs(ctx, logql.SelectLogParams{QueryRequest: &request})
   210  	require.Equal(t, httpgrpc.Errorf(http.StatusBadRequest, "the query time range exceeds the limit (query length: 3m0s, limit: 2m0s)"), err)
   211  }
   212  
   213  func TestQuerier_SeriesAPI(t *testing.T) {
   214  	mkReq := func(groups []string) *logproto.SeriesRequest {
   215  		return &logproto.SeriesRequest{
   216  			Start:  time.Unix(0, 0),
   217  			End:    time.Unix(10, 0),
   218  			Groups: groups,
   219  		}
   220  	}
   221  
   222  	mockSeriesResponse := func(series []map[string]string) *logproto.SeriesResponse {
   223  		resp := &logproto.SeriesResponse{}
   224  		for _, s := range series {
   225  			resp.Series = append(resp.Series, logproto.SeriesIdentifier{
   226  				Labels: s,
   227  			})
   228  		}
   229  		return resp
   230  	}
   231  
   232  	for _, tc := range []struct {
   233  		desc  string
   234  		req   *logproto.SeriesRequest
   235  		setup func(*storeMock, *queryClientMock, *querierClientMock, validation.Limits, *logproto.SeriesRequest)
   236  		run   func(*testing.T, *SingleTenantQuerier, *logproto.SeriesRequest)
   237  	}{
   238  		{
   239  			"ingester error",
   240  			mkReq([]string{`{a="1"}`}),
   241  			func(store *storeMock, querier *queryClientMock, ingester *querierClientMock, limits validation.Limits, req *logproto.SeriesRequest) {
   242  				ingester.On("Series", mock.Anything, req, mock.Anything).Return(nil, errors.New("tst-err"))
   243  
   244  				store.On("Series", mock.Anything, mock.Anything).Return(nil, nil)
   245  			},
   246  			func(t *testing.T, q *SingleTenantQuerier, req *logproto.SeriesRequest) {
   247  				ctx := user.InjectOrgID(context.Background(), "test")
   248  				_, err := q.Series(ctx, req)
   249  				require.Error(t, err)
   250  			},
   251  		},
   252  		{
   253  			"store error",
   254  			mkReq([]string{`{a="1"}`}),
   255  			func(store *storeMock, querier *queryClientMock, ingester *querierClientMock, limits validation.Limits, req *logproto.SeriesRequest) {
   256  				ingester.On("Series", mock.Anything, req, mock.Anything).Return(mockSeriesResponse([]map[string]string{
   257  					{"a": "1"},
   258  				}), nil)
   259  
   260  				store.On("Series", mock.Anything, mock.Anything).Return(nil, context.DeadlineExceeded)
   261  			},
   262  			func(t *testing.T, q *SingleTenantQuerier, req *logproto.SeriesRequest) {
   263  				ctx := user.InjectOrgID(context.Background(), "test")
   264  				_, err := q.Series(ctx, req)
   265  				require.Error(t, err)
   266  			},
   267  		},
   268  		{
   269  			"no matches",
   270  			mkReq([]string{`{a="1"}`}),
   271  			func(store *storeMock, querier *queryClientMock, ingester *querierClientMock, limits validation.Limits, req *logproto.SeriesRequest) {
   272  				ingester.On("Series", mock.Anything, req, mock.Anything).Return(mockSeriesResponse(nil), nil)
   273  				store.On("Series", mock.Anything, mock.Anything).Return(nil, nil)
   274  			},
   275  			func(t *testing.T, q *SingleTenantQuerier, req *logproto.SeriesRequest) {
   276  				ctx := user.InjectOrgID(context.Background(), "test")
   277  				resp, err := q.Series(ctx, req)
   278  				require.Nil(t, err)
   279  				require.Equal(t, &logproto.SeriesResponse{Series: make([]logproto.SeriesIdentifier, 0)}, resp)
   280  			},
   281  		},
   282  		{
   283  			"returns series",
   284  			mkReq([]string{`{a="1"}`}),
   285  			func(store *storeMock, querier *queryClientMock, ingester *querierClientMock, limits validation.Limits, req *logproto.SeriesRequest) {
   286  				ingester.On("Series", mock.Anything, req, mock.Anything).Return(mockSeriesResponse([]map[string]string{
   287  					{"a": "1", "b": "2"},
   288  					{"a": "1", "b": "3"},
   289  				}), nil)
   290  
   291  				store.On("Series", mock.Anything, mock.Anything).Return([]logproto.SeriesIdentifier{
   292  					{Labels: map[string]string{"a": "1", "b": "4"}},
   293  					{Labels: map[string]string{"a": "1", "b": "5"}},
   294  				}, nil)
   295  			},
   296  			func(t *testing.T, q *SingleTenantQuerier, req *logproto.SeriesRequest) {
   297  				ctx := user.InjectOrgID(context.Background(), "test")
   298  				resp, err := q.Series(ctx, req)
   299  				require.Nil(t, err)
   300  				require.ElementsMatch(t, []logproto.SeriesIdentifier{
   301  					{Labels: map[string]string{"a": "1", "b": "2"}},
   302  					{Labels: map[string]string{"a": "1", "b": "3"}},
   303  					{Labels: map[string]string{"a": "1", "b": "4"}},
   304  					{Labels: map[string]string{"a": "1", "b": "5"}},
   305  				}, resp.GetSeries())
   306  			},
   307  		},
   308  		{
   309  			"dedupes",
   310  			mkReq([]string{`{a="1"}`}),
   311  			func(store *storeMock, querier *queryClientMock, ingester *querierClientMock, limits validation.Limits, req *logproto.SeriesRequest) {
   312  				ingester.On("Series", mock.Anything, req, mock.Anything).Return(mockSeriesResponse([]map[string]string{
   313  					{"a": "1", "b": "2"},
   314  				}), nil)
   315  
   316  				store.On("Series", mock.Anything, mock.Anything).Return([]logproto.SeriesIdentifier{
   317  					{Labels: map[string]string{"a": "1", "b": "2"}},
   318  					{Labels: map[string]string{"a": "1", "b": "3"}},
   319  				}, nil)
   320  			},
   321  			func(t *testing.T, q *SingleTenantQuerier, req *logproto.SeriesRequest) {
   322  				ctx := user.InjectOrgID(context.Background(), "test")
   323  				resp, err := q.Series(ctx, req)
   324  				require.Nil(t, err)
   325  				require.ElementsMatch(t, []logproto.SeriesIdentifier{
   326  					{Labels: map[string]string{"a": "1", "b": "2"}},
   327  					{Labels: map[string]string{"a": "1", "b": "3"}},
   328  				}, resp.GetSeries())
   329  			},
   330  		},
   331  	} {
   332  		t.Run(tc.desc, func(t *testing.T) {
   333  			store := newStoreMock()
   334  			queryClient := newQueryClientMock()
   335  			ingesterClient := newQuerierClientMock()
   336  			defaultLimits := defaultLimitsTestConfig()
   337  			if tc.setup != nil {
   338  				tc.setup(store, queryClient, ingesterClient, defaultLimits, tc.req)
   339  			}
   340  
   341  			limits, err := validation.NewOverrides(defaultLimits, nil)
   342  			require.NoError(t, err)
   343  
   344  			q, err := newQuerier(
   345  				mockQuerierConfig(),
   346  				mockIngesterClientConfig(),
   347  				newIngesterClientMockFactory(ingesterClient),
   348  				mockReadRingWithOneActiveIngester(),
   349  				&mockDeleteGettter{},
   350  				store, limits)
   351  			require.NoError(t, err)
   352  
   353  			tc.run(t, q, tc.req)
   354  		})
   355  	}
   356  }
   357  
   358  func TestQuerier_IngesterMaxQueryLookback(t *testing.T) {
   359  	limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
   360  	require.NoError(t, err)
   361  
   362  	for _, tc := range []struct {
   363  		desc          string
   364  		lookback      time.Duration
   365  		end           time.Time
   366  		skipIngesters bool
   367  	}{
   368  		{
   369  			desc:          "0 value always queries ingesters",
   370  			lookback:      0,
   371  			end:           time.Now().Add(time.Hour),
   372  			skipIngesters: false,
   373  		},
   374  		{
   375  			desc:          "query ingester",
   376  			lookback:      time.Hour,
   377  			end:           time.Now(),
   378  			skipIngesters: false,
   379  		},
   380  		{
   381  			desc:          "skip ingester",
   382  			lookback:      time.Hour,
   383  			end:           time.Now().Add(-2 * time.Hour),
   384  			skipIngesters: true,
   385  		},
   386  	} {
   387  		t.Run(tc.desc, func(t *testing.T) {
   388  			req := logproto.QueryRequest{
   389  				Selector:  `{app="foo"}`,
   390  				Limit:     1000,
   391  				Start:     tc.end.Add(-6 * time.Hour),
   392  				End:       tc.end,
   393  				Direction: logproto.FORWARD,
   394  			}
   395  
   396  			queryClient := newQueryClientMock()
   397  			ingesterClient := newQuerierClientMock()
   398  
   399  			if !tc.skipIngesters {
   400  				ingesterClient.On("Query", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
   401  				queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 1)}), nil).Once()
   402  				queryClient.On("Recv").Return(nil, io.EOF).Once()
   403  			}
   404  
   405  			store := newStoreMock()
   406  			store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(0, 1), nil)
   407  
   408  			conf := mockQuerierConfig()
   409  			conf.QueryIngestersWithin = tc.lookback
   410  			q, err := newQuerier(
   411  				conf,
   412  				mockIngesterClientConfig(),
   413  				newIngesterClientMockFactory(ingesterClient),
   414  				mockReadRingWithOneActiveIngester(),
   415  				&mockDeleteGettter{},
   416  				store, limits)
   417  			require.NoError(t, err)
   418  
   419  			ctx := user.InjectOrgID(context.Background(), "test")
   420  
   421  			res, err := q.SelectLogs(ctx, logql.SelectLogParams{QueryRequest: &req})
   422  			require.Nil(t, err)
   423  
   424  			// since streams are loaded lazily, force iterators to exhaust
   425  			for res.Next() {
   426  			}
   427  			queryClient.AssertExpectations(t)
   428  			ingesterClient.AssertExpectations(t)
   429  			store.AssertExpectations(t)
   430  		})
   431  	}
   432  }
   433  
   434  func TestQuerier_concurrentTailLimits(t *testing.T) {
   435  	request := logproto.TailRequest{
   436  		Query:    "{type=\"test\"}",
   437  		DelayFor: 0,
   438  		Limit:    10,
   439  		Start:    time.Now(),
   440  	}
   441  
   442  	t.Parallel()
   443  
   444  	tests := map[string]struct {
   445  		ringIngesters []ring.InstanceDesc
   446  		expectedError error
   447  		tailersCount  uint32
   448  	}{
   449  		"empty ring": {
   450  			ringIngesters: []ring.InstanceDesc{},
   451  			expectedError: httpgrpc.Errorf(http.StatusInternalServerError, "no active ingester found"),
   452  		},
   453  		"ring containing one pending ingester": {
   454  			ringIngesters: []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.PENDING)},
   455  			expectedError: httpgrpc.Errorf(http.StatusInternalServerError, "no active ingester found"),
   456  		},
   457  		"ring containing one active ingester and 0 active tailers": {
   458  			ringIngesters: []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE)},
   459  		},
   460  		"ring containing one active ingester and 1 active tailer": {
   461  			ringIngesters: []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE)},
   462  			tailersCount:  1,
   463  		},
   464  		"ring containing one pending and active ingester with 1 active tailer": {
   465  			ringIngesters: []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.PENDING), mockInstanceDesc("2.2.2.2", ring.ACTIVE)},
   466  			tailersCount:  1,
   467  		},
   468  		"ring containing one active ingester and max active tailers": {
   469  			ringIngesters: []ring.InstanceDesc{mockInstanceDesc("1.1.1.1", ring.ACTIVE)},
   470  			expectedError: httpgrpc.Errorf(http.StatusBadRequest,
   471  				"max concurrent tail requests limit exceeded, count > limit (%d > %d)", 6, 5),
   472  			tailersCount: 5,
   473  		},
   474  	}
   475  
   476  	for testName, testData := range tests {
   477  		testData := testData
   478  
   479  		t.Run(testName, func(t *testing.T) {
   480  			// For this test's purpose, whenever a new ingester client needs to
   481  			// be created, the factory will always return the same mock instance
   482  			store := newStoreMock()
   483  			store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(1, 2), nil)
   484  
   485  			queryClient := newQueryClientMock()
   486  			queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 2)}), nil)
   487  
   488  			tailClient := newTailClientMock()
   489  			tailClient.On("Recv").Return(mockTailResponse(mockStream(1, 2)), nil)
   490  
   491  			ingesterClient := newQuerierClientMock()
   492  			ingesterClient.On("Query", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
   493  			ingesterClient.On("Tail", mock.Anything, &request, mock.Anything).Return(tailClient, nil)
   494  			ingesterClient.On("TailersCount", mock.Anything, mock.Anything, mock.Anything).Return(&logproto.TailersCountResponse{Count: testData.tailersCount}, nil)
   495  
   496  			defaultLimits := defaultLimitsTestConfig()
   497  			defaultLimits.MaxConcurrentTailRequests = 5
   498  
   499  			limits, err := validation.NewOverrides(defaultLimits, nil)
   500  			require.NoError(t, err)
   501  
   502  			q, err := newQuerier(
   503  				mockQuerierConfig(),
   504  				mockIngesterClientConfig(),
   505  				newIngesterClientMockFactory(ingesterClient),
   506  				newReadRingMock(testData.ringIngesters),
   507  				&mockDeleteGettter{},
   508  				store, limits)
   509  			require.NoError(t, err)
   510  
   511  			ctx := user.InjectOrgID(context.Background(), "test")
   512  			_, err = q.Tail(ctx, &request)
   513  			assert.Equal(t, testData.expectedError, err)
   514  		})
   515  	}
   516  }
   517  
   518  func TestQuerier_buildQueryIntervals(t *testing.T) {
   519  	// For simplicity it is always assumed that ingesterQueryStoreMaxLookback and queryIngestersWithin both would be set upto 11 hours so
   520  	// overlappingQuery has range of last 11 hours while nonOverlappingQuery has range older than last 11 hours.
   521  	// We would test the cases below with both the queries.
   522  	overlappingQuery := interval{
   523  		start: time.Now().Add(-6 * time.Hour),
   524  		end:   time.Now(),
   525  	}
   526  
   527  	nonOverlappingQuery := interval{
   528  		start: time.Now().Add(-24 * time.Hour),
   529  		end:   time.Now().Add(-12 * time.Hour),
   530  	}
   531  
   532  	type response struct {
   533  		ingesterQueryInterval *interval
   534  		storeQueryInterval    *interval
   535  	}
   536  
   537  	compareResponse := func(t *testing.T, expectedResponse, actualResponse response) {
   538  		if expectedResponse.ingesterQueryInterval == nil {
   539  			require.Nil(t, actualResponse.ingesterQueryInterval)
   540  		} else {
   541  			require.InDelta(t, expectedResponse.ingesterQueryInterval.start.Unix(), actualResponse.ingesterQueryInterval.start.Unix(), 1)
   542  			require.InDelta(t, expectedResponse.ingesterQueryInterval.end.Unix(), actualResponse.ingesterQueryInterval.end.Unix(), 1)
   543  		}
   544  
   545  		if expectedResponse.storeQueryInterval == nil {
   546  			require.Nil(t, actualResponse.storeQueryInterval)
   547  		} else {
   548  			require.InDelta(t, expectedResponse.storeQueryInterval.start.Unix(), actualResponse.storeQueryInterval.start.Unix(), 1)
   549  			require.InDelta(t, expectedResponse.storeQueryInterval.end.Unix(), actualResponse.storeQueryInterval.end.Unix(), 1)
   550  		}
   551  	}
   552  
   553  	for _, tc := range []struct {
   554  		name                                string
   555  		ingesterQueryStoreMaxLookback       time.Duration
   556  		queryIngestersWithin                time.Duration
   557  		overlappingQueryExpectedResponse    response
   558  		nonOverlappingQueryExpectedResponse response
   559  	}{
   560  		{
   561  			name: "default values, query ingesters and store for whole duration",
   562  			overlappingQueryExpectedResponse: response{ // query both store and ingesters
   563  				ingesterQueryInterval: &overlappingQuery,
   564  				storeQueryInterval:    &overlappingQuery,
   565  			},
   566  			nonOverlappingQueryExpectedResponse: response{ // query both store and ingesters
   567  				ingesterQueryInterval: &nonOverlappingQuery,
   568  				storeQueryInterval:    &nonOverlappingQuery,
   569  			},
   570  		},
   571  		{
   572  			name:                          "ingesterQueryStoreMaxLookback set to 1h",
   573  			ingesterQueryStoreMaxLookback: time.Hour,
   574  			overlappingQueryExpectedResponse: response{ // query ingesters for last 1h and store until last 1h.
   575  				ingesterQueryInterval: &interval{
   576  					start: time.Now().Add(-time.Hour),
   577  					end:   overlappingQuery.end,
   578  				},
   579  				storeQueryInterval: &interval{
   580  					start: overlappingQuery.start,
   581  					end:   time.Now().Add(-time.Hour),
   582  				},
   583  			},
   584  			nonOverlappingQueryExpectedResponse: response{ // query just the store
   585  				storeQueryInterval: &nonOverlappingQuery,
   586  			},
   587  		},
   588  		{
   589  			name:                          "ingesterQueryStoreMaxLookback set to 10h",
   590  			ingesterQueryStoreMaxLookback: 10 * time.Hour,
   591  			overlappingQueryExpectedResponse: response{ // query just the ingesters.
   592  				ingesterQueryInterval: &overlappingQuery,
   593  			},
   594  			nonOverlappingQueryExpectedResponse: response{ // query just the store
   595  				storeQueryInterval: &nonOverlappingQuery,
   596  			},
   597  		},
   598  		{
   599  			name:                          "ingesterQueryStoreMaxLookback set to 1h and queryIngestersWithin set to 2h, ingesterQueryStoreMaxLookback takes precedence",
   600  			ingesterQueryStoreMaxLookback: time.Hour,
   601  			queryIngestersWithin:          2 * time.Hour,
   602  			overlappingQueryExpectedResponse: response{ // query ingesters for last 1h and store until last 1h.
   603  				ingesterQueryInterval: &interval{
   604  					start: time.Now().Add(-time.Hour),
   605  					end:   overlappingQuery.end,
   606  				},
   607  				storeQueryInterval: &interval{
   608  					start: overlappingQuery.start,
   609  					end:   time.Now().Add(-time.Hour),
   610  				},
   611  			},
   612  			nonOverlappingQueryExpectedResponse: response{ // query just the store
   613  				storeQueryInterval: &nonOverlappingQuery,
   614  			},
   615  		},
   616  		{
   617  			name:                          "ingesterQueryStoreMaxLookback set to 2h and queryIngestersWithin set to 1h, ingesterQueryStoreMaxLookback takes precedence",
   618  			ingesterQueryStoreMaxLookback: 2 * time.Hour,
   619  			queryIngestersWithin:          time.Hour,
   620  			overlappingQueryExpectedResponse: response{ // query ingesters for last 2h and store until last 2h.
   621  				ingesterQueryInterval: &interval{
   622  					start: time.Now().Add(-2 * time.Hour),
   623  					end:   overlappingQuery.end,
   624  				},
   625  				storeQueryInterval: &interval{
   626  					start: overlappingQuery.start,
   627  					end:   time.Now().Add(-2 * time.Hour),
   628  				},
   629  			},
   630  			nonOverlappingQueryExpectedResponse: response{ // query just the store
   631  				storeQueryInterval: &nonOverlappingQuery,
   632  			},
   633  		},
   634  		{
   635  			name:                          "ingesterQueryStoreMaxLookback set to -1, query just ingesters",
   636  			ingesterQueryStoreMaxLookback: -1,
   637  			overlappingQueryExpectedResponse: response{
   638  				ingesterQueryInterval: &overlappingQuery,
   639  			},
   640  			nonOverlappingQueryExpectedResponse: response{
   641  				ingesterQueryInterval: &nonOverlappingQuery,
   642  			},
   643  		},
   644  		{
   645  			name:                 "queryIngestersWithin set to 1h",
   646  			queryIngestersWithin: time.Hour,
   647  			overlappingQueryExpectedResponse: response{ // query both store and ingesters since query overlaps queryIngestersWithin
   648  				ingesterQueryInterval: &overlappingQuery,
   649  				storeQueryInterval:    &overlappingQuery,
   650  			},
   651  			nonOverlappingQueryExpectedResponse: response{ // query just the store since query doesn't overlap queryIngestersWithin
   652  				storeQueryInterval: &nonOverlappingQuery,
   653  			},
   654  		},
   655  		{
   656  			name:                 "queryIngestersWithin set to 10h",
   657  			queryIngestersWithin: 10 * time.Hour,
   658  			overlappingQueryExpectedResponse: response{ // query both store and ingesters since query overlaps queryIngestersWithin
   659  				ingesterQueryInterval: &overlappingQuery,
   660  				storeQueryInterval:    &overlappingQuery,
   661  			},
   662  			nonOverlappingQueryExpectedResponse: response{ // query just the store since query doesn't overlap queryIngestersWithin
   663  				storeQueryInterval: &nonOverlappingQuery,
   664  			},
   665  		},
   666  	} {
   667  		t.Run(tc.name, func(t *testing.T) {
   668  			querier := SingleTenantQuerier{cfg: Config{
   669  				IngesterQueryStoreMaxLookback: tc.ingesterQueryStoreMaxLookback,
   670  				QueryIngestersWithin:          tc.queryIngestersWithin,
   671  			}}
   672  
   673  			ingesterQueryInterval, storeQueryInterval := querier.buildQueryIntervals(overlappingQuery.start, overlappingQuery.end)
   674  			compareResponse(t, tc.overlappingQueryExpectedResponse, response{
   675  				ingesterQueryInterval: ingesterQueryInterval,
   676  				storeQueryInterval:    storeQueryInterval,
   677  			})
   678  
   679  			ingesterQueryInterval, storeQueryInterval = querier.buildQueryIntervals(nonOverlappingQuery.start, nonOverlappingQuery.end)
   680  			compareResponse(t, tc.nonOverlappingQueryExpectedResponse, response{
   681  				ingesterQueryInterval: ingesterQueryInterval,
   682  				storeQueryInterval:    storeQueryInterval,
   683  			})
   684  		})
   685  	}
   686  }
   687  
   688  func TestQuerier_calculateIngesterMaxLookbackPeriod(t *testing.T) {
   689  	for _, tc := range []struct {
   690  		name                          string
   691  		ingesterQueryStoreMaxLookback time.Duration
   692  		queryIngestersWithin          time.Duration
   693  		expected                      time.Duration
   694  	}{
   695  		{
   696  			name:     "defaults are set; infinite lookback period if no values are set",
   697  			expected: -1,
   698  		},
   699  		{
   700  			name:                          "only setting ingesterQueryStoreMaxLookback",
   701  			ingesterQueryStoreMaxLookback: time.Hour,
   702  			expected:                      time.Hour,
   703  		},
   704  		{
   705  			name:                          "setting both ingesterQueryStoreMaxLookback and queryIngestersWithin; ingesterQueryStoreMaxLookback takes precedence",
   706  			ingesterQueryStoreMaxLookback: time.Hour,
   707  			queryIngestersWithin:          time.Minute,
   708  			expected:                      time.Hour,
   709  		},
   710  		{
   711  			name:                 "only setting queryIngestersWithin",
   712  			queryIngestersWithin: time.Minute,
   713  			expected:             time.Minute,
   714  		},
   715  	} {
   716  		t.Run(tc.name, func(t *testing.T) {
   717  			querier := SingleTenantQuerier{cfg: Config{
   718  				IngesterQueryStoreMaxLookback: tc.ingesterQueryStoreMaxLookback,
   719  				QueryIngestersWithin:          tc.queryIngestersWithin,
   720  			}}
   721  
   722  			assert.Equal(t, tc.expected, querier.calculateIngesterMaxLookbackPeriod())
   723  		})
   724  	}
   725  }
   726  
   727  func TestQuerier_isWithinIngesterMaxLookbackPeriod(t *testing.T) {
   728  	overlappingQuery := interval{
   729  		start: time.Now().Add(-6 * time.Hour),
   730  		end:   time.Now(),
   731  	}
   732  
   733  	nonOverlappingQuery := interval{
   734  		start: time.Now().Add(-24 * time.Hour),
   735  		end:   time.Now().Add(-12 * time.Hour),
   736  	}
   737  
   738  	for _, tc := range []struct {
   739  		name                          string
   740  		ingesterQueryStoreMaxLookback time.Duration
   741  		queryIngestersWithin          time.Duration
   742  		overlappingWithinRange        bool
   743  		nonOverlappingWithinRange     bool
   744  	}{
   745  		{
   746  			name:                      "default values, query ingesters and store for whole duration",
   747  			overlappingWithinRange:    true,
   748  			nonOverlappingWithinRange: true,
   749  		},
   750  		{
   751  			name:                          "ingesterQueryStoreMaxLookback set to 1h",
   752  			ingesterQueryStoreMaxLookback: time.Hour,
   753  			overlappingWithinRange:        true,
   754  			nonOverlappingWithinRange:     false,
   755  		},
   756  		{
   757  			name:                          "ingesterQueryStoreMaxLookback set to 10h",
   758  			ingesterQueryStoreMaxLookback: 10 * time.Hour,
   759  			overlappingWithinRange:        true,
   760  			nonOverlappingWithinRange:     false,
   761  		},
   762  		{
   763  			name:                          "ingesterQueryStoreMaxLookback set to 1h and queryIngestersWithin set to 16h, ingesterQueryStoreMaxLookback takes precedence",
   764  			ingesterQueryStoreMaxLookback: time.Hour,
   765  			queryIngestersWithin:          16 * time.Hour, // if used, this would put the nonOverlapping query in range
   766  			overlappingWithinRange:        true,
   767  			nonOverlappingWithinRange:     false,
   768  		},
   769  		{
   770  			name:                          "ingesterQueryStoreMaxLookback set to -1, query just ingesters",
   771  			ingesterQueryStoreMaxLookback: -1,
   772  			overlappingWithinRange:        true,
   773  			nonOverlappingWithinRange:     true,
   774  		},
   775  		{
   776  			name:                      "queryIngestersWithin set to 1h",
   777  			queryIngestersWithin:      time.Hour,
   778  			overlappingWithinRange:    true,
   779  			nonOverlappingWithinRange: false,
   780  		},
   781  		{
   782  			name:                      "queryIngestersWithin set to 10h",
   783  			queryIngestersWithin:      10 * time.Hour,
   784  			overlappingWithinRange:    true,
   785  			nonOverlappingWithinRange: false,
   786  		},
   787  	} {
   788  		t.Run(tc.name, func(t *testing.T) {
   789  			querier := SingleTenantQuerier{cfg: Config{
   790  				IngesterQueryStoreMaxLookback: tc.ingesterQueryStoreMaxLookback,
   791  				QueryIngestersWithin:          tc.queryIngestersWithin,
   792  			}}
   793  
   794  			lookbackPeriod := querier.calculateIngesterMaxLookbackPeriod()
   795  			assert.Equal(t, tc.overlappingWithinRange, querier.isWithinIngesterMaxLookbackPeriod(lookbackPeriod, overlappingQuery.end))
   796  			assert.Equal(t, tc.nonOverlappingWithinRange, querier.isWithinIngesterMaxLookbackPeriod(lookbackPeriod, nonOverlappingQuery.end))
   797  		})
   798  	}
   799  }
   800  
   801  func TestQuerier_RequestingIngesters(t *testing.T) {
   802  	ctx := user.InjectOrgID(context.Background(), "test")
   803  
   804  	requestMapping := map[string]struct {
   805  		ingesterMethod string
   806  		storeMethod    string
   807  	}{
   808  		"SelectLogs": {
   809  			ingesterMethod: "Query",
   810  			storeMethod:    "SelectLogs",
   811  		},
   812  		"SelectSamples": {
   813  			ingesterMethod: "QuerySample",
   814  			storeMethod:    "SelectSamples",
   815  		},
   816  		"LabelValuesForMetricName": {
   817  			ingesterMethod: "Label",
   818  			storeMethod:    "LabelValuesForMetricName",
   819  		},
   820  		"LabelNamesForMetricName": {
   821  			ingesterMethod: "Label",
   822  			storeMethod:    "LabelNamesForMetricName",
   823  		},
   824  		"Series": {
   825  			ingesterMethod: "Series",
   826  			storeMethod:    "Series",
   827  		},
   828  	}
   829  
   830  	tests := []struct {
   831  		desc                             string
   832  		start, end                       time.Time
   833  		setIngesterQueryStoreMaxLookback bool
   834  		expectedCallsStore               int
   835  		expectedCallsIngesters           int
   836  	}{
   837  		{
   838  			desc:                   "Data in storage and ingesters",
   839  			start:                  time.Now().Add(-time.Hour * 2),
   840  			end:                    time.Now(),
   841  			expectedCallsStore:     1,
   842  			expectedCallsIngesters: 1,
   843  		},
   844  		{
   845  			desc:                   "Data in ingesters (IngesterQueryStoreMaxLookback not set)",
   846  			start:                  time.Now().Add(-time.Minute * 15),
   847  			end:                    time.Now(),
   848  			expectedCallsStore:     1,
   849  			expectedCallsIngesters: 1,
   850  		},
   851  		{
   852  			desc:                   "Data only in storage",
   853  			start:                  time.Now().Add(-time.Hour * 2),
   854  			end:                    time.Now().Add(-time.Hour * 1),
   855  			expectedCallsStore:     1,
   856  			expectedCallsIngesters: 0,
   857  		},
   858  		{
   859  			desc:                             "Data in ingesters (IngesterQueryStoreMaxLookback set)",
   860  			start:                            time.Now().Add(-time.Minute * 15),
   861  			end:                              time.Now(),
   862  			setIngesterQueryStoreMaxLookback: true,
   863  			expectedCallsStore:               0,
   864  			expectedCallsIngesters:           1,
   865  		},
   866  	}
   867  
   868  	requests := []struct {
   869  		name string
   870  		do   func(querier *SingleTenantQuerier, start, end time.Time) error
   871  	}{
   872  		{
   873  			name: "SelectLogs",
   874  			do: func(querier *SingleTenantQuerier, start, end time.Time) error {
   875  				_, err := querier.SelectLogs(ctx, logql.SelectLogParams{
   876  					QueryRequest: &logproto.QueryRequest{
   877  						Selector:  "{type=\"test\", fail=\"yes\"} |= \"foo\"",
   878  						Limit:     10,
   879  						Start:     start,
   880  						End:       end,
   881  						Direction: logproto.FORWARD,
   882  					},
   883  				})
   884  
   885  				return err
   886  			},
   887  		},
   888  		{
   889  			name: "SelectSamples",
   890  			do: func(querier *SingleTenantQuerier, start, end time.Time) error {
   891  				_, err := querier.SelectSamples(ctx, logql.SelectSampleParams{
   892  					SampleQueryRequest: &logproto.SampleQueryRequest{
   893  						Selector: "count_over_time({foo=\"bar\"}[5m])",
   894  						Start:    start,
   895  						End:      end,
   896  					},
   897  				})
   898  				return err
   899  			},
   900  		},
   901  		{
   902  			name: "LabelValuesForMetricName",
   903  			do: func(querier *SingleTenantQuerier, start, end time.Time) error {
   904  				_, err := querier.Label(ctx, &logproto.LabelRequest{
   905  					Name:   "type",
   906  					Values: true,
   907  					Start:  &start,
   908  					End:    &end,
   909  				})
   910  				return err
   911  			},
   912  		},
   913  		{
   914  			name: "LabelNamesForMetricName",
   915  			do: func(querier *SingleTenantQuerier, start, end time.Time) error {
   916  				_, err := querier.Label(ctx, &logproto.LabelRequest{
   917  					Values: false,
   918  					Start:  &start,
   919  					End:    &end,
   920  				})
   921  				return err
   922  			},
   923  		},
   924  		{
   925  			name: "Series",
   926  			do: func(querier *SingleTenantQuerier, start, end time.Time) error {
   927  				_, err := querier.Series(ctx, &logproto.SeriesRequest{
   928  					Start: start,
   929  					End:   end,
   930  				})
   931  				return err
   932  			},
   933  		},
   934  	}
   935  
   936  	for _, tc := range tests {
   937  		t.Run(tc.desc, func(t *testing.T) {
   938  
   939  			conf := mockQuerierConfig()
   940  			conf.QueryIngestersWithin = time.Minute * 30
   941  			if tc.setIngesterQueryStoreMaxLookback {
   942  				conf.IngesterQueryStoreMaxLookback = conf.QueryIngestersWithin
   943  			}
   944  
   945  			limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
   946  			require.NoError(t, err)
   947  
   948  			for _, request := range requests {
   949  				t.Run(request.name, func(t *testing.T) {
   950  					ingesterClient, store, querier, err := setupIngesterQuerierMocks(conf, limits)
   951  					require.NoError(t, err)
   952  
   953  					err = request.do(querier, tc.start, tc.end)
   954  					require.NoError(t, err)
   955  
   956  					callsIngesters := ingesterClient.GetMockedCallsByMethod(requestMapping[request.name].ingesterMethod)
   957  					assert.Equal(t, tc.expectedCallsIngesters, len(callsIngesters))
   958  
   959  					callsStore := store.GetMockedCallsByMethod(requestMapping[request.name].storeMethod)
   960  					assert.Equal(t, tc.expectedCallsStore, len(callsStore))
   961  				})
   962  			}
   963  		})
   964  	}
   965  }
   966  
   967  func setupIngesterQuerierMocks(conf Config, limits *validation.Overrides) (*querierClientMock, *storeMock, *SingleTenantQuerier, error) {
   968  	queryClient := newQueryClientMock()
   969  	queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 1)}), nil)
   970  
   971  	querySampleClient := newQuerySampleClientMock()
   972  	querySampleClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 1)}), nil)
   973  
   974  	ingesterClient := newQuerierClientMock()
   975  	ingesterClient.On("Query", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
   976  	ingesterClient.On("QuerySample", mock.Anything, mock.Anything, mock.Anything).Return(querySampleClient, nil)
   977  	ingesterClient.On("Label", mock.Anything, mock.Anything, mock.Anything).Return(mockLabelResponse([]string{"bar"}), nil)
   978  	ingesterClient.On("Series", mock.Anything, mock.Anything, mock.Anything).Return(&logproto.SeriesResponse{
   979  		Series: []logproto.SeriesIdentifier{
   980  			{
   981  				Labels: map[string]string{"bar": "1"},
   982  			},
   983  		},
   984  	}, nil)
   985  
   986  	store := newStoreMock()
   987  	store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(0, 1), nil)
   988  	store.On("SelectSamples", mock.Anything, mock.Anything).Return(mockSampleIterator(querySampleClient), nil)
   989  	store.On("LabelValuesForMetricName", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]string{"1", "2", "3"}, nil)
   990  	store.On("LabelNamesForMetricName", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return([]string{"foo"}, nil)
   991  	store.On("Series", mock.Anything, mock.Anything).Return([]logproto.SeriesIdentifier{
   992  		{Labels: map[string]string{"foo": "1"}},
   993  	}, nil)
   994  
   995  	querier, err := newQuerier(
   996  		conf,
   997  		mockIngesterClientConfig(),
   998  		newIngesterClientMockFactory(ingesterClient),
   999  		mockReadRingWithOneActiveIngester(),
  1000  		&mockDeleteGettter{},
  1001  		store, limits)
  1002  
  1003  	if err != nil {
  1004  		return nil, nil, nil, err
  1005  	}
  1006  
  1007  	return ingesterClient, store, querier, nil
  1008  }
  1009  
  1010  type fakeTimeLimits struct {
  1011  	maxQueryLookback time.Duration
  1012  	maxQueryLength   time.Duration
  1013  }
  1014  
  1015  func (f fakeTimeLimits) MaxQueryLookback(_ string) time.Duration { return f.maxQueryLookback }
  1016  func (f fakeTimeLimits) MaxQueryLength(_ string) time.Duration   { return f.maxQueryLength }
  1017  
  1018  func Test_validateQueryTimeRangeLimits(t *testing.T) {
  1019  	now := time.Now()
  1020  	nowFunc = func() time.Time { return now }
  1021  	tests := []struct {
  1022  		name        string
  1023  		limits      timeRangeLimits
  1024  		from        time.Time
  1025  		through     time.Time
  1026  		wantFrom    time.Time
  1027  		wantThrough time.Time
  1028  		wantErr     bool
  1029  	}{
  1030  		{"no change", fakeTimeLimits{1000 * time.Hour, 1000 * time.Hour}, now, now.Add(24 * time.Hour), now, now.Add(24 * time.Hour), false},
  1031  		{"clamped to 24h", fakeTimeLimits{24 * time.Hour, 1000 * time.Hour}, now.Add(-48 * time.Hour), now, now.Add(-24 * time.Hour), now, false},
  1032  		{"end before start", fakeTimeLimits{}, now, now.Add(-48 * time.Hour), time.Time{}, time.Time{}, true},
  1033  		{"query too long", fakeTimeLimits{maxQueryLength: 24 * time.Hour}, now.Add(-48 * time.Hour), now, time.Time{}, time.Time{}, true},
  1034  	}
  1035  	for _, tt := range tests {
  1036  		t.Run(tt.name, func(t *testing.T) {
  1037  			from, through, err := validateQueryTimeRangeLimits(context.Background(), "foo", tt.limits, tt.from, tt.through)
  1038  			if tt.wantErr {
  1039  				require.NotNil(t, err)
  1040  			} else {
  1041  				require.Nil(t, err)
  1042  			}
  1043  			require.Equal(t, tt.wantFrom, from, "wanted (%s) got (%s)", tt.wantFrom, from)
  1044  			require.Equal(t, tt.wantThrough, through)
  1045  		})
  1046  	}
  1047  }
  1048  
  1049  func TestQuerier_SelectLogWithDeletes(t *testing.T) {
  1050  	store := newStoreMock()
  1051  	store.On("SelectLogs", mock.Anything, mock.Anything).Return(mockStreamIterator(1, 2), nil)
  1052  
  1053  	queryClient := newQueryClientMock()
  1054  	queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 2)}), nil)
  1055  
  1056  	ingesterClient := newQuerierClientMock()
  1057  	ingesterClient.On("Query", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
  1058  
  1059  	limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
  1060  	require.NoError(t, err)
  1061  
  1062  	delGetter := &mockDeleteGettter{
  1063  		results: []deletion.DeleteRequest{
  1064  			{Query: `0`, StartTime: 0, EndTime: 100},
  1065  			{Query: `1`, StartTime: 200, EndTime: 400},
  1066  			{Query: `2`, StartTime: 400, EndTime: 500},
  1067  			{Query: `3`, StartTime: 500, EndTime: 700},
  1068  			{Query: `4`, StartTime: 700, EndTime: 900},
  1069  		},
  1070  	}
  1071  
  1072  	q, err := newQuerier(
  1073  		mockQuerierConfig(),
  1074  		mockIngesterClientConfig(),
  1075  		newIngesterClientMockFactory(ingesterClient),
  1076  		mockReadRingWithOneActiveIngester(),
  1077  		delGetter, store, limits)
  1078  	require.NoError(t, err)
  1079  
  1080  	ctx := user.InjectOrgID(context.Background(), "test")
  1081  
  1082  	request := logproto.QueryRequest{
  1083  		Selector:  `{type="test"} |= "foo"`,
  1084  		Limit:     10,
  1085  		Start:     time.Unix(0, 300000000),
  1086  		End:       time.Unix(0, 600000000),
  1087  		Direction: logproto.FORWARD,
  1088  	}
  1089  
  1090  	_, err = q.SelectLogs(ctx, logql.SelectLogParams{QueryRequest: &request})
  1091  	require.NoError(t, err)
  1092  
  1093  	expectedRequest := &logproto.QueryRequest{
  1094  		Selector:  request.Selector,
  1095  		Limit:     request.Limit,
  1096  		Start:     request.Start,
  1097  		End:       request.End,
  1098  		Direction: request.Direction,
  1099  		Deletes: []*logproto.Delete{
  1100  			{Selector: "1", Start: 200000000, End: 400000000},
  1101  			{Selector: "2", Start: 400000000, End: 500000000},
  1102  			{Selector: "3", Start: 500000000, End: 700000000},
  1103  		},
  1104  	}
  1105  
  1106  	require.Contains(t, store.Calls[0].Arguments, logql.SelectLogParams{QueryRequest: expectedRequest})
  1107  	require.Contains(t, ingesterClient.Calls[0].Arguments, expectedRequest)
  1108  	require.Equal(t, "test", delGetter.user)
  1109  }
  1110  
  1111  func TestQuerier_SelectSamplesWithDeletes(t *testing.T) {
  1112  	queryClient := newQuerySampleClientMock()
  1113  	queryClient.On("Recv").Return(mockQueryResponse([]logproto.Stream{mockStream(1, 2)}), nil)
  1114  
  1115  	store := newStoreMock()
  1116  	store.On("SelectSamples", mock.Anything, mock.Anything).Return(mockSampleIterator(queryClient), nil)
  1117  
  1118  	ingesterClient := newQuerierClientMock()
  1119  	ingesterClient.On("QuerySample", mock.Anything, mock.Anything, mock.Anything).Return(queryClient, nil)
  1120  
  1121  	limits, err := validation.NewOverrides(defaultLimitsTestConfig(), nil)
  1122  	require.NoError(t, err)
  1123  
  1124  	delGetter := &mockDeleteGettter{
  1125  		results: []deletion.DeleteRequest{
  1126  			{Query: `0`, StartTime: 0, EndTime: 100},
  1127  			{Query: `1`, StartTime: 200, EndTime: 400},
  1128  			{Query: `2`, StartTime: 400, EndTime: 500},
  1129  			{Query: `3`, StartTime: 500, EndTime: 700},
  1130  			{Query: `4`, StartTime: 700, EndTime: 900},
  1131  		},
  1132  	}
  1133  
  1134  	q, err := newQuerier(
  1135  		mockQuerierConfig(),
  1136  		mockIngesterClientConfig(),
  1137  		newIngesterClientMockFactory(ingesterClient),
  1138  		mockReadRingWithOneActiveIngester(),
  1139  		delGetter, store, limits)
  1140  	require.NoError(t, err)
  1141  
  1142  	ctx := user.InjectOrgID(context.Background(), "test")
  1143  
  1144  	request := logproto.SampleQueryRequest{
  1145  		Selector: `count_over_time({foo="bar"}[5m])`,
  1146  		Start:    time.Unix(0, 300000000),
  1147  		End:      time.Unix(0, 600000000),
  1148  	}
  1149  
  1150  	_, err = q.SelectSamples(ctx, logql.SelectSampleParams{SampleQueryRequest: &request})
  1151  	require.NoError(t, err)
  1152  
  1153  	expectedRequest := logql.SelectSampleParams{
  1154  		SampleQueryRequest: &logproto.SampleQueryRequest{
  1155  			Selector: request.Selector,
  1156  			Start:    request.Start,
  1157  			End:      request.End,
  1158  			Deletes: []*logproto.Delete{
  1159  				{Selector: "1", Start: 200000000, End: 400000000},
  1160  				{Selector: "2", Start: 400000000, End: 500000000},
  1161  				{Selector: "3", Start: 500000000, End: 700000000},
  1162  			},
  1163  		},
  1164  	}
  1165  
  1166  	require.Contains(t, store.Calls[0].Arguments, expectedRequest)
  1167  	require.Contains(t, ingesterClient.Calls[0].Arguments, expectedRequest.SampleQueryRequest)
  1168  	require.Equal(t, "test", delGetter.user)
  1169  }
  1170  
  1171  func newQuerier(cfg Config, clientCfg client.Config, clientFactory ring_client.PoolFactory, ring ring.ReadRing, dg *mockDeleteGettter, store storage.Store, limits *validation.Overrides) (*SingleTenantQuerier, error) {
  1172  	iq, err := newIngesterQuerier(clientCfg, ring, cfg.ExtraQueryDelay, clientFactory)
  1173  	if err != nil {
  1174  		return nil, err
  1175  	}
  1176  
  1177  	return New(cfg, store, iq, limits, dg, nil)
  1178  }
  1179  
  1180  type mockDeleteGettter struct {
  1181  	user    string
  1182  	results []deletion.DeleteRequest
  1183  }
  1184  
  1185  func (d *mockDeleteGettter) GetAllDeleteRequestsForUser(ctx context.Context, userID string) ([]deletion.DeleteRequest, error) {
  1186  	d.user = userID
  1187  	return d.results, nil
  1188  }