2021-03-17 12:10:40 -05:00
|
|
|
package datasourceproxy
|
2018-10-03 05:55:01 -05:00
|
|
|
|
|
|
|
import (
|
2023-08-16 04:58:41 -05:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
2018-10-03 05:55:01 -05:00
|
|
|
"testing"
|
|
|
|
|
2023-08-16 04:58:41 -05:00
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
"github.com/grafana/grafana/pkg/plugins"
|
|
|
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
2023-09-11 06:59:24 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
2023-08-16 04:58:41 -05:00
|
|
|
"github.com/grafana/grafana/pkg/web"
|
2020-11-17 04:31:35 -06:00
|
|
|
"github.com/stretchr/testify/assert"
|
2023-08-16 04:58:41 -05:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-10-03 05:55:01 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestDataProxy(t *testing.T) {
|
2021-03-17 06:17:41 -05:00
|
|
|
t.Run("extractProxyPath", func(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
originalRawPath string
|
|
|
|
exp string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
"/api/datasources/proxy/1",
|
|
|
|
"",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"/api/datasources/proxy/1/some/thing",
|
|
|
|
"some/thing",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"/api/datasources/proxy/54/api/services/afsd%2Fafsd/operations",
|
|
|
|
"api/services/afsd%2Fafsd/operations",
|
|
|
|
},
|
2022-04-14 05:28:13 -05:00
|
|
|
{
|
|
|
|
"/api/datasources/proxy/uid/26MI0wZ7k",
|
|
|
|
"",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"/api/datasources/proxy/uid/26MI0wZ7k/some/thing",
|
|
|
|
"some/thing",
|
|
|
|
},
|
2023-01-24 10:15:52 -06:00
|
|
|
{
|
|
|
|
"/api/datasources/proxy/uid/pUWo-no4k/search",
|
|
|
|
"search",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"/api/datasources/proxy/uid/pUWo_no4k/search",
|
|
|
|
"search",
|
|
|
|
},
|
2022-04-14 05:28:13 -05:00
|
|
|
{
|
|
|
|
"/api/datasources/proxy/uid/26MI0wZ7k/api/services/afsd%2Fafsd/operations",
|
|
|
|
"api/services/afsd%2Fafsd/operations",
|
|
|
|
},
|
2021-03-17 06:17:41 -05:00
|
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run("Given raw path, should extract expected proxy path", func(t *testing.T) {
|
|
|
|
assert.Equal(t, tc.exp, extractProxyPath(tc.originalRawPath))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
2018-10-03 05:55:01 -05:00
|
|
|
}
|
2023-08-16 04:58:41 -05:00
|
|
|
|
|
|
|
// Tests request to datasource proxy service
|
|
|
|
func TestDatasourceProxy_proxyDatasourceRequest(t *testing.T) {
|
|
|
|
tcs := []struct {
|
2023-10-30 13:06:26 -05:00
|
|
|
name string
|
|
|
|
dsURL string
|
2023-08-16 04:58:41 -05:00
|
|
|
}{
|
|
|
|
{
|
2023-10-30 13:06:26 -05:00
|
|
|
name: "Empty datasource URL will return a 400 HTTP status code",
|
|
|
|
dsURL: "",
|
2023-08-16 04:58:41 -05:00
|
|
|
},
|
|
|
|
{
|
2023-10-30 13:06:26 -05:00
|
|
|
name: "Invalid datasource URL will return a 400 HTTP status code",
|
|
|
|
dsURL: "://host/path",
|
2023-08-16 04:58:41 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tcs {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
pluginID := datasources.DS_PROMETHEUS
|
|
|
|
|
2023-09-11 06:59:24 -05:00
|
|
|
pluginStore := &pluginstore.FakePluginStore{PluginList: []pluginstore.Plugin{
|
2023-08-16 04:58:41 -05:00
|
|
|
{JSONData: plugins.JSONData{ID: pluginID}},
|
|
|
|
}}
|
|
|
|
|
|
|
|
p := DataSourceProxyService{
|
|
|
|
PluginRequestValidator: &fakePluginRequestValidator{},
|
|
|
|
pluginStore: pluginStore,
|
|
|
|
}
|
|
|
|
|
|
|
|
responseRecorder := httptest.NewRecorder()
|
|
|
|
c := &contextmodel.ReqContext{
|
|
|
|
Context: &web.Context{
|
|
|
|
Req: &http.Request{URL: &url.URL{}},
|
|
|
|
Resp: web.NewResponseWriter("GET", responseRecorder),
|
|
|
|
},
|
|
|
|
Logger: log.NewNopLogger(),
|
|
|
|
}
|
|
|
|
|
|
|
|
p.proxyDatasourceRequest(c, &datasources.DataSource{
|
|
|
|
Type: pluginID,
|
|
|
|
URL: tc.dsURL,
|
|
|
|
})
|
|
|
|
|
|
|
|
resp := responseRecorder.Result()
|
|
|
|
body := resp.Body
|
|
|
|
|
|
|
|
b, err := io.ReadAll(body)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, body.Close())
|
|
|
|
|
|
|
|
jsonBody := make(map[string]string)
|
|
|
|
err = json.Unmarshal(b, &jsonBody)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
|
|
require.Equal(t, fmt.Sprintf("Invalid data source URL: %q", tc.dsURL), jsonBody["message"])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type fakePluginRequestValidator struct{}
|
|
|
|
|
|
|
|
func (rv *fakePluginRequestValidator) Validate(_ string, _ *http.Request) error {
|
|
|
|
return nil
|
|
|
|
}
|