Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/group_spec.rb')
-rw-r--r--spec/models/group_spec.rb384
1 files changed, 379 insertions, 5 deletions
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index fed4ee3f3a4..05ee2166245 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Group do
include ReloadHelpers
+ include StubGitlabCalls
let!(:group) { create(:group) }
@@ -39,6 +40,7 @@ RSpec.describe Group do
it { is_expected.to have_many(:bulk_import_exports).class_name('BulkImports::Export') }
it { is_expected.to have_many(:contacts).class_name('CustomerRelations::Contact') }
it { is_expected.to have_many(:organizations).class_name('CustomerRelations::Organization') }
+ it { is_expected.to have_one(:crm_settings) }
describe '#members & #requesters' do
let(:requester) { create(:user) }
@@ -63,6 +65,7 @@ RSpec.describe Group do
describe 'validations' do
it { is_expected.to validate_presence_of :name }
+ it { is_expected.not_to allow_value('colon:in:path').for(:path) } # This is to validate that a specially crafted name cannot bypass a pattern match. See !72555
it { is_expected.to allow_value('group test_4').for(:name) }
it { is_expected.not_to allow_value('test/../foo').for(:name) }
it { is_expected.not_to allow_value('<script>alert("Attack!")</script>').for(:name) }
@@ -502,6 +505,10 @@ RSpec.describe Group do
it { expect(group.descendants.to_sql).not_to include 'traversal_ids @>' }
end
+ describe '#self_and_hierarchy' do
+ it { expect(group.self_and_hierarchy.to_sql).not_to include 'traversal_ids @>' }
+ end
+
describe '#ancestors' do
it { expect(group.ancestors.to_sql).not_to include 'traversal_ids <@' }
end
@@ -526,6 +533,10 @@ RSpec.describe Group do
it { expect(group.descendants.to_sql).to include 'traversal_ids @>' }
end
+ describe '#self_and_hierarchy' do
+ it { expect(group.self_and_hierarchy.to_sql).to include 'traversal_ids @>' }
+ end
+
describe '#ancestors' do
it { expect(group.ancestors.to_sql).to include "\"namespaces\".\"id\" = #{group.parent_id}" }
@@ -670,6 +681,26 @@ RSpec.describe Group do
expect(result).to match_array([internal_group])
end
end
+
+ describe 'by_ids_or_paths' do
+ let(:group_path) { 'group_path' }
+ let!(:group) { create(:group, path: group_path) }
+ let(:group_id) { group.id }
+
+ it 'returns matching records based on paths' do
+ expect(described_class.by_ids_or_paths(nil, [group_path])).to match_array([group])
+ end
+
+ it 'returns matching records based on ids' do
+ expect(described_class.by_ids_or_paths([group_id], nil)).to match_array([group])
+ end
+
+ it 'returns matching records based on both paths and ids' do
+ new_group = create(:group)
+
+ expect(described_class.by_ids_or_paths([new_group.id], [group_path])).to match_array([group, new_group])
+ end
+ end
end
describe '#to_reference' do
@@ -2056,6 +2087,23 @@ RSpec.describe Group do
end
end
+ describe '#bots' do
+ subject { group.bots }
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project_bot) { create(:user, :project_bot) }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ [project_bot, user].each do |member|
+ group.add_maintainer(member)
+ end
+ end
+
+ it { is_expected.to contain_exactly(project_bot) }
+ it { is_expected.not_to include(user) }
+ end
+
describe '#related_group_ids' do
let(:nested_group) { create(:group, parent: group) }
let(:shared_with_group) { create(:group, parent: group) }
@@ -2492,7 +2540,7 @@ RSpec.describe Group do
end
end
- describe '#default_owner' do
+ describe '#first_owner' do
let(:group) { build(:group) }
context 'the group has owners' do
@@ -2502,7 +2550,7 @@ RSpec.describe Group do
end
it 'is the first owner' do
- expect(group.default_owner)
+ expect(group.first_owner)
.to eq(group.owners.first)
.and be_a(User)
end
@@ -2517,8 +2565,8 @@ RSpec.describe Group do
end
it 'is the first owner of the parent' do
- expect(group.default_owner)
- .to eq(parent.default_owner)
+ expect(group.first_owner)
+ .to eq(parent.first_owner)
.and be_a(User)
end
end
@@ -2529,7 +2577,7 @@ RSpec.describe Group do
end
it 'is the group.owner' do
- expect(group.default_owner)
+ expect(group.first_owner)
.to eq(group.owner)
.and be_a(User)
end
@@ -2775,4 +2823,330 @@ RSpec.describe Group do
end
end
end
+
+ describe '#dependency_proxy_setting' do
+ subject(:setting) { group.dependency_proxy_setting }
+
+ it 'builds a new policy if one does not exist', :aggregate_failures do
+ expect(setting.enabled).to eq(true)
+ expect(setting).not_to be_persisted
+ end
+
+ context 'with existing policy' do
+ before do
+ group.dependency_proxy_setting.update!(enabled: false)
+ end
+
+ it 'returns the policy if it already exists', :aggregate_failures do
+ expect(setting.enabled).to eq(false)
+ expect(setting).to be_persisted
+ end
+ end
+ end
+
+ describe '#crm_enabled?' do
+ it 'returns false where no crm_settings exist' do
+ expect(group.crm_enabled?).to be_falsey
+ end
+
+ it 'returns false where crm_settings.state is disabled' do
+ create(:crm_settings, enabled: false, group: group)
+
+ expect(group.crm_enabled?).to be_falsey
+ end
+
+ it 'returns true where crm_settings.state is enabled' do
+ create(:crm_settings, enabled: true, group: group)
+
+ expect(group.crm_enabled?).to be_truthy
+ end
+ end
+ describe '.get_ids_by_ids_or_paths' do
+ let(:group_path) { 'group_path' }
+ let!(:group) { create(:group, path: group_path) }
+ let(:group_id) { group.id }
+
+ it 'returns ids matching records based on paths' do
+ expect(described_class.get_ids_by_ids_or_paths(nil, [group_path])).to match_array([group_id])
+ end
+
+ it 'returns ids matching records based on ids' do
+ expect(described_class.get_ids_by_ids_or_paths([group_id], nil)).to match_array([group_id])
+ end
+
+ it 'returns ids matching records based on both paths and ids' do
+ new_group_id = create(:group).id
+
+ expect(described_class.get_ids_by_ids_or_paths([new_group_id], [group_path])).to match_array([group_id, new_group_id])
+ end
+ end
+
+ describe '#shared_with_group_links_visible_to_user' do
+ let_it_be(:admin) { create :admin }
+ let_it_be(:normal_user) { create :user }
+ let_it_be(:user_with_access) { create :user }
+ let_it_be(:user_with_parent_access) { create :user }
+ let_it_be(:user_without_access) { create :user }
+ let_it_be(:shared_group) { create :group }
+ let_it_be(:parent_group) { create :group, :private }
+ let_it_be(:shared_with_private_group) { create :group, :private, parent: parent_group }
+ let_it_be(:shared_with_internal_group) { create :group, :internal }
+ let_it_be(:shared_with_public_group) { create :group, :public }
+ let_it_be(:private_group_group_link) { create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_private_group) }
+ let_it_be(:internal_group_group_link) { create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_internal_group) }
+ let_it_be(:public_group_group_link) { create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_public_group) }
+
+ before do
+ shared_with_private_group.add_developer(user_with_access)
+ parent_group.add_developer(user_with_parent_access)
+ end
+
+ context 'when user is admin', :enable_admin_mode do
+ it 'returns all existing shared group links' do
+ expect(shared_group.shared_with_group_links_visible_to_user(admin)).to contain_exactly(private_group_group_link, internal_group_group_link, public_group_group_link)
+ end
+ end
+
+ context 'when user is nil' do
+ it 'returns only link of public shared group' do
+ expect(shared_group.shared_with_group_links_visible_to_user(nil)).to contain_exactly(public_group_group_link)
+ end
+ end
+
+ context 'when user has no access to private shared group' do
+ it 'returns links of internal and public shared groups' do
+ expect(shared_group.shared_with_group_links_visible_to_user(normal_user)).to contain_exactly(internal_group_group_link, public_group_group_link)
+ end
+ end
+
+ context 'when user is member of private shared group' do
+ it 'returns links of private, internal and public shared groups' do
+ expect(shared_group.shared_with_group_links_visible_to_user(user_with_access)).to contain_exactly(private_group_group_link, internal_group_group_link, public_group_group_link)
+ end
+ end
+
+ context 'when user is inherited member of private shared group' do
+ it 'returns links of private, internal and public shared groups' do
+ expect(shared_group.shared_with_group_links_visible_to_user(user_with_parent_access)).to contain_exactly(private_group_group_link, internal_group_group_link, public_group_group_link)
+ end
+ end
+ end
+
+ describe '#enforced_runner_token_expiration_interval and #effective_runner_token_expiration_interval' do
+ shared_examples 'no enforced expiration interval' do
+ it { expect(subject.enforced_runner_token_expiration_interval).to be_nil }
+ end
+
+ shared_examples 'enforced expiration interval' do |enforced_interval:|
+ it { expect(subject.enforced_runner_token_expiration_interval).to eq(enforced_interval) }
+ end
+
+ shared_examples 'no effective expiration interval' do
+ it { expect(subject.effective_runner_token_expiration_interval).to be_nil }
+ end
+
+ shared_examples 'effective expiration interval' do |effective_interval:|
+ it { expect(subject.effective_runner_token_expiration_interval).to eq(effective_interval) }
+ end
+
+ context 'when there is no interval in group settings' do
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ context 'when there is a group interval' do
+ let(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 3.days.to_i) }
+
+ subject { create(:group, namespace_settings: group_settings) }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'effective expiration interval', effective_interval: 3.days
+ end
+
+ # runner_token_expiration_interval should not affect the expiration interval, only
+ # group_runner_token_expiration_interval should.
+ context 'when there is a site-wide enforced shared interval' do
+ before do
+ stub_application_setting(runner_token_expiration_interval: 5.days.to_i)
+ end
+
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ context 'when there is a site-wide enforced group interval' do
+ before do
+ stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
+ end
+
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
+ it_behaves_like 'effective expiration interval', effective_interval: 5.days
+ end
+
+ # project_runner_token_expiration_interval should not affect the expiration interval, only
+ # group_runner_token_expiration_interval should.
+ context 'when there is a site-wide enforced project interval' do
+ before do
+ stub_application_setting(project_runner_token_expiration_interval: 5.days.to_i)
+ end
+
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ # runner_token_expiration_interval should not affect the expiration interval, only
+ # subgroup_runner_token_expiration_interval should.
+ context 'when there is a grandparent group enforced group interval' do
+ let_it_be(:grandparent_group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
+ let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
+ let_it_be(:subgroup) { create(:group, parent: parent_group) }
+
+ subject { subgroup }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ context 'when there is a grandparent group enforced subgroup interval' do
+ let_it_be(:grandparent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
+ let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
+ let_it_be(:subgroup) { create(:group, parent: parent_group) }
+
+ subject { subgroup }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
+ it_behaves_like 'effective expiration interval', effective_interval: 4.days
+ end
+
+ # project_runner_token_expiration_interval should not affect the expiration interval, only
+ # subgroup_runner_token_expiration_interval should.
+ context 'when there is a grandparent group enforced project interval' do
+ let_it_be(:grandparent_group_settings) { create(:namespace_settings, project_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:grandparent_group) { create(:group, namespace_settings: grandparent_group_settings) }
+ let_it_be(:parent_group) { create(:group, parent: grandparent_group) }
+ let_it_be(:subgroup) { create(:group, parent: parent_group) }
+
+ subject { subgroup }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ context 'when there is a parent group enforced interval overridden by group interval' do
+ let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 5.days.to_i) }
+ let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
+ let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:subgroup_with_settings) { create(:group, parent: parent_group, namespace_settings: group_settings) }
+
+ subject { subgroup_with_settings }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
+ it_behaves_like 'effective expiration interval', effective_interval: 4.days
+
+ it 'has human-readable expiration intervals' do
+ expect(subject.enforced_runner_token_expiration_interval_human_readable).to eq('5d')
+ expect(subject.effective_runner_token_expiration_interval_human_readable).to eq('4d')
+ end
+ end
+
+ context 'when site-wide enforced interval overrides group interval' do
+ before do
+ stub_application_setting(group_runner_token_expiration_interval: 3.days.to_i)
+ end
+
+ let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:group_with_settings) { create(:group, namespace_settings: group_settings) }
+
+ subject { group_with_settings }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
+ it_behaves_like 'effective expiration interval', effective_interval: 3.days
+ end
+
+ context 'when group interval overrides site-wide enforced interval' do
+ before do
+ stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
+ end
+
+ let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:group_with_settings) { create(:group, namespace_settings: group_settings) }
+
+ subject { group_with_settings }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 5.days
+ it_behaves_like 'effective expiration interval', effective_interval: 4.days
+ end
+
+ context 'when site-wide enforced interval overrides parent group enforced interval' do
+ before do
+ stub_application_setting(group_runner_token_expiration_interval: 3.days.to_i)
+ end
+
+ let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
+ let_it_be(:subgroup) { create(:group, parent: parent_group) }
+
+ subject { subgroup }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 3.days
+ it_behaves_like 'effective expiration interval', effective_interval: 3.days
+ end
+
+ context 'when parent group enforced interval overrides site-wide enforced interval' do
+ before do
+ stub_application_setting(group_runner_token_expiration_interval: 5.days.to_i)
+ end
+
+ let_it_be(:parent_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:parent_group) { create(:group, namespace_settings: parent_group_settings) }
+ let_it_be(:subgroup) { create(:group, parent: parent_group) }
+
+ subject { subgroup }
+
+ it_behaves_like 'enforced expiration interval', enforced_interval: 4.days
+ it_behaves_like 'effective expiration interval', effective_interval: 4.days
+ end
+
+ # Unrelated groups should not affect the expiration interval.
+ context 'when there is an enforced group interval in an unrelated group' do
+ let_it_be(:unrelated_group_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:unrelated_group) { create(:group, namespace_settings: unrelated_group_settings) }
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+
+ # Subgroups should not affect the parent group expiration interval.
+ context 'when there is an enforced group interval in a subgroup' do
+ let_it_be(:subgroup_settings) { create(:namespace_settings, subgroup_runner_token_expiration_interval: 4.days.to_i) }
+ let_it_be(:subgroup) { create(:group, parent: group, namespace_settings: subgroup_settings) }
+ let_it_be(:group) { create(:group) }
+
+ subject { group }
+
+ it_behaves_like 'no enforced expiration interval'
+ it_behaves_like 'no effective expiration interval'
+ end
+ end
end