grafana/pkg/api/preferences_test.go
Ashley Harrison 586272e5f0
Navigation: Introduce a preferences table to store Navbar preferences (#44914)
* First attempt at creating new navbar_preferences table in db

* Apply to every nav item instead of just home

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* Chore: introduce initTestDB options for features

* fix unit tests

* Add another unit test and some logic for detecting if a preference already exists

* tidy up

* Only override IsFeatureToggleEnabled if it's defined

* Extract setNavPreferences out into it's own function, initialise features correctly

* Make the linter happy

* Use new structure

* user essentials mob! 🔱

* user essentials mob! 🔱

* Split NavbarPreferences from Preferences

* user essentials mob! 🔱

* user essentials mob! 🔱

* Fix lint error

* Start adding tests

* Change internal db structure to be a generic json object

* GetJsonData -> GetPreferencesJsonData

* Stop using simplejson + add some more unit tests

* Update pkg/api/preferences.go

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>

* Updates following review comments

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* Change patch to upsert, add a unit test

* remove commented out code

* introduce patch user/org preferences methods

* Return Navbar preferences in the get call

* Fix integration test by instantiating JsonData

* Address review comments

* Rename HideFromNavbar -> Hide

* add swagger:model comment

* Add patch to the preferences documentation

* Add openapi annotations

* Add a short description

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* user essentials mob! 🔱

* Update unit tests

* remove unneeded url

* remove outdated comment

* Update integration tests

* update generated swagger

Co-authored-by: Alexandra Vargas <alexa1866@gmail.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
2022-03-17 12:07:20 +00:00

158 lines
6.5 KiB
Go

package api
import (
"net/http"
"strings"
"testing"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
getOrgPreferencesURL = "/api/org/preferences/"
putOrgPreferencesURL = "/api/org/preferences/"
patchOrgPreferencesUrl = "/api/org/preferences/"
patchUserPreferencesUrl = "/api/user/preferences/"
testUpdateOrgPreferencesCmd = `{ "theme": "light", "homeDashboardId": 1 }`
testPatchOrgPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}`
testPatchOrgPreferencesCmdBad = `this is not json`
testPatchUserPreferencesCmd = `{"navbar":{"savedItems":[{"id":"snapshots","text":"Snapshots","icon":"camera","url":"/dashboard/snapshots"}]}}`
testPatchUserPreferencesCmdBad = `this is not json`
)
func TestAPIEndpoint_GetCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, false)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
setInitCtxSignedInViewer(sc.initCtx)
t.Run("Viewer cannot get org preferences", func(t *testing.T) {
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
setInitCtxSignedInOrgAdmin(sc.initCtx)
t.Run("Org Admin can get org preferences", func(t *testing.T) {
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
assert.Equal(t, http.StatusOK, response.Code)
})
}
func TestAPIEndpoint_GetCurrentOrgPreferences_AccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, true)
setInitCtxSignedInViewer(sc.initCtx)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
t.Run("AccessControl allows getting org preferences with correct permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsPreferencesRead}}, sc.initCtx.OrgId)
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
assert.Equal(t, http.StatusOK, response.Code)
})
t.Run("AccessControl prevents getting org preferences with correct permissions in another org", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsPreferencesRead}}, 2)
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
t.Run("AccessControl prevents getting org preferences with incorrect permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "orgs:invalid"}}, sc.initCtx.OrgId)
response := callAPI(sc.server, http.MethodGet, getOrgPreferencesURL, nil, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
}
func TestAPIEndpoint_PutCurrentOrgPreferences_LegacyAccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, false)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
setInitCtxSignedInViewer(sc.initCtx)
input := strings.NewReader(testUpdateOrgPreferencesCmd)
t.Run("Viewer cannot update org preferences", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
setInitCtxSignedInOrgAdmin(sc.initCtx)
input = strings.NewReader(testUpdateOrgPreferencesCmd)
t.Run("Org Admin can update org preferences", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
}
func TestAPIEndpoint_PutCurrentOrgPreferences_AccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, true)
setInitCtxSignedInViewer(sc.initCtx)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
input := strings.NewReader(testUpdateOrgPreferencesCmd)
t.Run("AccessControl allows updating org preferences with correct permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsPreferencesWrite}}, sc.initCtx.OrgId)
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
input = strings.NewReader(testUpdateOrgPreferencesCmd)
t.Run("AccessControl prevents updating org preferences with correct permissions in another org", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsPreferencesWrite}}, 2)
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
input = strings.NewReader(testUpdateOrgPreferencesCmd)
t.Run("AccessControl prevents updating org preferences with incorrect permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "orgs:invalid"}}, sc.initCtx.OrgId)
response := callAPI(sc.server, http.MethodPut, putOrgPreferencesURL, input, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
}
func TestAPIEndpoint_PatchUserPreferences(t *testing.T) {
sc := setupHTTPServer(t, true, false)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
setInitCtxSignedInOrgAdmin(sc.initCtx)
input := strings.NewReader(testPatchUserPreferencesCmd)
t.Run("Returns 200 on success", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPatch, patchUserPreferencesUrl, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
input = strings.NewReader(testPatchUserPreferencesCmdBad)
t.Run("Returns 400 with bad data", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPut, patchUserPreferencesUrl, input, t)
assert.Equal(t, http.StatusBadRequest, response.Code)
})
}
func TestAPIEndpoint_PatchOrgPreferences(t *testing.T) {
sc := setupHTTPServer(t, true, false)
_, err := sc.db.CreateOrgWithMember("TestOrg", testUserID)
require.NoError(t, err)
setInitCtxSignedInOrgAdmin(sc.initCtx)
input := strings.NewReader(testPatchOrgPreferencesCmd)
t.Run("Returns 200 on success", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPatch, patchOrgPreferencesUrl, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
input = strings.NewReader(testPatchOrgPreferencesCmdBad)
t.Run("Returns 400 with bad data", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPut, patchOrgPreferencesUrl, input, t)
assert.Equal(t, http.StatusBadRequest, response.Code)
})
}