diff options
author | Bob Van Landuyt <bob@vanlanduyt.co> | 2017-12-11 15:21:06 +0100 |
---|---|---|
committer | Bob Van Landuyt <bob@vanlanduyt.co> | 2018-02-22 17:11:36 +0100 |
commit | 148816cd67a314f17e79c107270cc708501bdd39 (patch) | |
tree | eba07d109322392bb5862b715adc066a0ebbdf95 /spec/finders | |
parent | b5306075c21f5546d1447052558da6227629c15e (diff) | |
download | gitlab-ce-148816cd67a314f17e79c107270cc708501bdd39.tar.gz |
Port `read_cross_project` ability from EE
Diffstat (limited to 'spec/finders')
-rw-r--r-- | spec/finders/concerns/finder_methods_spec.rb | 70 | ||||
-rw-r--r-- | spec/finders/concerns/finder_with_cross_project_access_spec.rb | 118 | ||||
-rw-r--r-- | spec/finders/events_finder_spec.rb | 8 | ||||
-rw-r--r-- | spec/finders/milestones_finder_spec.rb | 8 | ||||
-rw-r--r-- | spec/finders/snippets_finder_spec.rb | 24 | ||||
-rw-r--r-- | spec/finders/user_recent_events_finder_spec.rb | 31 |
6 files changed, 256 insertions, 3 deletions
diff --git a/spec/finders/concerns/finder_methods_spec.rb b/spec/finders/concerns/finder_methods_spec.rb new file mode 100644 index 00000000000..a4ad331f613 --- /dev/null +++ b/spec/finders/concerns/finder_methods_spec.rb @@ -0,0 +1,70 @@ +require 'spec_helper' + +describe FinderMethods do + let(:finder_class) do + Class.new do + include FinderMethods + + attr_reader :current_user + + def initialize(user) + @current_user = user + end + + def execute + Project.all + end + end + end + + let(:user) { create(:user) } + let(:finder) { finder_class.new(user) } + let(:authorized_project) { create(:project) } + let(:unauthorized_project) { create(:project) } + + before do + authorized_project.add_developer(user) + end + + describe '#find_by!' do + it 'returns the project if the user has access' do + expect(finder.find_by!(id: authorized_project.id)).to eq(authorized_project) + end + + it 'raises not found when the project is not found' do + expect { finder.find_by!(id: 0) }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises not found the user does not have access' do + expect { finder.find_by!(id: unauthorized_project.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + describe '#find' do + it 'returns the project if the user has access' do + expect(finder.find(authorized_project.id)).to eq(authorized_project) + end + + it 'raises not found when the project is not found' do + expect { finder.find(0) }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'raises not found the user does not have access' do + expect { finder.find(unauthorized_project.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + + describe '#find_by' do + it 'returns the project if the user has access' do + expect(finder.find_by(id: authorized_project.id)).to eq(authorized_project) + end + + it 'returns nil when the project is not found' do + expect(finder.find_by(id: 0)).to be_nil + end + + it 'returns nil when the user does not have access' do + expect(finder.find_by(id: unauthorized_project.id)).to be_nil + end + end +end diff --git a/spec/finders/concerns/finder_with_cross_project_access_spec.rb b/spec/finders/concerns/finder_with_cross_project_access_spec.rb new file mode 100644 index 00000000000..c784fb87972 --- /dev/null +++ b/spec/finders/concerns/finder_with_cross_project_access_spec.rb @@ -0,0 +1,118 @@ +require 'spec_helper' + +describe FinderWithCrossProjectAccess do + let(:finder_class) do + Class.new do + prepend FinderWithCrossProjectAccess + include FinderMethods + + requires_cross_project_access if: -> { requires_access? } + + attr_reader :current_user + + def initialize(user) + @current_user = user + end + + def execute + Issue.all + end + end + end + + let(:user) { create(:user) } + subject(:finder) { finder_class.new(user) } + let!(:result) { create(:issue) } + + before do + result.project.add_master(user) + end + + def expect_access_check_on_result + expect(finder).not_to receive(:requires_access?) + expect(Ability).to receive(:allowed?).with(user, :read_issue, result).and_call_original + end + + context 'when the user cannot read cross project' do + before do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) + .and_return(false) + end + + describe '#execute' do + it 'returns a issue if the check is disabled' do + expect(finder).to receive(:requires_access?).and_return(false) + + expect(finder.execute).to include(result) + end + + it 'returns an empty relation when the check is enabled' do + expect(finder).to receive(:requires_access?).and_return(true) + + expect(finder.execute).to be_empty + end + + it 'only queries once when check is enabled' do + expect(finder).to receive(:requires_access?).and_return(true) + + expect { finder.execute }.not_to exceed_query_limit(1) + end + + it 'only queries once when check is disabled' do + expect(finder).to receive(:requires_access?).and_return(false) + + expect { finder.execute }.not_to exceed_query_limit(1) + end + end + + describe '#find' do + it 'checks the accessibility of the subject directly' do + expect_access_check_on_result + + finder.find(result.id) + end + + it 'returns the issue' do + expect(finder.find(result.id)).to eq(result) + end + end + + describe '#find_by' do + it 'checks the accessibility of the subject directly' do + expect_access_check_on_result + + finder.find_by(id: result.id) + end + end + + describe '#find_by!' do + it 'checks the accessibility of the subject directly' do + expect_access_check_on_result + + finder.find_by!(id: result.id) + end + + it 're-enables the check after the find failed' do + finder.find_by!(id: 9999) rescue ActiveRecord::RecordNotFound + + expect(finder.instance_variable_get(:@should_skip_cross_project_check)) + .to eq(false) + end + end + end + + context 'when the user can read cross project' do + before do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) + .and_return(true) + end + + it 'returns the result' do + expect(finder).not_to receive(:requires_access?) + + expect(finder.execute).to include(result) + end + end +end diff --git a/spec/finders/events_finder_spec.rb b/spec/finders/events_finder_spec.rb index 18d6c0cfd74..62968e83292 100644 --- a/spec/finders/events_finder_spec.rb +++ b/spec/finders/events_finder_spec.rb @@ -26,6 +26,14 @@ describe EventsFinder do expect(events).not_to include(opened_merge_request_event) end + + it 'returns nothing when the current user cannot read cross project' do + expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + + events = described_class.new(source: user, current_user: user).execute + + expect(events).to be_empty + end end context 'when targeting a project' do diff --git a/spec/finders/milestones_finder_spec.rb b/spec/finders/milestones_finder_spec.rb index 0b3cf7ece5f..656d120311a 100644 --- a/spec/finders/milestones_finder_spec.rb +++ b/spec/finders/milestones_finder_spec.rb @@ -70,4 +70,12 @@ describe MilestonesFinder do expect(result.to_a).to contain_exactly(milestone_1) end end + + describe '#find_by' do + it 'finds a single milestone' do + finder = described_class.new(project_ids: [project_1.id], state: 'all') + + expect(finder.find_by(iid: milestone_3.iid)).to eq(milestone_3) + end + end end diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb index 54a07eccaba..1ae0bd988f2 100644 --- a/spec/finders/snippets_finder_spec.rb +++ b/spec/finders/snippets_finder_spec.rb @@ -162,8 +162,26 @@ describe SnippetsFinder do end end - describe "#execute" do - # Snippet visibility scenarios are included in more details in spec/support/snippet_visibility.rb - include_examples 'snippet visibility', described_class + 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) + end + + context 'when the user cannot read cross project' do + before do + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + end + + it 'returns only personal snippets when the user cannot read cross project' do + expect(finder.execute).to contain_exactly(personal_snippet) + end + end end end diff --git a/spec/finders/user_recent_events_finder_spec.rb b/spec/finders/user_recent_events_finder_spec.rb new file mode 100644 index 00000000000..3ca0f7c3c89 --- /dev/null +++ b/spec/finders/user_recent_events_finder_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe UserRecentEventsFinder do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:project_owner) { project.creator } + let!(:event) { create(:event, project: project, author: project_owner) } + + subject(:finder) { described_class.new(user, project_owner) } + + describe '#execute' do + it 'does not include the event when a user does not have access to the project' do + expect(finder.execute).to be_empty + end + + context 'when the user has access to a project' do + before do + project.add_developer(user) + end + + it 'includes the event' do + expect(finder.execute).to include(event) + end + + it 'does not include the event if the user cannot read cross project' do + expect(Ability).to receive(:allowed?).with(user, :read_cross_project) { false } + expect(finder.execute).to be_empty + end + end + end +end |