unified-storage: Reduce calls to the user service (#102934)

* Create ListByIdOrUID in user service

* create UnstructuredToLegacyFolderList 

* update GetFolders to use list parser

* update GetDescendants to use list parser

* update UnstructuredToLegacyFolder to also make a single call to the user service

---------

Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
Will Assis
2025-03-27 22:01:07 +02:00
committed by GitHub
co-authored by Stephanie Hingtgen
parent 7e3efb3df2
commit 51825cfffe
13 changed files with 643 additions and 63 deletions
+105 -3
View File
@@ -3,9 +3,12 @@ package userimpl
import (
"context"
"fmt"
"sort"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -848,6 +851,105 @@ func TestIntegrationUserDataAccess(t *testing.T) {
assert.Equal(t, queryResult.OrgName, "user1@test.com")
assert.Equal(t, queryResult.IsGrafanaAdmin, false)
})
t.Run("Can get users by UID list", func(t *testing.T) {
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
return &user.CreateUserCommand{
Email: fmt.Sprint("USERLISTUIDTEST", i, "@test.com"),
Name: fmt.Sprint("USERLISTUIDTEST", i),
Login: fmt.Sprint("loginUSERLISTUIDTEST", i),
IsDisabled: false,
}
})
sort.Slice(users, func(i, j int) bool {
return users[i].ID < users[j].ID
})
alluids := make([]string, 0, 5)
for _, user := range users {
alluids = append(alluids, user.UID)
}
resultOnlyUIDs, err := userStore.ListByIdOrUID(context.Background(), alluids, []int64{})
require.NoError(t, err)
sort.Slice(resultOnlyUIDs, func(i, j int) bool {
return resultOnlyUIDs[i].ID < resultOnlyUIDs[j].ID
})
require.Equal(t, len(resultOnlyUIDs), len(users))
ignoreTimeFields := cmpopts.IgnoreFields(user.User{}, "Created", "Updated", "LastSeenAt")
if diff := cmp.Diff(users, resultOnlyUIDs, ignoreTimeFields); diff != "" {
t.Errorf("structs don't match (-want +got):\n%s", diff)
}
})
t.Run("Can get users by ID list", func(t *testing.T) {
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
return &user.CreateUserCommand{
Email: fmt.Sprint("USERLISTIDTEST", i, "@test.com"),
Name: fmt.Sprint("USERLISTIDTEST", i),
Login: fmt.Sprint("loginUSERLISTIDTEST", i),
IsDisabled: false,
}
})
sort.Slice(users, func(i, j int) bool {
return users[i].ID < users[j].ID
})
allids := make([]int64, 0, 5)
for _, user := range users {
allids = append(allids, user.ID)
}
resultOnlyIDs, err := userStore.ListByIdOrUID(context.Background(), []string{}, allids)
require.NoError(t, err)
sort.Slice(resultOnlyIDs, func(i, j int) bool {
return resultOnlyIDs[i].ID < resultOnlyIDs[j].ID
})
ignoreTimeFields := cmpopts.IgnoreFields(user.User{}, "Created", "Updated", "LastSeenAt")
if diff := cmp.Diff(users, resultOnlyIDs, ignoreTimeFields); diff != "" {
t.Errorf("structs don't match (-want +got):\n%s", diff)
}
})
t.Run("Can get users by UID and ID list", func(t *testing.T) {
users := createFiveTestUsers(t, usrSvc, func(i int) *user.CreateUserCommand {
return &user.CreateUserCommand{
Email: fmt.Sprint("USERLISTUIDANDIDTEST", i, "@test.com"),
Name: fmt.Sprint("USERLISTUIDANDIDTEST", i),
Login: fmt.Sprint("loginUSERLISTUIDANDIDTEST", i),
IsDisabled: false,
}
})
sort.Slice(users, func(i, j int) bool {
return users[i].ID < users[j].ID
})
ids := make([]int64, 0, 2)
uids := make([]string, 0, 3)
for i, user := range users {
if i < 2 {
ids = append(ids, user.ID)
} else {
uids = append(uids, user.UID)
}
}
resultOnlyIDs, err := userStore.ListByIdOrUID(context.Background(), uids, ids)
require.NoError(t, err)
sort.Slice(resultOnlyIDs, func(i, j int) bool {
return resultOnlyIDs[i].ID < resultOnlyIDs[j].ID
})
ignoreTimeFields := cmpopts.IgnoreFields(user.User{}, "Created", "Updated", "LastSeenAt")
if diff := cmp.Diff(users, resultOnlyIDs, ignoreTimeFields); diff != "" {
t.Errorf("structs don't match (-want +got):\n%s", diff)
}
})
}
func TestIntegrationUserUpdate(t *testing.T) {
@@ -905,15 +1007,15 @@ func TestIntegrationUserUpdate(t *testing.T) {
})
}
func createFiveTestUsers(t *testing.T, svc user.Service, fn func(i int) *user.CreateUserCommand) []user.User {
func createFiveTestUsers(t *testing.T, svc user.Service, fn func(i int) *user.CreateUserCommand) []*user.User {
t.Helper()
users := make([]user.User, 5)
users := make([]*user.User, 5)
for i := 0; i < 5; i++ {
cmd := fn(i)
user, err := svc.Create(context.Background(), cmd)
require.Nil(t, err)
users[i] = *user
users[i] = user
}
return users