mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved As part of https://github.com/zitadel/zitadel/issues/11917 we want to introduce error slugs so (API) clients can rely on stable, machine-readable errors and act accordingly. # How the Problems Are Solved - Added a `NewSlug` helper function in the domain package. - Added `ErrorDetails` to the `ZitadelError` - Added an `zitadel.error.v2.ErrorDetail` proto message - Updated the connectRPC error interceptor to map new slug based errors to the new `ErrorDetail` - Defined some common slugs and error functions like internal errors - Defined (session) specific slugs used in the `DeleteSession` and `CheckUser` functions and replaced old implementations - Updated integration tests to check specific errors if the relation database feature is enabled - Updated doc and guideline to reflect the latest changes and decisions - Updated DeleteSession endpoint API to list possible slugs # Additional Changes None # Additional Context - closes #11957 --------- Co-authored-by: Wim Van Laer <[email protected]>
736 lines
21 KiB
Go
736 lines
21 KiB
Go
package domain_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/mock/gomock"
|
|
"golang.org/x/text/language"
|
|
|
|
"github.com/zitadel/zitadel/backend/v3/domain"
|
|
domainmock "github.com/zitadel/zitadel/backend/v3/domain/mock"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
|
"github.com/zitadel/zitadel/backend/v3/storage/database/dbmock"
|
|
noopdb "github.com/zitadel/zitadel/backend/v3/storage/database/dialect/noop"
|
|
"github.com/zitadel/zitadel/internal/api/authz"
|
|
"github.com/zitadel/zitadel/internal/repository/session"
|
|
"github.com/zitadel/zitadel/internal/zerrors"
|
|
)
|
|
|
|
func TestUserCheckCommand_Validate(t *testing.T) {
|
|
t.Parallel()
|
|
getErr := errors.New("get error")
|
|
permissionErr := errors.New("permission denied")
|
|
notFoundErr := database.NewNoRowFoundError(nil)
|
|
|
|
tt := []struct {
|
|
testName string
|
|
userRepo func(ctrl *gomock.Controller) domain.UserRepository
|
|
permissionChecker func(ctrl *gomock.Controller) domain.PermissionRepository
|
|
cmd *domain.UserCheckCommand
|
|
expectedError error
|
|
}{
|
|
{
|
|
testName: "when CheckUser is nil should return no error",
|
|
cmd: &domain.UserCheckCommand{},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
testName: "when session ID is not set should return error",
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
},
|
|
expectedError: domain.ErrIDMissing(),
|
|
},
|
|
{
|
|
testName: "when instance ID is not set should return error",
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
},
|
|
expectedError: domain.ErrInstanceIDMissing(),
|
|
},
|
|
{
|
|
testName: "when permission check fails should return permission denied error",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(permissionErr)
|
|
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: zerrors.ThrowPermissionDenied(permissionErr, "DOM-4qz3mt", "Errors.PermissionDenied"),
|
|
},
|
|
{
|
|
testName: "when search type is UserId should fetch user by ID",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
userRepo: func(ctrl *gomock.Controller) domain.UserRepository {
|
|
repo := domainmock.NewUserRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("user-123"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
State: domain.UserStateActive,
|
|
}, nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
testName: "when user not active should return precondition failed error",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
userRepo: func(ctrl *gomock.Controller) domain.UserRepository {
|
|
repo := domainmock.NewUserRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("user-123"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
State: domain.UserStateInactive,
|
|
}, nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: domain.ErrUserNotActive("user-123", ""),
|
|
},
|
|
{
|
|
testName: "when user retrieval fails should return error",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
userRepo: func(ctrl *gomock.Controller) domain.UserRepository {
|
|
repo := domainmock.NewUserRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("user-123"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(nil, getErr)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: domain.ErrInternal(getErr, ""),
|
|
},
|
|
{
|
|
testName: "when user not found should return not found error",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
userRepo: func(ctrl *gomock.Controller) domain.UserRepository {
|
|
repo := domainmock.NewUserRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("user-123"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(nil, notFoundErr)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: domain.ErrUserNotFound(notFoundErr, "user-123"),
|
|
},
|
|
{
|
|
testName: "when search type is LoginName should attempt to fetch by login name",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
userRepo: func(ctrl *gomock.Controller) domain.UserRepository {
|
|
repo := domainmock.NewUserRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.LoginNameCondition(database.TextOperationEqual, "[email protected]"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.User{
|
|
ID: "user-123",
|
|
LoginNames: []domain.LoginName{{LoginName: "[email protected]"}},
|
|
OrganizationID: "org-1",
|
|
State: domain.UserStateActive,
|
|
}, nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{LoginName: "[email protected]"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
testName: "when search type is unknown should return invalid argument error",
|
|
permissionChecker: func(ctrl *gomock.Controller) domain.PermissionRepository {
|
|
repo := domainmock.NewMockPermissionChecker(ctrl)
|
|
|
|
repo.EXPECT().
|
|
CheckSessionPermission(gomock.Any(), domain.SessionWritePermission, "session-1").
|
|
Times(1).
|
|
Return(nil)
|
|
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
expectedError: domain.ErrInvalidRequest(""),
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
t.Parallel()
|
|
// Given
|
|
ctx := authz.NewMockContext(tc.cmd.InstanceID, "", "")
|
|
ctrl := gomock.NewController(t)
|
|
cmd := domain.NewUserCheckCommand(tc.cmd.SessionID, tc.cmd.InstanceID, tc.cmd.InputCheckUser)
|
|
|
|
opts := &domain.InvokeOpts{
|
|
Invoker: domain.NewTransactionInvoker(nil),
|
|
}
|
|
domain.WithQueryExecutor(new(noopdb.Pool))(opts)
|
|
if tc.userRepo != nil {
|
|
domain.WithUserRepo(tc.userRepo(ctrl))(opts)
|
|
}
|
|
if tc.permissionChecker != nil {
|
|
domain.WithPermissionChecker(tc.permissionChecker(ctrl))(opts)
|
|
}
|
|
|
|
// Test
|
|
err := cmd.Validate(ctx, opts)
|
|
|
|
// Verify
|
|
assert.ErrorIs(t, err, tc.expectedError)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUserCheckCommand_Execute(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
sessionNotFoundErr := database.NewNoRowFoundError(nil)
|
|
getErr := errors.New("get error")
|
|
updateErr := errors.New("update error")
|
|
|
|
tt := []struct {
|
|
testName string
|
|
sessionRepo func(ctrl *gomock.Controller) domain.SessionRepository
|
|
cmd *domain.UserCheckCommand
|
|
expectedError error
|
|
expectedPreferredLanguage *language.Tag
|
|
}{
|
|
{
|
|
testName: "when CheckUser is nil should return no error",
|
|
cmd: &domain.UserCheckCommand{},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
testName: "when session retrieval fails should return error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(nil, getErr)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
expectedError: domain.ErrInternal(getErr, ""),
|
|
},
|
|
{
|
|
testName: "when session not found should return not found error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(nil, sessionNotFoundErr)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
Human: &domain.HumanUser{
|
|
PreferredLanguage: language.Italian,
|
|
},
|
|
},
|
|
},
|
|
expectedError: domain.ErrSessionNotFound(sessionNotFoundErr, "session-1"),
|
|
},
|
|
{
|
|
testName: "when user change is attempted should return invalid argument error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "user-456",
|
|
}, nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
expectedError: domain.ErrSessionUserChange(),
|
|
},
|
|
{
|
|
testName: "when session update fails should return error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "user-123",
|
|
}, nil)
|
|
|
|
repo.EXPECT().
|
|
Update(gomock.Any(), gomock.Any(), repo.IDCondition("session-1"), repo.SetFactor(&domain.SessionFactorUser{
|
|
UserID: "user-123",
|
|
LastVerifiedAt: time.Now(),
|
|
})).
|
|
Times(1).
|
|
Return(int64(0), updateErr)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
expectedError: domain.ErrInternal(updateErr, "failed to update the session"),
|
|
},
|
|
{
|
|
testName: "when session update returns no rows should return not found error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "",
|
|
}, nil)
|
|
|
|
repo.EXPECT().
|
|
Update(gomock.Any(), gomock.Any(), repo.IDCondition("session-1"), repo.SetFactor(&domain.SessionFactorUser{
|
|
UserID: "user-123",
|
|
LastVerifiedAt: time.Now(),
|
|
})).
|
|
Times(1).
|
|
Return(int64(0), nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
expectedError: domain.ErrSessionNotFound(nil, "session-1"),
|
|
},
|
|
{
|
|
testName: "when session update returns multiple rows should return internal error",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "",
|
|
}, nil)
|
|
|
|
repo.EXPECT().
|
|
Update(gomock.Any(), gomock.Any(), repo.IDCondition("session-1"), repo.SetFactor(&domain.SessionFactorUser{
|
|
UserID: "user-123",
|
|
LastVerifiedAt: time.Now(),
|
|
})).
|
|
Times(1).
|
|
Return(int64(2), nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
expectedError: domain.ErrMoreThanOneRowAffected("unexpected number of rows updated", 2),
|
|
},
|
|
{
|
|
testName: "when session has no user and user is set should execute successfully",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "",
|
|
}, nil)
|
|
|
|
repo.EXPECT().
|
|
Update(gomock.Any(), gomock.Any(), repo.IDCondition("session-1"), repo.SetFactor(&domain.SessionFactorUser{
|
|
UserID: "user-123",
|
|
LastVerifiedAt: time.Now(),
|
|
})).
|
|
Times(1).
|
|
Return(int64(1), nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
Human: &domain.HumanUser{
|
|
PreferredLanguage: language.Albanian,
|
|
},
|
|
},
|
|
},
|
|
expectedPreferredLanguage: &language.Albanian,
|
|
},
|
|
{
|
|
testName: "when session user matches fetched user should execute successfully",
|
|
sessionRepo: func(ctrl *gomock.Controller) domain.SessionRepository {
|
|
repo := domainmock.NewSessionRepo(ctrl)
|
|
repo.EXPECT().
|
|
Get(gomock.Any(), gomock.Any(), dbmock.QueryOptions(
|
|
database.WithCondition(
|
|
repo.IDCondition("session-1"),
|
|
),
|
|
)).
|
|
Times(1).
|
|
Return(&domain.Session{
|
|
ID: "session-1",
|
|
UserID: "user-123",
|
|
}, nil)
|
|
|
|
repo.EXPECT().
|
|
Update(gomock.Any(), gomock.Any(), repo.IDCondition("session-1"), repo.SetFactor(&domain.SessionFactorUser{
|
|
UserID: "user-123",
|
|
LastVerifiedAt: time.Now(),
|
|
})).
|
|
Times(1).
|
|
Return(int64(1), nil)
|
|
return repo
|
|
},
|
|
cmd: &domain.UserCheckCommand{
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{
|
|
ID: "user-123",
|
|
OrganizationID: "org-1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
t.Parallel()
|
|
// Given
|
|
ctx := authz.NewMockContext("instance-1", "", "")
|
|
ctrl := gomock.NewController(t)
|
|
opts := &domain.InvokeOpts{
|
|
Invoker: domain.NewTransactionInvoker(nil),
|
|
}
|
|
domain.WithQueryExecutor(new(noopdb.Pool))(opts)
|
|
if tc.sessionRepo != nil {
|
|
domain.WithSessionRepo(tc.sessionRepo(ctrl))(opts)
|
|
}
|
|
|
|
// Test
|
|
err := tc.cmd.Execute(ctx, opts)
|
|
|
|
// Verify
|
|
assert.ErrorIs(t, err, tc.expectedError)
|
|
if tc.expectedError == nil && tc.cmd.InputCheckUser != nil {
|
|
assert.NotZero(t, tc.cmd.UserCheckedAt)
|
|
assert.Equal(t, tc.expectedPreferredLanguage, tc.cmd.PreferredUserLanguage)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUserCheckCommand_Events(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tt := []struct {
|
|
testName string
|
|
cmd *domain.UserCheckCommand
|
|
expectedEventLen int
|
|
expectedError error
|
|
}{
|
|
{
|
|
testName: "when CheckUser is nil should return nil",
|
|
cmd: &domain.UserCheckCommand{},
|
|
expectedEventLen: 0,
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
testName: "when CheckUser is set should return user checked event",
|
|
cmd: &domain.UserCheckCommand{
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
FetchedUser: domain.User{ID: "user-123", OrganizationID: "org-1"},
|
|
UserCheckedAt: time.Now(),
|
|
InputCheckUser: &domain.CheckUserType{UserID: "user-123"},
|
|
},
|
|
expectedEventLen: 1,
|
|
expectedError: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
t.Parallel()
|
|
// Given
|
|
ctx := authz.NewMockContext(tc.cmd.InstanceID, "", "")
|
|
opts := &domain.InvokeOpts{
|
|
Invoker: domain.NewTransactionInvoker(nil),
|
|
}
|
|
|
|
// Test
|
|
events, err := tc.cmd.Events(ctx, opts)
|
|
|
|
// Verify
|
|
assert.Equal(t, tc.expectedError, err)
|
|
require.Len(t, events, tc.expectedEventLen)
|
|
if tc.expectedEventLen != 0 {
|
|
usrCheckedEvent, ok := events[0].(*session.UserCheckedEvent)
|
|
require.True(t, ok)
|
|
|
|
assert.Equal(t, tc.cmd.FetchedUser.ID, usrCheckedEvent.UserID)
|
|
assert.Equal(t, tc.cmd.FetchedUser.OrganizationID, usrCheckedEvent.UserResourceOwner)
|
|
assert.NotZero(t, usrCheckedEvent.CheckedAt)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewUserCheckCommand(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tt := []struct {
|
|
testName string
|
|
sessionID string
|
|
instanceID string
|
|
checkUser *domain.CheckUserType
|
|
expected *domain.UserCheckCommand
|
|
}{
|
|
{
|
|
testName: "should create command with provided sessionID, instanceID and checkUserType",
|
|
sessionID: "session-1",
|
|
instanceID: "instance-1",
|
|
checkUser: &domain.CheckUserType{},
|
|
expected: &domain.UserCheckCommand{
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
InputCheckUser: &domain.CheckUserType{},
|
|
},
|
|
},
|
|
{
|
|
testName: "should create command with empty sessionID",
|
|
sessionID: "",
|
|
instanceID: "instance-1",
|
|
checkUser: &domain.CheckUserType{},
|
|
expected: &domain.UserCheckCommand{
|
|
SessionID: "",
|
|
InstanceID: "instance-1",
|
|
InputCheckUser: &domain.CheckUserType{},
|
|
},
|
|
},
|
|
{
|
|
testName: "should create command with empty instanceID",
|
|
sessionID: "session-1",
|
|
instanceID: "",
|
|
checkUser: &domain.CheckUserType{},
|
|
expected: &domain.UserCheckCommand{
|
|
SessionID: "session-1",
|
|
InstanceID: "",
|
|
InputCheckUser: &domain.CheckUserType{},
|
|
},
|
|
},
|
|
{
|
|
testName: "should create command with nil checkUserType",
|
|
sessionID: "session-1",
|
|
instanceID: "instance-1",
|
|
expected: &domain.UserCheckCommand{
|
|
SessionID: "session-1",
|
|
InstanceID: "instance-1",
|
|
},
|
|
},
|
|
{
|
|
testName: "should create command with all empty",
|
|
sessionID: "",
|
|
instanceID: "",
|
|
expected: &domain.UserCheckCommand{
|
|
SessionID: "",
|
|
InstanceID: "",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tt {
|
|
t.Run(tc.testName, func(t *testing.T) {
|
|
t.Parallel()
|
|
// Test
|
|
cmd := domain.NewUserCheckCommand(tc.sessionID, tc.instanceID, tc.checkUser)
|
|
|
|
// Verify
|
|
assert.Equal(t, tc.expected.SessionID, cmd.SessionID)
|
|
assert.Equal(t, tc.expected.InstanceID, cmd.InstanceID)
|
|
assert.Equal(t, tc.expected.InputCheckUser, cmd.InputCheckUser)
|
|
assert.Zero(t, cmd.UserCheckedAt)
|
|
assert.Nil(t, cmd.PreferredUserLanguage)
|
|
assert.Zero(t, cmd.FetchedUser)
|
|
})
|
|
}
|
|
}
|