diff options
author | Douwe Maan <douwe@gitlab.com> | 2017-09-07 18:29:47 +0000 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2017-09-07 18:29:47 +0000 |
commit | 22d6e69ecf004060de31823a8242d249a88c4e46 (patch) | |
tree | c83345b5ee54b32268ca70daedcbdc058ad25ca6 /spec | |
parent | 6a4ebc4a9bbc93d627f9da0091dd5050db1a916b (diff) | |
parent | 95f4dd4f1501f3901908f444790eea06f3d703bb (diff) | |
download | gitlab-ce-22d6e69ecf004060de31823a8242d249a88c4e46.tar.gz |
Merge branch 'improve-share-locking-feature-for-subgroups' into 'master'
Improve "Share with group lock" feature for subgroups
Closes #30550
See merge request !13944
Diffstat (limited to 'spec')
-rw-r--r-- | spec/features/groups/share_lock_spec.rb | 62 | ||||
-rw-r--r-- | spec/features/projects/group_links_spec.rb | 77 | ||||
-rw-r--r-- | spec/features/projects/members/groups_with_access_list_spec.rb (renamed from spec/features/projects/members/group_links_spec.rb) | 14 | ||||
-rw-r--r-- | spec/features/projects/members/share_with_group_spec.rb | 191 | ||||
-rw-r--r-- | spec/helpers/groups_helper_spec.rb | 93 | ||||
-rw-r--r-- | spec/models/namespace_spec.rb | 112 | ||||
-rw-r--r-- | spec/policies/group_policy_spec.rb | 90 | ||||
-rw-r--r-- | spec/services/groups/update_service_spec.rb | 34 | ||||
-rw-r--r-- | spec/views/groups/edit.html.haml_spec.rb | 116 |
9 files changed, 705 insertions, 84 deletions
diff --git a/spec/features/groups/share_lock_spec.rb b/spec/features/groups/share_lock_spec.rb new file mode 100644 index 00000000000..8842d1391aa --- /dev/null +++ b/spec/features/groups/share_lock_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +feature 'Group share with group lock' do + given(:root_owner) { create(:user) } + given(:root_group) { create(:group) } + + background do + root_group.add_owner(root_owner) + sign_in(root_owner) + end + + context 'with a subgroup', :nested_groups do + given!(:subgroup) { create(:group, parent: root_group) } + + context 'when enabling the parent group share with group lock' do + scenario 'the subgroup share with group lock becomes enabled' do + visit edit_group_path(root_group) + check 'group_share_with_group_lock' + + click_on 'Save group' + + expect(subgroup.reload.share_with_group_lock?).to be_truthy + end + end + + context 'when disabling the parent group share with group lock (which was already enabled)' do + background do + visit edit_group_path(root_group) + check 'group_share_with_group_lock' + click_on 'Save group' + end + + context 'and the subgroup share with group lock is enabled' do + scenario 'the subgroup share with group lock does not change' do + visit edit_group_path(root_group) + uncheck 'group_share_with_group_lock' + + click_on 'Save group' + + expect(subgroup.reload.share_with_group_lock?).to be_truthy + end + end + + context 'but the subgroup share with group lock is disabled' do + background do + visit edit_group_path(subgroup) + uncheck 'group_share_with_group_lock' + click_on 'Save group' + end + + scenario 'the subgroup share with group lock does not change' do + visit edit_group_path(root_group) + uncheck 'group_share_with_group_lock' + + click_on 'Save group' + + expect(subgroup.reload.share_with_group_lock?).to be_falsey + end + end + end + end +end diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb deleted file mode 100644 index 5195d027a9f..00000000000 --- a/spec/features/projects/group_links_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'spec_helper' - -feature 'Project group links', :js do - include Select2Helper - - let(:master) { create(:user) } - let(:project) { create(:project) } - let!(:group) { create(:group) } - - background do - project.add_master(master) - sign_in(master) - end - - context 'setting an expiration date for a group link' do - before do - visit project_settings_members_path(project) - - click_on 'share-with-group-tab' - - select2 group.id, from: '#link_group_id' - fill_in 'expires_at_groups', with: (Time.current + 4.5.days).strftime('%Y-%m-%d') - page.find('body').click - find('.btn-create').trigger('click') - end - - it 'shows the expiration time with a warning class' do - page.within('.project-members-groups') do - expect(page).to have_content('Expires in 4 days') - expect(page).to have_selector('.text-warning') - end - end - end - - context 'nested group project' do - let!(:nested_group) { create(:group, parent: group) } - let!(:another_group) { create(:group) } - let!(:project) { create(:project, namespace: nested_group) } - - background do - group.add_master(master) - another_group.add_master(master) - end - - it 'does not show ancestors', :nested_groups do - visit project_settings_members_path(project) - - click_on 'share-with-group-tab' - click_link 'Search for a group' - - page.within '.select2-drop' do - expect(page).to have_content(another_group.name) - expect(page).not_to have_content(group.name) - end - end - end - - describe 'the groups dropdown' do - before do - group_two = create(:group) - group.add_owner(master) - group_two.add_owner(master) - - visit project_settings_members_path(project) - execute_script 'GroupsSelect.PER_PAGE = 1;' - open_select2 '#link_group_id' - end - - it 'should infinitely scroll' do - expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 1) - - scroll_select2_to_bottom('.select2-drop .select2-results:visible') - - expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 2) - end - end -end diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb index 1c348b987d4..9950272af08 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/groups_with_access_list_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Anonymous user sees members', js: true do +feature 'Projects > Members > Groups with access list', js: true do let(:user) { create(:user) } let(:group) { create(:group, :public) } let(:project) { create(:project, :public) } @@ -13,7 +13,7 @@ feature 'Projects > Members > Anonymous user sees members', js: true do visit project_settings_members_path(project) end - it 'updates group access level' do + scenario 'updates group access level' do click_button @group_link.human_access page.within '.dropdown-menu' do @@ -27,7 +27,7 @@ feature 'Projects > Members > Anonymous user sees members', js: true do expect(first('.group_member')).to have_content('Guest') end - it 'updates expiry date' do + scenario 'updates expiry date' do tomorrow = Date.today + 3 fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F") @@ -38,7 +38,7 @@ feature 'Projects > Members > Anonymous user sees members', js: true do end end - it 'deletes group link' do + scenario 'deletes group link' do page.within(first('.group_member')) do find('.btn-remove').click end @@ -47,8 +47,8 @@ feature 'Projects > Members > Anonymous user sees members', js: true do expect(page).not_to have_selector('.group_member') end - context 'search' do - it 'finds no results' do + context 'search in existing members (yes, this filters the groups list as well)' do + scenario 'finds no results' do page.within '.member-search-form' do fill_in 'search', with: 'testing 123' find('.member-search-btn').click @@ -57,7 +57,7 @@ feature 'Projects > Members > Anonymous user sees members', js: true do expect(page).not_to have_selector('.group_member') end - it 'finds results' do + scenario 'finds results' do page.within '.member-search-form' do fill_in 'search', with: group.name find('.member-search-btn').click diff --git a/spec/features/projects/members/share_with_group_spec.rb b/spec/features/projects/members/share_with_group_spec.rb new file mode 100644 index 00000000000..3b368f8e25d --- /dev/null +++ b/spec/features/projects/members/share_with_group_spec.rb @@ -0,0 +1,191 @@ +require 'spec_helper' + +feature 'Project > Members > Share with Group', :js do + include Select2Helper + include ActionView::Helpers::DateHelper + + let(:master) { create(:user) } + + describe 'Share with group lock' do + shared_examples 'the project can be shared with groups' do + scenario 'the "Share with group" tab exists' do + visit project_settings_members_path(project) + expect(page).to have_selector('#share-with-group-tab') + end + end + + shared_examples 'the project cannot be shared with groups' do + scenario 'the "Share with group" tab does not exist' do + visit project_settings_members_path(project) + expect(page).to have_selector('#add-member-tab') + expect(page).not_to have_selector('#share-with-group-tab') + end + end + + context 'for a project in a root group' do + let!(:group_to_share_with) { create(:group) } + let(:project) { create(:project, namespace: create(:group)) } + + background do + project.add_master(master) + sign_in(master) + end + + context 'when the group has "Share with group lock" disabled' do + it_behaves_like 'the project can be shared with groups' + + scenario 'the project can be shared with another group' do + visit project_settings_members_path(project) + + click_on 'share-with-group-tab' + + select2 group_to_share_with.id, from: '#link_group_id' + page.find('body').click + find('.btn-create').trigger('click') + + page.within('.project-members-groups') do + expect(page).to have_content(group_to_share_with.name) + end + end + end + + context 'when the group has "Share with group lock" enabled' do + before do + project.namespace.update_column(:share_with_group_lock, true) + end + + it_behaves_like 'the project cannot be shared with groups' + end + end + + context 'for a project in a subgroup', :nested_groups do + let!(:group_to_share_with) { create(:group) } + let(:root_group) { create(:group) } + let(:subgroup) { create(:group, parent: root_group) } + let(:project) { create(:project, namespace: subgroup) } + + background do + project.add_master(master) + sign_in(master) + end + + context 'when the root_group has "Share with group lock" disabled' do + context 'when the subgroup has "Share with group lock" disabled' do + it_behaves_like 'the project can be shared with groups' + end + + context 'when the subgroup has "Share with group lock" enabled' do + before do + subgroup.update_column(:share_with_group_lock, true) + end + + it_behaves_like 'the project cannot be shared with groups' + end + end + + context 'when the root_group has "Share with group lock" enabled' do + before do + root_group.update_column(:share_with_group_lock, true) + end + + context 'when the subgroup has "Share with group lock" disabled (parent overridden)' do + it_behaves_like 'the project can be shared with groups' + end + + context 'when the subgroup has "Share with group lock" enabled' do + before do + subgroup.update_column(:share_with_group_lock, true) + end + + it_behaves_like 'the project cannot be shared with groups' + end + end + end + end + + describe 'setting an expiration date for a group link' do + let(:project) { create(:project) } + let!(:group) { create(:group) } + + around do |example| + Timecop.freeze { example.run } + end + + before do + project.add_master(master) + sign_in(master) + + visit project_settings_members_path(project) + + click_on 'share-with-group-tab' + + select2 group.id, from: '#link_group_id' + + fill_in 'expires_at_groups', with: (Time.now + 4.5.days).strftime('%Y-%m-%d') + page.find('body').click + find('.btn-create').trigger('click') + end + + scenario 'the group link shows the expiration time with a warning class' do + page.within('.project-members-groups') do + # Using distance_of_time_in_words_to_now because it is not the same as + # subtraction, and this way avoids time zone issues as well + expires_in_text = distance_of_time_in_words_to_now(project.project_group_links.first.expires_at) + expect(page).to have_content(expires_in_text) + expect(page).to have_selector('.text-warning') + end + end + end + + describe 'the groups dropdown' do + context 'with multiple groups to choose from' do + let(:project) { create(:project) } + + background do + project.add_master(master) + sign_in(master) + + create(:group).add_owner(master) + create(:group).add_owner(master) + + visit project_settings_members_path(project) + execute_script 'GroupsSelect.PER_PAGE = 1;' + open_select2 '#link_group_id' + end + + it 'should infinitely scroll' do + expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 1) + + scroll_select2_to_bottom('.select2-drop .select2-results:visible') + + expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 2) + end + end + + context 'for a project in a nested group' do + let(:group) { create(:group) } + let!(:nested_group) { create(:group, parent: group) } + let!(:group_to_share_with) { create(:group) } + let!(:project) { create(:project, namespace: nested_group) } + + background do + project.add_master(master) + sign_in(master) + group.add_master(master) + group_to_share_with.add_master(master) + end + + scenario 'the groups dropdown does not show ancestors', :nested_groups do + visit project_settings_members_path(project) + + click_on 'share-with-group-tab' + click_link 'Search for a group' + + page.within '.select2-drop' do + expect(page).to have_content(group_to_share_with.name) + expect(page).not_to have_content(group.name) + end + end + end + end +end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 05f969904f5..36031ac1a28 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -95,4 +95,97 @@ describe GroupsHelper do .to match(/<li style="text-indent: 16px;"><a.*>#{deep_nested_group.name}.*<\/li>.*<a.*>#{very_deep_nested_group.name}<\/a>/m) end end + + # rubocop:disable Layout/SpaceBeforeComma + describe '#share_with_group_lock_help_text', :nested_groups do + let!(:root_group) { create(:group) } + let!(:subgroup) { create(:group, parent: root_group) } + let!(:sub_subgroup) { create(:group, parent: subgroup) } + let(:root_owner) { create(:user) } + let(:sub_owner) { create(:user) } + let(:sub_sub_owner) { create(:user) } + let(:possible_help_texts) do + { + default_help: "This setting will be applied to all subgroups unless overridden by a group owner", + ancestor_locked_but_you_can_override: /This setting is applied on <a .+>.+<\/a>\. You can override the setting or .+/, + ancestor_locked_so_ask_the_owner: /This setting is applied on .+\. To share projects in this group with another group, ask the owner to override the setting or remove the share with group lock from .+/, + ancestor_locked_and_has_been_overridden: /This setting is applied on .+ and has been overridden on this subgroup/ + } + end + let(:possible_linked_ancestors) do + { + root_group: root_group, + subgroup: subgroup + } + end + let(:users) do + { + root_owner: root_owner, + sub_owner: sub_owner, + sub_sub_owner: sub_sub_owner + } + end + subject { helper.share_with_group_lock_help_text(sub_subgroup) } + + where(:root_share_with_group_locked, :subgroup_share_with_group_locked, :sub_subgroup_share_with_group_locked, :current_user, :help_text, :linked_ancestor) do + [ + [false , false , false , :root_owner , :default_help , nil], + [false , false , false , :sub_owner , :default_help , nil], + [false , false , false , :sub_sub_owner , :default_help , nil], + [false , false , true , :root_owner , :default_help , nil], + [false , false , true , :sub_owner , :default_help , nil], + [false , false , true , :sub_sub_owner , :default_help , nil], + [false , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :subgroup], + [false , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup], + [false , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :subgroup], + [false , true , true , :root_owner , :ancestor_locked_but_you_can_override , :subgroup], + [false , true , true , :sub_owner , :ancestor_locked_but_you_can_override , :subgroup], + [false , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :subgroup], + [true , false , false , :root_owner , :default_help , nil], + [true , false , false , :sub_owner , :default_help , nil], + [true , false , false , :sub_sub_owner , :default_help , nil], + [true , false , true , :root_owner , :default_help , nil], + [true , false , true , :sub_owner , :default_help , nil], + [true , false , true , :sub_sub_owner , :default_help , nil], + [true , true , false , :root_owner , :ancestor_locked_and_has_been_overridden , :root_group], + [true , true , false , :sub_owner , :ancestor_locked_and_has_been_overridden , :root_group], + [true , true , false , :sub_sub_owner , :ancestor_locked_and_has_been_overridden , :root_group], + [true , true , true , :root_owner , :ancestor_locked_but_you_can_override , :root_group], + [true , true , true , :sub_owner , :ancestor_locked_so_ask_the_owner , :root_group], + [true , true , true , :sub_sub_owner , :ancestor_locked_so_ask_the_owner , :root_group] + ] + end + + with_them do + before do + root_group.add_owner(root_owner) + subgroup.add_owner(sub_owner) + sub_subgroup.add_owner(sub_sub_owner) + + root_group.update_column(:share_with_group_lock, true) if root_share_with_group_locked + subgroup.update_column(:share_with_group_lock, true) if subgroup_share_with_group_locked + sub_subgroup.update_column(:share_with_group_lock, true) if sub_subgroup_share_with_group_locked + + allow(helper).to receive(:current_user).and_return(users[current_user]) + allow(helper).to receive(:can?) + .with(users[current_user], :change_share_with_group_lock, subgroup) + .and_return(Ability.allowed?(users[current_user], :change_share_with_group_lock, subgroup)) + + ancestor = possible_linked_ancestors[linked_ancestor] + if ancestor + allow(helper).to receive(:can?) + .with(users[current_user], :read_group, ancestor) + .and_return(Ability.allowed?(users[current_user], :read_group, ancestor)) + allow(helper).to receive(:can?) + .with(users[current_user], :admin_group, ancestor) + .and_return(Ability.allowed?(users[current_user], :admin_group, ancestor)) + end + end + + it 'has the correct help text with correct ancestor links' do + expect(subject).to match(possible_help_texts[help_text]) + expect(subject).to match(possible_linked_ancestors[linked_ancestor].name) unless help_text == :default_help + end + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index f5f83f0f114..81d5ab7a6d3 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -406,4 +406,116 @@ describe Namespace do it { expect(group.all_projects.to_a).to match_array([project2, project1]) } end + + describe '#share_with_group_lock with subgroups', :nested_groups do + context 'when creating a subgroup' do + let(:subgroup) { create(:group, parent: root_group )} + + context 'under a parent with "Share with group lock" enabled' do + let(:root_group) { create(:group, share_with_group_lock: true) } + + it 'enables "Share with group lock" on the subgroup' do + expect(subgroup.share_with_group_lock).to be_truthy + end + end + + context 'under a parent with "Share with group lock" disabled' do + let(:root_group) { create(:group) } + + it 'does not enable "Share with group lock" on the subgroup' do + expect(subgroup.share_with_group_lock).to be_falsey + end + end + end + + context 'when enabling the parent group "Share with group lock"' do + let(:root_group) { create(:group) } + let!(:subgroup) { create(:group, parent: root_group )} + + it 'the subgroup "Share with group lock" becomes enabled' do + root_group.update!(share_with_group_lock: true) + + expect(subgroup.reload.share_with_group_lock).to be_truthy + end + end + + context 'when disabling the parent group "Share with group lock" (which was already enabled)' do + let(:root_group) { create(:group, share_with_group_lock: true) } + + context 'and the subgroup "Share with group lock" is enabled' do + let(:subgroup) { create(:group, parent: root_group, share_with_group_lock: true )} + + it 'the subgroup "Share with group lock" does not change' do + root_group.update!(share_with_group_lock: false) + + expect(subgroup.reload.share_with_group_lock).to be_truthy + end + end + + context 'but the subgroup "Share with group lock" is disabled' do + let(:subgroup) { create(:group, parent: root_group )} + + it 'the subgroup "Share with group lock" does not change' do + root_group.update!(share_with_group_lock: false) + + expect(subgroup.reload.share_with_group_lock?).to be_falsey + end + end + end + + # Note: Group transfers are not yet implemented + context 'when a group is transferred into a root group' do + context 'when the root group "Share with group lock" is enabled' do + let(:root_group) { create(:group, share_with_group_lock: true) } + + context 'when the subgroup "Share with group lock" is enabled' do + let(:subgroup) { create(:group, share_with_group_lock: true )} + + it 'the subgroup "Share with group lock" does not change' do + subgroup.parent = root_group + subgroup.save! + + expect(subgroup.share_with_group_lock).to be_truthy + end + end + + context 'when the subgroup "Share with group lock" is disabled' do + let(:subgroup) { create(:group)} + + it 'the subgroup "Share with group lock" becomes enabled' do + subgroup.parent = root_group + subgroup.save! + + expect(subgroup.share_with_group_lock).to be_truthy + end + end + end + + context 'when the root group "Share with group lock" is disabled' do + let(:root_group) { create(:group) } + + context 'when the subgroup "Share with group lock" is enabled' do + let(:subgroup) { create(:group, share_with_group_lock: true )} + + it 'the subgroup "Share with group lock" does not change' do + subgroup.parent = root_group + subgroup.save! + + expect(subgroup.share_with_group_lock).to be_truthy + end + end + + context 'when the subgroup "Share with group lock" is disabled' do + let(:subgroup) { create(:group)} + + it 'the subgroup "Share with group lock" does not change' do + subgroup.parent = root_group + subgroup.save! + + expect(subgroup.share_with_group_lock).to be_falsey + end + end + end + end + end end diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 7f832bfa563..0c4044dc7ab 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -242,4 +242,94 @@ describe GroupPolicy do end end end + + describe 'change_share_with_group_lock' do + context 'when the current_user owns the group' do + let(:current_user) { owner } + + context 'when the group share_with_group_lock is enabled' do + let(:group) { create(:group, share_with_group_lock: true, parent: parent) } + + context 'when the parent group share_with_group_lock is enabled' do + context 'when the group has a grandparent' do + let(:parent) { create(:group, share_with_group_lock: true, parent: grandparent) } + + context 'when the grandparent share_with_group_lock is enabled' do + let(:grandparent) { create(:group, share_with_group_lock: true) } + + context 'when the current_user owns the parent' do + before do + parent.add_owner(current_user) + end + + context 'when the current_user owns the grandparent' do + before do + grandparent.add_owner(current_user) + end + + it { expect_allowed(:change_share_with_group_lock) } + end + + context 'when the current_user does not own the grandparent' do + it { expect_disallowed(:change_share_with_group_lock) } + end + end + + context 'when the current_user does not own the parent' do + it { expect_disallowed(:change_share_with_group_lock) } + end + end + + context 'when the grandparent share_with_group_lock is disabled' do + let(:grandparent) { create(:group) } + + context 'when the current_user owns the parent' do + before do + parent.add_owner(current_user) + end + + it { expect_allowed(:change_share_with_group_lock) } + end + + context 'when the current_user does not own the parent' do + it { expect_disallowed(:change_share_with_group_lock) } + end + end + end + + context 'when the group does not have a grandparent' do + let(:parent) { create(:group, share_with_group_lock: true) } + + context 'when the current_user owns the parent' do + before do + parent.add_owner(current_user) + end + + it { expect_allowed(:change_share_with_group_lock) } + end + + context 'when the current_user does not own the parent' do + it { expect_disallowed(:change_share_with_group_lock) } + end + end + end + + context 'when the parent group share_with_group_lock is disabled' do + let(:parent) { create(:group) } + + it { expect_allowed(:change_share_with_group_lock) } + end + end + + context 'when the group share_with_group_lock is disabled' do + it { expect_allowed(:change_share_with_group_lock) } + end + end + + context 'when the current_user does not own the group' do + let(:current_user) { create(:user) } + + it { expect_disallowed(:change_share_with_group_lock) } + end + end end diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 44f22a3b37b..1737fd0a9fc 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -100,4 +100,38 @@ describe Groups::UpdateService do end end end + + context 'for a subgroup', :nested_groups do + 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 end diff --git a/spec/views/groups/edit.html.haml_spec.rb b/spec/views/groups/edit.html.haml_spec.rb new file mode 100644 index 00000000000..38cfb84f0d5 --- /dev/null +++ b/spec/views/groups/edit.html.haml_spec.rb @@ -0,0 +1,116 @@ +require 'spec_helper' + +describe 'groups/edit.html.haml' do + include Devise::Test::ControllerHelpers + + describe '"Share with group lock" setting' do + let(:root_owner) { create(:user) } + let(:root_group) { create(:group) } + + before do + root_group.add_owner(root_owner) + end + + shared_examples_for '"Share with group lock" setting' do |checkbox_options| + it 'should have the correct label, help text, and checkbox options' do + assign(:group, test_group) + allow(view).to receive(:can?).with(test_user, :admin_group, test_group).and_return(true) + allow(view).to receive(:can_change_group_visibility_level?).and_return(false) + allow(view).to receive(:current_user).and_return(test_user) + expect(view).to receive(:can_change_share_with_group_lock?).and_return(!checkbox_options[:disabled]) + expect(view).to receive(:share_with_group_lock_help_text).and_return('help text here') + + render + + expect(rendered).to have_content("Prevent sharing a project within #{test_group.name} with other groups") + expect(rendered).to have_css('.descr', text: 'help text here') + expect(rendered).to have_field('group_share_with_group_lock', checkbox_options) + end + end + + context 'for a root group' do + let(:test_group) { root_group } + let(:test_user) { root_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } + end + + context 'for a subgroup', :nested_groups do + let!(:subgroup) { create(:group, parent: root_group) } + let(:sub_owner) { create(:user) } + let(:test_group) { subgroup } + + context 'when the root_group has "Share with group lock" disabled' do + context 'when the subgroup has "Share with group lock" disabled' do + context 'as the root_owner' do + let(:test_user) { root_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } + end + + context 'as the sub_owner' do + let(:test_user) { sub_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } + end + end + + context 'when the subgroup has "Share with group lock" enabled' do + before do + subgroup.update_column(:share_with_group_lock, true) + end + + context 'as the root_owner' do + let(:test_user) { root_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: true } + end + + context 'as the sub_owner' do + let(:test_user) { sub_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: true } + end + end + end + + context 'when the root_group has "Share with group lock" enabled' do + before do + root_group.update_column(:share_with_group_lock, true) + end + + context 'when the subgroup has "Share with group lock" disabled (parent overridden)' do + context 'as the root_owner' do + let(:test_user) { root_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } + end + + context 'as the sub_owner' do + let(:test_user) { sub_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: false } + end + end + + context 'when the subgroup has "Share with group lock" enabled (same as parent)' do + before do + subgroup.update_column(:share_with_group_lock, true) + end + + context 'as the root_owner' do + let(:test_user) { root_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: false, checked: true } + end + + context 'as the sub_owner' do + let(:test_user) { sub_owner } + + it_behaves_like '"Share with group lock" setting', { disabled: true, checked: true } + end + end + end + end + end +end |