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
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/bus"
"github.com/grafana/grafana/pkg/infra/metrics" "github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "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) 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 err != nil {
if errors.Is(err, models.ErrLastGrafanaAdmin) { if errors.Is(err, models.ErrLastGrafanaAdmin) {
return response.Error(400, models.ErrLastGrafanaAdmin.Error(), nil) 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) 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/auth"
"github.com/grafana/grafana/pkg/services/login" "github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -34,25 +35,18 @@ func TestAdminAPIEndpoint(t *testing.T) {
updateCmd := dtos.AdminUpdateUserPermissionsForm{ updateCmd := dtos.AdminUpdateUserPermissionsForm{
IsGrafanaAdmin: false, IsGrafanaAdmin: false,
} }
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrLastGrafanaAdmin,
}
putAdminScenario(t, "When calling PUT on", "/api/admin/users/1/permissions", putAdminScenario(t, "When calling PUT on", "/api/admin/users/1/permissions",
"/api/admin/users/:id/permissions", role, updateCmd, func(sc *scenarioContext) { "/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() sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code) 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) { 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", adminLogoutUserScenario(t, "Should not be allowed when calling POST on",
"/api/admin/users/1/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) { "/api/admin/users/1/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error { 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() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code) 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) { 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", adminLogoutUserScenario(t, "Should return not found when calling POST on", "/api/admin/users/200/logout",
"/api/admin/users/:id/logout", func(sc *scenarioContext) { "/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() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) 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) { 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} cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
mock := mockstore.SQLStoreMock{
ExpectedError: models.ErrUserNotFound,
}
adminRevokeUserAuthTokenScenario(t, "Should return not found when calling POST on", 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) { "/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() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) 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) { 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", 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) { "/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() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) 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) { 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, 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
hs := &HTTPServer{ hs := &HTTPServer{
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: auth.NewFakeUserAuthTokenService(), AuthTokenService: auth.NewFakeUserAuthTokenService(),
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -366,6 +349,7 @@ func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, rou
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -395,6 +379,7 @@ func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, route
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)

View File

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

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations" "github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -55,6 +56,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) })
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) { "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
@ -62,7 +64,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code) 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() sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) })
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) { "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
fakeAnnoRepo = &fakeAnnotationsRepo{} fakeAnnoRepo = &fakeAnnotationsRepo{}
@ -92,7 +94,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) 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() sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) })
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) { "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
setUp() setUp()
@ -174,7 +176,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 403, sc.resp.Code) 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() sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) })
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
"/api/annotations/:annotationId", role, func(sc *scenarioContext) { "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
setUp() setUp()
@ -207,7 +209,7 @@ func TestAnnotationsAPIEndpoint(t *testing.T) {
sc.handlerFunc = DeleteAnnotationByID sc.handlerFunc = DeleteAnnotationByID
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) 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.Delete("/stars/dashboard/:id", routing.Wrap(hs.UnstarDashboard))
userRoute.Put("/password", routing.Wrap(hs.ChangeUserPassword)) 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)) userRoute.Put("/helpflags/:id", routing.Wrap(hs.SetHelpFlag))
// For dev purpose // For dev purpose
userRoute.Get("/helpflags/clear", routing.Wrap(hs.ClearHelpFlags)) userRoute.Get("/helpflags/clear", routing.Wrap(hs.ClearHelpFlags))
@ -264,7 +264,7 @@ func (hs *HTTPServer) registerRoutes() {
// Preferences // Preferences
apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) { 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 // Data sources
@ -493,8 +493,8 @@ func (hs *HTTPServer) registerRoutes() {
adminUserRoute.Delete("/:id", authorize(reqGrafanaAdmin, ac.EvalPermission(ac.ActionUsersDelete, userIDScope)), routing.Wrap(AdminDeleteUser)) 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/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.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.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(UpdateUserQuota)) 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.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)) 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" "github.com/stretchr/testify/require"
) )
func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) { 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) 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
sc := setupScenarioContext(t, url) sc := setupScenarioContext(t, url)
sc.sqlStore = sqlStore
sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response {
sc.context = c sc.context = c
sc.context.UserId = testUserID sc.context.UserId = testUserID
@ -156,6 +157,7 @@ type scenarioContext struct {
req *http.Request req *http.Request
url string url string
userAuthTokenService *auth.FakeUserAuthTokenService userAuthTokenService *auth.FakeUserAuthTokenService
sqlStore sqlstore.Store
} }
func (sc *scenarioContext) exec() { func (sc *scenarioContext) exec() {

View File

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

View File

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "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) { 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", 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) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t) mockSnapshotResult := setUpSnapshotTest(t)
@ -84,7 +86,7 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
require.Nil(t, externalRequest) require.Nil(t, externalRequest)
}) }, mock)
}) })
t.Run("When user is anonymous", func(t *testing.T) { 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: &viewerRole, Permission: models.PERMISSION_VIEW},
{Role: &editorRole, Permission: models.PERMISSION_EDIT}, {Role: &editorRole, Permission: models.PERMISSION_EDIT},
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE", 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) { "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t) mockSnapshotResult := setUpSnapshotTest(t)
@ -143,11 +145,12 @@ func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
assert.Equal(t, 1, respJSON.Get("id").MustInt()) assert.Equal(t, 1, respJSON.Get("id").MustInt())
assert.Equal(t, ts.URL, fmt.Sprintf("http://%s", externalRequest.Host)) assert.Equal(t, ts.URL, fmt.Sprintf("http://%s", externalRequest.Host))
assert.Equal(t, "/", externalRequest.URL.EscapedPath()) assert.Equal(t, "/", externalRequest.URL.EscapedPath())
}) }, mock)
}) })
t.Run("When user is editor and creator of the snapshot", func(t *testing.T) { t.Run("When user is editor and creator of the snapshot", func(t *testing.T) {
aclMockResp = []*models.DashboardAclInfoDTO{} aclMockResp = []*models.DashboardAclInfoDTO{}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", 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) { "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
mockSnapshotResult := setUpSnapshotTest(t) 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.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
assert.Equal(t, 1, respJSON.Get("id").MustInt()) assert.Equal(t, 1, respJSON.Get("id").MustInt())
}) }, mock)
}) })
t.Run("When deleting an external snapshot", func(t *testing.T) { t.Run("When deleting an external snapshot", func(t *testing.T) {
aclMockResp = []*models.DashboardAclInfoDTO{} aclMockResp = []*models.DashboardAclInfoDTO{}
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should gracefully delete local snapshot when remote snapshot has already been removed when calling DELETE on", "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) { "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.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
assert.Equal(t, 1, respJSON.Get("id").MustInt()) assert.Equal(t, 1, respJSON.Get("id").MustInt())
}) }, mock)
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected 500 error occurs when calling DELETE on", "DELETE", "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) require.NoError(t, writeErr)
assert.Equal(t, 500, sc.resp.Code) assert.Equal(t, 500, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, loggedInUserScenarioWithRole(t,
"Should fail to delete local snapshot when an unexpected remote error occurs when calling DELETE on", "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() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
assert.Equal(t, 500, sc.resp.Code) assert.Equal(t, 500, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "Should be able to read a snapshot's unencrypted data when calling GET on", 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) { "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") id := dashboard.Get("id")
assert.Equal(t, int64(100), id.MustInt64()) 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/provisioning"
"github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/quota"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert" "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) { t.Run("When user is an Org Viewer", func(t *testing.T) {
role := models.ROLE_VIEWER role := models.ROLE_VIEWER
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp() state := setUp()
@ -171,7 +172,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin) assert.False(t, dash.Meta.CanAdmin)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/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, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -193,7 +194,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -201,12 +202,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
}) })
t.Run("When user is an Org Editor", func(t *testing.T) { t.Run("When user is an Org Editor", func(t *testing.T) {
role := models.ROLE_EDITOR role := models.ROLE_EDITOR
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp() state := setUp()
@ -217,7 +218,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin) assert.False(t, dash.Meta.CanAdmin)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -227,10 +228,11 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{}, LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{}, LibraryElementService: &mockLibraryElementService{},
SQLStore: mock,
}) })
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -238,7 +240,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -246,7 +248,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) }, mock)
}) })
}) })
@ -256,6 +258,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Live: newTestLive(t), Live: newTestLive(t),
LibraryPanelService: &mockLibraryPanelService{}, LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{}, LibraryElementService: &mockLibraryElementService{},
SQLStore: mockstore.NewSQLStoreMock(),
} }
setUp := func() *testState { 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) { t.Run("When user is an Org Viewer and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_VIEWER role := models.ROLE_VIEWER
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp() state := setUp()
@ -324,7 +327,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -333,7 +336,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -341,7 +344,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -349,12 +352,12 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code) 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) { t.Run("When user is an Org Editor and has no permissions for this dashboard", func(t *testing.T) {
role := models.ROLE_EDITOR role := models.ROLE_EDITOR
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUp() state := setUp()
@ -364,7 +367,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
@ -373,7 +376,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1",
"/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
@ -381,7 +384,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions",
"/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) { "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
@ -389,7 +392,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code) 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) { 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 return state
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi",
"/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -418,29 +421,28 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin) 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) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) }, mock)
}) })
t.Run("When user is an Org Viewer and viewers can edit", func(t *testing.T) { 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 return state
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -477,7 +479,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) assert.False(t, dash.Meta.CanSave)
assert.False(t, dash.Meta.CanAdmin) 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) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -485,7 +487,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) 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) { 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 return state
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -513,7 +515,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.True(t, dash.Meta.CanEdit) assert.True(t, dash.Meta.CanEdit)
assert.True(t, dash.Meta.CanSave) assert.True(t, dash.Meta.CanSave)
assert.True(t, dash.Meta.CanAdmin) 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) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -521,21 +523,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 200, sc.resp.Code) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 200, sc.resp.Code) 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) { 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 return state
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -561,7 +563,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid)
assert.False(t, dash.Meta.CanEdit) assert.False(t, dash.Meta.CanEdit)
assert.False(t, dash.Meta.CanSave) 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) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/uid/abcdefghi", "/api/dashboards/uid/:uid", role, func(sc *scenarioContext) {
state := setUpInner() state := setUpInner()
@ -569,21 +571,21 @@ func TestDashboardAPIEndpoint(t *testing.T) {
callDeleteDashboardByUID(sc, hs) callDeleteDashboardByUID(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
assert.Equal(t, "abcdefghi", state.dashQueries[0].Uid) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions/1", "/api/dashboards/id/:dashboardId/versions/:id", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersion(sc) callGetDashboardVersion(sc)
assert.Equal(t, 403, sc.resp.Code) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/2/versions", "/api/dashboards/id/:dashboardId/versions", role, func(sc *scenarioContext) {
setUpInner() setUpInner()
callGetDashboardVersions(sc) callGetDashboardVersions(sc)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mock)
}) })
}) })
@ -964,7 +966,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
return nil 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) { loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/dashboards/db/abcdefghi", "/api/dashboards/db/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp() setUp()
@ -972,12 +974,13 @@ func TestDashboardAPIEndpoint(t *testing.T) {
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
LibraryPanelService: &mockLibraryPanelService{}, LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{}, LibraryElementService: &mockLibraryElementService{},
SQLStore: mock,
}) })
assert.Equal(t, 400, sc.resp.Code) assert.Equal(t, 400, sc.resp.Code)
result := sc.ToJSON() result := sc.ToJSON()
assert.Equal(t, models.ErrDashboardCannotDeleteProvisionedDashboard.Error(), result.Get("error").MustString()) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/uid/dash", "/api/dashboards/uid/:uid", models.ROLE_EDITOR, func(sc *scenarioContext) {
setUp() setUp()
@ -990,8 +993,9 @@ func TestDashboardAPIEndpoint(t *testing.T) {
dash := getDashboardShouldReturn200WithConfig(sc, mock) dash := getDashboardShouldReturn200WithConfig(sc, mock)
assert.Equal(t, filepath.Join("test", "dashboard1.json"), dash.Meta.ProvisionedExternalId) 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) { 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() setUp()
@ -1008,6 +1012,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
ProvisioningService: mock, ProvisioningService: mock,
LibraryPanelService: &mockLibraryPanelService{}, LibraryPanelService: &mockLibraryPanelService{},
LibraryElementService: &mockLibraryElementService{}, LibraryElementService: &mockLibraryElementService{},
SQLStore: mockSQLStore,
} }
callGetDashboard(sc, hs) callGetDashboard(sc, hs)
@ -1018,7 +1023,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, false, dash.Meta.Provisioned) assert.Equal(t, false, dash.Meta.Provisioned)
}) }, mock)
}) })
} }
@ -1036,6 +1041,7 @@ func getDashboardShouldReturn200WithConfig(sc *scenarioContext, provisioningServ
LibraryPanelService: &libraryPanelsService, LibraryPanelService: &libraryPanelsService,
LibraryElementService: &libraryElementsService, LibraryElementService: &libraryElementsService,
ProvisioningService: provisioningService, ProvisioningService: provisioningService,
SQLStore: sc.sqlStore,
} }
callGetDashboard(sc, hs) callGetDashboard(sc, hs)

View File

@ -15,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -27,6 +28,7 @@ const (
) )
func TestDataSourcesProxy_userLoggedIn(t *testing.T) { func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "/api/datasources/", "/api/datasources/", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "/api/datasources/", "/api/datasources/", func(sc *scenarioContext) {
// Stubs the database query // Stubs the database query
bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourcesQuery) error { bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourcesQuery) error {
@ -45,6 +47,7 @@ func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
Bus: bus.GetBus(), Bus: bus.GetBus(),
Cfg: setting.NewCfg(), Cfg: setting.NewCfg(),
pluginStore: &fakePluginStore{}, pluginStore: &fakePluginStore{},
SQLStore: mock,
} }
sc.handlerFunc = hs.GetDataSources sc.handlerFunc = hs.GetDataSources
sc.fakeReq("GET", "/api/datasources").exec() 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, "BBB", respJSON[1]["name"])
assert.Equal(t, "mmm", respJSON[2]["name"]) assert.Equal(t, "mmm", respJSON[2]["name"])
assert.Equal(t, "ZZZ", respJSON[3]["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", 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) { "/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.handlerFunc = hs.DeleteDataSourceByName
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) assert.Equal(t, 404, sc.resp.Code)
}) }, mock)
} }
// Adding data sources with invalid URLs should lead to an error. // 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/models"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/guardian" "github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
) )
@ -34,11 +35,11 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
dashboards.NewFolderService = origNewFolderService dashboards.NewFolderService = origNewFolderService
}) })
mockFolderService(mock) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 404, sc.resp.Code) assert.Equal(t, 404, sc.resp.Code)
}) }, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{ cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{ Items: []dtos.DashboardAclUpdateItem{
@ -77,11 +78,11 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
} }
mockFolderService(mock) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 403, sc.resp.Code) assert.Equal(t, 403, sc.resp.Code)
}) }, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{ cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{ Items: []dtos.DashboardAclUpdateItem{
@ -130,7 +131,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
} }
mockFolderService(mock) 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
@ -142,7 +143,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
assert.Len(t, resp, 5) assert.Len(t, resp, 5)
assert.Equal(t, int64(2), resp[0].UserId) assert.Equal(t, int64(2), resp[0].UserId)
assert.Equal(t, models.PERMISSION_VIEW, resp[0].Permission) assert.Equal(t, models.PERMISSION_VIEW, resp[0].Permission)
}) }, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{ cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{ Items: []dtos.DashboardAclUpdateItem{
@ -325,6 +326,7 @@ func TestFolderPermissionAPIEndpoint(t *testing.T) {
mockFolderService(mock) mockFolderService(mock)
var resp []*models.DashboardAclInfoDTO 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) { loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
callGetFolderPermissions(sc, hs) callGetFolderPermissions(sc, hs)
assert.Equal(t, 200, sc.resp.Code) 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, models.PERMISSION_EDIT, resp[0].Permission)
assert.Equal(t, int64(4), resp[1].UserId) assert.Equal(t, int64(4), resp[1].UserId)
assert.Equal(t, models.PERMISSION_ADMIN, resp[1].Permission) assert.Equal(t, models.PERMISSION_ADMIN, resp[1].Permission)
}) }, mockSQLStore)
cmd := dtos.UpdateDashboardAclCommand{ cmd := dtos.UpdateDashboardAclCommand{
Items: []dtos.DashboardAclUpdateItem{ Items: []dtos.DashboardAclUpdateItem{

View File

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

View File

@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/setting"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
) )
@ -41,7 +42,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
sqlStore := sqlstore.InitTestDB(t) sqlStore := sqlstore.InitTestDB(t)
sqlStore.Cfg = settings sqlStore.Cfg = settings
hs.SQLStore = sqlStore hs.SQLStore = sqlStore
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "api/org/users", "api/org/users", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "api/org/users", "api/org/users", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore) setUpGetOrgUsersDB(t, sqlStore)
@ -54,7 +55,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
err := json.Unmarshal(sc.resp.Body.Bytes(), &resp) err := json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, resp, 3) assert.Len(t, resp, 3)
}) }, mock)
loggedInUserScenario(t, "When calling GET on", "api/org/users/search", "api/org/users/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "api/org/users/search", "api/org/users/search", func(sc *scenarioContext) {
setUpGetOrgUsersDB(t, sqlStore) setUpGetOrgUsersDB(t, sqlStore)
@ -72,7 +73,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, int64(3), resp.TotalCount) assert.Equal(t, int64(3), resp.TotalCount)
assert.Equal(t, 1000, resp.PerPage) assert.Equal(t, 1000, resp.PerPage)
assert.Equal(t, 1, resp.Page) 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) { 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) setUpGetOrgUsersDB(t, sqlStore)
@ -90,7 +91,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, int64(3), resp.TotalCount) assert.Equal(t, int64(3), resp.TotalCount)
assert.Equal(t, 2, resp.PerPage) assert.Equal(t, 2, resp.PerPage)
assert.Equal(t, 2, resp.Page) assert.Equal(t, 2, resp.Page)
}) }, mock)
t.Run("Given there are two hidden users", func(t *testing.T) { t.Run("Given there are two hidden users", func(t *testing.T) {
settings.HiddenUsers = map[string]struct{}{ settings.HiddenUsers = map[string]struct{}{
@ -113,7 +114,7 @@ func TestOrgUsersAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Len(t, resp, 2) assert.Len(t, resp, 2)
assert.Equal(t, testUserLogin, resp[0].Login) assert.Equal(t, testUserLogin, resp[0].Login)
assert.Equal(t, "user2", resp[1].Login) assert.Equal(t, "user2", resp[1].Login)
}) }, mock)
loggedInUserScenarioWithRole(t, "When calling GET as an admin on", "GET", "api/org/users/lookup", loggedInUserScenarioWithRole(t, "When calling GET as an admin on", "GET", "api/org/users/lookup",
"api/org/users/lookup", models.ROLE_ADMIN, func(sc *scenarioContext) { "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.Len(t, resp, 2)
assert.Equal(t, testUserLogin, resp[0].Login) assert.Equal(t, testUserLogin, resp[0].Login)
assert.Equal(t, "user2", resp[1].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-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response" "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/infra/fs"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins" "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} 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) { if !errors.Is(err, models.ErrPluginSettingNotFound) {
return response.Error(500, "Failed to get login settings", nil) 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.OrgId = c.OrgId
cmd.PluginId = pluginID 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) 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/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
) )
@ -18,7 +17,7 @@ const (
) )
// POST /api/preferences/set-home-dash // 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{} cmd := models.SavePreferencesCommand{}
if err := web.Bind(c.Req, &cmd); err != nil { if err := web.Bind(c.Req, &cmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err) 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.UserId = c.UserId
cmd.OrgId = c.OrgId 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) return response.Error(500, "Failed to set home dashboard", err)
} }

View File

@ -5,7 +5,6 @@ import (
"strconv" "strconv"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web" "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") 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 { if !setting.Quota.Enabled {
return response.Error(404, "Quotas not enabled", nil) return response.Error(404, "Quotas not enabled", nil)
} }
@ -73,14 +72,14 @@ func GetUserQuotas(c *models.ReqContext) response.Response {
query := models.GetUserQuotasQuery{UserId: id} 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.Error(500, "Failed to get org quotas", err)
} }
return response.JSON(200, query.Result) 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{} cmd := models.UpdateUserQuotaCmd{}
var err error var err error
if err := web.Bind(c.Req, &cmd); err != nil { 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) 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.Error(500, "Failed to update org quotas", err)
} }
return response.Success("Organization quota updated") 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/api/response"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/featuremgmt" "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/util"
"github.com/grafana/grafana/pkg/web" "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) 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 err != nil {
if errors.Is(err, models.ErrTeamNameTaken) { if errors.Is(err, models.ErrTeamNameTaken) {
return response.Error(409, "Team name taken", err) 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") c.Logger.Warn("Could not add creator to team because is not a real user")
} }
} }
return response.JSON(200, &util.DynMap{ return response.JSON(200, &util.DynMap{
"teamId": team.Id, "teamId": team.Id,
"message": "Team created", "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) 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/accesscontrol"
"github.com/grafana/grafana/pkg/services/licensing" "github.com/grafana/grafana/pkg/services/licensing"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/database"
"github.com/grafana/grafana/pkg/services/teamguardian/manager" "github.com/grafana/grafana/pkg/services/teamguardian/manager"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
@ -47,6 +48,7 @@ func TestTeamMembersAPIEndpoint_userLoggedIn(t *testing.T) {
License: &licensing.OSSLicensingService{}, License: &licensing.OSSLicensingService{},
SQLStore: sqlStore, SQLStore: sqlStore,
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members", loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "api/teams/1/members",
"api/teams/:teamId/members", models.ROLE_ADMIN, func(sc *scenarioContext) { "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) err := json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err) require.NoError(t, err)
assert.Len(t, resp, 3) assert.Len(t, resp, 3)
}) }, mock)
t.Run("Given there is two hidden users", func(t *testing.T) { t.Run("Given there is two hidden users", func(t *testing.T) {
settings.HiddenUsers = map[string]struct{}{ 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, "loginuser0", resp[0].Login)
assert.Equal(t, "loginuser1", resp[1].Login) assert.Equal(t, "loginuser1", resp[1].Login)
assert.Equal(t, "loginuser2", resp[2].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"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions" "github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/setting"
"github.com/grafana/grafana/pkg/web" "github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -34,7 +35,7 @@ func TestTeamAPIEndpoint(t *testing.T) {
t.Run("Given two teams", func(t *testing.T) { t.Run("Given two teams", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
hs.SQLStore = sqlstore.InitTestDB(t) hs.SQLStore = sqlstore.InitTestDB(t)
mock := mockstore.SQLStoreMock{}
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1) _, err := hs.SQLStore.CreateTeam("team1", "", 1)
require.NoError(t, err) require.NoError(t, err)
@ -50,7 +51,7 @@ func TestTeamAPIEndpoint(t *testing.T) {
assert.EqualValues(t, 2, resp.TotalCount) assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 2, len(resp.Teams)) assert.Equal(t, 2, len(resp.Teams))
}) }, mock)
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1) _, err := hs.SQLStore.CreateTeam("team1", "", 1)
@ -67,29 +68,15 @@ func TestTeamAPIEndpoint(t *testing.T) {
assert.EqualValues(t, 2, resp.TotalCount) assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 0, len(resp.Teams)) assert.Equal(t, 0, len(resp.Teams))
}) }, mock)
}) })
t.Run("When creating team with API key", func(t *testing.T) { t.Run("When creating team with API key", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil) hs := setupSimpleHTTPServer(nil)
hs.Cfg.EditorsCanAdmin = true hs.Cfg.EditorsCanAdmin = true
hs.SQLStore = mockstore.NewSQLStoreMock()
teamName := "team foo" 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 addTeamMemberCalled := 0
addOrUpdateTeamMember = func(ctx context.Context, resourcePermissionService *resourcepermissions.Service, userID, orgID, teamID int64, addOrUpdateTeamMember = func(ctx context.Context, resourcePermissionService *resourcepermissions.Service, userID, orgID, teamID int64,
permission string) error { permission string) error {
@ -109,9 +96,9 @@ func TestTeamAPIEndpoint(t *testing.T) {
} }
c.OrgRole = models.ROLE_EDITOR c.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName}) c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
hs.CreateTeam(c) r := hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 0) assert.Equal(t, 200, r.Status())
assert.True(t, stub.warnCalled) assert.True(t, stub.warnCalled)
assert.Equal(t, stub.warnMessage, "Could not add creator to team because is not a real user") 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.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName}) c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
createTeamCalled, addTeamMemberCalled = 0, 0 r := hs.CreateTeam(c)
hs.CreateTeam(c) assert.Equal(t, 200, r.Status())
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 1)
assert.False(t, stub.warnCalled) assert.False(t, stub.warnCalled)
}) })
}) })

View File

@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/services/secrets/database" "github.com/grafana/grafana/pkg/services/secrets/database"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/services/sqlstore" "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/setting"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -41,7 +42,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
}, },
TotalCount: 2, TotalCount: 2,
} }
mock := mockstore.NewSQLStoreMock()
loggedInUserScenario(t, "When calling GET on", "api/users/1", "api/users/:id", func(sc *scenarioContext) { 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) fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore)) secretsService := secretsManager.SetupTestService(t, database.ProvideSecretsStore(sqlStore))
@ -100,7 +101,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
resp.UpdatedAt = fakeNow resp.UpdatedAt = fakeNow
resp.AvatarUrl = avatarUrl resp.AvatarUrl = avatarUrl
require.EqualValues(t, expected, resp) require.EqualValues(t, expected, resp)
}) }, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users/lookup", "/api/users/lookup", func(sc *scenarioContext) { 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) 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", resp.Login)
require.Equal(t, "admin@test.com", resp.Email) require.Equal(t, "admin@test.com", resp.Email)
require.True(t, resp.IsGrafanaAdmin) require.True(t, resp.IsGrafanaAdmin)
}) }, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users", "/api/users", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "/api/users", "/api/users", func(sc *scenarioContext) {
var sentLimit int var sentLimit int
@ -165,7 +166,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes()) respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, 2, len(respJSON.MustArray())) 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) { loggedInUserScenario(t, "When calling GET with page and limit querystring parameters on", "/api/users", "/api/users", func(sc *scenarioContext) {
var sentLimit int var sentLimit int
@ -185,7 +186,7 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, 10, sentLimit) assert.Equal(t, 10, sentLimit)
assert.Equal(t, 2, sendPage) assert.Equal(t, 2, sendPage)
}) }, mock)
loggedInUserScenario(t, "When calling GET on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) { loggedInUserScenario(t, "When calling GET on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) {
var sentLimit int 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, respJSON.Get("totalCount").MustInt())
assert.Equal(t, 2, len(respJSON.Get("users").MustArray())) 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) { loggedInUserScenario(t, "When calling GET with page and perpage querystring parameters on", "/api/users/search", "/api/users/search", func(sc *scenarioContext) {
var sentLimit int var sentLimit int
@ -231,5 +232,5 @@ func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
assert.Equal(t, 10, sentLimit) assert.Equal(t, 10, sentLimit)
assert.Equal(t, 2, sendPage) 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/dtos"
"github.com/grafana/grafana/pkg/api/response" "github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util" "github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/web" "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 { func (hs *HTTPServer) logoutUserFromAllDevicesInternal(ctx context.Context, userID int64) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID} 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) { if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err) 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 { func (hs *HTTPServer) getUserAuthTokensInternal(c *models.ReqContext, userID int64) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID} 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) { if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err) 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 { func (hs *HTTPServer) revokeUserAuthTokenInternal(c *models.ReqContext, userID int64, cmd models.RevokeAuthTokenCmd) response.Response {
userQuery := models.GetUserByIdQuery{Id: userID} userQuery := models.GetUserByIdQuery{Id: userID}
if err := hs.SQLStore.GetUserById(c.Req.Context(), &userQuery); err != nil {
if err := bus.Dispatch(c.Req.Context(), &userQuery); err != nil {
if errors.Is(err, models.ErrUserNotFound) { if errors.Is(err, models.ErrUserNotFound) {
return response.Error(404, "User not found", err) 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/bus"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/auth" "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" "github.com/stretchr/testify/assert"
) )
func TestUserTokenAPIEndpoint(t *testing.T) { 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) { 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} cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
mock.ExpectedError = models.ErrUserNotFound
revokeUserAuthTokenScenario(t, "Should return not found when calling POST on", "/api/user/revoke-auth-token", 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) { "/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() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) 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) { 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) { 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() sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) 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) { 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) { 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() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) }, mock)
}) })
t.Run("When logout a non-existing user from all devices", func(t *testing.T) { 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) { logoutUserFromAllDevicesInternalScenario(t, "Should return not found", testUserID, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error { mock.ExpectedError = models.ErrUserNotFound
return models.ErrUserNotFound
})
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 404, sc.resp.Code) assert.Equal(t, 404, sc.resp.Code)
}) }, mock)
}) })
t.Run("When revoke an auth token for a user", func(t *testing.T) { t.Run("When revoke an auth token for a user", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2} cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
token := &models.UserToken{Id: 1} token := &models.UserToken{Id: 1}
mock := mockstore.SQLStoreMock{
ExpectedUser: &models.User{Id: 200},
}
revokeUserAuthTokenInternalScenario(t, "Should be successful", cmd, 200, token, func(sc *scenarioContext) { 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) { sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*models.UserToken, error) {
return &models.UserToken{Id: 2}, nil return &models.UserToken{Id: 2}, nil
} }
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 200, sc.resp.Code) assert.Equal(t, 200, sc.resp.Code)
}) }, mock)
}) })
t.Run("When revoke the active auth token used by himself", func(t *testing.T) { t.Run("When revoke the active auth token used by himself", func(t *testing.T) {
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2} cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
token := &models.UserToken{Id: 2} token := &models.UserToken{Id: 2}
mock := mockstore.NewSQLStoreMock()
revokeUserAuthTokenInternalScenario(t, "Should not be successful", cmd, testUserID, token, func(sc *scenarioContext) { revokeUserAuthTokenInternalScenario(t, "Should not be successful", cmd, testUserID, token, func(sc *scenarioContext) {
bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error { bus.AddHandler("test", func(ctx context.Context, cmd *models.GetUserByIdQuery) error {
cmd.Result = &models.User{Id: testUserID} cmd.Result = &models.User{Id: testUserID}
@ -103,18 +89,13 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
} }
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec() sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
assert.Equal(t, 400, sc.resp.Code) assert.Equal(t, 400, sc.resp.Code)
}) }, mock)
}) })
t.Run("When gets auth tokens for a user", func(t *testing.T) { t.Run("When gets auth tokens for a user", func(t *testing.T) {
currentToken := &models.UserToken{Id: 1} currentToken := &models.UserToken{Id: 1}
mock := mockstore.NewSQLStoreMock()
getUserAuthTokensInternalScenario(t, "Should be successful", currentToken, func(sc *scenarioContext) { 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{ tokens := []*models.UserToken{
{ {
Id: 1, Id: 1,
@ -165,12 +146,12 @@ func TestUserTokenAPIEndpoint(t *testing.T) {
assert.Equal(t, "11.0", resultTwo.Get("browserVersion").MustString()) assert.Equal(t, "11.0", resultTwo.Get("browserVersion").MustString())
assert.Equal(t, "iOS", resultTwo.Get("os").MustString()) assert.Equal(t, "iOS", resultTwo.Get("os").MustString())
assert.Equal(t, "11.0", resultTwo.Get("osVersion").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, 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -179,6 +160,7 @@ func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePat
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) 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.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -208,6 +190,7 @@ func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePatte
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, url) 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.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: auth.NewFakeUserAuthTokenService(), AuthTokenService: auth.NewFakeUserAuthTokenService(),
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, "/") 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, 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.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -262,6 +246,7 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, "/") sc := setupScenarioContext(t, "/")
@ -275,14 +260,12 @@ func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.R
return hs.revokeUserAuthTokenInternal(c, userId, cmd) return hs.revokeUserAuthTokenInternal(c, userId, cmd)
}) })
sc.m.Post("/", sc.defaultHandler) sc.m.Post("/", sc.defaultHandler)
fn(sc) 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.Run(desc, func(t *testing.T) {
t.Cleanup(bus.ClearBusHandlers) t.Cleanup(bus.ClearBusHandlers)
@ -291,6 +274,7 @@ func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.
hs := HTTPServer{ hs := HTTPServer{
Bus: bus.GetBus(), Bus: bus.GetBus(),
AuthTokenService: fakeAuthTokenService, AuthTokenService: fakeAuthTokenService,
SQLStore: sqlStore,
} }
sc := setupScenarioContext(t, "/") sc := setupScenarioContext(t, "/")

View File

@ -65,6 +65,7 @@ import (
serviceaccountsmanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager" serviceaccountsmanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
"github.com/grafana/grafana/pkg/services/shorturls" "github.com/grafana/grafana/pkg/services/shorturls"
"github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/teamguardian" "github.com/grafana/grafana/pkg/services/teamguardian"
teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database" teamguardianDatabase "github.com/grafana/grafana/pkg/services/teamguardian/database"
teamguardianManager "github.com/grafana/grafana/pkg/services/teamguardian/manager" 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.Service), new(*notifications.NotificationService)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)), wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)),
wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationService)), wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationService)),
wire.Bind(new(sqlstore.Store), new(*sqlstore.SQLStore)),
) )
var wireTestSet = wire.NewSet( var wireTestSet = wire.NewSet(
@ -217,6 +219,8 @@ var wireTestSet = wire.NewSet(
wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)), wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationServiceMock)), wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationServiceMock)),
wire.Bind(new(notifications.EmailSender), 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) { 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) 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 { return func(fallback web.Handler, getTargetOrg OrgIDGetter, evaluator accesscontrol.Evaluator) web.Handler {
if ac.IsDisabled() { if ac.IsDisabled() {
return fallback return fallback

View File

@ -9,7 +9,7 @@ import (
) )
type SQLStoreMock struct { type SQLStoreMock struct {
SQLStore *sqlstore.SQLStore ExpectedUser *models.User
ExpectedError error 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 { func (m SQLStoreMock) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error {
query.Result = m.ExpectedUser
return m.ExpectedError 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 { 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 { 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) { 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 { 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", ss.GetUserProfile)
bus.AddHandler("sql", SearchUsers) bus.AddHandler("sql", SearchUsers)
bus.AddHandler("sql", ss.GetUserOrgList) bus.AddHandler("sql", ss.GetUserOrgList)
bus.AddHandler("sql", DisableUser) bus.AddHandler("sql", ss.DisableUser)
bus.AddHandler("sql", ss.BatchDisableUsers) bus.AddHandler("sql", ss.BatchDisableUsers)
bus.AddHandler("sql", ss.DeleteUser) bus.AddHandler("sql", ss.DeleteUser)
bus.AddHandler("sql", ss.SetUserHelpFlag) bus.AddHandler("sql", ss.SetUserHelpFlag)
@ -320,7 +320,7 @@ func (ss *SQLStore) CreateUser(ctx context.Context, cmd models.CreateUserCommand
return user, err 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 { return withDbSession(ctx, x, func(sess *DBSession) error {
user := new(models.User) user := new(models.User)
has, err := sess.ID(query.Id).Get(user) has, err := sess.ID(query.Id).Get(user)
@ -721,7 +721,7 @@ func SearchUsers(ctx context.Context, query *models.SearchUsersQuery) error {
return err 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{} user := models.User{}
sess := x.Table("user") sess := x.Table("user")