SQL data sources: Convert to return data frames (#32257)
Convert SQL data sources to return data frames. Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Will Browne <will.browne@grafana.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
This commit is contained in:
co-authored by
Marcus Efraimsson
Arve Knudsen
Will Browne
Hugo Häggmark
parent
06c24476dc
commit
bd66c8dde3
@@ -0,0 +1,309 @@
|
||||
package sqleng
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/xorcare/pointer"
|
||||
)
|
||||
|
||||
func TestResampleWide(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input *data.Frame
|
||||
fillMissing *data.FillMissing
|
||||
timeRange backend.TimeRange
|
||||
interval time.Duration
|
||||
output *data.Frame
|
||||
}{
|
||||
{
|
||||
name: "interval 1s; fill null",
|
||||
fillMissing: &data.FillMissing{Mode: data.FillModeNull},
|
||||
timeRange: backend.TimeRange{
|
||||
From: time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
To: time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
},
|
||||
interval: time.Second,
|
||||
input: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
output: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 21, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 22, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 23, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 25, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
nil,
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
pointer.Int64(15),
|
||||
nil,
|
||||
nil,
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
nil,
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
pointer.Float64(15.0),
|
||||
nil,
|
||||
nil,
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "interval 1s; fill value",
|
||||
fillMissing: &data.FillMissing{Mode: data.FillModeValue, Value: -1},
|
||||
timeRange: backend.TimeRange{
|
||||
From: time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
To: time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
},
|
||||
interval: time.Second,
|
||||
input: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
output: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 21, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 22, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 23, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 25, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(-1),
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(-1),
|
||||
pointer.Int64(-1),
|
||||
pointer.Int64(-1),
|
||||
pointer.Int64(15),
|
||||
pointer.Int64(-1),
|
||||
pointer.Int64(-1),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(-1),
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(-1),
|
||||
pointer.Float64(-1),
|
||||
pointer.Float64(-1),
|
||||
pointer.Float64(15.0),
|
||||
pointer.Float64(-1),
|
||||
pointer.Float64(-1),
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "interval 1s; fill previous",
|
||||
fillMissing: &data.FillMissing{Mode: data.FillModePrevious},
|
||||
timeRange: backend.TimeRange{
|
||||
From: time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
To: time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
},
|
||||
interval: time.Second,
|
||||
input: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
output: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 21, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 22, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 23, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 25, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
nil,
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
pointer.Int64(15),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
nil,
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
pointer.Float64(15.0),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "interval 2s; fill null",
|
||||
fillMissing: &data.FillMissing{Mode: data.FillModeNull},
|
||||
timeRange: backend.TimeRange{
|
||||
From: time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
To: time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
},
|
||||
interval: 2 * time.Second,
|
||||
input: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
output: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 18, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 22, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 26, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(12),
|
||||
nil,
|
||||
nil,
|
||||
pointer.Int64(15),
|
||||
nil,
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(12.5),
|
||||
nil,
|
||||
nil,
|
||||
pointer.Float64(15.0),
|
||||
nil,
|
||||
})),
|
||||
},
|
||||
{
|
||||
name: "interval 1s; fill null; rows outside timerange window",
|
||||
fillMissing: &data.FillMissing{Mode: data.FillModeNull},
|
||||
timeRange: backend.TimeRange{
|
||||
From: time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
To: time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
},
|
||||
interval: time.Second,
|
||||
input: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 19, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(10),
|
||||
pointer.Int64(12),
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(10.5),
|
||||
pointer.Float64(12.5),
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
output: data.NewFrame("wide_test",
|
||||
data.NewField("Time", nil, []time.Time{
|
||||
time.Date(2020, 1, 2, 3, 4, 20, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 21, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 22, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 23, 0, time.UTC),
|
||||
time.Date(2020, 1, 2, 3, 4, 24, 0, time.UTC),
|
||||
}),
|
||||
data.NewField("Values Ints", nil, []*int64{
|
||||
pointer.Int64(12),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
pointer.Int64(15),
|
||||
}),
|
||||
data.NewField(`Values Floats`, data.Labels{"Animal Factor": "sloth"}, []*float64{
|
||||
pointer.Float64(12.5),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
pointer.Float64(15.0),
|
||||
})),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
frame, err := resample(tt.input, dataQueryModel{
|
||||
FillMissing: tt.fillMissing,
|
||||
TimeRange: tt.timeRange,
|
||||
Interval: tt.interval,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
if diff := cmp.Diff(tt.output, frame, data.FrameTestCompareOptions()...); diff != "" {
|
||||
t.Errorf("Result mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user