Skip to content

Commit

Permalink
handle url from settings when filling the default query (#1057)
Browse files Browse the repository at this point in the history
Co-authored-by: Ivana Huckova <[email protected]>
  • Loading branch information
yesoreyeram and ivanahuckova authored Nov 22, 2024
1 parent d44d3bd commit 6565b85
Show file tree
Hide file tree
Showing 7 changed files with 53 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .changeset/metal-cows-lie.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'grafana-infinity-datasource': patch
---

Fixed a bug where base url not working as expected when there is no url in the query. Fixes [#908](https://github.com/grafana/grafana-infinity-datasource/issues/908)
27 changes: 10 additions & 17 deletions pkg/models/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ type InfinityDataOverride struct {
Override string `json:"override"`
}

func ApplyDefaultsToQuery(ctx context.Context, query Query) Query {
func ApplyDefaultsToQuery(ctx context.Context, query Query, settings InfinitySettings) Query {
if query.Type == "" {
query.Type = QueryTypeJSON
if query.Source == "" {
Expand All @@ -198,20 +198,13 @@ func ApplyDefaultsToQuery(ctx context.Context, query Query) Query {
if query.Type == QueryTypeJSON && query.Source == "inline" && query.Data == "" {
query.Data = "[]"
}
if (query.Type == QueryTypeJSON || query.Type == QueryTypeGraphQL || query.Type == QueryTypeUQL || query.Type == QueryTypeGROQ) && query.Source == "url" && query.URL == "" {
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.json"
}
if query.Type == QueryTypeCSV && query.Source == "url" && query.URL == "" {
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.csv"
}
if query.Type == QueryTypeTSV && query.Source == "url" && query.URL == "" {
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.tsv"
}
if query.Type == QueryTypeXML && query.Source == "url" && query.URL == "" {
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.xml"
}
if query.Type == QueryTypeHTML && query.Source == "url" && query.URL == "" {
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.html"
if query.Source == "url" && query.URL == "" && strings.TrimSpace(settings.URL) == "" {
switch query.Type {
case QueryTypeJSON, QueryTypeCSV, QueryTypeTSV, QueryTypeXML, QueryTypeHTML:
query.URL = fmt.Sprintf("https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.%s", strings.ToLower(string(query.Type)))
case QueryTypeGraphQL, QueryTypeUQL, QueryTypeGROQ:
query.URL = "https://raw.githubusercontent.com/grafana/grafana-infinity-datasource/main/testdata/users.json"
}
}
if query.Source == "url" && strings.ToUpper(query.URLOptions.Method) == "POST" {
if query.URLOptions.BodyType == "" {
Expand Down Expand Up @@ -306,13 +299,13 @@ func ApplyDefaultsToQuery(ctx context.Context, query Query) Query {
return query
}

func LoadQuery(ctx context.Context, backendQuery backend.DataQuery, pluginContext backend.PluginContext) (Query, error) {
func LoadQuery(ctx context.Context, backendQuery backend.DataQuery, pluginContext backend.PluginContext, settings InfinitySettings) (Query, error) {
var query Query
err := json.Unmarshal(backendQuery.JSON, &query)
if err != nil {
return query, errorsource.DownstreamError(fmt.Errorf("error while parsing the query json. %w", err), false)
}
query = ApplyDefaultsToQuery(ctx, query)
query = ApplyDefaultsToQuery(ctx, query, settings)
if query.PageMode == PaginationModeList && strings.TrimSpace(query.PageParamListFieldName) == "" {
// Downstream error as user input is not correct
return query, errorsource.DownstreamError(errors.New("pagination_param_list_field_name cannot be empty"), false)
Expand Down
3 changes: 2 additions & 1 deletion pkg/models/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ func TestLoadQuery(t *testing.T) {
tests := []struct {
name string
queryJSON string
settings models.InfinitySettings
want models.Query
wantErr error
}{
Expand Down Expand Up @@ -121,7 +122,7 @@ func TestLoadQuery(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
q := &backend.DataQuery{JSON: []byte(tt.queryJSON)}
got, err := models.LoadQuery(context.Background(), *q, backend.PluginContext{})
got, err := models.LoadQuery(context.Background(), *q, backend.PluginContext{}, tt.settings)
if tt.wantErr != nil {
require.NotNil(t, err)
assert.Equal(t, tt.wantErr, err)
Expand Down
19 changes: 1 addition & 18 deletions pkg/pluginhost/handler_querydata.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (ds *DataSource) QueryData(ctx context.Context, req *backend.QueryDataReque
return response, errorsource.PluginError(errors.New("invalid infinity client"), false)
}
for _, q := range req.Queries {
query, err := models.LoadQuery(ctx, q, req.PluginContext)
query, err := models.LoadQuery(ctx, q, req.PluginContext, ds.client.Settings)
if err != nil {
span.RecordError(err)
logger.Error("error un-marshaling the query", "error", err.Error())
Expand All @@ -51,23 +51,6 @@ func (ds *DataSource) QueryData(ctx context.Context, req *backend.QueryDataReque
return response, nil
}

func QueryData(ctx context.Context, backendQuery backend.DataQuery, infClient infinity.Client, requestHeaders map[string]string, pluginContext backend.PluginContext) (response backend.DataResponse) {
logger := backend.Logger.FromContext(ctx)
ctx, span := tracing.DefaultTracer().Start(ctx, "QueryData")
defer span.End()
query, err := models.LoadQuery(ctx, backendQuery, pluginContext)
if err != nil {
span.RecordError(err)
span.SetStatus(500, err.Error())
logger.Error("error un-marshaling the query", "error", err.Error())
response.Error = fmt.Errorf("error un-marshaling the query. %w", err)
// We should have error source from the original error, but in a case it is not there, we are using the plugin error as the default source
response.ErrorSource = errorsource.SourceError(backend.ErrorSourcePlugin, err, false).Source()
return response
}
return QueryDataQuery(ctx, query, infClient, requestHeaders, pluginContext)
}

func QueryDataQuery(ctx context.Context, query models.Query, infClient infinity.Client, requestHeaders map[string]string, pluginContext backend.PluginContext) (response backend.DataResponse) {
logger := backend.Logger.FromContext(ctx)
ctx, span := tracing.DefaultTracer().Start(ctx, "QueryDataQuery", trace.WithAttributes(
Expand Down
9 changes: 4 additions & 5 deletions pkg/testsuite/handler_querydata_errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/grafana/grafana-infinity-datasource/pkg/infinity"
"github.com/grafana/grafana-infinity-datasource/pkg/models"
"github.com/grafana/grafana-infinity-datasource/pkg/pluginhost"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/infinity-libs/lib/go/jsonframer"
"github.com/stretchr/testify/require"
Expand All @@ -25,7 +24,7 @@ func TestErrors(t *testing.T) {
server.Start()
defer server.Close()
client, _ := infinity.NewClient(context.TODO(), models.InfinitySettings{})
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{ "url": "%s" }`, server.URL)),
}, *client, map[string]string{}, backend.PluginContext{})
require.Nil(t, res.Error)
Expand All @@ -38,7 +37,7 @@ func TestErrors(t *testing.T) {
server.Start()
defer server.Close()
client, _ := infinity.NewClient(context.TODO(), models.InfinitySettings{})
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{ "url": "%s" }`, server.URL)),
}, *client, map[string]string{}, backend.PluginContext{})
require.NotNil(t, res.Error)
Expand All @@ -54,7 +53,7 @@ func TestErrors(t *testing.T) {
server.Start()
defer server.Close()
client, _ := infinity.NewClient(context.TODO(), models.InfinitySettings{})
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{ "url": "%s" }`, server.URL)),
}, *client, map[string]string{}, backend.PluginContext{})
require.NotNil(t, res.Error)
Expand All @@ -70,7 +69,7 @@ func TestErrors(t *testing.T) {
server.Start()
defer server.Close()
client, _ := infinity.NewClient(context.TODO(), models.InfinitySettings{})
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{ "url": "%s", "parser": "backend", "root_selector": "foo bar baz"}`, server.URL)),
}, *client, map[string]string{}, backend.PluginContext{})
require.NotNil(t, res.Error)
Expand Down
53 changes: 30 additions & 23 deletions pkg/testsuite/handler_querydata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ import (
"github.com/stretchr/testify/require"
)

func queryData(t *testing.T, ctx context.Context, backendQuery backend.DataQuery, infClient infinity.Client, requestHeaders map[string]string, pluginContext backend.PluginContext) (response backend.DataResponse) {
t.Helper()
query, err := models.LoadQuery(ctx, backendQuery, pluginContext, infClient.Settings)
require.Nil(t, err)
return pluginhost.QueryDataQuery(ctx, query, infClient, requestHeaders, pluginContext)
}

func TestAuthentication(t *testing.T) {
t.Run("should throw error when allowed hosts not configured", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -29,7 +36,7 @@ func TestAuthentication(t *testing.T) {
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{AuthenticationMethod: models.AuthenticationMethodApiKey})
require.Nil(t, err)
require.NotNil(t, client)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -59,7 +66,7 @@ func TestAuthentication(t *testing.T) {
Password: "myPassword",
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -94,7 +101,7 @@ func TestAuthentication(t *testing.T) {
Password: "myIncorrectPassword",
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -124,7 +131,7 @@ func TestAuthentication(t *testing.T) {
ForwardOauthIdentity: true,
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand All @@ -148,7 +155,7 @@ func TestAuthentication(t *testing.T) {
ForwardOauthIdentity: false,
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -188,7 +195,7 @@ func TestAuthentication(t *testing.T) {
},
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"source": "url",
Expand Down Expand Up @@ -228,7 +235,7 @@ func TestAuthentication(t *testing.T) {
},
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"source": "url",
Expand Down Expand Up @@ -263,7 +270,7 @@ func TestAuthentication(t *testing.T) {
TLSCACert: mockPEMClientCACet,
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -294,7 +301,7 @@ func TestAuthentication(t *testing.T) {
InsecureSkipVerify: true,
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand All @@ -319,7 +326,7 @@ func TestAuthentication(t *testing.T) {
AllowedHosts: []string{"http://httpbin.org/digest-auth"},
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand All @@ -337,7 +344,7 @@ func TestAuthentication(t *testing.T) {
AllowedHosts: []string{"http://httpbin.org/digest-auth"},
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand All @@ -355,7 +362,7 @@ func TestAuthentication(t *testing.T) {
AllowedHosts: []string{"http://httpbin.org/digest-auth"},
})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand All @@ -378,7 +385,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -442,7 +449,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "json",
"url": "%s",
Expand Down Expand Up @@ -478,7 +485,7 @@ func TestResponseFormats(t *testing.T) {
t.Run("should parse the computed columns", func(t *testing.T) {
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: ""})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(`{
"type": "json",
"data": "[{ \"Name\": \"amc ambassador dpl\", \"Miles_per_Gallon\": 15, \"Cylinders\": 8, \"Displacement\": 390, \"Horsepower\": 190, \"Weight_in_lbs\": 3850, \"Acceleration\": 8.5, \"Year\": \"1970-01-01\", \"Origin\": \"USA\" }, { \"Name\": \"citroen ds-21 pallas\", \"Miles_per_Gallon\": null, \"Cylinders\": null, \"Displacement\": 133, \"Horsepower\": 115, \"Weight_in_lbs\": 3090, \"Acceleration\": 17.5, \"Year\": \"1970-01-01\", \"Origin\": \"Europe\" }, { \"Name\": \"chevrolet hello concours (sw)\", \"Miles_per_Gallon\": null, \"Cylinders\": 8, \"Displacement\": 350, \"Horsepower\": 165, \"Weight_in_lbs\": 4142, \"Acceleration\": 11.5, \"Year\": \"1970-01-01\", \"Origin\": \"USA\" }]",
Expand All @@ -496,7 +503,7 @@ func TestResponseFormats(t *testing.T) {
t.Run("should filter computed columns", func(t *testing.T) {
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: ""})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(`{
"type": "json",
"data": "[{\"id\":0,\"name\":\"iPhone 6S\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/phone/6s/images/goldbig.jpg\",\"price\":799},{\"id\":1,\"name\":\"iPhone 5S\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/phone/5s/images/silverbig.png\",\"price\":349},{\"id\":2,\"name\":\"Macbook\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/mac/macbook/images/pro.jpg\",\"price\":1499},{\"id\":3,\"name\":\"Macbook Air\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/mac/mbair/images/air.jpg\",\"price\":999},{\"id\":4,\"name\":\"Macbook Air 2013\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/mac/mbair/images/air.jpg\",\"price\":599},{\"id\":5,\"name\":\"Macbook Air 2012\",\"description\":\"Kogi skateboard tattooed, whatever portland fingerstache coloring book mlkshk leggings flannel dreamcatcher.\",\"imageUrl\":\"http://www.icentar.me/mac/mbair/images/air.jpg\",\"price\":499}]",
Expand All @@ -522,7 +529,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "graphql",
"url": "%s",
Expand All @@ -548,7 +555,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "uql",
"url": "%s",
Expand All @@ -574,7 +581,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "xml",
"url": "%s",
Expand All @@ -600,7 +607,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "uql",
"url": "%s",
Expand All @@ -626,7 +633,7 @@ func TestResponseFormats(t *testing.T) {
defer server.Close()
client, err := infinity.NewClient(context.TODO(), models.InfinitySettings{URL: server.URL})
require.Nil(t, err)
res := pluginhost.QueryData(context.Background(), backend.DataQuery{
res := queryData(t, context.Background(), backend.DataQuery{
JSON: []byte(fmt.Sprintf(`{
"type": "groq",
"url": "%s",
Expand Down Expand Up @@ -754,7 +761,7 @@ func TestInlineSources(t *testing.T) {
queryJSON = "{}"
}
bq := backend.DataQuery{JSON: []byte(queryJSON), TimeRange: tt.timeRange}
query, err := models.LoadQuery(context.Background(), bq, backend.PluginContext{})
query, err := models.LoadQuery(context.Background(), bq, backend.PluginContext{}, models.InfinitySettings{})
require.Nil(t, err)
frame, err := infinity.GetFrameForInlineSources(context.TODO(), query)
if tt.wantErr != nil {
Expand Down Expand Up @@ -924,7 +931,7 @@ func TestRemoteSources(t *testing.T) {
queryJSON = "{}"
}
bq := backend.DataQuery{JSON: []byte(queryJSON), TimeRange: tt.timeRange}
query, err := models.LoadQuery(context.Background(), bq, backend.PluginContext{})
query, err := models.LoadQuery(context.Background(), bq, backend.PluginContext{}, models.InfinitySettings{})
require.Nil(t, err)
client := tt.client
if client == nil {
Expand Down
Loading

0 comments on commit 6565b85

Please sign in to comment.