diff options
Diffstat (limited to 'spec/finders')
-rw-r--r-- | spec/finders/ci/runners_finder_spec.rb | 8 | ||||
-rw-r--r-- | spec/finders/projects/members/effective_access_level_finder_spec.rb | 257 |
2 files changed, 262 insertions, 3 deletions
diff --git a/spec/finders/ci/runners_finder_spec.rb b/spec/finders/ci/runners_finder_spec.rb index d4795d786bc..34639f9b7bd 100644 --- a/spec/finders/ci/runners_finder_spec.rb +++ b/spec/finders/ci/runners_finder_spec.rb @@ -25,10 +25,12 @@ RSpec.describe Ci::RunnersFinder do end context 'filter by status' do - it 'calls the corresponding scope on Ci::Runner' do - expect(Ci::Runner).to receive(:paused).and_call_original + Ci::Runner::AVAILABLE_STATUSES.each do |status| + it "calls the corresponding :#{status} scope on Ci::Runner" do + expect(Ci::Runner).to receive(status.to_sym).and_call_original - described_class.new(current_user: admin, params: { status_status: 'paused' }).execute + described_class.new(current_user: admin, params: { status_status: status }).execute + end end end diff --git a/spec/finders/projects/members/effective_access_level_finder_spec.rb b/spec/finders/projects/members/effective_access_level_finder_spec.rb new file mode 100644 index 00000000000..1112dbd0d6e --- /dev/null +++ b/spec/finders/projects/members/effective_access_level_finder_spec.rb @@ -0,0 +1,257 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Projects::Members::EffectiveAccessLevelFinder, '#execute' do + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + # The result set is being converted to json just for the ease of testing. + subject { described_class.new(project).execute.as_json } + + context 'for a personal project' do + let_it_be(:project) { create(:project) } + + shared_examples_for 'includes access level of the owner of the project as Maintainer' do + it 'includes access level of the owner of the project as Maintainer' do + expect(subject).to( + contain_exactly( + hash_including( + 'user_id' => project.namespace.owner.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + end + + context 'when the project owner is a member of the project' do + it_behaves_like 'includes access level of the owner of the project as Maintainer' + end + + context 'when the project owner is not explicitly a member of the project' do + before do + project.members.find_by(user_id: project.namespace.owner.id).destroy! + end + + it_behaves_like 'includes access level of the owner of the project as Maintainer' + end + end + + context 'direct members of the project' do + it 'includes access levels of the direct members of the project' do + developer = create(:project_member, :developer, source: project) + maintainer = create(:project_member, :maintainer, source: project) + + expect(subject).to( + include( + hash_including( + 'user_id' => developer.user.id, + 'access_level' => Gitlab::Access::DEVELOPER + ), + hash_including( + 'user_id' => maintainer.user.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + + it 'does not include access levels of users who have requested access to the project' do + member_with_access_request = create(:project_member, :access_request, :developer, source: project) + + expect(subject).not_to( + include( + hash_including( + 'user_id' => member_with_access_request.user.id + ) + ) + ) + end + + it 'includes access levels of users who are in non-active state' do + blocked_member = create(:project_member, :blocked, :developer, source: project) + + expect(subject).to( + include( + hash_including( + 'user_id' => blocked_member.user.id, + 'access_level' => Gitlab::Access::DEVELOPER + ) + ) + ) + end + end + + context 'for a project within a group' do + context 'project in a root group' do + it 'includes access levels of users who are direct members of the parent group' do + group_member = create(:group_member, :developer, source: group) + + expect(subject).to( + include( + hash_including( + 'user_id' => group_member.user.id, + 'access_level' => Gitlab::Access::DEVELOPER + ) + ) + ) + end + end + + context 'project in a subgroup' do + let_it_be(:project) { create(:project, group: create(:group, :nested)) } + + it 'includes access levels of users who are members of the ancestors of the parent group' do + group_member = create(:group_member, :maintainer, source: project.group.parent) + + expect(subject).to( + include( + hash_including( + 'user_id' => group_member.user.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + end + + context 'user is both a member of the project and a member of the parent group' do + let_it_be(:user) { create(:user) } + + before do + group.add_developer(user) + project.add_maintainer(user) + end + + it 'includes the maximum access level among project and group membership' do + expect(subject).to( + include( + hash_including( + 'user_id' => user.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + end + + context 'members from group share' do + let_it_be(:shared_with_group) { create(:group) } + let_it_be(:user_from_shared_with_group) { create(:user) } + + before do + shared_with_group.add_guest(user_from_shared_with_group) + create(:group_group_link, :developer, shared_group: project.group, shared_with_group: shared_with_group) + end + + it 'includes the user from the group share with the right access level' do + expect(subject).to( + include( + hash_including( + 'user_id' => user_from_shared_with_group.id, + 'access_level' => Gitlab::Access::GUEST + ) + ) + ) + end + + context 'when the project also has the same user as a member, but with a different access level' do + before do + project.add_maintainer(user_from_shared_with_group) + end + + it 'includes the maximum access level among project and group membership' do + expect(subject).to( + include( + hash_including( + 'user_id' => user_from_shared_with_group.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + end + + context "when the project's ancestor also has the same user as a member, but with a different access level" do + before do + project.group.add_maintainer(user_from_shared_with_group) + end + + it 'includes the maximum access level among project and group membership' do + expect(subject).to( + include( + hash_including( + 'user_id' => user_from_shared_with_group.id, + 'access_level' => Gitlab::Access::MAINTAINER + ) + ) + ) + end + end + end + end + + context 'for a project that is shared with other group(s)' do + let_it_be(:shared_with_group) { create(:group) } + let_it_be(:user_from_shared_with_group) { create(:user) } + + before do + create(:project_group_link, :developer, project: project, group: shared_with_group) + shared_with_group.add_maintainer(user_from_shared_with_group) + end + + it 'includes the least among the specified access levels' do + expect(subject).to( + include( + hash_including( + 'user_id' => user_from_shared_with_group.id, + 'access_level' => Gitlab::Access::DEVELOPER + ) + ) + ) + end + + context 'when the group containing the project has forbidden group shares for any of its projects' do + let_it_be(:project) { create(:project, group: create(:group)) } + + before do + project.namespace.update!(share_with_group_lock: true) + end + + it 'does not include the users from any group shares' do + expect(subject).not_to( + include( + hash_including( + 'user_id' => user_from_shared_with_group.id + ) + ) + ) + end + end + end + + context 'a combination of all possible avenues of membership' do + let_it_be(:user) { create(:user) } + let_it_be(:shared_with_group) { create(:group) } + + before do + create(:project_group_link, :maintainer, project: project, group: shared_with_group) + create(:group_group_link, :reporter, shared_group: project.group, shared_with_group: shared_with_group) + + shared_with_group.add_maintainer(user) + group.add_guest(user) + project.add_developer(user) + end + + it 'includes the highest access level from all avenues of memberships' do + expect(subject).to( + include( + hash_including( + 'user_id' => user.id, + 'access_level' => Gitlab::Access::MAINTAINER # From project_group_link + ) + ) + ) + end + end +end |