mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 12:44:10 -06:00
9340430723
* Add context for alert * Remove context.TODO * Remove xorm * Remove context.TODO * Fix UsageStatsQuerier interface
931 lines
32 KiB
Go
931 lines
32 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package dashboards
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/guardian"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
)
|
|
|
|
const testOrgID int64 = 1
|
|
|
|
func TestIntegratedDashboardService(t *testing.T) {
|
|
t.Run("Given saved folders and dashboards in organization A", func(t *testing.T) {
|
|
origUpdateAlerting := UpdateAlerting
|
|
t.Cleanup(func() {
|
|
UpdateAlerting = origUpdateAlerting
|
|
})
|
|
UpdateAlerting = func(ctx context.Context, store dashboards.Store, orgID int64, dashboard *models.Dashboard, user *models.SignedInUser) error {
|
|
return nil
|
|
}
|
|
|
|
// Basic validation tests
|
|
|
|
permissionScenario(t, "When saving a dashboard with non-existing id", true,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": float64(123412321),
|
|
"title": "Expect error",
|
|
}),
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardNotFound, err)
|
|
})
|
|
|
|
// Given other organization
|
|
|
|
t.Run("Given organization B", func(t *testing.T) {
|
|
const otherOrgId int64 = 2
|
|
|
|
permissionScenario(t, "When creating a dashboard with same id as dashboard in organization A",
|
|
true, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: otherOrgId,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"title": "Expect error",
|
|
}),
|
|
Overwrite: false,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardNotFound, err)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard with same uid as dashboard in organization A, it should create a new dashboard in org B",
|
|
true, func(t *testing.T, sc *permissionScenarioContext) {
|
|
const otherOrgId int64 = 2
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: otherOrgId,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "Dash with existing uid in other org",
|
|
}),
|
|
Overwrite: false,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(0, otherOrgId, sc.savedDashInFolder.Uid, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.NotEqual(t, sc.savedDashInFolder.Id, dash.Id)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
assert.Equal(t, otherOrgId, dash.OrgId)
|
|
assert.Equal(t, sc.savedDashInFolder.Uid, dash.Uid)
|
|
})
|
|
})
|
|
|
|
t.Run("Given user has no permission to save", func(t *testing.T) {
|
|
const canSave = false
|
|
|
|
permissionScenario(t, "When creating a new dashboard in the General folder", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
sqlStore := sqlstore.InitTestDB(t)
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": "Dash",
|
|
}),
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sqlStore)
|
|
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a new dashboard in other folder, it should create dashboard guardian for other folder with correct arguments and rsult in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: sc.otherSavedFolder.Id,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a new dashboard by existing title in folder, it should create dashboard guardian for folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.savedFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a new dashboard by existing UID in folder, it should create dashboard guardian for folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "New dash",
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.savedFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When updating a dashboard by existing id in the General folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInGeneralFolder.Id,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: sc.savedDashInGeneralFolder.FolderId,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.savedDashInGeneralFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When updating a dashboard by existing id in other folder, it should create dashboard guardian for dashboard with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: sc.savedDashInFolder.FolderId,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.savedDashInFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When moving a dashboard by existing ID to other folder from General folder, it should create dashboard guardian for other folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInGeneralFolder.Id,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: sc.otherSavedFolder.Id,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When moving a dashboard by existing id to the General folder from other folder, it should create dashboard guardian for General folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: 0,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When moving a dashboard by existing uid to other folder from General folder, it should create dashboard guardian for other folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInGeneralFolder.Uid,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: sc.otherSavedFolder.Id,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, sc.otherSavedFolder.Id, sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
|
|
permissionScenario(t, "When moving a dashboard by existing UID to the General folder from other folder, it should create dashboard guardian for General folder with correct arguments and result in access denied error",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "Dash",
|
|
}),
|
|
FolderId: 0,
|
|
UserId: 10000,
|
|
Overwrite: true,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
require.Equal(t, models.ErrDashboardUpdateAccessDenied, err)
|
|
|
|
assert.Equal(t, int64(0), sc.dashboardGuardianMock.DashId)
|
|
assert.Equal(t, cmd.OrgId, sc.dashboardGuardianMock.OrgId)
|
|
assert.Equal(t, cmd.UserId, sc.dashboardGuardianMock.User.UserId)
|
|
})
|
|
})
|
|
|
|
t.Run("Given user has permission to save", func(t *testing.T) {
|
|
const canSave = true
|
|
|
|
t.Run("and overwrite flag is set to false", func(t *testing.T) {
|
|
const shouldOverwrite = false
|
|
|
|
permissionScenario(t, "When creating a dashboard in General folder with same name as dashboard in other folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
FolderId: 0,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
assert.Equal(t, int64(0), dash.FolderId)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard in other folder with same name as dashboard in General folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInGeneralFolder.Title,
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, sc.savedFolder.Id, dash.FolderId)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a folder with same name as dashboard in other folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
IsFolder: true,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
assert.NotEqual(t, sc.savedDashInGeneralFolder.Id, res.Id)
|
|
assert.True(t, res.IsFolder)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(0), dash.FolderId)
|
|
assert.True(t, dash.IsFolder)
|
|
})
|
|
|
|
permissionScenario(t, "When saving a dashboard without id and uid and unique title in folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": "Dash without id and uid",
|
|
}),
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
assert.Greater(t, res.Id, int64(0))
|
|
assert.NotEmpty(t, res.Uid)
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
assert.Equal(t, res.Uid, dash.Uid)
|
|
})
|
|
|
|
permissionScenario(t, "When saving a dashboard when dashboard id is zero ", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": 0,
|
|
"title": "Dash with zero id",
|
|
}),
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
})
|
|
|
|
permissionScenario(t, "When saving a dashboard in non-existing folder", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": "Expect error",
|
|
}),
|
|
FolderId: 123412321,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardFolderNotFound, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by id without current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInGeneralFolder.Id,
|
|
"title": "test dash 23",
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardVersionMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by id with current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInGeneralFolder.Id,
|
|
"title": "Updated title",
|
|
"version": sc.savedDashInGeneralFolder.Version,
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(sc.savedDashInGeneralFolder.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated title", dash.Title)
|
|
assert.Equal(t, sc.savedFolder.Id, dash.FolderId)
|
|
assert.Greater(t, dash.Version, sc.savedDashInGeneralFolder.Version)
|
|
})
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by uid without current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "test dash 23",
|
|
}),
|
|
FolderId: 0,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardVersionMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by uid with current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "Updated title",
|
|
"version": sc.savedDashInFolder.Version,
|
|
}),
|
|
FolderId: 0,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(sc.savedDashInFolder.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated title", dash.Title)
|
|
assert.Equal(t, int64(0), dash.FolderId)
|
|
assert.Greater(t, dash.Version, sc.savedDashInFolder.Version)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard with same name as dashboard in other folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
FolderId: sc.savedDashInFolder.FolderId,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard with same name as dashboard in General folder",
|
|
canSave, func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInGeneralFolder.Title,
|
|
}),
|
|
FolderId: sc.savedDashInGeneralFolder.FolderId,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a folder with same name as existing folder", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedFolder.Title,
|
|
}),
|
|
IsFolder: true,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardWithSameNameInFolderExists, err)
|
|
})
|
|
})
|
|
|
|
t.Run("and overwrite flag is set to true", func(t *testing.T) {
|
|
const shouldOverwrite = true
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by id without current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInGeneralFolder.Id,
|
|
"title": "Updated title",
|
|
}),
|
|
FolderId: sc.savedFolder.Id,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(sc.savedDashInGeneralFolder.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated title", dash.Title)
|
|
assert.Equal(t, sc.savedFolder.Id, dash.FolderId)
|
|
assert.Greater(t, dash.Version, sc.savedDashInGeneralFolder.Version)
|
|
})
|
|
|
|
permissionScenario(t, "When updating an existing dashboard by uid without current version", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "Updated title",
|
|
}),
|
|
FolderId: 0,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(sc.savedDashInFolder.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Updated title", dash.Title)
|
|
assert.Equal(t, int64(0), dash.FolderId)
|
|
assert.Greater(t, dash.Version, sc.savedDashInFolder.Version)
|
|
})
|
|
|
|
permissionScenario(t, "When updating uid for existing dashboard using id", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"uid": "new-uid",
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
|
|
assert.Equal(t, "new-uid", res.Uid)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(sc.savedDashInFolder.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "new-uid", dash.Uid)
|
|
assert.Greater(t, dash.Version, sc.savedDashInFolder.Version)
|
|
})
|
|
|
|
permissionScenario(t, "When updating uid to an existing uid for existing dashboard using id", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"uid": sc.savedDashInGeneralFolder.Uid,
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardWithSameUIDExists, err)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard with same name as dashboard in other folder", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInFolder.Title,
|
|
}),
|
|
FolderId: sc.savedDashInFolder.FolderId,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
assert.Equal(t, sc.savedDashInFolder.Id, res.Id)
|
|
assert.Equal(t, sc.savedDashInFolder.Uid, res.Uid)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
assert.Equal(t, res.Uid, dash.Uid)
|
|
})
|
|
|
|
permissionScenario(t, "When creating a dashboard with same name as dashboard in General folder", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: testOrgID,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": sc.savedDashInGeneralFolder.Title,
|
|
}),
|
|
FolderId: sc.savedDashInGeneralFolder.FolderId,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
res := callSaveWithResult(t, cmd, sc.sqlStore)
|
|
require.NotNil(t, res)
|
|
assert.Equal(t, sc.savedDashInGeneralFolder.Id, res.Id)
|
|
assert.Equal(t, sc.savedDashInGeneralFolder.Uid, res.Uid)
|
|
|
|
dash, err := sc.sqlStore.GetDashboard(res.Id, cmd.OrgId, "", "")
|
|
require.NoError(t, err)
|
|
assert.Equal(t, res.Id, dash.Id)
|
|
assert.Equal(t, res.Uid, dash.Uid)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing folder to a dashboard using id", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedFolder.Id,
|
|
"title": "new title",
|
|
}),
|
|
IsFolder: false,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing dashboard to a folder using id", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": sc.savedDashInFolder.Id,
|
|
"title": "new folder title",
|
|
}),
|
|
IsFolder: true,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing folder to a dashboard using uid", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedFolder.Uid,
|
|
"title": "new title",
|
|
}),
|
|
IsFolder: false,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing dashboard to a folder using uid", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"uid": sc.savedDashInFolder.Uid,
|
|
"title": "new folder title",
|
|
}),
|
|
IsFolder: true,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardTypeMismatch, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing folder to a dashboard using title", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": sc.savedFolder.Title,
|
|
}),
|
|
IsFolder: false,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardWithSameNameAsFolder, err)
|
|
})
|
|
|
|
permissionScenario(t, "When updating existing dashboard to a folder using title", canSave,
|
|
func(t *testing.T, sc *permissionScenarioContext) {
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: 1,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"title": sc.savedDashInGeneralFolder.Title,
|
|
}),
|
|
IsFolder: true,
|
|
Overwrite: shouldOverwrite,
|
|
}
|
|
|
|
err := callSaveWithError(cmd, sc.sqlStore)
|
|
assert.Equal(t, models.ErrDashboardFolderWithSameNameAsDashboard, err)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
type permissionScenarioContext struct {
|
|
dashboardGuardianMock *guardian.FakeDashboardGuardian
|
|
sqlStore *sqlstore.SQLStore
|
|
savedFolder *models.Dashboard
|
|
savedDashInFolder *models.Dashboard
|
|
otherSavedFolder *models.Dashboard
|
|
savedDashInGeneralFolder *models.Dashboard
|
|
}
|
|
|
|
type permissionScenarioFunc func(t *testing.T, sc *permissionScenarioContext)
|
|
|
|
func permissionScenario(t *testing.T, desc string, canSave bool, fn permissionScenarioFunc) {
|
|
t.Helper()
|
|
|
|
mock := &guardian.FakeDashboardGuardian{
|
|
CanSaveValue: canSave,
|
|
}
|
|
|
|
t.Run(desc, func(t *testing.T) {
|
|
sqlStore := sqlstore.InitTestDB(t)
|
|
|
|
savedFolder := saveTestFolder(t, "Saved folder", testOrgID, sqlStore)
|
|
savedDashInFolder := saveTestDashboard(t, "Saved dash in folder", testOrgID, savedFolder.Id, sqlStore)
|
|
saveTestDashboard(t, "Other saved dash in folder", testOrgID, savedFolder.Id, sqlStore)
|
|
savedDashInGeneralFolder := saveTestDashboard(t, "Saved dashboard in general folder", testOrgID, 0, sqlStore)
|
|
otherSavedFolder := saveTestFolder(t, "Other saved folder", testOrgID, sqlStore)
|
|
|
|
require.Equal(t, "Saved folder", savedFolder.Title)
|
|
require.Equal(t, "saved-folder", savedFolder.Slug)
|
|
require.NotEqual(t, int64(0), savedFolder.Id)
|
|
require.True(t, savedFolder.IsFolder)
|
|
require.Equal(t, int64(0), savedFolder.FolderId)
|
|
require.NotEmpty(t, savedFolder.Uid)
|
|
|
|
require.Equal(t, "Saved dash in folder", savedDashInFolder.Title)
|
|
require.Equal(t, "saved-dash-in-folder", savedDashInFolder.Slug)
|
|
require.NotEqual(t, int64(0), savedDashInFolder.Id)
|
|
require.False(t, savedDashInFolder.IsFolder)
|
|
require.Equal(t, savedFolder.Id, savedDashInFolder.FolderId)
|
|
require.NotEmpty(t, savedDashInFolder.Uid)
|
|
|
|
origNewDashboardGuardian := guardian.New
|
|
t.Cleanup(func() {
|
|
guardian.New = origNewDashboardGuardian
|
|
})
|
|
guardian.MockDashboardGuardian(mock)
|
|
|
|
sc := &permissionScenarioContext{
|
|
dashboardGuardianMock: mock,
|
|
sqlStore: sqlStore,
|
|
savedDashInFolder: savedDashInFolder,
|
|
otherSavedFolder: otherSavedFolder,
|
|
savedDashInGeneralFolder: savedDashInGeneralFolder,
|
|
savedFolder: savedFolder,
|
|
}
|
|
|
|
fn(t, sc)
|
|
})
|
|
}
|
|
|
|
func callSaveWithResult(t *testing.T, cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLStore) *models.Dashboard {
|
|
t.Helper()
|
|
|
|
dto := toSaveDashboardDto(cmd)
|
|
res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
|
|
require.NoError(t, err)
|
|
|
|
return res
|
|
}
|
|
|
|
func callSaveWithError(cmd models.SaveDashboardCommand, sqlStore *sqlstore.SQLStore) error {
|
|
dto := toSaveDashboardDto(cmd)
|
|
_, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
|
|
return err
|
|
}
|
|
|
|
func saveTestDashboard(t *testing.T, title string, orgID, folderID int64, sqlStore *sqlstore.SQLStore) *models.Dashboard {
|
|
t.Helper()
|
|
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: orgID,
|
|
FolderId: folderID,
|
|
IsFolder: false,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": title,
|
|
}),
|
|
}
|
|
|
|
dto := SaveDashboardDTO{
|
|
OrgId: orgID,
|
|
Dashboard: cmd.GetDashboardModel(),
|
|
User: &models.SignedInUser{
|
|
UserId: 1,
|
|
OrgRole: models.ROLE_ADMIN,
|
|
},
|
|
}
|
|
|
|
res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
|
|
require.NoError(t, err)
|
|
|
|
return res
|
|
}
|
|
|
|
func saveTestFolder(t *testing.T, title string, orgID int64, sqlStore *sqlstore.SQLStore) *models.Dashboard {
|
|
t.Helper()
|
|
cmd := models.SaveDashboardCommand{
|
|
OrgId: orgID,
|
|
FolderId: 0,
|
|
IsFolder: true,
|
|
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
|
"id": nil,
|
|
"title": title,
|
|
}),
|
|
}
|
|
|
|
dto := SaveDashboardDTO{
|
|
OrgId: orgID,
|
|
Dashboard: cmd.GetDashboardModel(),
|
|
User: &models.SignedInUser{
|
|
UserId: 1,
|
|
OrgRole: models.ROLE_ADMIN,
|
|
},
|
|
}
|
|
|
|
res, err := NewService(sqlStore).SaveDashboard(context.Background(), &dto, false)
|
|
require.NoError(t, err)
|
|
|
|
return res
|
|
}
|
|
|
|
func toSaveDashboardDto(cmd models.SaveDashboardCommand) SaveDashboardDTO {
|
|
dash := (&cmd).GetDashboardModel()
|
|
|
|
return SaveDashboardDTO{
|
|
Dashboard: dash,
|
|
Message: cmd.Message,
|
|
OrgId: cmd.OrgId,
|
|
User: &models.SignedInUser{UserId: cmd.UserId},
|
|
Overwrite: cmd.Overwrite,
|
|
}
|
|
}
|