datasources: strict local-time-range parsing (#109180)

* datasources: strict local-time-range parsing

* fixed unit test
This commit is contained in:
Gábor Farkas
2025-08-07 11:46:43 +02:00
committed by GitHub
parent da93f58921
commit 81531dcd7b
2 changed files with 74 additions and 27 deletions
+18 -9
View File
@@ -311,16 +311,21 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
}
}
func getTimeRange(query *simplejson.Json, globalFrom string, globalTo string) gtime.TimeRange {
from := query.Get("timeRange").Get("from").MustString("")
to := query.Get("timeRange").Get("to").MustString("")
if (from == "") && (to == "") {
from = globalFrom
to = globalTo
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, use global from/to
return globalFrom, globalTo, nil
}
from, err := tr.Get("from").String()
if err != nil {
return "", "", errors.New("time range: field 'from' is missing or invalid")
}
to, err := tr.Get("to").String()
if err != nil {
return "", "", errors.New("time range: field 'to' is missing or invalid")
}
return gtime.NewTimeRange(from, to)
return from, to, nil
}
// parseRequest parses a request into parsed queries grouped by datasource uid
@@ -359,7 +364,11 @@ func (s *ServiceImpl) parseMetricRequest(ctx context.Context, user identity.Requ
var timeRange gtime.TimeRange
if supportLocalTimeRange {
timeRange = getTimeRange(query, reqDTO.From, reqDTO.To)
from, to, err := getTimeRange(query, reqDTO.From, reqDTO.To)
if err != nil {
return nil, err
}
timeRange = gtime.NewTimeRange(from, to)
} else {
timeRange = gtime.NewTimeRange(reqDTO.From, reqDTO.To)
}
+56 -18
View File
@@ -391,7 +391,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
verifyTimestamps(parsedReq2, int64(0), int64(0), int64(0), int64(0))
})
t.Run("Test a datasource query with malformed local time range", func(t *testing.T) {
t.Run("Test a datasource query with local time range, malformed to-value", func(t *testing.T) {
tc := setup(t, false, nil)
mr := metricRequestWithQueries(t, `{
"refId": "A",
@@ -401,31 +401,69 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
},
"timeRange": {
"from": "1753944618000",
"not_to": "1753944619000"
"to": 1753944619000
}
}`, `{
"refId": "B",
}`)
mr.From = ""
mr.To = ""
_, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true)
require.Error(t, err)
require.ErrorContains(t, err, "'to'")
})
t.Run("Test a datasource query with local time range, missing to-value", func(t *testing.T) {
tc := setup(t, false, nil)
mr := metricRequestWithQueries(t, `{
"refId": "A",
"datasource": {
"uid": "gIEkMvIVz",
"type": "postgres"
},
"timeRange": 42
"timeRange": {
"from": "1753944618000"
}
}`)
mr.From = ""
mr.To = ""
parsedReq, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true)
require.NoError(t, err)
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, int64(1753944618000), queries[0].query.TimeRange.From.UnixMilli())
assert.Equal(t, int64(0), queries[0].query.TimeRange.To.UnixMilli())
assert.Equal(t, int64(0), queries[1].query.TimeRange.From.UnixMilli())
assert.Equal(t, int64(0), queries[1].query.TimeRange.To.UnixMilli())
_, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true)
require.Error(t, err)
require.ErrorContains(t, err, "'to'")
})
t.Run("Test a datasource query with local time range, malformed from-value", func(t *testing.T) {
tc := setup(t, false, nil)
mr := metricRequestWithQueries(t, `{
"refId": "A",
"datasource": {
"uid": "gIEkMvIVz",
"type": "postgres"
},
"timeRange": {
"from": 1753944618000,
"to": "1753944619000"
}
}`)
mr.From = ""
mr.To = ""
_, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true)
require.Error(t, err)
require.ErrorContains(t, err, "'from'")
})
t.Run("Test a datasource query with local time range, missing from-value", func(t *testing.T) {
tc := setup(t, false, nil)
mr := metricRequestWithQueries(t, `{
"refId": "A",
"datasource": {
"uid": "gIEkMvIVz",
"type": "postgres"
},
"timeRange": {
"to": "1753944619000"
}
}`)
mr.From = ""
mr.To = ""
_, err := tc.queryService.parseMetricRequest(context.Background(), tc.signedInUser, true, mr, true)
require.Error(t, err)
require.ErrorContains(t, err, "'from'")
})
}