github.com/go-graphite/carbonapi@v0.17.0/expr/functions/moving/function_test.go (about)

     1  package moving
     2  
     3  import (
     4  	"context"
     5  	"math"
     6  	"strconv"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/go-graphite/carbonapi/expr/interfaces"
    11  	"github.com/go-graphite/carbonapi/expr/metadata"
    12  	"github.com/go-graphite/carbonapi/expr/types"
    13  	"github.com/go-graphite/carbonapi/pkg/parser"
    14  	th "github.com/go-graphite/carbonapi/tests"
    15  	"github.com/go-graphite/carbonapi/tests/compare"
    16  )
    17  
    18  var (
    19  	md []interfaces.FunctionMetadata = New("")
    20  )
    21  
    22  func init() {
    23  	for _, m := range md {
    24  		metadata.RegisterFunction(m.Name, m.F)
    25  	}
    26  }
    27  
    28  // Note: some of these tests are influenced by the testcases for moving* functions
    29  // in Graphite-web. See: https://github.com/graphite-project/graphite-web/blob/master/webapp/tests/test_functions.py
    30  func TestMoving(t *testing.T) {
    31  	tests := []th.EvalTestItemWithRange{
    32  		{
    33  			Target: "movingAverage(metric1,10)",
    34  			M: map[parser.MetricRequest][]*types.MetricData{
    35  				{Metric: "metric1", From: 20, Until: 25}: {types.MakeMetricData("metric1", th.GenerateValues(10, 25, 1), 1, 20)},
    36  				{Metric: "metric1", From: 10, Until: 25}: {types.MakeMetricData("metric1", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, 10)},
    37  			},
    38  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,10)`,
    39  				[]float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, 20).SetTag("movingAverage", "10").SetNameTag(`metric1`)},
    40  			From:  20,
    41  			Until: 25,
    42  		},
    43  		{
    44  			Target: "movingAverage(metric1,10)",
    45  			M: map[parser.MetricRequest][]*types.MetricData{
    46  				{Metric: "metric1", From: 20, Until: 30}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 20)},
    47  				{Metric: "metric1", From: 10, Until: 30}: {types.MakeMetricData("metric1", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 1, 10)},
    48  			},
    49  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,10)`,
    50  				[]float64{0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5}, 1, 20).SetTag("movingAverage", "10").SetNameTag(`metric1`)},
    51  			From:  20,
    52  			Until: 30,
    53  		},
    54  		{
    55  			Target: "movingAverage(metric1,60)",
    56  			M: map[parser.MetricRequest][]*types.MetricData{
    57  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 610)},
    58  				{Metric: "metric1", From: 550, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(0, 100, 1), 1, 600)},
    59  			},
    60  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,60)`,
    61  				[]float64{30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5}, 1, 660).SetTag("movingAverage", "60").SetNameTag(`metric1`)},
    62  			From:  610,
    63  			Until: 710,
    64  		},
    65  		{
    66  			Target: "movingAverage(metric1,'-1min')",
    67  			M: map[parser.MetricRequest][]*types.MetricData{
    68  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 610)},
    69  				{Metric: "metric1", From: 550, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(0, 100, 1), 1, 600)},
    70  			},
    71  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,'-1min')`,
    72  				[]float64{30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5}, 1, 660).SetTag("movingAverage", "'-1min'").SetNameTag(`metric1`)},
    73  			From:  610,
    74  			Until: 710,
    75  		},
    76  		{
    77  			Target: "movingMedian(metric1,10)",
    78  			M: map[parser.MetricRequest][]*types.MetricData{
    79  				{Metric: "metric1", From: 20, Until: 30}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 20)},
    80  				{Metric: "metric1", From: 10, Until: 30}: {types.MakeMetricData("metric1", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, 1, 10)},
    81  			},
    82  			Want: []*types.MetricData{types.MakeMetricData(`movingMedian(metric1,10)`,
    83  				[]float64{0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5}, 1, 20).SetTag("movingMedian", "10").SetNameTag(`metric1`)},
    84  			From:  20,
    85  			Until: 30,
    86  		},
    87  		{
    88  			Target: "movingMedian(metric1,10)",
    89  			M: map[parser.MetricRequest][]*types.MetricData{
    90  				{Metric: "metric1", From: 20, Until: 25}: {types.MakeMetricData("metric1", th.GenerateValues(10, 25, 1), 1, 20)},
    91  				{Metric: "metric1", From: 10, Until: 25}: {types.MakeMetricData("metric1", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, 10)},
    92  			},
    93  			Want: []*types.MetricData{types.MakeMetricData(`movingMedian(metric1,10)`,
    94  				[]float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, 20).SetTag("movingMedian", "10").SetNameTag(`metric1`)},
    95  			From:  20,
    96  			Until: 25,
    97  		},
    98  		{
    99  			Target: "movingMedian(metric1,60)",
   100  			M: map[parser.MetricRequest][]*types.MetricData{
   101  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 610)},
   102  				{Metric: "metric1", From: 550, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(0, 100, 1), 1, 600)},
   103  			},
   104  			Want: []*types.MetricData{types.MakeMetricData(`movingMedian(metric1,60)`,
   105  				[]float64{30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5}, 1, 660).SetTag("movingMedian", "60").SetNameTag(`metric1`)},
   106  			From:  610,
   107  			Until: 710,
   108  		},
   109  		{
   110  			Target: "movingMedian(metric1,'1min')",
   111  			M: map[parser.MetricRequest][]*types.MetricData{
   112  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 610)},
   113  				{Metric: "metric1", From: 550, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(0, 100, 1), 1, 600)},
   114  			},
   115  			Want: []*types.MetricData{types.MakeMetricData(`movingMedian(metric1,'1min')`,
   116  				[]float64{30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5}, 1, 660).SetTag("movingMedian", "'1min'").SetNameTag(`metric1`)},
   117  			From:  610,
   118  			Until: 710,
   119  		},
   120  		{
   121  			Target: "movingMedian(metric1,'-1min')",
   122  			M: map[parser.MetricRequest][]*types.MetricData{
   123  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(10, 110, 1), 1, 610)},
   124  				{Metric: "metric1", From: 550, Until: 710}: {types.MakeMetricData("metric1", th.GenerateValues(0, 100, 1), 1, 600)},
   125  			},
   126  			Want: []*types.MetricData{types.MakeMetricData(`movingMedian(metric1,'-1min')`,
   127  				[]float64{30.5, 31.5, 32.5, 33.5, 34.5, 35.5, 36.5, 37.5, 38.5, 39.5, 40.5, 41.5, 42.5, 43.5, 44.5, 45.5, 46.5, 47.5, 48.5, 49.5, 50.5, 51.5, 52.5, 53.5, 54.5, 55.5, 56.5, 57.5, 58.5, 59.5, 60.5, 61.5, 62.5, 63.5, 64.5, 65.5, 66.5, 67.5, 68.5, 69.5}, 1, 660).SetTag("movingMedian", "'-1min'").SetNameTag(`metric1`)},
   128  			From:  610,
   129  			Until: 710,
   130  		},
   131  		{
   132  			Target: "movingWindow(metric1,'3sec','average')",
   133  			M: map[parser.MetricRequest][]*types.MetricData{
   134  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 610)},
   135  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 607)},
   136  			},
   137  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   138  				[]float64{2, 2, 2}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)},
   139  			From:  610,
   140  			Until: 710,
   141  		},
   142  		{
   143  			Target: "movingWindow(metric1,'3sec','avg_zero')",
   144  			M: map[parser.MetricRequest][]*types.MetricData{
   145  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, math.NaN(), 1, math.NaN(), 3}, 1, 610)},
   146  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, math.NaN(), 1, math.NaN(), 3}, 1, 607)},
   147  			},
   148  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   149  				[]float64{1, 0.3333333333333333, 1.3333333333333333}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)},
   150  			From:  610,
   151  			Until: 710,
   152  		},
   153  		{
   154  			Target: "movingWindow(metric1,'3sec','count')",
   155  			M: map[parser.MetricRequest][]*types.MetricData{
   156  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, math.NaN(), 1, math.NaN(), 3}, 1, 610)},
   157  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, math.NaN(), 1, math.NaN(), 3}, 1, 607)},
   158  			},
   159  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   160  				[]float64{2, 1, 2}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)},
   161  			From:  610,
   162  			Until: 710,
   163  		},
   164  		{
   165  			Target: "movingWindow(metric1,'3sec','diff')",
   166  			M: map[parser.MetricRequest][]*types.MetricData{
   167  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 610)},
   168  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 607)},
   169  			},
   170  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   171  				[]float64{-1, 3, -5}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)},
   172  			From:  610,
   173  			Until: 710,
   174  		},
   175  		{
   176  			Target: "movingWindow(metric1,'3sec','range')",
   177  			M: map[parser.MetricRequest][]*types.MetricData{
   178  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 610)},
   179  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 607)},
   180  			},
   181  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   182  				[]float64{3, 3, 5}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)},
   183  			From:  610,
   184  			Until: 710,
   185  		},
   186  		{
   187  			Target: "movingWindow(metric1,'3sec','stddev')",
   188  			M: map[parser.MetricRequest][]*types.MetricData{
   189  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 610)},
   190  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 607)},
   191  			},
   192  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   193  				[]float64{1.247219128924647, 1.5, 2.5}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)}, // StartTime = from
   194  			From:  610,
   195  			Until: 710,
   196  		},
   197  		{
   198  			Target: "movingWindow(metric1,'3sec','last')",
   199  			M: map[parser.MetricRequest][]*types.MetricData{
   200  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 610)},
   201  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 0, math.NaN(), 5}, 1, 607)},
   202  			},
   203  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   204  				[]float64{0, math.NaN(), 5}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)}, // StartTime = from
   205  			From:  610,
   206  			Until: 710,
   207  		},
   208  		{
   209  			Target: "movingWindow(metric1,'3sec')",
   210  			M: map[parser.MetricRequest][]*types.MetricData{
   211  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 610)},
   212  				{Metric: "metric1", From: 607, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 607)},
   213  			},
   214  			Want: []*types.MetricData{types.MakeMetricData(`movingWindow(metric1,'3sec')`,
   215  				[]float64{2, 2, 2}, 1, 610).SetTag("movingWindow", "'3sec'").SetNameTag(`metric1`)}, // StartTime = from
   216  			From:  610,
   217  			Until: 710,
   218  		},
   219  		{
   220  			Target: "movingAverage(metric1,4)",
   221  			M: map[parser.MetricRequest][]*types.MetricData{
   222  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 1, 1, 1, 2, 2, 2, 4, 6, 4, 6, 8}, 1, 610)},
   223  				{Metric: "metric1", From: 606, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 1, 1, 1, 2, 2, 2, 4, 6, 4, 6, 8}, 1, 606)},
   224  			},
   225  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,4)`,
   226  				[]float64{1.25, 1.5, 1.75, 2.5, 3.5, 4.0, 5.0, 6.0}, 1, 610).SetTag("movingAverage", "4").SetNameTag(`metric1`)}, // StartTime = from
   227  			From:  610,
   228  			Until: 710,
   229  		},
   230  		{
   231  			Target: "movingAverage(metric1,'5s')",
   232  			M: map[parser.MetricRequest][]*types.MetricData{
   233  				{Metric: "metric1", From: 610, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3}, 10, 610)}, // step > windowSize
   234  				{Metric: "metric1", From: 605, Until: 710}: {types.MakeMetricData("metric1", []float64{1, 2, 3}, 10, 605)},
   235  			},
   236  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,'5s')`,
   237  				[]float64{math.NaN(), math.NaN(), math.NaN()}, 10, 610).SetTag("movingAverage", "'5s'").SetNameTag(`metric1`)}, // StartTime = from
   238  			From:  610,
   239  			Until: 710,
   240  		},
   241  		{
   242  			Target: "movingAverage(metric1,10)",
   243  			M: map[parser.MetricRequest][]*types.MetricData{
   244  				{Metric: "metric1", From: 610, Until: 700}: {types.MakeMetricData("metric1", []float64{1, 2, 3}, 30, 610)}, // step > windowSize
   245  				{Metric: "metric1", From: 310, Until: 700}: {types.MakeMetricData("metric1", []float64{1, 2, 3}, 30, 310)},
   246  			},
   247  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,10)`,
   248  				[]float64{}, 30, 610).SetTag("movingAverage", "10").SetNameTag(`metric1`)},
   249  			From:  610,
   250  			Until: 700,
   251  		},
   252  	}
   253  
   254  	for n, tt := range tests {
   255  		testName := tt.Target
   256  		t.Run(testName+"#"+strconv.Itoa(n), func(t *testing.T) {
   257  			eval := th.EvaluatorFromFunc(md[0].F)
   258  			th.TestEvalExprWithRange(t, eval, &tt)
   259  		})
   260  	}
   261  }
   262  
   263  func TestMovingXFilesFactor(t *testing.T) {
   264  	tests := []th.EvalTestItemWithRange{
   265  		{
   266  			Target: "movingSum(metric1,'3sec',0.5)",
   267  			M: map[parser.MetricRequest][]*types.MetricData{
   268  				{Metric: "metric1", From: 610, Until: 618}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, math.NaN(), 2, math.NaN(), 3}, 1, 610)},
   269  				{Metric: "metric1", From: 607, Until: 618}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, math.NaN(), 2, math.NaN(), 3}, 1, 607)},
   270  			},
   271  			Want: []*types.MetricData{types.MakeMetricData(`movingSum(metric1,'3sec')`,
   272  				[]float64{6, 4, 3, math.NaN(), 5}, 1, 610).SetTag("movingSum", "'3sec'").SetNameTag(`metric1`)},
   273  			From:  610,
   274  			Until: 618,
   275  		},
   276  		{
   277  			Target: "movingAverage(metric1,4,0.6)",
   278  			M: map[parser.MetricRequest][]*types.MetricData{
   279  				{Metric: "metric1", From: 610, Until: 622}: {types.MakeMetricData("metric1", []float64{1, 1, 1, 1, 2, math.NaN(), 2, 4, math.NaN(), 4, 6, 8}, 1, 610)},
   280  				{Metric: "metric1", From: 606, Until: 622}: {types.MakeMetricData("metric1", []float64{1, 1, 1, 1, 2, math.NaN(), 2, 4, math.NaN(), 4, 6, 8}, 1, 606)},
   281  			},
   282  			Want: []*types.MetricData{types.MakeMetricData(`movingAverage(metric1,4)`,
   283  				[]float64{1.25, 1.3333333333333333, 1.6666666666666667, 2.6666666666666665, math.NaN(), 3.3333333333333335, 4.666666666666667, 6}, 1, 610).SetTag("movingAverage", "4").SetNameTag(`metric1`)},
   284  			From:  610,
   285  			Until: 622,
   286  		},
   287  		{
   288  			Target: "movingMax(metric1,2,0.5)",
   289  			M: map[parser.MetricRequest][]*types.MetricData{
   290  				{Metric: "metric1", From: 610, Until: 616}: {types.MakeMetricData("metric1", []float64{1, 2, 3, math.NaN(), math.NaN(), 0}, 1, 610)},
   291  				{Metric: "metric1", From: 608, Until: 616}: {types.MakeMetricData("metric1", []float64{1, 2, 3, math.NaN(), math.NaN(), 0}, 1, 608)},
   292  			},
   293  			Want: []*types.MetricData{types.MakeMetricData(`movingMax(metric1,2)`,
   294  				[]float64{3, 3, math.NaN(), 0}, 1, 610).SetTag("movingMax", "2").SetNameTag(`metric1`)},
   295  			From:  610,
   296  			Until: 616,
   297  		},
   298  	}
   299  
   300  	for n, tt := range tests {
   301  		testName := tt.Target
   302  		t.Run(testName+"#"+strconv.Itoa(n), func(t *testing.T) {
   303  			eval := th.EvaluatorFromFunc(md[0].F)
   304  			th.TestEvalExprWithRange(t, eval, &tt)
   305  		})
   306  	}
   307  }
   308  
   309  func TestMovingError(t *testing.T) {
   310  	now32 := int64(time.Now().Unix())
   311  
   312  	tests := []th.EvalTestItemWithError{
   313  		{
   314  			Target: "movingWindow(metric1,'','average')",
   315  			M: map[parser.MetricRequest][]*types.MetricData{
   316  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 0)},
   317  			},
   318  			Error: parser.ErrBadType,
   319  		},
   320  		{
   321  			Target: "movingWindow(metric1,'-','average')",
   322  			M: map[parser.MetricRequest][]*types.MetricData{
   323  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 0)},
   324  			},
   325  			Error: parser.ErrBadType,
   326  		},
   327  		{
   328  			Target: "movingWindow(metric1,'+','average')",
   329  			M: map[parser.MetricRequest][]*types.MetricData{
   330  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, 0)},
   331  			},
   332  			Error: parser.ErrBadType,
   333  		},
   334  		{
   335  			Target: "movingWindow(metric1,'-s1','average')",
   336  			M: map[parser.MetricRequest][]*types.MetricData{
   337  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 1, 2, 3}, 1, now32)},
   338  			},
   339  			Error: parser.ErrBadType,
   340  		},
   341  	}
   342  
   343  	for n, tt := range tests {
   344  		testName := tt.Target
   345  		t.Run(testName+"#"+strconv.Itoa(n), func(t *testing.T) {
   346  			eval := th.EvaluatorFromFunc(md[0].F)
   347  			th.TestEvalExprWithError(t, eval, &tt)
   348  		})
   349  	}
   350  
   351  }
   352  
   353  func BenchmarkMoving(b *testing.B) {
   354  	benchmarks := []struct {
   355  		target string
   356  		M      map[parser.MetricRequest][]*types.MetricData
   357  	}{
   358  		{
   359  			target: "movingAverage(metric1,'5s')",
   360  			M: map[parser.MetricRequest][]*types.MetricData{
   361  				{Metric: "metric1", From: -5, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3}, 10, 1)}, // step > windowSize
   362  			},
   363  		},
   364  		{
   365  			target: "movingAverage(metric1,4)",
   366  			M: map[parser.MetricRequest][]*types.MetricData{
   367  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   368  			},
   369  		},
   370  		{
   371  			target: "movingAverage(metric1,2)",
   372  			M: map[parser.MetricRequest][]*types.MetricData{
   373  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   374  			},
   375  		},
   376  		{
   377  			target: "movingSum(metric1,2)",
   378  			M: map[parser.MetricRequest][]*types.MetricData{
   379  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   380  			},
   381  		},
   382  		{
   383  			target: "movingMin(metric1,2)",
   384  			M: map[parser.MetricRequest][]*types.MetricData{
   385  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   386  			},
   387  		},
   388  		{
   389  			target: "movingMax(metric1,2)",
   390  			M: map[parser.MetricRequest][]*types.MetricData{
   391  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   392  			},
   393  		},
   394  		{
   395  			target: "movingAverage(metric1,600)",
   396  			M: map[parser.MetricRequest][]*types.MetricData{
   397  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   398  			},
   399  		},
   400  		{
   401  			target: "movingSum(metric1,600)",
   402  			M: map[parser.MetricRequest][]*types.MetricData{
   403  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   404  			},
   405  		},
   406  		{
   407  			target: "movingMin(metric1,600)",
   408  			M: map[parser.MetricRequest][]*types.MetricData{
   409  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   410  			},
   411  		},
   412  		{
   413  			target: "movingMax(metric1,600)",
   414  			M: map[parser.MetricRequest][]*types.MetricData{
   415  				{Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", compare.GenerateMetrics(1024, 1.0, 9.0, 1.0), 1, 1)},
   416  			},
   417  		},
   418  	}
   419  
   420  	eval := th.EvaluatorFromFunc(md[0].F)
   421  
   422  	for _, bm := range benchmarks {
   423  		b.Run(bm.target, func(b *testing.B) {
   424  			exp, _, err := parser.ParseExpr(bm.target)
   425  			if err != nil {
   426  				b.Fatalf("failed to parse %s: %+v", bm.target, err)
   427  			}
   428  
   429  			b.ResetTimer()
   430  
   431  			for i := 0; i < b.N; i++ {
   432  				g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M)
   433  				if err != nil {
   434  					b.Fatalf("failed to eval %s: %+v", bm.target, err)
   435  				}
   436  				_ = g
   437  			}
   438  		})
   439  	}
   440  }