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

     1  package queryrangebase
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"sort"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/go-kit/log"
    13  	"github.com/prometheus/client_golang/prometheus"
    14  	"github.com/prometheus/prometheus/model/labels"
    15  	"github.com/prometheus/prometheus/promql"
    16  	"github.com/prometheus/prometheus/storage"
    17  	"github.com/stretchr/testify/require"
    18  
    19  	"github.com/grafana/loki/pkg/querier/astmapper"
    20  )
    21  
    22  var (
    23  	start  = time.Unix(1000, 0)
    24  	end    = start.Add(3 * time.Minute)
    25  	step   = 30 * time.Second
    26  	ctx    = context.Background()
    27  	engine = promql.NewEngine(promql.EngineOpts{
    28  		Reg:                prometheus.DefaultRegisterer,
    29  		Logger:             log.NewNopLogger(),
    30  		Timeout:            1 * time.Hour,
    31  		MaxSamples:         10e6,
    32  		ActiveQueryTracker: nil,
    33  	})
    34  )
    35  
    36  // This test allows to verify which PromQL expressions can be parallelized.
    37  func Test_PromQL(t *testing.T) {
    38  	t.Parallel()
    39  
    40  	var tests = []struct {
    41  		normalQuery string
    42  		shardQuery  string
    43  		shouldEqual bool
    44  	}{
    45  		// Vector can be parallelized but we need to remove the cortex shard label.
    46  		// It should be noted that the __cortex_shard__ label is required by the engine
    47  		// and therefore should be returned by the storage.
    48  		// Range vectors `bar1{baz="blip"}[1m]` are not tested here because it is not supported
    49  		// by range queries.
    50  		{
    51  			`bar1{baz="blip"}`,
    52  			`label_replace(
    53  				bar1{__cortex_shard__="0_of_3",baz="blip"} or
    54  				bar1{__cortex_shard__="1_of_3",baz="blip"} or
    55  				bar1{__cortex_shard__="2_of_3",baz="blip"},
    56  				"__cortex_shard__","","",""
    57  			)`,
    58  			true,
    59  		},
    60  		// __cortex_shard__ label is required otherwise the or will keep only the first series.
    61  		{
    62  			`sum(bar1{baz="blip"})`,
    63  			`sum(
    64  				sum (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
    65  				sum (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
    66  				sum (bar1{__cortex_shard__="2_of_3",baz="blip"})
    67  			  )`,
    68  			false,
    69  		},
    70  		{
    71  			`sum(bar1{baz="blip"})`,
    72  			`sum(
    73  				sum without(__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
    74  				sum without(__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
    75  				sum without(__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
    76  			  )`,
    77  			true,
    78  		},
    79  		{
    80  			`sum by (foo) (bar1{baz="blip"})`,
    81  			`sum by (foo) (
    82  				sum by(foo,__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
    83  				sum by(foo,__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
    84  				sum by(foo,__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
    85  			  )`,
    86  			true,
    87  		},
    88  		{
    89  			`sum by (foo,bar) (bar1{baz="blip"})`,
    90  			`sum by (foo,bar)(
    91  				sum by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
    92  				sum by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
    93  				sum by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
    94  			  )`,
    95  			true,
    96  		},
    97  		// since series are unique to a shard, it's safe to sum without shard first, then reaggregate
    98  		{
    99  			`sum without (foo,bar) (bar1{baz="blip"})`,
   100  			`sum without (foo,bar)(
   101  				sum without(__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   102  				sum without(__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   103  				sum without(__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   104  			  )`,
   105  			true,
   106  		},
   107  		{
   108  			`min by (foo,bar) (bar1{baz="blip"})`,
   109  			`min by (foo,bar)(
   110  				min by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   111  				min by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   112  				min by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   113  			  )`,
   114  			true,
   115  		},
   116  		{
   117  			`max by (foo,bar) (bar1{baz="blip"})`,
   118  			` max by (foo,bar)(
   119  				max by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   120  				max by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   121  				max by(foo,bar,__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   122  			  )`,
   123  			true,
   124  		},
   125  		// avg generally cant be parallelized
   126  		{
   127  			`avg(bar1{baz="blip"})`,
   128  			`avg(
   129  				avg by(__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   130  				avg by(__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   131  				avg by(__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   132  			  )`,
   133  			false,
   134  		},
   135  		// stddev can't be parallelized.
   136  		{
   137  			`stddev(bar1{baz="blip"})`,
   138  			` stddev(
   139  				stddev by(__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   140  				stddev by(__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   141  				stddev by(__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   142  			  )`,
   143  			false,
   144  		},
   145  		// stdvar can't be parallelized.
   146  		{
   147  			`stdvar(bar1{baz="blip"})`,
   148  			`stdvar(
   149  				stdvar by(__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   150  				stdvar by(__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   151  				stdvar by(__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   152  			  )`,
   153  			false,
   154  		},
   155  		{
   156  			`count(bar1{baz="blip"})`,
   157  			`count(
   158  				count without (__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   159  				count without (__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   160  				count without (__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   161  				)`,
   162  			true,
   163  		},
   164  		{
   165  			`count by (foo,bar) (bar1{baz="blip"})`,
   166  			`count by (foo,bar) (
   167  				count by (foo,bar,__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   168  				count by (foo,bar,__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   169  				count by (foo,bar,__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   170  			)`,
   171  			true,
   172  		},
   173  		// different ways to represent count without.
   174  		{
   175  			`count without (foo) (bar1{baz="blip"})`,
   176  			`count without (foo) (
   177  				count without (__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   178  				count without (__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   179  				count without (__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   180  			)`,
   181  			true,
   182  		},
   183  		{
   184  			`count without (foo) (bar1{baz="blip"})`,
   185  			`sum without (__cortex_shard__) (
   186  				count without (foo) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   187  				count without (foo) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   188  				count without (foo) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   189  			)`,
   190  			true,
   191  		},
   192  		{
   193  			`count without (foo, bar) (bar1{baz="blip"})`,
   194  			`count without (foo, bar) (
   195  				count without (__cortex_shard__) (bar1{__cortex_shard__="0_of_3",baz="blip"}) or
   196  				count without (__cortex_shard__) (bar1{__cortex_shard__="1_of_3",baz="blip"}) or
   197  				count without (__cortex_shard__) (bar1{__cortex_shard__="2_of_3",baz="blip"})
   198  			)`,
   199  			true,
   200  		},
   201  		{
   202  			`topk(2,bar1{baz="blip"})`,
   203  			`label_replace(
   204  				topk(2,
   205  					topk(2,(bar1{__cortex_shard__="0_of_3",baz="blip"})) without(__cortex_shard__) or
   206  					topk(2,(bar1{__cortex_shard__="1_of_3",baz="blip"})) without(__cortex_shard__) or
   207  					topk(2,(bar1{__cortex_shard__="2_of_3",baz="blip"})) without(__cortex_shard__)
   208  				),
   209                            "__cortex_shard__","","","")`,
   210  			true,
   211  		},
   212  		{
   213  			`bottomk(2,bar1{baz="blip"})`,
   214  			`label_replace(
   215  				bottomk(2,
   216  					bottomk(2,(bar1{__cortex_shard__="0_of_3",baz="blip"})) without(__cortex_shard__) or
   217  					bottomk(2,(bar1{__cortex_shard__="1_of_3",baz="blip"})) without(__cortex_shard__) or
   218  					bottomk(2,(bar1{__cortex_shard__="2_of_3",baz="blip"})) without(__cortex_shard__)
   219  				),
   220                            "__cortex_shard__","","","")`,
   221  			true,
   222  		},
   223  		{
   224  			`sum by (foo,bar) (avg_over_time(bar1{baz="blip"}[1m]))`,
   225  			`sum by (foo,bar)(
   226  				sum by(foo,bar,__cortex_shard__) (avg_over_time(bar1{__cortex_shard__="0_of_3",baz="blip"}[1m])) or
   227  				sum by(foo,bar,__cortex_shard__) (avg_over_time(bar1{__cortex_shard__="1_of_3",baz="blip"}[1m])) or
   228  				sum by(foo,bar,__cortex_shard__) (avg_over_time(bar1{__cortex_shard__="2_of_3",baz="blip"}[1m]))
   229  			  )`,
   230  			true,
   231  		},
   232  		{
   233  			`sum by (foo,bar) (min_over_time(bar1{baz="blip"}[1m]))`,
   234  			`sum by (foo,bar)(
   235  				sum by(foo,bar,__cortex_shard__) (min_over_time(bar1{__cortex_shard__="0_of_3",baz="blip"}[1m])) or
   236  				sum by(foo,bar,__cortex_shard__) (min_over_time(bar1{__cortex_shard__="1_of_3",baz="blip"}[1m])) or
   237  				sum by(foo,bar,__cortex_shard__) (min_over_time(bar1{__cortex_shard__="2_of_3",baz="blip"}[1m]))
   238  			  )`,
   239  			true,
   240  		},
   241  		{
   242  			// Sub aggregations must avoid non-associative series merging across shards
   243  			`sum(
   244  			  count(
   245  			    bar1
   246  			  )  by (foo,bazz)
   247  			)`,
   248  			`
   249  			  sum without(__cortex_shard__) (
   250  			    sum by(__cortex_shard__) (
   251  			      count by(foo, bazz) (foo{__cortex_shard__="0_of_2",bar="baz"})
   252  			    ) or
   253  			    sum by(__cortex_shard__) (
   254  			      count by(foo, bazz) (foo{__cortex_shard__="1_of_2",bar="baz"})
   255  			    )
   256  			  )
   257  `,
   258  			false,
   259  		},
   260  		{
   261  			// Note: this is a speculative optimization that we don't currently include due to mapping complexity.
   262  			// Certain sub aggregations may inject __cortex_shard__ for all (by) subgroupings.
   263  			// This is the same as the previous test with the exception that the shard label is injected to the count grouping
   264  			`sum(
   265  			  count(
   266  			    bar1
   267  			  )  by (foo,bazz)
   268  			)`,
   269  			`
   270  			  sum without(__cortex_shard__) (
   271  			    sum by(__cortex_shard__) (
   272  			      count by(foo, bazz, __cortex_shard__) (foo{__cortex_shard__="0_of_2",bar="baz"})
   273  			    ) or
   274  			    sum by(__cortex_shard__) (
   275  			      count by(foo, bazz, __cortex_shard__) (foo{__cortex_shard__="1_of_2",bar="baz"})
   276  			    )
   277  			  )
   278  `,
   279  			true,
   280  		},
   281  		{
   282  			// Note: this is a speculative optimization that we don't currently include due to mapping complexity
   283  			// This example details multiple layers of aggregations.
   284  			// Sub aggregations must inject __cortex_shard__ for all (by) subgroupings.
   285  			`sum(
   286  			  count(
   287  			    count(
   288  			      bar1
   289  			    )  by (foo,bazz)
   290  			  )  by (bazz)
   291  			)`,
   292  			`
   293  			  sum without(__cortex_shard__) (
   294  			    sum by(__cortex_shard__) (
   295  			      count by(bazz, __cortex_shard__) (
   296  				count by(foo, bazz, __cortex_shard__) (
   297  				  foo{__cortex_shard__="0_of_2", bar="baz"}
   298  				)
   299  			      )
   300  			    ) or
   301  			    sum by(__cortex_shard__) (
   302  			      count by(bazz, __cortex_shard__) (
   303  				count by(foo, bazz, __cortex_shard__) (
   304  				  foo{__cortex_shard__="1_of_2", bar="baz"}
   305  				)
   306  			      )
   307  			    )
   308  			  )
   309  `,
   310  			true,
   311  		},
   312  	}
   313  
   314  	for _, tt := range tests {
   315  		tt := tt
   316  		t.Run(tt.normalQuery, func(t *testing.T) {
   317  
   318  			baseQuery, err := engine.NewRangeQuery(shardAwareQueryable, nil, tt.normalQuery, start, end, step)
   319  			require.Nil(t, err)
   320  			shardQuery, err := engine.NewRangeQuery(shardAwareQueryable, nil, tt.shardQuery, start, end, step)
   321  			require.Nil(t, err)
   322  			baseResult := baseQuery.Exec(ctx)
   323  			shardResult := shardQuery.Exec(ctx)
   324  			t.Logf("base: %v\n", baseResult)
   325  			t.Logf("shard: %v\n", shardResult)
   326  			if tt.shouldEqual {
   327  				require.Equal(t, baseResult, shardResult)
   328  				return
   329  			}
   330  			require.NotEqual(t, baseResult, shardResult)
   331  		})
   332  	}
   333  
   334  }
   335  
   336  func Test_FunctionParallelism(t *testing.T) {
   337  	tpl := `sum(<fn>(bar1{}<fArgs>))`
   338  	shardTpl := `sum(
   339  				sum without(__cortex_shard__) (<fn>(bar1{__cortex_shard__="0_of_3"}<fArgs>)) or
   340  				sum without(__cortex_shard__) (<fn>(bar1{__cortex_shard__="1_of_3"}<fArgs>)) or
   341  				sum without(__cortex_shard__) (<fn>(bar1{__cortex_shard__="2_of_3"}<fArgs>))
   342  			  )`
   343  
   344  	mkQuery := func(tpl, fn string, testMatrix bool, fArgs []string) (result string) {
   345  		result = strings.Replace(tpl, "<fn>", fn, -1)
   346  
   347  		if testMatrix {
   348  			// turn selectors into ranges
   349  			result = strings.Replace(result, "}<fArgs>", "}[1m]<fArgs>", -1)
   350  		}
   351  
   352  		if len(fArgs) > 0 {
   353  			args := "," + strings.Join(fArgs, ",")
   354  			result = strings.Replace(result, "<fArgs>", args, -1)
   355  		} else {
   356  			result = strings.Replace(result, "<fArgs>", "", -1)
   357  		}
   358  
   359  		return result
   360  	}
   361  
   362  	for _, tc := range []struct {
   363  		fn           string
   364  		fArgs        []string
   365  		isTestMatrix bool
   366  		approximate  bool
   367  	}{
   368  		{
   369  			fn: "abs",
   370  		},
   371  		{
   372  			fn:           "avg_over_time",
   373  			isTestMatrix: true,
   374  			approximate:  true,
   375  		},
   376  		{
   377  			fn: "ceil",
   378  		},
   379  		{
   380  			fn:           "changes",
   381  			isTestMatrix: true,
   382  		},
   383  		{
   384  			fn:           "count_over_time",
   385  			isTestMatrix: true,
   386  		},
   387  		{
   388  			fn: "days_in_month",
   389  		},
   390  		{
   391  			fn: "day_of_month",
   392  		},
   393  		{
   394  			fn: "day_of_week",
   395  		},
   396  		{
   397  			fn:           "delta",
   398  			isTestMatrix: true,
   399  			approximate:  true,
   400  		},
   401  		{
   402  			fn:           "deriv",
   403  			isTestMatrix: true,
   404  			approximate:  true,
   405  		},
   406  		{
   407  			fn:          "exp",
   408  			approximate: true,
   409  		},
   410  		{
   411  			fn: "floor",
   412  		},
   413  		{
   414  			fn: "hour",
   415  		},
   416  		{
   417  			fn:           "idelta",
   418  			isTestMatrix: true,
   419  			approximate:  true,
   420  		},
   421  		{
   422  			fn:           "increase",
   423  			isTestMatrix: true,
   424  			approximate:  true,
   425  		},
   426  		{
   427  			fn:           "irate",
   428  			isTestMatrix: true,
   429  			approximate:  true,
   430  		},
   431  		{
   432  			fn:          "ln",
   433  			approximate: true,
   434  		},
   435  		{
   436  			fn:          "log10",
   437  			approximate: true,
   438  		},
   439  		{
   440  			fn:          "log2",
   441  			approximate: true,
   442  		},
   443  		{
   444  			fn:           "max_over_time",
   445  			isTestMatrix: true,
   446  		},
   447  		{
   448  			fn:           "min_over_time",
   449  			isTestMatrix: true,
   450  		},
   451  		{
   452  			fn: "minute",
   453  		},
   454  		{
   455  			fn: "month",
   456  		},
   457  		{
   458  			fn:           "rate",
   459  			isTestMatrix: true,
   460  			approximate:  true,
   461  		},
   462  		{
   463  			fn:           "resets",
   464  			isTestMatrix: true,
   465  		},
   466  		{
   467  			fn: "sort",
   468  		},
   469  		{
   470  			fn: "sort_desc",
   471  		},
   472  		{
   473  			fn:          "sqrt",
   474  			approximate: true,
   475  		},
   476  		{
   477  			fn:           "stddev_over_time",
   478  			isTestMatrix: true,
   479  			approximate:  true,
   480  		},
   481  		{
   482  			fn:           "stdvar_over_time",
   483  			isTestMatrix: true,
   484  			approximate:  true,
   485  		},
   486  		{
   487  			fn:           "sum_over_time",
   488  			isTestMatrix: true,
   489  		},
   490  		{
   491  			fn: "timestamp",
   492  		},
   493  		{
   494  			fn: "year",
   495  		},
   496  		{
   497  			fn:    "clamp_max",
   498  			fArgs: []string{"5"},
   499  		},
   500  		{
   501  			fn:    "clamp_min",
   502  			fArgs: []string{"5"},
   503  		},
   504  		{
   505  			fn:           "predict_linear",
   506  			isTestMatrix: true,
   507  			approximate:  true,
   508  			fArgs:        []string{"1"},
   509  		},
   510  		{
   511  			fn:    "round",
   512  			fArgs: []string{"20"},
   513  		},
   514  		{
   515  			fn:           "holt_winters",
   516  			isTestMatrix: true,
   517  			fArgs:        []string{"0.5", "0.7"},
   518  			approximate:  true,
   519  		},
   520  	} {
   521  
   522  		t.Run(tc.fn, func(t *testing.T) {
   523  			baseQuery, err := engine.NewRangeQuery(
   524  				shardAwareQueryable,
   525  				nil,
   526  				mkQuery(tpl, tc.fn, tc.isTestMatrix, tc.fArgs),
   527  				start,
   528  				end,
   529  				step,
   530  			)
   531  			require.Nil(t, err)
   532  			shardQuery, err := engine.NewRangeQuery(
   533  				shardAwareQueryable,
   534  				nil,
   535  				mkQuery(shardTpl, tc.fn, tc.isTestMatrix, tc.fArgs),
   536  				start,
   537  				end,
   538  				step,
   539  			)
   540  			require.Nil(t, err)
   541  			baseResult := baseQuery.Exec(ctx)
   542  			shardResult := shardQuery.Exec(ctx)
   543  			t.Logf("base: %+v\n", baseResult)
   544  			t.Logf("shard: %+v\n", shardResult)
   545  			if !tc.approximate {
   546  				require.Equal(t, baseResult, shardResult)
   547  			} else {
   548  				// Some functions yield tiny differences when sharded due to combining floating point calculations.
   549  				baseSeries := baseResult.Value.(promql.Matrix)[0]
   550  				shardSeries := shardResult.Value.(promql.Matrix)[0]
   551  
   552  				require.Equal(t, len(baseSeries.Points), len(shardSeries.Points))
   553  				for i, basePt := range baseSeries.Points {
   554  					shardPt := shardSeries.Points[i]
   555  					require.Equal(t, basePt.T, shardPt.T)
   556  					require.Equal(
   557  						t,
   558  						math.Round(basePt.V*1e6)/1e6,
   559  						math.Round(shardPt.V*1e6)/1e6,
   560  					)
   561  				}
   562  
   563  			}
   564  		})
   565  	}
   566  
   567  }
   568  
   569  var shardAwareQueryable = storage.QueryableFunc(func(ctx context.Context, mint, maxt int64) (storage.Querier, error) {
   570  	return &testMatrix{
   571  		series: []*promql.StorageSeries{
   572  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blop"}, {Name: "foo", Value: "barr"}}, factor(5)),
   573  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blop"}, {Name: "foo", Value: "bazz"}}, factor(7)),
   574  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blap"}, {Name: "foo", Value: "buzz"}}, factor(12)),
   575  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blap"}, {Name: "foo", Value: "bozz"}}, factor(11)),
   576  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blop"}, {Name: "foo", Value: "buzz"}}, factor(8)),
   577  			newSeries(labels.Labels{{Name: "__name__", Value: "bar1"}, {Name: "baz", Value: "blip"}, {Name: "bar", Value: "blap"}, {Name: "foo", Value: "bazz"}}, identity),
   578  		},
   579  	}, nil
   580  })
   581  
   582  type testMatrix struct {
   583  	series []*promql.StorageSeries
   584  }
   585  
   586  func (m *testMatrix) Copy() *testMatrix {
   587  	cpy := *m
   588  	return &cpy
   589  }
   590  
   591  func (m testMatrix) Next() bool { return len(m.series) != 0 }
   592  
   593  func (m *testMatrix) At() storage.Series {
   594  	res := m.series[0]
   595  	m.series = m.series[1:]
   596  	return res
   597  }
   598  
   599  func (m *testMatrix) Err() error { return nil }
   600  
   601  func (m *testMatrix) Warnings() storage.Warnings { return nil }
   602  
   603  func (m *testMatrix) Select(_ bool, selectParams *storage.SelectHints, matchers ...*labels.Matcher) storage.SeriesSet {
   604  	s, _, err := astmapper.ShardFromMatchers(matchers)
   605  	if err != nil {
   606  		return storage.ErrSeriesSet(err)
   607  	}
   608  
   609  	if s != nil {
   610  		return splitByShard(s.Shard, s.Of, m)
   611  	}
   612  
   613  	return m.Copy()
   614  }
   615  
   616  func (m *testMatrix) LabelValues(name string, matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
   617  	return nil, nil, nil
   618  }
   619  func (m *testMatrix) LabelNames(matchers ...*labels.Matcher) ([]string, storage.Warnings, error) {
   620  	return nil, nil, nil
   621  }
   622  func (m *testMatrix) Close() error { return nil }
   623  
   624  func newSeries(metric labels.Labels, generator func(float64) float64) *promql.StorageSeries {
   625  	sort.Sort(metric)
   626  	var points []promql.Point
   627  
   628  	for ts := start.Add(-step); ts.Unix() <= end.Unix(); ts = ts.Add(step) {
   629  		t := ts.Unix() * 1e3
   630  		points = append(points, promql.Point{
   631  			T: t,
   632  			V: generator(float64(t)),
   633  		})
   634  	}
   635  
   636  	return promql.NewStorageSeries(promql.Series{
   637  		Metric: metric,
   638  		Points: points,
   639  	})
   640  }
   641  
   642  func identity(t float64) float64 {
   643  	return t
   644  }
   645  
   646  func factor(f float64) func(float64) float64 {
   647  	i := 0.
   648  	return func(float64) float64 {
   649  		i++
   650  		res := i * f
   651  		return res
   652  	}
   653  }
   654  
   655  // var identity(t int64) float64 {
   656  // 	return float64(t)
   657  // }
   658  
   659  // splitByShard returns the shard subset of a testMatrix.
   660  // e.g if a testMatrix has 6 series, and we want 3 shard, then each shard will contain
   661  // 2 series.
   662  func splitByShard(shardIndex, shardTotal int, testMatrices *testMatrix) *testMatrix {
   663  	res := &testMatrix{}
   664  	for i, s := range testMatrices.series {
   665  		if i%shardTotal != shardIndex {
   666  			continue
   667  		}
   668  		var points []promql.Point
   669  		it := s.Iterator()
   670  		for it.Next() {
   671  			t, v := it.At()
   672  			points = append(points, promql.Point{
   673  				T: t,
   674  				V: v,
   675  			})
   676  
   677  		}
   678  		lbs := s.Labels().Copy()
   679  		lbs = append(lbs, labels.Label{Name: "__cortex_shard__", Value: fmt.Sprintf("%d_of_%d", shardIndex, shardTotal)})
   680  		sort.Sort(lbs)
   681  		res.series = append(res.series, promql.NewStorageSeries(promql.Series{
   682  			Metric: lbs,
   683  			Points: points,
   684  		}))
   685  	}
   686  	return res
   687  }