Remove bus from quota, preferences, plugins, user_token (#44762)

* Remove bus from quota, preferences, plugins, user_token

* Bind sqlstore.Store to *sqlstore.SQLStore

* Fix test

* Fix sqlstore wire injection, dependency
This commit is contained in:
idafurjes 2022-02-03 09:20:20 +01:00 committed by GitHub
parent b2655750e8
commit 1b286e6bb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 228 additions and 260 deletions

View File

@ -11,7 +11,6 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
)
@ -112,7 +111,7 @@ func (hs *HTTPServer) AdminUpdateUserPermissions(c *models.ReqContext) response.
return response.Error(http.StatusBadRequest, "id is invalid", err)
}
err = updateUserPermissions(hs.SQLStore, userID, form.IsGrafanaAdmin)
err = hs.SQLStore.UpdateUserPermissions(userID, form.IsGrafanaAdmin)
if err != nil {
if errors.Is(err, models.ErrLastGrafanaAdmin) {
return response.Error(400, models.ErrLastGrafanaAdmin.Error(), nil)
@ -230,10 +229,3 @@ func (hs *HTTPServer) AdminRevokeUserAuthToken(c *models.ReqContext) response.Re
}
return hs.revokeUserAuthTokenInternal(c, userID, cmd)
}
// updateUserPermissions updates the user's permissions.
//
// Stubbable by tests.
var updateUserPermissions = func(sqlStore *sqlstore.SQLStore, userID int64, isAdmin bool) error {
return sqlStore.UpdateUserPermissions(userID, isAdmin)
}

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -34,25 +35,18 @@ func TestAdminAPIEndpoint(t *testing.T) {
updateCmd := dtos.AdminUpdateUserPermissionsForm{
IsGrafanaAdmin: false,
}
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrLastGrafanaAdmin,
}
putAdminScenario(t, "When calling PUT on", "/api/admin/users/1/permissions",
"/api/admin/users/:id/permissions", role, updateCmd, func(sc *scenarioContext) {
// TODO: Use a fake SQLStore when it's represented by an interface
origUpdateUserPermissions := updateUserPermissions
t.Cleanup(func() {
updateUserPermissions = origUpdateUserPermissions
})
updateUserPermissions = func(sqlStore *sqlstore.SQLStore, userID int64, isAdmin bool) error {
return models.ErrLastGrafanaAdmin
}
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
})
}, mock)
})
t.Run("When a server admin attempts to logout himself from all devices", func(t *testing.T) {
mock := mockstore.NewSQLStoreMock()
adminLogoutUserScenario(t, "Should not be allowed when calling POST on",
"/api/admin/users/1/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
@ -62,54 +56,41 @@ func TestAdminAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
})
}, mock)
})
t.Run("When a server admin attempts to logout a non-existing user from all devices", func(t *testing.T) {
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrUserNotFound,
}
adminLogoutUserScenario(t, "Should return not found when calling POST on", "/api/admin/users/200/logout",
"/api/admin/users/:id/logout", func(sc *scenarioContext) {
userID := int64(0)
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
userID = cmd.Id
return models.ErrUserNotFound
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
assert.Equal(t, int64(200), userID)
})
}, mock)
})
t.Run("When a server admin attempts to revoke an auth token for a non-existing user", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrUserNotFound,
}
adminRevokeUserAuthTokenScenario(t, "Should return not found when calling POST on",
"/api/admin/users/200/revoke-auth-token", "/api/admin/users/:id/revoke-auth-token", cmd, func(sc *scenarioContext) {
var userID int64
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
userID = cmd.Id
return models.ErrUserNotFound
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
assert.Equal(t, int64(200), userID)
})
}, mock)
})
t.Run("When a server admin gets auth tokens for a non-existing user", func(t *testing.T) {
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrUserNotFound,
}
adminGetUserAuthTokensScenario(t, "Should return not found when calling GET on",
"/api/admin/users/200/auth-tokens", "/api/admin/users/:id/auth-tokens", func(sc *scenarioContext) {
var userID int64
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
userID = cmd.Id
return models.ErrUserNotFound
})
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
assert.Equal(t, int64(200), userID)
})
}, mock)
})
t.Run("When a server admin attempts to enable/disable a nonexistent user", func(t *testing.T) {
@ -305,12 +286,13 @@ func TestAdminAPIEndpoint(t *testing.T) {
}
func putAdminScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc) {
cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
hs := &HTTPServer{
Cfg: setting.NewCfg(),
Cfg: setting.NewCfg(),
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)
@ -330,13 +312,14 @@ func putAdminScenario(t *testing.T, desc string, url string, routePattern string
})
}
func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: auth.NewFakeUserAuthTokenService(),
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)
@ -357,7 +340,7 @@ func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern
})
}
func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc) {
func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -366,6 +349,7 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)
@ -386,7 +370,7 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
})
}
func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -395,6 +379,7 @@ func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, route
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/search"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -81,6 +82,7 @@ func TestAlertingAPIEndpoint(t *testing.T) {
})
})
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts",
models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
@ -102,7 +104,7 @@ func TestAlertingAPIEndpoint(t *testing.T) {
require.Nil(t, searchQuery)
assert.NotNil(t, getAlertsQuery)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET",
"/api/alerts?dashboardId=1&dashboardId=2&folderId=3&dashboardTag=abc&dashboardQuery=dbQuery&limit=5&query=alertQuery",
@ -140,7 +142,7 @@ func TestAlertingAPIEndpoint(t *testing.T) {
assert.Equal(t, int64(2), getAlertsQuery.DashboardIDs[1])
assert.Equal(t, int64(5), getAlertsQuery.Limit)
assert.Equal(t, "alertQuery", getAlertsQuery.Query)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/alert-notifications/1",
"/alert-notifications/:notificationId", models.ROLE_ADMIN, func(sc *scenarioContext) {
@ -149,7 +151,7 @@ func TestAlertingAPIEndpoint(t *testing.T) {
sc.handlerFunc = GetAlertNotificationByID
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
})
}, mock)
}
func callPauseAlert(sc *scenarioContext) {

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
)
@ -55,6 +56,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code)
})
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
fakeAnnoRepo = &fakeAnnotationsRepo{}
@ -62,7 +64,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
})
@ -84,7 +86,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
fakeAnnoRepo = &fakeAnnotationsRepo{}
@ -92,7 +94,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
})
})
@ -165,7 +167,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
})
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
setUp()
@ -174,7 +176,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
})
@ -198,7 +200,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
setUp()
@ -207,7 +209,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
})

View File

@ -154,7 +154,7 @@ func (hs *HTTPServer) registerRoutes() {
userRoute.Delete("/stars/dashboard/:id", routing.Wrap(hs.UnstarDashboard))
userRoute.Put("/password", routing.Wrap(hs.ChangeUserPassword))
userRoute.Get("/quotas", routing.Wrap(GetUserQuotas))
userRoute.Get("/quotas", routing.Wrap(hs.GetUserQuotas))
userRoute.Put("/helpflags/:id", routing.Wrap(hs.SetHelpFlag))
// For dev purpose
userRoute.Get("/helpflags/clear", routing.Wrap(hs.ClearHelpFlags))
@ -264,7 +264,7 @@ func (hs *HTTPServer) registerRoutes() {
// Preferences
apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) {
prefRoute.Post("/set-home-dash", routing.Wrap(SetHomeDashboard))
prefRoute.Post("/set-home-dash", routing.Wrap(hs.SetHomeDashboard))
})
// Data sources
@ -493,8 +493,8 @@ func (hs *HTTPServer) registerRoutes() {
adminUserRoute.Delete("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDelete, userIDScope)), routing.Wrap(AdminDeleteUser))
adminUserRoute.Post("/:id/disable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDisable, userIDScope)), routing.Wrap(hs.AdminDisableUser))
adminUserRoute.Post("/:id/enable", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersEnable, userIDScope)), routing.Wrap(AdminEnableUser))
adminUserRoute.Get("/:id/quotas", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasList, userIDScope)), routing.Wrap(GetUserQuotas))
adminUserRoute.Put("/:id/quotas/:target", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasUpdate, userIDScope)), routing.Wrap(UpdateUserQuota))
adminUserRoute.Get("/:id/quotas", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasList, userIDScope)), routing.Wrap(hs.GetUserQuotas))
adminUserRoute.Put("/:id/quotas/:target", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersQuotasUpdate, userIDScope)), routing.Wrap(hs.UpdateUserQuota))
adminUserRoute.Post("/:id/logout", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersLogout, userIDScope)), routing.Wrap(hs.AdminLogoutUser))
adminUserRoute.Get("/:id/auth-tokens", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersAuthTokenList, userIDScope)), routing.Wrap(hs.AdminGetUserAuthTokens))

View File

@ -40,15 +40,16 @@ import (
"github.com/stretchr/testify/require"
)
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
loggedInUserScenarioWithRole(t, desc, "GET", url, routePattern, models.ROLE_EDITOR, fn)
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) {
loggedInUserScenarioWithRole(t, desc, "GET", url, routePattern, models.ROLE_EDITOR, fn, sqlStore)
}
func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
sc := setupScenarioContext(t, url)
sc.sqlStore = sqlStore
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
sc.context = c
sc.context.UserId = testUserID
@ -156,6 +157,7 @@ type scenarioContext struct {
req *http.Request
url string
userAuthTokenService *auth.FakeUserAuthTokenService
sqlStore sqlstore.Store
}
func (sc *scenarioContext) exec() {

View File

@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/dashboards"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
)
@ -30,13 +31,13 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
return models.ErrDashboardNotFound
})
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
callGetDashboardPermissions(sc, hs)
assert.Equal(t, 404, sc.resp.Code)
})
}, mock)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -73,13 +74,13 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
return nil
})
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
callGetDashboardPermissions(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -125,6 +126,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
return nil
})
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
@ -139,7 +141,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
assert.Len(t, resp, 5)
assert.Equal(t, int64(2), resp[0].UserId)
assert.Equal(t, models.PERMISSION_VIEW, resp[0].Permission)
})
}, mock)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -341,7 +343,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
return nil
})
}
mock := mockstore.NewSQLStoreMock()
var resp []*models.DashboardAclInfoDTO
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
"/api/dashboards/id/:dashboardId/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
@ -357,7 +359,7 @@ func TestDashboardPermissionAPIEndpoint(t *testing.T) {
assert.Equal(t, models.PERMISSION_EDIT, resp[0].Permission)
assert.Equal(t, int64(4), resp[1].UserId)
assert.Equal(t, models.PERMISSION_ADMIN, resp[1].Permission)
})
}, mock)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -69,6 +70,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
}
t.Run("When user has editor role and is not in the ACL", func(t *testing.T) {
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "Should not be able to delete snapshot when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t)
@ -84,7 +86,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code)
require.Nil(t, externalRequest)
})
}, mock)
})
t.Run("When user is anonymous", func(t *testing.T) {
@ -120,7 +122,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE",
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t)
@ -143,11 +145,12 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.Equal(t, 1, respJSON.Get("id").MustInt())
assert.Equal(t, ts.URL, fmt.Sprintf("http://%s", externalRequest.Host))
assert.Equal(t, "/", externalRequest.URL.EscapedPath())
})
}, mock)
})
t.Run("When user is editor and creator of the snapshot", func(t *testing.T) {
aclMockResp = []*models.DashboardAclInfoDTO{}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t)
@ -164,11 +167,12 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
assert.Equal(t, 1, respJSON.Get("id").MustInt())
})
}, mock)
})
t.Run("When deleting an external snapshot", func(t *testing.T) {
aclMockResp = []*models.DashboardAclInfoDTO{}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t,
"Should gracefully delete local snapshot when remote snapshot has already been removed when calling DELETE on",
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
@ -192,7 +196,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
assert.Equal(t, 1, respJSON.Get("id").MustInt())
})
}, mock)
loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected 500 error occurs when calling DELETE on", "DELETE",
@ -213,7 +217,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
require.NoError(t, writeErr)
assert.Equal(t, 500, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected remote error occurs when calling DELETE on",
@ -230,7 +234,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
assert.Equal(t, 500, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "Should be able to read a snapshot's unencrypted data when calling GET on",
"GET", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
@ -247,6 +251,6 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
id := dashboard.Get("id")
assert.Equal(t, int64(100), id.MustInt64())
})
}, mock)
})
}

View File

@ -26,6 +26,7 @@ import (
"github.com/grafana/grafana/pkg/services/provisioning"
"github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
@ -159,7 +160,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -171,7 +172,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -185,7 +186,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -193,7 +194,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -201,12 +202,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -217,7 +218,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -227,10 +228,11 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
SQLStore: mock,
})
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -238,7 +240,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -246,7 +248,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
})
@ -256,6 +258,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Live: newTestLive(t),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
SQLStore: mockstore.NewSQLStoreMock(),
}
setUp := func() *testState {
@ -315,7 +318,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_VIEWER
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -324,7 +327,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -333,7 +336,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -341,7 +344,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -349,12 +352,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_EDITOR
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp()
@ -364,7 +367,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -373,7 +376,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -381,7 +384,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -389,7 +392,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
t.Run("When user is an Org Viewer but has an edit permission", func(t *testing.T) {
@ -407,7 +410,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
})
return state
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -418,29 +421,28 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
t.Run("When user is an Org Viewer and viewers can edit", func(t *testing.T) {
@ -466,7 +468,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return state
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -477,7 +479,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -485,7 +487,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
})
t.Run("When user is an Org Viewer but has an admin permission", func(t *testing.T) {
@ -503,7 +505,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
})
return state
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -513,7 +515,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave)
assert.True(t, dash.Meta.CanAdmin)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -521,21 +523,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
t.Run("When user is an Org Editor but has a view permission", func(t *testing.T) {
@ -553,7 +555,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
})
return state
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -561,7 +563,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner()
@ -569,21 +571,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner()
callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code)
})
}, mock)
})
})
@ -964,7 +966,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return nil
})
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/abcdefghi", "/api/dashboards/db/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
@ -972,12 +974,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
SQLStore: mock,
})
assert.Equal(t, 400, sc.resp.Code)
result := sc.ToJSON()
assert.Equal(t, models.ErrDashboardCannotDeleteProvisionedDashboard.Error(), result.Get("error").MustString())
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
@ -990,8 +993,9 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dash := getDashboardShouldReturn200WithConfig(sc, mock)
assert.Equal(t, filepath.Join("test", "dashboard1.json"), dash.Meta.ProvisionedExternalId)
})
}, mock)
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When allowUiUpdates is true and calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp()
@ -1008,6 +1012,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
ProvisioningService: mock,
LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{},
SQLStore: mockSQLStore,
}
callGetDashboard(sc, hs)
@ -1018,7 +1023,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, false, dash.Meta.Provisioned)
})
}, mock)
})
}
@ -1036,6 +1041,7 @@ func getDashboardShouldReturn200WithConfig(sc *scenarioContext, provisioningServ
LibraryPanelService: &libraryPanelsService,
LibraryElementService: &libraryElementsService,
ProvisioningService: provisioningService,
SQLStore: sc.sqlStore,
}
callGetDashboard(sc, hs)

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -27,6 +28,7 @@ const (
)
func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "/api/datasources/", "/api/datasources/", func(sc *scenarioContext) {
// Stubs the database query
bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourcesQuery) error {
@ -45,6 +47,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
Bus: bus.GetBus(),
Cfg: setting.NewCfg(),
pluginStore: &fakePluginStore{},
SQLStore: mock,
}
sc.handlerFunc = hs.GetDataSources
sc.fakeReq("GET", "/api/datasources").exec()
@ -57,7 +60,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
assert.Equal(t, "BBB", respJSON[1]["name"])
assert.Equal(t, "mmm", respJSON[2]["name"])
assert.Equal(t, "ZZZ", respJSON[3]["name"])
})
}, mock)
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) {
@ -70,7 +73,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
sc.handlerFunc = hs.DeleteDataSourceByName
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
})
}, mock)
}
// Adding data sources with invalid URLs should lead to an error.

View File

@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
)
@ -34,11 +35,11 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
dashboards.NewFolderService = origNewFolderService
})
mockFolderService(mock)
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs)
assert.Equal(t, 404, sc.resp.Code)
})
}, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -77,11 +78,11 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
}
mockFolderService(mock)
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs)
assert.Equal(t, 403, sc.resp.Code)
})
}, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -130,7 +131,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
}
mockFolderService(mock)
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
@ -142,7 +143,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
assert.Len(t, resp, 5)
assert.Equal(t, int64(2), resp[0].UserId)
assert.Equal(t, models.PERMISSION_VIEW, resp[0].Permission)
})
}, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{
@ -325,6 +326,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
mockFolderService(mock)
var resp []*models.DashboardAclInfoDTO
mockSQLStore := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code)
@ -337,7 +339,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
assert.Equal(t, models.PERMISSION_EDIT, resp[0].Permission)
assert.Equal(t, int64(4), resp[1].UserId)
assert.Equal(t, models.PERMISSION_ADMIN, resp[1].Permission)
})
}, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{

View File

@ -107,7 +107,7 @@ type HTTPServer struct {
LivePushGateway *pushhttp.Gateway
ThumbService thumbs.Service
ContextHandler *contexthandler.ContextHandler
SQLStore *sqlstore.SQLStore
SQLStore sqlstore.Store
AlertEngine *alerting.AlertEngine
LoadSchemaService *schemaloader.SchemaLoaderService
AlertNG *ngalert.AlertNG

View File

@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
@ -41,7 +42,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t)
sqlStore.Cfg = settings
hs.SQLStore = sqlStore
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "api/org/users", "api/org/users", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore)
@ -54,7 +55,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
err := json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err)
assert.Len(t, resp, 3)
})
}, mock)
loggedInUserScenario(t, "When calling GET on", "api/org/users/search", "api/org/users/search", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore)
@ -72,7 +73,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, int64(3), resp.TotalCount)
assert.Equal(t, 1000, resp.PerPage)
assert.Equal(t, 1, resp.Page)
})
}, mock)
loggedInUserScenario(t, "When calling GET with page and limit query parameters on", "api/org/users/search", "api/org/users/search", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore)
@ -90,7 +91,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, int64(3), resp.TotalCount)
assert.Equal(t, 2, resp.PerPage)
assert.Equal(t, 2, resp.Page)
})
}, mock)
t.Run("Given there are two hidden users", func(t *testing.T) {
settings.HiddenUsers = map[string]struct{}{
@ -113,7 +114,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Len(t, resp, 2)
assert.Equal(t, testUserLogin, resp[0].Login)
assert.Equal(t, "user2", resp[1].Login)
})
}, mock)
loggedInUserScenarioWithRole(t, "When calling GET as an admin on", "GET", "api/org/users/lookup",
"api/org/users/lookup", models.ROLE_ADMIN, func(sc *scenarioContext) {
@ -130,7 +131,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Len(t, resp, 2)
assert.Equal(t, testUserLogin, resp[0].Login)
assert.Equal(t, "user2", resp[1].Login)
})
}, mock)
})
}

View File

@ -18,7 +18,6 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/fs"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
@ -143,7 +142,7 @@ func (hs *HTTPServer) GetPluginSettingByID(c *models.ReqContext) response.Respon
}
query := models.GetPluginSettingByIdQuery{PluginId: pluginID, OrgId: c.OrgId}
if err := bus.Dispatch(c.Req.Context(), &query); err != nil {
if err := hs.SQLStore.GetPluginSettingById(c.Req.Context(), &query); err != nil {
if !errors.Is(err, models.ErrPluginSettingNotFound) {
return response.Error(500, "Failed to get login settings", nil)
}
@ -175,7 +174,7 @@ func (hs *HTTPServer) UpdatePluginSetting(c *models.ReqContext) response.Respons
cmd.OrgId = c.OrgId
cmd.PluginId = pluginID
if err := bus.Dispatch(c.Req.Context(), &cmd); err != nil {
if err := hs.SQLStore.UpdatePluginSetting(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to update plugin setting", err)
}

View File

@ -6,7 +6,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web"
)
@ -18,7 +17,7 @@ const (
)
// POST /api/preferences/set-home-dash
func SetHomeDashboard(c *models.ReqContext) response.Response {
func (hs *HTTPServer) SetHomeDashboard(c *models.ReqContext) response.Response {
cmd := models.SavePreferencesCommand{}
if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
@ -26,7 +25,7 @@ func SetHomeDashboard(c *models.ReqContext) response.Response {
cmd.UserId = c.UserId
cmd.OrgId = c.OrgId
if err := bus.Dispatch(c.Req.Context(), &cmd); err != nil {
if err := hs.SQLStore.SavePreferences(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to set home dashboard", err)
}

View File

@ -5,7 +5,6 @@ import (
"strconv"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
@ -61,7 +60,7 @@ func (hs *HTTPServer) UpdateOrgQuota(c *models.ReqContext) response.Response {
return response.Success("Organization quota updated")
}
func GetUserQuotas(c *models.ReqContext) response.Response {
func (hs *HTTPServer) GetUserQuotas(c *models.ReqContext) response.Response {
if !setting.Quota.Enabled {
return response.Error(404, "Quotas not enabled", nil)
}
@ -73,14 +72,14 @@ func GetUserQuotas(c *models.ReqContext) response.Response {
query := models.GetUserQuotasQuery{UserId: id}
if err := bus.Dispatch(c.Req.Context(), &query); err != nil {
if err := hs.SQLStore.GetUserQuotas(c.Req.Context(), &query); err != nil {
return response.Error(500, "Failed to get org quotas", err)
}
return response.JSON(200, query.Result)
}
func UpdateUserQuota(c *models.ReqContext) response.Response {
func (hs *HTTPServer) UpdateUserQuota(c *models.ReqContext) response.Response {
cmd := models.UpdateUserQuotaCmd{}
var err error
if err := web.Bind(c.Req, &cmd); err != nil {
@ -99,7 +98,7 @@ func UpdateUserQuota(c *models.ReqContext) response.Response {
return response.Error(404, "Invalid quota target", nil)
}
if err := bus.Dispatch(c.Req.Context(), &cmd); err != nil {
if err := hs.SQLStore.UpdateUserQuota(c.Req.Context(), &cmd); err != nil {
return response.Error(500, "Failed to update org quotas", err)
}
return response.Success("Organization quota updated")

View File

@ -9,7 +9,6 @@ import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
)
@ -25,7 +24,7 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response {
return response.Error(403, "Not allowed to create team.", nil)
}
team, err := createTeam(hs.SQLStore, cmd.Name, cmd.Email, c.OrgId)
team, err := hs.SQLStore.CreateTeam(cmd.Name, cmd.Email, c.OrgId)
if err != nil {
if errors.Is(err, models.ErrTeamNameTaken) {
return response.Error(409, "Team name taken", err)
@ -45,7 +44,6 @@ func (hs *HTTPServer) CreateTeam(c *models.ReqContext) response.Response {
c.Logger.Warn("Could not add creator to team because is not a real user")
}
}
return response.JSON(200, &util.DynMap{
"teamId": team.Id,
"message": "Team created",
@ -211,10 +209,3 @@ func (hs *HTTPServer) UpdateTeamPreferences(c *models.ReqContext) response.Respo
return hs.updatePreferencesFor(c.Req.Context(), orgId, 0, teamId, &dtoCmd)
}
// createTeam creates a team.
//
// Stubbable by tests.
var createTeam = func(sqlStore *sqlstore.SQLStore, name, email string, orgID int64) (models.Team, error) {
return sqlStore.CreateTeam(name, email, orgID)
}

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/teamguardian/database"
"github.com/grafana/grafana/pkg/services/teamguardian/manager"
"github.com/grafana/grafana/pkg/setting"
@ -47,6 +48,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
License: &licensing.OSSLicensingService{},
SQLStore: sqlStore,
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members",
"api/teams/:teamId/members", models.ROLE_ADMIN, func(sc *scenarioContext) {
@ -61,7 +63,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
err := json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err)
assert.Len(t, resp, 3)
})
}, mock)
t.Run("Given there is two hidden users", func(t *testing.T) {
settings.HiddenUsers = map[string]struct{}{
@ -86,7 +88,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, "loginuser0", resp[0].Login)
assert.Equal(t, "loginuser1", resp[1].Login)
assert.Equal(t, "loginuser2", resp[2].Login)
})
}, mock)
})
}

View File

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
@ -34,7 +35,7 @@ func TestTeamAPIEndpoint(t *testing.T) {
t.Run("Given two teams", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.SQLStore = sqlstore.InitTestDB(t)
mock := mockstore.SQLStoreMock{}
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1)
require.NoError(t, err)
@ -50,7 +51,7 @@ func TestTeamAPIEndpoint(t *testing.T) {
assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 2, len(resp.Teams))
})
}, mock)
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1)
@ -67,29 +68,15 @@ func TestTeamAPIEndpoint(t *testing.T) {
assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 0, len(resp.Teams))
})
}, mock)
})
t.Run("When creating team with API key", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.Cfg.EditorsCanAdmin = true
hs.SQLStore = mockstore.NewSQLStoreMock()
teamName := "team foo"
// TODO: Use a fake SQLStore when it's represented by an interface
orgCreateTeam := createTeam
orgAddTeamMember := addOrUpdateTeamMember
t.Cleanup(func() {
createTeam = orgCreateTeam
addOrUpdateTeamMember = orgAddTeamMember
})
createTeamCalled := 0
createTeam = func(sqlStore *sqlstore.SQLStore, name, email string, orgID int64) (models.Team, error) {
createTeamCalled++
return models.Team{Name: teamName, Id: 42}, nil
}
addTeamMemberCalled := 0
addOrUpdateTeamMember = func(ctx context.Context, resourcePermissionService *resourcepermissions.Service, userID, orgID, teamID int64,
permission string) error {
@ -109,9 +96,9 @@ func TestTeamAPIEndpoint(t *testing.T) {
}
c.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 0)
r := hs.CreateTeam(c)
assert.Equal(t, 200, r.Status())
assert.True(t, stub.warnCalled)
assert.Equal(t, stub.warnMessage, "Could not add creator to team because is not a real user")
})
@ -125,10 +112,8 @@ func TestTeamAPIEndpoint(t *testing.T) {
}
c.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
createTeamCalled, addTeamMemberCalled = 0, 0
hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 1)
r := hs.CreateTeam(c)
assert.Equal(t, 200, r.Status())
assert.False(t, stub.warnCalled)
})
})

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/services/secrets/database"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting"
"golang.org/x/oauth2"
@ -41,7 +42,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
},
TotalCount: 2,
}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "api/users/1", "api/users/:id", func(sc *scenarioContext) {
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
@ -100,7 +101,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
resp.UpdatedAt = fakeNow
resp.AvatarUrl = avatarUrl
require.EqualValues(t, expected, resp)
})
}, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users/lookup", "/api/users/lookup", func(sc *scenarioContext) {
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
@ -141,7 +142,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
require.Equal(t, "admin", resp.Login)
require.Equal(t, "admin@test.com", resp.Email)
require.True(t, resp.IsGrafanaAdmin)
})
}, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users", "/api/users", func(sc *scenarioContext) {
var sentLimit int
@ -165,7 +166,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
require.NoError(t, err)
assert.Equal(t, 2, len(respJSON.MustArray()))
})
}, mock)
loggedInUserScenario(t, "When calling GET with page and limit querystring parameters on", "/api/users", "/api/users", func(sc *scenarioContext) {
var sentLimit int
@ -185,7 +186,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, 10, sentLimit)
assert.Equal(t, 2, sendPage)
})
}, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) {
var sentLimit int
@ -211,7 +212,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, 2, respJSON.Get("totalCount").MustInt())
assert.Equal(t, 2, len(respJSON.Get("users").MustArray()))
})
}, mock)
loggedInUserScenario(t, "When calling GET with page and perpage querystring parameters on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) {
var sentLimit int
@ -231,5 +232,5 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, 10, sentLimit)
assert.Equal(t, 2, sendPage)
})
}, mock)
}

View File

@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web"
@ -32,7 +31,7 @@ func (hs *HTTPServer) RevokeUserAuthToken(c *models.ReqContext) response.Respons
func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, userID int64) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID}
if err := bus.Dispatch(ctx, &userQuery); err != nil {
if err := hs.SQLStore.GetUserById(ctx, &userQuery); err != nil {
if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err)
}
@ -52,7 +51,7 @@ func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, user
func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int64) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID}
if err := bus.Dispatch(c.Req.Context(), &userQuery); err != nil {
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err)
}
@ -118,8 +117,7 @@ func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int
func (hs *HTTPServer) revokeUserAuthTokenInternal(c *models.ReqContext, userID int64, cmd models.RevokeAuthTokenCmd) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID}
if err := bus.Dispatch(c.Req.Context(), &userQuery); err != nil {
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err)
}

View File

@ -11,87 +11,73 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert"
)
func TestUserTokenAPIEndpoint(t *testing.T) {
mock := mockstore.NewSQLStoreMock()
t.Run("When current user attempts to revoke an auth token for a non-existing user", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
mock.ExpectedError = models.ErrUserNotFound
revokeUserAuthTokenScenario(t, "Should return not found when calling POST on", "/api/user/revoke-auth-token",
"/api/user/revoke-auth-token", cmd, 200, func(sc *scenarioContext) {
var userID int64
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
userID = cmd.Id
return models.ErrUserNotFound
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
assert.Equal(t, int64(200), userID)
})
}, mock)
})
t.Run("When current user gets auth tokens for a non-existing user", func(t *testing.T) {
mock := mockstore.SQLStoreMock{
ExpectedUser: &models.User{Id: 200},
ExpectedError: models.ErrUserNotFound,
}
getUserAuthTokensScenario(t, "Should return not found when calling GET on", "/api/user/auth-tokens", "/api/user/auth-tokens", 200, func(sc *scenarioContext) {
var userID int64
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
userID = cmd.Id
return models.ErrUserNotFound
})
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
assert.Equal(t, int64(200), userID)
})
}, mock)
})
t.Run("When logging out an existing user from all devices", func(t *testing.T) {
mock := mockstore.SQLStoreMock{
ExpectedUser: &models.User{Id: 200},
}
logoutUserFromAllDevicesInternalScenario(t, "Should be successful", 1, func(sc *scenarioContext) {
const userID int64 = 200
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
cmd.Result = &models.User{Id: userID}
return nil
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
t.Run("When logout a non-existing user from all devices", func(t *testing.T) {
logoutUserFromAllDevicesInternalScenario(t, "Should return not found", testUserID, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
return models.ErrUserNotFound
})
mock.ExpectedError = models.ErrUserNotFound
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code)
})
}, mock)
})
t.Run("When revoke an auth token for a user", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
token := &models.UserToken{Id: 1}
mock := mockstore.SQLStoreMock{
ExpectedUser: &models.User{Id: 200},
}
revokeUserAuthTokenInternalScenario(t, "Should be successful", cmd, 200, token, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
cmd.Result = &models.User{Id: 200}
return nil
})
sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*models.UserToken, error) {
return &models.UserToken{Id: 2}, nil
}
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code)
})
}, mock)
})
t.Run("When revoke the active auth token used by himself", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
token := &models.UserToken{Id: 2}
mock := mockstore.NewSQLStoreMock()
revokeUserAuthTokenInternalScenario(t, "Should not be successful", cmd, testUserID, token, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
cmd.Result = &models.User{Id: testUserID}
@ -103,18 +89,13 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
}
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code)
})
}, mock)
})
t.Run("When gets auth tokens for a user", func(t *testing.T) {
currentToken := &models.UserToken{Id: 1}
mock := mockstore.NewSQLStoreMock()
getUserAuthTokensInternalScenario(t, "Should be successful", currentToken, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
cmd.Result = &models.User{Id: testUserID}
return nil
})
tokens := []*models.UserToken{
{
Id: 1,
@ -165,12 +146,12 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
assert.Equal(t, "11.0", resultTwo.Get("browserVersion").MustString())
assert.Equal(t, "iOS", resultTwo.Get("os").MustString())
assert.Equal(t, "11.0", resultTwo.Get("osVersion").MustString())
})
}, mock)
})
}
func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd,
userId int64, fn scenarioFunc) {
userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -179,6 +160,7 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)
@ -199,7 +181,7 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
})
}
func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, userId int64, fn scenarioFunc) {
func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -208,6 +190,7 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, url)
@ -227,13 +210,14 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte
})
}
func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId int64, fn scenarioFunc) {
func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId int64, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: auth.NewFakeUserAuthTokenService(),
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, "/")
@ -253,7 +237,7 @@ func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId
}
func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.RevokeAuthTokenCmd, userId int64,
token *models.UserToken, fn scenarioFunc) {
token *models.UserToken, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -262,6 +246,7 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, "/")
@ -275,14 +260,12 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
return hs.revokeUserAuthTokenInternal(c, userId, cmd)
})
sc.m.Post("/", sc.defaultHandler)
fn(sc)
})
}
func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.UserToken, fn scenarioFunc) {
func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.UserToken, fn scenarioFunc, sqlStore sqlstore.Store) {
t.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers)
@ -291,6 +274,7 @@ func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.
hs := HTTPServer{
Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
}
sc := setupScenarioContext(t, "/")

View File

@ -65,6 +65,7 @@ import (
serviceaccountsmanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
"github.com/grafana/grafana/pkg/services/shorturls"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/teamguardian"
teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database"
teamguardianManager "github.com/grafana/grafana/pkg/services/teamguardian/manager"
@ -205,6 +206,7 @@ var wireSet = wire.NewSet(
wire.Bind(new(notifications.Service), new(*notifications.NotificationService)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)),
wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationService)),
wire.Bind(new(sqlstore.Store), new(*sqlstore.SQLStore)),
)
var wireTestSet = wire.NewSet(
@ -217,6 +219,8 @@ var wireTestSet = wire.NewSet(
wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationServiceMock)),
wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationServiceMock)),
mockstore.NewSQLStoreMock,
wire.Bind(new(sqlstore.Store), new(*mockstore.SQLStoreMock)),
)
func Initialize(cla setting.CommandLineArgs, opts Options, apiOpts api.ServerOptions) (*Server, error) {

View File

@ -91,7 +91,7 @@ func buildScopeParams(c *models.ReqContext) accesscontrol.ScopeParams {
type OrgIDGetter func(c *models.ReqContext) (int64, error)
func AuthorizeInOrgMiddleware(ac accesscontrol.AccessControl, db *sqlstore.SQLStore) func(web.Handler, OrgIDGetter, accesscontrol.Evaluator) web.Handler {
func AuthorizeInOrgMiddleware(ac accesscontrol.AccessControl, db sqlstore.Store) func(web.Handler, OrgIDGetter, accesscontrol.Evaluator) web.Handler {
return func(fallback web.Handler, getTargetOrg OrgIDGetter, evaluator accesscontrol.Evaluator) web.Handler {
if ac.IsDisabled() {
return fallback

View File

@ -9,7 +9,7 @@ import (
)
type SQLStoreMock struct {
SQLStore *sqlstore.SQLStore
ExpectedUser *models.User
ExpectedError error
}
@ -98,6 +98,7 @@ func (m SQLStoreMock) CreateUser(ctx context.Context, cmd models.CreateUserComma
}
func (m SQLStoreMock) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error {
query.Result = m.ExpectedUser
return m.ExpectedError
}
@ -150,7 +151,7 @@ func (m SQLStoreMock) DeleteUser(ctx context.Context, cmd *models.DeleteUserComm
}
func (m SQLStoreMock) UpdateUserPermissions(userID int64, isAdmin bool) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error {
@ -158,7 +159,11 @@ func (m SQLStoreMock) SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHe
}
func (m SQLStoreMock) CreateTeam(name string, email string, orgID int64) (models.Team, error) {
return models.Team{}, nil // TODO: Implement
return models.Team{
Name: name,
Email: email,
OrgId: orgID,
}, nil
}
func (m SQLStoreMock) UpdateTeam(ctx context.Context, cmd *models.UpdateTeamCommand) error {

View File

@ -30,7 +30,7 @@ func (ss *SQLStore) addUserQueryAndCommandHandlers() {
bus.AddHandler("sql", ss.GetUserProfile)
bus.AddHandler("sql", SearchUsers)
bus.AddHandler("sql", ss.GetUserOrgList)
bus.AddHandler("sql", DisableUser)
bus.AddHandler("sql", ss.DisableUser)
bus.AddHandler("sql", ss.BatchDisableUsers)
bus.AddHandler("sql", ss.DeleteUser)
bus.AddHandler("sql", ss.SetUserHelpFlag)
@ -320,7 +320,7 @@ func (ss *SQLStore) CreateUser(ctx context.Context, cmd models.CreateUserCommand
return user, err
}
func (ss *SQLStore) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error {
func (ss SQLStore) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error {
return withDbSession(ctx, x, func(sess *DBSession) error {
user := new(models.User)
has, err := sess.ID(query.Id).Get(user)
@ -721,7 +721,7 @@ func SearchUsers(ctx context.Context, query *models.SearchUsersQuery) error {
return err
}
func DisableUser(ctx context.Context, cmd *models.DisableUserCommand) error {
func (ss *SQLStore) DisableUser(ctx context.Context, cmd *models.DisableUserCommand) error {
user := models.User{}
sess := x.Table("user")