mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-19 14:12:52 +00:00
## Summary This PR introduces the relational user repository for backend v3, including schema, repository APIs, reducers/projections, and tests for both human and machine users. ## What changed * Added user-focused relational migrations (users, verifications, metadata, PATs, machine keys, passkeys, identity provider links) and related FK wiring. * Implemented/expanded repository domain contracts and storage implementations for human and machine user flows. * Added support for machine secret handling and aligned access token type modeling. * Extended user domain models (verifications, password/email/phone/TOTP state, passkeys, metadata, invite handling, identity provider links). * Updated projection/reduction coverage and integration tests for key user lifecycle events. * Regenerated and updated mocks/enums plus supporting database change/column utilities. ## Notes for reviewers * This PR is large because it establishes the foundational relational user storage layer and related test scaffolding. Sorry for that. ## Closes Closes #10218 Closes #10224 Closes #10225 Closes #10209 Closes #10802 --------- Co-authored-by: Iraq Jaber <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Marco A. <[email protected]> Co-authored-by: Tim Möhlmann <[email protected]>
1108 lines
35 KiB
Go
1108 lines
35 KiB
Go
//go:build integration
|
|
|
|
package events_test
|
|
|
|
import (
|
|
"bytes"
|
|
_ "embed"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/brianvoe/gofakeit/v6"
|
|
"github.com/go-resty/resty/v2"
|
|
"github.com/muhlemmer/gu"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gopkg.in/headzoo/surf.v1"
|
|
|
|
"github.com/zitadel/zitadel/backend/v3/domain"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database/repository"
|
|
"github.com/zitadel/zitadel/internal/integration"
|
|
"github.com/zitadel/zitadel/pkg/grpc/management"
|
|
object "github.com/zitadel/zitadel/pkg/grpc/object/v2"
|
|
"github.com/zitadel/zitadel/pkg/grpc/user"
|
|
v2_user "github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
|
)
|
|
|
|
func TestServer_TestHumanUserReduces(t *testing.T) {
|
|
instanceID := Instance.ID()
|
|
orgID := Instance.DefaultOrg.Id
|
|
|
|
userRepo := repository.UserRepository()
|
|
|
|
t.Run("test human user added reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
before := time.Now()
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.added
|
|
// event user.human.added
|
|
// domain.User
|
|
assert.Equal(t, instanceID, user.InstanceID)
|
|
assert.Equal(t, orgID, user.OrganizationID)
|
|
assert.Equal(t, resp.UserId, user.ID)
|
|
assert.Equal(t, humanUserRequest.UserName, user.Username)
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
assert.WithinRange(t, user.CreatedAt, before, after)
|
|
// Email
|
|
assert.Equal(t, humanUserRequest.Email.Email, user.Human.Email.Address)
|
|
assert.NotZero(t, user.Human.Email.VerifiedAt)
|
|
assert.Nil(t, user.Human.Email.PendingVerification)
|
|
// Phone
|
|
if !assert.NotNil(t, humanUserRequest.Phone) {
|
|
assert.Equal(t, humanUserRequest.Phone.Phone, user.Human.Phone.Number)
|
|
assert.NotZero(t, user.Human.Phone.VerifiedAt)
|
|
assert.Nil(t, user.Human.Phone.PendingVerification)
|
|
}
|
|
// Human
|
|
assert.Equal(t, humanUserRequest.Profile.FirstName, user.Human.FirstName)
|
|
assert.Equal(t, humanUserRequest.Profile.LastName, user.Human.LastName)
|
|
assert.Equal(t, humanUserRequest.Profile.NickName, user.Human.Nickname)
|
|
assert.Equal(t, humanUserRequest.Profile.DisplayName, user.Human.DisplayName)
|
|
assert.Equal(t, humanUserRequest.Profile.PreferredLanguage, user.Human.PreferredLanguage.String())
|
|
assert.EqualValues(t, humanUserRequest.Profile.Gender, user.Human.Gender)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user register reduced", func(t *testing.T) {
|
|
token := integration.SystemToken
|
|
client := resty.New()
|
|
|
|
bow := surf.NewBrowser()
|
|
err := bow.Open("http://localhost:8082" + "/ui/login/register/org")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, bow.StatusCode())
|
|
|
|
csfr, err := bow.Forms()[1].Value("gorilla.csrf.Token")
|
|
require.NoError(t, err)
|
|
|
|
before := time.Now()
|
|
client.SetCookieJar(bow.CookieJar())
|
|
firstName := gofakeit.Name()
|
|
lastName := gofakeit.Name()
|
|
email := gofakeit.Email()
|
|
out, err := client.R().SetAuthToken(token).
|
|
SetFormData(map[string]string{
|
|
"gorilla.csrf.Token": csfr,
|
|
"orgname": gofakeit.Name(),
|
|
"firstname": firstName,
|
|
"lastname": lastName,
|
|
"email": email,
|
|
"register-password": "Password1!",
|
|
"register-password-confirmation": "Password1!",
|
|
}).
|
|
Post("http://localhost:8082" + "/ui/login/register/org")
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, out.StatusCode())
|
|
after := time.Now()
|
|
|
|
ctx := t.Context()
|
|
instanceRepo := repository.InstanceRepository()
|
|
instance, err := instanceRepo.Get(ctx, pool, database.WithCondition(instanceRepo.NameCondition(database.TextOperationEqual, "ZITADEL")))
|
|
assert.NoError(t, err)
|
|
instanceID := instance.ID
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*20)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.Human().FirstNameCondition(database.TextOperationEqual, firstName),
|
|
userRepo.Human().LastNameCondition(database.TextOperationEqual, lastName),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// domain.User
|
|
assert.Equal(t, instanceID, user.InstanceID)
|
|
assert.Equal(t, email, user.Username)
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
assert.WithinRange(t, user.CreatedAt, before, after)
|
|
// Email
|
|
assert.Equal(t, email, user.Human.Email.UnverifiedAddress)
|
|
assert.Zero(t, user.Human.Email.VerifiedAt)
|
|
assert.Nil(t, user.Human.Email.PendingVerification)
|
|
// Human
|
|
assert.Equal(t, firstName, user.Human.FirstName)
|
|
assert.Equal(t, lastName, user.Human.LastName)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user locked reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
before := time.Now()
|
|
_, err = MgmtClient.LockUser(IAMCTX, &management.LockUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.locked
|
|
assert.Equal(t, domain.UserStateLocked, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user unlock reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
_, err = MgmtClient.LockUser(IAMCTX, &management.LockUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateLocked, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
before := time.Now()
|
|
_, err = MgmtClient.UnlockUser(IAMCTX, &management.UnlockUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.unlocked
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user deactivate reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
before := time.Now()
|
|
_, err = MgmtClient.DeactivateUser(IAMCTX, &management.DeactivateUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.deactivated
|
|
assert.Equal(t, domain.UserStateInactive, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user reactivate reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
_, err = MgmtClient.DeactivateUser(IAMCTX, &management.DeactivateUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, domain.UserStateInactive, user.State)
|
|
}, retryDuration, tick)
|
|
|
|
before := time.Now()
|
|
_, err = MgmtClient.ReactivateUser(IAMCTX, &management.ReactivateUserRequest{
|
|
Id: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.reactivated
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user removed reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.NotNil(t, user)
|
|
}, retryDuration, tick)
|
|
|
|
_, err = UserClient.DeleteUser(IAMCTX, &v2_user.DeleteUserRequest{
|
|
UserId: resp.UserId,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
_, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
|
|
// event user.removed
|
|
require.ErrorIs(t, &database.NoRowFoundError{}, err)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user change name reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.NotNil(t, user)
|
|
}, retryDuration, tick)
|
|
|
|
username := gofakeit.Username()
|
|
_, err = UserClient.UpdateHumanUser(IAMCTX, &v2_user.UpdateHumanUserRequest{
|
|
UserId: resp.UserId,
|
|
Username: &username,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.username.changed
|
|
assert.Equal(t, username, user.Username)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user profile change reduced", func(t *testing.T) {
|
|
humanUserRequest := &management.AddHumanUserRequest{
|
|
UserName: gofakeit.Username(),
|
|
Profile: &management.AddHumanUserRequest_Profile{
|
|
FirstName: "first",
|
|
LastName: "last",
|
|
NickName: "nick",
|
|
DisplayName: "display",
|
|
PreferredLanguage: "en",
|
|
Gender: user.Gender_GENDER_MALE,
|
|
},
|
|
Email: &management.AddHumanUserRequest_Email{
|
|
Email: gofakeit.Email(),
|
|
IsEmailVerified: true,
|
|
},
|
|
Phone: &management.AddHumanUserRequest_Phone{
|
|
Phone: "+1" + gofakeit.Phone(),
|
|
IsPhoneVerified: true,
|
|
},
|
|
InitialPassword: "Password1!",
|
|
}
|
|
|
|
resp, err := MgmtClient.AddHumanUser(IAMCTX, humanUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.NotNil(t, user)
|
|
}, retryDuration, tick)
|
|
|
|
profile := &v2_user.SetHumanProfile{
|
|
GivenName: gofakeit.FirstName(),
|
|
FamilyName: gofakeit.LastName(),
|
|
NickName: gu.Ptr(gofakeit.Color()),
|
|
DisplayName: gu.Ptr(gofakeit.Name()),
|
|
PreferredLanguage: gu.Ptr("fr"),
|
|
Gender: gu.Ptr(v2_user.Gender_GENDER_FEMALE),
|
|
}
|
|
_, err = UserClient.UpdateHumanUser(IAMCTX, &v2_user.UpdateHumanUserRequest{
|
|
UserId: resp.UserId,
|
|
Profile: profile,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.human.profile.changed
|
|
assert.Equal(t, profile.GivenName, user.Human.FirstName)
|
|
assert.Equal(t, profile.FamilyName, user.Human.LastName)
|
|
assert.Equal(t, *profile.NickName, user.Human.Nickname)
|
|
assert.Equal(t, *profile.DisplayName, user.Human.DisplayName)
|
|
assert.Equal(t, *profile.PreferredLanguage, user.Human.PreferredLanguage.String())
|
|
assert.EqualValues(t, *profile.Gender, user.Human.Gender)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
// I added a delete user command (Over REST because there is no gRPC client (as far as I can tell) for the default instance)
|
|
// the issue is if the user does not exist it will throw and error when trying to delete it
|
|
t.Run("test human user avatar added reduced", func(t *testing.T) {
|
|
ctx := t.Context()
|
|
token := integration.SystemToken
|
|
|
|
instanceRepo := repository.InstanceRepository()
|
|
instance, err := instanceRepo.Get(ctx, pool, database.WithCondition(instanceRepo.NameCondition(database.TextOperationEqual, "ZITADEL")))
|
|
instanceID := instance.ID
|
|
require.NoError(t, err)
|
|
orgRepo := repository.OrganizationRepository()
|
|
org_, err := orgRepo.Get(ctx, pool, database.WithCondition(database.And(orgRepo.InstanceIDCondition(instanceID), orgRepo.NameCondition(database.TextOperationEqual, "ZITADEL"))))
|
|
require.NoError(t, err)
|
|
orgID := org_.ID
|
|
|
|
// delete user tester
|
|
deleteUserReq := v2_user.DeleteUserRequest{
|
|
UserId: "tester",
|
|
}
|
|
deleteUserReqJSON, err := json.Marshal(&deleteUserReq)
|
|
require.NoError(t, err)
|
|
client := resty.New()
|
|
out, err := client.R().SetAuthToken(token).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
SetBody(deleteUserReqJSON).
|
|
Delete("http://localhost:8082" + "/v2beta/users/human")
|
|
require.NoError(t, err)
|
|
// require.Equal(t, 200, out.StatusCode())
|
|
// require.NoError(t, err)
|
|
|
|
// create user tester
|
|
createUserReq := &v2_user.AddHumanUserRequest{
|
|
UserId: gu.Ptr("tester"), // YOLO
|
|
Organization: &object.Organization{
|
|
Org: &object.Organization_OrgId{
|
|
OrgId: orgID,
|
|
},
|
|
},
|
|
Profile: &v2_user.SetHumanProfile{
|
|
GivenName: "Donald",
|
|
FamilyName: "Duck",
|
|
NickName: gu.Ptr("Dukkie"),
|
|
DisplayName: gu.Ptr("Donald Duck"),
|
|
PreferredLanguage: gu.Ptr("en"),
|
|
Gender: v2_user.Gender_GENDER_DIVERSE.Enum(),
|
|
},
|
|
Email: &v2_user.SetHumanEmail{
|
|
Email: gofakeit.Email(),
|
|
},
|
|
Phone: &v2_user.SetHumanPhone{},
|
|
Metadata: []*v2_user.SetMetadataEntry{
|
|
{
|
|
Key: "somekey",
|
|
Value: []byte("somevalue"),
|
|
},
|
|
},
|
|
PasswordType: &v2_user.AddHumanUserRequest_Password{
|
|
Password: &v2_user.Password{
|
|
Password: "DifficultPW666!",
|
|
ChangeRequired: true,
|
|
},
|
|
},
|
|
}
|
|
createUserReqJSON, err := json.Marshal(createUserReq)
|
|
require.NoError(t, err)
|
|
client = resty.New()
|
|
out, err = client.R().SetAuthToken(token).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
SetBody(createUserReqJSON).
|
|
Post("http://localhost:8082" + "/v2beta/users/human")
|
|
require.NoError(t, err)
|
|
// require.Equal(t, 201, out.StatusCode())
|
|
|
|
require.NoError(t, err)
|
|
|
|
// client = resty.New()
|
|
// POST avatar
|
|
before := time.Now()
|
|
out, err = client.R().SetAuthToken(token).
|
|
SetMultipartField("file", "filename", "image/png", bytes.NewReader(picture)).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
Post("http://localhost:8082" + "/assets/v1" + "/users/me/avatar")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, out.StatusCode())
|
|
after := time.Now()
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition("tester"),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.human.avatar.added
|
|
avatarUrl := "users/tester/avatar?"
|
|
assert.Contains(t, user.Human.AvatarKey, avatarUrl)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
// I added a delete user command (Over REST because there is no gRPC client (as far as I can tell) for the default instance)
|
|
// the issue is if the user does not exist it will throw and error when trying to delete it
|
|
t.Run("test human user avatar removed reduced", func(t *testing.T) {
|
|
ctx := t.Context()
|
|
token := integration.SystemToken
|
|
|
|
instanceRepo := repository.InstanceRepository()
|
|
instance, err := instanceRepo.Get(ctx, pool, database.WithCondition(instanceRepo.NameCondition(database.TextOperationEqual, "ZITADEL")))
|
|
instanceID := instance.ID
|
|
require.NoError(t, err)
|
|
orgRepo := repository.OrganizationRepository()
|
|
org_, err := orgRepo.Get(ctx, pool, database.WithCondition(database.And(orgRepo.InstanceIDCondition(instanceID), orgRepo.NameCondition(database.TextOperationEqual, "ZITADEL"))))
|
|
require.NoError(t, err)
|
|
orgID := org_.ID
|
|
|
|
// delete user tester
|
|
deleteUserReq := v2_user.DeleteUserRequest{
|
|
UserId: "tester",
|
|
}
|
|
deleteUserReqJSON, err := json.Marshal(&deleteUserReq)
|
|
require.NoError(t, err)
|
|
client := resty.New()
|
|
out, err := client.R().SetAuthToken(token).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
SetBody(deleteUserReqJSON).
|
|
Delete("http://localhost:8082" + "/v2beta/users/human")
|
|
require.NoError(t, err)
|
|
// require.Equal(t, 200, out.StatusCode())
|
|
// require.NoError(t, err)
|
|
|
|
// create user tester
|
|
createUserReq := &v2_user.AddHumanUserRequest{
|
|
UserId: gu.Ptr("tester"), // YOLO
|
|
Organization: &object.Organization{
|
|
Org: &object.Organization_OrgId{
|
|
OrgId: orgID,
|
|
},
|
|
},
|
|
Profile: &v2_user.SetHumanProfile{
|
|
GivenName: "Donald",
|
|
FamilyName: "Duck",
|
|
NickName: gu.Ptr("Dukkie"),
|
|
DisplayName: gu.Ptr("Donald Duck"),
|
|
PreferredLanguage: gu.Ptr("en"),
|
|
Gender: v2_user.Gender_GENDER_DIVERSE.Enum(),
|
|
},
|
|
Email: &v2_user.SetHumanEmail{
|
|
Email: gofakeit.Email(),
|
|
},
|
|
Phone: &v2_user.SetHumanPhone{},
|
|
Metadata: []*v2_user.SetMetadataEntry{
|
|
{
|
|
Key: "somekey",
|
|
Value: []byte("somevalue"),
|
|
},
|
|
},
|
|
PasswordType: &v2_user.AddHumanUserRequest_Password{
|
|
Password: &v2_user.Password{
|
|
Password: "DifficultPW666!",
|
|
ChangeRequired: true,
|
|
},
|
|
},
|
|
}
|
|
createUserReqJSON, err := json.Marshal(createUserReq)
|
|
require.NoError(t, err)
|
|
client = resty.New()
|
|
out, err = client.R().SetAuthToken(token).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
SetBody(createUserReqJSON).
|
|
Post("http://localhost:8082" + "/v2beta/users/human")
|
|
require.NoError(t, err)
|
|
// require.Equal(t, 201, out.StatusCode())
|
|
|
|
require.NoError(t, err)
|
|
|
|
// POST avatar
|
|
out, err = client.R().SetAuthToken(token).
|
|
SetMultipartField("file", "filename", "image/png", bytes.NewReader(picture)).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
Post("http://localhost:8082" + "/assets/v1" + "/users/me/avatar")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, out.StatusCode())
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition("tester"),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, user.Human.AvatarKey)
|
|
|
|
avatarUrl := "users/tester/avatar?"
|
|
assert.Equal(t, avatarUrl, string(user.Human.AvatarKey)[:len(avatarUrl)])
|
|
}, retryDuration, tick)
|
|
|
|
// delete avatar
|
|
before := time.Now()
|
|
out, err = client.R().SetAuthToken(token).
|
|
SetHeader("x-zitadel-orgid", orgID).
|
|
Delete("http://localhost:8082/auth/v1/users/me/avatar")
|
|
require.NoError(t, err)
|
|
require.Equal(t, 200, out.StatusCode())
|
|
after := time.Now()
|
|
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition("tester"),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Empty(t, user.Human.AvatarKey)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test human user password change reduced", func(t *testing.T) {
|
|
createUserReq := &v2_user.AddHumanUserRequest{
|
|
// UserId: gu.Ptr("tester"),
|
|
Organization: &object.Organization{
|
|
Org: &object.Organization_OrgId{
|
|
OrgId: orgID,
|
|
},
|
|
},
|
|
Profile: &v2_user.SetHumanProfile{
|
|
GivenName: "Donald",
|
|
FamilyName: "Duck",
|
|
NickName: gu.Ptr("Dukkie"),
|
|
DisplayName: gu.Ptr("Donald Duck"),
|
|
PreferredLanguage: gu.Ptr("en"),
|
|
Gender: v2_user.Gender_GENDER_DIVERSE.Enum(),
|
|
},
|
|
Email: &v2_user.SetHumanEmail{
|
|
Email: gofakeit.Email(),
|
|
},
|
|
Phone: &v2_user.SetHumanPhone{},
|
|
Metadata: []*v2_user.SetMetadataEntry{
|
|
{
|
|
Key: "somekey",
|
|
Value: []byte("somevalue"),
|
|
},
|
|
},
|
|
PasswordType: &v2_user.AddHumanUserRequest_Password{
|
|
Password: &v2_user.Password{
|
|
Password: "Password1!",
|
|
ChangeRequired: true,
|
|
},
|
|
},
|
|
}
|
|
res, err := UserClient.AddHumanUser(IAMCTX, createUserReq)
|
|
require.NoError(t, err)
|
|
|
|
userID := res.UserId
|
|
|
|
// make sure user exists
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(userID),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.NotNil(t, user)
|
|
}, retryDuration, tick)
|
|
|
|
// change user password
|
|
before := time.Now()
|
|
_, err = UserClient.UpdateHumanUser(IAMCTX, &v2_user.UpdateHumanUserRequest{
|
|
UserId: userID,
|
|
Password: &v2_user.SetPassword{
|
|
PasswordType: &v2_user.SetPassword_Password{
|
|
Password: &v2_user.Password{
|
|
Password: "Password2!",
|
|
ChangeRequired: true,
|
|
},
|
|
},
|
|
Verification: &v2_user.SetPassword_CurrentPassword{
|
|
CurrentPassword: "Password1!",
|
|
},
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
// check password updated
|
|
retryDuration, tick = integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
humanUser, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(userID),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, true, humanUser.Human.Password.IsChangeRequired)
|
|
assert.WithinRange(t, humanUser.Human.Password.ChangedAt, before, after)
|
|
}, retryDuration, tick)
|
|
})
|
|
}
|
|
|
|
func TestServer_TestMachineUserReduces(t *testing.T) {
|
|
instanceID := Instance.ID()
|
|
orgID := Instance.DefaultOrg.Id
|
|
|
|
userRepo := repository.UserRepository()
|
|
|
|
t.Run("test machine user add reduced", func(t *testing.T) {
|
|
machineUserRequest := &management.AddMachineUserRequest{
|
|
UserId: gu.Ptr(gofakeit.Name()),
|
|
UserName: gofakeit.Name(),
|
|
Name: gofakeit.Name(),
|
|
Description: gofakeit.Blurb(),
|
|
AccessTokenType: user.AccessTokenType_ACCESS_TOKEN_TYPE_BEARER,
|
|
}
|
|
|
|
before := time.Now()
|
|
resp, err := MgmtClient.AddMachineUser(IAMCTX, machineUserRequest)
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(resp.UserId),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.machine.added
|
|
// user
|
|
assert.Equal(t, instanceID, user.InstanceID)
|
|
assert.Equal(t, orgID, user.OrganizationID)
|
|
assert.Equal(t, *machineUserRequest.UserId, user.ID)
|
|
assert.Equal(t, machineUserRequest.UserName, user.Username)
|
|
assert.Equal(t, domain.UserStateActive, user.State)
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
assert.WithinRange(t, user.CreatedAt, before, after)
|
|
// machine
|
|
assert.Equal(t, machineUserRequest.Name, user.Machine.Name)
|
|
assert.Equal(t, machineUserRequest.Description, user.Machine.Description)
|
|
assert.Equal(t, domain.AccessTokenTypeBearer, user.Machine.AccessTokenType)
|
|
}, retryDuration, tick)
|
|
})
|
|
|
|
t.Run("test machine user change reduced", func(t *testing.T) {
|
|
userID := gofakeit.Name()
|
|
machineUserRequest := &management.AddMachineUserRequest{
|
|
UserId: &userID,
|
|
UserName: gofakeit.Name(),
|
|
Name: gofakeit.Name(),
|
|
Description: gofakeit.Blurb(),
|
|
AccessTokenType: user.AccessTokenType_ACCESS_TOKEN_TYPE_BEARER,
|
|
}
|
|
|
|
_, err := MgmtClient.AddMachineUser(IAMCTX, machineUserRequest)
|
|
require.NoError(t, err)
|
|
|
|
updateMachineUserReq := &management.UpdateMachineRequest{
|
|
UserId: userID,
|
|
Name: gofakeit.Name(),
|
|
Description: gofakeit.Blurb(),
|
|
AccessTokenType: user.AccessTokenType_ACCESS_TOKEN_TYPE_JWT,
|
|
}
|
|
|
|
before := time.Now()
|
|
_, err = MgmtClient.UpdateMachine(IAMCTX, updateMachineUserReq)
|
|
require.NoError(t, err)
|
|
after := time.Now()
|
|
|
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(IAMCTX, time.Second*15)
|
|
assert.EventuallyWithT(t, func(t *assert.CollectT) {
|
|
user, err := userRepo.Get(
|
|
CTX,
|
|
pool,
|
|
database.WithCondition(database.And(
|
|
userRepo.InstanceIDCondition(instanceID),
|
|
userRepo.OrganizationIDCondition(orgID),
|
|
userRepo.IDCondition(userID),
|
|
)),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// event user.machine.changed
|
|
// user
|
|
assert.WithinRange(t, user.UpdatedAt, before, after)
|
|
// machine
|
|
assert.Equal(t, updateMachineUserReq.Name, user.Machine.Name)
|
|
assert.Equal(t, updateMachineUserReq.Description, user.Machine.Description)
|
|
assert.Equal(t, domain.AccessTokenTypeJWT, user.Machine.AccessTokenType)
|
|
}, retryDuration, tick, "event not reduced in time for user %q", userID)
|
|
t.Log("hodor")
|
|
})
|
|
}
|