debian-mirror-gitlab/spec/models/group_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

3799 lines
134 KiB
Ruby
Raw Normal View History

2019-07-07 11:18:12 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2023-03-17 16:20:25 +05:30
RSpec.describe Group, feature_category: :subgroups do
2021-04-29 21:17:54 +05:30
include ReloadHelpers
2022-03-02 08:16:31 +05:30
include StubGitlabCalls
2021-04-29 21:17:54 +05:30
2019-12-21 20:55:43 +05:30
let!(:group) { create(:group) }
2014-09-02 18:07:02 +05:30
2015-09-11 14:41:01 +05:30
describe 'associations' do
2015-04-26 12:48:37 +05:30
it { is_expected.to have_many :projects }
it { is_expected.to have_many(:group_members).dependent(:destroy) }
2023-03-17 16:20:25 +05:30
it { is_expected.to have_many(:namespace_members) }
it { is_expected.to have_many(:users).through(:group_members) }
2016-08-24 12:49:21 +05:30
it { is_expected.to have_many(:owners).through(:group_members) }
it { is_expected.to have_many(:requesters).dependent(:destroy) }
2023-03-17 16:20:25 +05:30
it { is_expected.to have_many(:namespace_requesters) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:members_and_requesters) }
2023-04-23 21:23:45 +05:30
it { is_expected.to have_many(:namespace_members_and_requesters) }
it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
2016-11-03 12:29:30 +05:30
it { is_expected.to have_many(:labels).class_name('GroupLabel') }
2017-09-10 17:25:29 +05:30
it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
2018-11-08 19:23:39 +05:30
it { is_expected.to have_many(:uploads) }
2017-08-17 22:00:37 +05:30
it { is_expected.to have_one(:chat_team) }
2018-03-17 18:26:18 +05:30
it { is_expected.to have_many(:custom_attributes).class_name('GroupCustomAttribute') }
2018-03-27 19:54:05 +05:30
it { is_expected.to have_many(:badges).class_name('GroupBadge') }
2018-12-13 13:39:08 +05:30
it { is_expected.to have_many(:cluster_groups).class_name('Clusters::Group') }
it { is_expected.to have_many(:clusters).class_name('Clusters::Cluster') }
2019-10-12 21:52:04 +05:30
it { is_expected.to have_many(:container_repositories) }
2020-05-24 23:13:21 +05:30
it { is_expected.to have_many(:milestones) }
2020-10-24 23:57:45 +05:30
it { is_expected.to have_many(:group_deploy_keys) }
2021-06-08 01:23:25 +05:30
it { is_expected.to have_many(:integrations) }
2021-01-29 00:20:46 +05:30
it { is_expected.to have_one(:dependency_proxy_setting) }
2021-11-11 11:23:49 +05:30
it { is_expected.to have_one(:dependency_proxy_image_ttl_policy) }
2021-01-29 00:20:46 +05:30
it { is_expected.to have_many(:dependency_proxy_blobs) }
2021-02-22 17:27:13 +05:30
it { is_expected.to have_many(:dependency_proxy_manifests) }
2021-03-08 18:12:59 +05:30
it { is_expected.to have_many(:debian_distributions).class_name('Packages::Debian::GroupDistribution').dependent(:destroy) }
2021-03-11 19:13:27 +05:30
it { is_expected.to have_many(:daily_build_group_report_results).class_name('Ci::DailyBuildGroupReportResult') }
2021-11-11 11:23:49 +05:30
it { is_expected.to have_many(:group_callouts).class_name('Users::GroupCallout').with_foreign_key(:group_id) }
2023-05-27 22:25:52 +05:30
it do
is_expected.to have_many(:application_setting)
.with_foreign_key(:instance_administrators_group_id).inverse_of(:instance_group)
end
2021-11-18 22:05:49 +05:30
it { is_expected.to have_many(:bulk_import_exports).class_name('BulkImports::Export') }
2023-05-27 22:25:52 +05:30
it do
is_expected.to have_many(:bulk_import_entities).class_name('BulkImports::Entity')
.with_foreign_key(:namespace_id).inverse_of(:group)
end
2021-12-11 22:18:48 +05:30
it { is_expected.to have_many(:contacts).class_name('CustomerRelations::Contact') }
it { is_expected.to have_many(:organizations).class_name('CustomerRelations::Organization') }
2023-03-04 22:38:38 +05:30
it { is_expected.to have_many(:protected_branches).inverse_of(:group).with_foreign_key(:namespace_id) }
2022-03-02 08:16:31 +05:30
it { is_expected.to have_one(:crm_settings) }
2022-06-21 17:19:12 +05:30
it { is_expected.to have_one(:group_feature) }
2022-08-13 15:12:31 +05:30
it { is_expected.to have_one(:harbor_integration) }
2016-08-24 12:49:21 +05:30
2023-03-17 16:20:25 +05:30
describe '#namespace_members' do
2016-08-24 12:49:21 +05:30
let(:requester) { create(:user) }
let(:developer) { create(:user) }
2020-03-13 15:44:24 +05:30
2016-08-24 12:49:21 +05:30
before do
group.request_access(requester)
group.add_developer(developer)
end
2023-03-17 16:20:25 +05:30
it 'includes the correct users' do
expect(group.namespace_members).to include Member.find_by(user: developer)
expect(group.namespace_members).not_to include Member.find_by(user: requester)
end
it 'is equivelent to #group_members' do
expect(group.namespace_members).to eq group.group_members
end
it_behaves_like 'query without source filters' do
subject { group.namespace_members }
end
end
describe '#namespace_requesters' do
let(:requester) { create(:user) }
let(:developer) { create(:user) }
before do
group.request_access(requester)
group.add_developer(developer)
end
it 'includes the correct users' do
expect(group.namespace_requesters).to include Member.find_by(user: requester)
expect(group.namespace_requesters).not_to include Member.find_by(user: developer)
end
it 'is equivalent to #requesters' do
expect(group.namespace_requesters).to eq group.requesters
end
it_behaves_like 'query without source filters' do
subject { group.namespace_requesters }
end
end
2023-04-23 21:23:45 +05:30
describe '#namespace_members_and_requesters' do
let_it_be(:group) { create(:group) }
let_it_be(:requester) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:invited_member) { create(:group_member, :invited, :owner, group: group) }
before do
group.request_access(requester)
group.add_developer(developer)
end
it 'includes the correct users' do
expect(group.namespace_members_and_requesters).to include(
Member.find_by(user: requester),
Member.find_by(user: developer),
Member.find(invited_member.id)
)
end
it 'is equivalent to #members_and_requesters' do
expect(group.namespace_members_and_requesters).to match_array group.members_and_requesters
end
it_behaves_like 'query without source filters' do
subject { group.namespace_members_and_requesters }
end
end
2023-03-17 16:20:25 +05:30
shared_examples 'polymorphic membership relationship' do
it do
expect(membership.attributes).to include(
'source_type' => 'Namespace',
'source_id' => group.id
)
end
end
shared_examples 'member_namespace membership relationship' do
it do
expect(membership.attributes).to include(
'member_namespace_id' => group.id
)
end
end
describe '#namespace_members setters' do
let(:user) { create(:user) }
let(:membership) { group.namespace_members.create!(user: user, access_level: Gitlab::Access::DEVELOPER) }
it { expect(membership).to be_instance_of(GroupMember) }
it { expect(membership.user).to eq user }
it { expect(membership.group).to eq group }
it { expect(membership.requested_at).to be_nil }
it_behaves_like 'polymorphic membership relationship'
it_behaves_like 'member_namespace membership relationship'
end
describe '#namespace_requesters setters' do
let(:requested_at) { Time.current }
let(:user) { create(:user) }
let(:membership) do
group.namespace_requesters.create!(user: user, requested_at: requested_at, access_level: Gitlab::Access::DEVELOPER)
end
it { expect(membership).to be_instance_of(GroupMember) }
it { expect(membership.user).to eq user }
it { expect(membership.group).to eq group }
it { expect(membership.requested_at).to eq requested_at }
it_behaves_like 'polymorphic membership relationship'
it_behaves_like 'member_namespace membership relationship'
end
2023-04-23 21:23:45 +05:30
describe '#namespace_members_and_requesters setters' do
let(:requested_at) { Time.current }
let(:user) { create(:user) }
let(:membership) do
group.namespace_members_and_requesters.create!(
user: user, requested_at: requested_at, access_level: Gitlab::Access::DEVELOPER
)
end
it { expect(membership).to be_instance_of(GroupMember) }
it { expect(membership.user).to eq user }
it { expect(membership.group).to eq group }
it { expect(membership.requested_at).to eq requested_at }
it_behaves_like 'polymorphic membership relationship'
it_behaves_like 'member_namespace membership relationship'
end
2023-03-17 16:20:25 +05:30
describe '#members & #requesters' do
let_it_be(:requester) { create(:user) }
let_it_be(:developer) { create(:user) }
before do
group.request_access(requester)
group.add_developer(developer)
end
2018-03-17 18:26:18 +05:30
it_behaves_like 'members and requesters associations' do
let(:namespace) { group }
2016-08-24 12:49:21 +05:30
end
end
2014-09-02 18:07:02 +05:30
end
2015-09-11 14:41:01 +05:30
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(Referable) }
end
describe 'validations' do
it { is_expected.to validate_presence_of :name }
2022-03-02 08:16:31 +05:30
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
2020-03-28 13:19:24 +05:30
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) }
2015-09-11 14:41:01 +05:30
it { is_expected.to validate_presence_of :path }
it { is_expected.not_to validate_presence_of :owner }
2017-08-17 22:00:37 +05:30
it { is_expected.to validate_presence_of :two_factor_grace_period }
it { is_expected.to validate_numericality_of(:two_factor_grace_period).is_greater_than_or_equal_to(0) }
2021-04-17 20:07:23 +05:30
context 'validating the parent of a group' do
context 'when the group has no parent' do
it 'allows a group to have no parent associated with it' do
group = build(:group)
expect(group).to be_valid
end
end
context 'when the group has a parent' do
it 'does not allow a group to have a namespace as its parent' do
group = build(:group, parent: build(:namespace))
expect(group).not_to be_valid
2021-11-11 11:23:49 +05:30
expect(group.errors[:parent_id].first).to eq('user namespace cannot be the parent of another namespace')
2021-04-17 20:07:23 +05:30
end
it 'allows a group to have another group as its parent' do
group = build(:group, parent: build(:group))
expect(group).to be_valid
end
2023-01-13 00:05:48 +05:30
it 'does not allow a subgroup to have the same name as an existing subgroup' do
sub_group1 = create(:group, parent: group, name: "SG", path: 'api')
sub_group2 = described_class.new(parent: group, name: "SG", path: 'api2')
expect(sub_group1).to be_valid
expect(sub_group2).not_to be_valid
expect(sub_group2.errors.full_messages.to_sentence).to eq('Name has already been taken')
end
2021-04-17 20:07:23 +05:30
end
end
2017-08-17 22:00:37 +05:30
describe 'path validation' do
it 'rejects paths reserved on the root namespace when the group has no parent' do
group = build(:group, path: 'api')
expect(group).not_to be_valid
end
it 'allows root paths when the group has a parent' do
group = build(:group, path: 'api', parent: create(:group))
expect(group).to be_valid
end
it 'rejects any wildcard paths when not a top level group' do
group = build(:group, path: 'tree', parent: create(:group))
expect(group).not_to be_valid
end
2018-03-17 18:26:18 +05:30
end
2017-08-17 22:00:37 +05:30
2019-10-12 21:52:04 +05:30
describe '#notification_settings' do
2018-11-08 19:23:39 +05:30
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:sub_group) { create(:group, parent_id: group.id) }
before do
group.add_developer(user)
2019-02-15 15:39:39 +05:30
sub_group.add_maintainer(user)
2018-11-08 19:23:39 +05:30
end
it 'also gets notification settings from parent groups' do
expect(sub_group.notification_settings.size).to eq(2)
expect(sub_group.notification_settings).to include(group.notification_settings.first)
end
context 'when sub group is deleted' do
it 'does not delete parent notification settings' do
expect do
2021-12-11 22:18:48 +05:30
sub_group.destroy!
2018-11-08 19:23:39 +05:30
end.to change { NotificationSetting.count }.by(-1)
end
end
end
2019-10-12 21:52:04 +05:30
describe '#notification_email_for' do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:subgroup) { create(:group, parent: group) }
let(:group_notification_email) { 'user+group@example.com' }
let(:subgroup_notification_email) { 'user+subgroup@example.com' }
2020-05-30 21:06:31 +05:30
before do
create(:email, :confirmed, user: user, email: group_notification_email)
create(:email, :confirmed, user: user, email: subgroup_notification_email)
end
2019-10-12 21:52:04 +05:30
subject { subgroup.notification_email_for(user) }
context 'when both group notification emails are set' do
it 'returns subgroup notification email' do
create(:notification_setting, user: user, source: group, notification_email: group_notification_email)
create(:notification_setting, user: user, source: subgroup, notification_email: subgroup_notification_email)
is_expected.to eq(subgroup_notification_email)
end
end
context 'when subgroup notification email is blank' do
it 'returns parent group notification email' do
create(:notification_setting, user: user, source: group, notification_email: group_notification_email)
create(:notification_setting, user: user, source: subgroup, notification_email: '')
is_expected.to eq(group_notification_email)
end
end
context 'when only the parent group notification email is set' do
it 'returns parent group notification email' do
create(:notification_setting, user: user, source: group, notification_email: group_notification_email)
is_expected.to eq(group_notification_email)
end
end
end
2018-03-17 18:26:18 +05:30
describe '#visibility_level_allowed_by_parent' do
let(:parent) { create(:group, :internal) }
let(:sub_group) { build(:group, parent_id: parent.id) }
2017-08-17 22:00:37 +05:30
2018-03-17 18:26:18 +05:30
context 'without a parent' do
it 'is valid' do
sub_group.parent_id = nil
expect(sub_group).to be_valid
end
end
context 'with a parent' do
context 'when visibility of sub group is greater than the parent' do
it 'is invalid' do
sub_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC
expect(sub_group).to be_invalid
end
end
context 'when visibility of sub group is lower or equal to the parent' do
[Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE].each do |level|
it 'is valid' do
sub_group.visibility_level = level
expect(sub_group).to be_valid
end
end
end
end
end
describe '#visibility_level_allowed_by_projects' do
let!(:internal_group) { create(:group, :internal) }
let!(:internal_project) { create(:project, :internal, group: internal_group) }
context 'when group has a lower visibility' do
it 'is invalid' do
internal_group.visibility_level = Gitlab::VisibilityLevel::PRIVATE
expect(internal_group).to be_invalid
expect(internal_group.errors[:visibility_level]).to include('private is not allowed since this group contains projects with higher visibility.')
end
end
context 'when group has a higher visibility' do
it 'is valid' do
internal_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC
expect(internal_group).to be_valid
end
end
end
describe '#visibility_level_allowed_by_sub_groups' do
let!(:internal_group) { create(:group, :internal) }
let!(:internal_sub_group) { create(:group, :internal, parent: internal_group) }
context 'when parent group has a lower visibility' do
it 'is invalid' do
internal_group.visibility_level = Gitlab::VisibilityLevel::PRIVATE
expect(internal_group).to be_invalid
expect(internal_group.errors[:visibility_level]).to include('private is not allowed since there are sub-groups with higher visibility.')
end
end
context 'when parent group has a higher visibility' do
it 'is valid' do
internal_group.visibility_level = Gitlab::VisibilityLevel::PUBLIC
expect(internal_group).to be_valid
end
2017-08-17 22:00:37 +05:30
end
end
2021-01-03 14:25:43 +05:30
describe '#two_factor_authentication_allowed' do
2021-04-29 21:17:54 +05:30
let_it_be_with_reload(:group) { create(:group) }
2021-01-03 14:25:43 +05:30
context 'for a parent group' do
it 'is valid' do
group.require_two_factor_authentication = true
expect(group).to be_valid
end
end
context 'for a child group' do
let(:sub_group) { create(:group, parent: group) }
it 'is valid when parent group allows' do
sub_group.require_two_factor_authentication = true
expect(sub_group).to be_valid
end
it 'is invalid when parent group blocks' do
group.namespace_settings.update!(allow_mfa_for_subgroups: false)
sub_group.require_two_factor_authentication = true
expect(sub_group).to be_invalid
expect(sub_group.errors[:require_two_factor_authentication]).to include('is forbidden by a top-level group')
end
end
end
end
2022-06-21 17:19:12 +05:30
it_behaves_like 'a BulkUsersByEmailLoad model'
2023-05-27 22:25:52 +05:30
it_behaves_like 'ensures runners_token is prefixed', :group
2022-06-21 17:19:12 +05:30
context 'after initialized' do
it 'has a group_feature' do
expect(described_class.new.group_feature).to be_present
end
end
context 'when creating a new project' do
let_it_be(:group) { create(:group) }
it 'automatically creates the groups feature for the group' do
expect(group.group_feature).to be_an_instance_of(Groups::FeatureSetting)
expect(group.group_feature).to be_persisted
end
end
2021-04-29 21:17:54 +05:30
context 'traversal_ids on create' do
context 'default traversal_ids' do
let(:group) { build(:group) }
before do
group.save!
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!
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!
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) }
2022-08-27 11:52:29 +05:30
subject { group.update!(parent: new_parent, name: 'new name') }
2021-04-29 21:17:54 +05:30
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!
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
2021-06-08 01:23:25 +05:30
context 'assign a new parent' do
2021-04-29 21:17:54 +05:30
let!(:group) { create(:group, parent: old_parent) }
2021-06-08 01:23:25 +05:30
let(:recorded_queries) { ActiveRecord::QueryRecorder.new }
subject do
recorded_queries.record do
2021-12-11 22:18:48 +05:30
group.update!(parent: new_parent)
2021-06-08 01:23:25 +05:30
end
end
2021-04-29 21:17:54 +05:30
2021-06-08 01:23:25 +05:30
context 'within the same hierarchy' do
2023-04-23 21:23:45 +05:30
let!(:root) { create(:group) }
2021-06-08 01:23:25 +05:30
let!(:old_parent) { create(:group, parent: root) }
let!(:new_parent) { create(:group, parent: root) }
2022-05-07 20:08:51 +05:30
context 'with FOR NO KEY UPDATE lock' do
before do
subject
end
2021-06-08 01:23:25 +05:30
2022-05-07 20:08:51 +05:30
it 'updates traversal_ids' do
expect(group.traversal_ids).to eq [root.id, new_parent.id, group.id]
end
it_behaves_like 'hierarchy with traversal_ids'
it_behaves_like 'locked row' do
let(:row) { root }
end
2021-06-08 01:23:25 +05:30
end
end
context 'to another hierarchy' do
let!(:old_parent) { create(:group) }
let!(:new_parent) { create(:group) }
let!(:group) { create(:group, parent: old_parent) }
2022-05-07 20:08:51 +05:30
before do
subject
end
2021-06-08 01:23:25 +05:30
it 'updates traversal_ids' do
expect(group.traversal_ids).to eq [new_parent.id, group.id]
end
it_behaves_like 'locked rows' do
let(:rows) { [old_parent, new_parent] }
end
context 'old hierarchy' do
let(:root) { old_parent.root_ancestor }
it_behaves_like 'hierarchy with traversal_ids'
end
context 'new hierarchy' do
let(:root) { new_parent.root_ancestor }
it_behaves_like 'hierarchy with traversal_ids'
end
end
context 'from being a root ancestor' do
let!(:old_parent) { nil }
let!(:new_parent) { create(:group) }
2022-05-07 20:08:51 +05:30
before do
subject
end
2021-06-08 01:23:25 +05:30
it 'updates traversal_ids' do
expect(group.traversal_ids).to eq [new_parent.id, group.id]
end
it_behaves_like 'locked rows' do
let(:rows) { [group, new_parent] }
end
it_behaves_like 'hierarchy with traversal_ids' do
let(:root) { new_parent }
end
end
context 'to being a root ancestor' do
let!(:old_parent) { create(:group) }
let!(:new_parent) { nil }
2022-05-07 20:08:51 +05:30
before do
subject
end
2021-06-08 01:23:25 +05:30
it 'updates traversal_ids' do
expect(group.traversal_ids).to eq [group.id]
end
it_behaves_like 'locked rows' do
let(:rows) { [old_parent, group] }
end
it_behaves_like 'hierarchy with traversal_ids' do
let(:root) { group }
end
2021-04-29 21:17:54 +05:30
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
2021-12-11 22:18:48 +05:30
parent_group.update!(parent: new_grandparent)
2023-04-23 21:23:45 +05:30
reload_models(parent_group, group)
2021-04-29 21:17:54 +05:30
end
it 'updates traversal_ids for all descendants' do
2023-04-23 21:23:45 +05:30
expect(parent_group.traversal_ids).to eq [new_grandparent.id, parent_group.id]
expect(group.traversal_ids).to eq [new_grandparent.id, parent_group.id, group.id]
2021-04-29 21:17:54 +05:30
end
end
end
2021-06-08 01:23:25 +05:30
context 'traversal queries' do
let_it_be(:group, reload: true) { create(:group, :nested) }
context 'recursive' do
before do
stub_feature_flags(use_traversal_ids: false)
end
it_behaves_like 'namespace traversal'
describe '#self_and_descendants' do
it { expect(group.self_and_descendants.to_sql).not_to include 'traversal_ids @>' }
end
2021-09-04 01:27:46 +05:30
describe '#self_and_descendant_ids' do
it { expect(group.self_and_descendant_ids.to_sql).not_to include 'traversal_ids @>' }
end
2021-06-08 01:23:25 +05:30
describe '#descendants' do
it { expect(group.descendants.to_sql).not_to include 'traversal_ids @>' }
end
2022-03-02 08:16:31 +05:30
describe '#self_and_hierarchy' do
it { expect(group.self_and_hierarchy.to_sql).not_to include 'traversal_ids @>' }
end
2021-06-08 01:23:25 +05:30
describe '#ancestors' do
it { expect(group.ancestors.to_sql).not_to include 'traversal_ids <@' }
end
2022-01-26 12:08:38 +05:30
describe '#ancestors_upto' do
it { expect(group.ancestors_upto.to_sql).not_to include "WITH ORDINALITY" }
end
2022-06-21 17:19:12 +05:30
describe '.shortest_traversal_ids_prefixes' do
it { expect { described_class.shortest_traversal_ids_prefixes }.to raise_error /Feature not supported since the `:use_traversal_ids` is disabled/ }
end
2021-06-08 01:23:25 +05:30
end
context 'linear' do
it_behaves_like 'namespace traversal'
describe '#self_and_descendants' do
it { expect(group.self_and_descendants.to_sql).to include 'traversal_ids @>' }
end
2021-09-04 01:27:46 +05:30
describe '#self_and_descendant_ids' do
it { expect(group.self_and_descendant_ids.to_sql).to include 'traversal_ids @>' }
end
2021-06-08 01:23:25 +05:30
describe '#descendants' do
it { expect(group.descendants.to_sql).to include 'traversal_ids @>' }
end
2022-03-02 08:16:31 +05:30
describe '#self_and_hierarchy' do
it { expect(group.self_and_hierarchy.to_sql).to include 'traversal_ids @>' }
end
2021-06-08 01:23:25 +05:30
describe '#ancestors' do
it { expect(group.ancestors.to_sql).to include "\"namespaces\".\"id\" = #{group.parent_id}" }
it 'hierarchy order' do
expect(group.ancestors(hierarchy_order: :asc).to_sql).to include 'ORDER BY "depth" ASC'
end
context 'ancestor linear queries feature flag disabled' do
before do
stub_feature_flags(use_traversal_ids_for_ancestors: false)
end
it { expect(group.ancestors.to_sql).not_to include 'traversal_ids <@' }
end
end
2021-12-11 22:18:48 +05:30
2022-01-26 12:08:38 +05:30
describe '#ancestors_upto' do
it { expect(group.ancestors_upto.to_sql).to include "WITH ORDINALITY" }
end
2022-06-21 17:19:12 +05:30
describe '.shortest_traversal_ids_prefixes' do
subject { filter.shortest_traversal_ids_prefixes }
context 'for many top-level namespaces' do
let!(:top_level_groups) { create_list(:group, 4) }
context 'when querying all groups' do
let(:filter) { described_class.id_in(top_level_groups) }
it "returns all traversal_ids" do
is_expected.to contain_exactly(
*top_level_groups.map { |group| [group.id] }
)
end
end
context 'when querying selected groups' do
let(:filter) { described_class.id_in(top_level_groups.first) }
it "returns only a selected traversal_ids" do
is_expected.to contain_exactly([top_level_groups.first.id])
end
end
end
context 'for namespace hierarchy' do
let!(:group_a) { create(:group) }
let!(:group_a_sub_1) { create(:group, parent: group_a) }
let!(:group_a_sub_2) { create(:group, parent: group_a) }
let!(:group_b) { create(:group) }
let!(:group_b_sub_1) { create(:group, parent: group_b) }
let!(:group_c) { create(:group) }
context 'when querying all groups' do
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_a_sub_2, group_b, group_b_sub_1, group_c]) }
it 'returns only shortest prefixes of top-level groups' do
is_expected.to contain_exactly(
[group_a.id],
[group_b.id],
[group_c.id]
)
end
end
context 'when sub-group is reparented' do
let(:filter) { described_class.id_in([group_b_sub_1, group_c]) }
before do
group_b_sub_1.update!(parent: group_c)
end
it 'returns a proper shortest prefix of a new group' do
is_expected.to contain_exactly(
[group_c.id]
)
end
end
context 'when querying sub-groups' do
let(:filter) { described_class.id_in([group_a_sub_1, group_b_sub_1, group_c]) }
it 'returns sub-groups as they are shortest prefixes' do
is_expected.to contain_exactly(
[group_a.id, group_a_sub_1.id],
[group_b.id, group_b_sub_1.id],
[group_c.id]
)
end
end
context 'when querying group and sub-group of this group' do
let(:filter) { described_class.id_in([group_a, group_a_sub_1, group_c]) }
it 'returns parent groups as this contains all sub-groups' do
is_expected.to contain_exactly(
[group_a.id],
[group_c.id]
)
end
end
end
end
2021-12-11 22:18:48 +05:30
context 'when project namespace exists in the group' do
let!(:project) { create(:project, group: group) }
let!(:project_namespace) { project.project_namespace }
it 'filters out project namespace' do
expect(group.descendants.find_by_id(project_namespace.id)).to be_nil
end
end
2021-06-08 01:23:25 +05:30
end
end
2021-01-03 14:25:43 +05:30
describe '.without_integration' do
let(:another_group) { create(:group) }
2021-09-30 23:02:18 +05:30
let(:instance_integration) { build(:jira_integration, :instance) }
2021-01-03 14:25:43 +05:30
before do
2021-12-11 22:18:48 +05:30
create(:jira_integration, :group, group: group)
create(:integrations_slack, :group, group: another_group)
2021-01-03 14:25:43 +05:30
end
it 'returns groups without integration' do
expect(Group.without_integration(instance_integration)).to contain_exactly(another_group)
end
2015-09-11 14:41:01 +05:30
end
2018-11-08 19:23:39 +05:30
describe '.public_or_visible_to_user' do
2022-10-11 01:57:18 +05:30
let!(:private_group) { create(:group, :private) }
let!(:private_subgroup) { create(:group, :private, parent: private_group) }
2018-11-08 19:23:39 +05:30
let!(:internal_group) { create(:group, :internal) }
2015-11-26 14:37:03 +05:30
2018-11-08 19:23:39 +05:30
subject { described_class.public_or_visible_to_user(user) }
2015-11-26 14:37:03 +05:30
2018-11-08 19:23:39 +05:30
context 'when user is nil' do
let!(:user) { nil }
2015-11-26 14:37:03 +05:30
2018-11-08 19:23:39 +05:30
it { is_expected.to match_array([group]) }
2015-11-26 14:37:03 +05:30
end
2018-11-08 19:23:39 +05:30
context 'when user' do
let!(:user) { create(:user) }
context 'when user does not have access to any private group' do
it { is_expected.to match_array([internal_group, group]) }
end
context 'when user is a member of private group' do
before do
2022-08-13 15:12:31 +05:30
private_group.add_member(user, Gitlab::Access::DEVELOPER)
2018-11-08 19:23:39 +05:30
end
it { is_expected.to match_array([private_group, internal_group, group]) }
2022-10-11 01:57:18 +05:30
it 'does not have access to subgroups (see accessible_to_user scope)' do
is_expected.not_to include(private_subgroup)
end
2018-11-08 19:23:39 +05:30
end
2019-10-12 21:52:04 +05:30
context 'when user is a member of private subgroup' do
2018-11-08 19:23:39 +05:30
let!(:private_subgroup) { create(:group, :private, parent: private_group) }
before do
2022-08-13 15:12:31 +05:30
private_subgroup.add_member(user, Gitlab::Access::DEVELOPER)
2018-11-08 19:23:39 +05:30
end
it { is_expected.to match_array([private_subgroup, internal_group, group]) }
end
2015-11-26 14:37:03 +05:30
end
end
2016-06-02 11:05:42 +05:30
describe 'scopes' do
2021-01-29 00:20:46 +05:30
let_it_be(:private_group) { create(:group, :private) }
let_it_be(:internal_group) { create(:group, :internal) }
let_it_be(:user1) { create(:user) }
let_it_be(:user2) { create(:user) }
2016-06-02 11:05:42 +05:30
describe 'public_only' do
subject { described_class.public_only.to_a }
2017-08-17 22:00:37 +05:30
it { is_expected.to eq([group]) }
2016-06-02 11:05:42 +05:30
end
describe 'public_and_internal_only' do
subject { described_class.public_and_internal_only.to_a }
2017-08-17 22:00:37 +05:30
it { is_expected.to match_array([group, internal_group]) }
end
describe 'non_public_only' do
subject { described_class.non_public_only.to_a }
it { is_expected.to match_array([private_group, internal_group]) }
2016-06-02 11:05:42 +05:30
end
2021-01-29 00:20:46 +05:30
2021-10-27 15:23:28 +05:30
describe 'private_only' do
subject { described_class.private_only.to_a }
it { is_expected.to match_array([private_group]) }
end
2021-06-08 01:23:25 +05:30
describe 'with_onboarding_progress' do
subject { described_class.with_onboarding_progress }
it 'joins onboarding_progress' do
create(:onboarding_progress, namespace: group)
expect(subject).to eq([group])
end
end
2021-01-29 00:20:46 +05:30
describe 'for_authorized_group_members' do
let_it_be(:group_member1) { create(:group_member, source: private_group, user_id: user1.id, access_level: Gitlab::Access::OWNER) }
it do
result = described_class.for_authorized_group_members([user1.id, user2.id])
expect(result).to match_array([private_group])
end
end
describe 'for_authorized_project_members' do
let_it_be(:project) { create(:project, group: internal_group) }
let_it_be(:project_member1) { create(:project_member, source: project, user_id: user1.id, access_level: Gitlab::Access::DEVELOPER) }
it do
result = described_class.for_authorized_project_members([user1.id, user2.id])
expect(result).to match_array([internal_group])
end
end
2022-03-02 08:16:31 +05:30
2023-06-20 00:43:36 +05:30
describe '.with_project_creation_levels' do
let_it_be(:group_1) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS) }
let_it_be(:group_2) { create(:group, project_creation_level: Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
let_it_be(:group_3) { create(:group, project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
let_it_be(:group_4) { create(:group, project_creation_level: nil) }
it 'returns groups with the specified project creation levels' do
result = described_class.with_project_creation_levels([
Gitlab::Access::NO_ONE_PROJECT_ACCESS,
Gitlab::Access::MAINTAINER_PROJECT_ACCESS
])
expect(result).to include(group_1, group_3)
expect(result).not_to include(group_2, group_4)
end
end
2022-08-27 11:52:29 +05:30
describe '.project_creation_allowed' do
let_it_be(:group_1) { create(:group, project_creation_level: Gitlab::Access::NO_ONE_PROJECT_ACCESS) }
let_it_be(:group_2) { create(:group, project_creation_level: Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
let_it_be(:group_3) { create(:group, project_creation_level: Gitlab::Access::MAINTAINER_PROJECT_ACCESS) }
let_it_be(:group_4) { create(:group, project_creation_level: nil) }
it 'only includes groups where project creation is allowed' do
result = described_class.project_creation_allowed
expect(result).to include(group_2, group_3, group_4)
expect(result).not_to include(group_1)
end
2023-06-20 00:43:36 +05:30
context 'when the application_setting is set to `NO_ONE_PROJECT_ACCESS`' do
before do
stub_application_setting(default_project_creation: Gitlab::Access::NO_ONE_PROJECT_ACCESS)
end
it 'only includes groups where project creation is allowed' do
result = described_class.project_creation_allowed
expect(result).to include(group_2, group_3)
# group_4 won't be included because it has `project_creation_level: nil`,
# and that means it behaves like the value of the application_setting will inherited.
expect(result).not_to include(group_1, group_4)
end
end
2022-08-27 11:52:29 +05:30
end
2022-03-02 08:16:31 +05:30
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])
2023-03-04 22:38:38 +05:30
expect(described_class.by_ids_or_paths(nil, [group_path.upcase])).to match_array([group])
2022-03-02 08:16:31 +05:30
end
it 'returns matching records based on ids' do
expect(described_class.by_ids_or_paths([group_id], nil)).to match_array([group])
2023-03-04 22:38:38 +05:30
expect(described_class.by_ids_or_paths([group_id], [])).to match_array([group])
2022-03-02 08:16:31 +05:30
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
2023-03-04 22:38:38 +05:30
it 'returns matching records based on full_paths' do
new_group = create(:group, parent: group)
expect(described_class.by_ids_or_paths(nil, [new_group.full_path])).to match_array([new_group])
expect(described_class.by_ids_or_paths(nil, [new_group.full_path.upcase])).to match_array([new_group])
end
2022-03-02 08:16:31 +05:30
end
2022-10-11 01:57:18 +05:30
describe 'accessible_to_user' do
subject { described_class.accessible_to_user(user) }
let_it_be(:public_group) { create(:group, :public) }
let_it_be(:unaccessible_group) { create(:group, :private) }
let_it_be(:unaccessible_subgroup) { create(:group, :private, parent: unaccessible_group) }
let_it_be(:accessible_group) { create(:group, :private) }
let_it_be(:accessible_subgroup) { create(:group, :private, parent: accessible_group) }
context 'when user is nil' do
let(:user) { nil }
it { is_expected.to match_array([group, public_group]) }
end
context 'when user is present' do
let(:user) { create(:user) }
it { is_expected.to match_array([group, internal_group, public_group]) }
context 'when user has access to accessible group' do
before do
accessible_group.add_developer(user)
end
it { is_expected.to match_array([group, internal_group, public_group, accessible_group, accessible_subgroup]) }
end
end
end
2016-06-02 11:05:42 +05:30
end
2015-09-11 14:41:01 +05:30
describe '#to_reference' do
it 'returns a String reference to the object' do
expect(group.to_reference).to eq "@#{group.name}"
end
end
2014-09-02 18:07:02 +05:30
2016-08-24 12:49:21 +05:30
describe '#users' do
2015-04-26 12:48:37 +05:30
it { expect(group.users).to eq(group.owners) }
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#human_name' do
2015-04-26 12:48:37 +05:30
it { expect(group.human_name).to eq(group.name) }
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#add_user' do
2014-09-02 18:07:02 +05:30
let(:user) { create(:user) }
2017-09-10 17:25:29 +05:30
2023-04-23 21:23:45 +05:30
it 'adds the user' do
2022-06-21 17:19:12 +05:30
expect_next_instance_of(GroupMember) do |member|
2023-04-23 21:23:45 +05:30
expect(member).to receive(:refresh_member_authorized_projects).and_call_original
2022-06-21 17:19:12 +05:30
end
2022-08-13 15:12:31 +05:30
group.add_member(user, GroupMember::MAINTAINER)
2022-06-21 17:19:12 +05:30
expect(group.group_members.maintainers.map(&:user)).to include(user)
2017-09-10 17:25:29 +05:30
end
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#add_users' do
2014-09-02 18:07:02 +05:30
let(:user) { create(:user) }
2017-09-10 17:25:29 +05:30
before do
2022-08-13 15:12:31 +05:30
group.add_members([user.id], GroupMember::GUEST)
2017-09-10 17:25:29 +05:30
end
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
it "updates the group permission" do
2015-04-26 12:48:37 +05:30
expect(group.group_members.guests.map(&:user)).to include(user)
2022-08-13 15:12:31 +05:30
group.add_members([user.id], GroupMember::DEVELOPER)
2015-04-26 12:48:37 +05:30
expect(group.group_members.developers.map(&:user)).to include(user)
expect(group.group_members.guests.map(&:user)).not_to include(user)
2014-09-02 18:07:02 +05:30
end
2021-12-11 22:18:48 +05:30
context 'when `tasks_to_be_done` and `tasks_project_id` are passed' do
let!(:project) { create(:project, group: group) }
before do
2022-08-13 15:12:31 +05:30
group.add_members([create(:user)], :developer, tasks_to_be_done: %w(ci code), tasks_project_id: project.id)
2021-12-11 22:18:48 +05:30
end
it 'creates a member_task with the correct attributes', :aggregate_failures do
member = group.group_members.last
expect(member.tasks_to_be_done).to match_array([:ci, :code])
expect(member.member_task.project).to eq(project)
end
end
2014-09-02 18:07:02 +05:30
end
2016-08-24 12:49:21 +05:30
describe '#avatar_type' do
2014-09-02 18:07:02 +05:30
let(:user) { create(:user) }
2017-09-10 17:25:29 +05:30
before do
2022-08-13 15:12:31 +05:30
group.add_member(user, GroupMember::MAINTAINER)
2017-09-10 17:25:29 +05:30
end
2014-09-02 18:07:02 +05:30
2016-09-13 17:45:13 +05:30
it "is true if avatar is image" do
2014-09-02 18:07:02 +05:30
group.update_attribute(:avatar, 'uploads/avatar.png')
2015-04-26 12:48:37 +05:30
expect(group.avatar_type).to be_truthy
2014-09-02 18:07:02 +05:30
end
2016-09-13 17:45:13 +05:30
it "is false if avatar is html page" do
2014-09-02 18:07:02 +05:30
group.update_attribute(:avatar, 'uploads/avatar.html')
2021-06-08 01:23:25 +05:30
group.avatar_type
expect(group.errors.added?(:avatar, "file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico, webp")).to be true
2014-09-02 18:07:02 +05:30
end
end
2016-06-02 11:05:42 +05:30
2017-08-17 22:00:37 +05:30
describe '#avatar_url' do
2019-12-21 20:55:43 +05:30
let!(:group) { create(:group, :with_avatar) }
2017-08-17 22:00:37 +05:30
let(:user) { create(:user) }
context 'when avatar file is uploaded' do
before do
2018-11-18 11:00:15 +05:30
group.add_maintainer(user)
2017-08-17 22:00:37 +05:30
end
2017-09-10 17:25:29 +05:30
it 'shows correct avatar url' do
2018-03-17 18:26:18 +05:30
expect(group.avatar_url).to eq(group.avatar.url)
expect(group.avatar_url(only_path: false)).to eq([Gitlab.config.gitlab.url, group.avatar.url].join)
2017-09-10 17:25:29 +05:30
end
2017-08-17 22:00:37 +05:30
end
end
2016-06-02 11:05:42 +05:30
describe '.search' do
it 'returns groups with a matching name' do
expect(described_class.search(group.name)).to eq([group])
end
it 'returns groups with a partially matching name' do
expect(described_class.search(group.name[0..2])).to eq([group])
end
it 'returns groups with a matching name regardless of the casing' do
expect(described_class.search(group.name.upcase)).to eq([group])
end
it 'returns groups with a matching path' do
expect(described_class.search(group.path)).to eq([group])
end
it 'returns groups with a partially matching path' do
expect(described_class.search(group.path[0..2])).to eq([group])
end
it 'returns groups with a matching path regardless of the casing' do
expect(described_class.search(group.path.upcase)).to eq([group])
end
end
describe '#has_owner?' do
2017-09-10 17:25:29 +05:30
before do
@members = setup_group_members(group)
create(:group_member, :invited, :owner, group: group)
end
it { expect(group.has_owner?(@members[:owner])).to be_truthy }
2018-11-18 11:00:15 +05:30
it { expect(group.has_owner?(@members[:maintainer])).to be_falsey }
it { expect(group.has_owner?(@members[:developer])).to be_falsey }
it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
it { expect(group.has_owner?(@members[:guest])).to be_falsey }
it { expect(group.has_owner?(@members[:requester])).to be_falsey }
2017-09-10 17:25:29 +05:30
it { expect(group.has_owner?(nil)).to be_falsey }
end
2018-11-18 11:00:15 +05:30
describe '#has_maintainer?' do
2017-09-10 17:25:29 +05:30
before do
@members = setup_group_members(group)
2018-11-18 11:00:15 +05:30
create(:group_member, :invited, :maintainer, group: group)
2017-09-10 17:25:29 +05:30
end
2018-11-18 11:00:15 +05:30
it { expect(group.has_maintainer?(@members[:owner])).to be_falsey }
it { expect(group.has_maintainer?(@members[:maintainer])).to be_truthy }
it { expect(group.has_maintainer?(@members[:developer])).to be_falsey }
it { expect(group.has_maintainer?(@members[:reporter])).to be_falsey }
it { expect(group.has_maintainer?(@members[:guest])).to be_falsey }
it { expect(group.has_maintainer?(@members[:requester])).to be_falsey }
it { expect(group.has_maintainer?(nil)).to be_falsey }
end
2019-07-07 11:18:12 +05:30
describe '#last_owner?' do
before do
@members = setup_group_members(group)
end
it { expect(group.last_owner?(@members[:owner])).to be_truthy }
2022-07-23 23:45:48 +05:30
context 'there is also a project_bot owner' do
before do
2022-08-13 15:12:31 +05:30
group.add_member(create(:user, :project_bot), GroupMember::OWNER)
2022-07-23 23:45:48 +05:30
end
it { expect(group.last_owner?(@members[:owner])).to be_truthy }
end
2019-07-07 11:18:12 +05:30
context 'with two owners' do
before do
create(:group_member, :owner, group: group)
end
it { expect(group.last_owner?(@members[:owner])).to be_falsy }
end
2019-10-12 21:52:04 +05:30
context 'with owners from a parent' do
2023-01-13 00:05:48 +05:30
context 'when top-level group' do
it { expect(group.last_owner?(@members[:owner])).to be_truthy }
context 'with group sharing' do
let!(:subgroup) { create(:group, parent: group) }
before do
create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
create(:group_member, :owner, group: subgroup)
end
it { expect(group.last_owner?(@members[:owner])).to be_truthy }
end
2019-07-07 11:18:12 +05:30
end
2023-01-13 00:05:48 +05:30
context 'when subgroup' do
let!(:subgroup) { create(:group, parent: group) }
it { expect(subgroup.last_owner?(@members[:owner])).to be_truthy }
context 'with two owners' do
before do
create(:group_member, :owner, group: group)
end
it { expect(subgroup.last_owner?(@members[:owner])).to be_falsey }
end
end
2019-07-07 11:18:12 +05:30
end
end
2021-04-29 21:17:54 +05:30
describe '#member_last_blocked_owner?' do
2023-01-13 00:05:48 +05:30
let!(:blocked_user) { create(:user, :blocked) }
2021-04-29 21:17:54 +05:30
2023-01-13 00:05:48 +05:30
let!(:member) { group.add_member(blocked_user, GroupMember::OWNER) }
2021-04-17 20:07:23 +05:30
2021-04-29 21:17:54 +05:30
context 'when last_blocked_owner is set' do
before do
2023-01-13 00:05:48 +05:30
expect(group).not_to receive(:member_owners_excluding_project_bots)
2021-04-29 21:17:54 +05:30
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
2022-08-13 15:12:31 +05:30
group.add_member(create(:user), GroupMember::OWNER)
2021-04-29 21:17:54 +05:30
end
it { expect(group.member_last_blocked_owner?(member)).to be(false) }
end
2023-01-13 00:05:48 +05:30
context 'with another active project_bot owner' do
before do
group.add_member(create(:user, :project_bot), GroupMember::OWNER)
end
it { expect(group.member_last_blocked_owner?(member)).to be(true) }
end
2021-04-29 21:17:54 +05:30
context 'with 2 blocked owners' do
before do
2022-08-13 15:12:31 +05:30
group.add_member(create(:user, :blocked), GroupMember::OWNER)
2021-04-29 21:17:54 +05:30
end
it { expect(group.member_last_blocked_owner?(member)).to be(false) }
end
context 'with owners from a parent' do
2023-01-13 00:05:48 +05:30
context 'when top-level group' do
it { expect(group.member_last_blocked_owner?(member)).to be(true) }
context 'with group sharing' do
let!(:subgroup) { create(:group, parent: group) }
before do
create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
create(:group_member, :owner, group: subgroup)
end
it { expect(group.member_last_blocked_owner?(member)).to be(true) }
end
2021-04-29 21:17:54 +05:30
end
2023-01-13 00:05:48 +05:30
context 'when subgroup' do
let!(:subgroup) { create(:group, :nested) }
let!(:member) { subgroup.add_member(blocked_user, GroupMember::OWNER) }
it { expect(subgroup.member_last_blocked_owner?(member)).to be(true) }
context 'with two owners' do
before do
create(:group_member, :owner, group: subgroup.parent)
end
it { expect(subgroup.member_last_blocked_owner?(member)).to be(false) }
end
end
2021-04-29 21:17:54 +05:30
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
2022-08-13 15:12:31 +05:30
group.add_member(blocked_user, GroupMember::OWNER)
2021-04-29 21:17:54 +05:30
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
2022-08-13 15:12:31 +05:30
group.add_member(blocked_user, GroupMember::OWNER)
group.add_member(blocked_user_2, GroupMember::OWNER)
2021-04-29 21:17:54 +05:30
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) }
2021-04-17 20:07:23 +05:30
before do
2022-08-13 15:12:31 +05:30
group.add_member(blocked_user, GroupMember::OWNER)
group.add_member(user, GroupMember::OWNER)
2021-04-17 20:07:23 +05:30
end
2021-04-29 21:17:54 +05:30
it 'has only blocked owners' do
expect(group.blocked_owners.map(&:user)).to match([blocked_user])
end
2021-04-17 20:07:23 +05:30
end
2021-04-29 21:17:54 +05:30
end
2023-01-13 00:05:48 +05:30
describe '#member_owners_excluding_project_bots' do
2021-04-29 21:17:54 +05:30
let_it_be(:user) { create(:user) }
2021-04-17 20:07:23 +05:30
2023-01-13 00:05:48 +05:30
let!(:member_owner) do
group.add_member(user, GroupMember::OWNER)
end
2021-04-17 20:07:23 +05:30
2023-01-13 00:05:48 +05:30
it 'returns the member-owners' do
expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
end
2022-07-23 23:45:48 +05:30
2023-01-13 00:05:48 +05:30
context 'there is also a project_bot owner' do
before do
group.add_member(create(:user, :project_bot), GroupMember::OWNER)
end
2022-07-23 23:45:48 +05:30
2023-01-13 00:05:48 +05:30
it 'returns only the human member-owners' do
expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
2021-04-29 21:17:54 +05:30
end
2021-04-17 20:07:23 +05:30
end
2023-01-13 00:05:48 +05:30
context 'with owners from a parent' do
context 'when top-level group' do
context 'with group sharing' do
let!(:subgroup) { create(:group, parent: group) }
2021-04-29 21:17:54 +05:30
2023-01-13 00:05:48 +05:30
before do
create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
subgroup.add_member(user, GroupMember::OWNER)
end
2022-07-23 23:45:48 +05:30
2023-01-13 00:05:48 +05:30
it 'returns only direct member-owners' do
expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
end
end
2021-04-17 20:07:23 +05:30
end
2023-01-13 00:05:48 +05:30
context 'when subgroup' do
let!(:subgroup) { create(:group, parent: group) }
2022-07-23 23:45:48 +05:30
2023-01-13 00:05:48 +05:30
let_it_be(:user_2) { create(:user) }
let!(:member_owner_2) do
subgroup.add_member(user_2, GroupMember::OWNER)
2022-07-23 23:45:48 +05:30
end
2023-01-13 00:05:48 +05:30
it 'returns member-owners including parents' do
expect(subgroup.member_owners_excluding_project_bots).to contain_exactly(member_owner, member_owner_2)
2022-07-23 23:45:48 +05:30
end
2021-04-29 21:17:54 +05:30
end
end
context 'when there are no owners' do
2023-01-13 00:05:48 +05:30
let_it_be(:empty_group) { create(:group) }
it 'returns an empty result' do
expect(empty_group.member_owners_excluding_project_bots).to be_empty
2021-04-29 21:17:54 +05:30
end
end
end
describe '#member_last_owner?' do
let_it_be(:user) { create(:user) }
let(:member) { group.members.last }
before do
2022-08-13 15:12:31 +05:30
group.add_member(user, GroupMember::OWNER)
2021-04-29 21:17:54 +05:30
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
2021-04-17 20:07:23 +05:30
end
end
2016-09-29 09:46:39 +05:30
describe '#lfs_enabled?' do
context 'LFS enabled globally' do
before do
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
end
it 'returns true when nothing is set' do
expect(group.lfs_enabled?).to be_truthy
end
it 'returns false when set to false' do
group.update_attribute(:lfs_enabled, false)
expect(group.lfs_enabled?).to be_falsey
end
it 'returns true when set to true' do
group.update_attribute(:lfs_enabled, true)
expect(group.lfs_enabled?).to be_truthy
end
end
context 'LFS disabled globally' do
before do
allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
end
it 'returns false when nothing is set' do
expect(group.lfs_enabled?).to be_falsey
end
it 'returns false when set to false' do
group.update_attribute(:lfs_enabled, false)
expect(group.lfs_enabled?).to be_falsey
end
it 'returns false when set to true' do
group.update_attribute(:lfs_enabled, true)
expect(group.lfs_enabled?).to be_falsey
end
end
end
2016-06-22 15:30:34 +05:30
describe '#owners' do
let(:owner) { create(:user) }
let(:developer) { create(:user) }
it 'returns the owners of a Group' do
group.add_owner(owner)
group.add_developer(developer)
expect(group.owners).to eq([owner])
end
end
def setup_group_members(group)
members = {
owner: create(:user),
2018-11-18 11:00:15 +05:30
maintainer: create(:user),
developer: create(:user),
reporter: create(:user),
guest: create(:user),
requester: create(:user)
}
2022-08-13 15:12:31 +05:30
group.add_member(members[:owner], GroupMember::OWNER)
group.add_member(members[:maintainer], GroupMember::MAINTAINER)
group.add_member(members[:developer], GroupMember::DEVELOPER)
group.add_member(members[:reporter], GroupMember::REPORTER)
group.add_member(members[:guest], GroupMember::GUEST)
group.request_access(members[:requester])
members
end
2016-11-03 12:29:30 +05:30
describe '#web_url' do
it 'returns the canonical URL' do
expect(group.web_url).to include("groups/#{group.name}")
end
2017-08-17 22:00:37 +05:30
context 'nested group' do
let(:nested_group) { create(:group, :nested) }
it { expect(nested_group.web_url).to include("groups/#{nested_group.full_path}") }
end
end
describe 'nested group' do
subject { build(:group, :nested) }
it { is_expected.to be_valid }
2017-09-10 17:25:29 +05:30
it { expect(subject.parent).to be_kind_of(described_class) }
2017-08-17 22:00:37 +05:30
end
2021-09-04 01:27:46 +05:30
describe '#max_member_access_for_user' do
2021-06-08 01:23:25 +05:30
let_it_be(:group_user) { create(:user) }
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'with user in the group' do
before do
group.add_owner(group_user)
2021-06-08 01:23:25 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
it 'returns correct access level' do
expect(group.max_member_access_for_user(group_user)).to eq(Gitlab::Access::OWNER)
2021-06-08 01:23:25 +05:30
end
2021-09-04 01:27:46 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'when user is nil' do
it 'returns NO_ACCESS' do
expect(group.max_member_access_for_user(nil)).to eq(Gitlab::Access::NO_ACCESS)
end
end
2020-03-07 23:17:34 +05:30
2021-09-04 01:27:46 +05:30
context 'evaluating admin access level' do
let_it_be(:admin) { create(:admin) }
2020-03-07 23:17:34 +05:30
2021-09-04 01:27:46 +05:30
context 'when admin mode is enabled', :enable_admin_mode do
it 'returns OWNER by default' do
expect(group.max_member_access_for_user(admin)).to eq(Gitlab::Access::OWNER)
2020-03-07 23:17:34 +05:30
end
2020-05-24 23:13:21 +05:30
end
2020-03-07 23:17:34 +05:30
2021-09-04 01:27:46 +05:30
context 'when admin mode is disabled' do
it 'returns NO_ACCESS' do
expect(group.max_member_access_for_user(admin)).to eq(Gitlab::Access::NO_ACCESS)
2019-12-26 22:10:19 +05:30
end
2021-09-04 01:27:46 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
it 'returns NO_ACCESS when only concrete membership should be considered' do
expect(group.max_member_access_for_user(admin, only_concrete_membership: true))
.to eq(Gitlab::Access::NO_ACCESS)
2020-05-24 23:13:21 +05:30
end
2021-06-08 01:23:25 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'group shared with another group' do
let_it_be(:parent_group_user) { create(:user) }
let_it_be(:child_group_user) { create(:user) }
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
let_it_be(:group_parent) { create(:group, :private) }
let_it_be(:group) { create(:group, :private, parent: group_parent) }
let_it_be(:group_child) { create(:group, :private, parent: group) }
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
let_it_be(:shared_group_parent) { create(:group, :private) }
let_it_be(:shared_group) { create(:group, :private, parent: shared_group_parent) }
let_it_be(:shared_group_child) { create(:group, :private, parent: shared_group) }
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
before do
group_parent.add_owner(parent_group_user)
group.add_owner(group_user)
group_child.add_owner(child_group_user)
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
create(:group_group_link, { shared_with_group: group,
shared_group: shared_group,
group_access: GroupMember::DEVELOPER })
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'with user in the group' do
it 'returns correct access level' do
expect(shared_group_parent.max_member_access_for_user(group_user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(group_user)).to eq(Gitlab::Access::DEVELOPER)
expect(shared_group_child.max_member_access_for_user(group_user)).to eq(Gitlab::Access::DEVELOPER)
end
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
context 'with lower group access level than max access level for share' do
let(:user) { create(:user) }
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
it 'returns correct access level' do
group.add_reporter(user)
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
expect(shared_group_parent.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(user)).to eq(Gitlab::Access::REPORTER)
expect(shared_group_child.max_member_access_for_user(user)).to eq(Gitlab::Access::REPORTER)
2021-06-08 01:23:25 +05:30
end
2019-12-26 22:10:19 +05:30
end
2021-09-04 01:27:46 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'with user in the parent group' do
it 'returns correct access level' do
expect(shared_group_parent.max_member_access_for_user(parent_group_user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(parent_group_user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group_child.max_member_access_for_user(parent_group_user)).to eq(Gitlab::Access::NO_ACCESS)
2021-06-08 01:23:25 +05:30
end
2021-09-04 01:27:46 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'with user in the child group' do
it 'returns correct access level' do
expect(shared_group_parent.max_member_access_for_user(child_group_user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(child_group_user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group_child.max_member_access_for_user(child_group_user)).to eq(Gitlab::Access::NO_ACCESS)
2021-06-08 01:23:25 +05:30
end
2021-09-04 01:27:46 +05:30
end
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
context 'unrelated project owner' do
let(:common_id) { [Project.maximum(:id).to_i, Namespace.maximum(:id).to_i].max + 999 }
let!(:group) { create(:group, id: common_id) }
let!(:unrelated_project) { create(:project, id: common_id) }
2022-04-04 11:22:00 +05:30
let(:user) { unrelated_project.first_owner }
2019-12-26 22:10:19 +05:30
2021-09-04 01:27:46 +05:30
it 'returns correct access level' do
expect(shared_group_parent.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group_child.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
2021-06-08 01:23:25 +05:30
end
2021-09-04 01:27:46 +05:30
end
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
context 'user without accepted access request' do
let!(:user) { create(:user) }
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
before do
create(:group_member, :developer, :access_request, user: user, group: group)
end
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
it 'returns correct access level' do
expect(shared_group_parent.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
expect(shared_group_child.max_member_access_for_user(user)).to eq(Gitlab::Access::NO_ACCESS)
2021-04-17 20:07:23 +05:30
end
end
2021-09-04 01:27:46 +05:30
end
2021-04-17 20:07:23 +05:30
2021-09-04 01:27:46 +05:30
context 'multiple groups shared with group' do
let(:user) { create(:user) }
let(:group) { create(:group, :private) }
let(:shared_group_parent) { create(:group, :private) }
let(:shared_group) { create(:group, :private, parent: shared_group_parent) }
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
before do
group.add_owner(user)
2021-06-08 01:23:25 +05:30
2021-09-04 01:27:46 +05:30
create(:group_group_link, { shared_with_group: group,
shared_group: shared_group,
group_access: GroupMember::DEVELOPER })
create(:group_group_link, { shared_with_group: group,
shared_group: shared_group_parent,
group_access: GroupMember::MAINTAINER })
end
2020-11-24 15:15:51 +05:30
2021-09-04 01:27:46 +05:30
it 'returns correct access level' do
expect(shared_group.max_member_access_for_user(user)).to eq(Gitlab::Access::MAINTAINER)
2020-11-24 15:15:51 +05:30
end
end
2019-12-26 22:10:19 +05:30
end
2021-04-17 20:07:23 +05:30
describe '#direct_members' do
let_it_be(:group) { create(:group, :nested) }
2022-08-13 15:12:31 +05:30
let_it_be(:maintainer) { group.parent.add_member(create(:user), GroupMember::MAINTAINER) }
let_it_be(:developer) { group.add_member(create(:user), GroupMember::DEVELOPER) }
2021-04-17 20:07:23 +05:30
it 'does not return members of the parent' do
expect(group.direct_members).not_to include(maintainer)
end
it 'returns the direct member of the group' do
expect(group.direct_members).to include(developer)
end
context 'group sharing' do
let!(:shared_group) { create(:group) }
before do
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
it 'does not return members of the shared_with group' do
expect(shared_group.direct_members).not_to(
include(developer))
end
end
end
2021-06-08 01:23:25 +05:30
shared_examples_for 'members_with_parents' do
2017-08-17 22:00:37 +05:30
let!(:group) { create(:group, :nested) }
2022-08-13 15:12:31 +05:30
let!(:maintainer) { group.parent.add_member(create(:user), GroupMember::MAINTAINER) }
let!(:developer) { group.add_member(create(:user), GroupMember::DEVELOPER) }
2022-05-07 20:08:51 +05:30
let!(:pending_maintainer) { create(:group_member, :awaiting, :maintainer, group: group.parent) }
let!(:pending_developer) { create(:group_member, :awaiting, :developer, group: group) }
2017-08-17 22:00:37 +05:30
2022-05-07 20:08:51 +05:30
it 'returns parents active members' do
2017-08-17 22:00:37 +05:30
expect(group.members_with_parents).to include(developer)
2018-11-18 11:00:15 +05:30
expect(group.members_with_parents).to include(maintainer)
2022-05-07 20:08:51 +05:30
expect(group.members_with_parents).not_to include(pending_developer)
expect(group.members_with_parents).not_to include(pending_maintainer)
2017-08-17 22:00:37 +05:30
end
2020-06-23 00:09:42 +05:30
context 'group sharing' do
let!(:shared_group) { create(:group) }
before do
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
2022-05-07 20:08:51 +05:30
it 'returns shared with group active members' do
2020-06-23 00:09:42 +05:30
expect(shared_group.members_with_parents).to(
include(developer))
2022-05-07 20:08:51 +05:30
expect(shared_group.members_with_parents).not_to(
include(pending_developer))
2020-06-23 00:09:42 +05:30
end
end
2017-08-17 22:00:37 +05:30
end
2021-06-08 01:23:25 +05:30
describe '#members_with_parents' do
it_behaves_like 'members_with_parents'
end
describe '#authorizable_members_with_parents' do
let(:group) { create(:group) }
it_behaves_like 'members_with_parents'
context 'members with associated user but also having invite_token' do
let!(:member) { create(:group_member, :developer, :invited, user: create(:user), group: group) }
it 'includes such members in the result' do
expect(group.authorizable_members_with_parents).to include(member)
end
end
context 'invited members' do
let!(:member) { create(:group_member, :developer, :invited, group: group) }
it 'does not include such members in the result' do
expect(group.authorizable_members_with_parents).not_to include(member)
end
end
context 'members from group shares' do
let(:shared_group) { group }
let(:shared_with_group) { create(:group) }
before do
create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_group)
end
context 'an invited member that is part of the shared_with_group' do
let!(:member) { create(:group_member, :developer, :invited, group: shared_with_group) }
it 'does not include such members in the result' do
expect(shared_group.authorizable_members_with_parents).not_to(
include(member))
end
end
end
end
2020-05-24 23:13:21 +05:30
describe '#members_from_self_and_ancestors_with_effective_access_level' do
let!(:group_parent) { create(:group, :private) }
let!(:group) { create(:group, :private, parent: group_parent) }
let!(:group_child) { create(:group, :private, parent: group) }
let!(:user) { create(:user) }
let(:parent_group_access_level) { Gitlab::Access::REPORTER }
let(:group_access_level) { Gitlab::Access::DEVELOPER }
let(:child_group_access_level) { Gitlab::Access::MAINTAINER }
before do
create(:group_member, user: user, group: group_parent, access_level: parent_group_access_level)
create(:group_member, user: user, group: group, access_level: group_access_level)
2020-11-24 15:15:51 +05:30
create(:group_member, :minimal_access, user: create(:user), source: group)
2020-05-24 23:13:21 +05:30
create(:group_member, user: user, group: group_child, access_level: child_group_access_level)
end
it 'returns effective access level for user' do
expect(group_parent.members_from_self_and_ancestors_with_effective_access_level.as_json).to(
contain_exactly(
hash_including('user_id' => user.id, 'access_level' => parent_group_access_level)
)
)
expect(group.members_from_self_and_ancestors_with_effective_access_level.as_json).to(
contain_exactly(
hash_including('user_id' => user.id, 'access_level' => group_access_level)
)
)
expect(group_child.members_from_self_and_ancestors_with_effective_access_level.as_json).to(
contain_exactly(
hash_including('user_id' => user.id, 'access_level' => child_group_access_level)
)
)
end
end
2021-02-22 17:27:13 +05:30
context 'members-related methods' do
2018-10-15 14:42:47 +05:30
let!(:group) { create(:group, :nested) }
let!(:sub_group) { create(:group, parent: group) }
2022-08-13 15:12:31 +05:30
let!(:maintainer) { group.parent.add_member(create(:user), GroupMember::MAINTAINER) }
let!(:developer) { group.add_member(create(:user), GroupMember::DEVELOPER) }
let!(:other_developer) { group.add_member(create(:user), GroupMember::DEVELOPER) }
2018-10-15 14:42:47 +05:30
2021-02-22 17:27:13 +05:30
describe '#direct_and_indirect_members' do
it 'returns parents members' do
expect(group.direct_and_indirect_members).to include(developer)
expect(group.direct_and_indirect_members).to include(maintainer)
end
it 'returns descendant members' do
expect(group.direct_and_indirect_members).to include(other_developer)
end
2018-10-15 14:42:47 +05:30
end
2021-02-22 17:27:13 +05:30
describe '#direct_and_indirect_members_with_inactive' do
2022-08-13 15:12:31 +05:30
let!(:maintainer_blocked) { group.parent.add_member(create(:user, :blocked), GroupMember::MAINTAINER) }
2021-02-22 17:27:13 +05:30
it 'returns parents members' do
expect(group.direct_and_indirect_members_with_inactive).to include(developer)
expect(group.direct_and_indirect_members_with_inactive).to include(maintainer)
expect(group.direct_and_indirect_members_with_inactive).to include(maintainer_blocked)
end
it 'returns descendant members' do
expect(group.direct_and_indirect_members_with_inactive).to include(other_developer)
end
2018-10-15 14:42:47 +05:30
end
end
2019-10-12 21:52:04 +05:30
describe '#users_with_descendants' do
2018-10-15 14:42:47 +05:30
let(:user_a) { create(:user) }
let(:user_b) { create(:user) }
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
let(:deep_nested_group) { create(:group, parent: nested_group) }
it 'returns member users on every nest level without duplication' do
group.add_developer(user_a)
nested_group.add_developer(user_b)
2019-02-15 15:39:39 +05:30
deep_nested_group.add_maintainer(user_a)
2018-10-15 14:42:47 +05:30
expect(group.users_with_descendants).to contain_exactly(user_a, user_b)
expect(nested_group.users_with_descendants).to contain_exactly(user_a, user_b)
expect(deep_nested_group.users_with_descendants).to contain_exactly(user_a)
end
end
2021-02-22 17:27:13 +05:30
context 'user-related methods' do
2018-10-15 14:42:47 +05:30
let(:user_a) { create(:user) }
let(:user_b) { create(:user) }
let(:user_c) { create(:user) }
let(:user_d) { create(:user) }
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
let(:deep_nested_group) { create(:group, parent: nested_group) }
let(:project) { create(:project, namespace: group) }
before do
group.add_developer(user_a)
group.add_developer(user_c)
nested_group.add_developer(user_b)
deep_nested_group.add_developer(user_a)
project.add_developer(user_d)
end
2021-02-22 17:27:13 +05:30
describe '#direct_and_indirect_users' do
it 'returns member users on every nest level without duplication' do
expect(group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c, user_d)
expect(nested_group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c)
expect(deep_nested_group.direct_and_indirect_users).to contain_exactly(user_a, user_b, user_c)
end
it 'does not return members of projects belonging to ancestor groups' do
expect(nested_group.direct_and_indirect_users).not_to include(user_d)
end
2018-10-15 14:42:47 +05:30
end
2021-02-22 17:27:13 +05:30
describe '#direct_and_indirect_users_with_inactive' do
let(:user_blocked_1) { create(:user, :blocked) }
let(:user_blocked_2) { create(:user, :blocked) }
let(:user_blocked_3) { create(:user, :blocked) }
let(:project_in_group) { create(:project, namespace: nested_group) }
before do
group.add_developer(user_blocked_1)
nested_group.add_developer(user_blocked_1)
deep_nested_group.add_developer(user_blocked_2)
project_in_group.add_developer(user_blocked_3)
end
it 'returns member users on every nest level without duplication' do
expect(group.direct_and_indirect_users_with_inactive).to contain_exactly(user_a, user_b, user_c, user_d, user_blocked_1, user_blocked_2, user_blocked_3)
expect(nested_group.direct_and_indirect_users_with_inactive).to contain_exactly(user_a, user_b, user_c, user_blocked_1, user_blocked_2, user_blocked_3)
expect(deep_nested_group.direct_and_indirect_users_with_inactive).to contain_exactly(user_a, user_b, user_c, user_blocked_1, user_blocked_2)
end
it 'returns members of projects belonging to group' do
expect(nested_group.direct_and_indirect_users_with_inactive).to include(user_blocked_3)
end
2018-10-15 14:42:47 +05:30
end
end
2019-10-12 21:52:04 +05:30
describe '#project_users_with_descendants' do
2018-10-15 14:42:47 +05:30
let(:user_a) { create(:user) }
let(:user_b) { create(:user) }
let(:user_c) { create(:user) }
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
let(:deep_nested_group) { create(:group, parent: nested_group) }
let(:project_a) { create(:project, namespace: group) }
let(:project_b) { create(:project, namespace: nested_group) }
let(:project_c) { create(:project, namespace: deep_nested_group) }
it 'returns members of all projects in group and subgroups' do
project_a.add_developer(user_a)
project_b.add_developer(user_b)
project_c.add_developer(user_c)
expect(group.project_users_with_descendants).to contain_exactly(user_a, user_b, user_c)
expect(nested_group.project_users_with_descendants).to contain_exactly(user_b, user_c)
expect(deep_nested_group.project_users_with_descendants).to contain_exactly(user_c)
end
end
2021-04-17 20:07:23 +05:30
describe '#refresh_members_authorized_projects' do
let_it_be(:group) { create(:group, :nested) }
let_it_be(:parent_group_user) { create(:user) }
let_it_be(:group_user) { create(:user) }
before do
group.parent.add_maintainer(parent_group_user)
group.add_developer(group_user)
end
context 'users for which authorizations refresh is executed' do
it 'processes authorizations refresh for all members of the group' do
expect(UserProjectAccessChangedService).to receive(:new).with(contain_exactly(group_user.id, parent_group_user.id)).and_call_original
group.refresh_members_authorized_projects
end
context 'when explicitly specified to run only for direct members' do
it 'processes authorizations refresh only for direct members of the group' do
expect(UserProjectAccessChangedService).to receive(:new).with(contain_exactly(group_user.id)).and_call_original
group.refresh_members_authorized_projects(direct_members_only: true)
end
end
end
end
describe '#users_ids_of_direct_members' do
let_it_be(:group) { create(:group, :nested) }
let_it_be(:parent_group_user) { create(:user) }
let_it_be(:group_user) { create(:user) }
before do
group.parent.add_maintainer(parent_group_user)
group.add_developer(group_user)
end
it 'does not return user ids of the members of the parent' do
expect(group.users_ids_of_direct_members).not_to include(parent_group_user.id)
end
it 'returns the user ids of the direct member of the group' do
expect(group.users_ids_of_direct_members).to include(group_user.id)
end
context 'group sharing' do
let!(:shared_group) { create(:group) }
before do
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
it 'does not return the user ids of members of the shared_with group' do
expect(shared_group.users_ids_of_direct_members).not_to(
include(group_user.id))
end
end
end
2017-08-17 22:00:37 +05:30
describe '#user_ids_for_project_authorizations' do
it 'returns the user IDs for which to refresh authorizations' do
2018-11-18 11:00:15 +05:30
maintainer = create(:user)
2017-08-17 22:00:37 +05:30
developer = create(:user)
2022-08-13 15:12:31 +05:30
group.add_member(maintainer, GroupMember::MAINTAINER)
group.add_member(developer, GroupMember::DEVELOPER)
2017-08-17 22:00:37 +05:30
2017-09-10 17:25:29 +05:30
expect(group.user_ids_for_project_authorizations)
2018-11-18 11:00:15 +05:30
.to include(maintainer.id, developer.id)
2017-08-17 22:00:37 +05:30
end
2020-06-23 00:09:42 +05:30
context 'group sharing' do
let_it_be(:group) { create(:group) }
let_it_be(:group_user) { create(:user) }
let_it_be(:shared_group) { create(:group) }
before do
group.add_developer(group_user)
create(:group_group_link, shared_group: shared_group, shared_with_group: group)
end
it 'returns the user IDs for shared with group members' do
expect(shared_group.user_ids_for_project_authorizations).to(
include(group_user.id))
end
end
2021-04-17 20:07:23 +05:30
context 'distinct user ids' do
let_it_be(:subgroup) { create(:group, :nested) }
let_it_be(:user) { create(:user) }
let_it_be(:shared_with_group) { create(:group) }
let_it_be(:other_subgroup_user) { create(:user) }
before do
create(:group_group_link, shared_group: subgroup, shared_with_group: shared_with_group)
subgroup.add_maintainer(other_subgroup_user)
# `user` is added as a direct member of the parent group, the subgroup
# and another group shared with the subgroup.
subgroup.parent.add_maintainer(user)
subgroup.add_developer(user)
shared_with_group.add_guest(user)
end
it 'returns only distinct user ids of users for which to refresh authorizations' do
expect(subgroup.user_ids_for_project_authorizations).to(
contain_exactly(user.id, other_subgroup_user.id))
end
end
2017-08-17 22:00:37 +05:30
end
2023-03-04 22:38:38 +05:30
describe '#self_and_hierarchy_intersecting_with_user_groups' do
let_it_be(:user) { create(:user) }
let(:subject) { group.self_and_hierarchy_intersecting_with_user_groups(user) }
it 'makes a call to GroupsFinder' do
expect(GroupsFinder).to receive_message_chain(:new, :execute, :unscope)
subject
end
context 'when the group is private' do
let_it_be(:group) { create(:group, :private) }
context 'when the user is not a member of the group' do
it 'is an empty array' do
expect(subject).to eq([])
end
end
context 'when the user is a member of the group' do
before do
group.add_developer(user)
end
it 'is equal to the group' do
expect(subject).to match_array([group])
end
end
context 'when the group has a sub group' do
let_it_be(:subgroup) { create(:group, :private, parent: group) }
context 'when the user is not a member of the subgroup' do
it 'is an empty array' do
expect(subject).to eq([])
end
end
context 'when the user is a member of the subgroup' do
before do
subgroup.add_developer(user)
end
it 'is equal to the group and subgroup' do
expect(subject).to match_array([group, subgroup])
end
context 'when the group has an ancestor' do
let_it_be(:ancestor) { create(:group, :private) }
before do
group.parent = ancestor
group.save!
end
it 'is equal to the ancestor, group and subgroup' do
expect(subject).to match_array([ancestor, group, subgroup])
end
end
end
end
end
context 'when the group is public' do
let_it_be(:group) { create(:group, :public) }
it 'is equal to the public group regardless of membership' do
expect(subject).to match_array([group])
end
end
end
2022-10-11 01:57:18 +05:30
describe '#update_two_factor_requirement_for_members' do
let_it_be_with_reload(:user) { create(:user) }
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
context 'group membership' do
2022-10-11 01:57:18 +05:30
it 'enables two_factor_requirement for group members' do
2022-08-13 15:12:31 +05:30
group.add_member(user, GroupMember::OWNER)
2019-09-04 21:01:54 +05:30
group.update!(require_two_factor_authentication: true)
2017-08-17 22:00:37 +05:30
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2017-08-17 22:00:37 +05:30
2022-10-11 01:57:18 +05:30
expect(user.reload.require_two_factor_authentication_from_group).to be_truthy
2019-09-04 21:01:54 +05:30
end
2022-10-11 01:57:18 +05:30
it 'disables two_factor_requirement for group members' do
user.update!(require_two_factor_authentication_from_group: true)
group.add_member(user, GroupMember::OWNER)
group.update!(require_two_factor_authentication: false)
2019-09-04 21:01:54 +05:30
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2019-09-04 21:01:54 +05:30
2022-10-11 01:57:18 +05:30
expect(user.reload.require_two_factor_authentication_from_group).to be_falsey
2019-09-04 21:01:54 +05:30
end
2017-08-17 22:00:37 +05:30
end
2019-10-12 21:52:04 +05:30
context 'sub groups and projects' do
context 'expanded group members' do
2019-09-04 21:01:54 +05:30
let(:indirect_user) { create(:user) }
2021-01-29 00:20:46 +05:30
context 'two_factor_requirement is enabled' do
context 'two_factor_requirement is also enabled for ancestor group' do
it 'enables two_factor_requirement for subgroup member' do
subgroup = create(:group, :nested, parent: group)
2022-08-13 15:12:31 +05:30
subgroup.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(require_two_factor_authentication: true)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_truthy
end
end
context 'two_factor_requirement is disabled for ancestor group' do
it 'enables two_factor_requirement for subgroup member' do
subgroup = create(:group, :nested, parent: group, require_two_factor_authentication: true)
2022-08-13 15:12:31 +05:30
subgroup.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(require_two_factor_authentication: false)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_truthy
end
it 'enable two_factor_requirement for ancestor group member' do
ancestor_group = create(:group)
2022-08-13 15:12:31 +05:30
ancestor_group.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(parent: ancestor_group)
group.update!(require_two_factor_authentication: true)
2019-09-04 21:01:54 +05:30
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_truthy
end
end
2019-09-04 21:01:54 +05:30
end
2021-01-29 00:20:46 +05:30
context 'two_factor_requirement is disabled' do
context 'two_factor_requirement is enabled for ancestor group' do
it 'enables two_factor_requirement for subgroup member' do
subgroup = create(:group, :nested, parent: group)
2022-08-13 15:12:31 +05:30
subgroup.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(require_two_factor_authentication: true)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_truthy
end
end
context 'two_factor_requirement is also disabled for ancestor group' do
it 'disables two_factor_requirement for subgroup member' do
subgroup = create(:group, :nested, parent: group)
2022-08-13 15:12:31 +05:30
subgroup.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(require_two_factor_authentication: false)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_falsey
end
it 'disables two_factor_requirement for ancestor group member' do
ancestor_group = create(:group, require_two_factor_authentication: false)
indirect_user.update!(require_two_factor_authentication_from_group: true)
2022-08-13 15:12:31 +05:30
ancestor_group.add_member(indirect_user, GroupMember::OWNER)
2021-01-29 00:20:46 +05:30
group.update!(require_two_factor_authentication: false)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2021-01-29 00:20:46 +05:30
expect(indirect_user.reload.require_two_factor_authentication_from_group).to be_falsey
end
end
2019-09-04 21:01:54 +05:30
end
end
context 'project members' do
it 'does not enable two_factor_requirement for child project member' do
project = create(:project, group: group)
project.add_maintainer(user)
group.update!(require_two_factor_authentication: true)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2019-09-04 21:01:54 +05:30
expect(user.reload.require_two_factor_authentication_from_group).to be_falsey
end
2019-10-12 21:52:04 +05:30
it 'does not enable two_factor_requirement for subgroup child project member' do
2019-09-04 21:01:54 +05:30
subgroup = create(:group, :nested, parent: group)
project = create(:project, group: subgroup)
project.add_maintainer(user)
group.update!(require_two_factor_authentication: true)
2022-10-11 01:57:18 +05:30
group.update_two_factor_requirement_for_members
2019-09-04 21:01:54 +05:30
expect(user.reload.require_two_factor_authentication_from_group).to be_falsey
end
end
2017-08-17 22:00:37 +05:30
end
2016-11-03 12:29:30 +05:30
end
2017-09-10 17:25:29 +05:30
2022-10-11 01:57:18 +05:30
describe '#update_two_factor_requirement' do
it 'enqueues a job when require_two_factor_authentication is changed' do
expect(Groups::UpdateTwoFactorRequirementForMembersWorker).to receive(:perform_async).with(group.id)
group.update!(require_two_factor_authentication: true)
end
it 'enqueues a job when two_factor_grace_period is changed' do
expect(Groups::UpdateTwoFactorRequirementForMembersWorker).to receive(:perform_async).with(group.id)
group.update!(two_factor_grace_period: 23)
end
it 'does not enqueue a job when other attributes are changed' do
expect(Groups::UpdateTwoFactorRequirementForMembersWorker).not_to receive(:perform_async).with(group.id)
group.update!(description: 'foobar')
end
end
2018-03-17 18:26:18 +05:30
describe '#path_changed_hook' do
let(:system_hook_service) { SystemHooksService.new }
context 'for a new group' do
let(:group) { build(:group) }
before do
expect(group).to receive(:system_hook_service).and_return(system_hook_service)
end
it 'does not trigger system hook' do
expect(system_hook_service).to receive(:execute_hooks_for).with(group, :create)
group.save!
end
end
context 'for an existing group' do
let(:group) { create(:group, path: 'old-path') }
context 'when the path is changed' do
let(:new_path) { 'very-new-path' }
it 'triggers the rename system hook' do
expect(group).to receive(:system_hook_service).and_return(system_hook_service)
expect(system_hook_service).to receive(:execute_hooks_for).with(group, :rename)
2018-11-18 11:00:15 +05:30
group.update!(path: new_path)
2018-03-17 18:26:18 +05:30
end
end
context 'when the path is not changed' do
it 'does not trigger system hook' do
expect(group).not_to receive(:system_hook_service)
2018-11-18 11:00:15 +05:30
group.update!(name: 'new name')
2018-03-17 18:26:18 +05:30
end
end
end
end
2019-10-12 21:52:04 +05:30
describe '#highest_group_member' do
2019-03-02 22:35:43 +05:30
let(:nested_group) { create(:group, parent: group) }
let(:nested_group_2) { create(:group, parent: nested_group) }
let(:user) { create(:user) }
subject(:highest_group_member) { nested_group_2.highest_group_member(user) }
context 'when the user is not a member of any group in the hierarchy' do
it 'returns nil' do
expect(highest_group_member).to be_nil
end
end
context 'when the user is only a member of one group in the hierarchy' do
before do
nested_group.add_developer(user)
end
it 'returns that group member' do
expect(highest_group_member.access_level).to eq(Gitlab::Access::DEVELOPER)
end
end
context 'when the user is a member of several groups in the hierarchy' do
before do
group.add_owner(user)
nested_group.add_developer(user)
nested_group_2.add_maintainer(user)
end
it 'returns the group member with the highest access level' do
expect(highest_group_member.access_level).to eq(Gitlab::Access::OWNER)
end
end
end
2022-03-02 08:16:31 +05:30
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
2020-03-13 15:44:24 +05:30
describe '#related_group_ids' do
let(:nested_group) { create(:group, parent: group) }
let(:shared_with_group) { create(:group, parent: group) }
before do
create(:group_group_link, shared_group: nested_group,
shared_with_group: shared_with_group)
end
subject(:related_group_ids) { nested_group.related_group_ids }
it 'returns id' do
expect(related_group_ids).to include(nested_group.id)
end
it 'returns ancestor id' do
expect(related_group_ids).to include(group.id)
end
it 'returns shared with group id' do
expect(related_group_ids).to include(shared_with_group.id)
end
context 'with more than one ancestor group' do
let(:ancestor_group) { create(:group) }
before do
2021-12-11 22:18:48 +05:30
group.update!(parent: ancestor_group)
2020-03-13 15:44:24 +05:30
end
it 'returns all ancestor group ids' do
expect(related_group_ids).to(
include(group.id, ancestor_group.id))
end
end
context 'with more than one shared with group' do
let(:another_shared_with_group) { create(:group, parent: group) }
before do
2022-10-11 01:57:18 +05:30
create(:group_group_link, shared_group: nested_group, shared_with_group: another_shared_with_group)
2020-03-13 15:44:24 +05:30
end
it 'returns all shared with group ids' do
expect(related_group_ids).to(
include(shared_with_group.id, another_shared_with_group.id))
end
end
end
2018-11-08 19:23:39 +05:30
context 'with uploads' do
2019-02-15 15:39:39 +05:30
it_behaves_like 'model with uploads', true do
2018-11-08 19:23:39 +05:30
let(:model_object) { create(:group, :with_avatar) }
let(:upload_attribute) { :avatar }
let(:uploader_class) { AttachmentUploader }
end
end
2019-02-15 15:39:39 +05:30
2019-07-07 11:18:12 +05:30
describe '#first_auto_devops_config' do
using RSpec::Parameterized::TableSyntax
let(:group) { create(:group) }
2022-05-07 20:08:51 +05:30
subject(:fetch_config) { group.first_auto_devops_config }
2019-07-07 11:18:12 +05:30
where(:instance_value, :group_value, :config) do
# Instance level enabled
true | nil | { status: true, scope: :instance }
true | true | { status: true, scope: :group }
true | false | { status: false, scope: :group }
# Instance level disabled
false | nil | { status: false, scope: :instance }
false | true | { status: true, scope: :group }
false | false | { status: false, scope: :group }
end
with_them do
before do
stub_application_setting(auto_devops_enabled: instance_value)
group.update_attribute(:auto_devops_enabled, group_value)
end
it { is_expected.to eq(config) }
end
2019-10-12 21:52:04 +05:30
context 'with parent groups' do
2022-05-07 20:08:51 +05:30
let(:parent) { create(:group) }
2019-07-07 11:18:12 +05:30
where(:instance_value, :parent_value, :group_value, :config) do
# Instance level enabled
true | nil | nil | { status: true, scope: :instance }
true | nil | true | { status: true, scope: :group }
true | nil | false | { status: false, scope: :group }
true | true | nil | { status: true, scope: :group }
true | true | true | { status: true, scope: :group }
true | true | false | { status: false, scope: :group }
true | false | nil | { status: false, scope: :group }
true | false | true | { status: true, scope: :group }
true | false | false | { status: false, scope: :group }
# Instance level disable
false | nil | nil | { status: false, scope: :instance }
false | nil | true | { status: true, scope: :group }
false | nil | false | { status: false, scope: :group }
false | true | nil | { status: true, scope: :group }
false | true | true | { status: true, scope: :group }
false | true | false | { status: false, scope: :group }
false | false | nil | { status: false, scope: :group }
false | false | true | { status: true, scope: :group }
false | false | false | { status: false, scope: :group }
end
with_them do
2022-05-07 20:08:51 +05:30
def define_cache_expectations(cache_key)
if group_value.nil?
expect(Rails.cache).to receive(:fetch).with(start_with(cache_key), expires_in: 1.day)
else
expect(Rails.cache).not_to receive(:fetch).with(start_with(cache_key), expires_in: 1.day)
end
end
2019-07-07 11:18:12 +05:30
before do
stub_application_setting(auto_devops_enabled: instance_value)
group.update!(
auto_devops_enabled: group_value,
parent: parent
)
2022-05-07 20:08:51 +05:30
parent.update!(auto_devops_enabled: parent_value)
group.reload # Reload so we get the populated traversal IDs
2019-07-07 11:18:12 +05:30
end
it { is_expected.to eq(config) }
2022-05-07 20:08:51 +05:30
it 'caches the parent config when group auto_devops_enabled is nil' do
cache_key = "namespaces:{#{group.traversal_ids.first}}:first_auto_devops_config:#{group.id}"
define_cache_expectations(cache_key)
fetch_config
end
end
context 'cache expiration' do
before do
group.update!(parent: parent)
reload_models(parent)
end
it 'clears both self and descendant cache when the parent value is updated' do
expect(Rails.cache).to receive(:delete_multi)
.with(
2022-11-25 23:54:43 +05:30
match_array(
[
start_with("namespaces:{#{parent.traversal_ids.first}}:first_auto_devops_config:#{parent.id}"),
start_with("namespaces:{#{parent.traversal_ids.first}}:first_auto_devops_config:#{group.id}")
])
2022-05-07 20:08:51 +05:30
)
parent.update!(auto_devops_enabled: true)
end
it 'only clears self cache when there are no dependents' do
expect(Rails.cache).to receive(:delete_multi)
.with([start_with("namespaces:{#{group.traversal_ids.first}}:first_auto_devops_config:#{group.id}")])
group.update!(auto_devops_enabled: true)
end
2019-07-07 11:18:12 +05:30
end
end
end
describe '#auto_devops_enabled?' do
subject { group.auto_devops_enabled? }
context 'when auto devops is explicitly enabled on group' do
let(:group) { create(:group, :auto_devops_enabled) }
it { is_expected.to be_truthy }
end
context 'when auto devops is explicitly disabled on group' do
let(:group) { create(:group, :auto_devops_disabled) }
it { is_expected.to be_falsy }
end
context 'when auto devops is implicitly enabled or disabled' do
before do
stub_application_setting(auto_devops_enabled: false)
group.update!(parent: parent_group)
end
context 'when auto devops is enabled on root group' do
let(:root_group) { create(:group, :auto_devops_enabled) }
let(:subgroup) { create(:group, parent: root_group) }
let(:parent_group) { create(:group, parent: subgroup) }
it { is_expected.to be_truthy }
end
context 'when auto devops is disabled on root group' do
let(:root_group) { create(:group, :auto_devops_disabled) }
let(:subgroup) { create(:group, parent: root_group) }
let(:parent_group) { create(:group, parent: subgroup) }
it { is_expected.to be_falsy }
end
context 'when auto devops is disabled on parent group and enabled on root group' do
let(:root_group) { create(:group, :auto_devops_enabled) }
let(:parent_group) { create(:group, :auto_devops_disabled, parent: root_group) }
it { is_expected.to be_falsy }
end
end
end
describe 'project_creation_level' do
it 'outputs the default one if it is nil' do
group = create(:group, project_creation_level: nil)
expect(group.project_creation_level).to eq(Gitlab::CurrentSettings.default_project_creation)
end
end
2019-10-12 21:52:04 +05:30
describe 'subgroup_creation_level' do
it 'defaults to maintainers' do
expect(group.subgroup_creation_level)
.to eq(Gitlab::Access::MAINTAINER_SUBGROUP_ACCESS)
end
end
2019-12-04 20:38:33 +05:30
describe '#access_request_approvers_to_be_notified' do
2021-06-08 01:23:25 +05:30
let_it_be(:group) { create(:group, :public) }
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
it 'returns a maximum of ten owners of the group in recent_sign_in descending order' do
2021-09-04 01:27:46 +05:30
limit = 2
stub_const("Member::ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT", limit)
users = create_list(:user, limit + 1, :with_sign_ins)
2019-12-04 20:38:33 +05:30
active_owners = users.map do |user|
create(:group_member, :owner, group: group, user: user)
end
2021-06-08 01:23:25 +05:30
active_owners_in_recent_sign_in_desc_order = group.members_and_requesters
.id_in(active_owners)
2021-09-04 01:27:46 +05:30
.order_recent_sign_in.limit(limit)
2019-12-04 20:38:33 +05:30
expect(group.access_request_approvers_to_be_notified).to eq(active_owners_in_recent_sign_in_desc_order)
end
2021-06-08 01:23:25 +05:30
it 'returns active, non_invited, non_requested owners of the group' do
owner = create(:group_member, :owner, source: group)
create(:group_member, :maintainer, group: group)
create(:group_member, :owner, :invited, group: group)
create(:group_member, :owner, :access_request, group: group)
create(:group_member, :owner, :blocked, group: group)
expect(group.access_request_approvers_to_be_notified.to_a).to eq([owner])
end
2019-12-04 20:38:33 +05:30
end
2019-12-21 20:55:43 +05:30
2021-03-11 19:13:27 +05:30
describe '.preset_root_ancestor_for' do
let_it_be(:rootgroup, reload: true) { create(:group) }
let_it_be(:subgroup, reload: true) { create(:group, parent: rootgroup) }
let_it_be(:subgroup2, reload: true) { create(:group, parent: subgroup) }
it 'does noting for single group' do
expect(subgroup).not_to receive(:self_and_ancestors)
described_class.preset_root_ancestor_for([subgroup])
end
it 'sets the same root_ancestor for multiple groups' do
expect(subgroup).not_to receive(:self_and_ancestors)
expect(subgroup2).not_to receive(:self_and_ancestors)
described_class.preset_root_ancestor_for([rootgroup, subgroup, subgroup2])
expect(subgroup.root_ancestor).to eq(rootgroup)
expect(subgroup2.root_ancestor).to eq(rootgroup)
end
end
2021-01-03 14:25:43 +05:30
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
2021-04-29 21:17:54 +05:30
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) }
2021-01-03 14:25:43 +05:30
2021-04-29 21:17:54 +05:30
it 'raises exception' do
expect { subject }
2021-01-03 14:25:43 +05:30
.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled')
2021-04-29 21:17:54 +05:30
end
it 'does not enable shared runners' do
expect do
2022-08-27 11:52:29 +05:30
begin
subject
rescue StandardError
nil
end
2021-04-29 21:17:54 +05:30
parent.reload
group.reload
project.reload
end.to not_change { parent.shared_runners_enabled }
2021-01-03 14:25:43 +05:30
.and not_change { group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
end
2020-07-28 23:09:34 +05:30
end
2021-01-03 14:25:43 +05:30
context 'root group with shared runners disabled' do
let_it_be(:group) { create(:group, :shared_runners_disabled) }
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
it 'enables shared Runners only for itself' do
expect { subject_and_reload(group, sub_group, project) }
.to change { group.shared_runners_enabled }.from(false).to(true)
.and not_change { sub_group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
2020-07-28 23:09:34 +05:30
end
end
end
2021-01-03 14:25:43 +05:30
context 'disabled_and_unoverridable' do
let_it_be(:group) { create(:group) }
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
let_it_be(:sub_group_2) { create(:group, parent: group) }
let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
2021-11-18 22:05:49 +05:30
subject { group.update_shared_runners_setting!(Namespace::SR_DISABLED_AND_UNOVERRIDABLE) }
2021-01-03 14:25:43 +05:30
it 'disables shared Runners for all descendant groups and projects' do
expect { subject_and_reload(group, sub_group, sub_group_2, project, project_2) }
.to change { group.shared_runners_enabled }.from(true).to(false)
.and not_change { group.allow_descendants_override_disabled_shared_runners }
.and not_change { sub_group.shared_runners_enabled }
.and change { sub_group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
.and change { sub_group_2.shared_runners_enabled }.from(true).to(false)
.and not_change { sub_group_2.allow_descendants_override_disabled_shared_runners }
.and change { project.shared_runners_enabled }.from(true).to(false)
.and change { project_2.shared_runners_enabled }.from(true).to(false)
end
context 'with override on self' do
let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
it 'disables it' do
expect { subject_and_reload(group) }
.to not_change { group.shared_runners_enabled }
.and change { group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
end
2020-07-28 23:09:34 +05:30
end
end
2023-03-17 16:20:25 +05:30
context 'disabled_and_overridable' do
subject { group.update_shared_runners_setting!(Namespace::SR_DISABLED_AND_OVERRIDABLE) }
context 'top level group' do
let_it_be(:group) { create(:group, :shared_runners_disabled) }
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
it 'enables allow descendants to override only for itself' do
expect { subject_and_reload(group, sub_group, project) }
.to change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and not_change { group.shared_runners_enabled }
.and not_change { sub_group.allow_descendants_override_disabled_shared_runners }
.and not_change { sub_group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
end
end
context 'group that its ancestors have shared Runners disabled but allows to override' do
let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
it 'enables allow descendants to override' do
expect { subject_and_reload(parent, group, project) }
.to not_change { parent.allow_descendants_override_disabled_shared_runners }
.and not_change { parent.shared_runners_enabled }
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and not_change { group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
end
end
context 'when parent does not allow' do
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 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')
end
it 'does not allow descendants to override' do
expect do
begin
subject
rescue StandardError
nil
end
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 }
end
end
context 'top level group that has shared Runners enabled' do
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
let_it_be(:sub_group) { create(:group, shared_runners_enabled: true, parent: group) }
let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
it 'enables allow descendants to override & disables shared runners everywhere' do
expect { subject_and_reload(group, sub_group, project) }
.to change { group.shared_runners_enabled }.from(true).to(false)
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and change { sub_group.shared_runners_enabled }.from(true).to(false)
.and change { project.shared_runners_enabled }.from(true).to(false)
end
end
end
context 'disabled_with_override (deprecated)' do
2021-11-18 22:05:49 +05:30
subject { group.update_shared_runners_setting!(Namespace::SR_DISABLED_WITH_OVERRIDE) }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
context 'top level group' do
let_it_be(:group) { create(:group, :shared_runners_disabled) }
let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
it 'enables allow descendants to override only for itself' do
expect { subject_and_reload(group, sub_group, project) }
.to change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and not_change { group.shared_runners_enabled }
.and not_change { sub_group.allow_descendants_override_disabled_shared_runners }
.and not_change { sub_group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
end
2020-07-28 23:09:34 +05:30
end
2021-01-03 14:25:43 +05:30
context 'group that its ancestors have shared Runners disabled but allows to override' do
let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
it 'enables allow descendants to override' do
expect { subject_and_reload(parent, group, project) }
.to not_change { parent.allow_descendants_override_disabled_shared_runners }
.and not_change { parent.shared_runners_enabled }
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and not_change { group.shared_runners_enabled }
.and not_change { project.shared_runners_enabled }
end
2020-07-28 23:09:34 +05:30
end
2021-01-03 14:25:43 +05:30
context 'when parent does not allow' do
2023-01-13 00:05:48 +05:30
let_it_be(:parent, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false) }
2021-04-29 21:17:54 +05:30
let_it_be(:group, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
2020-07-28 23:09:34 +05:30
2021-04-29 21:17:54 +05:30
it 'raises exception' do
expect { subject }
2021-01-03 14:25:43 +05:30
.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it')
2021-04-29 21:17:54 +05:30
end
it 'does not allow descendants to override' do
expect do
2022-08-27 11:52:29 +05:30
begin
subject
rescue StandardError
nil
end
2021-04-29 21:17:54 +05:30
parent.reload
group.reload
end.to not_change { parent.allow_descendants_override_disabled_shared_runners }
2021-01-03 14:25:43 +05:30
.and not_change { parent.shared_runners_enabled }
.and not_change { group.allow_descendants_override_disabled_shared_runners }
.and not_change { group.shared_runners_enabled }
end
2020-07-28 23:09:34 +05:30
end
2021-01-03 14:25:43 +05:30
context 'top level group that has shared Runners enabled' do
let_it_be(:group) { create(:group, shared_runners_enabled: true) }
let_it_be(:sub_group) { create(:group, shared_runners_enabled: true, parent: group) }
let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
it 'enables allow descendants to override & disables shared runners everywhere' do
expect { subject_and_reload(group, sub_group, project) }
.to change { group.shared_runners_enabled }.from(true).to(false)
.and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
.and change { sub_group.shared_runners_enabled }.from(true).to(false)
.and change { project.shared_runners_enabled }.from(true).to(false)
end
2020-07-28 23:09:34 +05:30
end
end
end
2021-01-03 14:25:43 +05:30
describe "#default_branch_name" do
2021-06-08 01:23:25 +05:30
context "when group.namespace_settings does not have a default branch name" do
2021-01-03 14:25:43 +05:30
it "returns nil" do
expect(group.default_branch_name).to be_nil
2020-07-28 23:09:34 +05:30
end
end
2021-06-08 01:23:25 +05:30
context "when group.namespace_settings has a default branch name" do
2021-01-03 14:25:43 +05:30
let(:example_branch_name) { "example_branch_name" }
2020-07-28 23:09:34 +05:30
2021-01-03 14:25:43 +05:30
before do
2021-06-08 01:23:25 +05:30
allow(group.namespace_settings)
2021-01-03 14:25:43 +05:30
.to receive(:default_branch_name)
.and_return(example_branch_name)
2020-07-28 23:09:34 +05:30
end
2021-01-03 14:25:43 +05:30
it "returns the default branch name" do
expect(group.default_branch_name).to eq(example_branch_name)
2020-07-28 23:09:34 +05:30
end
end
end
2020-10-24 23:57:45 +05:30
2023-04-23 21:23:45 +05:30
describe "#access_level_roles" do
let(:group) { create(:group) }
it "returns the correct roles" do
expect(group.access_level_roles).to eq(
{
'Guest' => 10,
'Reporter' => 20,
'Developer' => 30,
'Maintainer' => 40,
'Owner' => 50
}
)
end
end
2021-11-11 11:23:49 +05:30
describe '#membership_locked?' do
it 'returns false' do
expect(build(:group)).not_to be_membership_locked
end
end
2022-03-02 08:16:31 +05:30
describe '#first_owner' do
2020-10-24 23:57:45 +05:30
let(:group) { build(:group) }
context 'the group has owners' do
before do
group.add_owner(create(:user))
group.add_owner(create(:user))
end
it 'is the first owner' do
2022-03-02 08:16:31 +05:30
expect(group.first_owner)
2020-10-24 23:57:45 +05:30
.to eq(group.owners.first)
.and be_a(User)
end
end
context 'the group has a parent' do
let(:parent) { build(:group) }
before do
group.parent = parent
parent.add_owner(create(:user))
end
it 'is the first owner of the parent' do
2022-03-02 08:16:31 +05:30
expect(group.first_owner)
.to eq(parent.first_owner)
2020-10-24 23:57:45 +05:30
.and be_a(User)
end
end
context 'we fallback to group.owner' do
before do
group.owner = build(:user)
end
it 'is the group.owner' do
2022-03-02 08:16:31 +05:30
expect(group.first_owner)
2020-10-24 23:57:45 +05:30
.to eq(group.owner)
.and be_a(User)
end
end
end
2021-01-03 14:25:43 +05:30
describe '#parent_allows_two_factor_authentication?' do
it 'returns true for top-level group' do
expect(group.parent_allows_two_factor_authentication?).to eq(true)
end
context 'for subgroup' do
let(:subgroup) { create(:group, parent: group) }
it 'returns true if parent group allows two factor authentication for its descendants' do
expect(subgroup.parent_allows_two_factor_authentication?).to eq(true)
end
it 'returns true if parent group allows two factor authentication for its descendants' do
group.namespace_settings.update!(allow_mfa_for_subgroups: false)
expect(subgroup.parent_allows_two_factor_authentication?).to eq(false)
end
end
end
2021-01-29 00:20:46 +05:30
describe 'has_project_with_service_desk_enabled?' do
2023-03-04 22:38:38 +05:30
let_it_be_with_refind(:group) { create(:group, :private) }
2021-01-29 00:20:46 +05:30
subject { group.has_project_with_service_desk_enabled? }
before do
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(true)
end
context 'when service desk is enabled' do
context 'for top level group' do
let_it_be(:project) { create(:project, group: group, service_desk_enabled: true) }
it { is_expected.to eq(true) }
context 'when service desk is not supported' do
before do
allow(Gitlab::ServiceDesk).to receive(:supported?).and_return(false)
end
it { is_expected.to eq(false) }
end
end
context 'for subgroup project' do
2022-08-27 11:52:29 +05:30
let_it_be(:subgroup) { create(:group, :private, parent: group) }
2021-01-29 00:20:46 +05:30
let_it_be(:project) { create(:project, group: subgroup, service_desk_enabled: true) }
it { is_expected.to eq(true) }
end
end
context 'when none of group child projects has service desk enabled' do
let_it_be(:project) { create(:project, group: group, service_desk_enabled: false) }
before do
2021-12-11 22:18:48 +05:30
project.update!(service_desk_enabled: false)
2021-01-29 00:20:46 +05:30
end
it { is_expected.to eq(false) }
end
end
2021-03-08 18:12:59 +05:30
describe 'with Debian Distributions' do
subject { create(:group) }
2021-03-11 19:13:27 +05:30
it_behaves_like 'model with Debian distributions'
2021-03-08 18:12:59 +05:30
end
2021-04-29 21:17:54 +05:30
describe '.ids_with_disabled_email' do
2021-11-18 22:05:49 +05:30
let_it_be(:parent_1) { create(:group, emails_disabled: true) }
let_it_be(:child_1) { create(:group, parent: parent_1) }
2021-04-29 21:17:54 +05:30
2021-11-18 22:05:49 +05:30
let_it_be(:parent_2) { create(:group, emails_disabled: false) }
let_it_be(:child_2) { create(:group, parent: parent_2) }
2021-04-29 21:17:54 +05:30
2021-11-18 22:05:49 +05:30
let_it_be(:other_group) { create(:group, emails_disabled: false) }
2021-04-29 21:17:54 +05:30
2021-11-18 22:05:49 +05:30
shared_examples 'returns namespaces with disabled email' do
subject(:group_ids_where_email_is_disabled) { described_class.ids_with_disabled_email([child_1, child_2, other_group]) }
2021-04-29 21:17:54 +05:30
2021-11-18 22:05:49 +05:30
it { is_expected.to eq(Set.new([child_1.id])) }
end
it_behaves_like 'returns namespaces with disabled email'
2021-04-29 21:17:54 +05:30
end
2021-06-08 01:23:25 +05:30
2021-10-27 15:23:28 +05:30
describe '.timelogs' do
let(:project) { create(:project, namespace: group) }
let(:issue) { create(:issue, project: project) }
let(:other_project) { create(:project, namespace: create(:group)) }
let(:other_issue) { create(:issue, project: other_project) }
let!(:timelog1) { create(:timelog, issue: issue) }
let!(:timelog2) { create(:timelog, issue: other_issue) }
let!(:timelog3) { create(:timelog, issue: issue) }
it 'returns timelogs belonging to the group' do
expect(group.timelogs).to contain_exactly(timelog1, timelog3)
end
end
2021-11-11 11:23:49 +05:30
describe '.organizations' do
it 'returns organizations belonging to the group' do
organization1 = create(:organization, group: group)
create(:organization)
organization3 = create(:organization, group: group)
expect(group.organizations).to contain_exactly(organization1, organization3)
end
end
describe '.contacts' do
it 'returns contacts belonging to the group' do
contact1 = create(:contact, group: group)
create(:contact)
contact3 = create(:contact, group: group)
expect(group.contacts).to contain_exactly(contact1, contact3)
end
end
2021-06-08 01:23:25 +05:30
describe '#to_ability_name' do
it 'returns group' do
group = build(:group)
expect(group.to_ability_name).to eq('group')
end
end
describe '#activity_path' do
it 'returns the group activity_path' do
expected_path = "/groups/#{group.name}/-/activity"
expect(group.activity_path).to eq(expected_path)
end
end
2021-09-04 01:27:46 +05:30
context 'with export' do
let(:group) { create(:group, :with_export) }
it '#export_file_exists? returns true' do
expect(group.export_file_exists?).to be true
end
it '#export_archive_exists? returns true' do
expect(group.export_archive_exists?).to be true
end
end
describe '#open_issues_count', :aggregate_failures do
let(:group) { build(:group) }
it 'provides the issue count' do
expect(group.open_issues_count).to eq 0
end
it 'invokes the count service with current_user' do
user = build(:user)
count_service = instance_double(Groups::OpenIssuesCountService)
expect(Groups::OpenIssuesCountService).to receive(:new).with(group, user).and_return(count_service)
expect(count_service).to receive(:count)
group.open_issues_count(user)
end
it 'invokes the count service with no current_user' do
count_service = instance_double(Groups::OpenIssuesCountService)
expect(Groups::OpenIssuesCountService).to receive(:new).with(group, nil).and_return(count_service)
expect(count_service).to receive(:count)
group.open_issues_count
end
end
describe '#open_merge_requests_count', :aggregate_failures do
let(:group) { build(:group) }
it 'provides the merge request count' do
expect(group.open_merge_requests_count).to eq 0
end
it 'invokes the count service with current_user' do
user = build(:user)
count_service = instance_double(Groups::MergeRequestsCountService)
expect(Groups::MergeRequestsCountService).to receive(:new).with(group, user).and_return(count_service)
expect(count_service).to receive(:count)
group.open_merge_requests_count(user)
end
it 'invokes the count service with no current_user' do
count_service = instance_double(Groups::MergeRequestsCountService)
expect(Groups::MergeRequestsCountService).to receive(:new).with(group, nil).and_return(count_service)
expect(count_service).to receive(:count)
group.open_merge_requests_count
end
end
2021-11-11 11:23:49 +05:30
describe '#dependency_proxy_image_prefix' do
let_it_be(:group) { build_stubbed(:group, path: 'GroupWithUPPERcaseLetters') }
it 'converts uppercase letters to lowercase' do
expect(group.dependency_proxy_image_prefix).to end_with("/groupwithuppercaseletters#{DependencyProxy::URL_SUFFIX}")
end
it 'removes the protocol' do
expect(group.dependency_proxy_image_prefix).not_to include('http')
end
it 'does not include /groups' do
expect(group.dependency_proxy_image_prefix).not_to include('/groups')
end
end
describe '#dependency_proxy_image_ttl_policy' do
subject(:ttl_policy) { group.dependency_proxy_image_ttl_policy }
it 'builds a new policy if one does not exist', :aggregate_failures do
expect(ttl_policy.ttl).to eq(90)
expect(ttl_policy.enabled).to eq(false)
expect(ttl_policy.created_at).to be_nil
expect(ttl_policy.updated_at).to be_nil
end
context 'with existing policy' do
before do
group.dependency_proxy_image_ttl_policy.update!(ttl: 30, enabled: true)
end
it 'returns the policy if it already exists', :aggregate_failures do
expect(ttl_policy.ttl).to eq(30)
expect(ttl_policy.enabled).to eq(true)
expect(ttl_policy.created_at).not_to be_nil
expect(ttl_policy.updated_at).not_to be_nil
end
end
end
2022-02-27 12:50:16 +05:30
2022-03-02 08:16:31 +05:30
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
2022-05-07 20:08:51 +05:30
it 'returns true where crm_settings.state is enabled for subgroup' do
subgroup = create(:group, :crm_enabled, parent: group)
expect(subgroup.crm_enabled?).to be_truthy
end
2022-03-02 08:16:31 +05:30
end
2022-05-07 20:08:51 +05:30
2022-03-02 08:16:31 +05:30
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
2022-06-21 17:19:12 +05:30
2023-06-20 00:43:36 +05:30
describe '#content_editor_on_issues_feature_flag_enabled?' do
it_behaves_like 'checks self and root ancestor feature flag' do
let(:feature_flag) { :content_editor_on_issues }
let(:feature_flag_method) { :content_editor_on_issues_feature_flag_enabled? }
end
end
2022-06-21 17:19:12 +05:30
describe '#work_items_feature_flag_enabled?' do
it_behaves_like 'checks self and root ancestor feature flag' do
let(:feature_flag) { :work_items }
let(:feature_flag_method) { :work_items_feature_flag_enabled? }
end
end
2023-03-04 22:38:38 +05:30
describe '#work_items_mvc_feature_flag_enabled?' do
it_behaves_like 'checks self and root ancestor feature flag' do
let(:feature_flag) { :work_items_mvc }
let(:feature_flag_method) { :work_items_mvc_feature_flag_enabled? }
end
end
2022-08-27 11:52:29 +05:30
describe '#work_items_mvc_2_feature_flag_enabled?' do
it_behaves_like 'checks self and root ancestor feature flag' do
let(:feature_flag) { :work_items_mvc_2 }
let(:feature_flag_method) { :work_items_mvc_2_feature_flag_enabled? }
end
end
2022-06-21 17:19:12 +05:30
describe 'group shares' do
let!(:sub_group) { create(:group, parent: group) }
let!(:sub_sub_group) { create(:group, parent: sub_group) }
let!(:shared_group_1) { create(:group) }
let!(:shared_group_2) { create(:group) }
let!(:shared_group_3) { create(:group) }
before do
group.shared_with_groups << shared_group_1
sub_group.shared_with_groups << shared_group_2
sub_sub_group.shared_with_groups << shared_group_3
end
describe '#shared_with_group_links.of_ancestors' do
using RSpec::Parameterized::TableSyntax
where(:subject_group, :result) do
ref(:group) | []
ref(:sub_group) | lazy { [shared_group_1].map(&:id) }
ref(:sub_sub_group) | lazy { [shared_group_1, shared_group_2].map(&:id) }
end
with_them do
it 'returns correct group shares' do
expect(subject_group.shared_with_group_links.of_ancestors.map(&:shared_with_group_id)).to match_array(result)
end
end
end
describe '#shared_with_group_links.of_ancestors_and_self' do
using RSpec::Parameterized::TableSyntax
where(:subject_group, :result) do
ref(:group) | lazy { [shared_group_1].map(&:id) }
ref(:sub_group) | lazy { [shared_group_1, shared_group_2].map(&:id) }
ref(:sub_sub_group) | lazy { [shared_group_1, shared_group_2, shared_group_3].map(&:id) }
end
with_them do
it 'returns correct group shares' do
expect(subject_group.shared_with_group_links.of_ancestors_and_self.map(&:shared_with_group_id)).to match_array(result)
end
end
end
end
2022-07-23 23:45:48 +05:30
2022-10-11 01:57:18 +05:30
describe '#packages_policy_subject' do
it 'returns wrapper' do
expect(group.packages_policy_subject).to be_a(Packages::Policies::Group)
expect(group.packages_policy_subject.group).to eq(group)
end
end
2022-07-23 23:45:48 +05:30
describe '#gitlab_deploy_token' do
subject(:gitlab_deploy_token) { group.gitlab_deploy_token }
context 'when there is a gitlab deploy token associated' do
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, groups: [group]) }
it { is_expected.to eq(deploy_token) }
end
context 'when there is no a gitlab deploy token associated' do
it { is_expected.to be_nil }
end
context 'when there is a gitlab deploy token associated but is has been revoked' do
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, :revoked, groups: [group]) }
it { is_expected.to be_nil }
end
context 'when there is a gitlab deploy token associated but it is expired' do
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, :expired, groups: [group]) }
it { is_expected.to be_nil }
end
context 'when there is a deploy token associated with a different name' do
let!(:deploy_token) { create(:deploy_token, :group, groups: [group]) }
it { is_expected.to be_nil }
end
context 'when there is a gitlab deploy token associated to a different group' do
let!(:deploy_token) { create(:deploy_token, :group, :gitlab_deploy_token, groups: [create(:group)]) }
it { is_expected.to be_nil }
end
end
2023-03-17 16:20:25 +05:30
2023-06-20 00:43:36 +05:30
describe '#usage_quotas_enabled?', feature_category: :consumables_cost_management, unless: Gitlab.ee? do
2023-03-17 16:20:25 +05:30
using RSpec::Parameterized::TableSyntax
where(:feature_enabled, :root_group, :result) do
false | true | false
false | false | false
true | false | false
true | true | true
end
with_them do
before do
stub_feature_flags(usage_quotas_for_all_editions: feature_enabled)
allow(group).to receive(:root?).and_return(root_group)
end
it 'returns the expected result' do
expect(group.usage_quotas_enabled?).to eq result
end
end
end
2023-04-23 21:23:45 +05:30
describe '#readme_project' do
it 'returns groups project containing metadata' do
readme_project = create(:project, path: Group::README_PROJECT_PATH, namespace: group)
create(:project, namespace: group)
expect(group.readme_project).to eq(readme_project)
end
end
describe '#group_readme' do
it 'returns readme from group readme project' do
create(:project, :repository, path: Group::README_PROJECT_PATH, namespace: group)
expect(group.group_readme.name).to eq('README.md')
expect(group.group_readme.data).to include('testme')
end
it 'returns nil if no readme project is present' do
create(:project, :repository, namespace: group)
expect(group.group_readme).to be(nil)
end
end
2014-09-02 18:07:02 +05:30
end