mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 21:22:44 +08:00

Takes a specific code path for data that identifies itself as dataplane instead of "guessing" what the data is. The data must identify itself by being in the dataplane by having both the following frame metadata properties: - TypeVersion property that is greater than 0.0 - 'Type' property The flag is disableSSEDataplane and disables this functionality and uses the old code for all queries regardless. See https://github.com/grafana/grafana-plugin-sdk-go/blob/main/data/contract_docs/contract.md for dataplane details.
243 lines
6.7 KiB
Go
243 lines
6.7 KiB
Go
package expr
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/dataplane/examples"
|
|
"github.com/grafana/grafana-plugin-sdk-go/data"
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
|
datafakes "github.com/grafana/grafana/pkg/services/datasources/fakes"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPassThroughDataplaneExamples(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
validExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, collection := range validExamples.Collections() {
|
|
for _, example := range collection.ExampleSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
_, err := framesPassThroughService(t, example.Frames("A"))
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func framesPassThroughService(t *testing.T, frames data.Frames) (data.Frames, error) {
|
|
me := &mockEndpoint{
|
|
Frames: frames,
|
|
}
|
|
|
|
cfg := setting.NewCfg()
|
|
|
|
s := Service{
|
|
cfg: cfg,
|
|
dataService: me,
|
|
dataSourceService: &datafakes.FakeDataSourceService{},
|
|
features: &featuremgmt.FeatureManager{},
|
|
}
|
|
queries := []Query{{
|
|
RefID: "A",
|
|
DataSource: &datasources.DataSource{
|
|
OrgID: 1,
|
|
UID: "test",
|
|
Type: "test",
|
|
},
|
|
JSON: json.RawMessage(`{ "datasource": { "uid": "1" }, "intervalMs": 1000, "maxDataPoints": 1000 }`),
|
|
TimeRange: AbsoluteTimeRange{
|
|
From: time.Time{},
|
|
To: time.Time{},
|
|
},
|
|
}}
|
|
|
|
req := &Request{Queries: queries}
|
|
|
|
pl, err := s.BuildPipeline(req)
|
|
require.NoError(t, err)
|
|
|
|
res, err := s.ExecutePipeline(context.Background(), time.Now(), pl)
|
|
require.NoError(t, err)
|
|
|
|
require.Contains(t, res.Responses, "A")
|
|
|
|
return res.Responses["A"].Frames, res.Responses["A"].Error
|
|
}
|
|
|
|
func TestShouldUseDataplane(t *testing.T) {
|
|
t.Run("zero frames returns no data and is allowed", func(t *testing.T) {
|
|
f := data.Frames{}
|
|
dt, use, err := shouldUseDataplane(f, log.New(""), false)
|
|
require.NoError(t, err)
|
|
require.True(t, use)
|
|
require.Equal(t, data.KindUnknown, dt.Kind())
|
|
})
|
|
|
|
t.Run("a frame with Type and TypeVersion 0.0 will not use dataplane", func(t *testing.T) {
|
|
f := data.Frames{(&data.Frame{}).SetMeta(
|
|
&data.FrameMeta{
|
|
TypeVersion: data.FrameTypeVersion{},
|
|
Type: data.FrameTypeTimeSeriesMulti,
|
|
},
|
|
)}
|
|
_, use, err := shouldUseDataplane(f, log.New(""), false)
|
|
require.NoError(t, err)
|
|
require.False(t, use)
|
|
})
|
|
|
|
t.Run("a frame without Type and TypeVersion > 0.0 will not use dataplane", func(t *testing.T) {
|
|
f := data.Frames{(&data.Frame{}).SetMeta(
|
|
&data.FrameMeta{
|
|
TypeVersion: data.FrameTypeVersion{0, 1},
|
|
},
|
|
)}
|
|
_, use, err := shouldUseDataplane(f, log.New(""), false)
|
|
require.NoError(t, err)
|
|
require.False(t, use)
|
|
})
|
|
|
|
t.Run("a frame with no metadata will not use dataplane", func(t *testing.T) {
|
|
f := data.Frames{&data.Frame{}}
|
|
_, use, err := shouldUseDataplane(f, log.New(""), false)
|
|
require.NoError(t, err)
|
|
require.False(t, use)
|
|
})
|
|
|
|
t.Run("a newer version that supported will return a warning but still use dataplane", func(t *testing.T) {
|
|
ty := data.FrameTypeTimeSeriesMulti
|
|
v := data.FrameTypeVersion{999, 999}
|
|
f := data.Frames{(&data.Frame{}).SetMeta(
|
|
&data.FrameMeta{
|
|
Type: ty,
|
|
TypeVersion: v,
|
|
},
|
|
)}
|
|
dt, use, err := shouldUseDataplane(f, log.New(""), false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, use)
|
|
require.Equal(t, data.KindTimeSeries, dt.Kind())
|
|
})
|
|
|
|
t.Run("all valid dataplane examples should use dataplane", func(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
validExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, collection := range validExamples.Collections() {
|
|
for _, example := range collection.ExampleSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
_, err := framesPassThroughService(t, example.Frames("A"))
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestHandleDataplaneNumeric(t *testing.T) {
|
|
t.Run("no data", func(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
validNoDataNumericExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
Kind: data.KindNumeric,
|
|
NoData: util.Pointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, example := range validNoDataNumericExamples.AsSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
res, err := handleDataplaneNumeric(example.Frames("A"))
|
|
require.NoError(t, err)
|
|
require.Len(t, res.Values, 1)
|
|
})
|
|
}
|
|
})
|
|
|
|
t.Run("should read correct number of items from examples", func(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
numericExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
Kind: data.KindNumeric,
|
|
NoData: util.Pointer(false),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, example := range numericExamples.AsSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
res, err := handleDataplaneNumeric(example.Frames("A"))
|
|
require.NoError(t, err)
|
|
require.Len(t, res.Values, example.Info().ItemCount)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestHandleDataplaneTS(t *testing.T) {
|
|
t.Run("no data", func(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
validNoDataTSExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
Kind: data.KindTimeSeries,
|
|
NoData: util.Pointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, example := range validNoDataTSExamples.AsSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
res, err := handleDataplaneTimeseries(example.Frames("A"))
|
|
require.NoError(t, err)
|
|
require.Len(t, res.Values, 1)
|
|
})
|
|
}
|
|
})
|
|
t.Run("should read correct number of items from examples", func(t *testing.T) {
|
|
es, err := examples.GetExamples()
|
|
require.NoError(t, err)
|
|
|
|
tsExamples, err := es.Filter(examples.FilterOptions{
|
|
Version: data.FrameTypeVersion{0, 1},
|
|
Valid: util.Pointer(true),
|
|
Kind: data.KindTimeSeries,
|
|
NoData: util.Pointer(false),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
for _, example := range tsExamples.AsSlice() {
|
|
t.Run(example.Info().ID, func(t *testing.T) {
|
|
res, err := handleDataplaneTimeseries(example.Frames("A"))
|
|
require.NoError(t, err)
|
|
require.Len(t, res.Values, example.Info().ItemCount)
|
|
})
|
|
}
|
|
})
|
|
}
|