mirror of https://github.com/grafana/grafana.git
Query Service: Fix Time Bug (#108337)
This commit is contained in:
parent
7626508842
commit
f34127c449
|
|
@ -408,7 +408,12 @@ func (dn *DSNode) Execute(ctx context.Context, now time.Time, _ mathexp.Vars, s
|
|||
}
|
||||
} else {
|
||||
// transform request from backend.QueryDataRequest to k8s request
|
||||
k8sReq := &data.QueryDataRequest{}
|
||||
k8sReq := &data.QueryDataRequest{
|
||||
TimeRange: data.TimeRange{
|
||||
From: req.Queries[0].TimeRange.From.Format(time.RFC3339),
|
||||
To: req.Queries[0].TimeRange.To.Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
for _, q := range req.Queries {
|
||||
var dataQuery data.DataQuery
|
||||
err := json.Unmarshal(q.JSON, &dataQuery)
|
||||
|
|
|
|||
|
|
@ -64,3 +64,23 @@ func NewMtDatasourceClientBuilderWithClientSupplier(
|
|||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTestMTDSClientBuilder(isMultiTenant bool, mockClient clientapi.QueryDataClient) MTDatasourceClientBuilder {
|
||||
return &testBuilder{
|
||||
mockClient: mockClient,
|
||||
isMultitenant: isMultiTenant,
|
||||
}
|
||||
}
|
||||
|
||||
type testBuilder struct {
|
||||
mockClient clientapi.QueryDataClient
|
||||
isMultitenant bool
|
||||
}
|
||||
|
||||
func (b *testBuilder) BuildClient(pluginId string, uid string) (clientapi.QueryDataClient, bool) {
|
||||
if !b.isMultitenant {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return b.mockClient, true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,7 +295,12 @@ func (s *ServiceImpl) handleQuerySingleDatasource(ctx context.Context, user iden
|
|||
return s.pluginClient.QueryData(ctx, req)
|
||||
} else { // multi tenant flow
|
||||
// transform request from backend.QueryDataRequest to k8s request
|
||||
k8sReq := &data.QueryDataRequest{}
|
||||
k8sReq := &data.QueryDataRequest{
|
||||
TimeRange: data.TimeRange{
|
||||
From: req.Queries[0].TimeRange.From.Format(time.RFC3339),
|
||||
To: req.Queries[0].TimeRange.To.Format(time.RFC3339),
|
||||
},
|
||||
}
|
||||
for _, q := range req.Queries {
|
||||
var dataQuery data.DataQuery
|
||||
err := json.Unmarshal(q.JSON, &dataQuery)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
|
|
@ -24,6 +25,7 @@ import (
|
|||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/clientapi"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler"
|
||||
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
|
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||
|
|
@ -50,7 +52,7 @@ func TestMain(m *testing.M) {
|
|||
|
||||
func TestIntegrationParseMetricRequest(t *testing.T) {
|
||||
t.Run("Test a simple single datasource query", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -74,7 +76,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test a single datasource query with expressions", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -114,7 +116,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test a simple mixed datasource query", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -147,7 +149,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test a mixed datasource query with expressions", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -208,7 +210,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Header validation", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -250,7 +252,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("Test a duplicated refId", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
|
|
@ -271,7 +273,7 @@ func TestIntegrationParseMetricRequest(t *testing.T) {
|
|||
|
||||
func TestIntegrationQueryDataMultipleSources(t *testing.T) {
|
||||
t.Run("can query multiple datasources", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
query1, err := simplejson.NewJson([]byte(`
|
||||
{
|
||||
"datasource": {
|
||||
|
|
@ -320,7 +322,7 @@ func TestIntegrationQueryDataMultipleSources(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("can query multiple datasources with an expression present", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
query1, err := simplejson.NewJson([]byte(`
|
||||
{
|
||||
"datasource": {
|
||||
|
|
@ -386,7 +388,7 @@ func TestIntegrationQueryDataMultipleSources(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("error is returned in query when one of the queries fails", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
|
||||
query1, _ := simplejson.NewJson([]byte(`
|
||||
{
|
||||
|
|
@ -426,7 +428,7 @@ func TestIntegrationQueryDataMultipleSources(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("ignores a deprecated datasourceID", func(t *testing.T) {
|
||||
tc := setup(t)
|
||||
tc := setup(t, false, nil)
|
||||
query1, err := simplejson.NewJson([]byte(`
|
||||
{
|
||||
"datasource": {
|
||||
|
|
@ -452,7 +454,63 @@ func TestIntegrationQueryDataMultipleSources(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func setup(t *testing.T) *testContext {
|
||||
func TestIntegrationQueryDataWithMTDSClient(t *testing.T) {
|
||||
t.Run("can run a simple datasource query with a mt ds client", func(t *testing.T) {
|
||||
stubbedResponse := &backend.QueryDataResponse{Responses: make(backend.Responses)}
|
||||
testClient := &testClient{
|
||||
queryDataStubbedResponse: stubbedResponse,
|
||||
}
|
||||
tc := setup(t, true, testClient)
|
||||
mr := metricRequestWithQueries(t, `{
|
||||
"refId": "A",
|
||||
"datasource": {
|
||||
"uid": "gIEkMvIVz",
|
||||
"type": "postgres"
|
||||
}
|
||||
}`, `{
|
||||
"refId": "B",
|
||||
"datasource": {
|
||||
"uid": "gIEkMvIVz",
|
||||
"type": "postgres"
|
||||
}
|
||||
}`)
|
||||
mr.From = "2022-01-01"
|
||||
mr.To = "2022-01-02"
|
||||
ctx := context.Background()
|
||||
_, err := tc.queryService.QueryData(ctx, tc.signedInUser, true, mr)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, data.QueryDataRequest{
|
||||
TimeRange: data.TimeRange{
|
||||
From: "2022-01-01T00:00:00Z",
|
||||
To: "2022-01-02T00:00:00Z",
|
||||
},
|
||||
Queries: []data.DataQuery{
|
||||
{
|
||||
CommonQueryProperties: data.CommonQueryProperties{
|
||||
RefID: "A",
|
||||
Datasource: &data.DataSourceRef{
|
||||
Type: "postgres",
|
||||
UID: "gIEkMvIVz",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
CommonQueryProperties: data.CommonQueryProperties{
|
||||
RefID: "B",
|
||||
Datasource: &data.DataSourceRef{
|
||||
Type: "postgres",
|
||||
UID: "gIEkMvIVz",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Debug: false,
|
||||
}, testClient.queryDataLastCalledWith)
|
||||
})
|
||||
}
|
||||
|
||||
func setup(t *testing.T, isMultiTenant bool, mockClient clientapi.QueryDataClient) *testContext {
|
||||
dss := []*datasources.DataSource{
|
||||
{UID: "gIEkMvIVz", Type: "postgres"},
|
||||
{UID: "sEx6ZvSVk", Type: "testdata"},
|
||||
|
|
@ -468,24 +526,55 @@ func setup(t *testing.T) *testContext {
|
|||
sqlStore, cfg := db.InitTestDBWithCfg(t)
|
||||
secretsService := secretsmng.SetupTestService(t, fakes.NewFakeSecretsStore())
|
||||
ss := secretskvs.NewSQLSecretsKVStore(sqlStore, secretsService, log.New("test.logger"))
|
||||
|
||||
fakeDatasourceService := &fakeDatasources.FakeDataSourceService{
|
||||
DataSources: dss,
|
||||
SimulatePluginFailure: false,
|
||||
}
|
||||
|
||||
pCtxProvider := plugincontext.ProvideService(cfg,
|
||||
localcache.ProvideService(), &pluginstore.FakePluginStore{
|
||||
pCtxProvider := plugincontext.ProvideService(
|
||||
cfg,
|
||||
localcache.ProvideService(),
|
||||
&pluginstore.FakePluginStore{
|
||||
PluginList: []pluginstore.Plugin{
|
||||
{JSONData: plugins.JSONData{ID: "postgres"}},
|
||||
{JSONData: plugins.JSONData{ID: "testdata"}},
|
||||
{JSONData: plugins.JSONData{ID: "mysql"}},
|
||||
},
|
||||
}, &fakeDatasources.FakeCacheService{}, fakeDatasourceService,
|
||||
pluginSettings.ProvideService(sqlStore, secretsService), pluginconfig.NewFakePluginRequestConfigProvider(),
|
||||
},
|
||||
&fakeDatasources.FakeCacheService{},
|
||||
fakeDatasourceService,
|
||||
pluginSettings.ProvideService(sqlStore, secretsService),
|
||||
pluginconfig.NewFakePluginRequestConfigProvider(),
|
||||
)
|
||||
exprService := expr.ProvideService(&setting.Cfg{ExpressionsEnabled: true}, pc, pCtxProvider,
|
||||
featuremgmt.WithFeatures(), nil, tracing.InitializeTracerForTest(), mtdsclient.NewNullMTDatasourceClientBuilder())
|
||||
queryService := ProvideService(setting.NewCfg(), dc, exprService, rv, pc, pCtxProvider, mtdsclient.NewNullMTDatasourceClientBuilder()) // provider belonging to this package
|
||||
|
||||
var mtdsClientBuilder mtdsclient.MTDatasourceClientBuilder
|
||||
if isMultiTenant {
|
||||
mtdsClientBuilder = mtdsclient.NewTestMTDSClientBuilder(isMultiTenant, mockClient)
|
||||
} else {
|
||||
mtdsClientBuilder = mtdsclient.NewTestMTDSClientBuilder(false, nil)
|
||||
}
|
||||
|
||||
exprService := expr.ProvideService(
|
||||
&setting.Cfg{ExpressionsEnabled: true},
|
||||
pc,
|
||||
pCtxProvider,
|
||||
featuremgmt.WithFeatures(),
|
||||
nil,
|
||||
tracing.InitializeTracerForTest(),
|
||||
mtdsClientBuilder,
|
||||
)
|
||||
|
||||
queryService := ProvideService(
|
||||
setting.NewCfg(),
|
||||
dc,
|
||||
exprService,
|
||||
rv,
|
||||
pc,
|
||||
pCtxProvider,
|
||||
mtdsClientBuilder,
|
||||
)
|
||||
|
||||
return &testContext{
|
||||
pluginContext: pc,
|
||||
secretStore: ss,
|
||||
|
|
@ -573,3 +662,20 @@ func (c *fakePluginClient) QueryData(ctx context.Context, req *backend.QueryData
|
|||
|
||||
return &backend.QueryDataResponse{Responses: make(backend.Responses)}, nil
|
||||
}
|
||||
|
||||
type testClient struct {
|
||||
queryDataLastCalledWith data.QueryDataRequest
|
||||
queryDataStubbedResponse *backend.QueryDataResponse
|
||||
queryDataStubbedError error
|
||||
}
|
||||
|
||||
func (c *testClient) QueryData(ctx context.Context, req data.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
c.queryDataLastCalledWith = req
|
||||
if c.queryDataStubbedError != nil {
|
||||
return nil, c.queryDataStubbedError
|
||||
}
|
||||
if c.queryDataStubbedResponse != nil {
|
||||
return c.queryDataStubbedResponse, nil
|
||||
}
|
||||
return nil, errors.New("no response stubbed")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue