diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index bfbfc77f0..4392baf6a 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -352,15 +352,15 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve switch event.Type { case es_model.UserPasswordCheckSucceeded, es_model.UserPasswordCheckFailed, - es_model.MfaOtpCheckSucceeded, - es_model.MfaOtpCheckFailed, + es_model.MFAOTPCheckSucceeded, + es_model.MFAOTPCheckFailed, es_model.SignedOut, es_model.UserLocked, es_model.UserDeactivated, es_model.HumanPasswordCheckSucceeded, es_model.HumanPasswordCheckFailed, - es_model.HumanMfaOtpCheckSucceeded, - es_model.HumanMfaOtpCheckFailed, + es_model.HumanMFAOTPCheckSucceeded, + es_model.HumanMFAOTPCheckFailed, es_model.HumanSignedOut: eventData, err := user_view_model.UserSessionFromEvent(event) if err != nil { diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index b56ac8bd1..defda5dd3 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -107,9 +107,9 @@ type mockViewUser struct { func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) { return &user_view_model.UserView{ State: int32(user_model.UserStateActive), - UserName: "schofseckel", + UserName: "UserName", HumanView: &user_view_model.HumanView{ - FirstName: "schof", + FirstName: "FirstName", InitRequired: m.InitRequired, PasswordSet: m.PasswordSet, PasswordChangeRequired: m.PasswordChangeRequired, @@ -753,7 +753,7 @@ func Test_userSessionByIDs(t *testing.T) { userProvider: &mockViewUserSession{ PasswordVerification: time.Now().UTC().Round(1 * time.Second), }, - user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "schof"}}, + user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "FirstName"}}, eventProvider: &mockEventErrUser{}, }, &user_model.UserSessionView{ @@ -770,11 +770,11 @@ func Test_userSessionByIDs(t *testing.T) { PasswordVerification: time.Now().UTC().Round(1 * time.Second), }, agentID: "agentID", - user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "schof"}}, + user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "FirstName"}}, eventProvider: &mockEventUser{ &es_models.Event{ AggregateType: user_es_model.UserAggregate, - Type: user_es_model.MfaOtpCheckSucceeded, + Type: user_es_model.MFAOTPCheckSucceeded, CreationDate: time.Now().UTC().Round(1 * time.Second), }, }, @@ -797,7 +797,7 @@ func Test_userSessionByIDs(t *testing.T) { eventProvider: &mockEventUser{ &es_models.Event{ AggregateType: user_es_model.UserAggregate, - Type: user_es_model.MfaOtpCheckSucceeded, + Type: user_es_model.MFAOTPCheckSucceeded, CreationDate: time.Now().UTC().Round(1 * time.Second), Data: func() []byte { data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "otherID"}) @@ -820,11 +820,11 @@ func Test_userSessionByIDs(t *testing.T) { PasswordVerification: time.Now().UTC().Round(1 * time.Second), }, agentID: "agentID", - user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "schof"}}, + user: &user_model.UserView{ID: "id", HumanView: &user_model.HumanView{FirstName: "FirstName"}}, eventProvider: &mockEventUser{ &es_models.Event{ AggregateType: user_es_model.UserAggregate, - Type: user_es_model.MfaOtpCheckSucceeded, + Type: user_es_model.MFAOTPCheckSucceeded, CreationDate: time.Now().UTC().Round(1 * time.Second), Data: func() []byte { data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "agentID"}) @@ -903,10 +903,10 @@ func Test_userByID(t *testing.T) { }, &user_model.UserView{ State: user_model.UserStateActive, - UserName: "schofseckel", + UserName: "UserName", HumanView: &user_model.HumanView{ PasswordChangeRequired: true, - FirstName: "schof", + FirstName: "FirstName", }, }, nil, @@ -928,10 +928,10 @@ func Test_userByID(t *testing.T) { }, &user_model.UserView{ State: user_model.UserStateActive, - UserName: "schofseckel", + UserName: "UserName", HumanView: &user_model.HumanView{ PasswordChangeRequired: true, - FirstName: "schof", + FirstName: "FirstName", }, }, nil, @@ -957,11 +957,11 @@ func Test_userByID(t *testing.T) { &user_model.UserView{ ChangeDate: time.Now().UTC().Round(1 * time.Second), State: user_model.UserStateActive, - UserName: "schofseckel", + UserName: "UserName", HumanView: &user_model.HumanView{ PasswordChangeRequired: false, PasswordChanged: time.Now().UTC().Round(1 * time.Second), - FirstName: "schof", + FirstName: "FirstName", }, }, nil, diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index 64a5b9f36..4f2aa1cb6 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -91,7 +91,7 @@ func (u *User) ProcessUser(event *models.Event) (err error) { es_model.HumanMFAOTPAdded, es_model.HumanMFAOTPVerified, es_model.HumanMFAOTPRemoved, - es_model.HumanMfaInitSkipped, + es_model.HumanMFAInitSkipped, es_model.MachineChanged, es_model.HumanPasswordChanged: user, err = u.view.UserByID(event.AggregateID) diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index 769d7fe10..58ac71cfd 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -40,13 +40,13 @@ func (u *UserSession) Reduce(event *models.Event) (err error) { switch event.Type { case es_model.UserPasswordCheckSucceeded, es_model.UserPasswordCheckFailed, - es_model.MfaOtpCheckSucceeded, - es_model.MfaOtpCheckFailed, + es_model.MFAOTPCheckSucceeded, + es_model.MFAOTPCheckFailed, es_model.SignedOut, es_model.HumanPasswordCheckSucceeded, es_model.HumanPasswordCheckFailed, - es_model.HumanMfaOtpCheckSucceeded, - es_model.HumanMfaOtpCheckFailed, + es_model.HumanMFAOTPCheckSucceeded, + es_model.HumanMFAOTPCheckFailed, es_model.HumanSignedOut: eventData, err := view_model.UserSessionFromEvent(event) if err != nil { diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go index a821e7670..6ec960fd4 100644 --- a/internal/project/repository/eventsourcing/eventstore.go +++ b/internal/project/repository/eventsourcing/eventstore.go @@ -839,14 +839,14 @@ func (es *ProjectEventstore) AddProjectGrant(ctx context.Context, grant *proj_mo if grant == nil || !grant.IsValid() { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-37dhs", "Errors.Project.GrantInvalid") } - existingProject, err := es.ProjectByID(ctx, grant.AggregateID) + project, err := es.ProjectByID(ctx, grant.AggregateID) if err != nil { return nil, err } - if existingProject.ContainsGrantForOrg(grant.GrantedOrgID) { + if project.ContainsGrantForOrg(grant.GrantedOrgID) { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-7ug4g", "Errors.Project.GrantAlreadyExists") } - if !existingProject.ContainsRoles(grant.RoleKeys) { + if !project.ContainsRoles(grant.RoleKeys) { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-di83d", "Errors.Project.GrantHasNotExistingRole") } id, err := es.idGenerator.Next() @@ -855,7 +855,7 @@ func (es *ProjectEventstore) AddProjectGrant(ctx context.Context, grant *proj_mo } grant.GrantID = id - repoProject := model.ProjectFromModel(existingProject) + repoProject := model.ProjectFromModel(project) repoGrant := model.GrantFromModel(grant) addAggregate := ProjectGrantAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant) diff --git a/internal/project/repository/eventsourcing/project.go b/internal/project/repository/eventsourcing/project.go index 3a62c87e6..6ffd943d4 100644 --- a/internal/project/repository/eventsourcing/project.go +++ b/internal/project/repository/eventsourcing/project.go @@ -368,12 +368,12 @@ func OIDCClientSecretCheckFailedAggregate(aggCreator *es_models.AggregateCreator } } -func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existingProject *model.Project, grant *model.ProjectGrant) func(ctx context.Context) (*es_models.Aggregate, error) { +func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, project *model.Project, grant *model.ProjectGrant) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if grant == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kd89w", "Errors.Internal") } - agg, err := ProjectAggregate(ctx, aggCreator, existingProject) + agg, err := ProjectAggregate(ctx, aggCreator, project) if err != nil { return nil, err } diff --git a/internal/user/repository/eventsourcing/model/types.go b/internal/user/repository/eventsourcing/model/types.go index ea3dd3e1b..191aa735e 100644 --- a/internal/user/repository/eventsourcing/model/types.go +++ b/internal/user/repository/eventsourcing/model/types.go @@ -46,8 +46,8 @@ const ( MFAOTPAdded models.EventType = "user.mfa.otp.added" MFAOTPVerified models.EventType = "user.mfa.otp.verified" MFAOTPRemoved models.EventType = "user.mfa.otp.removed" - MfaOtpCheckSucceeded models.EventType = "user.mfa.otp.check.succeeded" - MfaOtpCheckFailed models.EventType = "user.mfa.otp.check.failed" + MFAOTPCheckSucceeded models.EventType = "user.mfa.otp.check.succeeded" + MFAOTPCheckFailed models.EventType = "user.mfa.otp.check.failed" MFAInitSkipped models.EventType = "user.mfa.init.skipped" SignedOut models.EventType = "user.signed.out" @@ -102,9 +102,9 @@ const ( HumanMFAOTPAdded models.EventType = "user.human.mfa.otp.added" HumanMFAOTPVerified models.EventType = "user.human.mfa.otp.verified" HumanMFAOTPRemoved models.EventType = "user.human.mfa.otp.removed" - HumanMfaOtpCheckSucceeded models.EventType = "user.human.mfa.otp.check.succeeded" - HumanMfaOtpCheckFailed models.EventType = "user.human.mfa.otp.check.failed" - HumanMfaInitSkipped models.EventType = "user.human.mfa.init.skipped" + HumanMFAOTPCheckSucceeded models.EventType = "user.human.mfa.otp.check.succeeded" + HumanMFAOTPCheckFailed models.EventType = "user.human.mfa.otp.check.failed" + HumanMFAInitSkipped models.EventType = "user.human.mfa.init.skipped" HumanSignedOut models.EventType = "user.human.signed.out" ) diff --git a/internal/user/repository/eventsourcing/model/user_human_test.go b/internal/user/repository/eventsourcing/model/user_human_test.go index fe090d57b..61f0dbb9d 100644 --- a/internal/user/repository/eventsourcing/model/user_human_test.go +++ b/internal/user/repository/eventsourcing/model/user_human_test.go @@ -6,117 +6,8 @@ import ( "time" es_models "github.com/caos/zitadel/internal/eventstore/models" - "github.com/caos/zitadel/internal/user/model" ) -func TestAppendDeactivatedEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append deactivate event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateInactive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendDeactivatedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendReactivatedEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append reactivate event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendReactivatedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendLockEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append lock event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateLocked)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendLockedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - -func TestAppendUnlockEvent(t *testing.T) { - type args struct { - user *User - } - tests := []struct { - name string - args args - result *User - }{ - { - name: "append unlock event", - args: args{ - user: &User{}, - }, - result: &User{State: int32(model.UserStateActive)}, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.args.user.appendUnlockedEvent() - if tt.args.user.State != tt.result.State { - t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) - } - }) - } -} - func TestAppendInitUserCodeEvent(t *testing.T) { type args struct { user *Human diff --git a/internal/user/repository/eventsourcing/model/user_machine.go b/internal/user/repository/eventsourcing/model/user_machine.go index 1f6e0cc34..49a7c8c5f 100644 --- a/internal/user/repository/eventsourcing/model/user_machine.go +++ b/internal/user/repository/eventsourcing/model/user_machine.go @@ -32,10 +32,6 @@ func (sa *Machine) AppendEvent(event *models.Event) (err error) { switch event.Type { case MachineAdded, MachineChanged: err = sa.setData(event) - case MachineKeyAdded: - fallthrough - case MachineKeyRemoved: - logging.Log("MODEL-iBgOc").Warn("key unimplemented") } return err diff --git a/internal/user/repository/eventsourcing/model/user_test.go b/internal/user/repository/eventsourcing/model/user_test.go new file mode 100644 index 000000000..a828d3e95 --- /dev/null +++ b/internal/user/repository/eventsourcing/model/user_test.go @@ -0,0 +1,115 @@ +package model + +import ( + "testing" + + "github.com/caos/zitadel/internal/user/model" +) + +func TestAppendDeactivatedEvent(t *testing.T) { + type args struct { + user *User + } + tests := []struct { + name string + args args + result *User + }{ + { + name: "append deactivate event", + args: args{ + user: &User{}, + }, + result: &User{State: int32(model.UserStateInactive)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.args.user.appendDeactivatedEvent() + if tt.args.user.State != tt.result.State { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) + } + }) + } +} + +func TestAppendReactivatedEvent(t *testing.T) { + type args struct { + user *User + } + tests := []struct { + name string + args args + result *User + }{ + { + name: "append reactivate event", + args: args{ + user: &User{}, + }, + result: &User{State: int32(model.UserStateActive)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.args.user.appendReactivatedEvent() + if tt.args.user.State != tt.result.State { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) + } + }) + } +} + +func TestAppendLockEvent(t *testing.T) { + type args struct { + user *User + } + tests := []struct { + name string + args args + result *User + }{ + { + name: "append lock event", + args: args{ + user: &User{}, + }, + result: &User{State: int32(model.UserStateLocked)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.args.user.appendLockedEvent() + if tt.args.user.State != tt.result.State { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) + } + }) + } +} + +func TestAppendUnlockEvent(t *testing.T) { + type args struct { + user *User + } + tests := []struct { + name string + args args + result *User + }{ + { + name: "append unlock event", + args: args{ + user: &User{}, + }, + result: &User{State: int32(model.UserStateActive)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.args.user.appendUnlockedEvent() + if tt.args.user.State != tt.result.State { + t.Errorf("got wrong result: expected: %v, actual: %v ", tt.result, tt.args.user) + } + }) + } +} diff --git a/internal/user/repository/eventsourcing/user.go b/internal/user/repository/eventsourcing/user.go index 531680457..edbefe383 100644 --- a/internal/user/repository/eventsourcing/user.go +++ b/internal/user/repository/eventsourcing/user.go @@ -347,7 +347,7 @@ func SkipMfaAggregate(aggCreator *es_models.AggregateCreator, user *model.User) if err != nil { return nil, err } - return agg.AppendEvent(model.HumanMfaInitSkipped, nil) + return agg.AppendEvent(model.HumanMFAInitSkipped, nil) } } @@ -658,7 +658,7 @@ func MFAOTPCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, user if err != nil { return nil, err } - return agg.AppendEvent(model.HumanMfaOtpCheckSucceeded, authReq) + return agg.AppendEvent(model.HumanMFAOTPCheckSucceeded, authReq) } } @@ -671,7 +671,7 @@ func MFAOTPCheckFailedAggregate(aggCreator *es_models.AggregateCreator, user *mo if err != nil { return nil, err } - return agg.AppendEvent(model.HumanMfaOtpCheckFailed, authReq) + return agg.AppendEvent(model.HumanMFAOTPCheckFailed, authReq) } } diff --git a/internal/user/repository/eventsourcing/user_test.go b/internal/user/repository/eventsourcing/user_test.go index 20e9b7be7..bd7be4d19 100644 --- a/internal/user/repository/eventsourcing/user_test.go +++ b/internal/user/repository/eventsourcing/user_test.go @@ -101,10 +101,10 @@ func TestUserQuery(t *testing.T) { } } -func TestUserCreateAggregate(t *testing.T) { +func TestHumanCreateAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User initCode *model.InitUserCode phoneCode *model.PhoneCode aggCreator *models.AggregateCreator @@ -126,7 +126,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "user create aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -147,7 +147,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ @@ -159,7 +159,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "create with init code", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -181,7 +181,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "create with phone code", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -203,7 +203,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "create with email verified", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -224,7 +224,7 @@ func TestUserCreateAggregate(t *testing.T) { name: "create with phone verified", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -245,7 +245,7 @@ func TestUserCreateAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - aggregates, err := HumanCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.initCode, tt.args.phoneCode, "", true) + aggregates, err := HumanCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.user, tt.args.initCode, tt.args.phoneCode, "", true) if !tt.res.wantErr && len(aggregates) != tt.res.aggregatesLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.aggregatesLen, len(aggregates)) @@ -272,10 +272,92 @@ func TestUserCreateAggregate(t *testing.T) { } } +func TestMachineCreateAggregate(t *testing.T) { + type args struct { + ctx context.Context + user *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + aggregatesLen int + checkData []bool + wantErr bool + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user create aggregate ok", + args: args{ + ctx: authz.NewMockContext("orgID", "userID"), + user: &model.User{ + ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + UserName: "UserName", + Machine: &model.Machine{ + Description: "Description", + Name: "Name", + }, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventTypes: []models.EventType{model.MachineAdded}, + checkData: []bool{true}, + aggregatesLen: 2, + }, + }, + { + name: "new user nil", + args: args{ + ctx: authz.NewMockContext("orgID", "userID"), + user: nil, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + wantErr: true, + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + aggregates, err := MachineCreateAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.user, "", true) + + if !tt.res.wantErr && len(aggregates) != tt.res.aggregatesLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.aggregatesLen, len(aggregates)) + } + + if !tt.res.wantErr && len(aggregates[0].Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if !tt.res.wantErr && aggregates[0].Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], aggregates[0].Events[i].Type.String()) + } + if !tt.res.wantErr && tt.res.checkData[i] && aggregates[0].Events[i].Data == nil { + t.Errorf("should have data in event") + } + if !tt.res.wantErr && !tt.res.checkData[i] && aggregates[0].Events[i].Data != nil { + t.Errorf("should not have data in event") + } + } + if tt.res.wantErr && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestUserRegisterAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User initCode *model.InitUserCode resourceOwner string aggCreator *models.AggregateCreator @@ -294,7 +376,7 @@ func TestUserRegisterAggregate(t *testing.T) { name: "user register aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -315,7 +397,7 @@ func TestUserRegisterAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, initCode: &model.InitUserCode{}, resourceOwner: "newResourceowner", aggCreator: models.NewAggregateCreator("Test"), @@ -329,7 +411,7 @@ func TestUserRegisterAggregate(t *testing.T) { args: args{ ctx: authz.NewMockContext("orgID", "userID"), resourceOwner: "newResourceowner", - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -347,7 +429,7 @@ func TestUserRegisterAggregate(t *testing.T) { name: "create with init code", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -368,7 +450,7 @@ func TestUserRegisterAggregate(t *testing.T) { name: "create no resourceowner", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", Human: &model.Human{ @@ -386,7 +468,7 @@ func TestUserRegisterAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.new, tt.args.resourceOwner, tt.args.initCode, false) + aggregates, err := UserRegisterAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.user, tt.args.resourceOwner, tt.args.initCode, false) if tt.res.errFunc == nil && len(aggregates[1].Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[1].Events)) @@ -409,7 +491,7 @@ func TestUserRegisterAggregate(t *testing.T) { func TestUserDeactivateAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User aggCreator *models.AggregateCreator } type res struct { @@ -426,12 +508,9 @@ func TestUserDeactivateAggregate(t *testing.T) { name: "user deactivate aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", - Human: &model.Human{ - Profile: &model.Profile{DisplayName: "DisplayName"}, - }, }, aggCreator: models.NewAggregateCreator("Test"), }, @@ -444,7 +523,7 @@ func TestUserDeactivateAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ @@ -454,7 +533,7 @@ func TestUserDeactivateAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - agg, err := UserDeactivateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + agg, err := UserDeactivateAggregate(tt.args.aggCreator, tt.args.user)(tt.args.ctx) if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) @@ -472,7 +551,7 @@ func TestUserDeactivateAggregate(t *testing.T) { func TestUserReactivateAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User aggCreator *models.AggregateCreator } type res struct { @@ -489,12 +568,9 @@ func TestUserReactivateAggregate(t *testing.T) { name: "user reactivate aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", - Human: &model.Human{ - Profile: &model.Profile{DisplayName: "DisplayName"}, - }, }, aggCreator: models.NewAggregateCreator("Test"), }, @@ -507,7 +583,7 @@ func TestUserReactivateAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ @@ -517,7 +593,7 @@ func TestUserReactivateAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - agg, err := UserReactivateAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + agg, err := UserReactivateAggregate(tt.args.aggCreator, tt.args.user)(tt.args.ctx) if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) @@ -535,7 +611,7 @@ func TestUserReactivateAggregate(t *testing.T) { func TestUserLockedAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User aggCreator *models.AggregateCreator } type res struct { @@ -552,12 +628,9 @@ func TestUserLockedAggregate(t *testing.T) { name: "user locked aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", - Human: &model.Human{ - Profile: &model.Profile{DisplayName: "DisplayName"}, - }, }, aggCreator: models.NewAggregateCreator("Test"), }, @@ -570,7 +643,7 @@ func TestUserLockedAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ @@ -580,7 +653,7 @@ func TestUserLockedAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - agg, err := UserLockAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + agg, err := UserLockAggregate(tt.args.aggCreator, tt.args.user)(tt.args.ctx) if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) @@ -598,7 +671,7 @@ func TestUserLockedAggregate(t *testing.T) { func TestUserUnlockedAggregate(t *testing.T) { type args struct { ctx context.Context - new *model.User + user *model.User aggCreator *models.AggregateCreator } type res struct { @@ -615,12 +688,9 @@ func TestUserUnlockedAggregate(t *testing.T) { name: "user unlocked aggregate ok", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: &model.User{ + user: &model.User{ ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserName: "UserName", - Human: &model.Human{ - Profile: &model.Profile{DisplayName: "DisplayName"}, - }, }, aggCreator: models.NewAggregateCreator("Test"), }, @@ -633,7 +703,7 @@ func TestUserUnlockedAggregate(t *testing.T) { name: "new user nil", args: args{ ctx: authz.NewMockContext("orgID", "userID"), - new: nil, + user: nil, aggCreator: models.NewAggregateCreator("Test"), }, res: res{ @@ -643,7 +713,7 @@ func TestUserUnlockedAggregate(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - agg, err := UserUnlockAggregate(tt.args.aggCreator, tt.args.new)(tt.args.ctx) + agg, err := UserUnlockAggregate(tt.args.aggCreator, tt.args.user)(tt.args.ctx) if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) @@ -904,7 +974,7 @@ func TestInitCodeCheckFailedAggregate(t *testing.T) { }, res: res{ eventLen: 1, - eventType: model.HumanMfaInitSkipped, + eventType: model.HumanMFAInitSkipped, }, }, } @@ -2045,7 +2115,7 @@ func TestChangeAddressAggregate(t *testing.T) { } } -func TestOtpAddAggregate(t *testing.T) { +func TestOTPAddAggregate(t *testing.T) { type args struct { ctx context.Context user *model.User @@ -2109,7 +2179,7 @@ func TestOtpAddAggregate(t *testing.T) { } } -func TestOtpVerifyAggregate(t *testing.T) { +func TestOTPVerifyAggregate(t *testing.T) { type args struct { ctx context.Context user *model.User @@ -2157,7 +2227,7 @@ func TestOtpVerifyAggregate(t *testing.T) { } } -func TestOtpRemoveAggregate(t *testing.T) { +func TestOTPRemoveAggregate(t *testing.T) { type args struct { ctx context.Context user *model.User diff --git a/internal/user/repository/view/model/notify_user_test.go b/internal/user/repository/view/model/notify_user_test.go index 9b75ab514..ff0b8a993 100644 --- a/internal/user/repository/view/model/notify_user_test.go +++ b/internal/user/repository/view/model/notify_user_test.go @@ -1,9 +1,10 @@ package model import ( + "testing" + es_models "github.com/caos/zitadel/internal/eventstore/models" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" - "testing" ) func TestNotifyUserAppendEvent(t *testing.T) { @@ -19,7 +20,15 @@ func TestNotifyUserAppendEvent(t *testing.T) { { name: "append added user event", args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(nil))}, + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(nil))}, + user: &NotifyUser{}, + }, + result: &NotifyUser{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, + }, + { + name: "append added human event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(nil))}, user: &NotifyUser{}, }, result: &NotifyUser{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", FirstName: "FirstName", LastName: "LastName", LastEmail: "Email", LastPhone: "Phone"}, diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index 26cd02fd8..44aeecbe5 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -257,7 +257,7 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) { es_model.HumanMFAOTPRemoved: u.OTPState = int32(model.MfaStateUnspecified) case es_model.MFAInitSkipped, - es_model.HumanMfaInitSkipped: + es_model.HumanMFAInitSkipped: u.MfaInitSkipped = event.CreationDate case es_model.InitializedUserCodeAdded, es_model.InitializedHumanCodeAdded: diff --git a/internal/user/repository/view/model/user_session.go b/internal/user/repository/view/model/user_session.go index 7499abf40..669241af7 100644 --- a/internal/user/repository/view/model/user_session.go +++ b/internal/user/repository/view/model/user_session.go @@ -88,14 +88,14 @@ func (v *UserSessionView) AppendEvent(event *models.Event) { es_model.HumanPasswordCheckFailed, es_model.HumanPasswordChanged: v.PasswordVerification = time.Time{} - case es_model.MfaOtpCheckSucceeded, - es_model.HumanMfaOtpCheckSucceeded: + case es_model.MFAOTPCheckSucceeded, + es_model.HumanMFAOTPCheckSucceeded: v.MfaSoftwareVerification = event.CreationDate v.MfaSoftwareVerificationType = int32(req_model.MfaTypeOTP) v.State = int32(req_model.UserSessionStateActive) - case es_model.MfaOtpCheckFailed, + case es_model.MFAOTPCheckFailed, es_model.MFAOTPRemoved, - es_model.HumanMfaOtpCheckFailed, + es_model.HumanMFAOTPCheckFailed, es_model.HumanMFAOTPRemoved: v.MfaSoftwareVerification = time.Time{} case es_model.SignedOut, diff --git a/internal/user/repository/view/model/user_session_test.go b/internal/user/repository/view/model/user_session_test.go index 0e936fd16..38c51d335 100644 --- a/internal/user/repository/view/model/user_session_test.go +++ b/internal/user/repository/view/model/user_session_test.go @@ -25,7 +25,7 @@ func TestAppendEvent(t *testing.T) { result *UserSessionView }{ { - name: "append password check succeeded event", + name: "append user password check succeeded event", args: args{ event: &es_models.Event{CreationDate: now(), Type: es_model.UserPasswordCheckSucceeded}, userView: &UserSessionView{}, @@ -33,7 +33,15 @@ func TestAppendEvent(t *testing.T) { result: &UserSessionView{ChangeDate: now(), PasswordVerification: now()}, }, { - name: "append password check failed event", + name: "append human password check succeeded event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanPasswordCheckSucceeded}, + userView: &UserSessionView{}, + }, + result: &UserSessionView{ChangeDate: now(), PasswordVerification: now()}, + }, + { + name: "append user password check failed event", args: args{ event: &es_models.Event{CreationDate: now(), Type: es_model.UserPasswordCheckFailed}, userView: &UserSessionView{PasswordVerification: now()}, @@ -41,7 +49,15 @@ func TestAppendEvent(t *testing.T) { result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}}, }, { - name: "append password changed event", + name: "append human password check failed event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanPasswordCheckFailed}, + userView: &UserSessionView{PasswordVerification: now()}, + }, + result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}}, + }, + { + name: "append user password changed event", args: args{ event: &es_models.Event{CreationDate: now(), Type: es_model.UserPasswordChanged}, userView: &UserSessionView{PasswordVerification: now()}, @@ -49,37 +65,77 @@ func TestAppendEvent(t *testing.T) { result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}}, }, { - name: "append otp check succeeded event", + name: "append human password changed event", args: args{ - event: &es_models.Event{CreationDate: now(), Type: es_model.MfaOtpCheckSucceeded}, + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanPasswordChanged}, + userView: &UserSessionView{PasswordVerification: now()}, + }, + result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}}, + }, + { + name: "append user otp check succeeded event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPCheckSucceeded}, userView: &UserSessionView{}, }, result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: now()}, }, { - name: "append otp check failed event", + name: "append human otp check succeeded event", args: args{ - event: &es_models.Event{CreationDate: now(), Type: es_model.MfaOtpCheckFailed}, + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPCheckSucceeded}, + userView: &UserSessionView{}, + }, + result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: now()}, + }, + { + name: "append user otp check failed event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPCheckFailed}, userView: &UserSessionView{MfaSoftwareVerification: now()}, }, result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}}, }, { - name: "append otp removed event", + name: "append human otp check failed event", args: args{ - event: &es_models.Event{CreationDate: now(), Type: es_model.MfaOtpCheckFailed}, + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPCheckFailed}, userView: &UserSessionView{MfaSoftwareVerification: now()}, }, result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}}, }, { - name: "append otp removed event", + name: "append user otp removed event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.MFAOTPRemoved}, + userView: &UserSessionView{MfaSoftwareVerification: now()}, + }, + result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}}, + }, + { + name: "append human otp removed event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanMFAOTPRemoved}, + userView: &UserSessionView{MfaSoftwareVerification: now()}, + }, + result: &UserSessionView{ChangeDate: now(), MfaSoftwareVerification: time.Time{}}, + }, + { + name: "append user signed out event", args: args{ event: &es_models.Event{CreationDate: now(), Type: es_model.SignedOut}, userView: &UserSessionView{PasswordVerification: now(), MfaSoftwareVerification: now()}, }, result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, MfaSoftwareVerification: time.Time{}, State: 1}, }, + { + name: "append human signed out event", + args: args{ + event: &es_models.Event{CreationDate: now(), Type: es_model.HumanSignedOut}, + userView: &UserSessionView{PasswordVerification: now(), MfaSoftwareVerification: now()}, + }, + result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}, MfaSoftwareVerification: time.Time{}, State: 1}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/user/repository/view/model/user_test.go b/internal/user/repository/view/model/user_test.go index 090c165de..853a1e55b 100644 --- a/internal/user/repository/view/model/user_test.go +++ b/internal/user/repository/view/model/user_test.go @@ -11,7 +11,7 @@ import ( es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) -func mockUserData(user *es_model.Human) []byte { +func mockUserData(user *es_model.User) []byte { data, _ := json.Marshal(user) return data } @@ -41,22 +41,35 @@ func mockAddressData(address *es_model.Address) []byte { return data } -func getFullUser(password *es_model.Password) *es_model.Human { - return &es_model.Human{ - Profile: &es_model.Profile{ - FirstName: "FirstName", - LastName: "LastName", +func getFullHuman(password *es_model.Password) *es_model.User { + return &es_model.User{ + UserName: "UserName", + Human: &es_model.Human{ + Profile: &es_model.Profile{ + FirstName: "FirstName", + LastName: "LastName", + }, + Email: &es_model.Email{ + EmailAddress: "Email", + }, + Phone: &es_model.Phone{ + PhoneNumber: "Phone", + }, + Address: &es_model.Address{ + Country: "Country", + }, + Password: password, }, - Email: &es_model.Email{ - EmailAddress: "Email", + } +} + +func getFullMachine() *es_model.User { + return &es_model.User{ + UserName: "UserName", + Machine: &es_model.Machine{ + Description: "Description", + Name: "Machine", }, - Phone: &es_model.Phone{ - PhoneNumber: "Phone", - }, - Address: &es_model.Address{ - Country: "Country", - }, - Password: password, } } @@ -73,15 +86,39 @@ func TestUserAppendEvent(t *testing.T) { { name: "append added user event", args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(nil))}, + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(nil))}, user: &UserView{}, }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, }, + { + name: "append added human event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(nil))}, + user: &UserView{}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, + }, + { + name: "append added machine event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.MachineAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullMachine())}, + user: &UserView{}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", MachineView: &MachineView{Description: "Description", Name: "Machine"}, State: int32(model.UserStateActive)}, + }, { name: "append added user with password event", args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(&es_model.Password{Secret: &crypto.CryptoValue{}}))}, + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(&es_model.Password{Secret: &crypto.CryptoValue{}}))}, + user: &UserView{}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateInitial)}, + }, + { + name: "append added human with password event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(&es_model.Password{Secret: &crypto.CryptoValue{}}))}, user: &UserView{}, }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateInitial)}, @@ -89,13 +126,21 @@ func TestUserAppendEvent(t *testing.T) { { name: "append added user with password but change required event", args: args{ - event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullUser(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}}))}, + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}}))}, user: &UserView{}, }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateInitial)}, }, { - name: "append password change event", + name: "append added human with password but change required event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanAdded, ResourceOwner: "OrgID", Data: mockUserData(getFullHuman(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}}))}, + user: &UserView{}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateInitial)}, + }, + { + name: "append password change event on user", args: args{ event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{Secret: &crypto.CryptoValue{}})}, user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, @@ -103,13 +148,29 @@ func TestUserAppendEvent(t *testing.T) { result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateActive)}, }, { - name: "append password change with change required event", + name: "append password change event on human", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{Secret: &crypto.CryptoValue{}})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true}, State: int32(model.UserStateActive)}, + }, + { + name: "append password change with change required event on user", args: args{ event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.UserPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}})}, user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateActive)}, }, + { + name: "append password change with change required event on human", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanPasswordChanged, ResourceOwner: "OrgID", Data: mockPasswordData(&es_model.Password{ChangeRequired: true, Secret: &crypto.CryptoValue{}})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country", PasswordSet: true, PasswordChangeRequired: true}, State: int32(model.UserStateActive)}, + }, { name: "append change user profile event", args: args{ @@ -118,6 +179,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstNameChanged", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, }, + { + name: "append change human profile event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanProfileChanged, ResourceOwner: "OrgID", Data: mockProfileData(&es_model.Profile{FirstName: "FirstNameChanged"})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstNameChanged", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, + }, { name: "append change user email event", args: args{ @@ -126,6 +195,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "EmailChanged", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, }, + { + name: "append change human email event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanEmailChanged, ResourceOwner: "OrgID", Data: mockEmailData(&es_model.Email{EmailAddress: "EmailChanged"})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "EmailChanged", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, { name: "append verify user email event", args: args{ @@ -134,6 +211,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, }, + { + name: "append verify human email event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanEmailVerified, ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateInitial)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, { name: "append change user phone event", args: args{ @@ -142,6 +227,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "PhoneChanged", Country: "Country"}, State: int32(model.UserStateActive)}, }, + { + name: "append change human phone event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanPhoneChanged, ResourceOwner: "OrgID", Data: mockPhoneData(&es_model.Phone{PhoneNumber: "PhoneChanged"})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "PhoneChanged", Country: "Country"}, State: int32(model.UserStateActive)}, + }, { name: "append verify user phone event", args: args{ @@ -150,6 +243,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", IsPhoneVerified: true, Country: "Country"}, State: int32(model.UserStateActive)}, }, + { + name: "append verify human phone event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanPhoneVerified, ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", IsPhoneVerified: true, Country: "Country"}, State: int32(model.UserStateActive)}, + }, { name: "append change user address event", args: args{ @@ -158,6 +259,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "CountryChanged"}, State: int32(model.UserStateActive)}, }, + { + name: "append change human address event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanAddressChanged, ResourceOwner: "OrgID", Data: mockAddressData(&es_model.Address{Country: "CountryChanged"})}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", IsEmailVerified: true, Phone: "Phone", Country: "CountryChanged"}, State: int32(model.UserStateActive)}, + }, { name: "append user deactivate event", args: args{ @@ -198,6 +307,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateNotReady)}, State: int32(model.UserStateActive)}, }, + { + name: "append human add otp event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanMFAOTPAdded, ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateNotReady)}, State: int32(model.UserStateActive)}, + }, { name: "append user verify otp event", args: args{ @@ -206,6 +323,14 @@ func TestUserAppendEvent(t *testing.T) { }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateReady)}, State: int32(model.UserStateActive)}, }, + { + name: "append human verify otp event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanMFAOTPVerified, ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateNotReady)}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateReady)}, State: int32(model.UserStateActive)}, + }, { name: "append user remove otp event", args: args{ @@ -215,13 +340,29 @@ func TestUserAppendEvent(t *testing.T) { result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateUnspecified)}, State: int32(model.UserStateActive)}, }, { - name: "append mfa init skipped event", + name: "append human remove otp event", + args: args{ + event: &es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: es_model.HumanMFAOTPRemoved, ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateReady)}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", OTPState: int32(model.MfaStateUnspecified)}, State: int32(model.UserStateActive)}, + }, + { + name: "append user mfa init skipped event", args: args{ event: &es_models.Event{Sequence: 1, CreationDate: time.Now().UTC(), Type: es_model.MFAInitSkipped, AggregateID: "AggregateID", ResourceOwner: "OrgID"}, user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, }, result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", MfaInitSkipped: time.Now().UTC()}, State: int32(model.UserStateActive)}, }, + { + name: "append human mfa init skipped event", + args: args{ + event: &es_models.Event{Sequence: 1, CreationDate: time.Now().UTC(), Type: es_model.HumanMFAInitSkipped, AggregateID: "AggregateID", ResourceOwner: "OrgID"}, + user: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country"}, State: int32(model.UserStateActive)}, + }, + result: &UserView{ID: "AggregateID", ResourceOwner: "OrgID", UserName: "UserName", HumanView: &HumanView{FirstName: "FirstName", LastName: "LastName", Email: "Email", Phone: "Phone", Country: "Country", MfaInitSkipped: time.Now().UTC()}, State: int32(model.UserStateActive)}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -229,44 +370,46 @@ func TestUserAppendEvent(t *testing.T) { if tt.args.user.ID != tt.result.ID { t.Errorf("got wrong result ID: expected: %v, actual: %v ", tt.result.ID, tt.args.user.ID) } - if tt.args.user.FirstName != tt.result.FirstName { - t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, tt.args.user.FirstName) - } - if tt.args.user.LastName != tt.result.LastName { - t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, tt.args.user.FirstName) - } if tt.args.user.ResourceOwner != tt.result.ResourceOwner { t.Errorf("got wrong result ResourceOwner: expected: %v, actual: %v ", tt.result.ResourceOwner, tt.args.user.ResourceOwner) } - if tt.args.user.Email != tt.result.Email { - t.Errorf("got wrong result email: expected: %v, actual: %v ", tt.result.Email, tt.args.user.Email) - } - if tt.args.user.IsEmailVerified != tt.result.IsEmailVerified { - t.Errorf("got wrong result IsEmailVerified: expected: %v, actual: %v ", tt.result.IsEmailVerified, tt.args.user.IsEmailVerified) - } - if tt.args.user.Phone != tt.result.Phone { - t.Errorf("got wrong result Phone: expected: %v, actual: %v ", tt.result.Phone, tt.args.user.Phone) - } - if tt.args.user.IsPhoneVerified != tt.result.IsPhoneVerified { - t.Errorf("got wrong result IsPhoneVerified: expected: %v, actual: %v ", tt.result.IsPhoneVerified, tt.args.user.IsPhoneVerified) - } - if tt.args.user.Country != tt.result.Country { - t.Errorf("got wrong result Country: expected: %v, actual: %v ", tt.result.Country, tt.args.user.Country) - } if tt.args.user.State != tt.result.State { t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.result.State, tt.args.user.State) } - if tt.args.user.OTPState != tt.result.OTPState { - t.Errorf("got wrong result OTPState: expected: %v, actual: %v ", tt.result.OTPState, tt.args.user.OTPState) - } - if tt.args.user.MfaInitSkipped.Round(1*time.Second) != tt.result.MfaInitSkipped.Round(1*time.Second) { - t.Errorf("got wrong result MfaInitSkipped: expected: %v, actual: %v ", tt.result.MfaInitSkipped.Round(1*time.Second), tt.args.user.MfaInitSkipped.Round(1*time.Second)) - } - if tt.args.user.PasswordSet != tt.result.PasswordSet { - t.Errorf("got wrong result PasswordSet: expected: %v, actual: %v ", tt.result.PasswordSet, tt.args.user.PasswordSet) - } - if tt.args.user.PasswordChangeRequired != tt.result.PasswordChangeRequired { - t.Errorf("got wrong result PasswordChangeRequired: expected: %v, actual: %v ", tt.result.PasswordChangeRequired, tt.args.user.PasswordChangeRequired) + if human := tt.args.user.HumanView; human != nil { + if human.FirstName != tt.result.FirstName { + t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, tt.args.user.FirstName) + } + if human.LastName != tt.result.LastName { + t.Errorf("got wrong result FirstName: expected: %v, actual: %v ", tt.result.FirstName, human.FirstName) + } + if human.Email != tt.result.Email { + t.Errorf("got wrong result email: expected: %v, actual: %v ", tt.result.Email, human.Email) + } + if human.IsEmailVerified != tt.result.IsEmailVerified { + t.Errorf("got wrong result IsEmailVerified: expected: %v, actual: %v ", tt.result.IsEmailVerified, human.IsEmailVerified) + } + if human.Phone != tt.result.Phone { + t.Errorf("got wrong result Phone: expected: %v, actual: %v ", tt.result.Phone, human.Phone) + } + if human.IsPhoneVerified != tt.result.IsPhoneVerified { + t.Errorf("got wrong result IsPhoneVerified: expected: %v, actual: %v ", tt.result.IsPhoneVerified, human.IsPhoneVerified) + } + if human.Country != tt.result.Country { + t.Errorf("got wrong result Country: expected: %v, actual: %v ", tt.result.Country, human.Country) + } + if human.OTPState != tt.result.OTPState { + t.Errorf("got wrong result OTPState: expected: %v, actual: %v ", tt.result.OTPState, human.OTPState) + } + if human.MfaInitSkipped.Round(1*time.Second) != tt.result.MfaInitSkipped.Round(1*time.Second) { + t.Errorf("got wrong result MfaInitSkipped: expected: %v, actual: %v ", tt.result.MfaInitSkipped.Round(1*time.Second), human.MfaInitSkipped.Round(1*time.Second)) + } + if human.PasswordSet != tt.result.PasswordSet { + t.Errorf("got wrong result PasswordSet: expected: %v, actual: %v ", tt.result.PasswordSet, human.PasswordSet) + } + if human.PasswordChangeRequired != tt.result.PasswordChangeRequired { + t.Errorf("got wrong result PasswordChangeRequired: expected: %v, actual: %v ", tt.result.PasswordChangeRequired, human.PasswordChangeRequired) + } } }) }