grafana/pkg/api/folder_test.go

307 lines
11 KiB
Go
Raw Normal View History

2018-01-29 06:51:01 -06:00
package api
2018-02-20 11:11:50 -06:00
import (
2018-02-21 04:24:54 -06:00
"encoding/json"
"fmt"
"net/http"
2018-02-21 04:24:54 -06:00
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
2018-02-21 04:24:54 -06:00
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/db/dbtest"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/dashboards"
Access control: Use access control for dashboard and folder (#44702) * Add actions and scopes * add resource service for dashboard and folder * Add dashboard guardian with fgac permission evaluation * Add CanDelete function to guardian interface * Add CanDelete property to folder and dashboard dto and set values * change to correct function name * Add accesscontrol to folder endpoints * add access control to dashboard endpoints * check access for nav links * Add fixed roles for dashboard and folders * use correct package * add hack to override guardian Constructor if accesscontrol is enabled * Add services * Add function to handle api backward compatability * Add permissionServices to HttpServer * Set permission when new dashboard is created * Add default permission when creating new dashboard * Set default permission when creating folder and dashboard * Add access control filter for dashboard search * Add to accept list * Add accesscontrol to dashboardimport * Disable access control in tests * Add check to see if user is allow to create a dashboard * Use SetPermissions * Use function to set several permissions at once * remove permissions for folder and dashboard on delete * update required permission * set permission for provisioning * Add CanCreate to dashboard guardian and set correct permisisons for provisioning * Dont set admin on folder / dashboard creation * Add dashboard and folder permission migrations * Add tests for CanCreate * Add roles and update descriptions * Solve uid to id for dashboard and folder permissions * Add folder and dashboard actions to permission filter * Handle viewer_can_edit flag * set folder and dashboard permissions services * Add dashboard permissions when importing a new dashboard * Set access control permissions on provisioning * Pass feature flags and only set permissions if access control is enabled * only add default permissions for folders and dashboards without folders * Batch create permissions in migrations * Remove `dashboards:edit` action * Remove unused function from interface * Update pkg/services/guardian/accesscontrol_guardian_test.go Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
2022-03-03 08:05:47 -06:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/team/teamtest"
"github.com/grafana/grafana/pkg/services/user"
2019-03-06 01:09:34 -06:00
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest"
2018-02-20 11:11:50 -06:00
)
func TestFoldersAPIEndpoint(t *testing.T) {
folderService := &foldertest.FakeService{}
t.Run("Given a correct request for creating a folder", func(t *testing.T) {
cmd := models.CreateFolderCommand{
Uid: "uid",
Title: "Folder",
}
2018-02-21 04:24:54 -06:00
folderService.ExpectedFolder = &folder.Folder{ID: 1, UID: "uid", Title: "Folder"}
2018-02-21 04:24:54 -06:00
createFolderScenario(t, "When calling POST on", "/api/folders", "/api/folders", folderService, cmd,
func(sc *scenarioContext) {
2018-02-21 04:24:54 -06:00
callCreateFolder(sc)
folder := dtos.Folder{}
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
require.NoError(t, err)
assert.Equal(t, int64(1), folder.Id)
assert.Equal(t, "uid", folder.Uid)
assert.Equal(t, "Folder", folder.Title)
2018-02-21 04:24:54 -06:00
})
})
2018-02-21 04:24:54 -06:00
t.Run("Given incorrect requests for creating a folder", func(t *testing.T) {
t.Cleanup(func() {
folderService.ExpectedError = nil
})
testCases := []struct {
Error error
ExpectedStatusCode int
}{
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: dashboards.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
}
2018-02-21 04:24:54 -06:00
cmd := models.CreateFolderCommand{
Uid: "uid",
Title: "Folder",
}
2018-02-21 04:24:54 -06:00
for _, tc := range testCases {
folderService.ExpectedError = tc.Error
2018-02-21 04:24:54 -06:00
createFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.Error.Error()),
"/api/folders", "/api/folders", folderService, cmd, func(sc *scenarioContext) {
2018-02-21 04:24:54 -06:00
callCreateFolder(sc)
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for error %s", tc.Error)
2018-02-21 04:24:54 -06:00
})
}
})
2018-02-21 04:24:54 -06:00
t.Run("Given a correct request for updating a folder", func(t *testing.T) {
title := "Folder upd"
cmd := folder.UpdateFolderCommand{
NewTitle: &title,
}
2018-02-21 04:24:54 -06:00
folderService.ExpectedFolder = &folder.Folder{ID: 1, UID: "uid", Title: "Folder upd"}
2018-02-21 04:24:54 -06:00
updateFolderScenario(t, "When calling PUT on", "/api/folders/uid", "/api/folders/:uid", folderService, cmd,
func(sc *scenarioContext) {
2018-02-21 04:24:54 -06:00
callUpdateFolder(sc)
folder := dtos.Folder{}
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
require.NoError(t, err)
assert.Equal(t, int64(1), folder.Id)
assert.Equal(t, "uid", folder.Uid)
assert.Equal(t, "Folder upd", folder.Title)
2018-02-21 04:24:54 -06:00
})
})
2018-02-21 04:24:54 -06:00
t.Run("Given incorrect requests for updating a folder", func(t *testing.T) {
testCases := []struct {
Error error
ExpectedStatusCode int
}{
{Error: dashboards.ErrFolderWithSameUIDExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderSameNameExists, ExpectedStatusCode: 409},
{Error: dashboards.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
{Error: dashboards.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
{Error: dashboards.ErrFolderAccessDenied, ExpectedStatusCode: 403},
{Error: dashboards.ErrFolderNotFound, ExpectedStatusCode: 404},
{Error: dashboards.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
{Error: dashboards.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
}
2018-02-21 04:24:54 -06:00
title := "Folder upd"
cmd := folder.UpdateFolderCommand{
NewTitle: &title,
}
2018-02-21 04:24:54 -06:00
for _, tc := range testCases {
folderService.ExpectedError = tc.Error
updateFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling PUT on", tc.Error.Error()),
"/api/folders/uid", "/api/folders/:uid", folderService, cmd, func(sc *scenarioContext) {
2018-02-21 04:24:54 -06:00
callUpdateFolder(sc)
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for %s", tc.Error)
2018-02-21 04:24:54 -06:00
})
}
2018-02-21 04:24:54 -06:00
})
}
func TestHTTPServer_FolderMetadata(t *testing.T) {
setUpRBACGuardian(t)
folderService := &foldertest.FakeService{}
server := SetupAPITestServer(t, func(hs *HTTPServer) {
hs.folderService = folderService
hs.AccessControl = acmock.New()
hs.QuotaService = quotatest.New(false, nil)
})
t.Run("Should attach access control metadata to multiple folders", func(t *testing.T) {
folderService.ExpectedFolders = []*folder.Folder{{UID: "1"}, {UID: "2"}, {UID: "3"}}
req := server.NewGetRequest("/api/folders?accesscontrol=true")
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("2")},
}),
}})
res, err := server.Send(req)
require.NoError(t, err)
defer func() { require.NoError(t, res.Body.Close()) }()
assert.Equal(t, http.StatusOK, res.StatusCode)
body := []dtos.FolderSearchHit{}
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
for _, f := range body {
assert.True(t, f.AccessControl[dashboards.ActionFoldersRead])
if f.Uid == "2" {
assert.True(t, f.AccessControl[dashboards.ActionFoldersWrite])
} else {
assert.False(t, f.AccessControl[dashboards.ActionFoldersWrite])
}
}
})
t.Run("Should attach access control metadata to folder response", func(t *testing.T) {
folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"}
req := server.NewGetRequest("/api/folders/folderUid?accesscontrol=true")
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
}),
}})
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
defer func() { require.NoError(t, res.Body.Close()) }()
body := dtos.Folder{}
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
assert.True(t, body.AccessControl[dashboards.ActionFoldersRead])
assert.True(t, body.AccessControl[dashboards.ActionFoldersWrite])
})
t.Run("Should attach access control metadata to folder response", func(t *testing.T) {
folderService.ExpectedFolder = &folder.Folder{UID: "folderUid"}
req := server.NewGetRequest("/api/folders/folderUid")
webtest.RequestWithSignedInUser(req, &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{
1: accesscontrol.GroupScopesByAction([]accesscontrol.Permission{
{Action: dashboards.ActionFoldersRead, Scope: dashboards.ScopeFoldersAll},
{Action: dashboards.ActionFoldersWrite, Scope: dashboards.ScopeFoldersProvider.GetResourceScopeUID("folderUid")},
}),
}})
res, err := server.Send(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, res.StatusCode)
defer func() { require.NoError(t, res.Body.Close()) }()
body := dtos.Folder{}
require.NoError(t, json.NewDecoder(res.Body).Decode(&body))
assert.False(t, body.AccessControl[dashboards.ActionFoldersRead])
assert.False(t, body.AccessControl[dashboards.ActionFoldersWrite])
})
}
2018-02-21 04:24:54 -06:00
func callCreateFolder(sc *scenarioContext) {
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
}
func createFolderScenario(t *testing.T, desc string, url string, routePattern string, folderService folder.Service,
cmd models.CreateFolderCommand, fn scenarioFunc) {
setUpRBACGuardian(t)
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
aclMockResp := []*dashboards.DashboardACLInfoDTO{}
teamSvc := &teamtest.FakeService{}
dashSvc := &dashboards.FakeDashboardService{}
dashSvc.On("GetDashboardACLInfoList", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardACLInfoListQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*dashboards.GetDashboardACLInfoListQuery)
q.Result = aclMockResp
}).Return(nil)
dashSvc.On("GetDashboard", mock.Anything, mock.AnythingOfType("*dashboards.GetDashboardQuery")).Run(func(args mock.Arguments) {
q := args.Get(1).(*dashboards.GetDashboardQuery)
q.Result = &dashboards.Dashboard{
ID: q.ID,
UID: q.UID,
}
}).Return(nil)
store := dbtest.NewFakeDB()
guardian.InitLegacyGuardian(store, dashSvc, teamSvc)
2019-03-06 01:09:34 -06:00
hs := HTTPServer{
AccessControl: acmock.New(),
folderService: folderService,
Cfg: setting.NewCfg(),
Features: featuremgmt.WithFeatures(),
accesscontrolService: actest.FakeService{},
2019-03-06 01:09:34 -06:00
}
sc := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
Security: Sync security changes on main (#45083) * * Teams: Appropriately apply user id filter in /api/teams/:id and /api/teams/search * Teams: Ensure that users searching for teams are only able see teams they have access to * Teams: Require teamGuardian admin privileges to list team members * Teams: Prevent org viewers from administering teams * Teams: Add org_id condition to team count query * Teams: clarify permission requirements in teams api docs * Teams: expand scenarios for team search tests * Teams: mock teamGuardian in tests Co-authored-by: Dan Cech <dcech@grafana.com> * remove duplicate WHERE statement * Fix for CVE-2022-21702 (cherry picked from commit 202d7c190082c094bc1dc13f7fe9464746c37f9e) * Lint and test fixes (cherry picked from commit 3e6b67d5504abf4a1d7b8d621f04d062c048e981) * check content type properly (cherry picked from commit 70b4458892bf2f776302720c10d24c9ff34edd98) * basic csrf origin check (cherry picked from commit 3adaa5ff39832364f6390881fb5b42ad47df92e1) * compare origin to host (cherry picked from commit 5443892699e8ed42836bb2b9a44744ff3e970f42) * simplify url parsing (cherry picked from commit b2ffbc9513fed75468628370a48b929d30af2b1d) * check csrf for GET requests, only compare origin (cherry picked from commit 8b81dc12d8f8a1f07852809c5b4d44f0f0b1d709) * parse content type properly (cherry picked from commit 16f76f4902e6f2188bea9606c68b551af186bdc0) * mentioned get in the comment (cherry picked from commit a7e61811ef8ae558ce721e2e3fed04ce7a5a5345) * add content-type: application/json to test HTTP requests * fix pluginproxy test * Fix linter when comparing errors Co-authored-by: Kevin Minehart <kmineh0151@gmail.com> Co-authored-by: Dan Cech <dcech@grafana.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com> Co-authored-by: Vardan Torosyan <vardants@gmail.com>
2022-02-09 06:44:38 -06:00
c.Req.Header.Add("Content-Type", "application/json")
2018-02-21 04:24:54 -06:00
sc.context = c
sc.context.SignedInUser = &user.SignedInUser{OrgID: testOrgID, UserID: testUserID}
2018-02-21 04:24:54 -06:00
return hs.CreateFolder(c)
2018-02-21 04:24:54 -06:00
})
sc.m.Post(routePattern, sc.defaultHandler)
2018-02-21 04:24:54 -06:00
fn(sc)
})
}
func callUpdateFolder(sc *scenarioContext) {
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
}
func updateFolderScenario(t *testing.T, desc string, url string, routePattern string, folderService folder.Service,
cmd folder.UpdateFolderCommand, fn scenarioFunc) {
setUpRBACGuardian(t)
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
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(),
AccessControl: acmock.New(),
folderService: folderService,
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 := setupScenarioContext(t, url)
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
c.Req.Body = mockRequestBody(cmd)
Security: Sync security changes on main (#45083) * * Teams: Appropriately apply user id filter in /api/teams/:id and /api/teams/search * Teams: Ensure that users searching for teams are only able see teams they have access to * Teams: Require teamGuardian admin privileges to list team members * Teams: Prevent org viewers from administering teams * Teams: Add org_id condition to team count query * Teams: clarify permission requirements in teams api docs * Teams: expand scenarios for team search tests * Teams: mock teamGuardian in tests Co-authored-by: Dan Cech <dcech@grafana.com> * remove duplicate WHERE statement * Fix for CVE-2022-21702 (cherry picked from commit 202d7c190082c094bc1dc13f7fe9464746c37f9e) * Lint and test fixes (cherry picked from commit 3e6b67d5504abf4a1d7b8d621f04d062c048e981) * check content type properly (cherry picked from commit 70b4458892bf2f776302720c10d24c9ff34edd98) * basic csrf origin check (cherry picked from commit 3adaa5ff39832364f6390881fb5b42ad47df92e1) * compare origin to host (cherry picked from commit 5443892699e8ed42836bb2b9a44744ff3e970f42) * simplify url parsing (cherry picked from commit b2ffbc9513fed75468628370a48b929d30af2b1d) * check csrf for GET requests, only compare origin (cherry picked from commit 8b81dc12d8f8a1f07852809c5b4d44f0f0b1d709) * parse content type properly (cherry picked from commit 16f76f4902e6f2188bea9606c68b551af186bdc0) * mentioned get in the comment (cherry picked from commit a7e61811ef8ae558ce721e2e3fed04ce7a5a5345) * add content-type: application/json to test HTTP requests * fix pluginproxy test * Fix linter when comparing errors Co-authored-by: Kevin Minehart <kmineh0151@gmail.com> Co-authored-by: Dan Cech <dcech@grafana.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com> Co-authored-by: Vardan Torosyan <vardants@gmail.com>
2022-02-09 06:44:38 -06:00
c.Req.Header.Add("Content-Type", "application/json")
2018-02-21 04:24:54 -06:00
sc.context = c
sc.context.SignedInUser = &user.SignedInUser{OrgID: testOrgID, UserID: testUserID}
return hs.UpdateFolder(c)
2018-02-21 04:24:54 -06:00
})
2018-02-21 04:24:54 -06:00
sc.m.Put(routePattern, sc.defaultHandler)
2018-02-21 04:24:54 -06:00
fn(sc)
})
}