mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Convert API tests to standard Go lib (#29009)
* Chore: Convert tests to standard Go lib Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
This commit is contained in:
parent
df8f63de7f
commit
cb62e69997
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
@ -8,288 +9,356 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
TestLogin = "test@example.com"
|
||||
TestPassword = "password"
|
||||
testLogin = "test@example.com"
|
||||
testPassword = "password"
|
||||
nonExistingOrgID = 1000
|
||||
)
|
||||
|
||||
func TestAdminApiEndpoint(t *testing.T) {
|
||||
role := models.ROLE_ADMIN
|
||||
Convey("Given a server admin attempts to remove themself as an admin", t, func() {
|
||||
func TestAdminAPIEndpoint(t *testing.T) {
|
||||
const role = models.ROLE_ADMIN
|
||||
|
||||
t.Run("Given a server admin attempts to remove themself as an admin", func(t *testing.T) {
|
||||
updateCmd := dtos.AdminUpdateUserPermissionsForm{
|
||||
IsGrafanaAdmin: false,
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.UpdateUserPermissionsCommand) error {
|
||||
return models.ErrLastGrafanaAdmin
|
||||
})
|
||||
putAdminScenario(t, "When calling PUT on", "/api/admin/users/1/permissions",
|
||||
"/api/admin/users/:id/permissions", role, updateCmd, func(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.UpdateUserPermissionsCommand) error {
|
||||
return models.ErrLastGrafanaAdmin
|
||||
})
|
||||
|
||||
putAdminScenario("When calling PUT on", "/api/admin/users/1/permissions", "/api/admin/users/:id/permissions", role, updateCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to logout himself from all devices", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: TestUserID}
|
||||
return nil
|
||||
})
|
||||
t.Run("When a server admin attempts to logout himself from all devices", func(t *testing.T) {
|
||||
adminLogoutUserScenario(t, "Should not be allowed when calling POST on",
|
||||
"/api/admin/users/1/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
adminLogoutUserScenario("Should not be allowed when calling POST on", "/api/admin/users/1/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to logout a non-existing user from all devices", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userId = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
t.Run("When a server admin attempts to logout a non-existing user from all devices", func(t *testing.T) {
|
||||
adminLogoutUserScenario(t, "Should return not found when calling POST on", "/api/admin/users/200/logout",
|
||||
"/api/admin/users/:id/logout", func(sc *scenarioContext) {
|
||||
userID := int64(0)
|
||||
|
||||
adminLogoutUserScenario("Should return not found when calling POST on", "/api/admin/users/200/logout", "/api/admin/users/:id/logout", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
So(userId, ShouldEqual, 200)
|
||||
})
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userID = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
assert.Equal(t, int64(200), userID)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to revoke an auth token for a non-existing user", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userId = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
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}
|
||||
|
||||
adminRevokeUserAuthTokenScenario("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) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
So(userId, ShouldEqual, 200)
|
||||
})
|
||||
})
|
||||
adminRevokeUserAuthTokenScenario(t, "Should return not found when calling POST on",
|
||||
"/api/admin/users/200/revoke-auth-token", "/api/admin/users/:id/revoke-auth-token", cmd, func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userID = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
Convey("When a server admin gets auth tokens for a non-existing user", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userId = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
adminGetUserAuthTokensScenario("Should return not found when calling GET on", "/api/admin/users/200/auth-tokens", "/api/admin/users/:id/auth-tokens", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
So(userId, ShouldEqual, 200)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to enable/disable a nonexistent user", t, func() {
|
||||
var userId int64
|
||||
isDisabled := false
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.DisableUserCommand) error {
|
||||
userId = cmd.UserId
|
||||
isDisabled = cmd.IsDisabled
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
adminDisableUserScenario("Should return user not found on a POST request", "enable", "/api/admin/users/42/enable", "/api/admin/users/:id/enable", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "user not found")
|
||||
|
||||
So(userId, ShouldEqual, 42)
|
||||
So(isDisabled, ShouldEqual, false)
|
||||
})
|
||||
|
||||
adminDisableUserScenario("Should return user not found on a POST request", "disable", "/api/admin/users/42/disable", "/api/admin/users/:id/disable", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "user not found")
|
||||
|
||||
So(userId, ShouldEqual, 42)
|
||||
So(isDisabled, ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to disable/enable external user", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
userId = cmd.UserId
|
||||
return nil
|
||||
})
|
||||
|
||||
adminDisableUserScenario("Should return Could not disable external user error", "disable", "/api/admin/users/42/disable", "/api/admin/users/:id/disable", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 500)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "Could not disable external user")
|
||||
|
||||
So(userId, ShouldEqual, 42)
|
||||
})
|
||||
|
||||
adminDisableUserScenario("Should return Could not enable external user error", "enable", "/api/admin/users/42/enable", "/api/admin/users/:id/enable", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 500)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "Could not enable external user")
|
||||
|
||||
So(userId, ShouldEqual, 42)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to delete a nonexistent user", t, func() {
|
||||
var userId int64
|
||||
bus.AddHandler("test", func(cmd *models.DeleteUserCommand) error {
|
||||
userId = cmd.UserId
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
adminDeleteUserScenario("Should return user not found error", "/api/admin/users/42", "/api/admin/users/:id", func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "user not found")
|
||||
|
||||
So(userId, ShouldEqual, 42)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to create a user", t, func() {
|
||||
var userLogin string
|
||||
var orgId int64
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
userLogin = cmd.Login
|
||||
orgId = cmd.OrgId
|
||||
|
||||
if orgId == nonExistingOrgID {
|
||||
return models.ErrOrgNotFound
|
||||
}
|
||||
|
||||
cmd.Result = models.User{Id: TestUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Without an organization", func() {
|
||||
createCmd := dtos.AdminCreateUserForm{
|
||||
Login: TestLogin,
|
||||
Password: TestPassword,
|
||||
}
|
||||
|
||||
adminCreateUserScenario("Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
assert.Equal(t, int64(200), userID)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When a server admin gets auth tokens for a non-existing user", func(t *testing.T) {
|
||||
adminGetUserAuthTokensScenario(t, "Should return not found when calling GET on",
|
||||
"/api/admin/users/200/auth-tokens", "/api/admin/users/:id/auth-tokens", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userID = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
assert.Equal(t, int64(200), userID)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to enable/disable a nonexistent user", func(t *testing.T) {
|
||||
adminDisableUserScenario(t, "Should return user not found on a POST request", "enable",
|
||||
"/api/admin/users/42/enable", "/api/admin/users/:id/enable", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
isDisabled := false
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.DisableUserCommand) error {
|
||||
userID = cmd.UserId
|
||||
isDisabled = cmd.IsDisabled
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "user not found", respJSON.Get("message").MustString())
|
||||
|
||||
assert.Equal(t, int64(42), userID)
|
||||
assert.Equal(t, false, isDisabled)
|
||||
})
|
||||
|
||||
adminDisableUserScenario(t, "Should return user not found on a POST request", "disable",
|
||||
"/api/admin/users/42/disable", "/api/admin/users/:id/disable", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
isDisabled := false
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.DisableUserCommand) error {
|
||||
userID = cmd.UserId
|
||||
isDisabled = cmd.IsDisabled
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "user not found", respJSON.Get("message").MustString())
|
||||
|
||||
assert.Equal(t, int64(42), userID)
|
||||
assert.Equal(t, true, isDisabled)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to disable/enable external user", func(t *testing.T) {
|
||||
adminDisableUserScenario(t, "Should return Could not disable external user error", "disable",
|
||||
"/api/admin/users/42/disable", "/api/admin/users/:id/disable", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
userID = cmd.UserId
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 500, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("id").MustInt64(), ShouldEqual, TestUserID)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "User created")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Could not disable external user", respJSON.Get("message").MustString())
|
||||
|
||||
// test that userLogin and orgId were transmitted correctly to the handler
|
||||
So(userLogin, ShouldEqual, TestLogin)
|
||||
So(orgId, ShouldEqual, 0)
|
||||
assert.Equal(t, int64(42), userID)
|
||||
})
|
||||
|
||||
adminDisableUserScenario(t, "Should return Could not enable external user error", "enable",
|
||||
"/api/admin/users/42/enable", "/api/admin/users/:id/enable", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.GetAuthInfoQuery) error {
|
||||
userID = cmd.UserId
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 500, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Could not enable external user", respJSON.Get("message").MustString())
|
||||
|
||||
assert.Equal(t, int64(42), userID)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to delete a nonexistent user", func(t *testing.T) {
|
||||
adminDeleteUserScenario(t, "Should return user not found error", "/api/admin/users/42",
|
||||
"/api/admin/users/:id", func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.DeleteUserCommand) error {
|
||||
userID = cmd.UserId
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user not found", respJSON.Get("message").MustString())
|
||||
|
||||
assert.Equal(t, int64(42), userID)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to create a user", func(t *testing.T) {
|
||||
t.Run("Without an organization", func(t *testing.T) {
|
||||
createCmd := dtos.AdminCreateUserForm{
|
||||
Login: testLogin,
|
||||
Password: testPassword,
|
||||
}
|
||||
|
||||
adminCreateUserScenario(t, "Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
bus.ClearBusHandlers()
|
||||
|
||||
var userLogin string
|
||||
var orgID int64
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
userLogin = cmd.Login
|
||||
orgID = cmd.OrgId
|
||||
|
||||
if orgID == nonExistingOrgID {
|
||||
return models.ErrOrgNotFound
|
||||
}
|
||||
|
||||
cmd.Result = models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserID, respJSON.Get("id").MustInt64())
|
||||
assert.Equal(t, "User created", respJSON.Get("message").MustString())
|
||||
|
||||
// Verify that userLogin and orgID were transmitted correctly to the handler
|
||||
assert.Equal(t, testLogin, userLogin)
|
||||
assert.Equal(t, int64(0), orgID)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("With an organization", func() {
|
||||
t.Run("With an organization", func(t *testing.T) {
|
||||
createCmd := dtos.AdminCreateUserForm{
|
||||
Login: TestLogin,
|
||||
Password: TestPassword,
|
||||
OrgId: TestOrgID,
|
||||
Login: testLogin,
|
||||
Password: testPassword,
|
||||
OrgId: testOrgID,
|
||||
}
|
||||
|
||||
adminCreateUserScenario("Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
adminCreateUserScenario(t, "Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
bus.ClearBusHandlers()
|
||||
|
||||
var userLogin string
|
||||
var orgID int64
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
userLogin = cmd.Login
|
||||
orgID = cmd.OrgId
|
||||
|
||||
if orgID == nonExistingOrgID {
|
||||
return models.ErrOrgNotFound
|
||||
}
|
||||
|
||||
cmd.Result = models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("id").MustInt64(), ShouldEqual, TestUserID)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "User created")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, testUserID, respJSON.Get("id").MustInt64())
|
||||
assert.Equal(t, "User created", respJSON.Get("message").MustString())
|
||||
|
||||
So(userLogin, ShouldEqual, TestLogin)
|
||||
So(orgId, ShouldEqual, TestOrgID)
|
||||
assert.Equal(t, testLogin, userLogin)
|
||||
assert.Equal(t, testOrgID, orgID)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("With a nonexistent organization", func() {
|
||||
t.Run("With a nonexistent organization", func(t *testing.T) {
|
||||
createCmd := dtos.AdminCreateUserForm{
|
||||
Login: TestLogin,
|
||||
Password: TestPassword,
|
||||
Login: testLogin,
|
||||
Password: testPassword,
|
||||
OrgId: nonExistingOrgID,
|
||||
}
|
||||
|
||||
adminCreateUserScenario("Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
adminCreateUserScenario(t, "Should create the user", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
bus.ClearBusHandlers()
|
||||
|
||||
var userLogin string
|
||||
var orgID int64
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
userLogin = cmd.Login
|
||||
orgID = cmd.OrgId
|
||||
|
||||
if orgID == nonExistingOrgID {
|
||||
return models.ErrOrgNotFound
|
||||
}
|
||||
|
||||
cmd.Result = models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("message").MustString(), ShouldEqual, "organization not found")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "organization not found", respJSON.Get("message").MustString())
|
||||
|
||||
So(userLogin, ShouldEqual, TestLogin)
|
||||
So(orgId, ShouldEqual, 1000)
|
||||
assert.Equal(t, testLogin, userLogin)
|
||||
assert.Equal(t, int64(1000), orgID)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When a server admin attempts to create a user with an already existing email/login", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
return models.ErrUserAlreadyExists
|
||||
})
|
||||
|
||||
t.Run("When a server admin attempts to create a user with an already existing email/login", func(t *testing.T) {
|
||||
createCmd := dtos.AdminCreateUserForm{
|
||||
Login: TestLogin,
|
||||
Password: TestPassword,
|
||||
Login: testLogin,
|
||||
Password: testPassword,
|
||||
}
|
||||
|
||||
adminCreateUserScenario("Should return an error", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
adminCreateUserScenario(t, "Should return an error", "/api/admin/users", "/api/admin/users", createCmd, func(sc *scenarioContext) {
|
||||
bus.ClearBusHandlers()
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.CreateUserCommand) error {
|
||||
return models.ErrUserAlreadyExists
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 412)
|
||||
assert.Equal(t, 412, sc.resp.Code)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("error").MustString(), ShouldEqual, "user already exists")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "user already exists", respJSON.Get("error").MustString())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func putAdminScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func putAdminScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
|
||||
cmd dtos.AdminUpdateUserPermissionsForm, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return AdminUpdateUserPermissions(c, cmd)
|
||||
@ -301,20 +370,22 @@ func putAdminScenario(desc string, url string, routePattern string, role models.
|
||||
})
|
||||
}
|
||||
|
||||
func adminLogoutUserScenario(desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminLogoutUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
hs := HTTPServer{
|
||||
Bus: bus.GetBus(),
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
t.Log("Route handler invoked", "url", c.Req.URL)
|
||||
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.AdminLogoutUser(c)
|
||||
@ -326,9 +397,9 @@ func adminLogoutUserScenario(desc string, url string, routePattern string, fn sc
|
||||
})
|
||||
}
|
||||
|
||||
func adminRevokeUserAuthTokenScenario(desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminRevokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -337,12 +408,12 @@ func adminRevokeUserAuthTokenScenario(desc string, url string, routePattern stri
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.AdminRevokeUserAuthToken(c, cmd)
|
||||
@ -354,9 +425,9 @@ func adminRevokeUserAuthTokenScenario(desc string, url string, routePattern stri
|
||||
})
|
||||
}
|
||||
|
||||
func adminGetUserAuthTokensScenario(desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminGetUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -365,12 +436,12 @@ func adminGetUserAuthTokensScenario(desc string, url string, routePattern string
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.AdminGetUserAuthTokens(c)
|
||||
@ -382,9 +453,9 @@ func adminGetUserAuthTokensScenario(desc string, url string, routePattern string
|
||||
})
|
||||
}
|
||||
|
||||
func adminDisableUserScenario(desc string, action string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminDisableUserScenario(t *testing.T, desc string, action string, url string, routePattern string, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -393,10 +464,10 @@ func adminDisableUserScenario(desc string, action string, url string, routePatte
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.UserId = testUserID
|
||||
|
||||
if action == "enable" {
|
||||
return AdminEnableUser(c)
|
||||
@ -411,14 +482,14 @@ func adminDisableUserScenario(desc string, action string, url string, routePatte
|
||||
})
|
||||
}
|
||||
|
||||
func adminDeleteUserScenario(desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminDeleteUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.UserId = testUserID
|
||||
|
||||
return AdminDeleteUser(c)
|
||||
})
|
||||
@ -429,14 +500,14 @@ func adminDeleteUserScenario(desc string, url string, routePattern string, fn sc
|
||||
})
|
||||
}
|
||||
|
||||
func adminCreateUserScenario(desc string, url string, routePattern string, cmd dtos.AdminCreateUserForm, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func adminCreateUserScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.AdminCreateUserForm, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.UserId = testUserID
|
||||
|
||||
return AdminCreateUser(c, cmd)
|
||||
})
|
||||
|
@ -1,29 +1,38 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAlertingApiEndpoint(t *testing.T) {
|
||||
Convey("Given an alert in a dashboard with an acl", t, func() {
|
||||
singleAlert := &models.Alert{Id: 1, DashboardId: 1, Name: "singlealert"}
|
||||
type setUpConf struct {
|
||||
aclMockResp []*models.DashboardAclInfoDTO
|
||||
}
|
||||
|
||||
func TestAlertingAPIEndpoint(t *testing.T) {
|
||||
singleAlert := &models.Alert{Id: 1, DashboardId: 1, Name: "singlealert"}
|
||||
viewerRole := models.ROLE_VIEWER
|
||||
editorRole := models.ROLE_EDITOR
|
||||
|
||||
setUp := func(confs ...setUpConf) {
|
||||
bus.AddHandler("test", func(query *models.GetAlertByIdQuery) error {
|
||||
query.Result = singleAlert
|
||||
return nil
|
||||
})
|
||||
|
||||
viewerRole := models.ROLE_VIEWER
|
||||
editorRole := models.ROLE_EDITOR
|
||||
|
||||
aclMockResp := []*models.DashboardAclInfoDTO{}
|
||||
for _, c := range confs {
|
||||
if c.aclMockResp != nil {
|
||||
aclMockResp = c.aclMockResp
|
||||
}
|
||||
}
|
||||
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
|
||||
query.Result = aclMockResp
|
||||
return nil
|
||||
@ -33,39 +42,45 @@ func TestAlertingApiEndpoint(t *testing.T) {
|
||||
query.Result = []*models.TeamDTO{}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
Convey("When user is editor and not in the ACL", func() {
|
||||
Convey("Should not be able to pause the alert", func() {
|
||||
cmd := dtos.PauseAlertCommand{
|
||||
AlertId: 1,
|
||||
Paused: true,
|
||||
}
|
||||
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
||||
CallPauseAlert(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
t.Run("When user is editor and not in the ACL", func(t *testing.T) {
|
||||
cmd := dtos.PauseAlertCommand{
|
||||
AlertId: 1,
|
||||
Paused: true,
|
||||
}
|
||||
postAlertScenario(t, "When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause",
|
||||
models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
|
||||
callPauseAlert(sc)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and dashboard has default ACL", func() {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{
|
||||
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
|
||||
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
|
||||
}
|
||||
|
||||
Convey("Should be able to pause the alert", func() {
|
||||
cmd := dtos.PauseAlertCommand{
|
||||
AlertId: 1,
|
||||
Paused: true,
|
||||
}
|
||||
postAlertScenario("When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause", models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
||||
CallPauseAlert(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
t.Run("When user is editor and dashboard has default ACL", func(t *testing.T) {
|
||||
cmd := dtos.PauseAlertCommand{
|
||||
AlertId: 1,
|
||||
Paused: true,
|
||||
}
|
||||
postAlertScenario(t, "When calling POST on", "/api/alerts/1/pause", "/api/alerts/:alertId/pause",
|
||||
models.ROLE_EDITOR, cmd, func(sc *scenarioContext) {
|
||||
setUp(setUpConf{
|
||||
aclMockResp: []*models.DashboardAclInfoDTO{
|
||||
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
|
||||
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callPauseAlert(sc)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/alerts?dashboardId=1", "/api/alerts",
|
||||
models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
|
||||
var searchQuery *search.Query
|
||||
bus.AddHandler("test", func(query *search.Query) error {
|
||||
searchQuery = query
|
||||
@ -81,11 +96,15 @@ func TestAlertingApiEndpoint(t *testing.T) {
|
||||
sc.handlerFunc = GetAlerts
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(searchQuery, ShouldBeNil)
|
||||
So(getAlertsQuery, ShouldNotBeNil)
|
||||
require.Nil(t, searchQuery)
|
||||
assert.NotNil(t, getAlertsQuery)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alerts?dashboardId=1&dashboardId=2&folderId=3&dashboardTag=abc&dashboardQuery=dbQuery&limit=5&query=alertQuery", "/api/alerts", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
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", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
|
||||
var searchQuery *search.Query
|
||||
bus.AddHandler("test", func(query *search.Query) error {
|
||||
searchQuery = query
|
||||
@ -105,29 +124,31 @@ func TestAlertingApiEndpoint(t *testing.T) {
|
||||
sc.handlerFunc = GetAlerts
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(searchQuery, ShouldNotBeNil)
|
||||
So(searchQuery.DashboardIds[0], ShouldEqual, 1)
|
||||
So(searchQuery.DashboardIds[1], ShouldEqual, 2)
|
||||
So(searchQuery.FolderIds[0], ShouldEqual, 3)
|
||||
So(searchQuery.Tags[0], ShouldEqual, "abc")
|
||||
So(searchQuery.Title, ShouldEqual, "dbQuery")
|
||||
require.NotNil(t, searchQuery)
|
||||
assert.Equal(t, int64(1), searchQuery.DashboardIds[0])
|
||||
assert.Equal(t, int64(2), searchQuery.DashboardIds[1])
|
||||
assert.Equal(t, int64(3), searchQuery.FolderIds[0])
|
||||
assert.Equal(t, "abc", searchQuery.Tags[0])
|
||||
assert.Equal(t, "dbQuery", searchQuery.Title)
|
||||
|
||||
So(getAlertsQuery, ShouldNotBeNil)
|
||||
So(getAlertsQuery.DashboardIDs[0], ShouldEqual, 1)
|
||||
So(getAlertsQuery.DashboardIDs[1], ShouldEqual, 2)
|
||||
So(getAlertsQuery.Limit, ShouldEqual, 5)
|
||||
So(getAlertsQuery.Query, ShouldEqual, "alertQuery")
|
||||
require.NotNil(t, getAlertsQuery)
|
||||
assert.Equal(t, int64(1), getAlertsQuery.DashboardIDs[0])
|
||||
assert.Equal(t, int64(2), getAlertsQuery.DashboardIDs[1])
|
||||
assert.Equal(t, int64(5), getAlertsQuery.Limit)
|
||||
assert.Equal(t, "alertQuery", getAlertsQuery.Query)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/alert-notifications/1", "/alert-notifications/:notificationId", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/alert-notifications/1",
|
||||
"/alert-notifications/:notificationId", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
|
||||
sc.handlerFunc = GetAlertNotificationByID
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func CallPauseAlert(sc *scenarioContext) {
|
||||
func callPauseAlert(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.PauseAlertCommand) error {
|
||||
return nil
|
||||
})
|
||||
@ -135,15 +156,16 @@ func CallPauseAlert(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func postAlertScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PauseAlertCommand, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func postAlertScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
|
||||
cmd dtos.PauseAlertCommand, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return PauseAlert(c, cmd)
|
||||
|
@ -247,7 +247,6 @@ func DeleteAnnotationByID(c *models.ReqContext) Response {
|
||||
OrgId: c.OrgId,
|
||||
Id: annotationID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return Error(500, "Failed to delete annotation", err)
|
||||
}
|
||||
@ -272,7 +271,6 @@ func canSaveByDashboardID(c *models.ReqContext, dashboardID int64) (bool, error)
|
||||
|
||||
func canSave(c *models.ReqContext, repo annotations.Repository, annotationID int64) Response {
|
||||
items, err := repo.Find(&annotations.ItemQuery{AnnotationId: annotationID, OrgId: c.OrgId})
|
||||
|
||||
if err != nil || len(items) == 0 {
|
||||
return Error(500, "Could not find annotation to update", err)
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/annotations"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
Convey("Given an annotation without a dashboard id", t, func() {
|
||||
func TestAnnotationsAPIEndpoint(t *testing.T) {
|
||||
t.Run("Given an annotation without a dashboard ID", func(t *testing.T) {
|
||||
cmd := dtos.PostAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
@ -31,60 +31,70 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
Tags: []string{"tag1", "tag2"},
|
||||
}
|
||||
|
||||
Convey("When user is an Org Viewer", func() {
|
||||
t.Run("When user is an Org Viewer", func(t *testing.T) {
|
||||
role := models.ROLE_VIEWER
|
||||
Convey("Should not be allowed to save an annotation", func() {
|
||||
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
t.Run("Should not be allowed to save an annotation", func(t *testing.T) {
|
||||
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role,
|
||||
cmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
putAnnotationScenario(t, "When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId",
|
||||
role, updateCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
patchAnnotationScenario(t, "When calling PATCH on", "/api/annotations/1",
|
||||
"/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
|
||||
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is an Org Editor", func() {
|
||||
t.Run("When user is an Org Editor", func(t *testing.T) {
|
||||
role := models.ROLE_EDITOR
|
||||
Convey("Should be able to save an annotation", func() {
|
||||
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
t.Run("Should be able to save an annotation", func(t *testing.T) {
|
||||
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role,
|
||||
cmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
putAnnotationScenario(t, "When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
patchAnnotationScenario(t, "When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
|
||||
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given an annotation with a dashboard id and the dashboard does not have an acl", t, func() {
|
||||
t.Run("Given an annotation with a dashboard ID and the dashboard does not have an ACL", func(t *testing.T) {
|
||||
cmd := dtos.PostAnnotationsCmd{
|
||||
Time: 1000,
|
||||
Text: "annotation text",
|
||||
@ -120,90 +130,111 @@ func TestAnnotationsApiEndpoint(t *testing.T) {
|
||||
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
|
||||
query.Result = aclMockResp
|
||||
return nil
|
||||
})
|
||||
setUp := func() {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
|
||||
query.Result = aclMockResp
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetTeamsByUserQuery) error {
|
||||
query.Result = []*models.TeamDTO{}
|
||||
return nil
|
||||
})
|
||||
bus.AddHandler("test", func(query *models.GetTeamsByUserQuery) error {
|
||||
query.Result = []*models.TeamDTO{}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
Convey("When user is an Org Viewer", func() {
|
||||
t.Run("When user is an Org Viewer", func(t *testing.T) {
|
||||
role := models.ROLE_VIEWER
|
||||
Convey("Should not be allowed to save an annotation", func() {
|
||||
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
t.Run("Should not be allowed to save an annotation", func(t *testing.T) {
|
||||
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
putAnnotationScenario(t, "When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
patchAnnotationScenario(t, "When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
|
||||
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is an Org Editor", func() {
|
||||
t.Run("When user is an Org Editor", func(t *testing.T) {
|
||||
role := models.ROLE_EDITOR
|
||||
Convey("Should be able to save an annotation", func() {
|
||||
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
t.Run("Should be able to save an annotation", func(t *testing.T) {
|
||||
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
putAnnotationScenario(t, "When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
patchAnnotationScenario(t, "When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/annotations/1", "/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling DELETE on", "DELETE", "/api/annotations/1",
|
||||
"/api/annotations/:annotationId", role, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
fakeAnnoRepo = &fakeAnnotationsRepo{}
|
||||
annotations.SetRepository(fakeAnnoRepo)
|
||||
sc.handlerFunc = DeleteAnnotationByID
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is an Admin", func() {
|
||||
t.Run("When user is an Admin", func(t *testing.T) {
|
||||
role := models.ROLE_ADMIN
|
||||
Convey("Should be able to do anything", func() {
|
||||
postAnnotationScenario("When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
t.Run("Should be able to do anything", func(t *testing.T) {
|
||||
postAnnotationScenario(t, "When calling POST on", "/api/annotations", "/api/annotations", role, cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
putAnnotationScenario("When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
putAnnotationScenario(t, "When calling PUT on", "/api/annotations/1", "/api/annotations/:annotationId", role, updateCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
patchAnnotationScenario("When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
patchAnnotationScenario(t, "When calling PATCH on", "/api/annotations/1", "/api/annotations/:annotationId", role, patchCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("PATCH", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
deleteAnnotationsScenario("When calling POST on", "/api/annotations/mass-delete", "/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
deleteAnnotationsScenario(t, "When calling POST on", "/api/annotations/mass-delete",
|
||||
"/api/annotations/mass-delete", role, deleteCmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -229,15 +260,16 @@ func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotati
|
||||
|
||||
var fakeAnnoRepo *fakeAnnotationsRepo
|
||||
|
||||
func postAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func postAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
|
||||
cmd dtos.PostAnnotationsCmd, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return PostAnnotation(c, cmd)
|
||||
@ -252,15 +284,16 @@ func postAnnotationScenario(desc string, url string, routePattern string, role m
|
||||
})
|
||||
}
|
||||
|
||||
func putAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func putAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
|
||||
cmd dtos.UpdateAnnotationsCmd, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return UpdateAnnotation(c, cmd)
|
||||
@ -275,15 +308,15 @@ func putAnnotationScenario(desc string, url string, routePattern string, role mo
|
||||
})
|
||||
}
|
||||
|
||||
func patchAnnotationScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func patchAnnotationScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType, cmd dtos.PatchAnnotationsCmd, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return PatchAnnotation(c, cmd)
|
||||
@ -298,15 +331,16 @@ func patchAnnotationScenario(desc string, url string, routePattern string, role
|
||||
})
|
||||
}
|
||||
|
||||
func deleteAnnotationsScenario(desc string, url string, routePattern string, role models.RoleType, cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func deleteAnnotationsScenario(t *testing.T, desc string, url string, routePattern string, role models.RoleType,
|
||||
cmd dtos.DeleteAnnotationsCmd, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
|
||||
return DeleteAnnotations(c, cmd)
|
||||
|
@ -11,24 +11,23 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
|
||||
loggedInUserScenarioWithRole(desc, "GET", url, url, models.ROLE_EDITOR, fn)
|
||||
func loggedInUserScenario(t *testing.T, desc string, url string, fn scenarioFunc) {
|
||||
loggedInUserScenarioWithRole(t, desc, "GET", url, url, models.ROLE_EDITOR, fn)
|
||||
}
|
||||
|
||||
func loggedInUserScenarioWithRole(desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = role
|
||||
if sc.handlerFunc != nil {
|
||||
return sc.handlerFunc(sc.context)
|
||||
@ -48,11 +47,11 @@ func loggedInUserScenarioWithRole(desc string, method string, url string, routeP
|
||||
})
|
||||
}
|
||||
|
||||
func anonymousUserScenario(desc string, method string, url string, routePattern string, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func anonymousUserScenario(t *testing.T, desc string, method string, url string, routePattern string, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
if sc.handlerFunc != nil {
|
||||
@ -76,7 +75,7 @@ func anonymousUserScenario(desc string, method string, url string, routePattern
|
||||
func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
|
||||
sc.resp = httptest.NewRecorder()
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(sc.t, err)
|
||||
sc.req = req
|
||||
|
||||
return sc
|
||||
@ -141,9 +140,10 @@ func (sc *scenarioContext) exec() {
|
||||
type scenarioFunc func(c *scenarioContext)
|
||||
type handlerFunc func(c *models.ReqContext) Response
|
||||
|
||||
func setupScenarioContext(url string) *scenarioContext {
|
||||
func setupScenarioContext(t *testing.T, url string) *scenarioContext {
|
||||
sc := &scenarioContext{
|
||||
url: url,
|
||||
t: t,
|
||||
}
|
||||
viewsPath, _ := filepath.Abs("../../public/views")
|
||||
|
||||
|
@ -48,7 +48,9 @@ func dashboardGuardianResponse(err error) Response {
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) GetDashboard(c *models.ReqContext) Response {
|
||||
dash, rsp := getDashboardHelper(c.OrgId, c.Params(":slug"), 0, c.Params(":uid"))
|
||||
slug := c.Params(":slug")
|
||||
uid := c.Params(":uid")
|
||||
dash, rsp := getDashboardHelper(c.OrgId, slug, 0, uid)
|
||||
if rsp != nil {
|
||||
return rsp
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
@ -8,21 +9,25 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
Convey("Dashboard permissions test", t, func() {
|
||||
Convey("Given dashboard not exists", func() {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
return models.ErrDashboardNotFound
|
||||
})
|
||||
func TestDashboardPermissionAPIEndpoint(t *testing.T) {
|
||||
t.Run("Dashboard permissions test", func(t *testing.T) {
|
||||
t.Run("Given dashboard not exists", func(t *testing.T) {
|
||||
setUp := func() {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
return models.ErrDashboardNotFound
|
||||
})
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callGetDashboardPermissions(sc)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
@ -30,26 +35,37 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
})
|
||||
updateDashboardPermissionScenario(t, "When calling POST on", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callUpdateDashboardPermissions(sc)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given user has no admin permissions", func() {
|
||||
t.Run("Given user has no admin permissions", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
||||
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
setUp := func() {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callGetDashboardPermissions(sc)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
@ -57,18 +73,20 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
updateDashboardPermissionScenario(t, "When calling POST on", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callUpdateDashboardPermissions(sc)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given user has admin permissions and permissions to update", func() {
|
||||
t.Run("Given user has admin permissions and permissions to update", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: true,
|
||||
@ -81,21 +99,25 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
setUp := func() {
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
callGetDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(len(respJSON.MustArray()), ShouldEqual, 5)
|
||||
So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2)
|
||||
So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, models.PERMISSION_VIEW)
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callGetDashboardPermissions(sc)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 5, len(respJSON.MustArray()))
|
||||
assert.Equal(t, 2, respJSON.GetIndex(0).Get("userId").MustInt())
|
||||
assert.Equal(t, int(models.PERMISSION_VIEW), respJSON.GetIndex(0).Get("permission").MustInt())
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
@ -103,29 +125,32 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
updateDashboardPermissionScenario(t, "When calling POST on", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callUpdateDashboardPermissions(sc)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When trying to update permissions with duplicate permissions", func() {
|
||||
t.Run("When trying to update permissions with duplicate permissions", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists,
|
||||
})
|
||||
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
setUp := func() {
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
@ -133,29 +158,33 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
updateDashboardPermissionScenario(t, "When calling POST on", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callUpdateDashboardPermissions(sc)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When trying to override inherited permissions with lower precedence", func() {
|
||||
t.Run("When trying to override inherited permissions with lower precedence", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride},
|
||||
)
|
||||
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
setUp := func() {
|
||||
getDashboardQueryResult := models.NewDashboard("Dash")
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = getDashboardQueryResult
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
@ -163,14 +192,12 @@ func TestDashboardPermissionApiEndpoint(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
updateDashboardPermissionScenario("When calling POST on", "/api/dashboards/id/1/permissions", "/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateDashboardPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
})
|
||||
updateDashboardPermissionScenario(t, "When calling POST on", "/api/dashboards/id/1/permissions",
|
||||
"/api/dashboards/id/:id/permissions", cmd, func(sc *scenarioContext) {
|
||||
setUp()
|
||||
callUpdateDashboardPermissions(sc)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -188,16 +215,16 @@ func callUpdateDashboardPermissions(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func updateDashboardPermissionScenario(desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func updateDashboardPermissionScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.UserId = testUserID
|
||||
|
||||
return UpdateDashboardPermissions(c, cmd)
|
||||
})
|
||||
|
@ -236,10 +236,10 @@ func DeleteDashboardSnapshot(c *models.ReqContext) Response {
|
||||
if err != nil {
|
||||
return Error(500, "Failed to get dashboard snapshot", err)
|
||||
}
|
||||
|
||||
if query.Result == nil {
|
||||
return Error(404, "Failed to get dashboard snapshot", nil)
|
||||
}
|
||||
|
||||
dashboard, err := query.Result.DashboardJSON()
|
||||
if err != nil {
|
||||
return Error(500, "Failed to get dashboard data for dashboard snapshot", err)
|
||||
|
@ -4,23 +4,38 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securedata"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/securedata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
Convey("Given a single snapshot", t, func() {
|
||||
var externalRequest *http.Request
|
||||
jsonModel, _ := simplejson.NewJson([]byte(`{"id":100}`))
|
||||
func TestDashboardSnapshotAPIEndpoint_singleSnapshot(t *testing.T) {
|
||||
setupRemoteServer := func(fn func(http.ResponseWriter, *http.Request)) *httptest.Server {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
fn(rw, r)
|
||||
}))
|
||||
t.Cleanup(s.Close)
|
||||
return s
|
||||
}
|
||||
|
||||
jsonModel, err := simplejson.NewJson([]byte(`{"id":100}`))
|
||||
require.NoError(t, err)
|
||||
|
||||
viewerRole := models.ROLE_VIEWER
|
||||
editorRole := models.ROLE_EDITOR
|
||||
aclMockResp := []*models.DashboardAclInfoDTO{}
|
||||
|
||||
setUpSnapshotTest := func(t *testing.T) *models.DashboardSnapshot {
|
||||
t.Helper()
|
||||
|
||||
mockSnapshotResult := &models.DashboardSnapshot{
|
||||
Id: 1,
|
||||
@ -41,9 +56,6 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
viewerRole := models.ROLE_VIEWER
|
||||
editorRole := models.ROLE_EDITOR
|
||||
aclMockResp := []*models.DashboardAclInfoDTO{}
|
||||
bus.AddHandler("test", func(query *models.GetDashboardAclInfoListQuery) error {
|
||||
query.Result = aclMockResp
|
||||
return nil
|
||||
@ -55,185 +67,199 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
setupRemoteServer := func(fn func(http.ResponseWriter, *http.Request)) *httptest.Server {
|
||||
return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
fn(rw, r)
|
||||
}))
|
||||
return mockSnapshotResult
|
||||
}
|
||||
|
||||
t.Run("When user has editor role and is not in the ACL", func(t *testing.T) {
|
||||
loggedInUserScenarioWithRole(t, "Should not be able to delete snapshot when calling DELETE on",
|
||||
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
|
||||
var externalRequest *http.Request
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
externalRequest = req
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
require.Nil(t, externalRequest)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When user is anonymous", func(t *testing.T) {
|
||||
anonymousUserScenario(t, "Should be able to delete a snapshot when calling GET on", "GET",
|
||||
"/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
|
||||
var externalRequest *http.Request
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(200)
|
||||
externalRequest = req
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshotByDeleteKey
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"deleteKey": "12345"}).exec()
|
||||
|
||||
require.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
|
||||
|
||||
assert.Equal(t, http.MethodGet, externalRequest.Method)
|
||||
assert.Equal(t, ts.URL, fmt.Sprintf("http://%s", externalRequest.Host))
|
||||
assert.Equal(t, "/", externalRequest.URL.EscapedPath())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When user is editor and dashboard has default ACL", func(t *testing.T) {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{
|
||||
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
|
||||
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
|
||||
}
|
||||
|
||||
Convey("When user has editor role and is not in the ACL", func() {
|
||||
Convey("Should not be able to delete snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
externalRequest = req
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on", "DELETE",
|
||||
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
So(externalRequest, ShouldBeNil)
|
||||
var externalRequest *http.Request
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(200)
|
||||
externalRequest = req
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
|
||||
assert.Equal(t, ts.URL, fmt.Sprintf("http://%s", externalRequest.Host))
|
||||
assert.Equal(t, "/", externalRequest.URL.EscapedPath())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is anonymous", func() {
|
||||
Convey("Should be able to delete snapshot by deleteKey", func() {
|
||||
anonymousUserScenario("When calling GET on", "GET", "/api/snapshots-delete/12345", "/api/snapshots-delete/:deleteKey", func(sc *scenarioContext) {
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(200)
|
||||
externalRequest = req
|
||||
})
|
||||
t.Run("When user is editor and creator of the snapshot", func(t *testing.T) {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{}
|
||||
loggedInUserScenarioWithRole(t, "Should be able to delete a snapshot when calling DELETE on",
|
||||
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshotByDeleteKey
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"deleteKey": "12345"}).exec()
|
||||
mockSnapshotResult.UserId = testUserID
|
||||
mockSnapshotResult.External = false
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
So(externalRequest.Method, ShouldEqual, http.MethodGet)
|
||||
So(fmt.Sprintf("http://%s", externalRequest.Host), ShouldEqual, ts.URL)
|
||||
So(externalRequest.URL.EscapedPath(), ShouldEqual, "/")
|
||||
assert.True(t, strings.HasPrefix(respJSON.Get("message").MustString(), "Snapshot deleted"))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When deleting an external snapshot", func(t *testing.T) {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{}
|
||||
var writeErr error
|
||||
loggedInUserScenarioWithRole(t,
|
||||
"Should gracefully delete local snapshot when remote snapshot has already been removed when calling DELETE on",
|
||||
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
mockSnapshotResult.UserId = testUserID
|
||||
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
_, writeErr = rw.Write([]byte(`{"message":"Failed to get dashboard snapshot"}`))
|
||||
rw.WriteHeader(500)
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
require.NoError(t, writeErr)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and dashboard has default ACL", func() {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{
|
||||
{Role: &viewerRole, Permission: models.PERMISSION_VIEW},
|
||||
{Role: &editorRole, Permission: models.PERMISSION_EDIT},
|
||||
}
|
||||
loggedInUserScenarioWithRole(t,
|
||||
"Should fail to delete local snapshot when an unexpected 500 error occurs when calling DELETE on", "DELETE",
|
||||
"/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
mockSnapshotResult.UserId = testUserID
|
||||
|
||||
Convey("Should be able to delete a snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(200)
|
||||
externalRequest = req
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
|
||||
So(fmt.Sprintf("http://%s", externalRequest.Host), ShouldEqual, ts.URL)
|
||||
So(externalRequest.URL.EscapedPath(), ShouldEqual, "/")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When user is editor and is the creator of the snapshot", func() {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{}
|
||||
mockSnapshotResult.UserId = TestUserID
|
||||
mockSnapshotResult.External = false
|
||||
|
||||
Convey("Should be able to delete a snapshot", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("message").MustString(), ShouldStartWith, "Snapshot deleted")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When deleting an external snapshot", func() {
|
||||
aclMockResp = []*models.DashboardAclInfoDTO{}
|
||||
mockSnapshotResult.UserId = TestUserID
|
||||
|
||||
Convey("Should gracefully delete local snapshot when remote snapshot has already been removed", func() {
|
||||
var writeErr error
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
_, writeErr = rw.Write([]byte(`{"message":"Failed to get dashboard snapshot"}`))
|
||||
rw.WriteHeader(500)
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(writeErr, ShouldBeNil)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(500)
|
||||
_, writeErr = rw.Write([]byte(`{"message":"Unexpected"}`))
|
||||
})
|
||||
|
||||
t.Log("Setting external delete URL", "url", ts.URL)
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
require.NoError(t, writeErr)
|
||||
assert.Equal(t, 500, sc.resp.Code)
|
||||
})
|
||||
|
||||
Convey("Should fail to delete local snapshot when an unexpected 500 error occurs", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
var writeErr error
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(500)
|
||||
_, writeErr = rw.Write([]byte(`{"message":"Unexpected"}`))
|
||||
})
|
||||
loggedInUserScenarioWithRole(t,
|
||||
"Should fail to delete local snapshot when an unexpected remote error occurs when calling DELETE on",
|
||||
"DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
mockSnapshotResult := setUpSnapshotTest(t)
|
||||
mockSnapshotResult.UserId = testUserID
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(writeErr, ShouldBeNil)
|
||||
So(sc.resp.Code, ShouldEqual, 500)
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(404)
|
||||
})
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
assert.Equal(t, 500, sc.resp.Code)
|
||||
})
|
||||
|
||||
Convey("Should fail to delete local snapshot when an unexpected remote error occurs", func() {
|
||||
loggedInUserScenarioWithRole("When calling DELETE on", "DELETE", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
ts := setupRemoteServer(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(404)
|
||||
})
|
||||
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) {
|
||||
setUpSnapshotTest(t)
|
||||
|
||||
mockSnapshotResult.ExternalDeleteUrl = ts.URL
|
||||
sc.handlerFunc = DeleteDashboardSnapshot
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
sc.handlerFunc = GetDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 500)
|
||||
})
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
dashboard := respJSON.Get("dashboard")
|
||||
id := dashboard.Get("id")
|
||||
|
||||
assert.Equal(t, int64(100), id.MustInt64())
|
||||
})
|
||||
|
||||
Convey("Should be able to read a snapshot's un-encrypted data", func() {
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = GetDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
dashboard := respJSON.Get("dashboard")
|
||||
id := dashboard.Get("id")
|
||||
|
||||
So(id.MustInt64(), ShouldEqual, 100)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Should be able to read a snapshot's encrypted data", func() {
|
||||
loggedInUserScenarioWithRole(t, "Should be able to read a snapshot's encrypted data When calling GET on",
|
||||
"GET", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
origSecret := setting.SecretKey
|
||||
setting.SecretKey = "dashboard_snapshot_api_test"
|
||||
t.Cleanup(func() {
|
||||
setting.SecretKey = origSecret
|
||||
})
|
||||
|
||||
dashboardId := 123
|
||||
jsonModel, err := simplejson.NewJson([]byte(fmt.Sprintf(`{"id":%d}`, dashboardId)))
|
||||
So(err, ShouldBeNil)
|
||||
const dashboardID int64 = 123
|
||||
jsonModel, err := simplejson.NewJson([]byte(fmt.Sprintf(`{"id":%d}`, dashboardID)))
|
||||
require.NoError(t, err)
|
||||
|
||||
jsonModelEncoded, err := jsonModel.Encode()
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
encrypted, err := securedata.Encrypt(jsonModelEncoded)
|
||||
So(err, ShouldBeNil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// mock snapshot with encrypted dashboard info
|
||||
mockSnapshotResult := &models.DashboardSnapshot{
|
||||
@ -242,21 +268,20 @@ func TestDashboardSnapshotApiEndpoint(t *testing.T) {
|
||||
Expires: time.Now().Add(time.Duration(1000) * time.Second),
|
||||
}
|
||||
|
||||
setUpSnapshotTest(t)
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetDashboardSnapshotQuery) error {
|
||||
query.Result = mockSnapshotResult
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/snapshots/12345", "/api/snapshots/:key", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
sc.handlerFunc = GetDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
sc.handlerFunc = GetDashboardSnapshot
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"key": "12345"}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("dashboard").Get("id").MustInt64(), ShouldEqual, dashboardId)
|
||||
})
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, dashboardID, respJSON.Get("dashboard").Get("id").MustInt64())
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,64 +6,57 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
const (
|
||||
TestOrgID = 1
|
||||
TestUserID = 1
|
||||
testOrgID int64 = 1
|
||||
testUserID int64 = 1
|
||||
)
|
||||
|
||||
func TestDataSourcesProxy(t *testing.T) {
|
||||
Convey("Given a user is logged in", t, func() {
|
||||
loggedInUserScenario("When calling GET on", "/api/datasources/", func(sc *scenarioContext) {
|
||||
// Stubs the database query
|
||||
bus.AddHandler("test", func(query *models.GetDataSourcesQuery) error {
|
||||
So(query.OrgId, ShouldEqual, TestOrgID)
|
||||
query.Result = []*models.DataSource{
|
||||
{Name: "mmm"},
|
||||
{Name: "ZZZ"},
|
||||
{Name: "BBB"},
|
||||
{Name: "aaa"},
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// handler func being tested
|
||||
sc.handlerFunc = GetDataSources
|
||||
sc.fakeReq("GET", "/api/datasources").exec()
|
||||
|
||||
respJSON := []map[string]interface{}{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&respJSON)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("should return list of datasources for org sorted alphabetically and case insensitively", func() {
|
||||
So(respJSON[0]["name"], ShouldEqual, "aaa")
|
||||
So(respJSON[1]["name"], ShouldEqual, "BBB")
|
||||
So(respJSON[2]["name"], ShouldEqual, "mmm")
|
||||
So(respJSON[3]["name"], ShouldEqual, "ZZZ")
|
||||
})
|
||||
func TestDataSourcesProxy_userLoggedIn(t *testing.T) {
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/datasources/", func(sc *scenarioContext) {
|
||||
// Stubs the database query
|
||||
bus.AddHandler("test", func(query *models.GetDataSourcesQuery) error {
|
||||
assert.Equal(t, testOrgID, query.OrgId)
|
||||
query.Result = []*models.DataSource{
|
||||
{Name: "mmm"},
|
||||
{Name: "ZZZ"},
|
||||
{Name: "BBB"},
|
||||
{Name: "aaa"},
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
Convey("Should be able to save a data source", func() {
|
||||
loggedInUserScenario("When calling DELETE on non-existing", "/api/datasources/name/12345", func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDataSourceByName
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
})
|
||||
})
|
||||
// handler func being tested
|
||||
sc.handlerFunc = GetDataSources
|
||||
sc.fakeReq("GET", "/api/datasources").exec()
|
||||
|
||||
respJSON := []map[string]interface{}{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&respJSON)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "aaa", respJSON[0]["name"])
|
||||
assert.Equal(t, "BBB", respJSON[1]["name"])
|
||||
assert.Equal(t, "mmm", respJSON[2]["name"])
|
||||
assert.Equal(t, "ZZZ", respJSON[3]["name"])
|
||||
})
|
||||
|
||||
loggedInUserScenario(t, "Should be able to save a data source when calling DELETE on non-existing",
|
||||
"/api/datasources/name/12345", func(sc *scenarioContext) {
|
||||
sc.handlerFunc = DeleteDataSourceByName
|
||||
sc.fakeReqWithParams("DELETE", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
}
|
||||
|
||||
// Adding data sources with invalid URLs should lead to an error.
|
||||
func TestAddDataSource_InvalidURL(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext("/api/datasources")
|
||||
// TODO: Make this an argument to setupScenarioContext
|
||||
sc.t = t
|
||||
sc := setupScenarioContext(t, "/api/datasources")
|
||||
|
||||
sc.m.Post(sc.url, Wrap(func(c *models.ReqContext) Response {
|
||||
return AddDataSource(c, models.AddDataSourceCommand{
|
||||
@ -93,9 +86,7 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
sc := setupScenarioContext("/api/datasources")
|
||||
// TODO: Make this an argument to setupScenarioContext
|
||||
sc.t = t
|
||||
sc := setupScenarioContext(t, "/api/datasources")
|
||||
|
||||
sc.m.Post(sc.url, Wrap(func(c *models.ReqContext) Response {
|
||||
return AddDataSource(c, models.AddDataSourceCommand{
|
||||
@ -113,9 +104,7 @@ func TestAddDataSource_URLWithoutProtocol(t *testing.T) {
|
||||
func TestUpdateDataSource_InvalidURL(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext("/api/datasources/1234")
|
||||
// TODO: Make this an argument to setupScenarioContext
|
||||
sc.t = t
|
||||
sc := setupScenarioContext(t, "/api/datasources/1234")
|
||||
|
||||
sc.m.Put(sc.url, Wrap(func(c *models.ReqContext) Response {
|
||||
return AddDataSource(c, models.AddDataSourceCommand{
|
||||
@ -145,9 +134,7 @@ func TestUpdateDataSource_URLWithoutProtocol(t *testing.T) {
|
||||
return nil
|
||||
})
|
||||
|
||||
sc := setupScenarioContext("/api/datasources/1234")
|
||||
// TODO: Make this an argument to setupScenarioContext
|
||||
sc.t = t
|
||||
sc := setupScenarioContext(t, "/api/datasources/1234")
|
||||
|
||||
sc.m.Put(sc.url, Wrap(func(c *models.ReqContext) Response {
|
||||
return AddDataSource(c, models.AddDataSourceCommand{
|
||||
|
@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
@ -9,204 +10,201 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFolderPermissionApiEndpoint(t *testing.T) {
|
||||
Convey("Folder permissions test", t, func() {
|
||||
Convey("Given folder not exists", func() {
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDError: models.ErrFolderNotFound,
|
||||
}
|
||||
func TestFolderPermissionAPIEndpoint(t *testing.T) {
|
||||
t.Run("Given folder not exists", func(t *testing.T) {
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDError: models.ErrFolderNotFound,
|
||||
}
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
mockFolderService(mock)
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
mockFolderService(mock)
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
|
||||
Convey("Given user has no admin permissions", func() {
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
updateFolderPermissionScenario(t, "When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
mockFolderService(mock)
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 403)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
t.Run("Given user has no admin permissions", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
|
||||
Convey("Given user has admin permissions and permissions to update", func() {
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: true,
|
||||
GetAclValue: []*models.DashboardAclInfoDTO{
|
||||
{OrgId: 1, DashboardId: 1, UserId: 2, Permission: models.PERMISSION_VIEW},
|
||||
{OrgId: 1, DashboardId: 1, UserId: 3, Permission: models.PERMISSION_EDIT},
|
||||
{OrgId: 1, DashboardId: 1, UserId: 4, Permission: models.PERMISSION_ADMIN},
|
||||
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: models.PERMISSION_VIEW},
|
||||
{OrgId: 1, DashboardId: 1, TeamId: 2, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
})
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{CanAdminValue: false})
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
mockFolderService(mock)
|
||||
mockFolderService(mock)
|
||||
|
||||
loggedInUserScenarioWithRole("When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(len(respJSON.MustArray()), ShouldEqual, 5)
|
||||
So(respJSON.GetIndex(0).Get("userId").MustInt(), ShouldEqual, 2)
|
||||
So(respJSON.GetIndex(0).Get("permission").MustInt(), ShouldEqual, models.PERMISSION_VIEW)
|
||||
})
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(respJSON.Get("id").MustInt(), ShouldEqual, 1)
|
||||
So(respJSON.Get("title").MustString(), ShouldEqual, "Folder")
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_EDITOR, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
Convey("When trying to update permissions with duplicate permissions", func() {
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists,
|
||||
})
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
updateFolderPermissionScenario(t, "When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
mockFolderService(mock)
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
t.Run("Given user has admin permissions and permissions to update", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
|
||||
Convey("When trying to override inherited permissions with lower precedence", func() {
|
||||
origNewGuardian := guardian.New
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride},
|
||||
)
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: true,
|
||||
GetAclValue: []*models.DashboardAclInfoDTO{
|
||||
{OrgId: 1, DashboardId: 1, UserId: 2, Permission: models.PERMISSION_VIEW},
|
||||
{OrgId: 1, DashboardId: 1, UserId: 3, Permission: models.PERMISSION_EDIT},
|
||||
{OrgId: 1, DashboardId: 1, UserId: 4, Permission: models.PERMISSION_ADMIN},
|
||||
{OrgId: 1, DashboardId: 1, TeamId: 1, Permission: models.PERMISSION_VIEW},
|
||||
{OrgId: 1, DashboardId: 1, TeamId: 2, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
})
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
mockFolderService(mock)
|
||||
mockFolderService(mock)
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
loggedInUserScenarioWithRole(t, "When calling GET on", "GET", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", models.ROLE_ADMIN, func(sc *scenarioContext) {
|
||||
callGetFolderPermissions(sc)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 5, len(respJSON.MustArray()))
|
||||
assert.Equal(t, 2, respJSON.GetIndex(0).Get("userId").MustInt())
|
||||
assert.Equal(t, int(models.PERMISSION_VIEW), respJSON.GetIndex(0).Get("permission").MustInt())
|
||||
})
|
||||
|
||||
updateFolderPermissionScenario("When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
})
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
Reset(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
updateFolderPermissionScenario(t, "When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, respJSON.Get("id").MustInt())
|
||||
assert.Equal(t, "Folder", respJSON.Get("title").MustString())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When trying to update permissions with duplicate permissions", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianPermissionExists,
|
||||
})
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
|
||||
mockFolderService(mock)
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario(t, "When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When trying to override inherited permissions with lower precedence", func(t *testing.T) {
|
||||
origNewGuardian := guardian.New
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
guardian.New = origNewGuardian
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
|
||||
guardian.MockDashboardGuardian(&guardian.FakeDashboardGuardian{
|
||||
CanAdminValue: true,
|
||||
CheckPermissionBeforeUpdateValue: false,
|
||||
CheckPermissionBeforeUpdateError: guardian.ErrGuardianOverride},
|
||||
)
|
||||
|
||||
mock := &fakeFolderService{
|
||||
GetFolderByUIDResult: &models.Folder{
|
||||
Id: 1,
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
},
|
||||
}
|
||||
|
||||
mockFolderService(mock)
|
||||
|
||||
cmd := dtos.UpdateDashboardAclCommand{
|
||||
Items: []dtos.DashboardAclUpdateItem{
|
||||
{UserId: 1000, Permission: models.PERMISSION_ADMIN},
|
||||
},
|
||||
}
|
||||
|
||||
updateFolderPermissionScenario(t, "When calling POST on", "/api/folders/uid/permissions", "/api/folders/:uid/permissions", cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolderPermissions(sc)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -224,16 +222,16 @@ func callUpdateFolderPermissions(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func updateFolderPermissionScenario(desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func updateFolderPermissionScenario(t *testing.T, desc string, url string, routePattern string, cmd dtos.UpdateDashboardAclCommand, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.UserId = testUserID
|
||||
|
||||
return UpdateFolderPermissions(c, cmd)
|
||||
})
|
||||
|
@ -10,127 +10,121 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFoldersApiEndpoint(t *testing.T) {
|
||||
Convey("Create/update folder response tests", t, func() {
|
||||
Convey("Given a correct request for creating a folder", func() {
|
||||
cmd := models.CreateFolderCommand{
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
func TestFoldersAPIEndpoint(t *testing.T) {
|
||||
t.Run("Given a correct request for creating a folder", func(t *testing.T) {
|
||||
cmd := models.CreateFolderCommand{
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
|
||||
mock := &fakeFolderService{
|
||||
CreateFolderResult: &models.Folder{Id: 1, Uid: "uid", Title: "Folder"},
|
||||
}
|
||||
mock := &fakeFolderService{
|
||||
CreateFolderResult: &models.Folder{Id: 1, Uid: "uid", Title: "Folder"},
|
||||
}
|
||||
|
||||
createFolderScenario("When calling POST on", "/api/folders", "/api/folders", mock, cmd, func(sc *scenarioContext) {
|
||||
createFolderScenario(t, "When calling POST on", "/api/folders", "/api/folders", mock, cmd,
|
||||
func(sc *scenarioContext) {
|
||||
callCreateFolder(sc)
|
||||
|
||||
Convey("It should return correct response data", func() {
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
So(err, ShouldBeNil)
|
||||
So(folder.Id, ShouldEqual, 1)
|
||||
So(folder.Uid, ShouldEqual, "uid")
|
||||
So(folder.Title, ShouldEqual, "Folder")
|
||||
})
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), folder.Id)
|
||||
assert.Equal(t, "uid", folder.Uid)
|
||||
assert.Equal(t, "Folder", folder.Title)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given incorrect requests for creating a folder", func() {
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
|
||||
}
|
||||
t.Run("Given incorrect requests for creating a folder", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
|
||||
}
|
||||
|
||||
cmd := models.CreateFolderCommand{
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock := &fakeFolderService{
|
||||
CreateFolderError: tc.Error,
|
||||
}
|
||||
|
||||
createFolderScenario(fmt.Sprintf("Expect '%s' error when calling POST on", tc.Error.Error()), "/api/folders", "/api/folders", mock, cmd, func(sc *scenarioContext) {
|
||||
callCreateFolder(sc)
|
||||
if sc.resp.Code != tc.ExpectedStatusCode {
|
||||
t.Errorf("For error '%s' expected status code %d, actual %d", tc.Error, tc.ExpectedStatusCode, sc.resp.Code)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Given a correct request for updating a folder", func() {
|
||||
cmd := models.UpdateFolderCommand{
|
||||
Title: "Folder upd",
|
||||
}
|
||||
cmd := models.CreateFolderCommand{
|
||||
Uid: "uid",
|
||||
Title: "Folder",
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock := &fakeFolderService{
|
||||
UpdateFolderResult: &models.Folder{Id: 1, Uid: "uid", Title: "Folder upd"},
|
||||
CreateFolderError: tc.Error,
|
||||
}
|
||||
|
||||
updateFolderScenario("When calling PUT on", "/api/folders/uid", "/api/folders/:uid", mock, cmd, func(sc *scenarioContext) {
|
||||
createFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling POST on", tc.Error.Error()),
|
||||
"/api/folders", "/api/folders", mock, cmd, func(sc *scenarioContext) {
|
||||
callCreateFolder(sc)
|
||||
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for error %s", tc.Error)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Given a correct request for updating a folder", func(t *testing.T) {
|
||||
cmd := models.UpdateFolderCommand{
|
||||
Title: "Folder upd",
|
||||
}
|
||||
|
||||
mock := &fakeFolderService{
|
||||
UpdateFolderResult: &models.Folder{Id: 1, Uid: "uid", Title: "Folder upd"},
|
||||
}
|
||||
|
||||
updateFolderScenario(t, "When calling PUT on", "/api/folders/uid", "/api/folders/:uid", mock, cmd,
|
||||
func(sc *scenarioContext) {
|
||||
callUpdateFolder(sc)
|
||||
|
||||
Convey("It should return correct response data", func() {
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
So(err, ShouldBeNil)
|
||||
So(folder.Id, ShouldEqual, 1)
|
||||
So(folder.Uid, ShouldEqual, "uid")
|
||||
So(folder.Title, ShouldEqual, "Folder upd")
|
||||
})
|
||||
folder := dtos.Folder{}
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&folder)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), folder.Id)
|
||||
assert.Equal(t, "uid", folder.Uid)
|
||||
assert.Equal(t, "Folder upd", folder.Title)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Given incorrect requests for updating a folder", func() {
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
|
||||
t.Run("Given incorrect requests for updating a folder", func(t *testing.T) {
|
||||
testCases := []struct {
|
||||
Error error
|
||||
ExpectedStatusCode int
|
||||
}{
|
||||
{Error: models.ErrFolderWithSameUIDExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderTitleEmpty, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderSameNameExists, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardInvalidUid, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrDashboardUidTooLong, ExpectedStatusCode: 400},
|
||||
{Error: models.ErrFolderAccessDenied, ExpectedStatusCode: 403},
|
||||
{Error: models.ErrFolderNotFound, ExpectedStatusCode: 404},
|
||||
{Error: models.ErrFolderVersionMismatch, ExpectedStatusCode: 412},
|
||||
{Error: models.ErrFolderFailedGenerateUniqueUid, ExpectedStatusCode: 500},
|
||||
}
|
||||
|
||||
cmd := models.UpdateFolderCommand{
|
||||
Title: "Folder upd",
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock := &fakeFolderService{
|
||||
UpdateFolderError: tc.Error,
|
||||
}
|
||||
|
||||
cmd := models.UpdateFolderCommand{
|
||||
Title: "Folder upd",
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock := &fakeFolderService{
|
||||
UpdateFolderError: tc.Error,
|
||||
}
|
||||
|
||||
updateFolderScenario(fmt.Sprintf("Expect '%s' error when calling PUT on", tc.Error.Error()), "/api/folders/uid", "/api/folders/:uid", mock, cmd, func(sc *scenarioContext) {
|
||||
updateFolderScenario(t, fmt.Sprintf("Expect '%s' error when calling PUT on", tc.Error.Error()),
|
||||
"/api/folders/uid", "/api/folders/:uid", mock, cmd, func(sc *scenarioContext) {
|
||||
callUpdateFolder(sc)
|
||||
if sc.resp.Code != tc.ExpectedStatusCode {
|
||||
t.Errorf("For error '%s' expected status code %d, actual %d", tc.Error, tc.ExpectedStatusCode, sc.resp.Code)
|
||||
}
|
||||
assert.Equalf(t, tc.ExpectedStatusCode, sc.resp.Code, "Wrong status code for %s", tc.Error)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -138,19 +132,20 @@ func callCreateFolder(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func createFolderScenario(desc string, url string, routePattern string, mock *fakeFolderService, cmd models.CreateFolderCommand, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func createFolderScenario(t *testing.T, desc string, url string, routePattern string, mock *fakeFolderService,
|
||||
cmd models.CreateFolderCommand, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
hs := HTTPServer{
|
||||
Bus: bus.GetBus(),
|
||||
Cfg: setting.NewCfg(),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.SignedInUser = &models.SignedInUser{OrgId: TestOrgID, UserId: TestUserID}
|
||||
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID}
|
||||
|
||||
return hs.CreateFolder(c, cmd)
|
||||
})
|
||||
@ -172,27 +167,27 @@ func callUpdateFolder(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("PUT", sc.url, map[string]string{}).exec()
|
||||
}
|
||||
|
||||
func updateFolderScenario(desc string, url string, routePattern string, mock *fakeFolderService, cmd models.UpdateFolderCommand, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
func updateFolderScenario(t *testing.T, desc string, url string, routePattern string, mock *fakeFolderService,
|
||||
cmd models.UpdateFolderCommand, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.SignedInUser = &models.SignedInUser{OrgId: TestOrgID, UserId: TestUserID}
|
||||
sc.context.SignedInUser = &models.SignedInUser{OrgId: testOrgID, UserId: testUserID}
|
||||
|
||||
return UpdateFolder(c, cmd)
|
||||
})
|
||||
|
||||
origNewFolderService := dashboards.NewFolderService
|
||||
t.Cleanup(func() {
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
})
|
||||
mockFolderService(mock)
|
||||
|
||||
sc.m.Put(routePattern, sc.defaultHandler)
|
||||
|
||||
defer func() {
|
||||
dashboards.NewFolderService = origNewFolderService
|
||||
}()
|
||||
|
||||
fn(sc)
|
||||
})
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ func logSentryEventScenario(t *testing.T, desc string, event frontendSentryEvent
|
||||
frontendLogger.SetHandler(origHandler)
|
||||
})
|
||||
|
||||
sc := setupScenarioContext("/log")
|
||||
sc := setupScenarioContext(t, "/log")
|
||||
hs := HTTPServer{}
|
||||
|
||||
handler := Wrap(func(w http.ResponseWriter, c *models.ReqContext) Response {
|
||||
|
@ -158,7 +158,6 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response {
|
||||
}
|
||||
|
||||
ldapConfig, err := getLDAPConfig()
|
||||
|
||||
if err != nil {
|
||||
return Error(http.StatusBadRequest, "Failed to obtain the LDAP configuration. Please verify the configuration and try again", err)
|
||||
}
|
||||
|
@ -50,11 +50,11 @@ func (m *LDAPMock) User(login string) (*models.ExternalUserInfo, ldap.ServerConf
|
||||
func getUserFromLDAPContext(t *testing.T, requestURL string) *scenarioContext {
|
||||
t.Helper()
|
||||
|
||||
sc := setupScenarioContext(requestURL)
|
||||
sc := setupScenarioContext(t, requestURL)
|
||||
|
||||
ldap := setting.LDAPEnabled
|
||||
origLDAP := setting.LDAPEnabled
|
||||
setting.LDAPEnabled = true
|
||||
defer func() { setting.LDAPEnabled = ldap }()
|
||||
t.Cleanup(func() { setting.LDAPEnabled = origLDAP })
|
||||
|
||||
hs := &HTTPServer{Cfg: setting.NewCfg()}
|
||||
|
||||
@ -73,7 +73,7 @@ func getUserFromLDAPContext(t *testing.T, requestURL string) *scenarioContext {
|
||||
return sc
|
||||
}
|
||||
|
||||
func TestGetUserFromLDAPApiEndpoint_UserNotFound(t *testing.T) {
|
||||
func TestGetUserFromLDAPAPIEndpoint_UserNotFound(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
@ -90,7 +90,7 @@ func TestGetUserFromLDAPApiEndpoint_UserNotFound(t *testing.T) {
|
||||
assert.JSONEq(t, "{\"message\":\"No user was found in the LDAP server(s) with that username\"}", sc.resp.Body.String())
|
||||
}
|
||||
|
||||
func TestGetUserFromLDAPApiEndpoint_OrgNotfound(t *testing.T) {
|
||||
func TestGetUserFromLDAPAPIEndpoint_OrgNotfound(t *testing.T) {
|
||||
isAdmin := true
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Name: "John Doe",
|
||||
@ -152,7 +152,7 @@ func TestGetUserFromLDAPApiEndpoint_OrgNotfound(t *testing.T) {
|
||||
assert.JSONEq(t, expected, sc.resp.Body.String())
|
||||
}
|
||||
|
||||
func TestGetUserFromLDAPApiEndpoint(t *testing.T) {
|
||||
func TestGetUserFromLDAPAPIEndpoint(t *testing.T) {
|
||||
isAdmin := true
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Name: "John Doe",
|
||||
@ -232,7 +232,7 @@ func TestGetUserFromLDAPApiEndpoint(t *testing.T) {
|
||||
assert.JSONEq(t, expected, sc.resp.Body.String())
|
||||
}
|
||||
|
||||
func TestGetUserFromLDAPApiEndpoint_WithTeamHandler(t *testing.T) {
|
||||
func TestGetUserFromLDAPAPIEndpoint_WithTeamHandler(t *testing.T) {
|
||||
isAdmin := true
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Name: "John Doe",
|
||||
@ -319,11 +319,11 @@ func getLDAPStatusContext(t *testing.T) *scenarioContext {
|
||||
t.Helper()
|
||||
|
||||
requestURL := "/api/admin/ldap/status"
|
||||
sc := setupScenarioContext(requestURL)
|
||||
sc := setupScenarioContext(t, requestURL)
|
||||
|
||||
ldap := setting.LDAPEnabled
|
||||
setting.LDAPEnabled = true
|
||||
defer func() { setting.LDAPEnabled = ldap }()
|
||||
t.Cleanup(func() { setting.LDAPEnabled = ldap })
|
||||
|
||||
hs := &HTTPServer{Cfg: setting.NewCfg()}
|
||||
|
||||
@ -342,7 +342,7 @@ func getLDAPStatusContext(t *testing.T) *scenarioContext {
|
||||
return sc
|
||||
}
|
||||
|
||||
func TestGetLDAPStatusApiEndpoint(t *testing.T) {
|
||||
func TestGetLDAPStatusAPIEndpoint(t *testing.T) {
|
||||
pingResult = []*multildap.ServerStatus{
|
||||
{Host: "10.0.0.3", Port: 361, Available: true, Error: nil},
|
||||
{Host: "10.0.0.3", Port: 362, Available: true, Error: nil},
|
||||
@ -375,16 +375,21 @@ func TestGetLDAPStatusApiEndpoint(t *testing.T) {
|
||||
// PostSyncUserWithLDAP tests
|
||||
// ***
|
||||
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string) *scenarioContext {
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(t *testing.T)) *scenarioContext {
|
||||
t.Helper()
|
||||
|
||||
sc := setupScenarioContext(requestURL)
|
||||
sc := setupScenarioContext(t, requestURL)
|
||||
|
||||
ldap := setting.LDAPEnabled
|
||||
t.Cleanup(func() {
|
||||
setting.LDAPEnabled = ldap
|
||||
})
|
||||
setting.LDAPEnabled = true
|
||||
defer func() { setting.LDAPEnabled = ldap }()
|
||||
|
||||
hs := &HTTPServer{Cfg: setting.NewCfg(), AuthTokenService: auth.NewFakeUserAuthTokenService()}
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
}
|
||||
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
@ -394,7 +399,11 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string) *scenarioConte
|
||||
sc.m.Post("/api/admin/ldap/sync/:id", sc.defaultHandler)
|
||||
|
||||
sc.resp = httptest.NewRecorder()
|
||||
req, _ := http.NewRequest(http.MethodPost, requestURL, nil)
|
||||
req, err := http.NewRequest(http.MethodPost, requestURL, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
preHook(t)
|
||||
|
||||
sc.req = req
|
||||
sc.exec()
|
||||
|
||||
@ -402,39 +411,39 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string) *scenarioConte
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Login: "ldap-daniel",
|
||||
}
|
||||
userSearchResult = &models.ExternalUserInfo{
|
||||
Login: "ldap-daniel",
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
||||
require.Equal(t, "ldap-daniel", cmd.ExternalUser.Login)
|
||||
return nil
|
||||
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
||||
require.Equal(t, "ldap-daniel", cmd.ExternalUser.Login)
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetAuthInfoQuery) error {
|
||||
require.Equal(t, q.UserId, int64(34))
|
||||
require.Equal(t, q.AuthModule, models.AuthModuleLDAP)
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetAuthInfoQuery) error {
|
||||
require.Equal(t, q.UserId, int64(34))
|
||||
require.Equal(t, q.AuthModule, models.AuthModuleLDAP)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34")
|
||||
|
||||
assert.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
|
||||
expected := `
|
||||
@ -447,22 +456,22 @@ func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
return models.ErrUserNotFound
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
})
|
||||
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34")
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, sc.resp.Code)
|
||||
|
||||
expected := `
|
||||
@ -475,36 +484,36 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
|
||||
userSearchError = multildap.ErrDidNotFindUser
|
||||
userSearchError = multildap.ErrDidNotFindUser
|
||||
|
||||
admin := setting.AdminUser
|
||||
setting.AdminUser = "ldap-daniel"
|
||||
defer func() { setting.AdminUser = admin }()
|
||||
admin := setting.AdminUser
|
||||
t.Cleanup(func() { setting.AdminUser = admin })
|
||||
setting.AdminUser = "ldap-daniel"
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetAuthInfoQuery) error {
|
||||
require.Equal(t, q.UserId, int64(34))
|
||||
require.Equal(t, q.AuthModule, models.AuthModuleLDAP)
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetAuthInfoQuery) error {
|
||||
require.Equal(t, q.UserId, int64(34))
|
||||
require.Equal(t, q.AuthModule, models.AuthModuleLDAP)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34")
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, sc.resp.Code)
|
||||
|
||||
expected := `
|
||||
@ -518,42 +527,42 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
getLDAPConfig = func() (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
newLDAP = func(_ []*ldap.ServerConfig) multildap.IMultiLDAP {
|
||||
return &LDAPMock{}
|
||||
}
|
||||
|
||||
userSearchResult = nil
|
||||
userSearchResult = nil
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
||||
require.Equal(t, "ldap-daniel", cmd.ExternalUser.Login)
|
||||
return nil
|
||||
bus.AddHandler("test", func(cmd *models.UpsertUserCommand) error {
|
||||
require.Equal(t, "ldap-daniel", cmd.ExternalUser.Login)
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetExternalUserInfoByLoginQuery) error {
|
||||
assert.Equal(t, "ldap-daniel", q.LoginOrEmail)
|
||||
q.Result = &models.ExternalUserInfo{IsDisabled: true, UserId: 34}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.DisableUserCommand) error {
|
||||
assert.Equal(t, 34, cmd.UserId)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
|
||||
q.Result = &models.User{Login: "ldap-daniel", Id: 34}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetExternalUserInfoByLoginQuery) error {
|
||||
assert.Equal(t, "ldap-daniel", q.LoginOrEmail)
|
||||
q.Result = &models.ExternalUserInfo{IsDisabled: true, UserId: 34}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(cmd *models.DisableUserCommand) error {
|
||||
assert.Equal(t, 34, cmd.UserId)
|
||||
return nil
|
||||
})
|
||||
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34")
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, sc.resp.Code)
|
||||
|
||||
expected := `
|
||||
|
@ -53,7 +53,7 @@ func (hs *HTTPServer) ValidateRedirectTo(redirectTo string) error {
|
||||
|
||||
// when using a subUrl, the redirect_to should start with the subUrl (which contains the leading slash), otherwise the redirect
|
||||
// will send the user to the wrong location
|
||||
if hs.Cfg.AppSubUrl != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubUrl+"/") {
|
||||
if hs.Cfg.AppSubURL != "" && !strings.HasPrefix(to.Path, hs.Cfg.AppSubURL+"/") {
|
||||
return login.ErrInvalidRedirectTo
|
||||
}
|
||||
|
||||
@ -62,8 +62,8 @@ func (hs *HTTPServer) ValidateRedirectTo(redirectTo string) error {
|
||||
|
||||
func (hs *HTTPServer) CookieOptionsFromCfg() middleware.CookieOptions {
|
||||
path := "/"
|
||||
if len(hs.Cfg.AppSubUrl) > 0 {
|
||||
path = hs.Cfg.AppSubUrl
|
||||
if len(hs.Cfg.AppSubURL) > 0 {
|
||||
path = hs.Cfg.AppSubURL
|
||||
}
|
||||
return middleware.CookieOptions{
|
||||
Path: path,
|
||||
@ -126,7 +126,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||
// the user is already logged so instead of rendering the login page with error
|
||||
// it should be redirected to the home page.
|
||||
log.Debugf("Ignored invalid redirect_to cookie value: %v", redirectTo)
|
||||
redirectTo = hs.Cfg.AppSubUrl + "/"
|
||||
redirectTo = hs.Cfg.AppSubURL + "/"
|
||||
}
|
||||
middleware.DeleteCookie(c.Resp, "redirect_to", hs.CookieOptionsFromCfg)
|
||||
c.Redirect(redirectTo)
|
||||
|
@ -84,7 +84,7 @@ func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
@ -138,7 +138,7 @@ func TestLoginViewRedirect(t *testing.T) {
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
@ -254,12 +254,12 @@ func TestLoginViewRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, c := range redirectCases {
|
||||
hs.Cfg.AppUrl = c.appURL
|
||||
hs.Cfg.AppSubUrl = c.appSubURL
|
||||
hs.Cfg.AppURL = c.appURL
|
||||
hs.Cfg.AppSubURL = c.appSubURL
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
expCookiePath := "/"
|
||||
if len(hs.Cfg.AppSubUrl) > 0 {
|
||||
expCookiePath = hs.Cfg.AppSubUrl
|
||||
if len(hs.Cfg.AppSubURL) > 0 {
|
||||
expCookiePath = hs.Cfg.AppSubURL
|
||||
}
|
||||
cookie := http.Cookie{
|
||||
Name: "redirect_to",
|
||||
@ -314,7 +314,7 @@ func TestLoginPostRedirect(t *testing.T) {
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
log: &FakeLogger{},
|
||||
Cfg: setting.NewCfg(),
|
||||
@ -423,12 +423,12 @@ func TestLoginPostRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, c := range redirectCases {
|
||||
hs.Cfg.AppUrl = c.appURL
|
||||
hs.Cfg.AppSubUrl = c.appSubURL
|
||||
hs.Cfg.AppURL = c.appURL
|
||||
hs.Cfg.AppSubURL = c.appSubURL
|
||||
t.Run(c.desc, func(t *testing.T) {
|
||||
expCookiePath := "/"
|
||||
if len(hs.Cfg.AppSubUrl) > 0 {
|
||||
expCookiePath = hs.Cfg.AppSubUrl
|
||||
if len(hs.Cfg.AppSubURL) > 0 {
|
||||
expCookiePath = hs.Cfg.AppSubURL
|
||||
}
|
||||
cookie := http.Cookie{
|
||||
Name: "redirect_to",
|
||||
@ -472,7 +472,7 @@ func TestLoginOAuthRedirect(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
@ -507,7 +507,7 @@ func TestLoginInternal(t *testing.T) {
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
@ -537,7 +537,7 @@ func TestLoginInternal(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuthProxyLoginEnableLoginTokenDisabled(t *testing.T) {
|
||||
sc := setupAuthProxyLoginTest(false)
|
||||
sc := setupAuthProxyLoginTest(t, false)
|
||||
|
||||
assert.Equal(t, sc.resp.Code, 302)
|
||||
location, ok := sc.resp.Header()["Location"]
|
||||
@ -549,7 +549,7 @@ func TestAuthProxyLoginEnableLoginTokenDisabled(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAuthProxyLoginWithEnableLoginToken(t *testing.T) {
|
||||
sc := setupAuthProxyLoginTest(true)
|
||||
sc := setupAuthProxyLoginTest(t, true)
|
||||
|
||||
assert.Equal(t, sc.resp.Code, 302)
|
||||
location, ok := sc.resp.Header()["Location"]
|
||||
@ -561,11 +561,11 @@ func TestAuthProxyLoginWithEnableLoginToken(t *testing.T) {
|
||||
assert.Equal(t, "grafana_session=; Path=/; Max-Age=0; HttpOnly", setCookie[0])
|
||||
}
|
||||
|
||||
func setupAuthProxyLoginTest(enableLoginToken bool) *scenarioContext {
|
||||
func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioContext {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
@ -601,7 +601,7 @@ func (r *loginHookTest) LoginHook(loginInfo *models.LoginInfo, req *models.ReqCo
|
||||
}
|
||||
|
||||
func TestLoginPostRunLokingHook(t *testing.T) {
|
||||
sc := setupScenarioContext("/login")
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hookService := &hooks.HooksService{}
|
||||
hs := &HTTPServer{
|
||||
log: log.New("test"),
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"golang.org/x/oauth2/google"
|
||||
)
|
||||
|
||||
// ApplyRoute should use the plugin route data to set auth headers and custom headers
|
||||
// ApplyRoute should use the plugin route data to set auth headers and custom headers.
|
||||
func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route *plugins.AppPluginRoute, ds *models.DataSource) {
|
||||
proxyPath = strings.TrimPrefix(proxyPath, route.Path)
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
@ -12,9 +13,8 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testLogger struct {
|
||||
@ -28,8 +28,8 @@ func (stub *testLogger) Warn(testMessage string, ctx ...interface{}) {
|
||||
stub.warnMessage = testMessage
|
||||
}
|
||||
|
||||
func TestTeamApiEndpoint(t *testing.T) {
|
||||
Convey("Given two teams", t, func() {
|
||||
func TestTeamAPIEndpoint(t *testing.T) {
|
||||
t.Run("Given two teams", func(t *testing.T) {
|
||||
mockResult := models.SearchTeamQueryResult{
|
||||
Teams: []*models.TeamDTO{
|
||||
{Name: "team1"},
|
||||
@ -42,56 +42,52 @@ func TestTeamApiEndpoint(t *testing.T) {
|
||||
Cfg: setting.NewCfg(),
|
||||
}
|
||||
|
||||
Convey("When searching with no parameters", func() {
|
||||
loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
|
||||
query.Result = mockResult
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = hs.SearchTeams
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sentLimit, ShouldEqual, 1000)
|
||||
So(sendPage, ShouldEqual, 1)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2)
|
||||
So(len(respJSON.Get("teams").MustArray()), ShouldEqual, 2)
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = hs.SearchTeams
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
assert.Equal(t, 1000, sentLimit)
|
||||
assert.Equal(t, 1, sendPage)
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, respJSON.Get("totalCount").MustInt())
|
||||
assert.Equal(t, 2, len(respJSON.Get("teams").MustArray()))
|
||||
})
|
||||
|
||||
Convey("When searching with page and perpage parameters", func() {
|
||||
loggedInUserScenario("When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
|
||||
query.Result = mockResult
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchTeamsQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = hs.SearchTeams
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
|
||||
So(sentLimit, ShouldEqual, 10)
|
||||
So(sendPage, ShouldEqual, 2)
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = hs.SearchTeams
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
|
||||
assert.Equal(t, 10, sentLimit)
|
||||
assert.Equal(t, 2, sendPage)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("When creating team with api key", func(t *testing.T) {
|
||||
t.Run("When creating team with API key", func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
hs := &HTTPServer{
|
||||
|
@ -10,50 +10,49 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUserApiEndpoint(t *testing.T) {
|
||||
Convey("Given a user is logged in", t, func() {
|
||||
mockResult := models.SearchUserQueryResult{
|
||||
Users: []*models.UserSearchHitDTO{
|
||||
{Name: "user1"},
|
||||
{Name: "user2"},
|
||||
},
|
||||
TotalCount: 2,
|
||||
}
|
||||
func TestUserAPIEndpoint_userLoggedIn(t *testing.T) {
|
||||
mockResult := models.SearchUserQueryResult{
|
||||
Users: []*models.UserSearchHitDTO{
|
||||
{Name: "user1"},
|
||||
{Name: "user2"},
|
||||
},
|
||||
TotalCount: 2,
|
||||
}
|
||||
|
||||
loggedInUserScenario("When calling GET on", "api/users/:id", func(sc *scenarioContext) {
|
||||
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
|
||||
bus.AddHandler("test", func(query *models.GetUserProfileQuery) error {
|
||||
query.Result = models.UserProfileDTO{
|
||||
Id: int64(1),
|
||||
Email: "daniel@grafana.com",
|
||||
Name: "Daniel",
|
||||
Login: "danlee",
|
||||
OrgId: int64(2),
|
||||
IsGrafanaAdmin: true,
|
||||
IsDisabled: false,
|
||||
IsExternal: false,
|
||||
UpdatedAt: fakeNow,
|
||||
CreatedAt: fakeNow,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
loggedInUserScenario(t, "When calling GET on", "api/users/:id", func(sc *scenarioContext) {
|
||||
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
|
||||
bus.AddHandler("test", func(query *models.GetUserProfileQuery) error {
|
||||
query.Result = models.UserProfileDTO{
|
||||
Id: int64(1),
|
||||
Email: "daniel@grafana.com",
|
||||
Name: "Daniel",
|
||||
Login: "danlee",
|
||||
OrgId: int64(2),
|
||||
IsGrafanaAdmin: true,
|
||||
IsDisabled: false,
|
||||
IsExternal: false,
|
||||
UpdatedAt: fakeNow,
|
||||
CreatedAt: fakeNow,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetAuthInfoQuery) error {
|
||||
query.Result = &models.UserAuth{
|
||||
AuthModule: models.AuthModuleLDAP,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
bus.AddHandler("test", func(query *models.GetAuthInfoQuery) error {
|
||||
query.Result = &models.UserAuth{
|
||||
AuthModule: models.AuthModuleLDAP,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = GetUserByID
|
||||
avatarUrl := dtos.GetGravatarUrl("daniel@grafana.com")
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
sc.handlerFunc = GetUserByID
|
||||
avatarUrl := dtos.GetGravatarUrl("daniel@grafana.com")
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
expected := fmt.Sprintf(`
|
||||
expected := fmt.Sprintf(`
|
||||
{
|
||||
"id": 1,
|
||||
"email": "daniel@grafana.com",
|
||||
@ -73,35 +72,35 @@ func TestUserApiEndpoint(t *testing.T) {
|
||||
}
|
||||
`, avatarUrl)
|
||||
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
require.JSONEq(t, expected, sc.resp.Body.String())
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
require.JSONEq(t, expected, sc.resp.Body.String())
|
||||
})
|
||||
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/users/lookup", func(sc *scenarioContext) {
|
||||
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
|
||||
bus.AddHandler("test", func(query *models.GetUserByLoginQuery) error {
|
||||
require.Equal(t, "danlee", query.LoginOrEmail)
|
||||
|
||||
query.Result = &models.User{
|
||||
Id: int64(1),
|
||||
Email: "daniel@grafana.com",
|
||||
Name: "Daniel",
|
||||
Login: "danlee",
|
||||
Theme: "light",
|
||||
IsAdmin: true,
|
||||
OrgId: int64(2),
|
||||
IsDisabled: false,
|
||||
Updated: fakeNow,
|
||||
Created: fakeNow,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenario("When calling GET on", "/api/users/lookup", func(sc *scenarioContext) {
|
||||
fakeNow := time.Date(2019, 2, 11, 17, 30, 40, 0, time.UTC)
|
||||
bus.AddHandler("test", func(query *models.GetUserByLoginQuery) error {
|
||||
require.Equal(t, "danlee", query.LoginOrEmail)
|
||||
sc.handlerFunc = GetUserByLoginOrEmail
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"loginOrEmail": "danlee"}).exec()
|
||||
|
||||
query.Result = &models.User{
|
||||
Id: int64(1),
|
||||
Email: "daniel@grafana.com",
|
||||
Name: "Daniel",
|
||||
Login: "danlee",
|
||||
Theme: "light",
|
||||
IsAdmin: true,
|
||||
OrgId: int64(2),
|
||||
IsDisabled: false,
|
||||
Updated: fakeNow,
|
||||
Created: fakeNow,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = GetUserByLoginOrEmail
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"loginOrEmail": "danlee"}).exec()
|
||||
|
||||
expected := `
|
||||
expected := `
|
||||
{
|
||||
"id": 1,
|
||||
"email": "daniel@grafana.com",
|
||||
@ -119,94 +118,93 @@ func TestUserApiEndpoint(t *testing.T) {
|
||||
}
|
||||
`
|
||||
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
require.JSONEq(t, expected, sc.resp.Body.String())
|
||||
require.Equal(t, http.StatusOK, sc.resp.Code)
|
||||
require.JSONEq(t, expected, sc.resp.Body.String())
|
||||
})
|
||||
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/users", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenario("When calling GET on", "/api/users", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
sc.handlerFunc = SearchUsers
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
assert.Equal(t, 1000, sentLimit)
|
||||
assert.Equal(t, 1, sendPage)
|
||||
|
||||
return nil
|
||||
})
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(respJSON.MustArray()))
|
||||
})
|
||||
|
||||
sc.handlerFunc = SearchUsers
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
loggedInUserScenario(t, "When calling GET with page and limit querystring parameters on", "/api/users", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
So(sentLimit, ShouldEqual, 1000)
|
||||
So(sendPage, ShouldEqual, 1)
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
So(len(respJSON.MustArray()), ShouldEqual, 2)
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenario("When calling GET with page and limit querystring parameters on", "/api/users", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
sc.handlerFunc = SearchUsers
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
assert.Equal(t, 10, sentLimit)
|
||||
assert.Equal(t, 2, sendPage)
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
loggedInUserScenario(t, "When calling GET on", "/api/users/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
sc.handlerFunc = SearchUsers
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
So(sentLimit, ShouldEqual, 10)
|
||||
So(sendPage, ShouldEqual, 2)
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenario("When calling GET on", "/api/users/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
sc.handlerFunc = SearchUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
assert.Equal(t, 1000, sentLimit)
|
||||
assert.Equal(t, 1, sendPage)
|
||||
|
||||
return nil
|
||||
})
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
require.NoError(t, err)
|
||||
|
||||
sc.handlerFunc = SearchUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 2, respJSON.Get("totalCount").MustInt())
|
||||
assert.Equal(t, 2, len(respJSON.Get("users").MustArray()))
|
||||
})
|
||||
|
||||
So(sentLimit, ShouldEqual, 1000)
|
||||
So(sendPage, ShouldEqual, 1)
|
||||
loggedInUserScenario(t, "When calling GET with page and perpage querystring parameters on", "/api/users/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
|
||||
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||
So(err, ShouldBeNil)
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2)
|
||||
So(len(respJSON.Get("users").MustArray()), ShouldEqual, 2)
|
||||
return nil
|
||||
})
|
||||
|
||||
loggedInUserScenario("When calling GET with page and perpage querystring parameters on", "/api/users/search", func(sc *scenarioContext) {
|
||||
var sentLimit int
|
||||
var sendPage int
|
||||
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||
query.Result = mockResult
|
||||
sc.handlerFunc = SearchUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
|
||||
sentLimit = query.Limit
|
||||
sendPage = query.Page
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = SearchUsersWithPaging
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||
|
||||
So(sentLimit, ShouldEqual, 10)
|
||||
So(sendPage, ShouldEqual, 2)
|
||||
})
|
||||
assert.Equal(t, 10, sentLimit)
|
||||
assert.Equal(t, 2, sendPage)
|
||||
})
|
||||
}
|
||||
|
@ -2,115 +2,117 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUserTokenApiEndpoint(t *testing.T) {
|
||||
Convey("When current user attempts to revoke an auth token for a non-existing user", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userId = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
func TestUserTokenAPIEndpoint(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}
|
||||
|
||||
revokeUserAuthTokenScenario("Should return not found when calling POST on", "/api/user/revoke-auth-token", "/api/user/revoke-auth-token", cmd, 200, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
So(userId, ShouldEqual, 200)
|
||||
})
|
||||
revokeUserAuthTokenScenario(t, "Should return not found when calling POST on", "/api/user/revoke-auth-token",
|
||||
"/api/user/revoke-auth-token", cmd, 200, func(sc *scenarioContext) {
|
||||
var userID int64
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userID = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
assert.Equal(t, int64(200), userID)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When current user gets auth tokens for a non-existing user", t, func() {
|
||||
userId := int64(0)
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
userId = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
t.Run("When current user gets auth tokens for a non-existing user", func(t *testing.T) {
|
||||
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(cmd *models.GetUserByIdQuery) error {
|
||||
userID = cmd.Id
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
getUserAuthTokensScenario("Should return not found when calling GET on", "/api/user/auth-tokens", "/api/user/auth-tokens", 200, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
So(userId, ShouldEqual, 200)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
assert.Equal(t, int64(200), userID)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When logout an existing user from all devices", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: 200}
|
||||
return nil
|
||||
})
|
||||
t.Run("When logging out an existing user from all devices", func(t *testing.T) {
|
||||
logoutUserFromAllDevicesInternalScenario(t, "Should be successful", 1, func(sc *scenarioContext) {
|
||||
const userID int64 = 200
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: userID}
|
||||
return nil
|
||||
})
|
||||
|
||||
logoutUserFromAllDevicesInternalScenario("Should be successful", 1, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When logout a non-existing user from all devices", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
t.Run("When logout a non-existing user from all devices", func(t *testing.T) {
|
||||
logoutUserFromAllDevicesInternalScenario(t, "Should return not found", testUserID, func(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
return models.ErrUserNotFound
|
||||
})
|
||||
|
||||
logoutUserFromAllDevicesInternalScenario("Should return not found", TestUserID, func(sc *scenarioContext) {
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 404)
|
||||
assert.Equal(t, 404, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When revoke an auth token for a user", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: 200}
|
||||
return nil
|
||||
})
|
||||
|
||||
t.Run("When revoke an auth token for a user", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
token := &models.UserToken{Id: 1}
|
||||
|
||||
revokeUserAuthTokenInternalScenario("Should be successful", cmd, 200, token, func(sc *scenarioContext) {
|
||||
revokeUserAuthTokenInternalScenario(t, "Should be successful", cmd, 200, token, func(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: 200}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*models.UserToken, error) {
|
||||
return &models.UserToken{Id: 2}, nil
|
||||
}
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When revoke the active auth token used by himself", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: TestUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
t.Run("When revoke the active auth token used by himself", func(t *testing.T) {
|
||||
cmd := models.RevokeAuthTokenCmd{AuthTokenId: 2}
|
||||
token := &models.UserToken{Id: 2}
|
||||
|
||||
revokeUserAuthTokenInternalScenario("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(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.userAuthTokenService.GetUserTokenProvider = func(ctx context.Context, userId, userTokenId int64) (*models.UserToken, error) {
|
||||
return token, nil
|
||||
}
|
||||
sc.fakeReqWithParams("POST", sc.url, map[string]string{}).exec()
|
||||
So(sc.resp.Code, ShouldEqual, 400)
|
||||
assert.Equal(t, 400, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When gets auth tokens for a user", t, func() {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: TestUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
t.Run("When gets auth tokens for a user", func(t *testing.T) {
|
||||
currentToken := &models.UserToken{Id: 1}
|
||||
|
||||
getUserAuthTokensInternalScenario("Should be successful", currentToken, func(sc *scenarioContext) {
|
||||
getUserAuthTokensInternalScenario(t, "Should be successful", currentToken, func(sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(cmd *models.GetUserByIdQuery) error {
|
||||
cmd.Result = &models.User{Id: testUserID}
|
||||
return nil
|
||||
})
|
||||
|
||||
tokens := []*models.UserToken{
|
||||
{
|
||||
Id: 1,
|
||||
@ -132,42 +134,43 @@ func TestUserTokenApiEndpoint(t *testing.T) {
|
||||
}
|
||||
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||
|
||||
So(sc.resp.Code, ShouldEqual, 200)
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
result := sc.ToJSON()
|
||||
So(result.MustArray(), ShouldHaveLength, 2)
|
||||
assert.Len(t, result.MustArray(), 2)
|
||||
|
||||
resultOne := result.GetIndex(0)
|
||||
So(resultOne.Get("id").MustInt64(), ShouldEqual, tokens[0].Id)
|
||||
So(resultOne.Get("isActive").MustBool(), ShouldBeTrue)
|
||||
So(resultOne.Get("clientIp").MustString(), ShouldEqual, "127.0.0.1")
|
||||
So(resultOne.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[0].CreatedAt, 0).Format(time.RFC3339))
|
||||
So(resultOne.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[0].SeenAt, 0).Format(time.RFC3339))
|
||||
assert.Equal(t, tokens[0].Id, resultOne.Get("id").MustInt64())
|
||||
assert.True(t, resultOne.Get("isActive").MustBool())
|
||||
assert.Equal(t, "127.0.0.1", resultOne.Get("clientIp").MustString())
|
||||
assert.Equal(t, time.Unix(tokens[0].CreatedAt, 0).Format(time.RFC3339), resultOne.Get("createdAt").MustString())
|
||||
assert.Equal(t, time.Unix(tokens[0].SeenAt, 0).Format(time.RFC3339), resultOne.Get("seenAt").MustString())
|
||||
|
||||
So(resultOne.Get("device").MustString(), ShouldEqual, "Other")
|
||||
So(resultOne.Get("browser").MustString(), ShouldEqual, "Chrome")
|
||||
So(resultOne.Get("browserVersion").MustString(), ShouldEqual, "72.0")
|
||||
So(resultOne.Get("os").MustString(), ShouldEqual, "Linux")
|
||||
So(resultOne.Get("osVersion").MustString(), ShouldEqual, "")
|
||||
assert.Equal(t, "Other", resultOne.Get("device").MustString())
|
||||
assert.Equal(t, "Chrome", resultOne.Get("browser").MustString())
|
||||
assert.Equal(t, "72.0", resultOne.Get("browserVersion").MustString())
|
||||
assert.Equal(t, "Linux", resultOne.Get("os").MustString())
|
||||
assert.Empty(t, resultOne.Get("osVersion").MustString())
|
||||
|
||||
resultTwo := result.GetIndex(1)
|
||||
So(resultTwo.Get("id").MustInt64(), ShouldEqual, tokens[1].Id)
|
||||
So(resultTwo.Get("isActive").MustBool(), ShouldBeFalse)
|
||||
So(resultTwo.Get("clientIp").MustString(), ShouldEqual, "127.0.0.2")
|
||||
So(resultTwo.Get("createdAt").MustString(), ShouldEqual, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339))
|
||||
So(resultTwo.Get("seenAt").MustString(), ShouldEqual, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339))
|
||||
assert.Equal(t, tokens[1].Id, resultTwo.Get("id").MustInt64())
|
||||
assert.False(t, resultTwo.Get("isActive").MustBool())
|
||||
assert.Equal(t, "127.0.0.2", resultTwo.Get("clientIp").MustString())
|
||||
assert.Equal(t, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339), resultTwo.Get("createdAt").MustString())
|
||||
assert.Equal(t, time.Unix(tokens[1].CreatedAt, 0).Format(time.RFC3339), resultTwo.Get("seenAt").MustString())
|
||||
|
||||
So(resultTwo.Get("device").MustString(), ShouldEqual, "iPhone")
|
||||
So(resultTwo.Get("browser").MustString(), ShouldEqual, "Mobile Safari")
|
||||
So(resultTwo.Get("browserVersion").MustString(), ShouldEqual, "11.0")
|
||||
So(resultTwo.Get("os").MustString(), ShouldEqual, "iOS")
|
||||
So(resultTwo.Get("osVersion").MustString(), ShouldEqual, "11.0")
|
||||
assert.Equal(t, "iPhone", resultTwo.Get("device").MustString())
|
||||
assert.Equal(t, "Mobile Safari", resultTwo.Get("browser").MustString())
|
||||
assert.Equal(t, "11.0", resultTwo.Get("browserVersion").MustString())
|
||||
assert.Equal(t, "iOS", resultTwo.Get("os").MustString())
|
||||
assert.Equal(t, "11.0", resultTwo.Get("osVersion").MustString())
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func revokeUserAuthTokenScenario(desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd, userId int64, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func revokeUserAuthTokenScenario(t *testing.T, desc string, url string, routePattern string, cmd models.RevokeAuthTokenCmd,
|
||||
userId int64, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -176,12 +179,12 @@ func revokeUserAuthTokenScenario(desc string, url string, routePattern string, c
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = userId
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.RevokeUserAuthToken(c, cmd)
|
||||
@ -193,9 +196,9 @@ func revokeUserAuthTokenScenario(desc string, url string, routePattern string, c
|
||||
})
|
||||
}
|
||||
|
||||
func getUserAuthTokensScenario(desc string, url string, routePattern string, userId int64, fn scenarioFunc) {
|
||||
Convey(desc+" "+url, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func getUserAuthTokensScenario(t *testing.T, desc string, url string, routePattern string, userId int64, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -204,12 +207,12 @@ func getUserAuthTokensScenario(desc string, url string, routePattern string, use
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(url)
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = userId
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.GetUserAuthTokens(c)
|
||||
@ -221,20 +224,20 @@ func getUserAuthTokensScenario(desc string, url string, routePattern string, use
|
||||
})
|
||||
}
|
||||
|
||||
func logoutUserFromAllDevicesInternalScenario(desc string, userId int64, fn scenarioFunc) {
|
||||
Convey(desc, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func logoutUserFromAllDevicesInternalScenario(t *testing.T, desc string, userId int64, fn scenarioFunc) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
hs := HTTPServer{
|
||||
Bus: bus.GetBus(),
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
}
|
||||
|
||||
sc := setupScenarioContext("/")
|
||||
sc := setupScenarioContext(t, "/")
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
|
||||
return hs.logoutUserFromAllDevicesInternal(context.Background(), userId)
|
||||
@ -246,9 +249,10 @@ func logoutUserFromAllDevicesInternalScenario(desc string, userId int64, fn scen
|
||||
})
|
||||
}
|
||||
|
||||
func revokeUserAuthTokenInternalScenario(desc string, cmd models.RevokeAuthTokenCmd, userId int64, token *models.UserToken, fn scenarioFunc) {
|
||||
Convey(desc, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func revokeUserAuthTokenInternalScenario(t *testing.T, desc string, cmd models.RevokeAuthTokenCmd, userId int64,
|
||||
token *models.UserToken, fn scenarioFunc) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -257,12 +261,12 @@ func revokeUserAuthTokenInternalScenario(desc string, cmd models.RevokeAuthToken
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext("/")
|
||||
sc := setupScenarioContext(t, "/")
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
sc.context.UserToken = token
|
||||
|
||||
@ -275,9 +279,9 @@ func revokeUserAuthTokenInternalScenario(desc string, cmd models.RevokeAuthToken
|
||||
})
|
||||
}
|
||||
|
||||
func getUserAuthTokensInternalScenario(desc string, token *models.UserToken, fn scenarioFunc) {
|
||||
Convey(desc, func() {
|
||||
defer bus.ClearBusHandlers()
|
||||
func getUserAuthTokensInternalScenario(t *testing.T, desc string, token *models.UserToken, fn scenarioFunc) {
|
||||
t.Run(desc, func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
|
||||
@ -286,16 +290,16 @@ func getUserAuthTokensInternalScenario(desc string, token *models.UserToken, fn
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
|
||||
sc := setupScenarioContext("/")
|
||||
sc := setupScenarioContext(t, "/")
|
||||
sc.userAuthTokenService = fakeAuthTokenService
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
sc.context = c
|
||||
sc.context.UserId = TestUserID
|
||||
sc.context.OrgId = TestOrgID
|
||||
sc.context.UserId = testUserID
|
||||
sc.context.OrgId = testOrgID
|
||||
sc.context.OrgRole = models.ROLE_ADMIN
|
||||
sc.context.UserToken = token
|
||||
|
||||
return hs.getUserAuthTokensInternal(c, TestUserID)
|
||||
return hs.getUserAuthTokensInternal(c, testUserID)
|
||||
})
|
||||
|
||||
sc.m.Get("/", sc.defaultHandler)
|
||||
|
@ -34,7 +34,7 @@ func (*OSSLicensingService) StateInfo() string {
|
||||
|
||||
func (l *OSSLicensingService) LicenseURL(user *models.SignedInUser) string {
|
||||
if user.IsGrafanaAdmin {
|
||||
return l.Cfg.AppSubUrl + "/admin/upgrading"
|
||||
return l.Cfg.AppSubURL + "/admin/upgrading"
|
||||
}
|
||||
|
||||
return "https://grafana.com/products/enterprise/?utm_source=grafana_footer"
|
||||
|
@ -235,7 +235,7 @@ func (rs *RenderingService) getURL(path string) string {
|
||||
|
||||
subPath := ""
|
||||
if rs.Cfg.ServeFromSubPath {
|
||||
subPath = rs.Cfg.AppSubUrl
|
||||
subPath = rs.Cfg.AppSubURL
|
||||
}
|
||||
|
||||
// &render=1 signals to the legacy redirect layer to
|
||||
|
@ -27,14 +27,14 @@ func TestGetUrl(t *testing.T) {
|
||||
|
||||
t.Run("And protocol HTTP configured should return expected path", func(t *testing.T) {
|
||||
rs.Cfg.ServeFromSubPath = false
|
||||
rs.Cfg.AppSubUrl = ""
|
||||
rs.Cfg.AppSubURL = ""
|
||||
setting.Protocol = setting.HTTPScheme
|
||||
url := rs.getURL(path)
|
||||
require.Equal(t, "http://localhost:3000/"+path+"&render=1", url)
|
||||
|
||||
t.Run("And serve from sub path should return expected path", func(t *testing.T) {
|
||||
rs.Cfg.ServeFromSubPath = true
|
||||
rs.Cfg.AppSubUrl = "/grafana"
|
||||
rs.Cfg.AppSubURL = "/grafana"
|
||||
url := rs.getURL(path)
|
||||
require.Equal(t, "http://localhost:3000/grafana/"+path+"&render=1", url)
|
||||
})
|
||||
@ -42,7 +42,7 @@ func TestGetUrl(t *testing.T) {
|
||||
|
||||
t.Run("And protocol HTTPS configured should return expected path", func(t *testing.T) {
|
||||
rs.Cfg.ServeFromSubPath = false
|
||||
rs.Cfg.AppSubUrl = ""
|
||||
rs.Cfg.AppSubURL = ""
|
||||
setting.Protocol = setting.HTTPSScheme
|
||||
url := rs.getURL(path)
|
||||
require.Equal(t, "https://localhost:3000/"+path+"&render=1", url)
|
||||
@ -50,7 +50,7 @@ func TestGetUrl(t *testing.T) {
|
||||
|
||||
t.Run("And protocol HTTP2 configured should return expected path", func(t *testing.T) {
|
||||
rs.Cfg.ServeFromSubPath = false
|
||||
rs.Cfg.AppSubUrl = ""
|
||||
rs.Cfg.AppSubURL = ""
|
||||
setting.Protocol = setting.HTTP2Scheme
|
||||
url := rs.getURL(path)
|
||||
require.Equal(t, "https://localhost:3000/"+path+"&render=1", url)
|
||||
|
@ -78,7 +78,7 @@ var (
|
||||
// Log settings.
|
||||
LogConfigs []util.DynMap
|
||||
|
||||
// Http server options
|
||||
// HTTP server options
|
||||
Protocol Scheme
|
||||
Domain string
|
||||
HttpAddr, HttpPort string
|
||||
@ -193,7 +193,7 @@ var (
|
||||
LDAPAllowSignup bool
|
||||
LDAPActiveSyncEnabled bool
|
||||
|
||||
// QUOTA
|
||||
// Quota
|
||||
Quota QuotaSettings
|
||||
|
||||
// Alerting
|
||||
@ -228,8 +228,8 @@ type Cfg struct {
|
||||
Logger log.Logger
|
||||
|
||||
// HTTP Server Settings
|
||||
AppUrl string
|
||||
AppSubUrl string
|
||||
AppURL string
|
||||
AppSubURL string
|
||||
ServeFromSubPath bool
|
||||
StaticRootPath string
|
||||
Protocol Scheme
|
||||
@ -707,7 +707,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
|
||||
|
||||
cfg.Raw = iniFile
|
||||
|
||||
// Temporary keep global, to make refactor in steps
|
||||
// Temporarily keep global, to make refactor in steps
|
||||
Raw = cfg.Raw
|
||||
|
||||
cfg.BuildVersion = BuildVersion
|
||||
@ -1203,8 +1203,8 @@ func readServerSettings(iniFile *ini.File, cfg *Cfg) error {
|
||||
}
|
||||
ServeFromSubPath = server.Key("serve_from_sub_path").MustBool(false)
|
||||
|
||||
cfg.AppUrl = AppUrl
|
||||
cfg.AppSubUrl = AppSubUrl
|
||||
cfg.AppURL = AppUrl
|
||||
cfg.AppSubURL = AppSubUrl
|
||||
cfg.ServeFromSubPath = ServeFromSubPath
|
||||
|
||||
Protocol = HTTPScheme
|
||||
|
Loading…
Reference in New Issue
Block a user