From f61bb2a16a514b71bf33aabbbb999d6732016a24 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 20 Apr 2021 14:36:54 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-11-stable-ee --- spec/models/group_spec.rb | 367 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 312 insertions(+), 55 deletions(-) (limited to 'spec/models/group_spec.rb') diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 24d09d1c035..2f82d8a0bbe 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Group do + include ReloadHelpers + let!(:group) { create(:group) } describe 'associations' do @@ -281,7 +283,7 @@ RSpec.describe Group do end describe '#two_factor_authentication_allowed' do - let_it_be(:group) { create(:group) } + let_it_be_with_reload(:group) { create(:group) } context 'for a parent group' do it 'is valid' do @@ -311,6 +313,120 @@ RSpec.describe Group do end end + context 'traversal_ids on create' do + context 'default traversal_ids' do + let(:group) { build(:group) } + + before do + group.save! + group.reload + end + + it { expect(group.traversal_ids).to eq [group.id] } + end + + context 'has a parent' do + let(:parent) { create(:group) } + let(:group) { build(:group, parent: parent) } + + before do + group.save! + reload_models(parent, group) + end + + it { expect(parent.traversal_ids).to eq [parent.id] } + it { expect(group.traversal_ids).to eq [parent.id, group.id] } + end + + context 'has a parent update before save' do + let(:parent) { create(:group) } + let(:group) { build(:group, parent: parent) } + let!(:new_grandparent) { create(:group) } + + before do + parent.update!(parent: new_grandparent) + group.save! + reload_models(parent, group) + end + + it 'avoid traversal_ids race condition' do + expect(parent.traversal_ids).to eq [new_grandparent.id, parent.id] + expect(group.traversal_ids).to eq [new_grandparent.id, parent.id, group.id] + end + end + end + + context 'traversal_ids on update' do + context 'parent is updated' do + let(:new_parent) { create(:group) } + + subject {group.update!(parent: new_parent, name: 'new name') } + + it_behaves_like 'update on column', :traversal_ids + end + + context 'parent is not updated' do + subject { group.update!(name: 'new name') } + + it_behaves_like 'no update on column', :traversal_ids + end + end + + context 'traversal_ids on ancestral update' do + context 'update multiple ancestors before save' do + let(:parent) { create(:group) } + let(:group) { create(:group, parent: parent) } + let!(:new_grandparent) { create(:group) } + let!(:new_parent) { create(:group) } + + before do + group.parent = new_parent + new_parent.update!(parent: new_grandparent) + + group.save! + reload_models(parent, group, new_grandparent, new_parent) + end + + it 'avoids traversal_ids race condition' do + expect(parent.traversal_ids).to eq [parent.id] + expect(group.traversal_ids).to eq [new_grandparent.id, new_parent.id, group.id] + expect(new_grandparent.traversal_ids).to eq [new_grandparent.id] + expect(new_parent.traversal_ids).to eq [new_grandparent.id, new_parent.id] + end + end + + context 'assigning a new parent' do + let!(:old_parent) { create(:group) } + let!(:new_parent) { create(:group) } + let!(:group) { create(:group, parent: old_parent) } + + before do + group.update(parent: new_parent) + reload_models(old_parent, new_parent, group) + end + + it 'updates traversal_ids' do + expect(group.traversal_ids).to eq [new_parent.id, group.id] + end + end + + context 'assigning a new grandparent' do + let!(:old_grandparent) { create(:group) } + let!(:new_grandparent) { create(:group) } + let!(:parent_group) { create(:group, parent: old_grandparent) } + let!(:group) { create(:group, parent: parent_group) } + + before do + parent_group.update(parent: new_grandparent) + end + + it 'updates traversal_ids for all descendants' do + expect(parent_group.reload.traversal_ids).to eq [new_grandparent.id, parent_group.id] + expect(group.reload.traversal_ids).to eq [new_grandparent.id, parent_group.id, group.id] + end + end + end + describe '.without_integration' do let(:another_group) { create(:group) } let(:instance_integration) { build(:jira_service, :instance) } @@ -565,39 +681,178 @@ RSpec.describe Group do end end - describe '#last_blocked_owner?' do - let(:blocked_user) { create(:user, :blocked) } + describe '#member_last_blocked_owner?' do + let_it_be(:blocked_user) { create(:user, :blocked) } + + let(:member) { blocked_user.group_members.last } before do group.add_user(blocked_user, GroupMember::OWNER) end - it { expect(group.last_blocked_owner?(blocked_user)).to be_truthy } + context 'when last_blocked_owner is set' do + before do + expect(group).not_to receive(:members_with_parents) + end + + it 'returns true' do + member.last_blocked_owner = true + + expect(group.member_last_blocked_owner?(member)).to be(true) + end + + it 'returns false' do + member.last_blocked_owner = false + + expect(group.member_last_blocked_owner?(member)).to be(false) + end + end + + context 'when last_blocked_owner is not set' do + it { expect(group.member_last_blocked_owner?(member)).to be(true) } + + context 'with another active owner' do + before do + group.add_user(create(:user), GroupMember::OWNER) + end + + it { expect(group.member_last_blocked_owner?(member)).to be(false) } + end + + context 'with 2 blocked owners' do + before do + group.add_user(create(:user, :blocked), GroupMember::OWNER) + end + + it { expect(group.member_last_blocked_owner?(member)).to be(false) } + end + + context 'with owners from a parent' do + before do + parent_group = create(:group) + create(:group_member, :owner, group: parent_group) + group.update(parent: parent_group) + end + + it { expect(group.member_last_blocked_owner?(member)).to be(false) } + end + end + end + + context 'when analyzing blocked owners' do + let_it_be(:blocked_user) { create(:user, :blocked) } + + describe '#single_blocked_owner?' do + context 'when there is only one blocked owner' do + before do + group.add_user(blocked_user, GroupMember::OWNER) + end + + it 'returns true' do + expect(group.single_blocked_owner?).to eq(true) + end + end + + context 'when there are multiple blocked owners' do + let_it_be(:blocked_user_2) { create(:user, :blocked) } + + before do + group.add_user(blocked_user, GroupMember::OWNER) + group.add_user(blocked_user_2, GroupMember::OWNER) + end + + it 'returns true' do + expect(group.single_blocked_owner?).to eq(false) + end + end + + context 'when there are no blocked owners' do + it 'returns false' do + expect(group.single_blocked_owner?).to eq(false) + end + end + end + + describe '#blocked_owners' do + let_it_be(:user) { create(:user) } - context 'with another active owner' do before do - group.add_user(create(:user), GroupMember::OWNER) + group.add_user(blocked_user, GroupMember::OWNER) + group.add_user(user, GroupMember::OWNER) end - it { expect(group.last_blocked_owner?(blocked_user)).to be_falsy } + it 'has only blocked owners' do + expect(group.blocked_owners.map(&:user)).to match([blocked_user]) + end end + end + + describe '#single_owner?' do + let_it_be(:user) { create(:user) } - context 'with 2 blocked owners' do + context 'when there is only one owner' do before do - group.add_user(create(:user, :blocked), GroupMember::OWNER) + group.add_user(user, GroupMember::OWNER) end - it { expect(group.last_blocked_owner?(blocked_user)).to be_falsy } + it 'returns true' do + expect(group.single_owner?).to eq(true) + end end - context 'with owners from a parent' do + context 'when there are multiple owners' do + let_it_be(:user_2) { create(:user) } + before do - parent_group = create(:group) - create(:group_member, :owner, group: parent_group) - group.update(parent: parent_group) + group.add_user(user, GroupMember::OWNER) + group.add_user(user_2, GroupMember::OWNER) end - it { expect(group.last_blocked_owner?(blocked_user)).to be_falsy } + it 'returns true' do + expect(group.single_owner?).to eq(false) + end + end + + context 'when there are no owners' do + it 'returns false' do + expect(group.single_owner?).to eq(false) + end + end + end + + describe '#member_last_owner?' do + let_it_be(:user) { create(:user) } + + let(:member) { group.members.last } + + before do + group.add_user(user, GroupMember::OWNER) + end + + context 'when last_owner is set' do + before do + expect(group).not_to receive(:last_owner?) + end + + it 'returns true' do + member.last_owner = true + + expect(group.member_last_owner?(member)).to be(true) + end + + it 'returns false' do + member.last_owner = false + + expect(group.member_last_owner?(member)).to be(false) + end + end + + context 'when last_owner is not set' do + it 'returns true' do + expect(group).to receive(:last_owner?).and_call_original + + expect(group.member_last_owner?(member)).to be(true) + end end end @@ -1500,30 +1755,6 @@ RSpec.describe Group do perfectly_matched_variable]) end end - - context 'when :scoped_group_variables feature flag is disabled' do - before do - stub_feature_flags(scoped_group_variables: false) - end - - context 'when environment scope is exactly matched' do - let(:environment_scope) { 'review/name' } - - it { is_expected.to contain_exactly(ci_variable) } - end - - context 'when environment scope is partially matched' do - let(:environment_scope) { 'review/*' } - - it { is_expected.to contain_exactly(ci_variable) } - end - - context 'when environment scope does not match' do - let(:environment_scope) { 'review/*/special' } - - it { is_expected.to contain_exactly(ci_variable) } - end - end end context 'when group has children' do @@ -1838,24 +2069,28 @@ RSpec.describe Group do end end - def subject_and_reload(*models) - subject - models.map(&:reload) - end - describe '#update_shared_runners_setting!' do context 'enabled' do subject { group.update_shared_runners_setting!('enabled') } context 'group that its ancestors have shared runners disabled' do - let_it_be(:parent) { create(:group, :shared_runners_disabled) } - let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) } - let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) } + let_it_be(:parent, reload: true) { create(:group, :shared_runners_disabled) } + let_it_be(:group, reload: true) { create(:group, :shared_runners_disabled, parent: parent) } + let_it_be(:project, reload: true) { create(:project, shared_runners_enabled: false, group: group) } - it 'raises error and does not enable shared Runners' do - expect { subject_and_reload(parent, group, project) } + it 'raises exception' do + expect { subject } .to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled') - .and not_change { parent.shared_runners_enabled } + end + + it 'does not enable shared runners' do + expect do + subject rescue nil + + parent.reload + group.reload + project.reload + end.to not_change { parent.shared_runners_enabled } .and not_change { group.shared_runners_enabled } .and not_change { project.shared_runners_enabled } end @@ -1941,13 +2176,21 @@ RSpec.describe Group do end context 'when parent does not allow' do - let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) } - let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) } + let_it_be(:parent, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) } + let_it_be(:group, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) } - it 'raises error and does not allow descendants to override' do - expect { subject_and_reload(parent, group) } + it 'raises exception' do + expect { subject } .to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it') - .and not_change { parent.allow_descendants_override_disabled_shared_runners } + end + + it 'does not allow descendants to override' do + expect do + subject rescue nil + + parent.reload + group.reload + end.to not_change { parent.allow_descendants_override_disabled_shared_runners } .and not_change { parent.shared_runners_enabled } .and not_change { group.allow_descendants_override_disabled_shared_runners } .and not_change { group.shared_runners_enabled } @@ -2104,4 +2347,18 @@ RSpec.describe Group do it_behaves_like 'model with Debian distributions' end + + describe '.ids_with_disabled_email' do + let!(:parent_1) { create(:group, emails_disabled: true) } + let!(:child_1) { create(:group, parent: parent_1) } + + let!(:parent_2) { create(:group, emails_disabled: false) } + let!(:child_2) { create(:group, parent: parent_2) } + + let!(:other_group) { create(:group, emails_disabled: false) } + + subject(:group_ids_where_email_is_disabled) { described_class.ids_with_disabled_email([child_1, child_2, other_group]) } + + it { is_expected.to eq(Set.new([child_1.id])) } + end end -- cgit v1.2.3