The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/alerting/conditions/query_interval_test.go

187 lines
6.4 KiB

package conditions
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/datasources"
fd "github.com/grafana/grafana/pkg/services/datasources/fakes"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
"github.com/stretchr/testify/require"
)
func TestQueryInterval(t *testing.T) {
t.Run("When evaluating query condition, regarding the interval value", func(t *testing.T) {
t.Run("Can handle interval-calculation with no panel-min-interval and no datasource-min-interval", func(t *testing.T) {
// no panel-min-interval in the queryModel
queryModel := `{"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`
// no datasource-min-interval
var dataSourceJson *simplejson.Json = nil
timeRange := "5m"
verifier := func(query legacydata.DataSubQuery) {
// 5minutes timerange = 300000milliseconds; default-resolution is 1500pixels,
// so we should have 300000/1500 = 200milliseconds here
require.Equal(t, int64(200), query.IntervalMS)
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
}
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
})
t.Run("Can handle interval-calculation with panel-min-interval and no datasource-min-interval", func(t *testing.T) {
// panel-min-interval in the queryModel
queryModel := `{"interval":"123s", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`
// no datasource-min-interval
var dataSourceJson *simplejson.Json = nil
timeRange := "5m"
verifier := func(query legacydata.DataSubQuery) {
require.Equal(t, int64(123000), query.IntervalMS)
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
}
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
})
t.Run("Can handle interval-calculation with no panel-min-interval and datasource-min-interval", func(t *testing.T) {
// no panel-min-interval in the queryModel
queryModel := `{"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`
// min-interval in datasource-json
dataSourceJson, err := simplejson.NewJson([]byte(`{
"timeInterval": "71s"
}`))
require.Nil(t, err)
timeRange := "5m"
verifier := func(query legacydata.DataSubQuery) {
require.Equal(t, int64(71000), query.IntervalMS)
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
}
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
})
t.Run("Can handle interval-calculation with both panel-min-interval and datasource-min-interval", func(t *testing.T) {
// panel-min-interval in the queryModel
queryModel := `{"interval":"19s", "target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`
// min-interval in datasource-json
dataSourceJson, err := simplejson.NewJson([]byte(`{
"timeInterval": "71s"
}`))
require.Nil(t, err)
timeRange := "5m"
verifier := func(query legacydata.DataSubQuery) {
// when both panel-min-interval and datasource-min-interval exists,
// panel-min-interval is used
require.Equal(t, int64(19000), query.IntervalMS)
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
}
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
})
t.Run("Can handle no min-interval, and very small time-ranges, where the default-min-interval=1ms applies", func(t *testing.T) {
// no panel-min-interval in the queryModel
queryModel := `{"target": "aliasByNode(statsd.fakesite.counters.session_start.mobile.count, 4)"}`
// no datasource-min-interval
var dataSourceJson *simplejson.Json = nil
timeRange := "1s"
verifier := func(query legacydata.DataSubQuery) {
// no min-interval exists, the default-min-interval will be used,
// and for such a short time-range this will cause the value to be 1millisecond.
require.Equal(t, int64(1), query.IntervalMS)
require.Equal(t, intervalv2.DefaultRes, query.MaxDataPoints)
}
applyScenario(t, timeRange, dataSourceJson, queryModel, verifier)
})
})
}
type queryIntervalTestContext struct {
result *alerting.EvalContext
condition *QueryCondition
}
type queryIntervalVerifier func(query legacydata.DataSubQuery)
type fakeIntervalTestReqHandler struct {
//nolint: staticcheck // legacydata.DataResponse deprecated
response legacydata.DataResponse
verifier queryIntervalVerifier
}
//nolint: staticcheck // legacydata.DataResponse deprecated
func (rh fakeIntervalTestReqHandler) HandleRequest(ctx context.Context, dsInfo *datasources.DataSource, query legacydata.DataQuery) (
legacydata.DataResponse, error) {
q := query.Queries[0]
rh.verifier(q)
return rh.response, nil
}
//nolint: staticcheck // legacydata.DataResponse deprecated
func applyScenario(t *testing.T, timeRange string, dataSourceJsonData *simplejson.Json, queryModel string, verifier func(query legacydata.DataSubQuery)) {
t.Run("desc", func(t *testing.T) {
store := mockstore.NewSQLStoreMock()
ctx := &queryIntervalTestContext{}
ctx.result = &alerting.EvalContext{
Ctx: context.Background(),
Rule: &alerting.Rule{},
RequestValidator: &validations.OSSPluginRequestValidator{},
Store: store,
DatasourceService: &fd.FakeDataSourceService{
DataSources: []*datasources.DataSource{
{Id: 1, Type: datasources.DS_GRAPHITE, JsonData: dataSourceJsonData},
},
},
}
jsonModel, err := simplejson.NewJson([]byte(`{
"type": "query",
"query": {
"params": ["A", "` + timeRange + `", "now"],
"datasourceId": 1,
"model": ` + queryModel + `
},
"reducer":{"type": "avg"},
"evaluator":{"type": "gt", "params": [100]}
}`))
require.Nil(t, err)
condition, err := newQueryCondition(jsonModel, 0)
require.Nil(t, err)
ctx.condition = condition
qr := legacydata.DataQueryResult{}
reqHandler := fakeIntervalTestReqHandler{
response: legacydata.DataResponse{
Results: map[string]legacydata.DataQueryResult{
"A": qr,
},
},
verifier: verifier,
}
_, err = condition.Eval(ctx.result, reqHandler)
require.Nil(t, err)
})
}