diff options
author | Robert Speicher <rspeicher@gmail.com> | 2019-03-22 11:25:51 +0000 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2019-03-22 11:25:51 +0000 |
commit | 322c14be63dd8eeab59a98aca6bb9b52642b377c (patch) | |
tree | 2542ac8019fa9c352dca41fa9ebe5008fcb90dcf /spec | |
parent | 685a85c6132fbd1f9e5ace08bd4b2808f3a50a8b (diff) | |
parent | 0750638f805eee7d386df5cfff23413610d4e528 (diff) | |
download | gitlab-ce-322c14be63dd8eeab59a98aca6bb9b52642b377c.tar.gz |
Merge branch 'ce-6618-extract-ee-specific-files-lines-for-create-spec-finders' into 'master'
[CE] Extract EE specific files/lines from spec/finders
Closes gitlab-ee#10142 and gitlab-ee#10141
See merge request gitlab-org/gitlab-ce!26337
Diffstat (limited to 'spec')
11 files changed, 662 insertions, 617 deletions
diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index d6d95906f5e..f8fcc2d0e40 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -1,26 +1,7 @@ require 'spec_helper' describe GroupProjectsFinder do - let(:group) { create(:group) } - let(:subgroup) { create(:group, parent: group) } - let(:current_user) { create(:user) } - let(:options) { {} } - - let(:finder) { described_class.new(group: group, current_user: current_user, options: options) } - - let!(:public_project) { create(:project, :public, group: group, path: '1') } - let!(:private_project) { create(:project, :private, group: group, path: '2') } - let!(:shared_project_1) { create(:project, :public, path: '3') } - let!(:shared_project_2) { create(:project, :private, path: '4') } - let!(:shared_project_3) { create(:project, :internal, path: '5') } - let!(:subgroup_project) { create(:project, :public, path: '6', group: subgroup) } - let!(:subgroup_private_project) { create(:project, :private, path: '7', group: subgroup) } - - before do - shared_project_1.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) - shared_project_2.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) - shared_project_3.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) - end + include_context 'GroupProjectsFinder context' subject { finder.execute } @@ -144,6 +125,24 @@ describe GroupProjectsFinder do end end + describe 'with an admin current user' do + let(:current_user) { create(:admin) } + + context "only shared" do + let(:options) { { only_shared: true } } + it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1]) } + end + + context "only owned" do + let(:options) { { only_owned: true } } + it { is_expected.to eq([private_project, public_project]) } + end + + context "all" do + it { is_expected.to eq([shared_project_3, shared_project_2, shared_project_1, private_project, public_project]) } + end + end + describe "no user" do context "only shared" do let(:options) { { only_shared: true } } diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index f74eb1364a6..00b6cad1a66 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -1,45 +1,10 @@ require 'spec_helper' describe IssuesFinder do - set(:user) { create(:user) } - set(:user2) { create(:user) } - set(:group) { create(:group) } - set(:subgroup) { create(:group, parent: group) } - set(:project1) { create(:project, group: group) } - set(:project2) { create(:project) } - set(:project3) { create(:project, group: subgroup) } - set(:milestone) { create(:milestone, project: project1) } - set(:label) { create(:label, project: project2) } - set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab', created_at: 1.week.ago, updated_at: 1.week.ago) } - set(:issue2) { create(:issue, author: user, assignees: [user], project: project2, description: 'gitlab', created_at: 1.week.from_now, updated_at: 1.week.from_now) } - set(:issue3) { create(:issue, author: user2, assignees: [user2], project: project2, title: 'tanuki', description: 'tanuki', created_at: 2.weeks.from_now, updated_at: 2.weeks.from_now) } - set(:issue4) { create(:issue, project: project3) } - set(:award_emoji1) { create(:award_emoji, name: 'thumbsup', user: user, awardable: issue1) } - set(:award_emoji2) { create(:award_emoji, name: 'thumbsup', user: user2, awardable: issue2) } - set(:award_emoji3) { create(:award_emoji, name: 'thumbsdown', user: user, awardable: issue3) } + include_context 'IssuesFinder context' describe '#execute' do - let!(:closed_issue) { create(:issue, author: user2, assignees: [user2], project: project2, state: 'closed') } - let!(:label_link) { create(:label_link, label: label, target: issue2) } - let(:search_user) { user } - let(:params) { {} } - let(:issues) { described_class.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } - - before(:context) do - project1.add_maintainer(user) - project2.add_developer(user) - project2.add_developer(user2) - project3.add_developer(user) - - issue1 - issue2 - issue3 - issue4 - - award_emoji1 - award_emoji2 - award_emoji3 - end + include_context 'IssuesFinder#execute context' context 'scope: all' do let(:scope) { 'all' } @@ -56,6 +21,21 @@ describe IssuesFinder do end end + context 'filtering by assignee usernames' do + set(:user3) { create(:user) } + let(:params) { { assignee_username: [user2.username, user3.username] } } + + before do + project2.add_developer(user3) + + issue3.assignees = [user2, user3] + end + + it 'returns issues assigned to those users' do + expect(issues).to contain_exactly(issue3) + end + end + context 'filtering by no assignee' do let(:params) { { assignee_id: 'None' } } @@ -643,6 +623,16 @@ describe IssuesFinder do expect(subject).to include(public_issue, confidential_issue) end end + + context 'for an admin' do + let(:admin_user) { create(:user, :admin) } + + subject { described_class.new(admin_user, params).with_confidentiality_access_check } + + it 'returns all issues' do + expect(subject).to include(public_issue, confidential_issue) + end + end end context 'when searching within a specific project' do @@ -710,6 +700,22 @@ describe IssuesFinder do subject end end + + context 'for an admin' do + let(:admin_user) { create(:user, :admin) } + + subject { described_class.new(admin_user, params).with_confidentiality_access_check } + + it 'returns all issues' do + expect(subject).to include(public_issue, confidential_issue) + end + + it 'does not filter by confidentiality' do + expect(Issue).not_to receive(:where).with(a_string_matching('confidential'), anything) + + subject + end + end end end diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index f1178b07eec..56136eb84bc 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -1,72 +1,24 @@ require 'spec_helper' describe MergeRequestsFinder do - include ProjectForksHelper - - # We need to explicitly permit Gitaly N+1s because of the specs that use - # :request_store. Gitaly N+1 detection is only enabled when :request_store is, - # but we don't care about potential N+1s when we're just creating several - # projects in the setup phase. - def create_project_without_n_plus_1(*args) - Gitlab::GitalyClient.allow_n_plus_1_calls do - create(:project, :public, *args) - end - end - context "multiple projects with merge requests" do - let(:user) { create :user } - let(:user2) { create :user } - - let(:group) { create(:group) } - let(:subgroup) { create(:group, parent: group) } - let(:project1) { create_project_without_n_plus_1(group: group) } - let(:project2) do - Gitlab::GitalyClient.allow_n_plus_1_calls do - fork_project(project1, user) - end - end - let(:project3) do - Gitlab::GitalyClient.allow_n_plus_1_calls do - p = fork_project(project1, user) - p.update!(archived: true) - p - end - end - let(:project4) { create_project_without_n_plus_1(:repository, group: subgroup) } - let(:project5) { create_project_without_n_plus_1(group: subgroup) } - let(:project6) { create_project_without_n_plus_1(group: subgroup) } - - let!(:merge_request1) { create(:merge_request, author: user, source_project: project2, target_project: project1, target_branch: 'merged-target') } - let!(:merge_request2) { create(:merge_request, :conflict, author: user, source_project: project2, target_project: project1, state: 'closed') } - let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2, state: 'locked', title: 'thing WIP thing') } - let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3, title: 'WIP thing') } - let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4, title: '[WIP]') } - let!(:merge_request6) { create(:merge_request, :simple, author: user, source_project: project5, target_project: project5, title: 'WIP: thing') } - let!(:merge_request7) { create(:merge_request, :simple, author: user, source_project: project6, target_project: project6, title: 'wip thing') } - let!(:merge_request8) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project1, title: '[wip] thing') } - let!(:merge_request9) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project2, title: 'wip: thing') } - - before do - project1.add_maintainer(user) - project2.add_developer(user) - project3.add_developer(user) - project2.add_developer(user2) - project4.add_developer(user) - project5.add_developer(user) - project6.add_developer(user) - end + include_context 'MergeRequestsFinder multiple projects with merge requests context' describe '#execute' do it 'filters by scope' do params = { scope: 'authored', state: 'opened' } + merge_requests = described_class.new(user, params).execute - expect(merge_requests.size).to eq(7) + + expect(merge_requests).to contain_exactly(merge_request1, merge_request4, merge_request5) end it 'filters by project' do params = { project_id: project1.id, scope: 'authored', state: 'opened' } + merge_requests = described_class.new(user, params).execute - expect(merge_requests.size).to eq(2) + + expect(merge_requests).to contain_exactly(merge_request1) end it 'filters by commit sha' do @@ -79,24 +31,15 @@ describe MergeRequestsFinder do end context 'filtering by group' do - it 'includes all merge requests when user has access' do - params = { group_id: group.id } - - merge_requests = described_class.new(user, params).execute - - expect(merge_requests.size).to eq(3) - end - - it 'excludes merge requests from projects the user does not have access to' do - private_project = create_project_without_n_plus_1(:private, group: group) - private_mr = create(:merge_request, :simple, author: user, source_project: private_project, target_project: private_project) + it 'includes all merge requests when user has access exceluding merge requests from projects the user does not have access to' do + private_project = allow_gitaly_n_plus_1 { create(:project, :private, group: group) } + private_project.add_guest(user) + create(:merge_request, :simple, author: user, source_project: private_project, target_project: private_project) params = { group_id: group.id } - private_project.add_guest(user) merge_requests = described_class.new(user, params).execute - expect(merge_requests.size).to eq(3) - expect(merge_requests).not_to include(private_mr) + expect(merge_requests).to contain_exactly(merge_request1, merge_request2) end it 'filters by group including subgroups', :nested_groups do @@ -104,14 +47,16 @@ describe MergeRequestsFinder do merge_requests = described_class.new(user, params).execute - expect(merge_requests.size).to eq(6) + expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request5) end end it 'filters by non_archived' do params = { non_archived: true } + merge_requests = described_class.new(user, params).execute - expect(merge_requests.size).to eq(8) + + expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request5) end it 'filters by iid' do @@ -146,41 +91,45 @@ describe MergeRequestsFinder do expect(merge_requests).to contain_exactly(merge_request3) end - it 'filters by wip' do - params = { wip: 'yes' } + describe 'WIP state' do + let!(:wip_merge_request1) { create(:merge_request, :simple, author: user, source_project: project5, target_project: project5, title: 'WIP: thing') } + let!(:wip_merge_request2) { create(:merge_request, :simple, author: user, source_project: project6, target_project: project6, title: 'wip thing') } + let!(:wip_merge_request3) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project1, title: '[wip] thing') } + let!(:wip_merge_request4) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project2, title: 'wip: thing') } - merge_requests = described_class.new(user, params).execute + it 'filters by wip' do + params = { wip: 'yes' } - expect(merge_requests).to contain_exactly(merge_request4, merge_request5, merge_request6, merge_request7, merge_request8, merge_request9) - end + merge_requests = described_class.new(user, params).execute - it 'filters by not wip' do - params = { wip: 'no' } + expect(merge_requests).to contain_exactly(merge_request4, merge_request5, wip_merge_request1, wip_merge_request2, wip_merge_request3, wip_merge_request4) + end - merge_requests = described_class.new(user, params).execute + it 'filters by not wip' do + params = { wip: 'no' } - expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3) - end + merge_requests = described_class.new(user, params).execute - it 'returns all items if no valid wip param exists' do - params = { wip: '' } + expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3) + end - merge_requests = described_class.new(user, params).execute + it 'returns all items if no valid wip param exists' do + params = { wip: '' } - expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request4, merge_request5, merge_request6, merge_request7, merge_request8, merge_request9) - end + merge_requests = described_class.new(user, params).execute - it 'adds wip to scalar params' do - scalar_params = described_class.scalar_params + expect(merge_requests).to contain_exactly(merge_request1, merge_request2, merge_request3, merge_request4, merge_request5, wip_merge_request1, wip_merge_request2, wip_merge_request3, wip_merge_request4) + end + + it 'adds wip to scalar params' do + scalar_params = described_class.scalar_params - expect(scalar_params).to include(:wip, :assignee_id) + expect(scalar_params).to include(:wip, :assignee_id) + end end context 'filtering by group milestone' do - let!(:group) { create(:group, :public) } let(:group_milestone) { create(:milestone, group: group) } - let!(:group_member) { create(:group_member, group: group, user: user) } - let(:params) { { milestone_title: group_milestone.title } } before do project2.update(namespace: group) @@ -188,7 +137,9 @@ describe MergeRequestsFinder do merge_request3.update(milestone: group_milestone) end - it 'returns issues assigned to that group milestone' do + it 'returns merge requests assigned to that group milestone' do + params = { milestone_title: group_milestone.title } + merge_requests = described_class.new(user, params).execute expect(merge_requests).to contain_exactly(merge_request2, merge_request3) @@ -285,7 +236,7 @@ describe MergeRequestsFinder do it 'returns the number of rows for the default state' do finder = described_class.new(user) - expect(finder.row_count).to eq(7) + expect(finder.row_count).to eq(3) end it 'returns the number of rows for a given state' do diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb index 134fb5f2c04..93287f3e9b8 100644 --- a/spec/finders/snippets_finder_spec.rb +++ b/spec/finders/snippets_finder_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe SnippetsFinder do include Gitlab::Allowable - using RSpec::Parameterized::TableSyntax describe '#initialize' do it 'raises ArgumentError when a project and author are given' do @@ -14,174 +13,142 @@ describe SnippetsFinder do end end - context 'filter by scope' do - let(:user) { create :user } - let!(:snippet1) { create(:personal_snippet, :private, author: user) } - let!(:snippet2) { create(:personal_snippet, :internal, author: user) } - let!(:snippet3) { create(:personal_snippet, :public, author: user) } - - it "returns all snippets for 'all' scope" do - snippets = described_class.new(user, scope: :all).execute - - expect(snippets).to include(snippet1, snippet2, snippet3) - end - - it "returns all snippets for 'are_private' scope" do - snippets = described_class.new(user, scope: :are_private).execute + describe '#execute' do + set(:user) { create(:user) } + set(:private_personal_snippet) { create(:personal_snippet, :private, author: user) } + set(:internal_personal_snippet) { create(:personal_snippet, :internal, author: user) } + set(:public_personal_snippet) { create(:personal_snippet, :public, author: user) } - expect(snippets).to include(snippet1) - expect(snippets).not_to include(snippet2, snippet3) - end + context 'filter by scope' do + it "returns all snippets for 'all' scope" do + snippets = described_class.new(user, scope: :all).execute - it "returns all snippets for 'are_internal' scope" do - snippets = described_class.new(user, scope: :are_internal).execute + expect(snippets).to contain_exactly(private_personal_snippet, internal_personal_snippet, public_personal_snippet) + end - expect(snippets).to include(snippet2) - expect(snippets).not_to include(snippet1, snippet3) - end + it "returns all snippets for 'are_private' scope" do + snippets = described_class.new(user, scope: :are_private).execute - it "returns all snippets for 'are_private' scope" do - snippets = described_class.new(user, scope: :are_public).execute + expect(snippets).to contain_exactly(private_personal_snippet) + end - expect(snippets).to include(snippet3) - expect(snippets).not_to include(snippet1, snippet2) - end - end + it "returns all snippets for 'are_internal' scope" do + snippets = described_class.new(user, scope: :are_internal).execute - context 'filter by author' do - let(:user) { create :user } - let(:user1) { create :user } - let!(:snippet1) { create(:personal_snippet, :private, author: user) } - let!(:snippet2) { create(:personal_snippet, :internal, author: user) } - let!(:snippet3) { create(:personal_snippet, :public, author: user) } + expect(snippets).to contain_exactly(internal_personal_snippet) + end - it "returns all public and internal snippets" do - snippets = described_class.new(user1, author: user).execute + it "returns all snippets for 'are_private' scope" do + snippets = described_class.new(user, scope: :are_public).execute - expect(snippets).to include(snippet2, snippet3) - expect(snippets).not_to include(snippet1) + expect(snippets).to contain_exactly(public_personal_snippet) + end end - it "returns internal snippets" do - snippets = described_class.new(user, author: user, scope: :are_internal).execute + context 'filter by author' do + it 'returns all public and internal snippets' do + snippets = described_class.new(create(:user), author: user).execute - expect(snippets).to include(snippet2) - expect(snippets).not_to include(snippet1, snippet3) - end + expect(snippets).to contain_exactly(internal_personal_snippet, public_personal_snippet) + end - it "returns private snippets" do - snippets = described_class.new(user, author: user, scope: :are_private).execute + it 'returns internal snippets' do + snippets = described_class.new(user, author: user, scope: :are_internal).execute - expect(snippets).to include(snippet1) - expect(snippets).not_to include(snippet2, snippet3) - end + expect(snippets).to contain_exactly(internal_personal_snippet) + end - it "returns public snippets" do - snippets = described_class.new(user, author: user, scope: :are_public).execute + it 'returns private snippets' do + snippets = described_class.new(user, author: user, scope: :are_private).execute - expect(snippets).to include(snippet3) - expect(snippets).not_to include(snippet1, snippet2) - end + expect(snippets).to contain_exactly(private_personal_snippet) + end - it "returns all snippets" do - snippets = described_class.new(user, author: user).execute + it 'returns public snippets' do + snippets = described_class.new(user, author: user, scope: :are_public).execute - expect(snippets).to include(snippet1, snippet2, snippet3) - end + expect(snippets).to contain_exactly(public_personal_snippet) + end - it "returns only public snippets if unauthenticated user" do - snippets = described_class.new(nil, author: user).execute + it 'returns all snippets' do + snippets = described_class.new(user, author: user).execute - expect(snippets).to include(snippet3) - expect(snippets).not_to include(snippet2, snippet1) - end + expect(snippets).to contain_exactly(private_personal_snippet, internal_personal_snippet, public_personal_snippet) + end - it 'returns all snippets for an admin' do - admin = create(:user, :admin) - snippets = described_class.new(admin, author: user).execute + it 'returns only public snippets if unauthenticated user' do + snippets = described_class.new(nil, author: user).execute - expect(snippets).to include(snippet1, snippet2, snippet3) - end - end + expect(snippets).to contain_exactly(public_personal_snippet) + end - context 'filter by project' do - let(:user) { create :user } - let(:group) { create :group, :public } - let(:project1) { create(:project, :public, group: group) } + it 'returns all snippets for an admin' do + admin = create(:user, :admin) + snippets = described_class.new(admin, author: user).execute - before do - @snippet1 = create(:project_snippet, :private, project: project1) - @snippet2 = create(:project_snippet, :internal, project: project1) - @snippet3 = create(:project_snippet, :public, project: project1) + expect(snippets).to contain_exactly(private_personal_snippet, internal_personal_snippet, public_personal_snippet) + end end - it "returns public snippets for unauthorized user" do - snippets = described_class.new(nil, project: project1).execute + context 'project snippets' do + let(:group) { create(:group, :public) } + let(:project) { create(:project, :public, group: group) } + let!(:private_project_snippet) { create(:project_snippet, :private, project: project) } + let!(:internal_project_snippet) { create(:project_snippet, :internal, project: project) } + let!(:public_project_snippet) { create(:project_snippet, :public, project: project) } - expect(snippets).to include(@snippet3) - expect(snippets).not_to include(@snippet1, @snippet2) - end + it 'returns public personal and project snippets for unauthorized user' do + snippets = described_class.new(nil, project: project).execute - it "returns public and internal snippets for non project members" do - snippets = described_class.new(user, project: project1).execute + expect(snippets).to contain_exactly(public_project_snippet) + end - expect(snippets).to include(@snippet2, @snippet3) - expect(snippets).not_to include(@snippet1) - end + it 'returns public and internal snippets for non project members' do + snippets = described_class.new(user, project: project).execute - it "returns public snippets for non project members" do - snippets = described_class.new(user, project: project1, scope: :are_public).execute + expect(snippets).to contain_exactly(internal_project_snippet, public_project_snippet) + end - expect(snippets).to include(@snippet3) - expect(snippets).not_to include(@snippet1, @snippet2) - end + it 'returns public snippets for non project members' do + snippets = described_class.new(user, project: project, scope: :are_public).execute - it "returns internal snippets for non project members" do - snippets = described_class.new(user, project: project1, scope: :are_internal).execute + expect(snippets).to contain_exactly(public_project_snippet) + end - expect(snippets).to include(@snippet2) - expect(snippets).not_to include(@snippet1, @snippet3) - end + it 'returns internal snippets for non project members' do + snippets = described_class.new(user, project: project, scope: :are_internal).execute - it "does not return private snippets for non project members" do - snippets = described_class.new(user, project: project1, scope: :are_private).execute + expect(snippets).to contain_exactly(internal_project_snippet) + end - expect(snippets).not_to include(@snippet1, @snippet2, @snippet3) - end + it 'does not return private snippets for non project members' do + snippets = described_class.new(user, project: project, scope: :are_private).execute - it "returns all snippets for project members" do - project1.add_developer(user) + expect(snippets).to be_empty + end - snippets = described_class.new(user, project: project1).execute + it 'returns all snippets for project members' do + project.add_developer(user) - expect(snippets).to include(@snippet1, @snippet2, @snippet3) - end + snippets = described_class.new(user, project: project).execute - it "returns private snippets for project members" do - project1.add_developer(user) + expect(snippets).to contain_exactly(private_project_snippet, internal_project_snippet, public_project_snippet) + end - snippets = described_class.new(user, project: project1, scope: :are_private).execute + it 'returns private snippets for project members' do + project.add_developer(user) - expect(snippets).to include(@snippet1) - end + snippets = described_class.new(user, project: project, scope: :are_private).execute - it 'returns all snippets for an admin' do - admin = create(:user, :admin) - snippets = described_class.new(admin, project: project1).execute + expect(snippets).to contain_exactly(private_project_snippet) + end - expect(snippets).to include(@snippet1, @snippet2, @snippet3) - end - end + it 'returns all snippets for an admin' do + admin = create(:user, :admin) + snippets = described_class.new(admin, project: project).execute - describe '#execute' do - let(:project) { create(:project, :public) } - let!(:project_snippet) { create(:project_snippet, :public, project: project) } - let!(:personal_snippet) { create(:personal_snippet, :public) } - let(:user) { create(:user) } - subject(:finder) { described_class.new(user) } - - it 'returns project- and personal snippets' do - expect(finder.execute).to contain_exactly(project_snippet, personal_snippet) + expect(snippets).to contain_exactly(private_project_snippet, internal_project_snippet, public_project_snippet) + end end context 'when the user cannot read cross project' do @@ -191,7 +158,7 @@ describe SnippetsFinder do end it 'returns only personal snippets when the user cannot read cross project' do - expect(finder.execute).to contain_exactly(personal_snippet) + expect(described_class.new(user).execute).to contain_exactly(private_personal_snippet, internal_personal_snippet, public_personal_snippet) end end end diff --git a/spec/finders/users_finder_spec.rb b/spec/finders/users_finder_spec.rb index fecf97dc641..d71d3c99272 100644 --- a/spec/finders/users_finder_spec.rb +++ b/spec/finders/users_finder_spec.rb @@ -2,10 +2,7 @@ require 'spec_helper' describe UsersFinder do describe '#execute' do - let!(:user1) { create(:user, username: 'johndoe') } - let!(:user2) { create(:user, :blocked, username: 'notsorandom') } - let!(:external_user) { create(:user, :external) } - let!(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } + include_context 'UsersFinder#execute filter by project context' context 'with a normal user' do let(:user) { create(:user) } @@ -13,43 +10,43 @@ describe UsersFinder do it 'returns all users' do users = described_class.new(user).execute - expect(users).to contain_exactly(user, user1, user2, omniauth_user) + expect(users).to contain_exactly(user, normal_user, blocked_user, omniauth_user) end it 'filters by username' do users = described_class.new(user, username: 'johndoe').execute - expect(users).to contain_exactly(user1) + expect(users).to contain_exactly(normal_user) end it 'filters by username (case insensitive)' do users = described_class.new(user, username: 'joHNdoE').execute - expect(users).to contain_exactly(user1) + expect(users).to contain_exactly(normal_user) end it 'filters by search' do users = described_class.new(user, search: 'orando').execute - expect(users).to contain_exactly(user2) + expect(users).to contain_exactly(blocked_user) end it 'filters by blocked users' do users = described_class.new(user, blocked: true).execute - expect(users).to contain_exactly(user2) + expect(users).to contain_exactly(blocked_user) end it 'filters by active users' do users = described_class.new(user, active: true).execute - expect(users).to contain_exactly(user, user1, omniauth_user) + expect(users).to contain_exactly(user, normal_user, omniauth_user) end it 'returns no external users' do users = described_class.new(user, external: true).execute - expect(users).to contain_exactly(user, user1, user2, omniauth_user) + expect(users).to contain_exactly(user, normal_user, blocked_user, omniauth_user) end it 'filters by created_at' do @@ -69,7 +66,7 @@ describe UsersFinder do custom_attributes: { foo: 'bar' } ).execute - expect(users).to contain_exactly(user, user1, user2, omniauth_user) + expect(users).to contain_exactly(user, normal_user, blocked_user, omniauth_user) end end @@ -85,20 +82,20 @@ describe UsersFinder do it 'returns all users' do users = described_class.new(admin).execute - expect(users).to contain_exactly(admin, user1, user2, external_user, omniauth_user) + expect(users).to contain_exactly(admin, normal_user, blocked_user, external_user, omniauth_user) end it 'filters by custom attributes' do - create :user_custom_attribute, user: user1, key: 'foo', value: 'foo' - create :user_custom_attribute, user: user1, key: 'bar', value: 'bar' - create :user_custom_attribute, user: user2, key: 'foo', value: 'foo' + create :user_custom_attribute, user: normal_user, key: 'foo', value: 'foo' + create :user_custom_attribute, user: normal_user, key: 'bar', value: 'bar' + create :user_custom_attribute, user: blocked_user, key: 'foo', value: 'foo' users = described_class.new( admin, custom_attributes: { foo: 'foo', bar: 'bar' } ).execute - expect(users).to contain_exactly(user1) + expect(users).to contain_exactly(normal_user) end end end diff --git a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb new file mode 100644 index 00000000000..a0d994c4d8d --- /dev/null +++ b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +RSpec.shared_context 'GroupProjectsFinder context' do + let(:group) { create(:group) } + let(:subgroup) { create(:group, parent: group) } + let(:current_user) { create(:user) } + let(:options) { {} } + + let(:finder) { described_class.new(group: group, current_user: current_user, options: options) } + + let!(:public_project) { create(:project, :public, group: group, path: '1') } + let!(:private_project) { create(:project, :private, group: group, path: '2') } + let!(:shared_project_1) { create(:project, :public, path: '3') } + let!(:shared_project_2) { create(:project, :private, path: '4') } + let!(:shared_project_3) { create(:project, :internal, path: '5') } + let!(:subgroup_project) { create(:project, :public, path: '6', group: subgroup) } + let!(:subgroup_private_project) { create(:project, :private, path: '7', group: subgroup) } + + before do + shared_project_1.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) + shared_project_2.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) + shared_project_3.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group) + end +end diff --git a/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb new file mode 100644 index 00000000000..b8a9554f55f --- /dev/null +++ b/spec/support/shared_contexts/finders/issues_finder_shared_contexts.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +RSpec.shared_context 'IssuesFinder context' do + set(:user) { create(:user) } + set(:user2) { create(:user) } + set(:group) { create(:group) } + set(:subgroup) { create(:group, parent: group) } + set(:project1) { create(:project, group: group) } + set(:project2) { create(:project) } + set(:project3) { create(:project, group: subgroup) } + set(:milestone) { create(:milestone, project: project1) } + set(:label) { create(:label, project: project2) } + set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab', created_at: 1.week.ago, updated_at: 1.week.ago) } + set(:issue2) { create(:issue, author: user, assignees: [user], project: project2, description: 'gitlab', created_at: 1.week.from_now, updated_at: 1.week.from_now) } + set(:issue3) { create(:issue, author: user2, assignees: [user2], project: project2, title: 'tanuki', description: 'tanuki', created_at: 2.weeks.from_now, updated_at: 2.weeks.from_now) } + set(:issue4) { create(:issue, project: project3) } + set(:award_emoji1) { create(:award_emoji, name: 'thumbsup', user: user, awardable: issue1) } + set(:award_emoji2) { create(:award_emoji, name: 'thumbsup', user: user2, awardable: issue2) } + set(:award_emoji3) { create(:award_emoji, name: 'thumbsdown', user: user, awardable: issue3) } +end + +RSpec.shared_context 'IssuesFinder#execute context' do + let!(:closed_issue) { create(:issue, author: user2, assignees: [user2], project: project2, state: 'closed') } + let!(:label_link) { create(:label_link, label: label, target: issue2) } + let(:search_user) { user } + let(:params) { {} } + let(:issues) { described_class.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } + + before(:context) do + project1.add_maintainer(user) + project2.add_developer(user) + project2.add_developer(user2) + project3.add_developer(user) + + issue1 + issue2 + issue3 + issue4 + + award_emoji1 + award_emoji2 + award_emoji3 + end +end diff --git a/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb new file mode 100644 index 00000000000..4df80b4168a --- /dev/null +++ b/spec/support/shared_contexts/finders/merge_requests_finder_shared_contexts.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +RSpec.shared_context 'MergeRequestsFinder multiple projects with merge requests context' do + include ProjectForksHelper + + # We need to explicitly permit Gitaly N+1s because of the specs that use + # :request_store. Gitaly N+1 detection is only enabled when :request_store is, + # but we don't care about potential N+1s when we're just creating several + # projects in the setup phase. + def allow_gitaly_n_plus_1 + Gitlab::GitalyClient.allow_n_plus_1_calls do + yield + end + end + + set(:user) { create(:user) } + set(:user2) { create(:user) } + + set(:group) { create(:group) } + set(:subgroup) { create(:group, parent: group) } + set(:project1) do + allow_gitaly_n_plus_1 { create(:project, :public, group: group) } + end + # We cannot use `set` here otherwise we get: + # Failure/Error: allow(RepositoryForkWorker).to receive(:perform_async).and_return(true) + # The use of doubles or partial doubles from rspec-mocks outside of the per-test lifecycle is not supported. + let(:project2) do + allow_gitaly_n_plus_1 do + fork_project(project1, user) + end + end + let(:project3) do + allow_gitaly_n_plus_1 do + fork_project(project1, user).tap do |project| + project.update!(archived: true) + end + end + end + set(:project4) do + allow_gitaly_n_plus_1 { create(:project, :repository, group: subgroup) } + end + set(:project5) do + allow_gitaly_n_plus_1 { create(:project, group: subgroup) } + end + set(:project6) do + allow_gitaly_n_plus_1 { create(:project, group: subgroup) } + end + + let!(:merge_request1) { create(:merge_request, author: user, source_project: project2, target_project: project1, target_branch: 'merged-target') } + let!(:merge_request2) { create(:merge_request, :conflict, author: user, source_project: project2, target_project: project1, state: 'closed') } + let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2, state: 'locked', title: 'thing WIP thing') } + let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3, title: 'WIP thing') } + let!(:merge_request5) { create(:merge_request, :simple, author: user, source_project: project4, target_project: project4, title: '[WIP]') } + + before do + project1.add_maintainer(user) + project2.add_developer(user) + project3.add_developer(user) + project4.add_developer(user) + project5.add_developer(user) + project6.add_developer(user) + + project2.add_developer(user2) + end +end diff --git a/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb new file mode 100644 index 00000000000..9e1f89ee0ed --- /dev/null +++ b/spec/support/shared_contexts/finders/users_finder_shared_contexts.rb @@ -0,0 +1,8 @@ +require 'spec_helper' + +RSpec.shared_context 'UsersFinder#execute filter by project context' do + set(:normal_user) { create(:user, username: 'johndoe') } + set(:blocked_user) { create(:user, :blocked, username: 'notsorandom') } + set(:external_user) { create(:user, :external) } + set(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') } +end diff --git a/spec/support/shared_examples/snippet_visibility.rb b/spec/support/shared_examples/snippet_visibility.rb deleted file mode 100644 index 3a7c69b7877..00000000000 --- a/spec/support/shared_examples/snippet_visibility.rb +++ /dev/null @@ -1,322 +0,0 @@ -RSpec.shared_examples 'snippet visibility' do - let!(:author) { create(:user) } - let!(:member) { create(:user) } - let!(:external) { create(:user, :external) } - - let!(:snippet_type_visibilities) do - { - public: Snippet::PUBLIC, - internal: Snippet::INTERNAL, - private: Snippet::PRIVATE - } - end - - context "For project snippets" do - let!(:users) do - { - unauthenticated: nil, - external: external, - non_member: create(:user), - member: member, - author: author - } - end - - let!(:project_type_visibilities) do - { - public: Gitlab::VisibilityLevel::PUBLIC, - internal: Gitlab::VisibilityLevel::INTERNAL, - private: Gitlab::VisibilityLevel::PRIVATE - } - end - - let(:project_feature_visibilities) do - { - enabled: ProjectFeature::ENABLED, - private: ProjectFeature::PRIVATE, - disabled: ProjectFeature::DISABLED - } - end - - where(:project_type, :feature_visibility, :user_type, :snippet_type, :outcome) do - [ - # Public projects - [:public, :enabled, :unauthenticated, :public, true], - [:public, :enabled, :unauthenticated, :internal, false], - [:public, :enabled, :unauthenticated, :private, false], - - [:public, :enabled, :external, :public, true], - [:public, :enabled, :external, :internal, false], - [:public, :enabled, :external, :private, false], - - [:public, :enabled, :non_member, :public, true], - [:public, :enabled, :non_member, :internal, true], - [:public, :enabled, :non_member, :private, false], - - [:public, :enabled, :member, :public, true], - [:public, :enabled, :member, :internal, true], - [:public, :enabled, :member, :private, true], - - [:public, :enabled, :author, :public, true], - [:public, :enabled, :author, :internal, true], - [:public, :enabled, :author, :private, true], - - [:public, :private, :unauthenticated, :public, false], - [:public, :private, :unauthenticated, :internal, false], - [:public, :private, :unauthenticated, :private, false], - - [:public, :private, :external, :public, false], - [:public, :private, :external, :internal, false], - [:public, :private, :external, :private, false], - - [:public, :private, :non_member, :public, false], - [:public, :private, :non_member, :internal, false], - [:public, :private, :non_member, :private, false], - - [:public, :private, :member, :public, true], - [:public, :private, :member, :internal, true], - [:public, :private, :member, :private, true], - - [:public, :private, :author, :public, true], - [:public, :private, :author, :internal, true], - [:public, :private, :author, :private, true], - - [:public, :disabled, :unauthenticated, :public, false], - [:public, :disabled, :unauthenticated, :internal, false], - [:public, :disabled, :unauthenticated, :private, false], - - [:public, :disabled, :external, :public, false], - [:public, :disabled, :external, :internal, false], - [:public, :disabled, :external, :private, false], - - [:public, :disabled, :non_member, :public, false], - [:public, :disabled, :non_member, :internal, false], - [:public, :disabled, :non_member, :private, false], - - [:public, :disabled, :member, :public, false], - [:public, :disabled, :member, :internal, false], - [:public, :disabled, :member, :private, false], - - [:public, :disabled, :author, :public, false], - [:public, :disabled, :author, :internal, false], - [:public, :disabled, :author, :private, false], - - # Internal projects - [:internal, :enabled, :unauthenticated, :public, false], - [:internal, :enabled, :unauthenticated, :internal, false], - [:internal, :enabled, :unauthenticated, :private, false], - - [:internal, :enabled, :external, :public, false], - [:internal, :enabled, :external, :internal, false], - [:internal, :enabled, :external, :private, false], - - [:internal, :enabled, :non_member, :public, true], - [:internal, :enabled, :non_member, :internal, true], - [:internal, :enabled, :non_member, :private, false], - - [:internal, :enabled, :member, :public, true], - [:internal, :enabled, :member, :internal, true], - [:internal, :enabled, :member, :private, true], - - [:internal, :enabled, :author, :public, true], - [:internal, :enabled, :author, :internal, true], - [:internal, :enabled, :author, :private, true], - - [:internal, :private, :unauthenticated, :public, false], - [:internal, :private, :unauthenticated, :internal, false], - [:internal, :private, :unauthenticated, :private, false], - - [:internal, :private, :external, :public, false], - [:internal, :private, :external, :internal, false], - [:internal, :private, :external, :private, false], - - [:internal, :private, :non_member, :public, false], - [:internal, :private, :non_member, :internal, false], - [:internal, :private, :non_member, :private, false], - - [:internal, :private, :member, :public, true], - [:internal, :private, :member, :internal, true], - [:internal, :private, :member, :private, true], - - [:internal, :private, :author, :public, true], - [:internal, :private, :author, :internal, true], - [:internal, :private, :author, :private, true], - - [:internal, :disabled, :unauthenticated, :public, false], - [:internal, :disabled, :unauthenticated, :internal, false], - [:internal, :disabled, :unauthenticated, :private, false], - - [:internal, :disabled, :external, :public, false], - [:internal, :disabled, :external, :internal, false], - [:internal, :disabled, :external, :private, false], - - [:internal, :disabled, :non_member, :public, false], - [:internal, :disabled, :non_member, :internal, false], - [:internal, :disabled, :non_member, :private, false], - - [:internal, :disabled, :member, :public, false], - [:internal, :disabled, :member, :internal, false], - [:internal, :disabled, :member, :private, false], - - [:internal, :disabled, :author, :public, false], - [:internal, :disabled, :author, :internal, false], - [:internal, :disabled, :author, :private, false], - - # Private projects - [:private, :enabled, :unauthenticated, :public, false], - [:private, :enabled, :unauthenticated, :internal, false], - [:private, :enabled, :unauthenticated, :private, false], - - [:private, :enabled, :external, :public, true], - [:private, :enabled, :external, :internal, true], - [:private, :enabled, :external, :private, true], - - [:private, :enabled, :non_member, :public, false], - [:private, :enabled, :non_member, :internal, false], - [:private, :enabled, :non_member, :private, false], - - [:private, :enabled, :member, :public, true], - [:private, :enabled, :member, :internal, true], - [:private, :enabled, :member, :private, true], - - [:private, :enabled, :author, :public, true], - [:private, :enabled, :author, :internal, true], - [:private, :enabled, :author, :private, true], - - [:private, :private, :unauthenticated, :public, false], - [:private, :private, :unauthenticated, :internal, false], - [:private, :private, :unauthenticated, :private, false], - - [:private, :private, :external, :public, true], - [:private, :private, :external, :internal, true], - [:private, :private, :external, :private, true], - - [:private, :private, :non_member, :public, false], - [:private, :private, :non_member, :internal, false], - [:private, :private, :non_member, :private, false], - - [:private, :private, :member, :public, true], - [:private, :private, :member, :internal, true], - [:private, :private, :member, :private, true], - - [:private, :private, :author, :public, true], - [:private, :private, :author, :internal, true], - [:private, :private, :author, :private, true], - - [:private, :disabled, :unauthenticated, :public, false], - [:private, :disabled, :unauthenticated, :internal, false], - [:private, :disabled, :unauthenticated, :private, false], - - [:private, :disabled, :external, :public, false], - [:private, :disabled, :external, :internal, false], - [:private, :disabled, :external, :private, false], - - [:private, :disabled, :non_member, :public, false], - [:private, :disabled, :non_member, :internal, false], - [:private, :disabled, :non_member, :private, false], - - [:private, :disabled, :member, :public, false], - [:private, :disabled, :member, :internal, false], - [:private, :disabled, :member, :private, false], - - [:private, :disabled, :author, :public, false], - [:private, :disabled, :author, :internal, false], - [:private, :disabled, :author, :private, false] - ] - end - - with_them do - let!(:project) { create(:project, visibility_level: project_type_visibilities[project_type]) } - let!(:project_feature) { project.project_feature.update_column(:snippets_access_level, project_feature_visibilities[feature_visibility]) } - let!(:user) { users[user_type] } - let!(:snippet) { create(:project_snippet, visibility_level: snippet_type_visibilities[snippet_type], project: project, author: author) } - let!(:members) do - project.add_developer(author) - project.add_developer(member) - project.add_developer(external) if project.private? - end - - context "For #{params[:project_type]} project and #{params[:user_type]} users" do - it 'should agree with the read_project_snippet policy' do - expect(can?(user, :read_project_snippet, snippet)).to eq(outcome) - end - - it 'should return proper outcome' do - results = described_class.new(user, project: project).execute - expect(results.include?(snippet)).to eq(outcome) - end - end - - context "Without a given project and #{params[:user_type]} users" do - it 'should return proper outcome' do - results = described_class.new(user).execute - expect(results.include?(snippet)).to eq(outcome) - end - - it 'returns no snippets when the user cannot read cross project' do - allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } - - snippets = described_class.new(user).execute - - expect(snippets).to be_empty - end - end - end - end - - context 'For personal snippets' do - let!(:users) do - { - unauthenticated: nil, - external: external, - non_member: create(:user), - author: author - } - end - - where(:snippet_visibility, :user_type, :outcome) do - [ - [:public, :unauthenticated, true], - [:public, :external, true], - [:public, :non_member, true], - [:public, :author, true], - - [:internal, :unauthenticated, false], - [:internal, :external, false], - [:internal, :non_member, true], - [:internal, :author, true], - - [:private, :unauthenticated, false], - [:private, :external, false], - [:private, :non_member, false], - [:private, :author, true] - ] - end - - with_them do - let!(:user) { users[user_type] } - let!(:snippet) { create(:personal_snippet, visibility_level: snippet_type_visibilities[snippet_visibility], author: author) } - - context "For personal and #{params[:snippet_visibility]} snippets with #{params[:user_type]} user" do - it 'should agree with read_personal_snippet policy' do - expect(can?(user, :read_personal_snippet, snippet)).to eq(outcome) - end - - it 'should return proper outcome' do - results = described_class.new(user).execute - expect(results.include?(snippet)).to eq(outcome) - end - - it 'should return personal snippets when the user cannot read cross project' do - allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } - - results = described_class.new(user).execute - - expect(results.include?(snippet)).to eq(outcome) - end - end - end - end -end diff --git a/spec/support/shared_examples/snippet_visibility_shared_examples.rb b/spec/support/shared_examples/snippet_visibility_shared_examples.rb new file mode 100644 index 00000000000..4f662db2120 --- /dev/null +++ b/spec/support/shared_examples/snippet_visibility_shared_examples.rb @@ -0,0 +1,306 @@ +RSpec.shared_examples 'snippet visibility' do + using RSpec::Parameterized::TableSyntax + + # Make sure no snippets exist prior to running the test matrix + before(:context) do + DatabaseCleaner.clean_with(:truncation) + end + + set(:author) { create(:user) } + set(:member) { create(:user) } + set(:external) { create(:user, :external) } + + context "For project snippets" do + let!(:users) do + { + unauthenticated: nil, + external: external, + non_member: create(:user), + member: member, + author: author + } + end + + where(:project_type, :feature_visibility, :user_type, :snippet_type, :outcome) do + [ + # Public projects + [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, true], + [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], + [:public, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:public, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, true], + [:public, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, false], + [:public, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, false], + + [:public, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, true], + [:public, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, true], + [:public, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], + + [:public, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], + [:public, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], + [:public, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], + + [:public, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], + [:public, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], + [:public, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], + + [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], + [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], + [:public, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], + + [:public, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, false], + [:public, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, false], + [:public, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, false], + + [:public, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], + [:public, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], + [:public, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], + + [:public, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], + [:public, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], + [:public, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], + + [:public, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], + [:public, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], + [:public, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], + + [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], + [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], + [:public, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:public, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], + [:public, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], + [:public, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], + + [:public, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], + [:public, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], + [:public, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], + + [:public, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], + [:public, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], + [:public, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], + + [:public, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], + [:public, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], + [:public, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false], + + # Internal projects + [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, false], + [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], + [:internal, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, false], + [:internal, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, false], + [:internal, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, true], + [:internal, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, true], + [:internal, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], + [:internal, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], + [:internal, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], + + [:internal, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], + [:internal, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], + [:internal, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], + + [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], + [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], + [:internal, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, false], + [:internal, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, false], + [:internal, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], + [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], + [:internal, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], + [:internal, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], + [:internal, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], + + [:internal, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], + [:internal, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], + [:internal, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], + + [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], + [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], + [:internal, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], + [:internal, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], + [:internal, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], + [:internal, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], + [:internal, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], + [:internal, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], + [:internal, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], + + [:internal, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], + [:internal, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], + [:internal, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false], + + # Private projects + [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::PUBLIC, false], + [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::INTERNAL, false], + [:private, ProjectFeature::ENABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:private, ProjectFeature::ENABLED, :external, Snippet::PUBLIC, true], + [:private, ProjectFeature::ENABLED, :external, Snippet::INTERNAL, true], + [:private, ProjectFeature::ENABLED, :external, Snippet::PRIVATE, true], + + [:private, ProjectFeature::ENABLED, :non_member, Snippet::PUBLIC, false], + [:private, ProjectFeature::ENABLED, :non_member, Snippet::INTERNAL, false], + [:private, ProjectFeature::ENABLED, :non_member, Snippet::PRIVATE, false], + + [:private, ProjectFeature::ENABLED, :member, Snippet::PUBLIC, true], + [:private, ProjectFeature::ENABLED, :member, Snippet::INTERNAL, true], + [:private, ProjectFeature::ENABLED, :member, Snippet::PRIVATE, true], + + [:private, ProjectFeature::ENABLED, :author, Snippet::PUBLIC, true], + [:private, ProjectFeature::ENABLED, :author, Snippet::INTERNAL, true], + [:private, ProjectFeature::ENABLED, :author, Snippet::PRIVATE, true], + + [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PUBLIC, false], + [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::INTERNAL, false], + [:private, ProjectFeature::PRIVATE, :unauthenticated, Snippet::PRIVATE, false], + + [:private, ProjectFeature::PRIVATE, :external, Snippet::PUBLIC, true], + [:private, ProjectFeature::PRIVATE, :external, Snippet::INTERNAL, true], + [:private, ProjectFeature::PRIVATE, :external, Snippet::PRIVATE, true], + + [:private, ProjectFeature::PRIVATE, :non_member, Snippet::PUBLIC, false], + [:private, ProjectFeature::PRIVATE, :non_member, Snippet::INTERNAL, false], + [:private, ProjectFeature::PRIVATE, :non_member, Snippet::PRIVATE, false], + + [:private, ProjectFeature::PRIVATE, :member, Snippet::PUBLIC, true], + [:private, ProjectFeature::PRIVATE, :member, Snippet::INTERNAL, true], + [:private, ProjectFeature::PRIVATE, :member, Snippet::PRIVATE, true], + + [:private, ProjectFeature::PRIVATE, :author, Snippet::PUBLIC, true], + [:private, ProjectFeature::PRIVATE, :author, Snippet::INTERNAL, true], + [:private, ProjectFeature::PRIVATE, :author, Snippet::PRIVATE, true], + + [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::PUBLIC, false], + [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::INTERNAL, false], + [:private, ProjectFeature::DISABLED, :unauthenticated, Snippet::PRIVATE, false], + + [:private, ProjectFeature::DISABLED, :external, Snippet::PUBLIC, false], + [:private, ProjectFeature::DISABLED, :external, Snippet::INTERNAL, false], + [:private, ProjectFeature::DISABLED, :external, Snippet::PRIVATE, false], + + [:private, ProjectFeature::DISABLED, :non_member, Snippet::PUBLIC, false], + [:private, ProjectFeature::DISABLED, :non_member, Snippet::INTERNAL, false], + [:private, ProjectFeature::DISABLED, :non_member, Snippet::PRIVATE, false], + + [:private, ProjectFeature::DISABLED, :member, Snippet::PUBLIC, false], + [:private, ProjectFeature::DISABLED, :member, Snippet::INTERNAL, false], + [:private, ProjectFeature::DISABLED, :member, Snippet::PRIVATE, false], + + [:private, ProjectFeature::DISABLED, :author, Snippet::PUBLIC, false], + [:private, ProjectFeature::DISABLED, :author, Snippet::INTERNAL, false], + [:private, ProjectFeature::DISABLED, :author, Snippet::PRIVATE, false] + ] + end + + with_them do + let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel.level_value(project_type.to_s)) } + let!(:project_feature) { project.project_feature.update_column(:snippets_access_level, feature_visibility) } + let!(:user) { users[user_type] } + let!(:snippet) { create(:project_snippet, visibility_level: snippet_type, project: project, author: author) } + let!(:members) do + project.add_developer(author) + project.add_developer(member) + project.add_developer(external) if project.private? + end + + context "For #{params[:project_type]} project and #{params[:user_type]} users" do + it 'should agree with the read_project_snippet policy' do + expect(can?(user, :read_project_snippet, snippet)).to eq(outcome) + end + + it 'should return proper outcome' do + results = described_class.new(user, project: project).execute + + expect(results.include?(snippet)).to eq(outcome) + end + end + + context "Without a given project and #{params[:user_type]} users" do + it 'should return proper outcome' do + results = described_class.new(user).execute + expect(results.include?(snippet)).to eq(outcome) + end + + it 'returns no snippets when the user cannot read cross project' do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + + snippets = described_class.new(user).execute + + expect(snippets).to be_empty + end + end + end + end + + context 'For personal snippets' do + let!(:users) do + { + unauthenticated: nil, + external: external, + non_member: create(:user), + author: author + } + end + + where(:snippet_visibility, :user_type, :outcome) do + [ + [Snippet::PUBLIC, :unauthenticated, true], + [Snippet::PUBLIC, :external, true], + [Snippet::PUBLIC, :non_member, true], + [Snippet::PUBLIC, :author, true], + + [Snippet::INTERNAL, :unauthenticated, false], + [Snippet::INTERNAL, :external, false], + [Snippet::INTERNAL, :non_member, true], + [Snippet::INTERNAL, :author, true], + + [Snippet::PRIVATE, :unauthenticated, false], + [Snippet::PRIVATE, :external, false], + [Snippet::PRIVATE, :non_member, false], + [Snippet::PRIVATE, :author, true] + ] + end + + with_them do + let!(:user) { users[user_type] } + let!(:snippet) { create(:personal_snippet, visibility_level: snippet_visibility, author: author) } + + context "For personal and #{params[:snippet_visibility]} snippets with #{params[:user_type]} user" do + it 'should agree with read_personal_snippet policy' do + expect(can?(user, :read_personal_snippet, snippet)).to eq(outcome) + end + + it 'should return proper outcome' do + results = described_class.new(user).execute + expect(results.include?(snippet)).to eq(outcome) + end + + it 'should return personal snippets when the user cannot read cross project' do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + + results = described_class.new(user).execute + + expect(results.include?(snippet)).to eq(outcome) + end + end + end + end +end |