mirror of
https://github.com/zitadel/zitadel.git
synced 2025-07-17 22:38:37 +00:00
404 lines
13 KiB
Go
404 lines
13 KiB
Go
![]() |
//go:build integration
|
||
|
|
||
|
package user_test
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"encoding/base64"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/brianvoe/gofakeit/v6"
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/zitadel/zitadel/internal/integration"
|
||
|
"github.com/zitadel/zitadel/pkg/grpc/filter/v2"
|
||
|
metadata "github.com/zitadel/zitadel/pkg/grpc/metadata/v2"
|
||
|
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||
|
)
|
||
|
|
||
|
func TestServer_SetUserMetadata(t *testing.T) {
|
||
|
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
ctx context.Context
|
||
|
dep func(request *user.SetUserMetadataRequest)
|
||
|
req *user.SetUserMetadataRequest
|
||
|
setDate bool
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "missing permission",
|
||
|
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeNoPermission),
|
||
|
dep: func(req *user.SetUserMetadataRequest) {
|
||
|
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
|
||
|
},
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
|
||
|
},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "set user metadata",
|
||
|
ctx: iamOwnerCTX,
|
||
|
dep: func(req *user.SetUserMetadataRequest) {
|
||
|
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
|
||
|
},
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
|
||
|
},
|
||
|
setDate: true,
|
||
|
},
|
||
|
{
|
||
|
name: "set user metadata, multiple",
|
||
|
ctx: iamOwnerCTX,
|
||
|
dep: func(req *user.SetUserMetadataRequest) {
|
||
|
req.UserId = Instance.CreateUserTypeHuman(CTX, gofakeit.Email()).GetId()
|
||
|
},
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
Metadata: []*user.Metadata{
|
||
|
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
|
||
|
{Key: "key2", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))},
|
||
|
{Key: "key3", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value3")))},
|
||
|
},
|
||
|
},
|
||
|
setDate: true,
|
||
|
},
|
||
|
{
|
||
|
name: "set user metadata on non existent user",
|
||
|
ctx: iamOwnerCTX,
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
UserId: "notexisting",
|
||
|
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
|
||
|
},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "update user metadata",
|
||
|
ctx: Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner),
|
||
|
dep: func(req *user.SetUserMetadataRequest) {
|
||
|
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
|
||
|
},
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))}},
|
||
|
},
|
||
|
setDate: true,
|
||
|
},
|
||
|
{
|
||
|
name: "update user metadata with same value",
|
||
|
ctx: Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner),
|
||
|
dep: func(req *user.SetUserMetadataRequest) {
|
||
|
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
|
||
|
},
|
||
|
req: &user.SetUserMetadataRequest{
|
||
|
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
|
||
|
},
|
||
|
setDate: true,
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
creationDate := time.Now().UTC()
|
||
|
if tt.dep != nil {
|
||
|
tt.dep(tt.req)
|
||
|
}
|
||
|
got, err := Client.SetUserMetadata(tt.ctx, tt.req)
|
||
|
changeDate := time.Now().UTC()
|
||
|
if tt.wantErr {
|
||
|
require.Error(t, err)
|
||
|
return
|
||
|
}
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
assertSetUserMetadataResponse(t, creationDate, changeDate, tt.setDate, got)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func assertSetUserMetadataResponse(t *testing.T, creationDate, changeDate time.Time, expectedSetDat bool, actualResp *user.SetUserMetadataResponse) {
|
||
|
if expectedSetDat {
|
||
|
if !changeDate.IsZero() {
|
||
|
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, changeDate)
|
||
|
} else {
|
||
|
assert.WithinRange(t, actualResp.GetSetDate().AsTime(), creationDate, time.Now().UTC())
|
||
|
}
|
||
|
} else {
|
||
|
assert.Nil(t, actualResp.SetDate)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestServer_ListUserMetadata(t *testing.T) {
|
||
|
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||
|
|
||
|
type args struct {
|
||
|
ctx context.Context
|
||
|
dep func(context.Context, *user.ListUserMetadataRequest, *user.ListUserMetadataResponse)
|
||
|
req *user.ListUserMetadataRequest
|
||
|
}
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
args args
|
||
|
want *user.ListUserMetadataResponse
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "missing permission",
|
||
|
args: args{
|
||
|
ctx: Instance.WithAuthorization(context.Background(), integration.UserTypeNoPermission),
|
||
|
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
|
||
|
},
|
||
|
req: &user.ListUserMetadataRequest{},
|
||
|
},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "list request",
|
||
|
args: args{
|
||
|
ctx: iamOwnerCTX,
|
||
|
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
metadataResp := Instance.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
|
||
|
|
||
|
response.Metadata[0] = &metadata.Metadata{
|
||
|
CreationDate: metadataResp.GetSetDate(),
|
||
|
ChangeDate: metadataResp.GetSetDate(),
|
||
|
Key: "key1",
|
||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1"))),
|
||
|
}
|
||
|
},
|
||
|
req: &user.ListUserMetadataRequest{},
|
||
|
},
|
||
|
want: &user.ListUserMetadataResponse{
|
||
|
Pagination: &filter.PaginationResponse{
|
||
|
TotalResult: 1,
|
||
|
AppliedLimit: 100,
|
||
|
},
|
||
|
Metadata: []*metadata.Metadata{
|
||
|
{},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "list request single key",
|
||
|
args: args{
|
||
|
ctx: iamOwnerCTX,
|
||
|
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
key := "key1"
|
||
|
response.Metadata[0] = setUserMetadata(iamOwnerCTX, userID, key, "value1")
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, "key2", "value2")
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, "key3", "value3")
|
||
|
request.Filters[0] = &metadata.MetadataSearchFilter{
|
||
|
Filter: &metadata.MetadataSearchFilter_KeyFilter{KeyFilter: &metadata.MetadataKeyFilter{Key: key}},
|
||
|
}
|
||
|
},
|
||
|
req: &user.ListUserMetadataRequest{
|
||
|
Filters: []*metadata.MetadataSearchFilter{{}},
|
||
|
},
|
||
|
},
|
||
|
want: &user.ListUserMetadataResponse{
|
||
|
Pagination: &filter.PaginationResponse{
|
||
|
TotalResult: 1,
|
||
|
AppliedLimit: 100,
|
||
|
},
|
||
|
Metadata: []*metadata.Metadata{
|
||
|
{},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
{
|
||
|
name: "list multiple keys",
|
||
|
args: args{
|
||
|
ctx: iamOwnerCTX,
|
||
|
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
|
||
|
response.Metadata[2] = setUserMetadata(iamOwnerCTX, userID, "key1", "value1")
|
||
|
response.Metadata[1] = setUserMetadata(iamOwnerCTX, userID, "key2", "value2")
|
||
|
response.Metadata[0] = setUserMetadata(iamOwnerCTX, userID, "key3", "value3")
|
||
|
},
|
||
|
req: &user.ListUserMetadataRequest{},
|
||
|
},
|
||
|
want: &user.ListUserMetadataResponse{
|
||
|
Pagination: &filter.PaginationResponse{
|
||
|
TotalResult: 3,
|
||
|
AppliedLimit: 100,
|
||
|
},
|
||
|
Metadata: []*metadata.Metadata{
|
||
|
{}, {}, {},
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
if tt.args.dep != nil {
|
||
|
tt.args.dep(tt.args.ctx, tt.args.req, tt.want)
|
||
|
}
|
||
|
|
||
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(iamOwnerCTX, time.Minute)
|
||
|
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||
|
got, listErr := Instance.Client.UserV2.ListUserMetadata(tt.args.ctx, tt.args.req)
|
||
|
if tt.wantErr {
|
||
|
require.Error(ttt, listErr)
|
||
|
return
|
||
|
}
|
||
|
require.NoError(ttt, listErr)
|
||
|
// always first check length, otherwise its failed anyway
|
||
|
if assert.Len(ttt, got.Metadata, len(tt.want.Metadata)) {
|
||
|
assert.EqualExportedValues(ttt, got.Metadata, tt.want.Metadata)
|
||
|
}
|
||
|
assertPaginationResponse(ttt, tt.want.Pagination, got.Pagination)
|
||
|
}, retryDuration, tick, "timeout waiting for expected execution result")
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func setUserMetadata(ctx context.Context, userID, key, value string) *metadata.Metadata {
|
||
|
metadataResp := Instance.SetUserMetadata(ctx, userID, key, value)
|
||
|
return &metadata.Metadata{
|
||
|
CreationDate: metadataResp.GetSetDate(),
|
||
|
ChangeDate: metadataResp.GetSetDate(),
|
||
|
Key: key,
|
||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte(value))),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func assertPaginationResponse(t *assert.CollectT, expected *filter.PaginationResponse, actual *filter.PaginationResponse) {
|
||
|
assert.Equal(t, expected.AppliedLimit, actual.AppliedLimit)
|
||
|
assert.Equal(t, expected.TotalResult, actual.TotalResult)
|
||
|
}
|
||
|
|
||
|
func TestServer_DeleteUserMetadata(t *testing.T) {
|
||
|
iamOwnerCTX := Instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||
|
|
||
|
tests := []struct {
|
||
|
name string
|
||
|
ctx context.Context
|
||
|
prepare func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time)
|
||
|
req *user.DeleteUserMetadataRequest
|
||
|
wantDeletionDate bool
|
||
|
wantErr bool
|
||
|
}{
|
||
|
{
|
||
|
name: "empty id",
|
||
|
ctx: iamOwnerCTX,
|
||
|
req: &user.DeleteUserMetadataRequest{
|
||
|
UserId: "",
|
||
|
},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "delete, user not existing",
|
||
|
ctx: iamOwnerCTX,
|
||
|
req: &user.DeleteUserMetadataRequest{
|
||
|
UserId: "notexisting",
|
||
|
},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "delete",
|
||
|
ctx: iamOwnerCTX,
|
||
|
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
|
||
|
creationDate := time.Now().UTC()
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
key := "key1"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
|
||
|
request.Keys = []string{key}
|
||
|
return creationDate, time.Time{}
|
||
|
},
|
||
|
req: &user.DeleteUserMetadataRequest{},
|
||
|
wantDeletionDate: true,
|
||
|
},
|
||
|
{
|
||
|
name: "delete, empty list",
|
||
|
ctx: iamOwnerCTX,
|
||
|
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
|
||
|
creationDate := time.Now().UTC()
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
key := "key1"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
|
||
|
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
|
||
|
return creationDate, time.Now().UTC()
|
||
|
},
|
||
|
req: &user.DeleteUserMetadataRequest{},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "delete, already removed",
|
||
|
ctx: iamOwnerCTX,
|
||
|
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
|
||
|
creationDate := time.Now().UTC()
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
key := "key1"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
|
||
|
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
|
||
|
request.Keys = []string{key}
|
||
|
return creationDate, time.Now().UTC()
|
||
|
},
|
||
|
req: &user.DeleteUserMetadataRequest{},
|
||
|
wantErr: true,
|
||
|
},
|
||
|
{
|
||
|
name: "delete, multiple",
|
||
|
ctx: iamOwnerCTX,
|
||
|
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
|
||
|
creationDate := time.Now().UTC()
|
||
|
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, gofakeit.Email()).GetId()
|
||
|
request.UserId = userID
|
||
|
key1 := "key1"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key1, "value1")
|
||
|
key2 := "key2"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key2, "value1")
|
||
|
key3 := "key3"
|
||
|
Instance.SetUserMetadata(iamOwnerCTX, userID, key3, "value1")
|
||
|
request.Keys = []string{key1, key2, key3}
|
||
|
return creationDate, time.Time{}
|
||
|
},
|
||
|
req: &user.DeleteUserMetadataRequest{},
|
||
|
wantDeletionDate: true,
|
||
|
},
|
||
|
}
|
||
|
for _, tt := range tests {
|
||
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
var creationDate, deletionDate time.Time
|
||
|
if tt.prepare != nil {
|
||
|
creationDate, deletionDate = tt.prepare(tt.req)
|
||
|
}
|
||
|
got, err := Instance.Client.UserV2.DeleteUserMetadata(tt.ctx, tt.req)
|
||
|
if tt.wantErr {
|
||
|
assert.Error(t, err)
|
||
|
return
|
||
|
}
|
||
|
assert.NoError(t, err)
|
||
|
assertDeleteProjectResponse(t, creationDate, deletionDate, tt.wantDeletionDate, got)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func assertDeleteProjectResponse(t *testing.T, creationDate, deletionDate time.Time, expectedDeletionDate bool, actualResp *user.DeleteUserMetadataResponse) {
|
||
|
if expectedDeletionDate {
|
||
|
if !deletionDate.IsZero() {
|
||
|
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), creationDate, deletionDate)
|
||
|
} else {
|
||
|
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), creationDate, time.Now().UTC())
|
||
|
}
|
||
|
} else {
|
||
|
assert.Nil(t, actualResp.DeletionDate)
|
||
|
}
|
||
|
}
|