mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:47:32 +00:00
feat(api): add password reset and change to user service (#6036)
* feat(api): add password reset and change to user service * integration tests * invalidate password check after password change * handle notification type * fix proto
This commit is contained in:
611
internal/command/user_v2_password_test.go
Normal file
611
internal/command/user_v2_password_test.go
Normal file
@@ -0,0 +1,611 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
func TestCommands_RequestPasswordReset(t *testing.T) {
|
||||
type fields struct {
|
||||
checkPermission domain.PermissionCheck
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
userEncryption crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
userID string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "missing userID",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "",
|
||||
},
|
||||
wantErr: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SAFdda", "Errors.User.IDMissing"),
|
||||
},
|
||||
{
|
||||
name: "user not existing",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-SAF4f", "Errors.User.NotFound"),
|
||||
},
|
||||
{
|
||||
name: "user not initialized",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("code")}, 10*time.Second),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sfe4g", "Errors.User.NotInitialised"),
|
||||
},
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
userEncryption: tt.fields.userEncryption,
|
||||
}
|
||||
_, _, err := c.RequestPasswordReset(tt.args.ctx, tt.args.userID)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_requestPasswordReset
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_RequestPasswordResetReturnCode(t *testing.T) {
|
||||
type fields struct {
|
||||
checkPermission domain.PermissionCheck
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
userEncryption crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
userID string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "missing userID",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "",
|
||||
},
|
||||
wantErr: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SAFdda", "Errors.User.IDMissing"),
|
||||
},
|
||||
{
|
||||
name: "user not existing",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-SAF4f", "Errors.User.NotFound"),
|
||||
},
|
||||
{
|
||||
name: "user not initialized",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("code")}, 10*time.Second),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sfe4g", "Errors.User.NotInitialised"),
|
||||
},
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
userEncryption: tt.fields.userEncryption,
|
||||
}
|
||||
_, _, err := c.RequestPasswordResetReturnCode(tt.args.ctx, tt.args.userID)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_requestPasswordReset
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_RequestPasswordResetURLTemplate(t *testing.T) {
|
||||
type fields struct {
|
||||
checkPermission domain.PermissionCheck
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
userEncryption crypto.EncryptionAlgorithm
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
userID string
|
||||
urlTmpl string
|
||||
notificationType domain.NotificationType
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "invalid template",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
userID: "user1",
|
||||
urlTmpl: "{{",
|
||||
},
|
||||
wantErr: caos_errs.ThrowInvalidArgument(nil, "DOMAIN-oGh5e", "Errors.User.InvalidURLTemplate"),
|
||||
},
|
||||
|
||||
{
|
||||
name: "missing userID",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "",
|
||||
},
|
||||
wantErr: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SAFdda", "Errors.User.IDMissing"),
|
||||
},
|
||||
{
|
||||
name: "user not existing",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-SAF4f", "Errors.User.NotFound"),
|
||||
},
|
||||
{
|
||||
name: "user not initialized",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("code")}, 10*time.Second),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sfe4g", "Errors.User.NotInitialised"),
|
||||
},
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
wantErr: caos_errs.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
userEncryption: tt.fields.userEncryption,
|
||||
}
|
||||
_, _, err := c.RequestPasswordResetURLTemplate(tt.args.ctx, tt.args.userID, tt.args.urlTmpl, tt.args.notificationType)
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
// successful cases are tested in TestCommands_requestPasswordReset
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommands_requestPasswordReset(t *testing.T) {
|
||||
type fields struct {
|
||||
checkPermission domain.PermissionCheck
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
userEncryption crypto.EncryptionAlgorithm
|
||||
newCode cryptoCodeFunc
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
userID string
|
||||
returnCode bool
|
||||
urlTmpl string
|
||||
notificationType domain.NotificationType
|
||||
}
|
||||
type res struct {
|
||||
details *domain.ObjectDetails
|
||||
code *string
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "missing userID",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-SAFdda", "Errors.User.IDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user not existing",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.ThrowNotFound(nil, "COMMAND-SAF4f", "Errors.User.NotFound"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user not initialized",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
user.NewHumanInitialCodeAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{CryptoType: crypto.TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("code")}, 10*time.Second),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Sfe4g", "Errors.User.NotInitialised"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "missing permission",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckNotAllowed(),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
res: res{
|
||||
err: caos_errs.ThrowPermissionDenied(nil, "AUTHZ-HKJD33", "Errors.PermissionDenied"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "code generated",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
user.NewHumanPasswordCodeAddedEventV2(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("code"),
|
||||
},
|
||||
10*time.Minute,
|
||||
domain.NotificationTypeEmail,
|
||||
"",
|
||||
false,
|
||||
)),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
newCode: mockCode("code", 10*time.Minute),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
},
|
||||
res: res{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
code: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "code generated template",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
user.NewHumanPasswordCodeAddedEventV2(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("code"),
|
||||
},
|
||||
10*time.Minute,
|
||||
domain.NotificationTypeEmail,
|
||||
"https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
false,
|
||||
)),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
newCode: mockCode("code", 10*time.Minute),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
urlTmpl: "https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
},
|
||||
res: res{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
code: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "code generated template sms",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
user.NewHumanPasswordCodeAddedEventV2(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("code"),
|
||||
},
|
||||
10*time.Minute,
|
||||
domain.NotificationTypeSms,
|
||||
"https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
false,
|
||||
)),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
newCode: mockCode("code", 10*time.Minute),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
urlTmpl: "https://example.com/password/changey?userID={{.UserID}}&code={{.Code}}&orgID={{.OrgID}}",
|
||||
notificationType: domain.NotificationTypeSms,
|
||||
},
|
||||
res: res{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
code: nil,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "code generated returned",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewHumanAddedEvent(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
"username", "firstname", "lastname", "nickname", "displayname",
|
||||
language.English, domain.GenderUnspecified, "email", false),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
eventPusherToEvents(
|
||||
user.NewHumanPasswordCodeAddedEventV2(context.Background(), &user.NewAggregate("userID", "org1").Aggregate,
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("code"),
|
||||
},
|
||||
10*time.Minute,
|
||||
domain.NotificationTypeEmail,
|
||||
"",
|
||||
true,
|
||||
)),
|
||||
),
|
||||
),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
newCode: mockCode("code", 10*time.Minute),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
userID: "userID",
|
||||
returnCode: true,
|
||||
},
|
||||
res: res{
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
code: gu.Ptr("code"),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
c := &Commands{
|
||||
checkPermission: tt.fields.checkPermission,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
userEncryption: tt.fields.userEncryption,
|
||||
newCode: tt.fields.newCode,
|
||||
}
|
||||
got, gotPlainCode, err := c.requestPasswordReset(tt.args.ctx, tt.args.userID, tt.args.returnCode, tt.args.urlTmpl, tt.args.notificationType)
|
||||
require.ErrorIs(t, err, tt.res.err)
|
||||
assert.Equal(t, tt.res.details, got)
|
||||
assert.Equal(t, tt.res.code, gotPlainCode)
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user