2019-07-07 11:18:12 +05:30
# frozen_string_literal: true
2014-09-02 18:07:02 +05:30
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec . describe Group 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 }
2016-06-16 23:09:34 +05:30
it { is_expected . to have_many ( :group_members ) . dependent ( :destroy ) }
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 ) }
2018-03-17 18:26:18 +05:30
it { is_expected . to have_many ( :members_and_requesters ) }
2016-06-16 23:09:34 +05:30
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 ) }
2021-11-18 22:05:49 +05:30
it { is_expected . to have_many ( :bulk_import_exports ) . class_name ( 'BulkImports::Export' ) }
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' ) }
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
describe '#members & #requesters' do
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
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
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'
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!
group . reload
end
it { expect ( group . traversal_ids ) . to eq [ group . id ] }
end
context 'has a parent' do
let ( :parent ) { create ( :group ) }
let ( :group ) { build ( :group , parent : parent ) }
before do
group . save!
reload_models ( parent , group )
end
it { expect ( parent . traversal_ids ) . to eq [ parent . id ] }
it { expect ( group . traversal_ids ) . to eq [ parent . id , group . id ] }
end
context 'has a parent update before save' do
let ( :parent ) { create ( :group ) }
let ( :group ) { build ( :group , parent : parent ) }
let! ( :new_grandparent ) { create ( :group ) }
before do
parent . update! ( parent : new_grandparent )
group . save!
reload_models ( parent , group )
end
it 'avoid traversal_ids race condition' do
expect ( parent . traversal_ids ) . to eq [ new_grandparent . id , parent . id ]
expect ( group . traversal_ids ) . to eq [ new_grandparent . id , parent . id , group . id ]
end
end
end
context 'traversal_ids on update' do
context 'parent is updated' do
let ( :new_parent ) { create ( :group ) }
subject { group . update! ( parent : new_parent , name : 'new name' ) }
it_behaves_like 'update on column' , :traversal_ids
end
context 'parent is not updated' do
subject { group . update! ( name : 'new name' ) }
it_behaves_like 'no update on column' , :traversal_ids
end
end
context 'traversal_ids on ancestral update' do
context 'update multiple ancestors before save' do
let ( :parent ) { create ( :group ) }
let ( :group ) { create ( :group , parent : parent ) }
let! ( :new_grandparent ) { create ( :group ) }
let! ( :new_parent ) { create ( :group ) }
before do
group . parent = new_parent
new_parent . update! ( parent : new_grandparent )
group . save!
reload_models ( parent , group , new_grandparent , new_parent )
end
it 'avoids traversal_ids race condition' do
expect ( parent . traversal_ids ) . to eq [ parent . id ]
expect ( group . traversal_ids ) . to eq [ new_grandparent . id , new_parent . id , group . id ]
expect ( new_grandparent . traversal_ids ) . to eq [ new_grandparent . id ]
expect ( new_parent . traversal_ids ) . to eq [ new_grandparent . id , new_parent . id ]
end
end
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
let! ( :root ) { create ( :group ) . reload }
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
reload_models ( old_parent , new_parent , group )
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
reload_models ( old_parent , new_parent , group )
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
reload_models ( old_parent , new_parent , group )
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
reload_models ( old_parent , new_parent , group )
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 )
2021-04-29 21:17:54 +05:30
end
it 'updates traversal_ids for all descendants' do
expect ( parent_group . reload . traversal_ids ) . to eq [ new_grandparent . id , parent_group . id ]
expect ( group . reload . traversal_ids ) . to eq [ new_grandparent . id , parent_group . id , group . id ]
end
end
end
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
let! ( :private_group ) { create ( :group , :private ) }
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 ] ) }
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
describe 'by_ids_or_paths' do
let ( :group_path ) { 'group_path' }
let! ( :group ) { create ( :group , path : group_path ) }
let ( :group_id ) { group . id }
it 'returns matching records based on paths' do
expect ( described_class . by_ids_or_paths ( nil , [ group_path ] ) ) . to match_array ( [ group ] )
end
it 'returns matching records based on ids' do
expect ( described_class . by_ids_or_paths ( [ group_id ] , nil ) ) . to match_array ( [ group ] )
end
it 'returns matching records based on both paths and ids' do
new_group = create ( :group )
expect ( described_class . by_ids_or_paths ( [ new_group . id ] , [ group_path ] ) ) . to match_array ( [ group , new_group ] )
end
end
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
2022-06-21 17:19:12 +05:30
it 'adds the user with a blocking refresh by default' do
expect_next_instance_of ( GroupMember ) do | member |
expect ( member ) . to receive ( :refresh_member_authorized_projects ) . with ( blocking : true )
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
2022-06-21 17:19:12 +05:30
it 'passes the blocking refresh value to member' do
expect_next_instance_of ( GroupMember ) do | member |
expect ( member ) . to receive ( :refresh_member_authorized_projects ) . with ( blocking : false )
end
2022-08-13 15:12:31 +05:30
group . add_member ( user , GroupMember :: MAINTAINER , blocking_refresh : false )
2022-06-21 17:19:12 +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
2016-06-16 23:09:34 +05:30
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
2016-06-16 23:09:34 +05:30
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 }
2016-06-16 23:09:34 +05:30
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 }
2016-06-16 23:09:34 +05:30
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
2016-06-16 23:09:34 +05:30
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 }
2016-06-16 23:09:34 +05:30
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
2019-07-07 11:18:12 +05:30
before do
parent_group = create ( :group )
create ( :group_member , :owner , group : parent_group )
2021-12-11 22:18:48 +05:30
group . update! ( parent : parent_group )
2019-07-07 11:18:12 +05:30
end
it { expect ( group . last_owner? ( @members [ :owner ] ) ) . to be_falsy }
end
end
2021-04-29 21:17:54 +05:30
describe '#member_last_blocked_owner?' do
let_it_be ( :blocked_user ) { create ( :user , :blocked ) }
let ( :member ) { blocked_user . group_members . last }
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 )
2021-04-17 20:07:23 +05:30
end
2021-04-29 21:17:54 +05:30
context 'when last_blocked_owner is set' do
before do
expect ( group ) . not_to receive ( :members_with_parents )
end
it 'returns true' do
member . last_blocked_owner = true
expect ( group . member_last_blocked_owner? ( member ) ) . to be ( true )
end
it 'returns false' do
member . last_blocked_owner = false
expect ( group . member_last_blocked_owner? ( member ) ) . to be ( false )
end
end
context 'when last_blocked_owner is not set' do
it { expect ( group . member_last_blocked_owner? ( member ) ) . to be ( true ) }
context 'with another active owner' do
before do
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
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
before do
parent_group = create ( :group )
create ( :group_member , :owner , group : parent_group )
2021-12-11 22:18:48 +05:30
group . update! ( parent : parent_group )
2021-04-29 21:17:54 +05:30
end
it { expect ( group . member_last_blocked_owner? ( member ) ) . to be ( false ) }
end
end
end
context 'when analyzing blocked owners' do
let_it_be ( :blocked_user ) { create ( :user , :blocked ) }
describe '#single_blocked_owner?' do
context 'when there is only one blocked owner' do
before do
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
2022-07-23 23:45:48 +05:30
describe '#all_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
2021-04-29 21:17:54 +05:30
context 'when there is only one owner' do
2022-07-23 23:45:48 +05:30
let! ( :owner ) do
2022-08-13 15:12:31 +05:30
group . add_member ( user , GroupMember :: OWNER )
2021-04-17 20:07:23 +05:30
end
2022-07-23 23:45:48 +05:30
it 'returns the owner' do
expect ( group . all_owners_excluding_project_bots ) . to contain_exactly ( owner )
end
context 'and 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 'returns only the human owner' do
expect ( group . all_owners_excluding_project_bots ) . to contain_exactly ( owner )
end
2021-04-29 21:17:54 +05:30
end
2021-04-17 20:07:23 +05:30
end
2021-04-29 21:17:54 +05:30
context 'when there are multiple owners' do
let_it_be ( :user_2 ) { create ( :user ) }
2022-07-23 23:45:48 +05:30
let! ( :owner ) do
2022-08-13 15:12:31 +05:30
group . add_member ( user , GroupMember :: OWNER )
2022-07-23 23:45:48 +05:30
end
let! ( :owner2 ) do
2022-08-13 15:12:31 +05:30
group . add_member ( user_2 , GroupMember :: OWNER )
2021-04-17 20:07:23 +05:30
end
2022-07-23 23:45:48 +05:30
it 'returns both owners' do
expect ( group . all_owners_excluding_project_bots ) . to contain_exactly ( owner , owner2 )
end
context 'and 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 'returns only the human owners' do
expect ( group . all_owners_excluding_project_bots ) . to contain_exactly ( owner , owner2 )
end
2021-04-29 21:17:54 +05:30
end
end
context 'when there are no owners' do
it 'returns false' do
2022-07-23 23:45:48 +05:30
expect ( group . all_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
2016-06-16 23:09:34 +05:30
def setup_group_members ( group )
members = {
owner : create ( :user ) ,
2018-11-18 11:00:15 +05:30
maintainer : create ( :user ) ,
2016-06-16 23:09:34 +05:30
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 )
2016-06-16 23:09:34 +05:30
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
describe '#update_two_factor_requirement' do
let ( :user ) { create ( :user ) }
2019-09-04 21:01:54 +05:30
context 'group membership' do
before do
2022-08-13 15:12:31 +05:30
group . add_member ( user , GroupMember :: OWNER )
2019-09-04 21:01:54 +05:30
end
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
it 'is called when require_two_factor_authentication is changed' do
expect_any_instance_of ( User ) . to receive ( :update_two_factor_requirement )
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
group . update! ( require_two_factor_authentication : true )
end
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
it 'is called when two_factor_grace_period is changed' do
expect_any_instance_of ( User ) . to receive ( :update_two_factor_requirement )
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
group . update! ( two_factor_grace_period : 23 )
end
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
it 'is not called when other attributes are changed' do
expect_any_instance_of ( User ) . not_to receive ( :update_two_factor_requirement )
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
group . update! ( description : 'foobar' )
end
it 'calls #update_two_factor_requirement on each group member' do
other_user = create ( :user )
2022-08-13 15:12:31 +05:30
group . add_member ( other_user , GroupMember :: OWNER )
2019-09-04 21:01:54 +05:30
calls = 0
allow_any_instance_of ( User ) . to receive ( :update_two_factor_requirement ) do
calls += 1
end
group . update! ( require_two_factor_authentication : true , two_factor_grace_period : 23 )
expect ( calls ) . to eq 2
end
2017-08-17 22:00:37 +05:30
end
2019-10-12 21:52:04 +05:30
context 'sub groups and projects' do
2019-09-04 21:01:54 +05:30
it 'enables two_factor_requirement for group member' do
2022-08-13 15:12:31 +05:30
group . add_member ( user , GroupMember :: OWNER )
2017-08-17 22:00:37 +05:30
2019-09-04 21:01:54 +05:30
group . update! ( require_two_factor_authentication : true )
expect ( user . reload . require_two_factor_authentication_from_group ) . to be_truthy
2017-08-17 22:00:37 +05:30
end
2019-10-12 21:52:04 +05:30
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 )
2017-08-17 22:00:37 +05:30
2021-01-29 00:20:46 +05:30
group . update! ( require_two_factor_authentication : true )
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 )
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
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 )
2019-09-04 21:01:54 +05:30
2021-01-29 00:20:46 +05:30
group . update! ( require_two_factor_authentication : true )
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 )
2019-09-04 21:01:54 +05:30
2021-01-29 00:20:46 +05:30
group . update! ( require_two_factor_authentication : false )
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 )
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 )
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 )
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
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
2018-12-13 13:39:08 +05:30
describe '#ci_variables_for' do
2017-09-10 17:25:29 +05:30
let ( :project ) { create ( :project , group : group ) }
2021-04-17 20:07:23 +05:30
let ( :environment_scope ) { '*' }
2017-09-10 17:25:29 +05:30
2018-12-13 13:39:08 +05:30
let! ( :ci_variable ) do
2021-04-17 20:07:23 +05:30
create ( :ci_group_variable , value : 'secret' , group : group , environment_scope : environment_scope )
2017-09-10 17:25:29 +05:30
end
let! ( :protected_variable ) do
create ( :ci_group_variable , :protected , value : 'protected' , group : group )
end
2018-12-13 13:39:08 +05:30
subject { group . ci_variables_for ( 'ref' , project ) }
2017-09-10 17:25:29 +05:30
2021-04-17 20:07:23 +05:30
it 'memoizes the result by ref and environment' , :request_store do
scoped_variable = create ( :ci_group_variable , value : 'secret' , group : group , environment_scope : 'scoped' )
2020-04-08 14:13:33 +05:30
expect ( project ) . to receive ( :protected_for? ) . with ( 'ref' ) . once . and_return ( true )
2021-04-17 20:07:23 +05:30
expect ( project ) . to receive ( :protected_for? ) . with ( 'other' ) . twice . and_return ( false )
2020-04-08 14:13:33 +05:30
2 . times do
2021-04-17 20:07:23 +05:30
expect ( group . ci_variables_for ( 'ref' , project , environment : 'production' ) ) . to contain_exactly ( ci_variable , protected_variable )
2020-04-08 14:13:33 +05:30
expect ( group . ci_variables_for ( 'other' , project ) ) . to contain_exactly ( ci_variable )
2021-04-17 20:07:23 +05:30
expect ( group . ci_variables_for ( 'other' , project , environment : 'scoped' ) ) . to contain_exactly ( ci_variable , scoped_variable )
2020-04-08 14:13:33 +05:30
end
end
2017-09-10 17:25:29 +05:30
shared_examples 'ref is protected' do
it 'contains all the variables' do
2018-12-13 13:39:08 +05:30
is_expected . to contain_exactly ( ci_variable , protected_variable )
2017-09-10 17:25:29 +05:30
end
end
context 'when the ref is not protected' do
before do
stub_application_setting (
default_branch_protection : Gitlab :: Access :: PROTECTION_NONE )
end
2018-12-13 13:39:08 +05:30
it 'contains only the CI variables' do
is_expected . to contain_exactly ( ci_variable )
2017-09-10 17:25:29 +05:30
end
end
context 'when the ref is a protected branch' do
before do
2018-03-17 18:26:18 +05:30
allow ( project ) . to receive ( :protected_for? ) . with ( 'ref' ) . and_return ( true )
2017-09-10 17:25:29 +05:30
end
it_behaves_like 'ref is protected'
end
context 'when the ref is a protected tag' do
before do
2018-03-17 18:26:18 +05:30
allow ( project ) . to receive ( :protected_for? ) . with ( 'ref' ) . and_return ( true )
2017-09-10 17:25:29 +05:30
end
it_behaves_like 'ref is protected'
end
2021-04-17 20:07:23 +05:30
context 'when environment name is specified' do
let ( :environment ) { 'review/name' }
subject do
group . ci_variables_for ( 'ref' , project , environment : environment )
end
context 'when environment scope is exactly matched' do
let ( :environment_scope ) { 'review/name' }
it { is_expected . to contain_exactly ( ci_variable ) }
end
context 'when environment scope is matched by wildcard' do
let ( :environment_scope ) { 'review/*' }
it { is_expected . to contain_exactly ( ci_variable ) }
end
context 'when environment scope does not match' do
let ( :environment_scope ) { 'review/*/special' }
it { is_expected . not_to contain_exactly ( ci_variable ) }
end
context 'when environment scope has _' do
let ( :environment_scope ) { '*_*' }
it 'does not treat it as wildcard' do
is_expected . not_to contain_exactly ( ci_variable )
end
context 'when environment name contains underscore' do
let ( :environment ) { 'foo_bar/test' }
let ( :environment_scope ) { 'foo_bar/*' }
it 'matches literally for _' do
is_expected . to contain_exactly ( ci_variable )
end
end
end
# The environment name and scope cannot have % at the moment,
# but we're considering relaxing it and we should also make sure
# it doesn't break in case some data sneaked in somehow as we're
# not checking this integrity in database level.
context 'when environment scope has %' do
it 'does not treat it as wildcard' do
ci_variable . update_attribute ( :environment_scope , '*%*' )
is_expected . not_to contain_exactly ( ci_variable )
end
context 'when environment name contains a percent' do
let ( :environment ) { 'foo%bar/test' }
it 'matches literally for %' do
2021-12-11 22:18:48 +05:30
ci_variable . update_attribute ( :environment_scope , 'foo%bar/*' )
2021-04-17 20:07:23 +05:30
is_expected . to contain_exactly ( ci_variable )
end
end
end
context 'when variables with the same name have different environment scopes' do
let! ( :partially_matched_variable ) do
create ( :ci_group_variable ,
key : ci_variable . key ,
value : 'partial' ,
environment_scope : 'review/*' ,
group : group )
end
let! ( :perfectly_matched_variable ) do
create ( :ci_group_variable ,
key : ci_variable . key ,
value : 'prefect' ,
environment_scope : 'review/name' ,
group : group )
end
it 'puts variables matching environment scope more in the end' do
is_expected . to eq (
[ ci_variable ,
partially_matched_variable ,
perfectly_matched_variable ] )
end
end
end
2019-10-12 21:52:04 +05:30
context 'when group has children' do
2017-09-10 17:25:29 +05:30
let ( :group_child ) { create ( :group , parent : group ) }
let ( :group_child_2 ) { create ( :group , parent : group_child ) }
let ( :group_child_3 ) { create ( :group , parent : group_child_2 ) }
let ( :variable_child ) { create ( :ci_group_variable , group : group_child ) }
let ( :variable_child_2 ) { create ( :ci_group_variable , group : group_child_2 ) }
let ( :variable_child_3 ) { create ( :ci_group_variable , group : group_child_3 ) }
2018-03-17 18:26:18 +05:30
before do
allow ( project ) . to receive ( :protected_for? ) . with ( 'ref' ) . and_return ( true )
end
2021-06-08 01:23:25 +05:30
context 'traversal queries' do
shared_examples 'correct ancestor order' do
it 'returns all variables belong to the group and parent groups' do
expected_array1 = [ protected_variable , ci_variable ]
expected_array2 = [ variable_child , variable_child_2 , variable_child_3 ]
got_array = group_child_3 . ci_variables_for ( 'ref' , project ) . to_a
expect ( got_array . shift ( 2 ) ) . to contain_exactly ( * expected_array1 )
expect ( got_array ) . to eq ( expected_array2 )
end
end
context 'recursive' do
before do
stub_feature_flags ( use_traversal_ids : false )
end
2017-09-10 17:25:29 +05:30
2021-06-08 01:23:25 +05:30
include_examples 'correct ancestor order'
end
context 'linear' do
before do
stub_feature_flags ( use_traversal_ids : true )
group_child_3 . reload # make sure traversal_ids are reloaded
end
include_examples 'correct ancestor order'
end
2017-09-10 17:25:29 +05:30
end
end
end
2018-03-17 18:26:18 +05:30
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
create ( :group_group_link , shared_group : nested_group ,
shared_with_group : another_shared_with_group )
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 (
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 } " )
] )
)
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
describe '.groups_including_descendants_by' do
2021-11-11 11:23:49 +05:30
let_it_be ( :parent_group1 ) { create ( :group ) }
let_it_be ( :parent_group2 ) { create ( :group ) }
let_it_be ( :extra_group ) { create ( :group ) }
let_it_be ( :child_group1 ) { create ( :group , parent : parent_group1 ) }
let_it_be ( :child_group2 ) { create ( :group , parent : parent_group1 ) }
let_it_be ( :child_group3 ) { create ( :group , parent : parent_group2 ) }
2019-12-21 20:55:43 +05:30
2021-11-11 11:23:49 +05:30
subject { described_class . groups_including_descendants_by ( [ parent_group2 . id , parent_group1 . id ] ) }
2019-12-21 20:55:43 +05:30
2021-11-11 11:23:49 +05:30
shared_examples 'returns the expected groups for a group and its descendants' do
specify { is_expected . to contain_exactly ( parent_group1 , parent_group2 , child_group1 , child_group2 , child_group3 ) }
end
2019-12-21 20:55:43 +05:30
2021-11-11 11:23:49 +05:30
it_behaves_like 'returns the expected groups for a group and its descendants'
2019-12-21 20:55:43 +05:30
end
2020-07-28 23:09:34 +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
subject rescue nil
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
2021-01-03 14:25:43 +05:30
context 'disabled_with_override' 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
2021-04-29 21:17:54 +05:30
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 ) }
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
subject rescue nil
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
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
let_it_be ( :group ) { create ( :group , :private ) }
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
let_it_be ( :subgroup ) { create ( :group , :private , parent : group ) }
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
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
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
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
2014-09-02 18:07:02 +05:30
end