The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/dashboardimport/service/service_test.go

236 lines
8.3 KiB

package service
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/dashboardimport"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/librarypanels"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/plugindashboards"
"github.com/grafana/grafana/pkg/services/user"
)
func TestImportDashboardService(t *testing.T) {
t.Run("When importing a plugin dashboard should save dashboard and sync library panels", func(t *testing.T) {
pluginDashboardService := &pluginDashboardServiceMock{
loadPluginDashboardFunc: loadTestDashboard,
}
var importDashboardArg *dashboards.SaveDashboardDTO
dashboardService := &dashboardServiceMock{
importDashboardFunc: func(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) {
importDashboardArg = dto
return &dashboards.Dashboard{
ID: 4,
UID: dto.Dashboard.UID,
Slug: dto.Dashboard.Slug,
OrgID: 3,
Version: dto.Dashboard.Version,
PluginID: "prometheus",
FolderID: dto.Dashboard.FolderID, // nolint:staticcheck
Title: dto.Dashboard.Title,
Data: dto.Dashboard.Data,
}, nil
},
}
importLibraryPanelsForDashboard := false
connectLibraryPanelsForDashboardCalled := false
libraryPanelService := &libraryPanelServiceMock{
importLibraryPanelsForDashboardFunc: func(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error {
importLibraryPanelsForDashboard = true
return nil
},
connectLibraryPanelsForDashboardFunc: func(ctx context.Context, signedInUser identity.Requester, dash *dashboards.Dashboard) error {
connectLibraryPanelsForDashboardCalled = true
return nil
},
}
folderService := &foldertest.FakeService{
ExpectedFolder: &folder.Folder{
ID: 5,
UID: "123",
},
}
s := &ImportDashboardService{
pluginDashboardService: pluginDashboardService,
dashboardService: dashboardService,
libraryPanelService: libraryPanelService,
folderService: folderService,
}
req := &dashboardimport.ImportDashboardRequest{
PluginId: "prometheus",
Path: "dashboard.json",
Inputs: []dashboardimport.ImportDashboardInput{
{Name: "*", Type: "datasource", Value: "prom"},
},
User: &user.SignedInUser{UserID: 2, OrgRole: org.RoleAdmin, OrgID: 3},
FolderId: 5, // nolint:staticcheck
}
resp, err := s.ImportDashboard(context.Background(), req)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg)
require.Equal(t, int64(3), importDashboardArg.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, "prometheus", importDashboardArg.Dashboard.PluginID)
// nolint:staticcheck
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)
panel := importDashboardArg.Dashboard.Data.Get("panels").GetIndex(0)
require.Equal(t, "prom", panel.Get("datasource").MustString())
require.True(t, importLibraryPanelsForDashboard)
require.True(t, connectLibraryPanelsForDashboardCalled)
})
t.Run("When importing a non-plugin dashboard should save dashboard and sync library panels", func(t *testing.T) {
var importDashboardArg *dashboards.SaveDashboardDTO
dashboardService := &dashboardServiceMock{
importDashboardFunc: func(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) {
importDashboardArg = dto
return &dashboards.Dashboard{
ID: 4,
UID: dto.Dashboard.UID,
Slug: dto.Dashboard.Slug,
OrgID: 3,
Version: dto.Dashboard.Version,
PluginID: "prometheus",
FolderID: dto.Dashboard.FolderID, // nolint:staticcheck
Title: dto.Dashboard.Title,
Data: dto.Dashboard.Data,
}, nil
},
}
libraryPanelService := &libraryPanelServiceMock{}
folderService := &foldertest.FakeService{
ExpectedFolder: &folder.Folder{
ID: 5,
UID: "123",
},
}
s := &ImportDashboardService{
dashboardService: dashboardService,
libraryPanelService: libraryPanelService,
folderService: folderService,
}
loadResp, err := loadTestDashboard(context.Background(), &plugindashboards.LoadPluginDashboardRequest{
PluginID: "",
Reference: "dashboard.json",
})
require.NoError(t, err)
req := &dashboardimport.ImportDashboardRequest{
Dashboard: loadResp.Dashboard.Data,
Path: "plugin_dashboard.json",
Inputs: []dashboardimport.ImportDashboardInput{
{Name: "*", Type: "datasource", Value: "prom"},
},
User: &user.SignedInUser{UserID: 2, OrgRole: org.RoleAdmin, OrgID: 3},
FolderId: 5, // nolint:staticcheck
}
resp, err := s.ImportDashboard(context.Background(), req)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, "UDdpyzz7z", resp.UID)
userID, err := identity.IntIdentifier(importDashboardArg.User.GetNamespacedID())
require.NoError(t, err)
require.NotNil(t, importDashboardArg)
require.Equal(t, int64(3), importDashboardArg.OrgID)
require.Equal(t, int64(2), userID)
require.Equal(t, "", importDashboardArg.Dashboard.PluginID)
// nolint:staticcheck
require.Equal(t, int64(5), importDashboardArg.Dashboard.FolderID)
panel := importDashboardArg.Dashboard.Data.Get("panels").GetIndex(0)
require.Equal(t, "prom", panel.Get("datasource").MustString())
})
}
func loadTestDashboard(ctx context.Context, req *plugindashboards.LoadPluginDashboardRequest) (*plugindashboards.LoadPluginDashboardResponse, error) {
// It's safe to ignore gosec warning G304 since this is a test and arguments comes from test configuration.
// nolint:gosec
bytes, err := os.ReadFile(filepath.Join("testdata", req.Reference))
if err != nil {
return nil, err
}
dashboardJSON, err := simplejson.NewJson(bytes)
if err != nil {
return nil, err
}
return &plugindashboards.LoadPluginDashboardResponse{
Dashboard: dashboards.NewDashboardFromJson(dashboardJSON),
}, nil
}
type pluginDashboardServiceMock struct {
plugindashboards.Service
loadPluginDashboardFunc func(ctx context.Context, req *plugindashboards.LoadPluginDashboardRequest) (*plugindashboards.LoadPluginDashboardResponse, error)
}
func (m *pluginDashboardServiceMock) LoadPluginDashboard(ctx context.Context, req *plugindashboards.LoadPluginDashboardRequest) (*plugindashboards.LoadPluginDashboardResponse, error) {
if m.loadPluginDashboardFunc != nil {
return m.loadPluginDashboardFunc(ctx, req)
}
return nil, nil
}
type dashboardServiceMock struct {
dashboards.DashboardService
importDashboardFunc func(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error)
}
func (s *dashboardServiceMock) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) {
if s.importDashboardFunc != nil {
return s.importDashboardFunc(ctx, dto)
}
return nil, nil
}
type libraryPanelServiceMock struct {
librarypanels.Service
connectLibraryPanelsForDashboardFunc func(c context.Context, signedInUser identity.Requester, dash *dashboards.Dashboard) error
importLibraryPanelsForDashboardFunc func(c context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error
}
var _ librarypanels.Service = (*libraryPanelServiceMock)(nil)
func (s *libraryPanelServiceMock) ConnectLibraryPanelsForDashboard(ctx context.Context, signedInUser identity.Requester, dash *dashboards.Dashboard) error {
if s.connectLibraryPanelsForDashboardFunc != nil {
return s.connectLibraryPanelsForDashboardFunc(ctx, signedInUser, dash)
}
return nil
}
func (s *libraryPanelServiceMock) ImportLibraryPanelsForDashboard(ctx context.Context, signedInUser identity.Requester, libraryPanels *simplejson.Json, panels []any, folderID int64) error {
if s.importLibraryPanelsForDashboardFunc != nil {
return s.importLibraryPanelsForDashboardFunc(ctx, signedInUser, libraryPanels, panels, folderID)
}
return nil
}