gitlab-org--gitlab-foss/spec/presenters/merge_request_presenter_spec.rb
Sean McGivern ad2bfeb857 Fix conflict resolution from corrupted upstream
I don't know why this happens exactly, but given an upstream and fork repository
from a customer, both of which required GC, resolving conflicts would corrupt
the fork so badly that it couldn't be cloned.

This isn't a perfect fix for that case, because the MR may still need to be
merged manually, but it does ensure that the repository is at least usable.

My best guess is that when we generate the index for the conflict
resolution (which we previously did in the target project), we obtain a
reference to an OID that doesn't exist in the source, even though we already
fetch the refs from the target into the source.

Explicitly setting the source project as the place to get the merge index from
seems to prevent repository corruption in this way.
2017-05-12 20:47:51 +01:00

356 lines
10 KiB
Ruby

require 'spec_helper'
describe MergeRequestPresenter do
let(:resource) { create :merge_request, source_project: project }
let(:project) { create :empty_project }
let(:user) { create(:user) }
describe '#ci_status' do
subject { described_class.new(resource).ci_status }
context 'when no head pipeline' do
it 'return status using CiService' do
ci_service = double(MockCiService)
ci_status = double
allow(resource.source_project)
.to receive(:ci_service)
.and_return(ci_service)
allow(resource).to receive(:head_pipeline).and_return(nil)
expect(ci_service).to receive(:commit_status)
.with(resource.diff_head_sha, resource.source_branch)
.and_return(ci_status)
is_expected.to eq(ci_status)
end
end
context 'when head pipeline present' do
let(:pipeline) { build_stubbed(:ci_pipeline) }
before do
allow(resource).to receive(:head_pipeline).and_return(pipeline)
end
context 'success with warnings' do
before do
allow(pipeline).to receive(:success?) { true }
allow(pipeline).to receive(:has_warnings?) { true }
end
it 'returns "success_with_warnings"' do
is_expected.to eq('success_with_warnings')
end
end
context 'pipeline HAS status AND its not success with warnings' do
before do
allow(pipeline).to receive(:success?) { false }
allow(pipeline).to receive(:has_warnings?) { false }
end
it 'returns pipeline status' do
is_expected.to eq('pending')
end
end
context 'pipeline has NO status AND its not success with warnings' do
before do
allow(pipeline).to receive(:status) { nil }
allow(pipeline).to receive(:success?) { false }
allow(pipeline).to receive(:has_warnings?) { false }
end
it 'returns "preparing"' do
is_expected.to eq('preparing')
end
end
end
end
describe '#conflict_resolution_path' do
let(:project) { create :empty_project }
let(:user) { create :user }
let(:presenter) { described_class.new(resource, current_user: user) }
let(:path) { presenter.conflict_resolution_path }
context 'when MR cannot be resolved in UI' do
it 'does not return conflict resolution path' do
allow(presenter).to receive_message_chain(:conflicts, :can_be_resolved_in_ui?) { false }
expect(path).to be_nil
end
end
context 'when conflicts cannot be resolved by user' do
it 'does not return conflict resolution path' do
allow(presenter).to receive_message_chain(:conflicts, :can_be_resolved_in_ui?) { true }
allow(presenter).to receive_message_chain(:conflicts, :can_be_resolved_by?).with(user) { false }
expect(path).to be_nil
end
end
context 'when able to access conflict resolution UI' do
it 'does return conflict resolution path' do
allow(presenter).to receive_message_chain(:conflicts, :can_be_resolved_in_ui?) { true }
allow(presenter).to receive_message_chain(:conflicts, :can_be_resolved_by?).with(user) { true }
expect(path)
.to eq("/#{project.full_path}/merge_requests/#{resource.iid}/conflicts")
end
end
end
context 'issues links' do
let(:project) { create(:project, :private, creator: user, namespace: user.namespace) }
let(:issue_a) { create(:issue, project: project) }
let(:issue_b) { create(:issue, project: project) }
let(:resource) do
create(:merge_request,
source_project: project, target_project: project,
description: "Fixes #{issue_a.to_reference} Related #{issue_b.to_reference}")
end
before do
project.team << [user, :developer]
allow(resource.project).to receive(:default_branch)
.and_return(resource.target_branch)
end
describe '#closing_issues_links' do
subject { described_class.new(resource, current_user: user).closing_issues_links }
it 'presents closing issues links' do
is_expected.to match("#{project.full_path}/issues/#{issue_a.iid}")
end
it 'does not present related issues links' do
is_expected.not_to match("#{project.full_path}/issues/#{issue_b.iid}")
end
end
describe '#mentioned_issues_links' do
subject do
described_class.new(resource, current_user: user)
.mentioned_issues_links
end
it 'presents related issues links' do
is_expected.to match("#{project.full_path}/issues/#{issue_b.iid}")
end
it 'does not present closing issues links' do
is_expected.not_to match("#{project.full_path}/issues/#{issue_a.iid}")
end
end
describe '#assign_to_closing_issues_link' do
subject do
described_class.new(resource, current_user: user)
.assign_to_closing_issues_link
end
before do
assign_issues_service = double(MergeRequests::AssignIssuesService, assignable_issues: assignable_issues)
allow(MergeRequests::AssignIssuesService).to receive(:new)
.and_return(assign_issues_service)
end
context 'single closing issue' do
let(:issue) { create(:issue) }
let(:assignable_issues) { [issue] }
it 'returns correct link with correct text' do
is_expected
.to match("#{project.full_path}/merge_requests/#{resource.iid}/assign_related_issues")
is_expected
.to match("Assign yourself to this issue")
end
end
context 'multiple closing issues' do
let(:issues) { create_list(:issue, 2) }
let(:assignable_issues) { issues }
it 'returns correct link with correct text' do
is_expected
.to match("#{project.full_path}/merge_requests/#{resource.iid}/assign_related_issues")
is_expected
.to match("Assign yourself to these issues")
end
end
context 'no closing issue' do
let(:assignable_issues) { [] }
it 'returns correct link with correct text' do
is_expected.to be_nil
end
end
end
end
describe '#cancel_merge_when_pipeline_succeeds_path' do
subject do
described_class.new(resource, current_user: user)
.cancel_merge_when_pipeline_succeeds_path
end
context 'when can cancel mwps' do
it 'returns path' do
allow(resource).to receive(:can_cancel_merge_when_pipeline_succeeds?)
.with(user)
.and_return(true)
is_expected.to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}/cancel_merge_when_pipeline_succeeds")
end
end
context 'when cannot cancel mwps' do
it 'returns nil' do
allow(resource).to receive(:can_cancel_merge_when_pipeline_succeeds?)
.with(user)
.and_return(false)
is_expected.to be_nil
end
end
end
describe '#merge_path' do
subject do
described_class.new(resource, current_user: user).merge_path
end
context 'when can be merged by user' do
it 'returns path' do
allow(resource).to receive(:can_be_merged_by?)
.with(user)
.and_return(true)
is_expected
.to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}/merge")
end
end
context 'when cannot be merged by user' do
it 'returns nil' do
allow(resource).to receive(:can_be_merged_by?)
.with(user)
.and_return(false)
is_expected.to be_nil
end
end
end
describe '#create_issue_to_resolve_discussions_path' do
subject do
described_class.new(resource, current_user: user)
.create_issue_to_resolve_discussions_path
end
context 'when can create issue and issues enabled' do
it 'returns path' do
allow(project).to receive(:issues_enabled?) { true }
project.team << [user, :master]
is_expected
.to eq("/#{resource.project.full_path}/issues/new?merge_request_to_resolve_discussions_of=#{resource.iid}")
end
end
context 'when cannot create issue' do
it 'returns nil' do
allow(project).to receive(:issues_enabled?) { true }
is_expected.to be_nil
end
end
context 'when issues disabled' do
it 'returns nil' do
allow(project).to receive(:issues_enabled?) { false }
project.team << [user, :master]
is_expected.to be_nil
end
end
end
describe '#remove_wip_path' do
subject do
described_class.new(resource, current_user: user).remove_wip_path
end
context 'when merge request enabled and has permission' do
it 'has remove_wip_path' do
allow(project).to receive(:merge_requests_enabled?) { true }
project.team << [user, :master]
is_expected
.to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}/remove_wip")
end
end
context 'when has no permission' do
it 'returns nil' do
is_expected.to be_nil
end
end
end
describe '#target_branch_commits_path' do
subject do
described_class.new(resource, current_user: user)
.target_branch_commits_path
end
context 'when target branch exists' do
it 'returns path' do
allow(resource).to receive(:target_branch_exists?) { true }
is_expected
.to eq("/#{resource.target_project.full_path}/commits/#{resource.target_branch}")
end
end
context 'when target branch does not exists' do
it 'returns nil' do
allow(resource).to receive(:target_branch_exists?) { false }
is_expected.to be_nil
end
end
end
describe '#source_branch_path' do
subject do
described_class.new(resource, current_user: user).source_branch_path
end
context 'when source branch exists' do
it 'returns path' do
allow(resource).to receive(:source_branch_exists?) { true }
is_expected
.to eq("/#{resource.source_project.full_path}/branches/#{resource.source_branch}")
end
end
context 'when source branch does not exists' do
it 'returns nil' do
allow(resource).to receive(:source_branch_exists?) { false }
is_expected.to be_nil
end
end
end
end