2019-07-31 22:56:46 +05:30
# frozen_string_literal: true
2016-06-02 11:05:42 +05:30
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec . describe Groups :: UpdateService do
2017-08-17 22:00:37 +05:30
let! ( :user ) { create ( :user ) }
let! ( :private_group ) { create ( :group , :private ) }
let! ( :internal_group ) { create ( :group , :internal ) }
let! ( :public_group ) { create ( :group , :public ) }
2016-06-02 11:05:42 +05:30
describe " # execute " do
2020-10-24 23:57:45 +05:30
shared_examples 'with packages' do
before do
group . add_owner ( user )
end
context 'with npm packages' do
let! ( :package ) { create ( :npm_package , project : project ) }
it 'does not allow a path update' do
expect ( update_group ( group , user , path : 'updated' ) ) . to be false
expect ( group . errors [ :path ] ) . to include ( 'cannot change when group contains projects with NPM packages' )
end
it 'allows name update' do
expect ( update_group ( group , user , name : 'Updated' ) ) . to be true
expect ( group . errors ) . to be_empty
expect ( group . name ) . to eq ( 'Updated' )
end
end
end
context 'with project' do
let! ( :group ) { create ( :group , :public ) }
let ( :project ) { create ( :project , namespace : group ) }
it_behaves_like 'with packages'
context 'located in a subgroup' do
let ( :subgroup ) { create ( :group , parent : group ) }
let! ( :project ) { create ( :project , namespace : subgroup ) }
before do
subgroup . add_owner ( user )
end
it_behaves_like 'with packages'
it 'does allow a path update if there is not a root namespace change' do
expect ( update_group ( subgroup , user , path : 'updated' ) ) . to be true
expect ( subgroup . errors [ :path ] ) . to be_empty
end
end
end
2016-06-02 11:05:42 +05:30
context " project visibility_level validation " do
context " public group with public projects " do
2017-08-17 22:00:37 +05:30
let! ( :service ) { described_class . new ( public_group , user , visibility_level : Gitlab :: VisibilityLevel :: INTERNAL ) }
2016-06-02 11:05:42 +05:30
before do
2022-08-13 15:12:31 +05:30
public_group . add_member ( user , Gitlab :: Access :: OWNER )
2017-09-10 17:25:29 +05:30
create ( :project , :public , group : public_group )
2018-11-18 11:00:15 +05:30
expect ( TodosDestroyer :: GroupPrivateWorker ) . not_to receive ( :perform_in )
2016-06-02 11:05:42 +05:30
end
it " does not change permission level " do
service . execute
expect ( public_group . errors . count ) . to eq ( 1 )
2018-11-18 11:00:15 +05:30
expect ( TodosDestroyer :: GroupPrivateWorker ) . not_to receive ( :perform_in )
2016-06-02 11:05:42 +05:30
end
2018-12-13 13:39:08 +05:30
it " returns false if save failed " do
allow ( public_group ) . to receive ( :save ) . and_return ( false )
expect ( service . execute ) . to be_falsey
end
2019-12-26 22:10:19 +05:30
context 'when a project has container images' do
let ( :params ) { { path : SecureRandom . hex } }
let! ( :container_repository ) { create ( :container_repository , project : project ) }
subject { described_class . new ( public_group , user , params ) . execute }
context 'within group' do
let ( :project ) { create ( :project , group : public_group ) }
context 'with path updates' do
it 'does not allow the update' do
expect ( subject ) . to be false
expect ( public_group . errors [ :base ] . first ) . to match ( / Docker images in their Container Registry / )
end
end
context 'with name updates' do
let ( :params ) { { name : 'new-name' } }
it 'allows the update' do
expect ( subject ) . to be true
expect ( public_group . reload . name ) . to eq ( 'new-name' )
end
end
end
context 'within subgroup' do
let ( :subgroup ) { create ( :group , parent : public_group ) }
let ( :project ) { create ( :project , group : subgroup ) }
it 'does not allow path updates' do
expect ( subject ) . to be false
expect ( public_group . errors [ :base ] . first ) . to match ( / Docker images in their Container Registry / )
end
end
end
2016-06-02 11:05:42 +05:30
end
context " internal group with internal project " do
2017-08-17 22:00:37 +05:30
let! ( :service ) { described_class . new ( internal_group , user , visibility_level : Gitlab :: VisibilityLevel :: PRIVATE ) }
2016-06-02 11:05:42 +05:30
before do
2022-08-13 15:12:31 +05:30
internal_group . add_member ( user , Gitlab :: Access :: OWNER )
2017-09-10 17:25:29 +05:30
create ( :project , :internal , group : internal_group )
2018-11-18 11:00:15 +05:30
expect ( TodosDestroyer :: GroupPrivateWorker ) . not_to receive ( :perform_in )
2016-06-02 11:05:42 +05:30
end
it " does not change permission level " do
service . execute
expect ( internal_group . errors . count ) . to eq ( 1 )
end
end
2018-11-18 11:00:15 +05:30
context " internal group with private project " do
let! ( :service ) { described_class . new ( internal_group , user , visibility_level : Gitlab :: VisibilityLevel :: PRIVATE ) }
before do
2022-08-13 15:12:31 +05:30
internal_group . add_member ( user , Gitlab :: Access :: OWNER )
2018-11-18 11:00:15 +05:30
create ( :project , :private , group : internal_group )
expect ( TodosDestroyer :: GroupPrivateWorker ) . to receive ( :perform_in )
2019-01-03 12:48:30 +05:30
. with ( Todo :: WAIT_FOR_DELETE , internal_group . id )
2018-11-18 11:00:15 +05:30
end
it " changes permission level to private " do
service . execute
expect ( internal_group . visibility_level )
. to eq ( Gitlab :: VisibilityLevel :: PRIVATE )
end
end
2016-06-02 11:05:42 +05:30
end
2017-08-17 22:00:37 +05:30
context " with parent_id user doesn't have permissions for " do
let ( :service ) { described_class . new ( public_group , user , parent_id : private_group . id ) }
before do
service . execute
end
it 'does not update parent_id' do
updated_group = public_group . reload
expect ( updated_group . parent_id ) . to be_nil
end
end
2022-03-02 08:16:31 +05:30
context 'crm_enabled param' do
context 'when no existing crm_settings' do
it 'when param not present, leave crm disabled' do
params = { }
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_falsey
end
it 'when param set true, enables crm' do
params = { crm_enabled : true }
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_truthy
end
end
context 'with existing crm_settings' do
it 'when param set true, enables crm' do
params = { crm_enabled : true }
create ( :crm_settings , group : public_group )
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_truthy
end
it 'when param set false, disables crm' do
params = { crm_enabled : false }
create ( :crm_settings , group : public_group , enabled : true )
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_falsy
end
it 'when param not present, crm remains disabled' do
params = { }
create ( :crm_settings , group : public_group )
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_falsy
end
it 'when param not present, crm remains enabled' do
params = { }
create ( :crm_settings , group : public_group , enabled : true )
described_class . new ( public_group , user , params ) . execute
updated_group = public_group . reload
expect ( updated_group . crm_enabled? ) . to be_truthy
end
end
end
2016-06-02 11:05:42 +05:30
end
context " unauthorized visibility_level validation " do
2017-08-17 22:00:37 +05:30
let! ( :service ) { described_class . new ( internal_group , user , visibility_level : 99 ) }
2019-10-12 21:52:04 +05:30
2016-06-02 11:05:42 +05:30
before do
2022-08-13 15:12:31 +05:30
internal_group . add_member ( user , Gitlab :: Access :: MAINTAINER )
2016-06-02 11:05:42 +05:30
end
it " does not change permission level " do
service . execute
expect ( internal_group . errors . count ) . to eq ( 1 )
end
end
2017-08-17 22:00:37 +05:30
2022-07-29 17:44:30 +05:30
context 'when user is not group owner' do
context 'when group is private' do
before do
private_group . add_maintainer ( user )
end
it 'does not update the group to public' do
result = described_class . new ( private_group , user , visibility_level : Gitlab :: VisibilityLevel :: PUBLIC ) . execute
expect ( result ) . to eq ( false )
expect ( private_group . errors . count ) . to eq ( 1 )
expect ( private_group ) . to be_private
end
it 'does not update the group to public with tricky value' do
result = described_class . new ( private_group , user , visibility_level : Gitlab :: VisibilityLevel :: PUBLIC . to_s + 'r' ) . execute
expect ( result ) . to eq ( false )
expect ( private_group . errors . count ) . to eq ( 1 )
expect ( private_group ) . to be_private
end
end
context 'when group is public' do
before do
public_group . add_maintainer ( user )
end
it 'does not update the group to private' do
result = described_class . new ( public_group , user , visibility_level : Gitlab :: VisibilityLevel :: PRIVATE ) . execute
expect ( result ) . to eq ( false )
expect ( public_group . errors . count ) . to eq ( 1 )
expect ( public_group ) . to be_public
end
it 'does not update the group to private with invalid string value' do
result = described_class . new ( public_group , user , visibility_level : 'invalid' ) . execute
expect ( result ) . to eq ( false )
expect ( public_group . errors . count ) . to eq ( 1 )
expect ( public_group ) . to be_public
end
it 'does not update the group to private with valid string value' do
result = described_class . new ( public_group , user , visibility_level : 'private' ) . execute
expect ( result ) . to eq ( false )
expect ( public_group . errors . count ) . to eq ( 1 )
expect ( public_group ) . to be_public
end
# See https://gitlab.com/gitlab-org/gitlab/-/issues/359910
it 'does not update the group to private because of Active Record typecasting' do
result = described_class . new ( public_group , user , visibility_level : 'public' ) . execute
expect ( result ) . to eq ( true )
expect ( public_group . errors . count ) . to eq ( 0 )
expect ( public_group ) . to be_public
end
end
end
2019-10-12 21:52:04 +05:30
context 'when updating #emails_disabled' do
let ( :service ) { described_class . new ( internal_group , user , emails_disabled : true ) }
it 'updates the attribute' do
2022-08-13 15:12:31 +05:30
internal_group . add_member ( user , Gitlab :: Access :: OWNER )
2019-10-12 21:52:04 +05:30
expect { service . execute } . to change { internal_group . emails_disabled } . to ( true )
end
it 'does not update when not group owner' do
expect { service . execute } . not_to change { internal_group . emails_disabled }
end
end
2020-05-24 23:13:21 +05:30
context 'updating default_branch_protection' do
let ( :service ) do
described_class . new ( internal_group , user , default_branch_protection : Gitlab :: Access :: PROTECTION_NONE )
end
context 'for users who have the ability to update default_branch_protection' do
it 'updates the attribute' do
internal_group . add_owner ( user )
expect { service . execute } . to change { internal_group . default_branch_protection } . to ( Gitlab :: Access :: PROTECTION_NONE )
end
end
context 'for users who do not have the ability to update default_branch_protection' do
it 'does not update the attribute' do
expect { service . execute } . not_to change { internal_group . default_branch_protection }
end
end
end
2022-08-27 11:52:29 +05:30
context 'EventStore' do
let ( :service ) { described_class . new ( group , user , ** params ) }
let ( :root_group ) { create ( :group , path : 'root' ) }
let ( :group ) do
create ( :group , parent : root_group , path : 'old-path' ) . tap { | g | g . add_owner ( user ) }
end
context 'when changing a group path' do
let ( :new_path ) { SecureRandom . hex }
let ( :params ) { { path : new_path } }
it 'publishes a GroupPathChangedEvent' do
old_path = group . full_path
expect { service . execute }
. to publish_event ( Groups :: GroupPathChangedEvent )
. with (
group_id : group . id ,
root_namespace_id : group . root_ancestor . id ,
old_path : old_path ,
new_path : " root/ #{ new_path } "
)
end
end
context 'when not changing a group path' do
let ( :params ) { { name : 'very-new-name' } }
it 'does not publish a GroupPathChangedEvent' do
expect { service . execute }
. not_to publish_event ( Groups :: GroupPathChangedEvent )
end
end
end
2017-08-17 22:00:37 +05:30
context 'rename group' do
2022-08-27 11:52:29 +05:30
let ( :new_path ) { SecureRandom . hex }
let! ( :service ) { described_class . new ( internal_group , user , path : new_path ) }
2017-08-17 22:00:37 +05:30
before do
2022-08-13 15:12:31 +05:30
internal_group . add_member ( user , Gitlab :: Access :: MAINTAINER )
2017-09-10 17:25:29 +05:30
create ( :project , :internal , group : internal_group )
2017-08-17 22:00:37 +05:30
end
it 'returns true' do
expect ( service . execute ) . to eq ( true )
end
context 'error moving group' do
before do
allow ( internal_group ) . to receive ( :move_dir ) . and_raise ( Gitlab :: UpdatePathError )
end
it 'does not raise an error' do
expect { service . execute } . not_to raise_error
end
it 'returns false' do
expect ( service . execute ) . to eq ( false )
end
it 'has the right error' do
service . execute
expect ( internal_group . errors . full_messages . first ) . to eq ( 'Gitlab::UpdatePathError' )
end
it " hasn't changed the path " do
2022-08-27 11:52:29 +05:30
expect { service . execute } . not_to change { internal_group . reload . path }
2017-08-17 22:00:37 +05:30
end
end
end
2018-03-17 18:26:18 +05:30
2019-10-12 21:52:04 +05:30
context 'for a subgroup' do
2018-03-17 18:26:18 +05:30
let ( :subgroup ) { create ( :group , :private , parent : private_group ) }
context 'when the parent group share_with_group_lock is enabled' do
before do
private_group . update_column ( :share_with_group_lock , true )
end
context 'for the parent group owner' do
it 'allows disabling share_with_group_lock' do
private_group . add_owner ( user )
result = described_class . new ( subgroup , user , share_with_group_lock : false ) . execute
expect ( result ) . to be_truthy
expect ( subgroup . reload . share_with_group_lock ) . to be_falsey
end
end
context 'for a subgroup owner (who does not own the parent)' do
it 'does not allow disabling share_with_group_lock' do
subgroup_owner = create ( :user )
subgroup . add_owner ( subgroup_owner )
result = described_class . new ( subgroup , subgroup_owner , share_with_group_lock : false ) . execute
expect ( result ) . to be_falsey
expect ( subgroup . errors . full_messages . first ) . to match ( / cannot be disabled when the parent group "Share with group lock" is enabled, except by the owner of the parent group / )
expect ( subgroup . reload . share_with_group_lock ) . to be_truthy
end
end
end
end
2020-10-24 23:57:45 +05:30
2021-01-03 14:25:43 +05:30
context 'change shared Runners config' do
let ( :group ) { create ( :group ) }
let ( :project ) { create ( :project , shared_runners_enabled : true , group : group ) }
2021-11-18 22:05:49 +05:30
subject { described_class . new ( group , user , shared_runners_setting : Namespace :: SR_DISABLED_AND_UNOVERRIDABLE ) . execute }
2021-01-03 14:25:43 +05:30
before do
group . add_owner ( user )
end
it 'calls the shared runners update service' do
expect_any_instance_of ( :: Groups :: UpdateSharedRunnersService ) . to receive ( :execute ) . and_return ( { status : :success } )
expect ( subject ) . to be_truthy
end
it 'handles errors in the shared runners update service' do
expect_any_instance_of ( :: Groups :: UpdateSharedRunnersService ) . to receive ( :execute ) . and_return ( { status : :error , message : 'something happened' } )
expect ( subject ) . to be_falsy
expect ( group . errors [ :update_shared_runners ] . first ) . to eq ( 'something happened' )
end
end
context 'changes allowing subgroups to establish own 2FA' do
let ( :group ) { create ( :group ) }
let ( :params ) { { allow_mfa_for_subgroups : false } }
subject { described_class . new ( group , user , params ) . execute }
it 'changes settings' do
subject
expect ( group . namespace_settings . reload . allow_mfa_for_subgroups ) . to eq ( false )
end
it 'enqueues update subgroups and its members' do
expect ( DisallowTwoFactorForSubgroupsWorker ) . to receive ( :perform_async ) . with ( group . id )
subject
end
end
2020-10-24 23:57:45 +05:30
def update_group ( group , user , opts )
Groups :: UpdateService . new ( group , user , opts ) . execute
end
2016-06-02 11:05:42 +05:30
end