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

     1  package queryrange
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/grafana/loki/pkg/loghttp"
    10  
    11  	"github.com/go-kit/log"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/weaveworks/common/user"
    14  
    15  	"github.com/grafana/loki/pkg/logproto"
    16  	"github.com/grafana/loki/pkg/querier/queryrange/queryrangebase"
    17  )
    18  
    19  func Test_RangeVectorSplit(t *testing.T) {
    20  	srm := NewSplitByRangeMiddleware(log.NewNopLogger(), fakeLimits{
    21  		maxSeries: 10000,
    22  		splits: map[string]time.Duration{
    23  			"tenant": time.Minute,
    24  		},
    25  	}, nilShardingMetrics)
    26  
    27  	ctx := user.InjectOrgID(context.TODO(), "tenant")
    28  
    29  	for _, tc := range []struct {
    30  		in         queryrangebase.Request
    31  		subQueries []queryrangebase.RequestResponse
    32  		expected   queryrangebase.Response
    33  	}{
    34  		{
    35  			in: &LokiInstantRequest{
    36  				Query:  `sum(bytes_over_time({app="foo"}[3m]))`,
    37  				TimeTs: time.Unix(1, 0),
    38  				Path:   "/loki/api/v1/query",
    39  			},
    40  			subQueries: []queryrangebase.RequestResponse{
    41  				subQueryRequestResponse(`sum(bytes_over_time({app="foo"}[1m]))`, 1),
    42  				subQueryRequestResponse(`sum(bytes_over_time({app="foo"}[1m] offset 1m0s))`, 2),
    43  				subQueryRequestResponse(`sum(bytes_over_time({app="foo"}[1m] offset 2m0s))`, 3),
    44  			},
    45  			expected: expectedMergedResponse(1 + 2 + 3),
    46  		},
    47  		{
    48  			in: &LokiInstantRequest{
    49  				Query:  `sum by (bar) (bytes_over_time({app="foo"}[3m]))`,
    50  				TimeTs: time.Unix(1, 0),
    51  				Path:   "/loki/api/v1/query",
    52  			},
    53  			subQueries: []queryrangebase.RequestResponse{
    54  				subQueryRequestResponse(`sum by(bar)(bytes_over_time({app="foo"}[1m]))`, 10),
    55  				subQueryRequestResponse(`sum by(bar)(bytes_over_time({app="foo"}[1m] offset 1m0s))`, 20),
    56  				subQueryRequestResponse(`sum by(bar)(bytes_over_time({app="foo"}[1m] offset 2m0s))`, 30),
    57  			},
    58  			expected: expectedMergedResponse(10 + 20 + 30),
    59  		},
    60  		{
    61  			in: &LokiInstantRequest{
    62  				Query:  `sum(count_over_time({app="foo"}[3m]))`,
    63  				TimeTs: time.Unix(1, 0),
    64  				Path:   "/loki/api/v1/query",
    65  			},
    66  			subQueries: []queryrangebase.RequestResponse{
    67  				subQueryRequestResponse(`sum(count_over_time({app="foo"}[1m]))`, 1),
    68  				subQueryRequestResponse(`sum(count_over_time({app="foo"}[1m] offset 1m0s))`, 1),
    69  				subQueryRequestResponse(`sum(count_over_time({app="foo"}[1m] offset 2m0s))`, 1),
    70  			},
    71  			expected: expectedMergedResponse(1 + 1 + 1),
    72  		},
    73  		{
    74  			in: &LokiInstantRequest{
    75  				Query:  `sum by (bar) (count_over_time({app="foo"}[3m]))`,
    76  				TimeTs: time.Unix(1, 0),
    77  				Path:   "/loki/api/v1/query",
    78  			},
    79  			subQueries: []queryrangebase.RequestResponse{
    80  				subQueryRequestResponse(`sum by(bar)(count_over_time({app="foo"}[1m]))`, 0),
    81  				subQueryRequestResponse(`sum by(bar)(count_over_time({app="foo"}[1m] offset 1m0s))`, 0),
    82  				subQueryRequestResponse(`sum by(bar)(count_over_time({app="foo"}[1m] offset 2m0s))`, 0),
    83  			},
    84  			expected: expectedMergedResponse(0 + 0 + 0),
    85  		},
    86  		{
    87  			in: &LokiInstantRequest{
    88  				Query:  `sum(sum_over_time({app="foo"} | unwrap bar [3m]))`,
    89  				TimeTs: time.Unix(1, 0),
    90  				Path:   "/loki/api/v1/query",
    91  			},
    92  			subQueries: []queryrangebase.RequestResponse{
    93  				subQueryRequestResponse(`sum(sum_over_time({app="foo"} | unwrap bar[1m]))`, 1),
    94  				subQueryRequestResponse(`sum(sum_over_time({app="foo"} | unwrap bar[1m] offset 1m0s))`, 2),
    95  				subQueryRequestResponse(`sum(sum_over_time({app="foo"} | unwrap bar[1m] offset 2m0s))`, 3),
    96  			},
    97  			expected: expectedMergedResponse(1 + 2 + 3),
    98  		},
    99  		{
   100  			in: &LokiInstantRequest{
   101  				Query:  `sum by (bar) (sum_over_time({app="foo"} | unwrap bar [3m]))`,
   102  				TimeTs: time.Unix(1, 0),
   103  				Path:   "/loki/api/v1/query",
   104  			},
   105  			subQueries: []queryrangebase.RequestResponse{
   106  				subQueryRequestResponse(`sum by(bar)(sum_over_time({app="foo"} | unwrap bar[1m]))`, 1),
   107  				subQueryRequestResponse(`sum by(bar)(sum_over_time({app="foo"} | unwrap bar[1m] offset 1m0s))`, 2),
   108  				subQueryRequestResponse(`sum by(bar)(sum_over_time({app="foo"} | unwrap bar[1m] offset 2m0s))`, 3),
   109  			},
   110  			expected: expectedMergedResponse(1 + 2 + 3),
   111  		},
   112  	} {
   113  		tc := tc
   114  		t.Run(tc.in.GetQuery(), func(t *testing.T) {
   115  			resp, err := srm.Wrap(queryrangebase.HandlerFunc(
   116  				func(ctx context.Context, req queryrangebase.Request) (queryrangebase.Response, error) {
   117  					// Assert subquery request
   118  					for _, reqResp := range tc.subQueries {
   119  						if req.GetQuery() == reqResp.Request.GetQuery() {
   120  							require.Equal(t, reqResp.Request, req)
   121  							// return the test data subquery response
   122  							return reqResp.Response, nil
   123  						}
   124  					}
   125  
   126  					return nil, fmt.Errorf("subquery request '" + req.GetQuery() + "' not found")
   127  				})).Do(ctx, tc.in)
   128  			require.NoError(t, err)
   129  			require.Equal(t, tc.expected, resp.(*LokiPromResponse).Response)
   130  		})
   131  	}
   132  }
   133  
   134  // subQueryRequestResponse returns a RequestResponse containing the expected subQuery instant request
   135  // and a response containing a sample value returned from the following wrapper
   136  func subQueryRequestResponse(expectedSubQuery string, sampleValue float64) queryrangebase.RequestResponse {
   137  	return queryrangebase.RequestResponse{
   138  		Request: &LokiInstantRequest{
   139  			Query:  expectedSubQuery,
   140  			TimeTs: time.Unix(1, 0),
   141  			Path:   "/loki/api/v1/query",
   142  		},
   143  		Response: &LokiPromResponse{
   144  			Response: &queryrangebase.PrometheusResponse{
   145  				Status: loghttp.QueryStatusSuccess,
   146  				Data: queryrangebase.PrometheusData{
   147  					ResultType: loghttp.ResultTypeVector,
   148  					Result: []queryrangebase.SampleStream{
   149  						{
   150  							Labels: []logproto.LabelAdapter{
   151  								{Name: "app", Value: "foo"},
   152  							},
   153  							Samples: []logproto.LegacySample{
   154  								{TimestampMs: 1000, Value: sampleValue},
   155  							},
   156  						},
   157  					},
   158  				},
   159  			},
   160  		},
   161  	}
   162  }
   163  
   164  // expectedMergedResponse returns the expected middleware Prometheus response with the samples
   165  // as the expectedSampleValue
   166  func expectedMergedResponse(expectedSampleValue float64) *queryrangebase.PrometheusResponse {
   167  	return &queryrangebase.PrometheusResponse{
   168  		Status: loghttp.QueryStatusSuccess,
   169  		Data: queryrangebase.PrometheusData{
   170  			ResultType: loghttp.ResultTypeVector,
   171  			Result: []queryrangebase.SampleStream{
   172  				{
   173  					Labels: []logproto.LabelAdapter{},
   174  					Samples: []logproto.LegacySample{
   175  						{TimestampMs: 1000, Value: expectedSampleValue},
   176  					},
   177  				},
   178  			},
   179  		},
   180  	}
   181  }