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
@@ -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
}
@@ -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))
}
})
}
}