PublicDashboards: move methods from store to service (#57599)

This commit is contained in:
Ezequiel Victorero
2022-10-25 16:29:18 -03:00
committed by GitHub
parent c27aac0d38
commit c5e420a94c
8 changed files with 363 additions and 201 deletions

View File

@@ -25,6 +25,7 @@ import (
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func TestIntegrationDashboardDataAccess(t *testing.T) {
@@ -243,7 +244,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
t.Run("Should be able to delete dashboard and related public dashboard", func(t *testing.T) {
setup()
uid, _ := publicDashboardStore.GenerateNewPublicDashboardUid(context.Background())
uid := util.GenerateShortUID()
cmd := publicDashboardModels.SavePublicDashboardConfigCommand{
PublicDashboard: publicDashboardModels.PublicDashboard{
Uid: uid,
@@ -278,7 +279,7 @@ func TestIntegrationDashboardDataAccess(t *testing.T) {
t.Run("Should be able to delete a dashboard folder, with its dashboard and related public dashboard", func(t *testing.T) {
setup()
uid, _ := publicDashboardStore.GenerateNewPublicDashboardUid(context.Background())
uid := util.GenerateShortUID()
cmd := publicDashboardModels.SavePublicDashboardConfigCommand{
PublicDashboard: publicDashboardModels.PublicDashboard{
Uid: uid,

View File

@@ -9,9 +9,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/util"
)
// Define the storage implementation. We're generating the mock implementation
@@ -106,67 +104,7 @@ func (d *PublicDashboardStoreImpl) GetPublicDashboardAndDashboard(ctx context.Co
return pdRes, dashRes, err
}
// Generates a new unique uid to retrieve a public dashboard
func (d *PublicDashboardStoreImpl) GenerateNewPublicDashboardUid(ctx context.Context) (string, error) {
var uid string
err := d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
for i := 0; i < 3; i++ {
uid = util.GenerateShortUID()
exists, err := sess.Get(&PublicDashboard{Uid: uid})
if err != nil {
return err
}
if !exists {
return nil
}
}
return ErrPublicDashboardFailedGenerateUniqueUid
})
if err != nil {
return "", err
}
return uid, nil
}
// Generates a new unique access token for a new public dashboard
func (d *PublicDashboardStoreImpl) GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error) {
var accessToken string
err := d.sqlStore.WithDbSession(ctx, func(sess *db.Session) error {
for i := 0; i < 3; i++ {
var err error
accessToken, err = tokens.GenerateAccessToken()
if err != nil {
continue
}
exists, err := sess.Get(&PublicDashboard{AccessToken: accessToken})
if err != nil {
return err
}
if !exists {
return nil
}
}
return ErrPublicDashboardFailedGenerateAccessToken
})
if err != nil {
return "", err
}
return accessToken, nil
}
// Retrieves public dashboard configuration by Uid
// GetPublicDashboardByUid Returns public dashboard configuration by Uid or nil if not found
func (d *PublicDashboardStoreImpl) GetPublicDashboardByUid(ctx context.Context, uid string) (*PublicDashboard, error) {
if uid == "" {
return nil, nil
@@ -191,6 +129,31 @@ func (d *PublicDashboardStoreImpl) GetPublicDashboardByUid(ctx context.Context,
return pdRes, err
}
// GetPublicDashboardByAccessToken Returns public dashboard by access token or nil if not found
func (d *PublicDashboardStoreImpl) GetPublicDashboardByAccessToken(ctx context.Context, accessToken string) (*PublicDashboard, error) {
if accessToken == "" {
return nil, ErrPublicDashboardIdentifierNotSet
}
var found bool
pdRes := &PublicDashboard{AccessToken: accessToken}
err := d.sqlStore.WithTransactionalDbSession(ctx, func(sess *db.Session) error {
var err error
found, err = sess.Get(pdRes)
return err
})
if err != nil {
return nil, err
}
if !found {
return nil, nil
}
return pdRes, err
}
// Retrieves public dashboard configuration
func (d *PublicDashboardStoreImpl) GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error) {
if dashboardUid == "" {

View File

@@ -576,8 +576,7 @@ func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardSto
func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardStoreImpl, dashboardUid string, orgId int64, isEnabled bool) *PublicDashboard {
ctx := context.Background()
uid, err := publicdashboardStore.GenerateNewPublicDashboardUid(ctx)
require.NoError(t, err)
uid := util.GenerateShortUID()
accessToken, err := tokens.GenerateAccessToken()
require.NoError(t, err)

View File

@@ -23,20 +23,41 @@ type FakePublicDashboardService struct {
mock.Mock
}
// AccessTokenExists provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardService) PublicDashboardEnabledExistsByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
// GenerateNewPublicDashboardAccessToken provides a mock function with given fields: ctx
func (_m *FakePublicDashboardService) GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, accessToken)
var r0 string
if rf, ok := ret.Get(0).(func(context.Context) string); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(bool)
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, accessToken)
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GenerateNewPublicDashboardUid provides a mock function with given fields: ctx
func (_m *FakePublicDashboardService) GenerateNewPublicDashboardUid(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
var r0 string
if rf, ok := ret.Get(0).(func(context.Context) string); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
@@ -111,7 +132,30 @@ func (_m *FakePublicDashboardService) GetMetricRequest(ctx context.Context, dash
return r0, r1
}
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
// GetPublicDashboard provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardService) GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
var r0 *models.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *models.PublicDashboard); ok {
r0 = rf(ctx, orgId, dashboardUid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
r1 = rf(ctx, orgId, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardAndDashboard provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardService) GetPublicDashboardAndDashboard(ctx context.Context, accessToken string) (*models.PublicDashboard, *pkgmodels.Dashboard, error) {
ret := _m.Called(ctx, accessToken)
@@ -143,29 +187,6 @@ func (_m *FakePublicDashboardService) GetPublicDashboardAndDashboard(ctx context
return r0, r1, r2
}
// GetPublicDashboardConfig provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardService) GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
var r0 *models.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *models.PublicDashboard); ok {
r0 = rf(ctx, orgId, dashboardUid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
r1 = rf(ctx, orgId, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardOrgId provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardService) GetPublicDashboardOrgId(ctx context.Context, accessToken string) (int64, error) {
ret := _m.Called(ctx, accessToken)
@@ -233,7 +254,28 @@ func (_m *FakePublicDashboardService) ListPublicDashboards(ctx context.Context,
return r0, r1
}
// PublicDashboardEnabled provides a mock function with given fields: ctx, dashboardUid
// PublicDashboardEnabledExistsByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardService) PublicDashboardEnabledExistsByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, accessToken)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, accessToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PublicDashboardIsEnabled provides a mock function with given fields: ctx, dashboardUid
func (_m *FakePublicDashboardService) PublicDashboardIsEnabled(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
@@ -254,7 +296,7 @@ func (_m *FakePublicDashboardService) PublicDashboardIsEnabled(ctx context.Conte
return r0, r1
}
// SavePublicDashboardConfig provides a mock function with given fields: ctx, u, dto
// SavePublicDashboard provides a mock function with given fields: ctx, u, dto
func (_m *FakePublicDashboardService) SavePublicDashboard(ctx context.Context, u *user.SignedInUser, dto *models.SavePublicDashboardConfigDTO) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, u, dto)

View File

@@ -1,4 +1,4 @@
// Code generated by mockery v2.12.1. DO NOT EDIT.
// Code generated by mockery v2.14.0. DO NOT EDIT.
package publicdashboards
@@ -9,8 +9,6 @@ import (
mock "github.com/stretchr/testify/mock"
publicdashboardsmodels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
testing "testing"
)
// FakePublicDashboardStore is an autogenerated mock type for the Store type
@@ -18,69 +16,6 @@ type FakePublicDashboardStore struct {
mock.Mock
}
// EnabledPublicDashboardExistsByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) PublicDashboardEnabledExistsByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, accessToken)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, accessToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GenerateNewPublicDashboardAccessToken provides a mock function with given fields: ctx
func (_m *FakePublicDashboardStore) GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
var r0 string
if rf, ok := ret.Get(0).(func(context.Context) string); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GenerateNewPublicDashboardUid provides a mock function with given fields: ctx
func (_m *FakePublicDashboardStore) GenerateNewPublicDashboardUid(ctx context.Context) (string, error) {
ret := _m.Called(ctx)
var r0 string
if rf, ok := ret.Get(0).(func(context.Context) string); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetDashboard provides a mock function with given fields: ctx, dashboardUid
func (_m *FakePublicDashboardStore) GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error) {
ret := _m.Called(ctx, dashboardUid)
@@ -104,7 +39,30 @@ func (_m *FakePublicDashboardStore) GetDashboard(ctx context.Context, dashboardU
return r0, r1
}
// GetPublicDashboard provides a mock function with given fields: ctx, accessToken
// GetPublicDashboard provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, orgId, dashboardUid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
r1 = rf(ctx, orgId, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardAndDashboard provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) GetPublicDashboardAndDashboard(ctx context.Context, accessToken string) (*publicdashboardsmodels.PublicDashboard, *models.Dashboard, error) {
ret := _m.Called(ctx, accessToken)
@@ -136,6 +94,29 @@ func (_m *FakePublicDashboardStore) GetPublicDashboardAndDashboard(ctx context.C
return r0, r1, r2
}
// GetPublicDashboardByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) GetPublicDashboardByAccessToken(ctx context.Context, accessToken string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, accessToken)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, string) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, accessToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, accessToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardByUid provides a mock function with given fields: ctx, uid
func (_m *FakePublicDashboardStore) GetPublicDashboardByUid(ctx context.Context, uid string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, uid)
@@ -159,29 +140,6 @@ func (_m *FakePublicDashboardStore) GetPublicDashboardByUid(ctx context.Context,
return r0, r1
}
// GetPublicDashboard provides a mock function with given fields: ctx, orgId, dashboardUid
func (_m *FakePublicDashboardStore) GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, orgId, dashboardUid)
var r0 *publicdashboardsmodels.PublicDashboard
if rf, ok := ret.Get(0).(func(context.Context, int64, string) *publicdashboardsmodels.PublicDashboard); ok {
r0 = rf(ctx, orgId, dashboardUid)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*publicdashboardsmodels.PublicDashboard)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, int64, string) error); ok {
r1 = rf(ctx, orgId, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetPublicDashboardOrgId provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) GetPublicDashboardOrgId(ctx context.Context, accessToken string) (int64, error) {
ret := _m.Called(ctx, accessToken)
@@ -226,7 +184,28 @@ func (_m *FakePublicDashboardStore) ListPublicDashboards(ctx context.Context, or
return r0, r1
}
// PublicDashboardIsEnabled provides a mock function with given fields: ctx, dashboardUid
// PublicDashboardEnabledExistsByAccessToken provides a mock function with given fields: ctx, accessToken
func (_m *FakePublicDashboardStore) PublicDashboardEnabledExistsByAccessToken(ctx context.Context, accessToken string) (bool, error) {
ret := _m.Called(ctx, accessToken)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, accessToken)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, accessToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PublicDashboardEnabledExistsByDashboardUid provides a mock function with given fields: ctx, dashboardUid
func (_m *FakePublicDashboardStore) PublicDashboardEnabledExistsByDashboardUid(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
@@ -261,7 +240,7 @@ func (_m *FakePublicDashboardStore) SavePublicDashboard(ctx context.Context, cmd
return r0
}
// UpdatePublicDashboardConfig provides a mock function with given fields: ctx, cmd
// UpdatePublicDashboard provides a mock function with given fields: ctx, cmd
func (_m *FakePublicDashboardStore) UpdatePublicDashboard(ctx context.Context, cmd publicdashboardsmodels.SavePublicDashboardConfigCommand) error {
ret := _m.Called(ctx, cmd)
@@ -275,8 +254,13 @@ func (_m *FakePublicDashboardStore) UpdatePublicDashboard(ctx context.Context, c
return r0
}
// NewFakePublicDashboardStore creates a new instance of FakePublicDashboardStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
func NewFakePublicDashboardStore(t testing.TB) *FakePublicDashboardStore {
type mockConstructorTestingTNewFakePublicDashboardStore interface {
mock.TestingT
Cleanup(func())
}
// NewFakePublicDashboardStore creates a new instance of FakePublicDashboardStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewFakePublicDashboardStore(t mockConstructorTestingTNewFakePublicDashboardStore) *FakePublicDashboardStore {
mock := &FakePublicDashboardStore{}
mock.Mock.Test(t)

View File

@@ -14,6 +14,8 @@ import (
//go:generate mockery --name Service --structname FakePublicDashboardService --inpackage --filename public_dashboard_service_mock.go
type Service interface {
GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error)
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
GetAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error)
GetMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64, reqDTO PublicDashboardQueryDTO) (dtos.MetricRequest, error)
@@ -29,11 +31,10 @@ type Service interface {
//go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go
type Store interface {
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error)
GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error)
GetPublicDashboard(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
GetPublicDashboardAndDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error)
GetPublicDashboardByAccessToken(ctx context.Context, accessToken string) (*PublicDashboard, error)
GetPublicDashboardByUid(ctx context.Context, uid string) (*PublicDashboard, error)
GetPublicDashboardOrgId(ctx context.Context, accessToken string) (int64, error)
ListPublicDashboards(ctx context.Context, orgId int64) ([]PublicDashboardListResponse, error)

View File

@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
"github.com/grafana/grafana/pkg/services/query"
@@ -19,6 +20,7 @@ import (
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
"github.com/grafana/grafana/pkg/util"
)
// PublicDashboardServiceImpl Define the Service Implementation. We're generating mock implementation
@@ -153,15 +155,47 @@ func (pd *PublicDashboardServiceImpl) SavePublicDashboard(ctx context.Context, u
return newPubdash, err
}
// GenerateNewPublicDashboardUid Generates a unique uid to create a public dashboard. Will make 3 attempts and fail if it cannot find an unused uid
func (pd *PublicDashboardServiceImpl) GenerateNewPublicDashboardUid(ctx context.Context) (string, error) {
var uid string
for i := 0; i < 3; i++ {
uid = util.GenerateShortUID()
pubdash, _ := pd.store.GetPublicDashboardByUid(ctx, uid)
if pubdash == nil {
return uid, nil
}
}
return "", ErrPublicDashboardFailedGenerateUniqueUid
}
// GenerateNewPublicDashboardAccessToken Generates a unique accessToken to create a public dashboard. Will make 3 attempts and fail if it cannot find an unused access token
func (pd *PublicDashboardServiceImpl) GenerateNewPublicDashboardAccessToken(ctx context.Context) (string, error) {
var accessToken string
for i := 0; i < 3; i++ {
var err error
accessToken, err = tokens.GenerateAccessToken()
if err != nil {
continue
}
pubdash, _ := pd.store.GetPublicDashboardByAccessToken(ctx, accessToken)
if pubdash == nil {
return accessToken, nil
}
}
return "", ErrPublicDashboardFailedGenerateAccessToken
}
// Called by SavePublicDashboard this handles business logic
// to generate token and calls create at the database layer
func (pd *PublicDashboardServiceImpl) savePublicDashboard(ctx context.Context, dto *SavePublicDashboardConfigDTO) (string, error) {
uid, err := pd.store.GenerateNewPublicDashboardUid(ctx)
uid, err := pd.GenerateNewPublicDashboardUid(ctx)
if err != nil {
return "", err
}
accessToken, err := pd.store.GenerateNewPublicDashboardAccessToken(ctx)
accessToken, err := pd.GenerateNewPublicDashboardAccessToken(ctx)
if err != nil {
return "", err
}

View File

@@ -3,6 +3,7 @@ package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"testing"
"time"
@@ -22,11 +23,13 @@ import (
"github.com/grafana/grafana/pkg/services/featuremgmt"
. "github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/util"
)
var timeSettings = &TimeSettings{From: "now-12h", To: "now"}
@@ -224,12 +227,19 @@ func TestSavePublicDashboard(t *testing.T) {
t.Run("Pubdash access token generation throws an error and pubdash is not persisted", func(t *testing.T) {
dashboard := models.NewDashboard("testDashie")
pubdash := &PublicDashboard{
IsEnabled: true,
AnnotationsEnabled: false,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
TimeSettings: timeSettings,
}
publicDashboardStore := &FakePublicDashboardStore{}
publicDashboardStore.On("GetDashboard", mock.Anything, mock.Anything).Return(dashboard, nil)
publicDashboardStore.On("GetPublicDashboardByUid", mock.Anything, mock.Anything).Return(nil, nil)
publicDashboardStore.On("GetPublicDashboardByAccessToken", mock.Anything, mock.Anything).Return(pubdash, nil)
publicDashboardStore.On("GenerateNewPublicDashboardUid", mock.Anything).Return("an-uid", nil)
publicDashboardStore.On("GenerateNewPublicDashboardAccessToken", mock.Anything).Return("", ErrPublicDashboardFailedGenerateAccessToken)
service := &PublicDashboardServiceImpl{
log: log.New("test.logger"),
@@ -782,3 +792,131 @@ func TestPublicDashboardServiceImpl_ListPublicDashboards(t *testing.T) {
})
}
}
func TestPublicDashboardServiceImpl_GenerateNewPublicDashboardUid(t *testing.T) {
mockedDashboard := &PublicDashboard{
IsEnabled: true,
AnnotationsEnabled: false,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
TimeSettings: timeSettings,
}
type args struct {
ctx context.Context
}
type mockResponse struct {
PublicDashboard *PublicDashboard
Err error
}
tests := []struct {
name string
args args
mockStore *mockResponse
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "should return a new uid",
args: args{ctx: context.Background()},
mockStore: &mockResponse{nil, nil},
want: "NOTTHESAME",
wantErr: assert.NoError,
},
{
name: "should return an error if the generated uid exists 3 times",
args: args{ctx: context.Background()},
mockStore: &mockResponse{mockedDashboard, nil},
want: "",
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
store := NewFakePublicDashboardStore(t)
store.On("GetPublicDashboardByUid", mock.Anything, mock.Anything).
Return(tt.mockStore.PublicDashboard, tt.mockStore.Err)
pd := &PublicDashboardServiceImpl{store: store}
got, err := pd.GenerateNewPublicDashboardUid(tt.args.ctx)
if !tt.wantErr(t, err, fmt.Sprintf("GenerateNewPublicDashboardUid(%v)", tt.args.ctx)) {
return
}
if err == nil {
assert.NotEqual(t, got, tt.want, "GenerateNewPublicDashboardUid(%v)", tt.args.ctx)
assert.True(t, util.IsValidShortUID(got), "GenerateNewPublicDashboardUid(%v)", tt.args.ctx)
store.AssertNumberOfCalls(t, "GetPublicDashboardByUid", 1)
} else {
store.AssertNumberOfCalls(t, "GetPublicDashboardByUid", 3)
assert.True(t, errors.Is(err, ErrPublicDashboardFailedGenerateUniqueUid))
}
})
}
}
func TestPublicDashboardServiceImpl_GenerateNewPublicDashboardAccessToken(t *testing.T) {
mockedDashboard := &PublicDashboard{
IsEnabled: true,
AnnotationsEnabled: false,
DashboardUid: "NOTTHESAME",
OrgId: 9999999,
TimeSettings: timeSettings,
}
type args struct {
ctx context.Context
}
type mockResponse struct {
PublicDashboard *PublicDashboard
Err error
}
tests := []struct {
name string
args args
mockStore *mockResponse
want string
wantErr assert.ErrorAssertionFunc
}{
{
name: "should return a new access token",
args: args{ctx: context.Background()},
mockStore: &mockResponse{nil, nil},
want: "6522e152530f4ee76522e152530f4ee7",
wantErr: assert.NoError,
},
{
name: "should return an error if the generated access token exists 3 times",
args: args{ctx: context.Background()},
mockStore: &mockResponse{mockedDashboard, nil},
want: "",
wantErr: assert.Error,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
store := NewFakePublicDashboardStore(t)
store.On("GetPublicDashboardByAccessToken", mock.Anything, mock.Anything).
Return(tt.mockStore.PublicDashboard, tt.mockStore.Err)
pd := &PublicDashboardServiceImpl{store: store}
got, err := pd.GenerateNewPublicDashboardAccessToken(tt.args.ctx)
if !tt.wantErr(t, err, fmt.Sprintf("GenerateNewPublicDashboardAccessToken(%v)", tt.args.ctx)) {
return
}
if err == nil {
assert.NotEqual(t, got, tt.want, "GenerateNewPublicDashboardAccessToken(%v)", tt.args.ctx)
assert.True(t, tokens.IsValidAccessToken(got), "GenerateNewPublicDashboardAccessToken(%v)", tt.args.ctx)
store.AssertNumberOfCalls(t, "GetPublicDashboardByAccessToken", 1)
} else {
store.AssertNumberOfCalls(t, "GetPublicDashboardByAccessToken", 3)
assert.True(t, errors.Is(err, ErrPublicDashboardFailedGenerateAccessToken))
}
})
}
}