diff --git a/apps/advisor/go.mod b/apps/advisor/go.mod index 70c3e695347..fb3e8dbf3aa 100644 --- a/apps/advisor/go.mod +++ b/apps/advisor/go.mod @@ -10,7 +10,7 @@ require ( github.com/grafana/grafana v0.0.0-00010101000000-000000000000 github.com/grafana/grafana-app-sdk v0.48.2 github.com/grafana/grafana-app-sdk/logging v0.48.1 - github.com/grafana/grafana-plugin-sdk-go v0.282.0 + github.com/grafana/grafana-plugin-sdk-go v0.283.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0 github.com/stretchr/testify v1.11.1 k8s.io/apimachinery v0.34.2 diff --git a/apps/advisor/go.sum b/apps/advisor/go.sum index ca0ee360b74..189664f60b8 100644 --- a/apps/advisor/go.sum +++ b/apps/advisor/go.sum @@ -667,8 +667,8 @@ github.com/grafana/grafana-aws-sdk v1.3.0 h1:/bfJzP93rCel1GbWoRSq0oUo424MZXt8jAp github.com/grafana/grafana-aws-sdk v1.3.0/go.mod h1:VGycF0JkCGKND2O5je1ucOqPJ0ZNhZYzV3c2bNBAaGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1 h1:FFcEA01tW+SmuJIuDbHOdgUBL+d7DPrZ2N4zwzPhfGk= github.com/grafana/grafana-azure-sdk-go/v2 v2.3.1/go.mod h1:Oi4anANlCuTCc66jCyqIzfVbgLXFll8Wja+Y4vfANlc= -github.com/grafana/grafana-plugin-sdk-go v0.282.0 h1:9JT9E6T0h8HsK9emTZ5s01uCKaf0Ok4PjYbb7M/iOjM= -github.com/grafana/grafana-plugin-sdk-go v0.282.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= +github.com/grafana/grafana-plugin-sdk-go v0.283.0 h1:G7IHshAr30rLWV9FtX3iLlFTTlBhuOkfe7xVAoIP5rE= +github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= github.com/grafana/grafana/pkg/promlib v0.0.8/go.mod h1:U1ezG/MGaEPoThqsr3lymMPN5yIPdVTJnDZ+wcXT+ao= github.com/grafana/grafana/pkg/semconv v0.0.0-20250804150913-990f1c69ecc2 h1:A65jWgLk4Re28gIuZcpC0aTh71JZ0ey89hKGE9h543s= diff --git a/apps/dashboard/go.mod b/apps/dashboard/go.mod index c8315d44434..a175b696c57 100644 --- a/apps/dashboard/go.mod +++ b/apps/dashboard/go.mod @@ -7,7 +7,7 @@ require ( github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 github.com/grafana/grafana-app-sdk v0.48.2 github.com/grafana/grafana-app-sdk/logging v0.48.1 - github.com/grafana/grafana-plugin-sdk-go v0.282.0 + github.com/grafana/grafana-plugin-sdk-go v0.283.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/prometheus/client_golang v1.23.2 github.com/stretchr/testify v1.11.1 diff --git a/apps/dashboard/go.sum b/apps/dashboard/go.sum index 5c2d4405a26..867bf7e2697 100644 --- a/apps/dashboard/go.sum +++ b/apps/dashboard/go.sum @@ -89,8 +89,8 @@ github.com/grafana/grafana-app-sdk v0.48.2 h1:CQQDhwo1fWaXQVKvxxOcK6azbuY3E2TgJH github.com/grafana/grafana-app-sdk v0.48.2/go.mod h1:LDOvQ7OOyHLcXdSa0InATCa5OMoYAd6E1+rGLrMgHuk= github.com/grafana/grafana-app-sdk/logging v0.48.1 h1:veM0X5LAPyN3KsDLglWjIofndbGuf7MqnrDuDN+F/Ng= github.com/grafana/grafana-app-sdk/logging v0.48.1/go.mod h1:Gh/nBWnspK3oDNWtiM5qUF/fardHzOIEez+SPI3JeHA= -github.com/grafana/grafana-plugin-sdk-go v0.282.0 h1:9JT9E6T0h8HsK9emTZ5s01uCKaf0Ok4PjYbb7M/iOjM= -github.com/grafana/grafana-plugin-sdk-go v0.282.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= +github.com/grafana/grafana-plugin-sdk-go v0.283.0 h1:G7IHshAr30rLWV9FtX3iLlFTTlBhuOkfe7xVAoIP5rE= +github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= diff --git a/go.mod b/go.mod index aa04c633a7c..0139b0ae433 100644 --- a/go.mod +++ b/go.mod @@ -103,7 +103,7 @@ require ( github.com/grafana/grafana-cloud-migration-snapshot v1.9.0 // @grafana/grafana-operator-experience-squad github.com/grafana/grafana-google-sdk-go v0.4.2 // @grafana/partner-datasources github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 // @grafana/grafana-backend-group - github.com/grafana/grafana-plugin-sdk-go v0.282.0 // @grafana/plugins-platform-backend + github.com/grafana/grafana-plugin-sdk-go v0.283.0 // @grafana/plugins-platform-backend github.com/grafana/loki/pkg/push v0.0.0-20250823105456-332df2b20000 // @grafana/alerting-backend github.com/grafana/loki/v3 v3.2.1 // @grafana/observability-logs github.com/grafana/nanogit v0.0.0-20251106115617-c622d3e0fc4b // indirect; @grafana/grafana-git-ui-sync-team diff --git a/go.sum b/go.sum index 42d0ecd1703..238a14bff36 100644 --- a/go.sum +++ b/go.sum @@ -1647,8 +1647,8 @@ github.com/grafana/grafana-google-sdk-go v0.4.2 h1:F44hQF1y6UVJhlJPi+Mz+GCJsioVg github.com/grafana/grafana-google-sdk-go v0.4.2/go.mod h1:U73+w9DlbEtUonhQUzERwlXnzWTtfRoyrtKH8d3VY40= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79 h1:r+mU5bGMzcXCRVAuOrTn54S80qbfVkvTdUJZfSfTNbs= github.com/grafana/grafana-openapi-client-go v0.0.0-20231213163343-bd475d63fb79/go.mod h1:wc6Hbh3K2TgCUSfBC/BOzabItujtHMESZeFk5ZhdxhQ= -github.com/grafana/grafana-plugin-sdk-go v0.282.0 h1:9JT9E6T0h8HsK9emTZ5s01uCKaf0Ok4PjYbb7M/iOjM= -github.com/grafana/grafana-plugin-sdk-go v0.282.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= +github.com/grafana/grafana-plugin-sdk-go v0.283.0 h1:G7IHshAr30rLWV9FtX3iLlFTTlBhuOkfe7xVAoIP5rE= +github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b h1:6Bo65etvjQ4tStkaA5+N3A3ENbO4UAWj53TxF6g2Hdk= github.com/grafana/grafana/apps/example v0.0.0-20251027162426-edef69fdc82b/go.mod h1:6+wASOCN8LWt6FJ8dc0oODUBIEY5XHaE6ABi8g0mR+k= github.com/grafana/grafana/pkg/promlib v0.0.8 h1:VUWsqttdf0wMI4j9OX9oNrykguQpZcruudDAFpJJVw0= diff --git a/pkg/aggregator/go.mod b/pkg/aggregator/go.mod index b2ae6dc4df5..c1004c6a52f 100644 --- a/pkg/aggregator/go.mod +++ b/pkg/aggregator/go.mod @@ -4,7 +4,7 @@ go 1.25.3 require ( github.com/emicklei/go-restful/v3 v3.13.0 - github.com/grafana/grafana-plugin-sdk-go v0.282.0 + github.com/grafana/grafana-plugin-sdk-go v0.283.0 github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e github.com/grafana/grafana/pkg/semconv v0.0.0-20250514132646-acbc7b54ed9e github.com/mattbaird/jsonpatch v0.0.0-20240118010651-0ba75a80ca38 diff --git a/pkg/aggregator/go.sum b/pkg/aggregator/go.sum index 404c3743c70..9be90d153dc 100644 --- a/pkg/aggregator/go.sum +++ b/pkg/aggregator/go.sum @@ -101,8 +101,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= -github.com/grafana/grafana-plugin-sdk-go v0.282.0 h1:9JT9E6T0h8HsK9emTZ5s01uCKaf0Ok4PjYbb7M/iOjM= -github.com/grafana/grafana-plugin-sdk-go v0.282.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= +github.com/grafana/grafana-plugin-sdk-go v0.283.0 h1:G7IHshAr30rLWV9FtX3iLlFTTlBhuOkfe7xVAoIP5rE= +github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= github.com/grafana/grafana/pkg/semconv v0.0.0-20250514132646-acbc7b54ed9e h1:vheR6iPO1np+G/ARjcWx9yiWd7BnTDgyTgsnMhOvx70= diff --git a/pkg/apis/query/v0alpha1/query_test.go b/pkg/apis/query/v0alpha1/query_test.go index 279373079ce..368ebe8dd9e 100644 --- a/pkg/apis/query/v0alpha1/query_test.go +++ b/pkg/apis/query/v0alpha1/query_test.go @@ -73,7 +73,7 @@ func TestParseQueriesIntoQueryDataRequest(t *testing.T) { "maxDataPoints": 10, "queryType": "foo", "refId": "Z", - "_timeRange": { + "timeRange": { "from": "100", "to": "200" } diff --git a/pkg/promlib/go.mod b/pkg/promlib/go.mod index e472abd1ad3..27e09f912a4 100644 --- a/pkg/promlib/go.mod +++ b/pkg/promlib/go.mod @@ -4,7 +4,7 @@ go 1.25.3 require ( github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 - github.com/grafana/grafana-plugin-sdk-go v0.282.0 + github.com/grafana/grafana-plugin-sdk-go v0.283.0 github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134 github.com/json-iterator/go v1.1.12 github.com/prometheus/client_golang v1.23.2 diff --git a/pkg/promlib/go.sum b/pkg/promlib/go.sum index 04556e32c24..f32307ff8b3 100644 --- a/pkg/promlib/go.sum +++ b/pkg/promlib/go.sum @@ -130,8 +130,8 @@ github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81 github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI= github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4= -github.com/grafana/grafana-plugin-sdk-go v0.282.0 h1:9JT9E6T0h8HsK9emTZ5s01uCKaf0Ok4PjYbb7M/iOjM= -github.com/grafana/grafana-plugin-sdk-go v0.282.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= +github.com/grafana/grafana-plugin-sdk-go v0.283.0 h1:G7IHshAr30rLWV9FtX3iLlFTTlBhuOkfe7xVAoIP5rE= +github.com/grafana/grafana-plugin-sdk-go v0.283.0/go.mod h1:20qhoYxIgbZRmwCEO1KMP8q2yq/Kge5+xE/99/hLEk0= github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134 h1:xly75v5lFNR37q+wXnwA5yU/fPW9IOSYbhFpt4tQyt8= github.com/grafana/grafana/apps/scope v0.0.0-20251007093103-792853df9134/go.mod h1:zijsUNa1zi476JJIR2Lcm/Paz1nRCno9XCp6hbS6G9o= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20251007081214-26e147d01f0a h1:L7xgV9mP6MRF3L2/vDOjNR7heaBPbXPMGTDN9/jXSFQ= diff --git a/pkg/services/query/query.go b/pkg/services/query/query.go index 138812ebd03..34abc9a2dbf 100644 --- a/pkg/services/query/query.go +++ b/pkg/services/query/query.go @@ -333,12 +333,9 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden } func getTimeRange(query *simplejson.Json, globalFrom string, globalTo string) (string, string, error) { - tr, ok := query.CheckGet("_timeRange") - if !ok { // timeRange json node does not exist - tr, ok = query.CheckGet("timeRange") // try the old name for backward compatibility - if !ok { // timeRange json node does not exist, use global from/to - return globalFrom, globalTo, nil - } + tr, ok := query.CheckGet("timeRange") + if !ok { // timeRange json node does not exist, use global from/to + return globalFrom, globalTo, nil } from, err := tr.Get("from").String() if err != nil { @@ -352,6 +349,40 @@ func getTimeRange(query *simplejson.Json, globalFrom string, globalTo string) (s return from, to, nil } +const timeRangeKey = "timeRange" + +func queryToJson(query *simplejson.Json, supportLocalTimeRange bool) ([]byte, error) { + if !supportLocalTimeRange { + return query.MarshalJSON() + } + + // we need to remove the `timeRange` attribute from the JSON, if it exists there, + // because it might cause complications with certain data sources. + _, has := query.CheckGet(timeRangeKey) + if !has { + return query.MarshalJSON() + } + + qMap, err := query.Map() + if err != nil { + return nil, err + } + + // we do not want to modify the query, + // so we create a copy without + // the timeRange attribute + d := make(map[string]any) + + // without the `timeRange` attribute + for k, v := range qMap { + if k != timeRangeKey { + d[k] = v + } + } + + return simplejson.NewFromAny(d).MarshalJSON() +} + // parseRequest parses a request into parsed queries grouped by datasource uid func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requester, skipDSCache bool, reqDTO dtos.MetricRequest, supportLocalTimeRange bool) (*parsedRequest, error) { if len(reqDTO.Queries) == 0 { @@ -397,7 +428,7 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ timeRange = gtime.NewTimeRange(reqDTO.From, reqDTO.To) } - modelJSON, err := query.MarshalJSON() + modelJSON, err := queryToJson(query, supportLocalTimeRange) if err != nil { return nil, err } diff --git a/pkg/services/query/query_test.go b/pkg/services/query/query_test.go index 02a4dea4824..7763bdcaecf 100644 --- a/pkg/services/query/query_test.go +++ b/pkg/services/query/query_test.go @@ -334,62 +334,6 @@ func TestIntegrationParseMetricRequest(t *testing.T) { assert.Equal(t, int64(1753944629000), q.query.TimeRange.To.UnixMilli()) } }) - t.Run("Test a datasource query with local time range, old attribute-name", func(t *testing.T) { - tc := setup(t, false, nil) - mr := metricRequestWithQueries(t, `{ - "refId": "A", - "datasource": { - "uid": "gIEkMvIVz", - "type": "postgres" - }, - "timeRange": { - "from": "1753944618000", - "to": "1753944619000" - } - }`, `{ - "refId": "B", - "datasource": { - "uid": "gIEkMvIVz", - "type": "postgres" - }, - "timeRange": { - "from": "1753944628000", - "to": "1753944629000" - } - }`) - mr.From = "" - mr.To = "" - - verifyTimestamps := func(parsedReq *parsedRequest, ts1 int64, ts2 int64, ts3 int64, ts4 int64) { - require.NotNil(t, parsedReq) - assert.Len(t, parsedReq.parsedQueries, 1) - assert.Contains(t, parsedReq.parsedQueries, "gIEkMvIVz") - queries := parsedReq.getFlattenedQueries() - assert.Len(t, queries, 2) - - assert.Equal(t, ts1, queries[0].query.TimeRange.From.UnixMilli()) - assert.Equal(t, ts2, queries[0].query.TimeRange.To.UnixMilli()) - - assert.Equal(t, ts3, queries[1].query.TimeRange.From.UnixMilli()) - assert.Equal(t, ts4, queries[1].query.TimeRange.To.UnixMilli()) - } - - // with flag enabled - parsedReq, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true) - require.NoError(t, err) - - verifyTimestamps(parsedReq, - int64(1753944618000), - int64(1753944619000), - int64(1753944628000), - int64(1753944629000)) - - // with flag disabled - parsedReq2, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, false) - require.NoError(t, err) - - verifyTimestamps(parsedReq2, int64(0), int64(0), int64(0), int64(0)) - }) t.Run("Test a datasource query with local time range", func(t *testing.T) { tc := setup(t, false, nil) mr := metricRequestWithQueries(t, `{ @@ -408,43 +352,86 @@ func TestIntegrationParseMetricRequest(t *testing.T) { "uid": "gIEkMvIVz", "type": "postgres" }, - "_timeRange": { + "timeRange": { "from": "1753944628000", "to": "1753944629000" } + }`, `{ + "refId": "C", + "datasource": { + "uid": "gIEkMvIVz", + "type": "postgres" + } }`) - mr.From = "" - mr.To = "" + mr.From = "1753944638000" + mr.To = "1753944639000" - verifyTimestamps := func(parsedReq *parsedRequest, ts1 int64, ts2 int64, ts3 int64, ts4 int64) { + q0Copy := mr.Queries[0].DeepCopy() + q1Copy := mr.Queries[1].DeepCopy() + + verifyTimestamps := func( + parsedReq *parsedRequest, + ts1 int64, ts2 int64, q0JSON string, + ts3 int64, ts4 int64, q1JSON string, + ts5 int64, ts6 int64, q2JSON string, + ) { require.NotNil(t, parsedReq) assert.Len(t, parsedReq.parsedQueries, 1) assert.Contains(t, parsedReq.parsedQueries, "gIEkMvIVz") queries := parsedReq.getFlattenedQueries() - assert.Len(t, queries, 2) + assert.Len(t, queries, 3) + assert.Equal(t, "A", queries[0].query.RefID) assert.Equal(t, ts1, queries[0].query.TimeRange.From.UnixMilli()) assert.Equal(t, ts2, queries[0].query.TimeRange.To.UnixMilli()) + assert.JSONEq(t, q0JSON, string(queries[0].query.JSON)) + assert.Equal(t, "B", queries[1].query.RefID) assert.Equal(t, ts3, queries[1].query.TimeRange.From.UnixMilli()) assert.Equal(t, ts4, queries[1].query.TimeRange.To.UnixMilli()) + assert.JSONEq(t, q1JSON, string(queries[1].query.JSON)) + + assert.Equal(t, "C", queries[2].query.RefID) + assert.Equal(t, ts5, queries[2].query.TimeRange.From.UnixMilli()) + assert.Equal(t, ts6, queries[2].query.TimeRange.To.UnixMilli()) + assert.JSONEq(t, q2JSON, string(queries[2].query.JSON)) } // with flag enabled parsedReq, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true) require.NoError(t, err) + // verify the query-structures were not mutated + require.Equal(t, q0Copy, mr.Queries[0]) + require.Equal(t, q1Copy, mr.Queries[1]) + verifyTimestamps(parsedReq, int64(1753944618000), int64(1753944619000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"A"}`, int64(1753944628000), - int64(1753944629000)) + int64(1753944629000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"B"}`, + int64(1753944638000), + int64(1753944639000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"C"}`, + ) // with flag disabled parsedReq2, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, false) require.NoError(t, err) - verifyTimestamps(parsedReq2, int64(0), int64(0), int64(0), int64(0)) + verifyTimestamps(parsedReq2, + int64(1753944638000), + int64(1753944639000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"A", "timeRange":{"from":"1753944618000", "to":"1753944619000"}}`, + int64(1753944638000), + int64(1753944639000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"B", "timeRange":{"from":"1753944628000", "to":"1753944629000"}}`, + int64(1753944638000), + int64(1753944639000), + `{"datasource":{"type":"postgres","uid":"gIEkMvIVz"},"refId":"C"}`, + ) }) t.Run("Test a datasource query with local time range, malformed to-value", func(t *testing.T) { @@ -455,7 +442,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) { "uid": "gIEkMvIVz", "type": "postgres" }, - "_timeRange": { + "timeRange": { "from": "1753944618000", "to": 1753944619000 } @@ -474,7 +461,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) { "uid": "gIEkMvIVz", "type": "postgres" }, - "_timeRange": { + "timeRange": { "from": "1753944618000" } }`) @@ -492,7 +479,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) { "uid": "gIEkMvIVz", "type": "postgres" }, - "_timeRange": { + "timeRange": { "from": 1753944618000, "to": "1753944619000" } @@ -511,7 +498,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) { "uid": "gIEkMvIVz", "type": "postgres" }, - "_timeRange": { + "timeRange": { "to": "1753944619000" } }`) @@ -774,6 +761,69 @@ func TestIntegrationQueryDataWithQSDSClient(t *testing.T) { }) } +func TestQueryToJson(t *testing.T) { + tests := []struct { + name string + data []byte + expected []byte + expectedError bool + }{ + { + name: "simple", + data: []byte(`{"refId":"A", "expr": "42", "timeRange":{"from":"111","to":"112"}}`), + expected: []byte(`{"refId":"A", "expr": "42"}`), + expectedError: false, + }, + { + name: "no time range", + data: []byte(`{"refId":"A", "expr": "42"}`), + expected: []byte(`{"refId":"A", "expr": "42"}`), + expectedError: false, + }, + { + name: "nested structures, numbers", + data: []byte(`{"a":{"b":["c","d"]},"intervalMs":60000, "timeRange":{"from":"111","to":"112"}}`), + expected: []byte(`{"a":{"b":["c","d"]},"intervalMs":60000}`), + expectedError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + q, err := simplejson.NewJson(tt.data) + require.NoError(t, err) + + // first we go with supportLocalTimeRange=false + res, err := queryToJson(q, false) + require.NoError(t, err) + + // verify that we did not mutate the input + data2, err := q.MarshalJSON() + require.NoError(t, err) + require.JSONEq(t, string(data2), string(tt.data)) + + // verify the output is the same as the input (because we used supportLocalTimeRange=false) + require.JSONEq(t, string(res), string(tt.data)) + + // now we go with supportLocalTimeRange=true + + res, err = queryToJson(q, true) + if tt.expectedError { + require.Error(t, err) + } else { + require.NoError(t, err) + + require.JSONEq(t, string(tt.expected), string(res)) + } + + // verify that we did not mutate the input + data2, err = q.MarshalJSON() + require.NoError(t, err) + require.JSONEq(t, string(data2), string(tt.data)) + }) + } +} + func setup(t *testing.T, isMultiTenant bool, mockClient clientapi.QueryDataClient) *testContext { dss := []*datasources.DataSource{ {UID: "gIEkMvIVz", Type: "postgres"},