grafana/pkg/services/folder/folderimpl/sqlstore_test.go
Sofia Papagiannaki 9855e74b92
Chore: Refactor quota service (#58643)
Chore: Refactor quota service (#57586)

* Chore: refactore quota service

* Apply suggestions from code review
2022-11-14 21:08:10 +02:00

681 lines
19 KiB
Go

package folderimpl
import (
"context"
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/util"
)
func TestIntegrationCreate(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
t.Run("creating a folder without providing a UID should fail", func(t *testing.T) {
_, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "folder1",
Description: "folder desc",
OrgID: orgID,
})
require.Error(t, err)
})
t.Run("creating a folder with unknown parent should fail", func(t *testing.T) {
_, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "folder1",
OrgID: orgID,
ParentUID: "unknown",
Description: "folder desc",
UID: util.GenerateShortUID(),
})
require.Error(t, err)
})
t.Run("creating a folder without providing a parent should default to the general folder", func(t *testing.T) {
uid := util.GenerateShortUID()
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "folder1",
Description: "folder desc",
OrgID: orgID,
UID: uid,
})
require.NoError(t, err)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), f.UID, orgID)
require.NoError(t, err)
})
assert.Equal(t, "folder1", f.Title)
assert.Equal(t, "folder desc", f.Description)
assert.NotEmpty(t, f.ID)
assert.Equal(t, uid, f.UID)
assert.Equal(t, folder.GeneralFolderUID, f.ParentUID)
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &f.UID,
OrgID: orgID,
})
assert.NoError(t, err)
assert.Equal(t, "folder1", ff.Title)
assert.Equal(t, "folder desc", ff.Description)
assert.Equal(t, accesscontrol.GeneralFolderUID, ff.ParentUID)
assertAncestorUIDs(t, folderStore, f, []string{folder.GeneralFolderUID})
})
t.Run("creating a folder with a known parent should succeed", func(t *testing.T) {
parentUID := util.GenerateShortUID()
parent, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "parent",
OrgID: orgID,
UID: parentUID,
})
require.NoError(t, err)
require.Equal(t, "parent", parent.Title)
require.NotEmpty(t, parent.ID)
assert.Equal(t, parentUID, parent.UID)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), parent.UID, orgID)
require.NoError(t, err)
})
assertAncestorUIDs(t, folderStore, parent, []string{folder.GeneralFolderUID})
uid := util.GenerateShortUID()
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "folder1",
OrgID: orgID,
ParentUID: parent.UID,
Description: "folder desc",
UID: uid,
})
require.NoError(t, err)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), f.UID, orgID)
require.NoError(t, err)
})
assert.Equal(t, "folder1", f.Title)
assert.Equal(t, "folder desc", f.Description)
assert.NotEmpty(t, f.ID)
assert.Equal(t, uid, f.UID)
assert.Equal(t, parentUID, f.ParentUID)
assertAncestorUIDs(t, folderStore, f, []string{folder.GeneralFolderUID, parent.UID})
assertChildrenUIDs(t, folderStore, parent, []string{f.UID})
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &f.UID,
OrgID: f.OrgID,
})
assert.NoError(t, err)
assert.Equal(t, "folder1", ff.Title)
assert.Equal(t, "folder desc", ff.Description)
assert.Equal(t, parentUID, ff.ParentUID)
})
/*
t.Run("creating a nested folder with the maximum nested folder depth should fail", func(t *testing.T) {
ancestorUIDs := createSubTree(t, folderStore, orgID, accesscontrol.GeneralFolderUID, folder.MaxNestedFolderDepth, "")
t.Cleanup(func() {
for _, uid := range ancestorUIDs[1:] {
err := folderStore.Delete(context.Background(), uid, orgID)
require.NoError(t, err)
}
})
title := fmt.Sprintf("folder-%d", len(ancestorUIDs))
_, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: "folder1",
OrgID: orgID,
ParentUID: ancestorUIDs[len(ancestorUIDs)-1],
UID: util.GenerateShortUID(),
})
assert.Error(t, err)
})
*/
}
func TestIntegrationDelete(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
/*
t.Run("attempt to delete unknown folder should fail", func(t *testing.T) {
err := folderSrore.Delete(context.Background(), "unknown", orgID)
assert.Error(t, err)
})
*/
ancestorUIDs := CreateSubTree(t, folderStore, orgID, accesscontrol.GeneralFolderUID, folder.MaxNestedFolderDepth, "")
require.Len(t, ancestorUIDs, folder.MaxNestedFolderDepth+1)
t.Cleanup(func() {
for _, uid := range ancestorUIDs[1:] {
err := folderStore.Delete(context.Background(), uid, orgID)
require.NoError(t, err)
}
})
/*
t.Run("deleting folder with children should fail", func(t *testing.T) {
err = folderSrore.Delete(context.Background(), ancestorUIDs[2], orgID)
require.Error(t, err)
})
*/
t.Run("deleting a leaf folder should succeed", func(t *testing.T) {
err := folderStore.Delete(context.Background(), ancestorUIDs[len(ancestorUIDs)-1], orgID)
require.NoError(t, err)
children, err := folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: ancestorUIDs[len(ancestorUIDs)-2],
OrgID: orgID,
})
require.NoError(t, err)
assert.Len(t, children, 0)
})
}
func TestIntegrationUpdate(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
// create folder
origTitle := "folder1"
origDesc := "folder desc"
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: origTitle,
Description: origDesc,
OrgID: orgID,
UID: util.GenerateShortUID(),
})
require.NoError(t, err)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), f.UID, orgID)
require.NoError(t, err)
})
/*
t.Run("updating an unknown folder should fail", func(t *testing.T) {
newTitle := "new title"
newDesc := "new desc"
_, err := folderSrore.Update(context.Background(), &folder.UpdateFolderCommand{
Folder: f,
NewTitle: &newTitle,
NewDescription: &newDesc,
})
require.NoError(t, err)
ff, err := folderSrore.Get(context.Background(), &folder.GetFolderQuery{
UID: &f.UID,
})
require.NoError(t, err)
assert.Equal(t, origTitle, ff.Title)
assert.Equal(t, origDesc, ff.Description)
})
*/
t.Run("should not panic in case of bad requests", func(t *testing.T) {
_, err = folderStore.Update(context.Background(), folder.UpdateFolderCommand{})
require.Error(t, err)
_, err = folderStore.Update(context.Background(), folder.UpdateFolderCommand{
Folder: &folder.Folder{},
})
require.Error(t, err)
})
t.Run("updating a folder should succeed", func(t *testing.T) {
newTitle := "new title"
newDesc := "new desc"
existingUpdated := f.Updated
updated, err := folderStore.Update(context.Background(), folder.UpdateFolderCommand{
Folder: f,
NewTitle: &newTitle,
NewDescription: &newDesc,
})
require.NoError(t, err)
assert.Equal(t, f.UID, updated.UID)
assert.Equal(t, newTitle, updated.Title)
assert.Equal(t, newDesc, updated.Description)
assert.Greater(t, updated.Updated.UnixNano(), existingUpdated.UnixNano())
updated, err = folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &updated.UID,
OrgID: orgID,
})
require.NoError(t, err)
assert.Equal(t, newTitle, updated.Title)
assert.Equal(t, newDesc, updated.Description)
})
t.Run("updating folder UID should succeed", func(t *testing.T) {
newUID := "new"
existingTitle := f.Title
existingDesc := f.Description
updated, err := folderStore.Update(context.Background(), folder.UpdateFolderCommand{
Folder: f,
NewUID: &newUID,
})
require.NoError(t, err)
assert.Equal(t, newUID, updated.UID)
updated, err = folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &updated.UID,
OrgID: orgID,
})
require.NoError(t, err)
assert.Equal(t, newUID, updated.UID)
assert.Equal(t, existingTitle, updated.Title)
assert.Equal(t, existingDesc, updated.Description)
})
}
func TestIntegrationGet(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
// create folder
title1 := "folder1"
desc1 := "folder desc"
uid1 := util.GenerateShortUID()
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: title1,
Description: desc1,
OrgID: orgID,
UID: uid1,
})
require.NoError(t, err)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), f.UID, orgID)
require.NoError(t, err)
})
t.Run("should gently fail in case of bad request", func(t *testing.T) {
_, err = folderStore.Get(context.Background(), folder.GetFolderQuery{})
require.Error(t, err)
})
t.Run("get folder by UID should succeed", func(t *testing.T) {
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
UID: &f.UID,
OrgID: orgID,
})
require.NoError(t, err)
assert.Equal(t, f.ID, ff.ID)
assert.Equal(t, f.UID, ff.UID)
assert.Equal(t, f.OrgID, ff.OrgID)
assert.Equal(t, f.Title, ff.Title)
assert.Equal(t, f.Description, ff.Description)
//assert.Equal(t, folder.GeneralFolderUID, ff.ParentUID)
assert.NotEmpty(t, ff.Created)
assert.NotEmpty(t, ff.Updated)
})
t.Run("get folder by title should succeed", func(t *testing.T) {
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
Title: &f.Title,
OrgID: orgID,
})
require.NoError(t, err)
assert.Equal(t, f.ID, ff.ID)
assert.Equal(t, f.UID, ff.UID)
assert.Equal(t, f.OrgID, ff.OrgID)
assert.Equal(t, f.Title, ff.Title)
assert.Equal(t, f.Description, ff.Description)
//assert.Equal(t, folder.GeneralFolderUID, ff.ParentUID)
assert.NotEmpty(t, ff.Created)
assert.NotEmpty(t, ff.Updated)
})
t.Run("get folder by title should succeed", func(t *testing.T) {
ff, err := folderStore.Get(context.Background(), folder.GetFolderQuery{
ID: &f.ID,
})
require.NoError(t, err)
assert.Equal(t, f.ID, ff.ID)
assert.Equal(t, f.UID, ff.UID)
assert.Equal(t, f.OrgID, ff.OrgID)
assert.Equal(t, f.Title, ff.Title)
assert.Equal(t, f.Description, ff.Description)
//assert.Equal(t, folder.GeneralFolderUID, ff.ParentUID)
assert.NotEmpty(t, ff.Created)
assert.NotEmpty(t, ff.Updated)
})
}
func TestIntegrationGetParents(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
// create folder
title1 := "folder1"
desc1 := "folder desc"
uid1 := util.GenerateShortUID()
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: title1,
Description: desc1,
OrgID: orgID,
UID: uid1,
})
require.NoError(t, err)
t.Cleanup(func() {
err := folderStore.Delete(context.Background(), f.UID, orgID)
require.NoError(t, err)
})
t.Run("get parents of 1-st level folder should be empty", func(t *testing.T) {
parents, err := folderStore.GetParents(context.Background(), folder.GetParentsQuery{
UID: f.UID,
OrgID: orgID,
})
require.NoError(t, err)
require.Empty(t, parents)
})
t.Run("get parents of 2-st level folder should not be empty", func(t *testing.T) {
title2 := "folder2"
desc2 := "folder2 desc"
uid2 := util.GenerateShortUID()
f, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: title2,
Description: desc2,
OrgID: orgID,
UID: uid2,
ParentUID: f.UID,
})
require.NoError(t, err)
parents, err := folderStore.GetParents(context.Background(), folder.GetParentsQuery{
UID: f.UID,
OrgID: orgID,
})
require.NoError(t, err)
parentUIDs := make([]string, 0)
for _, p := range parents {
parentUIDs = append(parentUIDs, p.UID)
}
require.Equal(t, []string{uid1}, parentUIDs)
})
}
func TestIntegrationGetChildren(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Skip("skipping until folder migration is merged")
db := sqlstore.InitTestDB(t)
folderStore := ProvideStore(db, db.Cfg, &featuremgmt.FeatureManager{})
orgID := CreateOrg(t, db)
// create folder
title1 := "folder1"
desc1 := "folder desc"
uid1 := util.GenerateShortUID()
parent, err := folderStore.Create(context.Background(), folder.CreateFolderCommand{
Title: title1,
Description: desc1,
OrgID: orgID,
UID: uid1,
})
require.NoError(t, err)
treeLeaves := CreateLeaves(t, folderStore, parent, 4)
t.Cleanup(func() {
for _, uid := range treeLeaves {
err := folderStore.Delete(context.Background(), uid, orgID)
require.NoError(t, err)
}
})
/*
t.Run("should gently fail in case of bad request", func(t *testing.T) {
_, err := folderStore.GetChildren(context.Background(), folder.GetTreeQuery{})
require.Error(t, err)
})
*/
t.Run("should successfully get all children", func(t *testing.T) {
children, err := folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: parent.UID,
OrgID: orgID,
})
require.NoError(t, err)
childrenUIDs := make([]string, 0, len(children))
for _, c := range children {
childrenUIDs = append(childrenUIDs, c.UID)
}
if diff := cmp.Diff(treeLeaves, childrenUIDs); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
})
t.Run("query with pagination should work as expected", func(t *testing.T) {
children, err := folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: parent.UID,
OrgID: orgID,
Limit: 1,
Page: 1,
})
require.NoError(t, err)
childrenUIDs := make([]string, 0, len(children))
for _, c := range children {
childrenUIDs = append(childrenUIDs, c.UID)
}
if diff := cmp.Diff(treeLeaves[1:2], childrenUIDs); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
children, err = folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: parent.UID,
OrgID: orgID,
Limit: 1,
Page: 2,
})
require.NoError(t, err)
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
childrenUIDs = append(childrenUIDs, c.UID)
}
if diff := cmp.Diff(treeLeaves[2:3], childrenUIDs); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
// no page is set
children, err = folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: parent.UID,
OrgID: orgID,
Limit: 1,
})
require.NoError(t, err)
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
childrenUIDs = append(childrenUIDs, c.UID)
}
if diff := cmp.Diff(treeLeaves[1:2], childrenUIDs); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
// page is set but limit is not set, it should return them all
children, err = folderStore.GetChildren(context.Background(), folder.GetTreeQuery{
UID: parent.UID,
OrgID: orgID,
Page: 1,
})
require.NoError(t, err)
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
childrenUIDs = append(childrenUIDs, c.UID)
}
if diff := cmp.Diff(treeLeaves, childrenUIDs); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
})
}
func CreateOrg(t *testing.T, db *sqlstore.SQLStore) int64 {
t.Helper()
orgService, err := orgimpl.ProvideService(db, db.Cfg, quotatest.New(false, nil))
require.NoError(t, err)
orgID, err := orgService.GetOrCreate(context.Background(), "test-org")
require.NoError(t, err)
t.Cleanup(func() {
err = orgService.Delete(context.Background(), &org.DeleteOrgCommand{ID: orgID})
require.NoError(t, err)
})
return orgID
}
func CreateSubTree(t *testing.T, store *sqlStore, orgID int64, parentUID string, depth int, prefix string) []string {
t.Helper()
ancestorUIDs := []string{parentUID}
for i := 0; i < depth; i++ {
parentUID := ancestorUIDs[len(ancestorUIDs)-1]
title := fmt.Sprintf("%sfolder-%d", prefix, i)
f, err := store.Create(context.Background(), folder.CreateFolderCommand{
Title: title,
OrgID: orgID,
ParentUID: parentUID,
UID: util.GenerateShortUID(),
})
require.NoError(t, err)
require.Equal(t, title, f.Title)
require.NotEmpty(t, f.ID)
require.NotEmpty(t, f.UID)
parents, err := store.GetParents(context.Background(), folder.GetParentsQuery{
UID: f.UID,
OrgID: orgID,
})
require.NoError(t, err)
parentUIDs := []string{folder.GeneralFolderUID}
for _, p := range parents {
parentUIDs = append(parentUIDs, p.UID)
}
require.Equal(t, ancestorUIDs, parentUIDs)
ancestorUIDs = append(ancestorUIDs, f.UID)
}
return ancestorUIDs
}
func CreateLeaves(t *testing.T, store *sqlStore, parent *folder.Folder, num int) []string {
t.Helper()
leaves := make([]string, 0)
for i := 0; i < num; i++ {
f, err := store.Create(context.Background(), folder.CreateFolderCommand{
Title: fmt.Sprintf("folder-%d", i),
UID: util.GenerateShortUID(),
OrgID: parent.OrgID,
ParentUID: parent.UID,
})
require.NoError(t, err)
leaves = append(leaves, f.UID)
}
return leaves
}
func assertAncestorUIDs(t *testing.T, store *sqlStore, f *folder.Folder, expected []string) {
t.Helper()
ancestors, err := store.GetParents(context.Background(), folder.GetParentsQuery{
UID: f.UID,
OrgID: f.OrgID,
})
require.NoError(t, err)
actualAncestorsUIDs := []string{folder.GeneralFolderUID}
for _, f := range ancestors {
actualAncestorsUIDs = append(actualAncestorsUIDs, f.UID)
}
assert.Equal(t, expected, actualAncestorsUIDs)
}
func assertChildrenUIDs(t *testing.T, store *sqlStore, f *folder.Folder, expected []string) {
t.Helper()
ancestors, err := store.GetChildren(context.Background(), folder.GetTreeQuery{
UID: f.UID,
OrgID: f.OrgID,
})
require.NoError(t, err)
actualChildrenUIDs := make([]string, 0)
for _, f := range ancestors {
actualChildrenUIDs = append(actualChildrenUIDs, f.UID)
}
assert.Equal(t, expected, actualChildrenUIDs)
}