grafana/pkg/services/libraryelements/libraryelements_patch_test.go

506 lines
22 KiB
Go
Raw Permalink Normal View History

package libraryelements
import (
"encoding/json"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/libraryelements/model"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/util/testutil"
"github.com/grafana/grafana/pkg/web"
)
func TestIntegration_PatchLibraryElement(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
scenarioWithPanel(t, "When an admin tries to patch a library panel that does not exist, it should fail",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{Kind: int64(model.PanelElement), Version: 1}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": "unknown"})
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 404, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel that exists, it should succeed",
func(t *testing.T, sc scenarioContext) {
newFolder := &folder.Folder{
ID: 2,
OrgID: 1,
UID: "uid_for_NewFolder",
Title: "NewFolder",
}
sc.folderSvc.ExpectedFolder = newFolder
sc.folderSvc.ExpectedFolders = []*folder.Folder{newFolder}
cmd := model.PatchLibraryElementCommand{
FolderID: newFolder.ID, // nolint:staticcheck
FolderUID: &newFolder.UID,
Name: "Panel - New name",
Model: []byte(`
{
"datasource": "${DS_GDEV-TESTDATA}",
"description": "An updated description",
"id": 1,
"title": "Model - New name",
"type": "graph"
}
`),
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp)
var expected = libraryElementResult{
Result: libraryElement{
ID: 1,
OrgID: 1,
FolderID: newFolder.ID, // nolint:staticcheck
FolderUID: newFolder.UID,
UID: sc.initialResult.Result.UID,
Name: "Panel - New name",
Kind: int64(model.PanelElement),
Type: "graph",
Description: "An updated description",
Model: map[string]any{
"datasource": "${DS_GDEV-TESTDATA}",
"description": "An updated description",
"id": float64(1),
"title": "Model - New name",
"type": "graph",
},
Version: 2,
Meta: model.LibraryElementDTOMeta{
FolderName: "NewFolder",
FolderUID: "uid_for_NewFolder",
LibraryPanels: removes feature toggle (#33839) * WIP: intial structure * Refactor: adds create library element endpoint * Feature: adds delete library element * wip * Refactor: adds get api * Refactor: adds get all api * Refactor: adds patch api * Refactor: changes to library_element_connection * Refactor: add get connections api * wip: in the middle of refactor * wip * Refactor: consolidating both api:s * Refactor: points front end to library elements api * Tests: Fixes broken test * LibraryPanels: removes feature toggle * Fix: fixes delete library elements in folder and adds tests * Tests: fixes snapshot * Refactor: adds service interfaces so they can be easily mocked * Refactor: changes order of tabs in manage folder * Refactor: fixes so link does not cover whole card * Refactor: fixes index string name * Update pkg/services/libraryelements/libraryelements.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/services/libraryelements/libraryelements_permissions_test.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/services/libraryelements/database.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Chore: changes after PR comments * Update libraryelements.go * Update libraryelements.go * Chore: updates after PR comments * Chore: trying to fix build error * Refactor: fixed stupid mistake * Update libraryelements.go * Chore: tries to fix build errors * Refactor: trying to fix MySQL key length * Update libraryelements.go * Update pkg/services/libraryelements/libraryelements.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Update pkg/services/librarypanels/librarypanels.go Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> * Refactor: changes after PR comments * Refactor: changes after PR comments * Tests: fixes tests * Refactor: renames connections to connectedDashboards Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
2021-05-12 02:48:17 -04:00
ConnectedDashboards: 0,
Created: sc.initialResult.Result.Meta.Created,
Updated: result.Result.Meta.Updated,
CreatedBy: model.LibraryElementDTOMetaUser{
Id: 1,
Name: userInDbName,
AvatarUrl: userInDbAvatar,
},
UpdatedBy: model.LibraryElementDTOMetaUser{
Id: 1,
Name: "signed_in_user",
AvatarUrl: "/avatar/00c249f3bdb8ead55b7b551e293907924d644158062bddc4e29a578ec3f89018",
},
},
},
}
if diff := cmp.Diff(expected, result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with folder only, it should change folder successfully and return correct result",
func(t *testing.T, sc scenarioContext) {
newFolder := &folder.Folder{
ID: 2,
OrgID: 1,
UID: "uid_for_NewFolder",
Title: "NewFolder",
}
sc.folderSvc.ExpectedFolder = newFolder
sc.folderSvc.ExpectedFolders = []*folder.Folder{newFolder}
cmd := model.PatchLibraryElementCommand{
FolderID: newFolder.ID, // nolint:staticcheck
FolderUID: &newFolder.UID,
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var result = validateAndUnMarshalResponse(t, resp)
// nolint:staticcheck
sc.initialResult.Result.FolderID = newFolder.ID
sc.initialResult.Result.FolderUID = newFolder.UID
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Version = 2
sc.initialResult.Result.Meta.FolderName = "NewFolder"
sc.initialResult.Result.Meta.FolderUID = "uid_for_NewFolder"
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with name only, it should change name successfully and return correct result",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
Name: "New Name",
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Name = "New Name"
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Model["title"] = "Text - Library Panel"
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with a nonexistent UID, it should change UID successfully and return correct result",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
UID: util.GenerateShortUID(),
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.UID = cmd.UID
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Model["title"] = "Text - Library Panel"
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with an invalid UID, it should fail",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
UID: "Testing an invalid UID",
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with an UID that is too long, it should fail",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
FolderUID: &sc.folder.UID,
UID: "j6T00KRZzj6T00KRZzj6T00KRZzj6T00KRZzj6T00K",
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with an existing UID, it should fail",
func(t *testing.T, sc scenarioContext) {
// nolint:staticcheck
command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Existing UID")
command.UID = util.GenerateShortUID()
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
FolderUID: &sc.folder.UID,
UID: command.UID,
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with model only, it should change model successfully, sync type and description fields and return correct result",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
Model: []byte(`{ "title": "New Model Title", "name": "New Model Name", "type":"graph", "description": "New description" }`),
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "graph"
sc.initialResult.Result.Description = "New description"
sc.initialResult.Result.Model = map[string]any{
"title": "New Model Title",
"name": "New Model Name",
"type": "graph",
"description": "New description",
}
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with model.description only, it should change model successfully, sync type and description fields and return correct result",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
Model: []byte(`{ "description": "New description" }`),
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "text"
sc.initialResult.Result.Description = "New description"
sc.initialResult.Result.Model = map[string]any{
"type": "text",
"description": "New description",
}
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with model.type only, it should change model successfully, sync type and description fields and return correct result",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
Model: []byte(`{ "type": "graph" }`),
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Type = "graph"
sc.initialResult.Result.Description = "A description"
sc.initialResult.Result.Model = map[string]any{
"type": "graph",
"description": "A description",
}
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When another admin tries to patch a library panel, it should change UpdatedBy successfully and return correct result",
func(t *testing.T, sc scenarioContext) {
// nolint:staticcheck
cmd := model.PatchLibraryElementCommand{FolderID: -1, Version: 1, Kind: int64(model.PanelElement)}
sc.reqContext.UserID = 2
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
sc.initialResult.Result.Meta.UpdatedBy.Id = int64(2)
sc.initialResult.Result.Meta.CreatedBy.Name = userInDbName
sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = userInDbAvatar
sc.initialResult.Result.Meta.Updated = result.Result.Meta.Updated
sc.initialResult.Result.Version = 2
if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" {
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
}
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with a name that already exists, it should pass",
func(t *testing.T, sc scenarioContext) {
// nolint:staticcheck
command := getCreatePanelCommand(sc.folder.ID, sc.folder.UID, "Another Panel")
sc.ctx.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
var result = validateAndUnMarshalResponse(t, resp)
cmd := model.PatchLibraryElementCommand{
Name: "Text - Library Panel",
Version: 1,
Kind: int64(model.PanelElement),
FolderUID: &sc.folder.UID,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with a folder where a library panel with the same name already exists, it should pass",
func(t *testing.T, sc scenarioContext) {
newFolder := &folder.Folder{
ID: 2,
OrgID: 1,
UID: "uid_for_NewFolder",
Title: "NewFolder",
}
sc.folderSvc.ExpectedFolder = newFolder
sc.folderSvc.ExpectedFolders = []*folder.Folder{newFolder}
// nolint:staticcheck
command := getCreatePanelCommand(newFolder.ID, newFolder.UID, "Text - Library Panel")
sc.ctx.Req.Body = mockRequestBody(command)
sc.service.createHandler(sc.reqContext)
cmd := model.PatchLibraryElementCommand{
FolderID: newFolder.ID, // nolint:staticcheck
FolderUID: &newFolder.UID,
Version: 1,
Kind: int64(model.PanelElement),
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel in another org, it should fail",
func(t *testing.T, sc scenarioContext) {
sc.folderSvc.ExpectedFolder = nil
sc.folderSvc.ExpectedError = folder.ErrFolderNotFound
cmd := model.PatchLibraryElementCommand{
FolderID: sc.folder.ID, // nolint:staticcheck
FolderUID: &sc.folder.UID,
Version: 1,
Kind: int64(model.PanelElement),
}
sc.reqContext.OrgID = 2
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 400, resp.Status())
})
scenarioWithPanel(t, "When an admin tries to patch a library panel with an old version number, it should fail",
func(t *testing.T, sc scenarioContext) {
cmd := model.PatchLibraryElementCommand{
FolderID: sc.folder.ID, // nolint:staticcheck
FolderUID: &sc.folder.UID,
Version: 1,
Kind: int64(model.PanelElement),
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.ctx.Req.Body = mockRequestBody(cmd)
resp := sc.service.patchHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
sc.ctx.Req.Body = mockRequestBody(cmd)
resp = sc.service.patchHandler(sc.reqContext)
require.Equal(t, 412, resp.Status())
})
// Regression: getAllLibraryElements reads library_element.folder_uid directly from
// the table, so PATCH must keep that column in sync with folder_id or the list view
// diverges from GET-by-UID (which derives the UID from folder_id).
scenarioWithPanel(t, "When an admin moves a library panel to another folder, the list endpoint reflects the new folder",
func(t *testing.T, sc scenarioContext) {
destFolder := &folder.Folder{
ID: 2,
OrgID: 1,
UID: "uid_for_DestFolder",
Title: "DestFolder",
}
sc.folderSvc.ExpectedFolder = destFolder
sc.folderSvc.ExpectedFolders = []*folder.Folder{sc.folder, destFolder}
moveCmd := model.PatchLibraryElementCommand{
FolderID: destFolder.ID, // nolint:staticcheck
FolderUID: &destFolder.UID,
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(moveCmd)
require.Equal(t, 200, sc.service.patchHandler(sc.reqContext).Status())
require.NoError(t, sc.reqContext.Req.ParseForm())
sc.reqContext.Req.Form.Set("folderFilterUIDs", destFolder.UID)
resp := sc.service.getAllHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var atDest libraryElementsSearch
require.NoError(t, json.Unmarshal(resp.Body(), &atDest))
require.Len(t, atDest.Result.Elements, 1, "moved panel should appear when filtering by destination folder")
require.Equal(t, sc.initialResult.Result.UID, atDest.Result.Elements[0].UID)
require.Equal(t, destFolder.UID, atDest.Result.Elements[0].FolderUID)
require.Equal(t, destFolder.UID, atDest.Result.Elements[0].Meta.FolderUID)
sc.reqContext.Req.Form.Set("folderFilterUIDs", sc.folder.UID)
resp = sc.service.getAllHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var atOrig libraryElementsSearch
require.NoError(t, json.Unmarshal(resp.Body(), &atOrig))
require.Empty(t, atOrig.Result.Elements, "moved panel should not appear in original folder")
})
scenarioWithPanel(t, "When an admin moves a library panel to the root folder, the list endpoint reflects the move",
func(t *testing.T, sc scenarioContext) {
rootUID := ""
moveCmd := model.PatchLibraryElementCommand{
FolderUID: &rootUID,
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(moveCmd)
require.Equal(t, 200, sc.service.patchHandler(sc.reqContext).Status())
require.NoError(t, sc.reqContext.Req.ParseForm())
sc.reqContext.Req.Form.Set("folderFilter", "0")
resp := sc.service.getAllHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var listed libraryElementsSearch
require.NoError(t, json.Unmarshal(resp.Body(), &listed))
require.Len(t, listed.Result.Elements, 1, "panel should appear in root after move-to-root")
require.Equal(t, sc.initialResult.Result.UID, listed.Result.Elements[0].UID)
require.Equal(t, "", listed.Result.Elements[0].FolderUID)
require.Equal(t, "", listed.Result.Elements[0].Meta.FolderUID)
})
scenarioWithPanel(t, "When an admin patches a library panel without folderUid, it should stay in its existing folder",
func(t *testing.T, sc scenarioContext) {
renameCmd := model.PatchLibraryElementCommand{
FolderID: -1, // nolint:staticcheck
Name: "Renamed",
Kind: int64(model.PanelElement),
Version: 1,
}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(renameCmd)
require.Equal(t, 200, sc.service.patchHandler(sc.reqContext).Status())
require.NoError(t, sc.reqContext.Req.ParseForm())
sc.reqContext.Req.Form.Set("folderFilterUIDs", sc.folder.UID)
resp := sc.service.getAllHandler(sc.reqContext)
require.Equal(t, 200, resp.Status())
var listed libraryElementsSearch
require.NoError(t, json.Unmarshal(resp.Body(), &listed))
require.Len(t, listed.Result.Elements, 1, "panel should remain in its original folder when folderUid is not patched")
require.Equal(t, sc.folder.UID, listed.Result.Elements[0].FolderUID)
require.Equal(t, sc.folder.UID, listed.Result.Elements[0].Meta.FolderUID)
})
}