diff --git a/pkg/expr/commands.go b/pkg/expr/commands.go index 16a29fc9512..8410fc02c5c 100644 --- a/pkg/expr/commands.go +++ b/pkg/expr/commands.go @@ -266,15 +266,22 @@ func (gr *ResampleCommand) Execute(_ context.Context, now time.Time, vars mathex newRes := mathexp.Results{} timeRange := gr.TimeRange.AbsoluteTime(now) for _, val := range vars[gr.VarToResample].Values { - series, ok := val.(mathexp.Series) - if !ok { + if val == nil { + continue + } + switch v := val.(type) { + case mathexp.Series: + num, err := v.Resample(gr.refID, gr.Window, gr.Downsampler, gr.Upsampler, timeRange.From, timeRange.To) + if err != nil { + return newRes, err + } + newRes.Values = append(newRes.Values, num) + case mathexp.NoData: + newRes.Values = append(newRes.Values, v.New()) + return newRes, nil + default: return newRes, fmt.Errorf("can only resample type series, got type %v", val.Type()) } - num, err := series.Resample(gr.refID, gr.Window, gr.Downsampler, gr.Upsampler, timeRange.From, timeRange.To) - if err != nil { - return newRes, err - } - newRes.Values = append(newRes.Values, num) } return newRes, nil } diff --git a/pkg/expr/commands_test.go b/pkg/expr/commands_test.go index 7faa68c6eeb..aa741dada2e 100644 --- a/pkg/expr/commands_test.go +++ b/pkg/expr/commands_test.go @@ -14,6 +14,7 @@ import ( ptr "github.com/xorcare/pointer" "github.com/grafana/grafana/pkg/expr/mathexp" + "github.com/grafana/grafana/pkg/expr/mathexp/parse" "github.com/grafana/grafana/pkg/util" ) @@ -170,3 +171,62 @@ func randomReduceFunc() string { res := mathexp.GetSupportedReduceFuncs() return res[rand.Intn(len(res)-1)] } + +func TestResampleCommand_Execute(t *testing.T) { + varToReduce := util.GenerateShortUID() + tr := RelativeTimeRange{ + From: -10 * time.Second, + To: 0, + } + cmd, err := NewResampleCommand(util.GenerateShortUID(), "1s", varToReduce, "sum", "pad", tr) + require.NoError(t, err) + + var tests = []struct { + name string + vals mathexp.Value + isError bool + expectedType parse.ReturnType + }{ + { + name: "should resample when input Series", + vals: mathexp.NewSeries(varToReduce, nil, 100), + expectedType: parse.TypeSeriesSet, + }, + { + name: "should return NoData when input NoData", + vals: mathexp.NoData{}, + expectedType: parse.TypeNoData, + }, { + name: "should return error when input Number", + vals: mathexp.NewNumber("test", nil), + isError: true, + }, { + name: "should return error when input Scalar", + vals: mathexp.NewScalar("test", ptr.Float64(rand.Float64())), + isError: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{ + varToReduce: mathexp.Results{Values: mathexp.Values{test.vals}}, + }) + if test.isError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Len(t, result.Values, 1) + res := result.Values[0] + require.Equal(t, test.expectedType, res.Type()) + } + }) + } + + t.Run("should return empty result if input is nil Value", func(t *testing.T) { + result, err := cmd.Execute(context.Background(), time.Now(), mathexp.Vars{ + varToReduce: mathexp.Results{Values: mathexp.Values{nil}}, + }) + require.Empty(t, result.Values) + require.NoError(t, err) + }) +}