diff options
Diffstat (limited to 'spec/services/issue_links/list_service_spec.rb')
-rw-r--r-- | spec/services/issue_links/list_service_spec.rb | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/spec/services/issue_links/list_service_spec.rb b/spec/services/issue_links/list_service_spec.rb new file mode 100644 index 00000000000..7a3ba845c7c --- /dev/null +++ b/spec/services/issue_links/list_service_spec.rb @@ -0,0 +1,194 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe IssueLinks::ListService do + let(:user) { create :user } + let(:project) { create(:project_empty_repo, :private) } + let(:issue) { create :issue, project: project } + let(:user_role) { :developer } + + before do + project.add_role(user, user_role) + end + + describe '#execute' do + subject { described_class.new(issue, user).execute } + + context 'user can see all issues' do + let(:issue_b) { create :issue, project: project } + let(:issue_c) { create :issue, project: project } + let(:issue_d) { create :issue, project: project } + + let!(:issue_link_c) do + create(:issue_link, source: issue_d, + target: issue) + end + + let!(:issue_link_b) do + create(:issue_link, source: issue, + target: issue_c) + end + + let!(:issue_link_a) do + create(:issue_link, source: issue, + target: issue_b) + end + + it 'ensures no N+1 queries are made' do + control_count = ActiveRecord::QueryRecorder.new { subject }.count + + project = create :project, :public + milestone = create :milestone, project: project + issue_x = create :issue, project: project, milestone: milestone + issue_y = create :issue, project: project, assignees: [user] + issue_z = create :issue, project: project + create :issue_link, source: issue_x, target: issue_y + create :issue_link, source: issue_x, target: issue_z + create :issue_link, source: issue_y, target: issue_z + + expect { subject }.not_to exceed_query_limit(control_count) + end + + it 'returns related issues JSON' do + expect(subject.size).to eq(3) + + expect(subject).to include(include(id: issue_b.id, + title: issue_b.title, + state: issue_b.state, + reference: issue_b.to_reference(project), + path: "/#{project.full_path}/-/issues/#{issue_b.iid}", + relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_a.id}")) + + expect(subject).to include(include(id: issue_c.id, + title: issue_c.title, + state: issue_c.state, + reference: issue_c.to_reference(project), + path: "/#{project.full_path}/-/issues/#{issue_c.iid}", + relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_b.id}")) + + expect(subject).to include(include(id: issue_d.id, + title: issue_d.title, + state: issue_d.state, + reference: issue_d.to_reference(project), + path: "/#{project.full_path}/-/issues/#{issue_d.iid}", + relation_path: "/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link_c.id}")) + end + end + + context 'referencing a public project issue' do + let(:public_project) { create :project, :public } + let(:issue_b) { create :issue, project: public_project } + + let!(:issue_link) do + create(:issue_link, source: issue, target: issue_b) + end + + it 'presents issue' do + expect(subject.size).to eq(1) + end + end + + context 'referencing issue with removed relationships' do + context 'when referenced a deleted issue' do + let(:issue_b) { create :issue, project: project } + let!(:issue_link) do + create(:issue_link, source: issue, target: issue_b) + end + + it 'ignores issue' do + issue_b.destroy! + + is_expected.to eq([]) + end + end + + context 'when referenced an issue with deleted project' do + let(:issue_b) { create :issue, project: project } + let!(:issue_link) do + create(:issue_link, source: issue, target: issue_b) + end + + it 'ignores issue' do + project.destroy! + + is_expected.to eq([]) + end + end + + context 'when referenced an issue with deleted namespace' do + let(:issue_b) { create :issue, project: project } + let!(:issue_link) do + create(:issue_link, source: issue, target: issue_b) + end + + it 'ignores issue' do + project.namespace.destroy! + + is_expected.to eq([]) + end + end + end + + context 'user cannot see relations' do + context 'when user cannot see the referenced issue' do + let!(:issue_link) do + create(:issue_link, source: issue) + end + + it 'returns an empty list' do + is_expected.to eq([]) + end + end + + context 'when user cannot see the issue that referenced' do + let!(:issue_link) do + create(:issue_link, target: issue) + end + + it 'returns an empty list' do + is_expected.to eq([]) + end + end + end + + context 'remove relations' do + let!(:issue_link) do + create(:issue_link, source: issue, target: referenced_issue) + end + + context 'user can admin related issues just on target project' do + let(:user_role) { :guest } + let(:target_project) { create :project } + let(:referenced_issue) { create :issue, project: target_project } + + it 'returns no destroy relation path' do + target_project.add_developer(user) + + expect(subject.first[:relation_path]).to be_nil + end + end + + context 'user can admin related issues just on source project' do + let(:user_role) { :developer } + let(:target_project) { create :project } + let(:referenced_issue) { create :issue, project: target_project } + + it 'returns no destroy relation path' do + target_project.add_guest(user) + + expect(subject.first[:relation_path]).to be_nil + end + end + + context 'when user can admin related issues on both projects' do + let(:referenced_issue) { create :issue, project: project } + + it 'returns related issue destroy relation path' do + expect(subject.first[:relation_path]) + .to eq("/#{project.full_path}/-/issues/#{issue.iid}/links/#{issue_link.id}") + end + end + end + end +end |