Chore: Remove simplejson usage from the test data source (#71332)

This commit is contained in:
Andres Martinez Gotor 2023-07-11 15:13:09 +02:00 committed by GitHub
parent 6f102ccad0
commit 3dc0187b74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 120 additions and 98 deletions

View File

@ -165,7 +165,7 @@ func (s *Service) doReadQuery(ctx context.Context, query backend.DataQuery) back
func (s *Service) doRandomWalk(query backend.DataQuery) backend.DataResponse {
response := backend.DataResponse{}
model := simplejson.New()
model := testdatasource.JSONModel{}
response.Frames = data.Frames{testdatasource.RandomWalk(query, model, 0)}
return response

View File

@ -13,8 +13,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson"
)
const (
@ -233,18 +231,63 @@ func (s *Service) registerScenario(scenario *Scenario) {
s.queryMux.HandleFunc(scenario.ID, scenario.handler)
}
type JSONModel struct {
ScenarioID string `json:"scenarioId"`
SeriesCount int `json:"seriesCount"`
StringInput string `json:"stringInput"`
Lines int64 `json:"lines"`
IncludeLevelColumn bool `json:"includeLevelColumn"`
StartValue float64 `json:"startValue"`
Spread float64 `json:"spread"`
Noise float64 `json:"noise"`
Drop float64 `json:"drop"`
Min *float64 `json:"min,omitempty"`
Max *float64 `json:"max,omitempty"`
Labels string `json:"labels"`
WithNil bool `json:"withNil"`
PulseWave pulseWave `json:"pulseWave"`
Alias string `json:"alias"`
// Cannot specify a type for csvWave since legacy queries
// does not follow the same format as the new ones (and there is no migration).
CSVWave interface{} `json:"csvWave"`
}
type pulseWave struct {
TimeStep int64 `json:"timeStep"`
OnCount int64 `json:"onCount"`
OffCount int64 `json:"offCount"`
OnValue interface{} `json:"onValue"`
OffValue interface{} `json:"offValue"`
}
func getModel(j json.RawMessage) (JSONModel, error) {
model := JSONModel{
// Default values
ScenarioID: string(randomWalkQuery),
SeriesCount: 1,
Lines: 10,
StartValue: rand.Float64() * 100,
Spread: 1,
}
err := json.Unmarshal(j, &model)
if err != nil {
return JSONModel{}, err
}
return model, nil
}
// handleFallbackScenario handles the scenario where queryType is not set and fallbacks to scenarioId.
func (s *Service) handleFallbackScenario(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
scenarioQueries := map[string][]backend.DataQuery{}
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
s.logger.Error("Failed to unmarshal query model to JSON", "error", err)
continue
}
scenarioID := model.Get("scenarioId").MustString(string(randomWalkQuery))
scenarioID := model.ScenarioID
if _, exist := s.scenarios[scenarioID]; exist {
if _, ok := scenarioQueries[scenarioID]; !ok {
scenarioQueries[scenarioID] = []backend.DataQuery{}
@ -281,11 +324,11 @@ func (s *Service) handleRandomWalkScenario(ctx context.Context, req *backend.Que
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
seriesCount := model.Get("seriesCount").MustInt(1)
seriesCount := model.SeriesCount
for i := 0; i < seriesCount; i++ {
respD := resp.Responses[q.RefID]
@ -301,7 +344,7 @@ func (s *Service) handleDatapointsOutsideRangeScenario(ctx context.Context, req
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
@ -325,13 +368,12 @@ func (s *Service) handleCSVMetricValuesScenario(ctx context.Context, req *backen
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
stringInput := model.Get("stringInput").MustString()
stringInput := model.StringInput
valueField, err := csvLineToField(stringInput)
if err != nil {
return nil, err
@ -369,7 +411,7 @@ func (s *Service) handleRandomWalkWithErrorScenario(ctx context.Context, req *ba
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
@ -387,12 +429,12 @@ func (s *Service) handleRandomWalkSlowScenario(ctx context.Context, req *backend
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
stringInput := model.Get("stringInput").MustString()
stringInput := model.StringInput
parsedInterval, _ := time.ParseDuration(stringInput)
time.Sleep(parsedInterval)
@ -408,7 +450,7 @@ func (s *Service) handleRandomWalkTableScenario(ctx context.Context, req *backen
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
@ -425,7 +467,7 @@ func (s *Service) handlePredictableCSVWaveScenario(ctx context.Context, req *bac
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
return nil, err
}
@ -446,7 +488,7 @@ func (s *Service) handlePredictablePulseScenario(ctx context.Context, req *backe
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
@ -465,12 +507,12 @@ func (s *Service) handlePredictablePulseScenario(ctx context.Context, req *backe
func (s *Service) handleServerError500Scenario(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
stringInput := model.Get("stringInput").MustString()
stringInput := model.StringInput
if stringInput == "" {
panic("Test Data Panic!")
}
@ -487,7 +529,7 @@ func (s *Service) handleArrowScenario(ctx context.Context, req *backend.QueryDat
resp := backend.NewQueryDataResponse()
for _, q := range req.Queries {
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
return nil, err
}
@ -573,13 +615,13 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
from := q.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := q.TimeRange.To.UnixNano() / int64(time.Millisecond)
model, err := simplejson.NewJson(q.JSON)
model, err := getModel(q.JSON)
if err != nil {
continue
}
lines := model.Get("lines").MustInt64(10)
includeLevelColumn := model.Get("levelColumn").MustBool(false)
lines := model.Lines
includeLevelColumn := model.IncludeLevelColumn
logLevelGenerator := newRandomStringProvider([]string{
"emerg",
@ -651,19 +693,27 @@ func (s *Service) handleLogsScenario(ctx context.Context, req *backend.QueryData
return resp, nil
}
func RandomWalk(query backend.DataQuery, model *simplejson.Json, index int) *data.Frame {
func RandomWalk(query backend.DataQuery, model JSONModel, index int) *data.Frame {
rand := rand.New(rand.NewSource(time.Now().UnixNano() + int64(index)))
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
startValue := model.Get("startValue").MustFloat64(rand.Float64() * 100)
spread := model.Get("spread").MustFloat64(1)
noise := model.Get("noise").MustFloat64(0)
drop := model.Get("drop").MustFloat64(0) / 100.0 // value is 0-100
startValue := model.StartValue
spread := model.Spread
noise := model.Noise
drop := model.Drop / 100.0 // value is 0-100
min, err := model.Get("min").Float64()
hasMin := err == nil
max, err := model.Get("max").Float64()
hasMax := err == nil
min := float64(0)
hasMin := false
if model.Min != nil {
hasMin = true
min = *model.Min
}
max := float64(0)
hasMax := false
if model.Max != nil {
hasMax = true
max = *model.Max
}
timeVec := make([]*time.Time, 0)
floatVec := make([]*float64, 0)
@ -704,12 +754,12 @@ func RandomWalk(query backend.DataQuery, model *simplejson.Json, index int) *dat
)
}
func randomWalkTable(query backend.DataQuery, model *simplejson.Json) *data.Frame {
func randomWalkTable(query backend.DataQuery, model JSONModel) *data.Frame {
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
timeWalkerMs := query.TimeRange.From.UnixNano() / int64(time.Millisecond)
to := query.TimeRange.To.UnixNano() / int64(time.Millisecond)
withNil := model.Get("withNil").MustBool(false)
walker := model.Get("startValue").MustFloat64(rand.Float64() * 100)
withNil := model.WithNil
walker := model.StartValue
spread := 2.5
stateField := data.NewFieldFromFieldType(data.FieldTypeEnum, 0)
@ -784,14 +834,13 @@ type pCSVOptions struct {
Name string `json:"name"`
}
func predictableCSVWave(query backend.DataQuery, model *simplejson.Json) ([]*data.Frame, error) {
rawQueries, err := model.Get("csvWave").ToDB()
func predictableCSVWave(query backend.DataQuery, model JSONModel) ([]*data.Frame, error) {
queries := []pCSVOptions{}
input, err := json.Marshal(model.CSVWave)
if err != nil {
return nil, err
}
queries := []pCSVOptions{}
err = json.Unmarshal(rawQueries, &queries)
err = json.Unmarshal(input, &queries)
if err != nil {
return nil, err
}
@ -882,7 +931,7 @@ func predictableSeries(timeRange backend.TimeRange, timeStep, length int64, getV
}, nil
}
func predictablePulse(query backend.DataQuery, model *simplejson.Json) (*data.Frame, error) {
func predictablePulse(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
// Process Input
var timeStep int64
var onCount int64
@ -890,26 +939,20 @@ func predictablePulse(query backend.DataQuery, model *simplejson.Json) (*data.Fr
var onValue *float64
var offValue *float64
options := model.Get("pulseWave")
options := model.PulseWave
var err error
if timeStep, err = options.Get("timeStep").Int64(); err != nil {
return nil, fmt.Errorf("failed to parse timeStep value '%v' into integer: %v", options.Get("timeStep"), err)
}
if onCount, err = options.Get("onCount").Int64(); err != nil {
return nil, fmt.Errorf("failed to parse onCount value '%v' into integer: %v", options.Get("onCount"), err)
}
if offCount, err = options.Get("offCount").Int64(); err != nil {
return nil, fmt.Errorf("failed to parse offCount value '%v' into integer: %v", options.Get("offCount"), err)
}
timeStep = options.TimeStep
onCount = options.OnCount
offCount = options.OffCount
onValue, err = fromStringOrNumber(options.Get("onValue"))
onValue, err = fromStringOrNumber(options.OnValue)
if err != nil {
return nil, fmt.Errorf("failed to parse onValue value '%v' into float: %v", options.Get("onValue"), err)
return nil, fmt.Errorf("failed to parse onValue value '%v' into float: %v", options.OnValue, err)
}
offValue, err = fromStringOrNumber(options.Get("offValue"))
offValue, err = fromStringOrNumber(options.OffValue)
if err != nil {
return nil, fmt.Errorf("failed to parse offValue value '%v' into float: %v", options.Get("offValue"), err)
return nil, fmt.Errorf("failed to parse offValue value '%v' into float: %v", options.OffValue, err)
}
timeStep *= 1000 // Seconds to Milliseconds
@ -958,8 +1001,8 @@ func randomHeatmapData(query backend.DataQuery, fnBucketGen func(index int) floa
return frame
}
func doArrowQuery(query backend.DataQuery, model *simplejson.Json) (*data.Frame, error) {
encoded := model.Get("stringInput").MustString("")
func doArrowQuery(query backend.DataQuery, model JSONModel) (*data.Frame, error) {
encoded := model.StringInput
if encoded == "" {
return nil, nil
}
@ -970,8 +1013,8 @@ func doArrowQuery(query backend.DataQuery, model *simplejson.Json) (*data.Frame,
return data.UnmarshalArrowFrame(arrow)
}
func newSeriesForQuery(query backend.DataQuery, model *simplejson.Json, index int) *data.Frame {
alias := model.Get("alias").MustString("")
func newSeriesForQuery(query backend.DataQuery, model JSONModel, index int) *data.Frame {
alias := model.Alias
suffix := ""
if index > 0 {
@ -998,9 +1041,8 @@ func newSeriesForQuery(query backend.DataQuery, model *simplejson.Json, index in
*
* '{job="foo", instance="bar"} => {job: "foo", instance: "bar"}`
*/
func parseLabels(model *simplejson.Json, seriesIndex int) data.Labels {
labelText := model.Get("labels").MustString("")
return parseLabelsString(labelText, seriesIndex)
func parseLabels(model JSONModel, seriesIndex int) data.Labels {
return parseLabelsString(model.Labels, seriesIndex)
}
func parseLabelsString(labelText string, seriesIndex int) data.Labels {
@ -1027,8 +1069,8 @@ func parseLabelsString(labelText string, seriesIndex int) data.Labels {
return tags
}
func frameNameForQuery(query backend.DataQuery, model *simplejson.Json, index int) string {
name := model.Get("alias").MustString("")
func frameNameForQuery(query backend.DataQuery, model JSONModel, index int) string {
name := model.Alias
suffix := ""
if index > 0 {
@ -1050,13 +1092,10 @@ func frameNameForQuery(query backend.DataQuery, model *simplejson.Json, index in
return name
}
func fromStringOrNumber(val *simplejson.Json) (*float64, error) {
switch v := val.Interface().(type) {
case json.Number:
fV, err := v.Float64()
if err != nil {
return nil, err
}
func fromStringOrNumber(val interface{}) (*float64, error) {
switch v := val.(type) {
case float64:
fV := val.(float64)
return &fV, nil
case string:
switch v {

View File

@ -12,7 +12,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
)
@ -23,11 +22,6 @@ func TestTestdataScenarios(t *testing.T) {
t.Run("Should start at the requested value", func(t *testing.T) {
timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
model := simplejson.New()
model.Set("startValue", 1.234)
modelBytes, err := model.MarshalJSON()
require.NoError(t, err)
query := backend.DataQuery{
RefID: "A",
TimeRange: backend.TimeRange{
@ -36,7 +30,7 @@ func TestTestdataScenarios(t *testing.T) {
},
Interval: 100 * time.Millisecond,
MaxDataPoints: 100,
JSON: modelBytes,
JSON: []byte(`{"startValue": 1.234}`),
}
req := &backend.QueryDataRequest{
@ -67,10 +61,6 @@ func TestTestdataScenarios(t *testing.T) {
t.Run("Should return a table that looks like value/min/max", func(t *testing.T) {
timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
model := simplejson.New()
modelBytes, err := model.MarshalJSON()
require.NoError(t, err)
query := backend.DataQuery{
RefID: "A",
TimeRange: backend.TimeRange{
@ -79,7 +69,7 @@ func TestTestdataScenarios(t *testing.T) {
},
Interval: 100 * time.Millisecond,
MaxDataPoints: 100,
JSON: modelBytes,
JSON: []byte(`{}`),
}
req := &backend.QueryDataRequest{
@ -121,12 +111,6 @@ func TestTestdataScenarios(t *testing.T) {
t.Run("Should return a table with some nil values", func(t *testing.T) {
timeRange := legacydata.DataTimeRange{From: "5m", To: "now", Now: time.Now()}
model := simplejson.New()
model.Set("withNil", true)
modelBytes, err := model.MarshalJSON()
require.NoError(t, err)
query := backend.DataQuery{
RefID: "A",
TimeRange: backend.TimeRange{
@ -135,7 +119,7 @@ func TestTestdataScenarios(t *testing.T) {
},
Interval: 100 * time.Millisecond,
MaxDataPoints: 100,
JSON: modelBytes,
JSON: []byte(`{"withNil": true}`),
}
req := &backend.QueryDataRequest{
@ -199,32 +183,32 @@ func TestParseLabels(t *testing.T) {
tests := []struct {
name string
model map[string]interface{}
model JSONModel
expected data.Labels
}{
{
name: "wrapped in {} and quoted value ",
model: map[string]interface{}{"labels": `{job="foo", instance="bar"}`},
model: JSONModel{Labels: `{job="foo", instance="bar"}`},
expected: expectedTags,
},
{
name: "comma-separated non-quoted",
model: map[string]interface{}{"labels": `job=foo, instance=bar`},
model: JSONModel{Labels: `job=foo, instance=bar`},
expected: expectedTags,
},
{
name: "comma-separated quoted",
model: map[string]interface{}{"labels": `job="foo"", instance="bar"`},
model: JSONModel{Labels: `job="foo"", instance="bar"`},
expected: expectedTags,
},
{
name: "comma-separated with spaces, non quoted",
model: map[string]interface{}{"labels": `job = foo,instance = bar`},
model: JSONModel{Labels: `job = foo,instance = bar`},
expected: expectedTags,
},
{
name: "expands $seriesIndex",
model: map[string]interface{}{"labels": `job=series-$seriesIndex,instance=bar`},
model: JSONModel{Labels: `job=series-$seriesIndex,instance=bar`},
expected: data.Labels{
"job": fmt.Sprintf("series-%d", seriesIndex),
"instance": "bar",
@ -234,8 +218,7 @@ func TestParseLabels(t *testing.T) {
for i, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
model := simplejson.NewFromAny(tc.model)
assert.Equal(t, tc.expected, parseLabels(model, seriesIndex), fmt.Sprintf("Actual tags in test case %d doesn't match expected tags", i+1))
assert.Equal(t, tc.expected, parseLabels(tc.model, seriesIndex), fmt.Sprintf("Actual tags in test case %d doesn't match expected tags", i+1))
})
}
}