grafana/pkg/api/datasources_test.go

492 lines
16 KiB
Go
Raw Normal View History

package api
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
2022-09-20 12:31:08 -05:00
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db/dbtest"
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
"github.com/grafana/grafana/pkg/services/authz/zanzana"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/datasources/guardian"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/grafana/grafana/pkg/web/webtest"
)
const (
testOrgID int64 = 1
testUserID int64 = 1
testUserLogin string = "testUser"
)
func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
mockSQLStore := dbtest.NewFakeDB()
loggedInUserScenario(t, "When calling GET on", "/api/datasources/", "/api/datasources/", func(sc *scenarioContext) {
// Stubs the database query
ds := []*datasources.DataSource{
{Name: "mmm"},
{Name: "ZZZ"},
{Name: "BBB"},
{Name: "aaa"},
}
// handler func being tested
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
2021-03-17 10:06:10 -05:00
hs := &HTTPServer{
Cfg: setting.NewCfg(),
pluginStore: &pluginstore.FakePluginStore{},
DataSourcesService: &dataSourcesServiceMock{
expectedDatasources: ds,
},
dsGuardian: guardian.ProvideGuardian(),
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866) * PluginManager: Make Plugins and DataSources non-global Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Replace outdated command Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix build Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * DashboardService: Ensure it gets constructed with necessary parameters Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove FocusConvey Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Remove dead code Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Undo interface changes Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Rename to DataSourceCount Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Consolidate dashboard interfaces into one Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix test Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> * Fix dashboard integration tests Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
2021-03-17 10:06:10 -05:00
}
sc.handlerFunc = hs.GetDataSources
sc.fakeReq("GET", "/api/datasources").exec()
respJSON := []map[string]any{}
err := json.NewDecoder(sc.resp.Body).Decode(&respJSON)
require.NoError(t, err)
assert.Equal(t, "aaa", respJSON[0]["name"])
assert.Equal(t, "BBB", respJSON[1]["name"])
assert.Equal(t, "mmm", respJSON[2]["name"])
assert.Equal(t, "ZZZ", respJSON[3]["name"])
}, mockSQLStore)
loggedInUserScenario(t, "Should be able to save a data source when calling DELETE on non-existing",
"/api/datasources/name/12345", "/api/datasources/name/:name", func(sc *scenarioContext) {
// handler func being tested
hs := &HTTPServer{
Plugins: Refactor Plugin Management (#40477) * add core plugin flow * add instrumentation * move func * remove cruft * support external backend plugins * refactor + clean up * remove comments * refactor loader * simplify core plugin path arg * cleanup loggers * move signature validator to plugins package * fix sig packaging * cleanup plugin model * remove unnecessary plugin field * add start+stop for pm * fix failures * add decommissioned state * export fields just to get things flowing * fix comments * set static routes * make image loading idempotent * merge with backend plugin manager * re-use funcs * reorder imports + remove unnecessary interface * add some TODOs + remove unused func * remove unused instrumentation func * simplify client usage * remove import alias * re-use backendplugin.Plugin interface * re order funcs * improve var name * fix log statements * refactor data model * add logic for dupe check during loading * cleanup state setting * refactor loader * cleanup manager interface * add rendering flow * refactor loading + init * add renderer support * fix renderer plugin * reformat imports * track errors * fix plugin signature inheritance * name param in interface * update func comment * fix func arg name * introduce class concept * remove func * fix external plugin check * apply changes from pm-experiment * fix core plugins * fix imports * rename interface * comment API interface * add support for testdata plugin * enable alerting + use correct core plugin contracts * slim manager API * fix param name * fix filter * support static routes * fix rendering * tidy rendering * get tests compiling * fix install+uninstall * start finder test * add finder test coverage * start loader tests * add test for core plugins * load core + bundled test * add test for nested plugin loading * add test files * clean interface + fix registering some core plugins * refactoring * reformat and create sub packages * simplify core plugin init * fix ctx cancel scenario * migrate initializer * remove Init() funcs * add test starter * new logger * flesh out initializer tests * refactoring * remove unused svc * refactor rendering flow * fixup loader tests * add enabled helper func * fix logger name * fix data fetchers * fix case where plugin dir doesn't exist * improve coverage + move dupe checking to loader * remove noisy debug logs * register core plugins automagically * add support for renderer in catalog * make private func + fix req validation * use interface * re-add check for renderer in catalog * tidy up from moving to auto reg core plugins * core plugin registrar * guards * copy over core plugins for test infra * all tests green * renames * propagate new interfaces * kill old manager * get compiling * tidy up * update naming * refactor manager test + cleanup * add more cases to finder test * migrate validator to field * more coverage * refactor dupe checking * add test for plugin class * add coverage for initializer * split out rendering * move * fixup tests * fix uss test * fix frontend settings * fix grafanads test * add check when checking sig errors * fix enabled map * fixup * allow manual setup of CM * rename to cloud-monitoring * remove TODO * add installer interface for testing * loader interface returns * tests passing * refactor + add more coverage * support 'stackdriver' * fix frontend settings loading * improve naming based on package name * small tidy * refactor test * fix renderer start * make cloud-monitoring plugin ID clearer * add plugin update test * add integration tests * don't break all if sig can't be calculated * add root URL check test * add more signature verification tests * update DTO name * update enabled plugins comment * update comments * fix linter * revert fe naming change * fix errors endpoint * reset error code field name * re-order test to help verify * assert -> require * pm check * add missing entry + re-order * re-check * dump icon log * verify manager contents first * reformat * apply PR feedback * apply style changes * fix one vs all loading err * improve log output * only start when no signature error * move log * rework plugin update check * fix test * fix multi loading from cfg.PluginSettings * improve log output #2 * add error abstraction to capture errors without registering a plugin * add debug log * add unsigned warning * e2e test attempt * fix logger * set home path * prevent panic * alternate * ugh.. fix home path * return renderer even if not started * make renderer plugin managed * add fallback renderer icon, update renderer badge + prevent changes when renderer is installed * fix icon loading * rollback renderer changes * use correct field * remove unneccessary block * remove newline * remove unused func * fix bundled plugins base + module fields * remove unused field since refactor * add authorizer abstraction * loader only returns plugins expected to run * fix multi log output
2021-11-01 04:53:33 -05:00
Cfg: setting.NewCfg(),
pluginStore: &pluginstore.FakePluginStore{},
}
sc.handlerFunc = hs.DeleteDataSourceByName
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
}, mockSQLStore)
}
// Adding data sources with invalid URLs should lead to an error.
func TestAddDataSource_InvalidURL(t *testing.T) {
sc := setupScenarioContext(t, "/api/datasources")
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{},
2022-09-20 12:31:08 -05:00
Cfg: setting.NewCfg(),
}
sc.m.Post(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: "Test",
URL: "invalid:url",
Access: "direct",
Type: "test",
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
}
// Adding data sources with URLs not specifying protocol should work.
func TestAddDataSource_URLWithoutProtocol(t *testing.T) {
const name = "Test"
const url = "localhost:5432"
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{
expectedDatasource: &datasources.DataSource{},
},
Cfg: setting.NewCfg(),
AccessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
accesscontrolService: actest.FakeService{},
}
sc := setupScenarioContext(t, "/api/datasources")
sc.m.Post(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: name,
URL: url,
Access: "direct",
Type: "test",
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
}
2022-09-20 12:31:08 -05:00
// Using a custom header whose name matches the name specified for auth proxy header should fail
func TestAddDataSource_InvalidJSONData(t *testing.T) {
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{},
Cfg: setting.NewCfg(),
}
sc := setupScenarioContext(t, "/api/datasources")
hs.Cfg = setting.NewCfg()
hs.Cfg.AuthProxy.Enabled = true
hs.Cfg.AuthProxy.HeaderName = "X-AUTH-PROXY-HEADER"
2022-09-20 12:31:08 -05:00
jsonData := simplejson.New()
jsonData.Set("httpHeaderName1", hs.Cfg.AuthProxy.HeaderName)
2022-09-20 12:31:08 -05:00
sc.m.Post(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
2022-09-20 12:31:08 -05:00
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: "Test",
URL: "localhost:5432",
2022-09-20 12:31:08 -05:00
Access: "direct",
Type: "test",
JsonData: jsonData,
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
2022-09-20 12:31:08 -05:00
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
}
// Updating data sources with invalid URLs should lead to an error.
func TestUpdateDataSource_InvalidURL(t *testing.T) {
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{},
2022-09-20 12:31:08 -05:00
Cfg: setting.NewCfg(),
}
sc := setupScenarioContext(t, "/api/datasources/1234")
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: "Test",
URL: "invalid:url",
Access: "direct",
Type: "test",
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
}
2022-09-20 12:31:08 -05:00
// Using a custom header whose name matches the name specified for auth proxy header should fail
func TestUpdateDataSource_InvalidJSONData(t *testing.T) {
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{},
Cfg: setting.NewCfg(),
}
sc := setupScenarioContext(t, "/api/datasources/1234")
hs.Cfg.AuthProxy.Enabled = true
hs.Cfg.AuthProxy.HeaderName = "X-AUTH-PROXY-HEADER"
2022-09-20 12:31:08 -05:00
jsonData := simplejson.New()
jsonData.Set("httpHeaderName1", hs.Cfg.AuthProxy.HeaderName)
2022-09-20 12:31:08 -05:00
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
2022-09-20 12:31:08 -05:00
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: "Test",
URL: "localhost:5432",
2022-09-20 12:31:08 -05:00
Access: "direct",
Type: "test",
JsonData: jsonData,
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
2022-09-20 12:31:08 -05:00
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
}
func TestAddDataSourceTeamHTTPHeaders(t *testing.T) {
tenantID := "1234"
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{
expectedDatasource: &datasources.DataSource{},
},
Cfg: setting.NewCfg(),
Features: featuremgmt.WithFeatures(featuremgmt.FlagTeamHttpHeaders),
accesscontrolService: actest.FakeService{},
AccessControl: actest.FakeAccessControl{
ExpectedEvaluate: true,
ExpectedErr: nil,
},
}
sc := setupScenarioContext(t, fmt.Sprintf("/api/datasources/%s", tenantID))
hs.Cfg.AuthProxy.Enabled = true
jsonData := simplejson.New()
jsonData.Set("teamHttpHeaders", datasources.TeamHTTPHeaders{
Headers: datasources.TeamHeaders{
tenantID: []datasources.TeamHTTPHeader{
{
Header: "Authorization",
Value: "foo!=bar",
},
},
},
})
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: "Test",
URL: "localhost:5432",
Access: "direct",
Type: "test",
JsonData: jsonData,
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{
{Action: datasources.ActionPermissionsWrite, Scope: datasources.ScopeAll},
})
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, http.StatusForbidden, sc.resp.Code)
// Parse the JSON response
var response map[string]string
err := json.Unmarshal(sc.resp.Body.Bytes(), &response)
assert.NoError(t, err, "Failed to parse JSON response")
// Check the error message in the JSON response
assert.Equal(t, "Cannot create datasource with team HTTP headers, need to use updateDatasourceLBACRules API", response["message"])
2022-09-20 12:31:08 -05:00
}
// Updating data sources with URLs not specifying protocol should work.
func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) {
const name = "Test"
const url = "localhost:5432"
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{
expectedDatasource: &datasources.DataSource{},
},
Cfg: setting.NewCfg(),
AccessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
accesscontrolService: actest.FakeService{},
}
sc := setupScenarioContext(t, "/api/datasources/1234")
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req.Body = mockRequestBody(datasources.AddDataSourceCommand{
Name: name,
URL: url,
Access: "direct",
Type: "test",
})
c.SignedInUser = authedUserWithPermissions(1, 1, []ac.Permission{})
return hs.AddDataSource(c)
}))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
}
// Updating data source name where data source with same name exists.
func TestUpdateDataSourceByID_DataSourceNameExists(t *testing.T) {
hs := &HTTPServer{
DataSourcesService: &dataSourcesServiceMock{
expectedDatasource: &datasources.DataSource{},
mockUpdateDataSource: func(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) (*datasources.DataSource, error) {
return nil, datasources.ErrDataSourceNameExists
},
},
Cfg: setting.NewCfg(),
AccessControl: acimpl.ProvideAccessControl(featuremgmt.WithFeatures(), zanzana.NewNoopClient()),
accesscontrolService: actest.FakeService{},
Live: newTestLive(t, nil),
}
sc := setupScenarioContext(t, "/api/datasources/1")
sc.m.Put(sc.url, routing.Wrap(func(c *contextmodel.ReqContext) response.Response {
c.Req = web.SetURLParams(c.Req, map[string]string{":id": "1"})
c.Req.Body = mockRequestBody(datasources.UpdateDataSourceCommand{
Access: "direct",
Type: "test",
Name: "test",
})
return hs.UpdateDataSourceByID(c)
}))
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
require.Equal(t, http.StatusConflict, sc.resp.Code)
}
func TestAPI_datasources_AccessControl(t *testing.T) {
type testCase struct {
desc string
urls []string
method string
body string
permission []ac.Permission
expectedCode int
}
tests := []testCase{
{
desc: "should be able to update datasource with correct permission",
urls: []string{"api/datasources/1", "/api/datasources/uid/1"},
method: http.MethodPut,
body: `{"name": "test", "url": "http://localhost:5432", "type": "postgresql", "access": "Proxy"}`,
permission: []ac.Permission{
{Action: datasources.ActionWrite, Scope: datasources.ScopeProvider.GetResourceScope("1")},
{Action: datasources.ActionWrite, Scope: datasources.ScopeProvider.GetResourceScopeUID("1")},
},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to update datasource without correct permission",
urls: []string{"api/datasources/1", "/api/datasources/uid/1"},
method: http.MethodPut,
permission: []ac.Permission{},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to fetch datasource with correct permission",
urls: []string{"api/datasources/1", "/api/datasources/uid/1", "/api/datasources/name/test"},
method: http.MethodGet,
permission: []ac.Permission{
{Action: datasources.ActionRead, Scope: datasources.ScopeProvider.GetResourceScope("1")},
{Action: datasources.ActionRead, Scope: datasources.ScopeProvider.GetResourceScopeUID("1")},
{Action: datasources.ActionRead, Scope: datasources.ScopeProvider.GetResourceScopeName("test")},
},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to fetch datasource without correct permission",
urls: []string{"api/datasources/1", "/api/datasources/uid/1"},
method: http.MethodGet,
permission: []ac.Permission{},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to create datasource with correct permission",
urls: []string{"/api/datasources"},
method: http.MethodPost,
body: `{"name": "test", "url": "http://localhost:5432", "type": "postgresql", "access": "Proxy"}`,
permission: []ac.Permission{{Action: datasources.ActionCreate}},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to create datasource without correct permission",
urls: []string{"/api/datasources"},
method: http.MethodPost,
permission: []ac.Permission{},
expectedCode: http.StatusForbidden,
},
{
desc: "should be able to delete datasource with correct permission",
urls: []string{"/api/datasources/1", "/api/datasources/uid/1"},
method: http.MethodDelete,
permission: []ac.Permission{
{Action: datasources.ActionDelete, Scope: datasources.ScopeProvider.GetResourceScope("1")},
{Action: datasources.ActionDelete, Scope: datasources.ScopeProvider.GetResourceScopeUID("1")},
},
expectedCode: http.StatusOK,
},
{
desc: "should not be able to delete datasource without correct permission",
urls: []string{"/api/datasources/1", "/api/datasources/uid/1"},
method: http.MethodDelete,
permission: []ac.Permission{},
expectedCode: http.StatusForbidden,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.Cfg = setting.NewCfg()
hs.DataSourcesService = &dataSourcesServiceMock{expectedDatasource: &datasources.DataSource{}}
hs.accesscontrolService = actest.FakeService{}
hs.Live = newTestLive(t, hs.SQLStore)
})
for _, url := range tt.urls {
var body io.Reader
if tt.body != "" {
body = strings.NewReader(tt.body)
}
res, err := server.SendJSON(webtest.RequestWithSignedInUser(server.NewRequest(tt.method, url, body), authedUserWithPermissions(1, 1, tt.permission)))
require.NoError(t, err)
assert.Equal(t, tt.expectedCode, res.StatusCode)
require.NoError(t, res.Body.Close())
}
})
}
}
type dataSourcesServiceMock struct {
datasources.DataSourceService
expectedDatasources []*datasources.DataSource
expectedDatasource *datasources.DataSource
expectedError error
mockUpdateDataSource func(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) (*datasources.DataSource, error)
}
func (m *dataSourcesServiceMock) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error) {
return m.expectedDatasource, m.expectedError
}
func (m *dataSourcesServiceMock) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
return m.expectedDatasources, m.expectedError
}
func (m *dataSourcesServiceMock) GetDataSourcesByType(ctx context.Context, query *datasources.GetDataSourcesByTypeQuery) ([]*datasources.DataSource, error) {
return m.expectedDatasources, m.expectedError
}
func (m *dataSourcesServiceMock) DeleteDataSource(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error {
return m.expectedError
}
func (m *dataSourcesServiceMock) AddDataSource(ctx context.Context, cmd *datasources.AddDataSourceCommand) (*datasources.DataSource, error) {
return m.expectedDatasource, m.expectedError
}
func (m *dataSourcesServiceMock) UpdateDataSource(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) (*datasources.DataSource, error) {
if m.mockUpdateDataSource != nil {
return m.mockUpdateDataSource(ctx, cmd)
}
return m.expectedDatasource, m.expectedError
}
Secrets: Implement basic unified secret store service (#45804) * wip: Implement kvstore for secrets * wip: Refactor kvstore for secrets * wip: Add format key function to secrets kvstore sql * wip: Add migration for secrets kvstore * Remove unused Key field from secrets kvstore * Remove secret values from debug logs * Integrate unified secrets with datasources * Fix minor issues and tests for kvstore * Create test service helper for secret store * Remove encryption tests from datasources * Move secret operations after datasources * Fix datasource proxy tests * Fix legacy data tests * Add Name to all delete data source commands * Implement decryption cache on sql secret store * Fix minor issue with cache and tests * Use secret type on secret store datasource operations * Add comments to make create and update clear * Rename itemFound variable to isFound * Improve secret deletion and cache management * Add base64 encoding to sql secret store * Move secret retrieval to decrypted values function * Refactor decrypt secure json data functions * Fix expr tests * Fix datasource tests * Fix plugin proxy tests * Fix query tests * Fix metrics api tests * Remove unused fake secrets service from query tests * Add rename function to secret store * Add check for error renaming secret * Remove bus from tests to fix merge conflicts * Add background secrets migration to datasources * Get datasource secure json fields from secrets * Move migration to secret store * Revert "Move migration to secret store" This reverts commit 7c3f872072e9aff601fb9d639127d468c03f97ef. * Add secret service to datasource service on tests * Fix datasource tests * Remove merge conflict on wire * Add ctx to data source http transport on prometheus stats collector * Add ctx to data source http transport on stats collector test
2022-04-25 11:57:45 -05:00
func (m *dataSourcesServiceMock) DecryptedValues(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) {
Secrets: Implement basic unified secret store service (#45804) * wip: Implement kvstore for secrets * wip: Refactor kvstore for secrets * wip: Add format key function to secrets kvstore sql * wip: Add migration for secrets kvstore * Remove unused Key field from secrets kvstore * Remove secret values from debug logs * Integrate unified secrets with datasources * Fix minor issues and tests for kvstore * Create test service helper for secret store * Remove encryption tests from datasources * Move secret operations after datasources * Fix datasource proxy tests * Fix legacy data tests * Add Name to all delete data source commands * Implement decryption cache on sql secret store * Fix minor issue with cache and tests * Use secret type on secret store datasource operations * Add comments to make create and update clear * Rename itemFound variable to isFound * Improve secret deletion and cache management * Add base64 encoding to sql secret store * Move secret retrieval to decrypted values function * Refactor decrypt secure json data functions * Fix expr tests * Fix datasource tests * Fix plugin proxy tests * Fix query tests * Fix metrics api tests * Remove unused fake secrets service from query tests * Add rename function to secret store * Add check for error renaming secret * Remove bus from tests to fix merge conflicts * Add background secrets migration to datasources * Get datasource secure json fields from secrets * Move migration to secret store * Revert "Move migration to secret store" This reverts commit 7c3f872072e9aff601fb9d639127d468c03f97ef. * Add secret service to datasource service on tests * Fix datasource tests * Remove merge conflict on wire * Add ctx to data source http transport on prometheus stats collector * Add ctx to data source http transport on stats collector test
2022-04-25 11:57:45 -05:00
decryptedValues := make(map[string]string)
return decryptedValues, m.expectedError
}