mirror of
https://github.com/grafana/grafana.git
synced 2025-01-26 08:16:59 -06:00
f1b2c750e5
* 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 * Fix: fixes delete library elements in folder and adds tests * Refactor: changes order of tabs in manage folder * Refactor: fixes so link does not cover whole card * 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 * Chore: updates after PR comments Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
822 lines
23 KiB
Go
822 lines
23 KiB
Go
package librarypanels
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/macaron.v1"
|
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
dboards "github.com/grafana/grafana/pkg/dashboards"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/registry"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/libraryelements"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
const UserInDbName = "user_in_db"
|
|
const UserInDbAvatar = "/avatar/402d08de060496d6b6874495fe20f5ad"
|
|
|
|
func TestLoadLibraryPanelsForDashboard(t *testing.T) {
|
|
scenarioWithLibraryPanel(t, "When an admin tries to load a dashboard with a library panel, it should copy JSON properties from library panel",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing LoadLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
err := sc.elementService.ConnectElementsToDashboard(sc.reqContext, []string{sc.initialResult.Result.UID}, dashInDB.Id)
|
|
require.NoError(t, err)
|
|
|
|
err = sc.service.LoadLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.NoError(t, err)
|
|
expectedJSON := map[string]interface{}{
|
|
"title": "Testing LoadLibraryPanelsForDashboard",
|
|
"uid": dashInDB.Uid,
|
|
"version": dashInDB.Version,
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"description": "A description",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
"type": sc.initialResult.Result.Type,
|
|
"description": sc.initialResult.Result.Description,
|
|
"version": sc.initialResult.Result.Version,
|
|
"meta": map[string]interface{}{
|
|
"folderName": "ScenarioFolder",
|
|
"folderUid": sc.folder.Uid,
|
|
"connectedDashboards": int64(1),
|
|
"created": sc.initialResult.Result.Meta.Created,
|
|
"updated": sc.initialResult.Result.Meta.Updated,
|
|
"createdBy": map[string]interface{}{
|
|
"id": sc.initialResult.Result.Meta.CreatedBy.ID,
|
|
"name": UserInDbName,
|
|
"avatarUrl": UserInDbAvatar,
|
|
},
|
|
"updatedBy": map[string]interface{}{
|
|
"id": sc.initialResult.Result.Meta.UpdatedBy.ID,
|
|
"name": UserInDbName,
|
|
"avatarUrl": UserInDbAvatar,
|
|
},
|
|
},
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
expected := simplejson.NewFromAny(expectedJSON)
|
|
if diff := cmp.Diff(expected.Interface(), dash.Data.Interface(), getCompareOptions()...); diff != "" {
|
|
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to load a dashboard with a library panel without uid, it should fail",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"libraryPanel": map[string]interface{}{
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing LoadLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
err := sc.elementService.ConnectElementsToDashboard(sc.reqContext, []string{sc.initialResult.Result.UID}, dashInDB.Id)
|
|
require.NoError(t, err)
|
|
|
|
err = sc.service.LoadLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.EqualError(t, err, errLibraryPanelHeaderUIDMissing.Error())
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to load a dashboard with a library panel that is not connected, it should set correct JSON and continue",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing LoadLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.LoadLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.NoError(t, err)
|
|
expectedJSON := map[string]interface{}{
|
|
"title": "Testing LoadLibraryPanelsForDashboard",
|
|
"uid": dashInDB.Uid,
|
|
"version": dashInDB.Version,
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"type": fmt.Sprintf("Name: \"%s\", UID: \"%s\"", sc.initialResult.Result.Name, sc.initialResult.Result.UID),
|
|
},
|
|
},
|
|
}
|
|
expected := simplejson.NewFromAny(expectedJSON)
|
|
if diff := cmp.Diff(expected.Interface(), dash.Data.Interface(), getCompareOptions()...); diff != "" {
|
|
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCleanLibraryPanelsForDashboard(t *testing.T) {
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel, it should just keep the correct JSON properties in library panel",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing CleanLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.CleanLibraryPanelsForDashboard(dashInDB)
|
|
require.NoError(t, err)
|
|
expectedJSON := map[string]interface{}{
|
|
"title": "Testing CleanLibraryPanelsForDashboard",
|
|
"uid": dashInDB.Uid,
|
|
"version": dashInDB.Version,
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
expected := simplejson.NewFromAny(expectedJSON)
|
|
if diff := cmp.Diff(expected.Interface(), dash.Data.Interface(), getCompareOptions()...); diff != "" {
|
|
t.Fatalf("Result mismatch (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel without uid, it should fail",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing CleanLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.CleanLibraryPanelsForDashboard(dashInDB)
|
|
require.EqualError(t, err, errLibraryPanelHeaderUIDMissing.Error())
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel without name, it should fail",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing CleanLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.CleanLibraryPanelsForDashboard(dashInDB)
|
|
require.EqualError(t, err, errLibraryPanelHeaderNameMissing.Error())
|
|
})
|
|
}
|
|
|
|
func TestConnectLibraryPanelsForDashboard(t *testing.T) {
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel, it should connect the two",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing ConnectLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.ConnectLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.NoError(t, err)
|
|
|
|
elements, err := sc.elementService.GetElementsForDashboard(sc.reqContext, dashInDB.Id)
|
|
require.NoError(t, err)
|
|
require.Len(t, elements, 1)
|
|
require.Equal(t, sc.initialResult.Result.UID, elements[sc.initialResult.Result.UID].UID)
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with a library panel without uid, it should fail",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
},
|
|
}
|
|
dash := models.Dashboard{
|
|
Title: "Testing ConnectLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
|
|
err := sc.service.ConnectLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.EqualError(t, err, errLibraryPanelHeaderUIDMissing.Error())
|
|
})
|
|
|
|
scenarioWithLibraryPanel(t, "When an admin tries to store a dashboard with unused/removed library panels, it should disconnect unused/removed library panels",
|
|
func(t *testing.T, sc scenarioContext) {
|
|
unused, err := sc.elementService.CreateElement(sc.reqContext, libraryelements.CreateLibraryElementCommand{
|
|
FolderID: sc.folder.Id,
|
|
Name: "Unused Libray Panel",
|
|
Model: []byte(`
|
|
{
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"id": 4,
|
|
"title": "Unused Libray Panel",
|
|
"type": "text",
|
|
"description": "Unused description"
|
|
}
|
|
`),
|
|
Kind: int64(libraryelements.Panel),
|
|
})
|
|
require.NoError(t, err)
|
|
dashJSON := map[string]interface{}{
|
|
"panels": []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(4),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": unused.UID,
|
|
"name": unused.Name,
|
|
},
|
|
"title": "Unused Libray Panel",
|
|
"description": "Unused description",
|
|
},
|
|
},
|
|
}
|
|
|
|
dash := models.Dashboard{
|
|
Title: "Testing ConnectLibraryPanelsForDashboard",
|
|
Data: simplejson.NewFromAny(dashJSON),
|
|
}
|
|
dashInDB := createDashboard(t, sc.sqlStore, sc.user, &dash, sc.folder.Id)
|
|
err = sc.elementService.ConnectElementsToDashboard(sc.reqContext, []string{sc.initialResult.Result.UID}, dashInDB.Id)
|
|
require.NoError(t, err)
|
|
|
|
panelJSON := []interface{}{
|
|
map[string]interface{}{
|
|
"id": int64(1),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 0,
|
|
"y": 0,
|
|
},
|
|
},
|
|
map[string]interface{}{
|
|
"id": int64(2),
|
|
"gridPos": map[string]interface{}{
|
|
"h": 6,
|
|
"w": 6,
|
|
"x": 6,
|
|
"y": 0,
|
|
},
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"libraryPanel": map[string]interface{}{
|
|
"uid": sc.initialResult.Result.UID,
|
|
"name": sc.initialResult.Result.Name,
|
|
},
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
},
|
|
}
|
|
dashInDB.Data.Set("panels", panelJSON)
|
|
err = sc.service.ConnectLibraryPanelsForDashboard(sc.reqContext, dashInDB)
|
|
require.NoError(t, err)
|
|
|
|
elements, err := sc.elementService.GetElementsForDashboard(sc.reqContext, dashInDB.Id)
|
|
require.NoError(t, err)
|
|
require.Len(t, elements, 1)
|
|
require.Equal(t, sc.initialResult.Result.UID, elements[sc.initialResult.Result.UID].UID)
|
|
})
|
|
}
|
|
|
|
type libraryPanel struct {
|
|
ID int64
|
|
OrgID int64
|
|
FolderID int64
|
|
UID string
|
|
Name string
|
|
Type string
|
|
Description string
|
|
Model map[string]interface{}
|
|
Version int64
|
|
Meta libraryelements.LibraryElementDTOMeta
|
|
}
|
|
|
|
type libraryPanelResult struct {
|
|
Result libraryPanel `json:"result"`
|
|
}
|
|
|
|
func overrideLibraryServicesInRegistry(cfg *setting.Cfg) (*LibraryPanelService, *libraryelements.LibraryElementService) {
|
|
les := libraryelements.LibraryElementService{
|
|
SQLStore: nil,
|
|
Cfg: cfg,
|
|
}
|
|
|
|
elementsOverride := func(d registry.Descriptor) (*registry.Descriptor, bool) {
|
|
descriptor := registry.Descriptor{
|
|
Name: "LibraryElementService",
|
|
Instance: &les,
|
|
}
|
|
|
|
return &descriptor, true
|
|
}
|
|
|
|
registry.RegisterOverride(elementsOverride)
|
|
|
|
lps := LibraryPanelService{
|
|
SQLStore: nil,
|
|
Cfg: cfg,
|
|
LibraryElementService: &les,
|
|
}
|
|
|
|
panelsOverride := func(d registry.Descriptor) (*registry.Descriptor, bool) {
|
|
descriptor := registry.Descriptor{
|
|
Name: "LibraryPanelService",
|
|
Instance: &lps,
|
|
}
|
|
|
|
return &descriptor, true
|
|
}
|
|
|
|
registry.RegisterOverride(panelsOverride)
|
|
|
|
return &lps, &les
|
|
}
|
|
|
|
type scenarioContext struct {
|
|
ctx *macaron.Context
|
|
service *LibraryPanelService
|
|
elementService *libraryelements.LibraryElementService
|
|
reqContext *models.ReqContext
|
|
user models.SignedInUser
|
|
folder *models.Folder
|
|
initialResult libraryPanelResult
|
|
sqlStore *sqlstore.SQLStore
|
|
}
|
|
|
|
type folderACLItem struct {
|
|
roleType models.RoleType
|
|
permission models.PermissionType
|
|
}
|
|
|
|
func createDashboard(t *testing.T, sqlStore *sqlstore.SQLStore, user models.SignedInUser, dash *models.Dashboard, folderID int64) *models.Dashboard {
|
|
dash.FolderId = folderID
|
|
dashItem := &dashboards.SaveDashboardDTO{
|
|
Dashboard: dash,
|
|
Message: "",
|
|
OrgId: user.OrgId,
|
|
User: &user,
|
|
Overwrite: false,
|
|
}
|
|
origUpdateAlerting := dashboards.UpdateAlerting
|
|
t.Cleanup(func() {
|
|
dashboards.UpdateAlerting = origUpdateAlerting
|
|
})
|
|
dashboards.UpdateAlerting = func(store dboards.Store, orgID int64, dashboard *models.Dashboard,
|
|
user *models.SignedInUser) error {
|
|
return nil
|
|
}
|
|
|
|
dashboard, err := dashboards.NewService(sqlStore).SaveDashboard(dashItem, true)
|
|
require.NoError(t, err)
|
|
|
|
return dashboard
|
|
}
|
|
|
|
func createFolderWithACL(t *testing.T, sqlStore *sqlstore.SQLStore, title string, user models.SignedInUser,
|
|
items []folderACLItem) *models.Folder {
|
|
t.Helper()
|
|
|
|
s := dashboards.NewFolderService(user.OrgId, &user, sqlStore)
|
|
t.Logf("Creating folder with title and UID %q", title)
|
|
folder, err := s.CreateFolder(title, title)
|
|
require.NoError(t, err)
|
|
|
|
updateFolderACL(t, sqlStore, folder.Id, items)
|
|
|
|
return folder
|
|
}
|
|
|
|
func updateFolderACL(t *testing.T, sqlStore *sqlstore.SQLStore, folderID int64, items []folderACLItem) {
|
|
t.Helper()
|
|
|
|
if len(items) == 0 {
|
|
return
|
|
}
|
|
|
|
var aclItems []*models.DashboardAcl
|
|
for _, item := range items {
|
|
role := item.roleType
|
|
permission := item.permission
|
|
aclItems = append(aclItems, &models.DashboardAcl{
|
|
DashboardID: folderID,
|
|
Role: &role,
|
|
Permission: permission,
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
}
|
|
|
|
err := sqlStore.UpdateDashboardACL(folderID, aclItems)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
|
t.Helper()
|
|
|
|
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
|
|
command := libraryelements.CreateLibraryElementCommand{
|
|
FolderID: sc.folder.Id,
|
|
Name: "Text - Library Panel",
|
|
Model: []byte(`
|
|
{
|
|
"datasource": "${DS_GDEV-TESTDATA}",
|
|
"id": 1,
|
|
"title": "Text - Library Panel",
|
|
"type": "text",
|
|
"description": "A description"
|
|
}
|
|
`),
|
|
Kind: int64(libraryelements.Panel),
|
|
}
|
|
resp, err := sc.elementService.CreateElement(sc.reqContext, command)
|
|
require.NoError(t, err)
|
|
var model map[string]interface{}
|
|
err = json.Unmarshal(resp.Model, &model)
|
|
require.NoError(t, err)
|
|
|
|
sc.initialResult = libraryPanelResult{
|
|
Result: libraryPanel{
|
|
ID: resp.ID,
|
|
OrgID: resp.OrgID,
|
|
FolderID: resp.FolderID,
|
|
UID: resp.UID,
|
|
Name: resp.Name,
|
|
Type: resp.Type,
|
|
Description: resp.Description,
|
|
Model: model,
|
|
Version: resp.Version,
|
|
Meta: resp.Meta,
|
|
},
|
|
}
|
|
|
|
fn(t, sc)
|
|
})
|
|
}
|
|
|
|
// testScenario is a wrapper around t.Run performing common setup for library panel tests.
|
|
// It takes your real test function as a callback.
|
|
func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
|
|
t.Helper()
|
|
|
|
t.Run(desc, func(t *testing.T) {
|
|
t.Cleanup(registry.ClearOverrides)
|
|
|
|
ctx := macaron.Context{
|
|
Req: macaron.Request{Request: &http.Request{}},
|
|
}
|
|
orgID := int64(1)
|
|
role := models.ROLE_ADMIN
|
|
|
|
cfg := setting.NewCfg()
|
|
// Everything in this service is behind the feature toggle "panelLibrary"
|
|
cfg.FeatureToggles = map[string]bool{"panelLibrary": true}
|
|
// Because the LibraryPanelService is behind a feature toggle, we need to override the service in the registry
|
|
// with a Cfg that contains the feature toggle so migrations are run properly
|
|
service, elementService := overrideLibraryServicesInRegistry(cfg)
|
|
|
|
// We need to assign SQLStore after the override and migrations are done
|
|
sqlStore := sqlstore.InitTestDB(t)
|
|
elementService.SQLStore = sqlStore
|
|
service.SQLStore = sqlStore
|
|
|
|
user := models.SignedInUser{
|
|
UserId: 1,
|
|
Name: "Signed In User",
|
|
Login: "signed_in_user",
|
|
Email: "signed.in.user@test.com",
|
|
OrgId: orgID,
|
|
OrgRole: role,
|
|
LastSeenAt: time.Now(),
|
|
}
|
|
|
|
// deliberate difference between signed in user and user in db to make it crystal clear
|
|
// what to expect in the tests
|
|
// In the real world these are identical
|
|
cmd := models.CreateUserCommand{
|
|
Email: "user.in.db@test.com",
|
|
Name: "User In DB",
|
|
Login: UserInDbName,
|
|
}
|
|
_, err := sqlStore.CreateUser(context.Background(), cmd)
|
|
require.NoError(t, err)
|
|
|
|
sc := scenarioContext{
|
|
user: user,
|
|
ctx: &ctx,
|
|
service: service,
|
|
elementService: elementService,
|
|
sqlStore: sqlStore,
|
|
reqContext: &models.ReqContext{
|
|
Context: &ctx,
|
|
SignedInUser: &user,
|
|
},
|
|
}
|
|
|
|
sc.folder = createFolderWithACL(t, sc.sqlStore, "ScenarioFolder", sc.user, []folderACLItem{})
|
|
|
|
fn(t, sc)
|
|
})
|
|
}
|
|
|
|
func getCompareOptions() []cmp.Option {
|
|
return []cmp.Option{
|
|
cmp.Transformer("Time", func(in time.Time) int64 {
|
|
return in.UTC().Unix()
|
|
}),
|
|
}
|
|
}
|