Files
zitadel/internal/api/grpc/user/v2/integration_test/metadata_test.go
T
62cb5bbb83 feat: delete metadata on SetOrganizationMetadata api (#11790)
# Which Problems Are Solved

Currently, to delete an Organization metadata key, callers must use a
separate
[DeleteMetadata](https://zitadel.com/docs/reference/api/org/zitadel.org.v2.OrganizationService.DeleteOrganizationMetadata)
API. This increases the complexity on client-side for operations where
metadata need to be synchronized.

# How the Problems Are Solved

Introduce deletion behavior to
[SetOrganizationMetadata](https://zitadel.com/docs/reference/api/org/zitadel.org.v2.OrganizationService.SetOrganizationMetadata):

When a metadata entry is passed with an empty value ("" / empty bytes):

- If the key exists → delete the key
- If the key does not exist → no-op (idempotent, no error)

# Additional Changes

n/a

# Additional Context

Relates to #11776

---------

Co-authored-by: Gayathri Vijayan <[email protected]>
Co-authored-by: Gayathri Vijayan <[email protected]>
2026-03-10 10:09:51 +00:00

624 lines
23 KiB
Go

//go:build integration
package user_test
import (
"context"
"encoding/base64"
"testing"
"time"
"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.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner)
tests := []struct {
name string
ctx context.Context
dep func(request *user.SetUserMetadataRequest)
req *user.SetUserMetadataRequest
assert func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse)
wantErr bool
}{
{
name: "missing permission",
ctx: Instance.WithAuthorizationToken(context.Background(), integration.UserTypeNoPermission),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(OrgCTX, integration.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(OrgCTX, integration.Email()).GetId()
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
assert.WithinRange(t, setResponse.GetSetDate().AsTime(), testStartTime, time.Now().UTC())
expectedMetadata := []*metadata.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
{
name: "set user metadata, multiple",
ctx: iamOwnerCTX,
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(OrgCTX, integration.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")))},
},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
assert.WithinRange(t, setResponse.GetSetDate().AsTime(), testStartTime, time.Now().UTC())
expectedMetadata := []*metadata.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")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
{
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.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))}},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
assert.WithinRange(t, setResponse.GetSetDate().AsTime(), testStartTime, time.Now().UTC())
expectedMetadata := []*metadata.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value2")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
{
name: "update user metadata with same value",
ctx: Instance.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))}},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
// assert that the set date is not updated, i.e., it is before testStartTime, because no change to the metadata should be made
assert.True(t, setResponse.GetSetDate().AsTime().Before(testStartTime))
expectedMetadata := []*metadata.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
{
name: "delete user metadata",
ctx: Instance.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{{Key: "key1", Value: nil}},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
assert.WithinRange(t, setResponse.GetSetDate().AsTime(), testStartTime, time.Now().UTC())
assert.Len(t, getResponse.GetMetadata(), 0)
},
},
{
name: "delete non-existent user metadata key is noop",
ctx: Instance.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{
{Key: "key2", Value: nil}, // delete non-existent key; should be a no-op
},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
// assert that the set date is not updated, i.e., it is before testStartTime, because no change to the metadata should be made
assert.True(t, setResponse.GetSetDate().AsTime().Before(testStartTime))
expectedMetadata := []*metadata.Metadata{
{Key: "key1", Value: []byte(base64.StdEncoding.EncodeToString([]byte("value1")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
{
name: "update and delete user metadata",
ctx: Instance.WithAuthorizationToken(OrgCTX, integration.UserTypeIAMOwner),
dep: func(req *user.SetUserMetadataRequest) {
req.UserId = Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key1", "value1")
Instance.SetUserMetadata(iamOwnerCTX, req.UserId, "key2", "value2")
},
req: &user.SetUserMetadataRequest{
Metadata: []*user.Metadata{
{Key: "key1", Value: nil}, // delete
{Key: "key2", Value: []byte(base64.StdEncoding.EncodeToString([]byte("updated")))},
},
},
assert: func(t *testing.T, setResponse *user.SetUserMetadataResponse, testStartTime time.Time, getResponse *user.ListUserMetadataResponse) {
assert.WithinRange(t, setResponse.GetSetDate().AsTime(), testStartTime, time.Now().UTC())
expectedMetadata := []*metadata.Metadata{
{Key: "key2", Value: []byte(base64.StdEncoding.EncodeToString([]byte("updated")))},
}
integration.AssertMetadataEquals(t, expectedMetadata, getResponse.GetMetadata())
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.dep != nil {
tt.dep(tt.req)
}
testStartTime := time.Now().UTC()
got, err := Client.SetUserMetadata(tt.ctx, tt.req)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
Instance.TriggerUserByID(tt.ctx, tt.req.GetUserId())
gotMetadataResponse, err := Client.ListUserMetadata(tt.ctx, &user.ListUserMetadataRequest{
UserId: tt.req.GetUserId(),
})
require.NoError(t, err)
tt.assert(t, got, testStartTime, gotMetadataResponse)
})
}
}
func TestServer_ListUserMetadata(t *testing.T) {
iamOwnerCTX := Instance.WithAuthorizationToken(OrgCTX, 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
}{
{
name: "missing permission, actual TotalResult count returned",
args: args{
ctx: Instance.WithAuthorizationToken(context.Background(), integration.UserTypeNoPermission),
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
Instance.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
},
req: &user.ListUserMetadataRequest{},
},
want: &user.ListUserMetadataResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 1,
AppliedLimit: 100,
},
},
},
{
name: "list request",
args: args{
ctx: iamOwnerCTX,
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.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, integration.Email()).GetId()
request.UserId = userID
key := "key1"
response.Metadata[0] = setUserMetadata(iamOwnerCTX, Instance, 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, integration.Email()).GetId()
request.UserId = userID
response.Metadata[2] = setUserMetadata(iamOwnerCTX, Instance, userID, "key1", "value1")
response.Metadata[1] = setUserMetadata(iamOwnerCTX, Instance, userID, "key2", "value2")
response.Metadata[0] = setUserMetadata(iamOwnerCTX, Instance, 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)
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 TestServer_ListUserMetadata_WithPermissionV2(t *testing.T) {
ensureFeaturePermissionV2Enabled(t, InstancePermissionV2)
iamOwnerCTX := InstancePermissionV2.WithAuthorizationToken(OrgCTX, 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
}{
{
name: "missing permission, TotalResult set to 0",
args: args{
ctx: InstancePermissionV2.WithAuthorizationToken(context.Background(), integration.UserTypeNoPermission),
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := InstancePermissionV2.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
InstancePermissionV2.SetUserMetadata(iamOwnerCTX, userID, "key1", "value1")
},
req: &user.ListUserMetadataRequest{},
},
want: &user.ListUserMetadataResponse{
Pagination: &filter.PaginationResponse{
TotalResult: 0,
AppliedLimit: 100,
},
},
},
{
name: "list request",
args: args{
ctx: iamOwnerCTX,
dep: func(ctx context.Context, request *user.ListUserMetadataRequest, response *user.ListUserMetadataResponse) {
userID := InstancePermissionV2.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
metadataResp := InstancePermissionV2.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 := InstancePermissionV2.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
key := "key1"
response.Metadata[0] = setUserMetadata(iamOwnerCTX, InstancePermissionV2, userID, key, "value1")
InstancePermissionV2.SetUserMetadata(iamOwnerCTX, userID, "key2", "value2")
InstancePermissionV2.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 := InstancePermissionV2.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
response.Metadata[2] = setUserMetadata(iamOwnerCTX, InstancePermissionV2, userID, "key1", "value1")
response.Metadata[1] = setUserMetadata(iamOwnerCTX, InstancePermissionV2, userID, "key2", "value2")
response.Metadata[0] = setUserMetadata(iamOwnerCTX, InstancePermissionV2, 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 := InstancePermissionV2.Client.UserV2.ListUserMetadata(tt.args.ctx, tt.args.req)
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, instance *integration.Instance, 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.WithAuthorizationToken(OrgCTX, 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) {
testStartTime := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
request.Keys = []string{key}
return testStartTime, time.Time{}
},
req: &user.DeleteUserMetadataRequest{},
wantDeletionDate: true,
},
{
name: "delete, empty list",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
testStartTime := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
return testStartTime, time.Now().UTC()
},
req: &user.DeleteUserMetadataRequest{},
wantErr: true,
},
{
name: "delete, already removed",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
testStartTime := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.Email()).GetId()
request.UserId = userID
key := "key1"
Instance.SetUserMetadata(iamOwnerCTX, userID, key, "value1")
Instance.DeleteUserMetadata(iamOwnerCTX, userID, key)
request.Keys = []string{key}
return testStartTime, time.Now().UTC()
},
req: &user.DeleteUserMetadataRequest{},
wantErr: true,
},
{
name: "delete, multiple",
ctx: iamOwnerCTX,
prepare: func(request *user.DeleteUserMetadataRequest) (time.Time, time.Time) {
testStartTime := time.Now().UTC()
userID := Instance.CreateUserTypeHuman(iamOwnerCTX, integration.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 testStartTime, time.Time{}
},
req: &user.DeleteUserMetadataRequest{},
wantDeletionDate: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var testStartTime, deletionDate time.Time
if tt.prepare != nil {
testStartTime, 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, testStartTime, deletionDate, tt.wantDeletionDate, got)
})
}
}
func assertDeleteProjectResponse(t *testing.T, testStartTime, deletionDate time.Time, expectedDeletionDate bool, actualResp *user.DeleteUserMetadataResponse) {
if expectedDeletionDate {
if !deletionDate.IsZero() {
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), testStartTime, deletionDate)
} else {
assert.WithinRange(t, actualResp.GetDeletionDate().AsTime(), testStartTime, time.Now().UTC())
}
} else {
assert.Nil(t, actualResp.DeletionDate)
}
}