mirror of
https://github.com/grafana/grafana.git
synced 2025-01-07 22:53:56 -06:00
155 lines
4.1 KiB
Go
155 lines
4.1 KiB
Go
package querydata_test
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/experimental"
|
|
sdkapi "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/promlib/models"
|
|
)
|
|
|
|
var update = true
|
|
|
|
func TestRangeResponses(t *testing.T) {
|
|
tt := []struct {
|
|
name string
|
|
filepath string
|
|
}{
|
|
{name: "parse a simple matrix response", filepath: "range_simple"},
|
|
{name: "parse a simple matrix response with value missing steps", filepath: "range_missing"},
|
|
{name: "parse a matrix response with Infinity", filepath: "range_infinity"},
|
|
{name: "parse a matrix response with NaN", filepath: "range_nan"},
|
|
{name: "parse a response with legendFormat __auto", filepath: "range_auto"},
|
|
}
|
|
|
|
for _, test := range tt {
|
|
queryFileName := filepath.Join("../testdata", test.filepath+".query.json")
|
|
responseFileName := filepath.Join("../testdata", test.filepath+".result.json")
|
|
goldenFileName := test.filepath + ".result.golden"
|
|
t.Run(test.name, goldenScenario(test.name, queryFileName, responseFileName, goldenFileName))
|
|
}
|
|
}
|
|
|
|
func TestExemplarResponses(t *testing.T) {
|
|
tt := []struct {
|
|
name string
|
|
filepath string
|
|
}{
|
|
{name: "parse an exemplar response", filepath: "exemplar"},
|
|
}
|
|
|
|
for _, test := range tt {
|
|
queryFileName := filepath.Join("../testdata", test.filepath+".query.json")
|
|
responseFileName := filepath.Join("../testdata", test.filepath+".result.json")
|
|
goldenFileName := test.filepath + ".result.golden"
|
|
t.Run(test.name, goldenScenario(test.name, queryFileName, responseFileName, goldenFileName))
|
|
}
|
|
}
|
|
|
|
func goldenScenario(name, queryFileName, responseFileName, goldenFileName string) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
query, err := loadStoredQuery(queryFileName)
|
|
require.NoError(t, err)
|
|
|
|
//nolint:gosec
|
|
responseBytes, err := os.ReadFile(responseFileName)
|
|
require.NoError(t, err)
|
|
|
|
result, err := runQuery(responseBytes, query)
|
|
require.NoError(t, err)
|
|
require.Len(t, result.Responses, 1)
|
|
|
|
dr, found := result.Responses["A"]
|
|
require.True(t, found)
|
|
|
|
experimental.CheckGoldenJSONResponse(t, "../testdata", goldenFileName, &dr, update)
|
|
}
|
|
}
|
|
|
|
// we store the prometheus query data in a json file, here is some minimal code
|
|
// to be able to read it back. unfortunately we cannot use the models.Query
|
|
// struct here, because it has `time.time` and `time.duration` fields that
|
|
// cannot be unmarshalled from JSON automatically.
|
|
type storedPrometheusQuery struct {
|
|
RefId string
|
|
RangeQuery bool
|
|
ExemplarQuery bool
|
|
Start int64
|
|
End int64
|
|
Step int64
|
|
Expr string
|
|
LegendFormat string
|
|
}
|
|
|
|
func loadStoredQuery(fileName string) (*backend.QueryDataRequest, error) {
|
|
//nolint:gosec
|
|
bytes, err := os.ReadFile(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var sq storedPrometheusQuery
|
|
|
|
err = json.Unmarshal(bytes, &sq)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
qm := models.QueryModel{
|
|
PrometheusQueryProperties: models.PrometheusQueryProperties{
|
|
Range: sq.RangeQuery,
|
|
Exemplar: sq.ExemplarQuery,
|
|
Expr: sq.Expr,
|
|
LegendFormat: sq.LegendFormat,
|
|
},
|
|
CommonQueryProperties: sdkapi.CommonQueryProperties{
|
|
IntervalMS: float64(sq.Step * 1000),
|
|
},
|
|
Interval: fmt.Sprintf("%ds", sq.Step),
|
|
}
|
|
|
|
data, err := json.Marshal(&qm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &backend.QueryDataRequest{
|
|
Queries: []backend.DataQuery{
|
|
{
|
|
TimeRange: backend.TimeRange{
|
|
From: time.Unix(sq.Start, 0),
|
|
To: time.Unix(sq.End, 0),
|
|
},
|
|
RefID: sq.RefId,
|
|
Interval: time.Second * time.Duration(sq.Step),
|
|
JSON: json.RawMessage(data),
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func runQuery(response []byte, q *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
|
tCtx, err := setup()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res := &http.Response{
|
|
StatusCode: 200,
|
|
Body: io.NopCloser(bytes.NewReader(response)),
|
|
}
|
|
tCtx.httpProvider.setResponse(res)
|
|
return tCtx.queryData.Execute(context.Background(), q)
|
|
}
|