mirror of
https://github.com/zitadel/zitadel.git
synced 2025-12-28 03:24:05 +00:00
Add extra checks for organization update
This commit is contained in:
@@ -43,3 +43,17 @@ func NewMultipleOrgsUpdatedError(id string, expected, actual int64) error {
|
||||
func (err *MultipleOrgsUpdatedError) Error() string {
|
||||
return fmt.Sprintf("ID=%s Message=expecting %d row(s) updated, got %d", err.ID, err.Expected, err.Actual)
|
||||
}
|
||||
|
||||
type OrgNameNotChangedError struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func NewOrgNameNotChangedError(errID string) error {
|
||||
return &OrgNameNotChangedError{
|
||||
ID: errID,
|
||||
}
|
||||
}
|
||||
|
||||
func (err *OrgNameNotChangedError) Error() string {
|
||||
return fmt.Sprintf("ID=%s Message=organization name has not changed", err.ID)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
@@ -31,10 +30,25 @@ func (u *UpdateOrgCommand) Execute(ctx context.Context, opts *CommandOpts) (err
|
||||
|
||||
organizationRepo := opts.orgRepo()
|
||||
|
||||
org, err := organizationRepo.Get(ctx, database.WithCondition(organizationRepo.IDCondition(u.ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if org.Name == u.Name {
|
||||
err = NewOrgNameNotChangedError("DOM-nDzwIu")
|
||||
return err
|
||||
}
|
||||
|
||||
if org.State == OrgStateInactive {
|
||||
err = NewOrgNotFoundError("DOM-OcA1jq")
|
||||
return err
|
||||
}
|
||||
|
||||
updateCount, err := organizationRepo.Update(
|
||||
ctx,
|
||||
organizationRepo.IDCondition(u.ID),
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
organizationRepo.IDCondition(org.ID),
|
||||
org.InstanceID,
|
||||
database.NewChange(organizationRepo.NameColumn(), u.Name),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -17,7 +17,10 @@ import (
|
||||
)
|
||||
|
||||
func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
txInitErr := errors.New("tx init error")
|
||||
getErr := errors.New("get error")
|
||||
updateErr := errors.New("update error")
|
||||
|
||||
tt := []struct {
|
||||
@@ -43,14 +46,79 @@ func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
},
|
||||
expectedError: txInitErr,
|
||||
},
|
||||
{
|
||||
testName: "when retrieving org fails should return error",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(nil, getErr)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
},
|
||||
inputID: "org-1",
|
||||
inputName: "test org update",
|
||||
expectedError: getErr,
|
||||
},
|
||||
{
|
||||
testName: "when org name is not changed should return name not changed error",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "test org update",
|
||||
}, nil)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
},
|
||||
inputID: "org-1",
|
||||
inputName: "test org update",
|
||||
expectedError: domain.NewOrgNameNotChangedError("DOM-nDzwIu"),
|
||||
},
|
||||
{
|
||||
testName: "when org is inactive should return not found error",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "old org name",
|
||||
State: domain.OrgStateInactive,
|
||||
}, nil)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
},
|
||||
inputID: "org-1",
|
||||
inputName: "test org update",
|
||||
expectedError: domain.NewOrgNotFoundError("DOM-OcA1jq"),
|
||||
},
|
||||
{
|
||||
testName: "when org update fails should return error",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "old org name",
|
||||
InstanceID: "instance-1",
|
||||
State: domain.OrgStateActive,
|
||||
}, nil)
|
||||
|
||||
repo.EXPECT().
|
||||
Update(gomock.Any(), repo.IDCondition("org-1"), "instance-1", repo.SetName("test org update")).
|
||||
Return(int64(0), updateErr).
|
||||
AnyTimes()
|
||||
Times(1).
|
||||
Return(int64(0), updateErr)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
@@ -65,10 +133,20 @@ func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
inputName: "test org update",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "old org name",
|
||||
InstanceID: "instance-1",
|
||||
State: domain.OrgStateActive,
|
||||
}, nil)
|
||||
|
||||
repo.EXPECT().
|
||||
Update(gomock.Any(), repo.IDCondition("org-1"), "instance-1", repo.SetName("test org update")).
|
||||
Return(int64(0), nil).
|
||||
AnyTimes()
|
||||
Times(1).
|
||||
Return(int64(0), nil)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
@@ -79,10 +157,20 @@ func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
testName: "when org update returns more than 1 row updated should return internal error",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "old org name",
|
||||
InstanceID: "instance-1",
|
||||
State: domain.OrgStateActive,
|
||||
}, nil)
|
||||
|
||||
repo.EXPECT().
|
||||
Update(gomock.Any(), repo.IDCondition("org-1"), "instance-1", repo.SetName("test org update")).
|
||||
Return(int64(2), nil).
|
||||
AnyTimes()
|
||||
Times(1).
|
||||
Return(int64(2), nil)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
@@ -95,10 +183,20 @@ func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
testName: "when org update returns 1 row updated should return no error and set cache",
|
||||
orgRepo: func(ctrl *gomock.Controller) func(database.QueryExecutor) domain.OrganizationRepository {
|
||||
repo := domainmock.NewOrgRepo(ctrl)
|
||||
repo.EXPECT().
|
||||
Get(gomock.Any(), gomock.Any()).
|
||||
Times(1).
|
||||
Return(&domain.Organization{
|
||||
ID: "org-1",
|
||||
Name: "old org name",
|
||||
InstanceID: "instance-1",
|
||||
State: domain.OrgStateActive,
|
||||
}, nil)
|
||||
|
||||
repo.EXPECT().
|
||||
Update(gomock.Any(), repo.IDCondition("org-1"), "instance-1", repo.SetName("test org update")).
|
||||
Return(int64(1), nil).
|
||||
AnyTimes()
|
||||
Times(1).
|
||||
Return(int64(1), nil)
|
||||
return func(_ database.QueryExecutor) domain.OrganizationRepository {
|
||||
return repo
|
||||
}
|
||||
@@ -129,6 +227,7 @@ func TestUpdateOrgCommand_Execute(t *testing.T) {
|
||||
opts.DB = tc.queryExecutor(ctrl)
|
||||
}
|
||||
|
||||
// Test
|
||||
err := cmd.Execute(ctx, opts)
|
||||
|
||||
// Verify
|
||||
|
||||
Reference in New Issue
Block a user