Query Service: Combine SSE handling in single tenant and multi tenant paths (#108041)
* parse via sse I need to figure out how to handle the pipeline.execute with our own client. I think this is important for MT reasons, just like using our own cache (via legacy) is important. parsing is done though! * WIP nonsense * horrible code but i think it works * Add support for sql expressions config settings * Cleanup: - remove spew from nodes.go - uncomment out plugin context and use in single tenant flow - make code more readable and add comments * Cleanup: - create separate file for mt ds client builder - ensure error handling is the same for both expressions and regular queries - other cleanup * not working but good thoughts * WIP, vector not working for non sse * super hacky but i think vectors work now * delete delete delete * Comments for future ref * break out query handling and start test * add prom debugger * clean up: remove comments and commented out bits * fix query_test * add prom debugger * create table-driven tests with testsdata files * Fix test * Add test * go mod?? * idk * Remove comment * go enterprise issue maybe * Fix codeowners * Delete * Remove test data * Clean up * logger * Remove go changes hopefully * idk go man * sad * idk i ran go mod tidy and this is what it wants * Fix readme, with much help from adam * some linting and testing errors * lint * fix lint * fix lint register.go * another lint * address lint in test * fix dead code and linters for query_test * Go mod? * Struggling with go mod * Fix test * Fix another test * Revert headers change * Its difficult to test this in OSS as it depends on functionality defined in enterprise, let's bring these tests back in some form in enterprise * Fix codeowners --------- Co-authored-by: Adam Simpson <adam@adamsimpson.net>
This commit is contained in:
co-authored by
Adam Simpson
parent
8acdc7e37b
commit
3fad863fd1
@@ -1,167 +0,0 @@
|
||||
package dashboards
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
data "github.com/grafana/grafana-plugin-sdk-go/experimental/apis/data/v0alpha1"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/tests/apis"
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testsuite.Run(m)
|
||||
}
|
||||
|
||||
func TestIntegrationSimpleQuery(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
|
||||
AppModeProduction: false, // dev mode required for datasource connections
|
||||
EnableFeatureToggles: []string{
|
||||
featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, // Required to start the example service
|
||||
},
|
||||
})
|
||||
|
||||
// Create a single datasource
|
||||
ds := helper.CreateDS(&datasources.AddDataSourceCommand{
|
||||
Name: "test",
|
||||
Type: datasources.DS_TESTDATA,
|
||||
UID: "test",
|
||||
OrgID: int64(1),
|
||||
})
|
||||
require.Equal(t, "test", ds.UID)
|
||||
|
||||
t.Run("Call query with expression", func(t *testing.T) {
|
||||
client := helper.Org1.Admin.RESTClient(t, &schema.GroupVersion{
|
||||
Group: "query.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
})
|
||||
|
||||
body, err := json.Marshal(&data.QueryDataRequest{
|
||||
Queries: []data.DataQuery{
|
||||
data.NewDataQuery(map[string]any{
|
||||
"refId": "X",
|
||||
"datasource": data.DataSourceRef{
|
||||
Type: "grafana-testdata-datasource",
|
||||
UID: ds.UID,
|
||||
},
|
||||
"scenarioId": "csv_content",
|
||||
"csvContent": "a\n1",
|
||||
}),
|
||||
data.NewDataQuery(map[string]any{
|
||||
"refId": "Y",
|
||||
"datasource": data.DataSourceRef{
|
||||
UID: "__expr__",
|
||||
},
|
||||
"type": "math",
|
||||
"expression": "$X + 2",
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
//t.Logf("%s", string(body))
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
result := client.Post().
|
||||
Namespace("default").
|
||||
Suffix("query").
|
||||
SetHeader("Content-type", "application/json").
|
||||
Body(body).
|
||||
Do(context.Background())
|
||||
|
||||
require.NoError(t, result.Error())
|
||||
|
||||
contentType := "?"
|
||||
result.ContentType(&contentType)
|
||||
require.Equal(t, "application/json", contentType)
|
||||
|
||||
body, err = result.Raw()
|
||||
require.NoError(t, err)
|
||||
t.Logf("OUT: %s", string(body))
|
||||
|
||||
rsp := &backend.QueryDataResponse{}
|
||||
err = json.Unmarshal(body, rsp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(rsp.Responses))
|
||||
|
||||
frameX := rsp.Responses["X"].Frames[0]
|
||||
frameY := rsp.Responses["Y"].Frames[0]
|
||||
|
||||
vX, _ := frameX.Fields[0].ConcreteAt(0)
|
||||
vY, _ := frameY.Fields[0].ConcreteAt(0)
|
||||
|
||||
require.Equal(t, int64(1), vX)
|
||||
require.Equal(t, float64(3), vY) // 1 + 2, but always float64
|
||||
})
|
||||
|
||||
t.Run("Gets an error with invalid queries", func(t *testing.T) {
|
||||
client := helper.Org1.Admin.RESTClient(t, &schema.GroupVersion{
|
||||
Group: "query.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
})
|
||||
|
||||
body, err := json.Marshal(&data.QueryDataRequest{
|
||||
Queries: []data.DataQuery{
|
||||
data.NewDataQuery(map[string]any{
|
||||
"refId": "Y",
|
||||
"datasource": data.DataSourceRef{
|
||||
UID: "__expr__",
|
||||
},
|
||||
"type": "math",
|
||||
"expression": "$X + 2", // invalid X does not exit
|
||||
}),
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
result := client.Post().
|
||||
Namespace("default").
|
||||
Suffix("query").
|
||||
SetHeader("Content-type", "application/json").
|
||||
Body(body).
|
||||
Do(context.Background())
|
||||
|
||||
body, err = result.Raw()
|
||||
//t.Logf("OUT: %s", string(body))
|
||||
|
||||
require.Error(t, err, "expecting a 400")
|
||||
require.JSONEq(t, `{
|
||||
"results": {
|
||||
"A": {
|
||||
"error": "[sse.dependencyError] did not execute expression [Y] due to a failure of the dependent expression or query [X]",
|
||||
"status": 400,
|
||||
"errorSource": ""
|
||||
}
|
||||
}
|
||||
}`, string(body))
|
||||
// require.JSONEq(t, `{
|
||||
// "status": "Failure",
|
||||
// "metadata": {},
|
||||
// "message": "did not execute expression [Y] due to a failure of the dependent expression or query [X]",
|
||||
// "reason": "BadRequest",
|
||||
// "details": { "group": "query.grafana.app" },
|
||||
// "code": 400,
|
||||
// "messageId": "sse.dependencyError",
|
||||
// "extra": { "depRefId": "X", "refId": "Y" }
|
||||
// }`, string(body))
|
||||
|
||||
statusCode := -1
|
||||
contentType := "?"
|
||||
result.ContentType(&contentType)
|
||||
result.StatusCode(&statusCode)
|
||||
require.Equal(t, "application/json", contentType)
|
||||
require.Equal(t, http.StatusBadRequest, statusCode)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user