github.com/go-graphite/carbonapi@v0.17.0/pkg/parser/parser_test.go (about)

     1  package parser
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/stretchr/testify/assert"
     7  )
     8  
     9  func TestSkipWhitespace(t *testing.T) {
    10  	testCases := []struct{ in, expected string }{
    11  		{
    12  			in:       " ",
    13  			expected: "",
    14  		},
    15  		{
    16  			in:       " foo",
    17  			expected: "foo",
    18  		},
    19  		{
    20  			in:       " foo ",
    21  			expected: "foo ",
    22  		},
    23  		{
    24  			in:       "\nfoo",
    25  			expected: "foo",
    26  		},
    27  		{
    28  			in:       "\tfoo",
    29  			expected: "foo",
    30  		},
    31  	}
    32  
    33  	for _, tc := range testCases {
    34  		t.Run(tc.in, func(t *testing.T) {
    35  			out := skipWhitespace(tc.in)
    36  			assert.Equal(t, tc.expected, out)
    37  		})
    38  	}
    39  }
    40  
    41  func TestParseExpr(t *testing.T) {
    42  	tests := []struct {
    43  		s string
    44  		e *expr
    45  	}{
    46  		{"metric=",
    47  			&expr{target: "metric="},
    48  		},
    49  		{"metric",
    50  			&expr{target: "metric"},
    51  		},
    52  		{
    53  			"metric.foo",
    54  			&expr{target: "metric.foo"},
    55  		},
    56  		{"metric.*.foo",
    57  			&expr{target: "metric.*.foo"},
    58  		},
    59  		{
    60  			"func(metric)",
    61  			&expr{
    62  				target:    "func",
    63  				etype:     EtFunc,
    64  				args:      []*expr{{target: "metric"}},
    65  				argString: "metric",
    66  			},
    67  		},
    68  		{
    69  			"func(metric1,metric2,metric3)",
    70  			&expr{
    71  				target: "func",
    72  				etype:  EtFunc,
    73  				args: []*expr{
    74  					{target: "metric1"},
    75  					{target: "metric2"},
    76  					{target: "metric3"}},
    77  				argString: "metric1,metric2,metric3",
    78  			},
    79  		},
    80  		{
    81  			"func1(metric1,func2(metricA, metricB),metric3)",
    82  			&expr{
    83  				target: "func1",
    84  				etype:  EtFunc,
    85  				args: []*expr{
    86  					{target: "metric1"},
    87  					{target: "func2",
    88  						etype:     EtFunc,
    89  						args:      []*expr{{target: "metricA"}, {target: "metricB"}},
    90  						argString: "metricA, metricB",
    91  					},
    92  					{target: "metric3"}},
    93  				argString: "metric1,func2(metricA, metricB),metric3",
    94  			},
    95  		},
    96  
    97  		{
    98  			"3",
    99  			&expr{val: 3, etype: EtConst, valStr: "3"},
   100  		},
   101  		{
   102  			"3.1",
   103  			&expr{val: 3.1, etype: EtConst, valStr: "3.1"},
   104  		},
   105  		{
   106  			"func1(metric1, 3, 1e2, 2e-3)",
   107  			&expr{
   108  				target: "func1",
   109  				etype:  EtFunc,
   110  				args: []*expr{
   111  					{target: "metric1"},
   112  					{val: 3, etype: EtConst, valStr: "3"},
   113  					{val: 100, etype: EtConst, valStr: "1e2"},
   114  					{val: 0.002, etype: EtConst, valStr: "2e-3"},
   115  				},
   116  				argString: "metric1, 3, 1e2, 2e-3",
   117  			},
   118  		},
   119  		{
   120  			"func1(metric1, 'stringconst')",
   121  			&expr{
   122  				target: "func1",
   123  				etype:  EtFunc,
   124  				args: []*expr{
   125  					{target: "metric1"},
   126  					{valStr: "stringconst", etype: EtString},
   127  				},
   128  				argString: "metric1, 'stringconst'",
   129  			},
   130  		},
   131  		{
   132  			`func1(metric1, "stringconst")`,
   133  			&expr{
   134  				target: "func1",
   135  				etype:  EtFunc,
   136  				args: []*expr{
   137  					{target: "metric1"},
   138  					{valStr: "stringconst", etype: EtString},
   139  				},
   140  				argString: `metric1, "stringconst"`,
   141  			},
   142  		},
   143  		{
   144  			"func1(metric1, -3)",
   145  			&expr{
   146  				target: "func1",
   147  				etype:  EtFunc,
   148  				args: []*expr{
   149  					{target: "metric1"},
   150  					{val: -3, etype: EtConst, valStr: "-3"},
   151  				},
   152  				argString: "metric1, -3",
   153  			},
   154  		},
   155  
   156  		{
   157  			"func1(metric1, -3 , 'foo' )",
   158  			&expr{
   159  				target: "func1",
   160  				etype:  EtFunc,
   161  				args: []*expr{
   162  					{target: "metric1"},
   163  					{val: -3, etype: EtConst, valStr: "-3"},
   164  					{valStr: "foo", etype: EtString},
   165  				},
   166  				argString: "metric1, -3 , 'foo' ",
   167  			},
   168  		},
   169  
   170  		{
   171  			"func(metric, key='value')",
   172  			&expr{
   173  				target: "func",
   174  				etype:  EtFunc,
   175  				args: []*expr{
   176  					{target: "metric"},
   177  				},
   178  				namedArgs: map[string]*expr{
   179  					"key": {etype: EtString, valStr: "value"},
   180  				},
   181  				argString: "metric, key='value'",
   182  			},
   183  		},
   184  		{
   185  			"func(metric, key=true)",
   186  			&expr{
   187  				target: "func",
   188  				etype:  EtFunc,
   189  				args: []*expr{
   190  					{target: "metric"},
   191  				},
   192  				namedArgs: map[string]*expr{
   193  					"key": {etype: EtBool, target: "true", valStr: "true"},
   194  				},
   195  				argString: "metric, key=true",
   196  			},
   197  		},
   198  		{
   199  			"func(metric, key=1)",
   200  			&expr{
   201  				target: "func",
   202  				etype:  EtFunc,
   203  				args: []*expr{
   204  					{target: "metric"},
   205  				},
   206  				namedArgs: map[string]*expr{
   207  					"key": {etype: EtConst, val: 1, valStr: "1"},
   208  				},
   209  				argString: "metric, key=1",
   210  			},
   211  		},
   212  		{
   213  			"func(metric, key=0.1)",
   214  			&expr{
   215  				target: "func",
   216  				etype:  EtFunc,
   217  				args: []*expr{
   218  					{target: "metric"},
   219  				},
   220  				namedArgs: map[string]*expr{
   221  					"key": {etype: EtConst, val: 0.1, valStr: "0.1"},
   222  				},
   223  				argString: "metric, key=0.1",
   224  			},
   225  		},
   226  
   227  		{
   228  			"func(metric, 1, key='value')",
   229  			&expr{
   230  				target: "func",
   231  				etype:  EtFunc,
   232  				args: []*expr{
   233  					{target: "metric"},
   234  					{etype: EtConst, val: 1, valStr: "1"},
   235  				},
   236  				namedArgs: map[string]*expr{
   237  					"key": {etype: EtString, valStr: "value"},
   238  				},
   239  				argString: "metric, 1, key='value'",
   240  			},
   241  		},
   242  		{
   243  			"func(metric, key='value', 1)",
   244  			&expr{
   245  				target: "func",
   246  				etype:  EtFunc,
   247  				args: []*expr{
   248  					{target: "metric"},
   249  					{etype: EtConst, val: 1, valStr: "1"},
   250  				},
   251  				namedArgs: map[string]*expr{
   252  					"key": {etype: EtString, valStr: "value"},
   253  				},
   254  				argString: "metric, key='value', 1",
   255  			},
   256  		},
   257  		{
   258  			"func(metric, key1='value1', key2='value2')",
   259  			&expr{
   260  				target: "func",
   261  				etype:  EtFunc,
   262  				args: []*expr{
   263  					{target: "metric"},
   264  				},
   265  				namedArgs: map[string]*expr{
   266  					"key1": {etype: EtString, valStr: "value1"},
   267  					"key2": {etype: EtString, valStr: "value2"},
   268  				},
   269  				argString: "metric, key1='value1', key2='value2'",
   270  			},
   271  		},
   272  		{
   273  			"func(metric, key2='value2', key1='value1')",
   274  			&expr{
   275  				target: "func",
   276  				etype:  EtFunc,
   277  				args: []*expr{
   278  					{target: "metric"},
   279  				},
   280  				namedArgs: map[string]*expr{
   281  					"key2": {etype: EtString, valStr: "value2"},
   282  					"key1": {etype: EtString, valStr: "value1"},
   283  				},
   284  				argString: "metric, key2='value2', key1='value1'",
   285  			},
   286  		},
   287  
   288  		{
   289  			`foo.{bar,baz}.qux`,
   290  			&expr{
   291  				target: "foo.{bar,baz}.qux",
   292  				etype:  EtName,
   293  			},
   294  		},
   295  		{
   296  			`foo.b[0-9].qux`,
   297  			&expr{
   298  				target: "foo.b[0-9].qux",
   299  				etype:  EtName,
   300  			},
   301  		},
   302  		{
   303  			`virt.v1.*.text-match:<foo.bar.qux>`,
   304  			&expr{
   305  				target: "virt.v1.*.text-match:<foo.bar.qux>",
   306  				etype:  EtName,
   307  			},
   308  		},
   309  		{
   310  			"func2(metricA, metricB)|func1(metric1,metric3)",
   311  			&expr{
   312  				target: "func1",
   313  				etype:  EtFunc,
   314  				args: []*expr{
   315  					{target: "func2",
   316  						etype:     EtFunc,
   317  						args:      []*expr{{target: "metricA"}, {target: "metricB"}},
   318  						argString: "metricA, metricB",
   319  					},
   320  					{target: "metric1"},
   321  					{target: "metric3"}},
   322  				argString: "func2(metricA, metricB),metric1,metric3",
   323  			},
   324  		},
   325  		{
   326  			`movingAverage(company.server*.applicationInstance.requestsHandled|aliasByNode(1),"5min")`,
   327  			&expr{
   328  				target: "movingAverage",
   329  				etype:  EtFunc,
   330  				args: []*expr{
   331  					{target: "aliasByNode",
   332  						etype: EtFunc,
   333  						args: []*expr{
   334  							{target: "company.server*.applicationInstance.requestsHandled"},
   335  							{val: 1, etype: EtConst, valStr: "1"},
   336  						},
   337  						argString: "company.server*.applicationInstance.requestsHandled,1",
   338  					},
   339  					{etype: EtString, valStr: "5min"},
   340  				},
   341  				argString: `aliasByNode(company.server*.applicationInstance.requestsHandled,1),"5min"`,
   342  			},
   343  		},
   344  		{
   345  			`aliasByNode(company.server*.applicationInstance.requestsHandled,1)|movingAverage("5min")`,
   346  			&expr{
   347  				target: "movingAverage",
   348  				etype:  EtFunc,
   349  				args: []*expr{
   350  					{target: "aliasByNode",
   351  						etype: EtFunc,
   352  						args: []*expr{
   353  							{target: "company.server*.applicationInstance.requestsHandled"},
   354  							{val: 1, etype: EtConst, valStr: "1"},
   355  						},
   356  						argString: "company.server*.applicationInstance.requestsHandled,1",
   357  					},
   358  					{etype: EtString, valStr: "5min"},
   359  				},
   360  				argString: `aliasByNode(company.server*.applicationInstance.requestsHandled,1),"5min"`,
   361  			},
   362  		},
   363  		{
   364  			`company.server*.applicationInstance.requestsHandled|aliasByNode(1)|movingAverage("5min")`,
   365  			&expr{
   366  				target: "movingAverage",
   367  				etype:  EtFunc,
   368  				args: []*expr{
   369  					{target: "aliasByNode",
   370  						etype: EtFunc,
   371  						args: []*expr{
   372  							{target: "company.server*.applicationInstance.requestsHandled"},
   373  							{val: 1, etype: EtConst, valStr: "1"},
   374  						},
   375  						argString: "company.server*.applicationInstance.requestsHandled,1",
   376  					},
   377  					{etype: EtString, valStr: "5min"},
   378  				},
   379  				argString: `aliasByNode(company.server*.applicationInstance.requestsHandled,1),"5min"`,
   380  			},
   381  		},
   382  		{
   383  			`company.server*.applicationInstance.requestsHandled|keepLastValue()`,
   384  			&expr{
   385  				target: "keepLastValue",
   386  				etype:  EtFunc,
   387  				args: []*expr{
   388  					{target: "company.server*.applicationInstance.requestsHandled"},
   389  				},
   390  				argString: `company.server*.applicationInstance.requestsHandled`,
   391  			},
   392  		},
   393  		{"hello&world",
   394  			&expr{target: "hello&world"},
   395  		},
   396  		{
   397  			"foo.bar\n.baz\t",
   398  			&expr{
   399  				target: "foo.bar",
   400  				etype:  EtName,
   401  			},
   402  		},
   403  		{
   404  			"absolute( baz )\n",
   405  			&expr{
   406  				target: "absolute",
   407  				etype:  EtFunc,
   408  				args: []*expr{
   409  					{target: "baz"},
   410  				},
   411  				argString: " baz ",
   412  			},
   413  		},
   414  		{
   415  			"func1(\"example blah\")",
   416  			&expr{
   417  				target: "func1",
   418  				etype:  EtFunc,
   419  				args: []*expr{
   420  					{
   421  						etype:  EtString,
   422  						valStr: "example blah",
   423  					},
   424  				},
   425  				argString: "\"example blah\"",
   426  			},
   427  		},
   428  		{
   429  			"foobar(\n)",
   430  			&expr{
   431  				target: "foobar",
   432  				etype:  EtFunc,
   433  			},
   434  		},
   435  		{
   436  			"foobar(asdf,\n\tzxcv,\n\tqwer\n)",
   437  			&expr{
   438  				target: "foobar",
   439  				etype:  EtFunc,
   440  				args: []*expr{
   441  					{target: "asdf"},
   442  					{target: "zxcv"},
   443  					{target: "qwer"},
   444  				},
   445  				argString: "asdf,\n\tzxcv,\n\tqwer\n",
   446  			},
   447  		},
   448  		{
   449  			"func1(foo.bar)\n| func2(foo.baz)|\n func3(\n\tfunc4(asdf.zxcv.qwer)\n)",
   450  			&expr{
   451  				target: "func3",
   452  				etype:  EtFunc,
   453  				args: []*expr{
   454  					{
   455  						target: "func2",
   456  						etype:  EtFunc,
   457  						args: []*expr{
   458  							{
   459  								target: "func1",
   460  								etype:  EtFunc,
   461  								args: []*expr{
   462  									{target: "foo.bar"},
   463  								},
   464  								argString: "foo.bar",
   465  							},
   466  							{target: "foo.baz"},
   467  						},
   468  						argString: "func1(foo.bar),foo.baz",
   469  					},
   470  					{
   471  						target: "func4",
   472  						etype:  EtFunc,
   473  						args: []*expr{
   474  							{target: "asdf.zxcv.qwer"},
   475  						},
   476  						argString: "asdf.zxcv.qwer",
   477  					},
   478  				},
   479  				argString: "func2(func1(foo.bar),foo.baz),func4(asdf.zxcv.qwer)",
   480  			},
   481  		},
   482  	}
   483  
   484  	for _, tt := range tests {
   485  		t.Run(tt.s, func(t *testing.T) {
   486  			assert := assert.New(t)
   487  
   488  			e, _, err := ParseExpr(tt.s)
   489  			if assert.NoError(err) {
   490  				assert.Equal(tt.e, e, tt.s)
   491  			}
   492  		})
   493  	}
   494  }
   495  
   496  func TestDoGetBoolVar(t *testing.T) {
   497  	tests := []struct {
   498  		s string
   499  		e *expr
   500  		r bool
   501  	}{
   502  		{
   503  			"1 is true",
   504  			&expr{val: 1, etype: EtConst, valStr: "1"},
   505  			true,
   506  		},
   507  		{
   508  			"true is true",
   509  			&expr{etype: EtString, valStr: "true"},
   510  			true,
   511  		},
   512  		{
   513  			"True is true",
   514  			&expr{etype: EtString, valStr: "True"},
   515  			true,
   516  		},
   517  		{
   518  			"0 is false",
   519  			&expr{val: 0, etype: EtConst, valStr: "0"},
   520  			false,
   521  		},
   522  		{
   523  			"False is false",
   524  			&expr{etype: EtString, valStr: "False"},
   525  			false,
   526  		},
   527  		{
   528  			"false is false",
   529  			&expr{etype: EtString, valStr: "false"},
   530  			false,
   531  		},
   532  	}
   533  	for _, tt := range tests {
   534  		t.Run(tt.s, func(t *testing.T) {
   535  			assert := assert.New(t)
   536  
   537  			r, err := tt.e.doGetBoolArg()
   538  			if assert.NoError(err) {
   539  				assert.Equal(tt.r, r, tt.s)
   540  			}
   541  		})
   542  	}
   543  }
   544  
   545  func TestGetIntervalNamedOrPosArgDefault(t *testing.T) {
   546  	e, _, err := ParseExpr("func(metric, key='1min')")
   547  	assert.NoError(t, err)
   548  
   549  	val, err := e.GetIntervalNamedOrPosArgDefault("key", 1, -1, 0)
   550  	assert.NoError(t, err)
   551  	assert.Equal(t, int64(-60), val)
   552  }
   553  
   554  func TestDoGetFloatArg(t *testing.T) {
   555  	tests := []struct {
   556  		s string
   557  		e *expr
   558  		r float64
   559  	}{
   560  		{
   561  			"parse float",
   562  			&expr{val: 1.0, etype: EtConst, valStr: "1.0"},
   563  			1.0,
   564  		},
   565  		{
   566  			"parse string to float",
   567  			&expr{etype: EtString, valStr: "1.0"},
   568  			1.0,
   569  		},
   570  	}
   571  	for _, tt := range tests {
   572  		t.Run(tt.s, func(t *testing.T) {
   573  			assert := assert.New(t)
   574  
   575  			r, err := tt.e.doGetFloatArg()
   576  			if assert.NoError(err) {
   577  				assert.Equal(tt.r, r, tt.s)
   578  			}
   579  		})
   580  	}
   581  }
   582  
   583  func TestDoGetIntArg(t *testing.T) {
   584  	tests := []struct {
   585  		s string
   586  		e *expr
   587  		r int
   588  	}{
   589  		{
   590  			"parse int",
   591  			&expr{val: 5, etype: EtConst, valStr: "5"},
   592  			5,
   593  		},
   594  		{
   595  			"parse string to int",
   596  			&expr{etype: EtString, valStr: "1"},
   597  			1,
   598  		},
   599  	}
   600  	for _, tt := range tests {
   601  		t.Run(tt.s, func(t *testing.T) {
   602  			assert := assert.New(t)
   603  
   604  			r, err := tt.e.doGetIntArg()
   605  			if assert.NoError(err) {
   606  				assert.Equal(tt.r, r, tt.s)
   607  			}
   608  		})
   609  	}
   610  }
   611  
   612  func TestDoGetIntOrInf(t *testing.T) {
   613  	tests := []struct {
   614  		s string
   615  		e *expr
   616  		r IntOrInf
   617  	}{
   618  		{
   619  			"parse int",
   620  			&expr{val: 5, etype: EtConst, valStr: "5"},
   621  			IntOrInf{IntVal: 5},
   622  		},
   623  		{
   624  			"parse string to int",
   625  			&expr{etype: EtString, valStr: "1"},
   626  			IntOrInf{IntVal: 1},
   627  		},
   628  		{
   629  			"parse inf",
   630  			&expr{etype: EtName, target: "inf"},
   631  			IntOrInf{IsInf: true},
   632  		},
   633  		{
   634  			"parse capitalized inf",
   635  			&expr{etype: EtName, target: "INF"},
   636  			IntOrInf{IsInf: true},
   637  		},
   638  		{
   639  			"parse string to inf",
   640  			&expr{etype: EtString, valStr: "inf"},
   641  			IntOrInf{IsInf: true},
   642  		},
   643  	}
   644  	for _, tt := range tests {
   645  		t.Run(tt.s, func(t *testing.T) {
   646  			assert := assert.New(t)
   647  
   648  			r, err := tt.e.doGetIntOrInfArg()
   649  			if assert.NoError(err) {
   650  				assert.Equal(tt.r, r, tt.s)
   651  			}
   652  		})
   653  	}
   654  }
   655  
   656  func TestMetrics(t *testing.T) {
   657  	tests := []struct {
   658  		s        string
   659  		e        *expr
   660  		from     int64
   661  		to       int64
   662  		expected []MetricRequest
   663  	}{
   664  		{
   665  			"hitcount(metric1, '1h', true)",
   666  			&expr{
   667  				target: "hitcount",
   668  				etype:  EtFunc,
   669  				args: []*expr{
   670  					{target: "metric1"},
   671  					{valStr: "1h", etype: EtString},
   672  					{valStr: "true", etype: EtBool},
   673  				},
   674  				argString: "metric1, '1h', true",
   675  			},
   676  			1410346740,
   677  			1410346865,
   678  			[]MetricRequest{
   679  				{
   680  					Metric: "metric1",
   681  					From:   1410343200,
   682  					Until:  1410346865,
   683  				},
   684  			},
   685  		},
   686  		{
   687  			"hitcount(metric1, '1h', alignToInterval=True)",
   688  			&expr{
   689  				target: "hitcount",
   690  				etype:  EtFunc,
   691  				args: []*expr{
   692  					{target: "metric1"},
   693  					{valStr: "1h", etype: EtString},
   694  				},
   695  				namedArgs: map[string]*expr{
   696  					"alignToInterval": {
   697  						target: "true",
   698  						etype:  EtBool,
   699  						valStr: "true",
   700  					},
   701  				},
   702  				argString: "metric1, '1h', alignToInterval=True",
   703  			},
   704  			1410346740,
   705  			1410346865,
   706  			[]MetricRequest{
   707  				{
   708  					Metric: "metric1",
   709  					From:   1410343200,
   710  					Until:  1410346865,
   711  				},
   712  			},
   713  		},
   714  		{
   715  			"hitcount(metric1, '1h')",
   716  			&expr{
   717  				target: "hitcount",
   718  				etype:  EtFunc,
   719  				args: []*expr{
   720  					{target: "metric1"},
   721  					{valStr: "1h", etype: EtString},
   722  				},
   723  				argString: "metric1, '1h'",
   724  			},
   725  			1410346740,
   726  			1410346865,
   727  			[]MetricRequest{
   728  				{
   729  					Metric: "metric1",
   730  					From:   1410346740,
   731  					Until:  1410346865,
   732  				},
   733  			},
   734  		},
   735  		{
   736  			"hitcount(timeShift(metric1, '-1h'),'1h')",
   737  			&expr{
   738  				target: "hitcount",
   739  				etype:  EtFunc,
   740  				args: []*expr{
   741  					{
   742  						target: "timeShift",
   743  						etype:  EtFunc,
   744  						args: []*expr{
   745  							{target: "metric1"},
   746  							{valStr: "-1h", etype: EtString},
   747  						},
   748  						argString: "metric1, '-1h'",
   749  					},
   750  					{valStr: "1h", etype: EtString},
   751  					{valStr: "true", etype: EtBool},
   752  				},
   753  				argString: "timeShift(metric1, '-1h'),'1h'",
   754  			},
   755  			1410346740,
   756  			1410346865,
   757  			[]MetricRequest{
   758  				{
   759  					Metric: "metric1",
   760  					From:   1410339600,
   761  					Until:  1410343265,
   762  				},
   763  			},
   764  		},
   765  		{
   766  			"holtWintersAberration(metric1)",
   767  			&expr{
   768  				target: "holtWintersAberration",
   769  				etype:  EtFunc,
   770  				args: []*expr{
   771  					{target: "metric1"},
   772  				},
   773  				argString: "metric1",
   774  			},
   775  			1410346740,
   776  			1410346865,
   777  			[]MetricRequest{
   778  				{
   779  					Metric: "metric1",
   780  					From:   1410346740,
   781  					Until:  1410346865,
   782  				},
   783  				{
   784  					Metric: "metric1",
   785  					From:   1409741940,
   786  					Until:  1410346865,
   787  				},
   788  			},
   789  		},
   790  		{
   791  			"holtWintersAberration(metric1,3,'6d')",
   792  			&expr{
   793  				target: "holtWintersAberration",
   794  				etype:  EtFunc,
   795  				args: []*expr{
   796  					{target: "metric1"},
   797  					{valStr: "3", etype: EtConst},
   798  					{valStr: "6d", etype: EtString},
   799  				},
   800  				argString: "metric1, 3, '6d'",
   801  			},
   802  			1410346740,
   803  			1410346865,
   804  			[]MetricRequest{
   805  				{
   806  					Metric: "metric1",
   807  					From:   1410346740,
   808  					Until:  1410346865,
   809  				},
   810  				{
   811  					Metric: "metric1",
   812  					From:   1409828340,
   813  					Until:  1410346865,
   814  				},
   815  			},
   816  		},
   817  		{
   818  			"holtWintersConfidenceBands(metric1)",
   819  			&expr{
   820  				target: "holtWintersConfidenceBands",
   821  				etype:  EtFunc,
   822  				args: []*expr{
   823  					{target: "metric1"},
   824  				},
   825  				argString: "metric1",
   826  			},
   827  			1410346740,
   828  			1410346865,
   829  			[]MetricRequest{
   830  				{
   831  					Metric: "metric1",
   832  					From:   1409741940,
   833  					Until:  1410346865,
   834  				},
   835  			},
   836  		},
   837  		{
   838  			"holtWintersConfidenceBands(metric1, 4, '1d')",
   839  			&expr{
   840  				target: "holtWintersConfidenceBands",
   841  				etype:  EtFunc,
   842  				args: []*expr{
   843  					{target: "metric1"},
   844  					{valStr: "4", etype: EtConst},
   845  					{valStr: "1d", etype: EtString},
   846  				},
   847  				argString: "metric1, 4, '1d'",
   848  			},
   849  			1410346740,
   850  			1410346865,
   851  			[]MetricRequest{
   852  				{
   853  					Metric: "metric1",
   854  					From:   1410260340,
   855  					Until:  1410346865,
   856  				},
   857  			},
   858  		},
   859  		{
   860  			"holtWintersConfidenceBands(metric1, 4, bootstrapInterval='3d')",
   861  			&expr{
   862  				target: "holtWintersConfidenceBands",
   863  				etype:  EtFunc,
   864  				args: []*expr{
   865  					{target: "metric1"},
   866  					{valStr: "4", etype: EtConst},
   867  				},
   868  				namedArgs: map[string]*expr{
   869  					"bootstrapInterval": {etype: EtString, valStr: "3d"},
   870  				},
   871  				argString: "metric1, 4, '3d'",
   872  			},
   873  			1410346740,
   874  			1410346865,
   875  			[]MetricRequest{
   876  				{
   877  					Metric: "metric1",
   878  					From:   1410087540,
   879  					Until:  1410346865,
   880  				},
   881  			},
   882  		},
   883  		{
   884  			"holtWintersForecast(metric1,'1d')",
   885  			&expr{
   886  				target: "holtWintersConfidenceBands",
   887  				etype:  EtFunc,
   888  				args: []*expr{
   889  					{target: "metric1"},
   890  				},
   891  				argString: "metric1",
   892  			},
   893  			1410346740,
   894  			1410346865,
   895  			[]MetricRequest{
   896  				{
   897  					Metric: "metric1",
   898  					From:   1409741940,
   899  					Until:  1410346865,
   900  				},
   901  			},
   902  		},
   903  		{
   904  			"smartSummarize(metric1, '1h', 'sum', 'seconds')",
   905  			&expr{
   906  				target: "smartSummarize",
   907  				etype:  EtFunc,
   908  				args: []*expr{
   909  					{target: "metric1"},
   910  					{valStr: "1h", etype: EtString},
   911  					{valStr: "sum", etype: EtString},
   912  					{valStr: "seconds", etype: EtString},
   913  				},
   914  				argString: "metric1, '1h', 'sum', 'seconds'",
   915  			},
   916  			1410346740,
   917  			1410346865,
   918  			[]MetricRequest{
   919  				{
   920  					Metric: "metric1",
   921  					From:   1410346740,
   922  					Until:  1410346865,
   923  				},
   924  			},
   925  		},
   926  		{
   927  			"smartSummarize(metric1, '1h', 'sum', '1minutes')",
   928  			&expr{
   929  				target: "smartSummarize",
   930  				etype:  EtFunc,
   931  				args: []*expr{
   932  					{target: "metric1"},
   933  					{valStr: "1h", etype: EtString},
   934  					{valStr: "sum", etype: EtString},
   935  					{valStr: "1minutes", etype: EtString},
   936  				},
   937  				argString: "metric1, '1h', 'sum', '1minutes'",
   938  			},
   939  			1410346745,
   940  			1410346865,
   941  			[]MetricRequest{
   942  				{
   943  					Metric: "metric1",
   944  					From:   1410346740,
   945  					Until:  1410346865,
   946  				},
   947  			},
   948  		},
   949  		{
   950  			"smartSummarize(metric1, '1h', 'sum', 'hours')",
   951  			&expr{
   952  				target: "smartSummarize",
   953  				etype:  EtFunc,
   954  				args: []*expr{
   955  					{target: "metric1"},
   956  					{valStr: "1h", etype: EtString},
   957  					{valStr: "sum", etype: EtString},
   958  					{valStr: "hours", etype: EtString},
   959  				},
   960  				argString: "metric1, '1h', 'sum', 'hours'",
   961  			},
   962  			1410346740,
   963  			1410346865,
   964  			[]MetricRequest{
   965  				{
   966  					Metric: "metric1",
   967  					From:   1410343200,
   968  					Until:  1410346865,
   969  				},
   970  			},
   971  		},
   972  		{
   973  			"smartSummarize(metric1, '1h', 'sum', 'days')",
   974  			&expr{
   975  				target: "smartSummarize",
   976  				etype:  EtFunc,
   977  				args: []*expr{
   978  					{target: "metric1"},
   979  					{valStr: "1h", etype: EtString},
   980  					{valStr: "sum", etype: EtString},
   981  					{valStr: "days", etype: EtString},
   982  				},
   983  				argString: "metric1, '1h', 'sum', 'days'",
   984  			},
   985  			1410346740,
   986  			1410346865,
   987  			[]MetricRequest{
   988  				{
   989  					Metric: "metric1",
   990  					From:   1410307200,
   991  					Until:  1410346865,
   992  				},
   993  			},
   994  		},
   995  		{
   996  			"smartSummarize(metric1, '1hours','sum','weeks5')",
   997  			&expr{
   998  				target: "smartSummarize",
   999  				etype:  EtFunc,
  1000  				args: []*expr{
  1001  					{target: "metric1"},
  1002  					{valStr: "1h", etype: EtString},
  1003  					{valStr: "sum", etype: EtString},
  1004  					{valStr: "weeks5", etype: EtString},
  1005  				},
  1006  				argString: "metric1, '1h', 'sum', 'weeks5'",
  1007  			},
  1008  			1410346740,
  1009  			1410346865,
  1010  			[]MetricRequest{
  1011  				{
  1012  					Metric: "metric1",
  1013  					From:   1409875200,
  1014  					Until:  1410346865,
  1015  				},
  1016  			},
  1017  		},
  1018  		{
  1019  			"smartSummarize(metric1, '1hours','sum','months')",
  1020  			&expr{
  1021  				target: "smartSummarize",
  1022  				etype:  EtFunc,
  1023  				args: []*expr{
  1024  					{target: "metric1"},
  1025  					{valStr: "1h", etype: EtString},
  1026  					{valStr: "sum", etype: EtString},
  1027  					{valStr: "months", etype: EtString},
  1028  				},
  1029  				argString: "metric1, '1h', 'sum', 'months'",
  1030  			},
  1031  			1410346740,
  1032  			1410346865,
  1033  			[]MetricRequest{
  1034  				{
  1035  					Metric: "metric1",
  1036  					From:   1409529600,
  1037  					Until:  1410346865,
  1038  				},
  1039  			},
  1040  		},
  1041  		{
  1042  			"smartSummarize(metric1, '1hours','sum','y')",
  1043  			&expr{
  1044  				target: "smartSummarize",
  1045  				etype:  EtFunc,
  1046  				args: []*expr{
  1047  					{target: "metric1"},
  1048  					{valStr: "1h", etype: EtString},
  1049  					{valStr: "sum", etype: EtString},
  1050  					{valStr: "years", etype: EtString},
  1051  				},
  1052  				argString: "metric1, '1h', 'sum', 'years'",
  1053  			},
  1054  			1410346740,
  1055  			1410346865,
  1056  			[]MetricRequest{
  1057  				{
  1058  					Metric: "metric1",
  1059  					From:   1388534400,
  1060  					Until:  1410346865,
  1061  				},
  1062  			},
  1063  		},
  1064  	}
  1065  	for _, tt := range tests {
  1066  		t.Run(tt.s, func(t *testing.T) {
  1067  
  1068  			r := tt.e.Metrics(tt.from, tt.to)
  1069  			assert.Equal(t, tt.expected, r)
  1070  		})
  1071  	}
  1072  }