gitlab-org--gitlab-foss/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
Zeger-Jan van de Weg 399056ed78 Remove dependencies on Linguist
This saves about 128 MB of baseline RAM usage per Unicorn and
Sidekiq process (!).

Linguist wasn't detecting languages anymore from CE/EE since
9ae8b57467. However, Linguist::BlobHelper
was still being depended on by BlobLike and others.

This removes the Linguist gem, given it isn't required anymore.
EscapeUtils were pulled in as dependency, but given Banzai depends on
it, it is now added explicitly.

Previously, Linguist was used to detect the best ACE mode. Instead,
we rely on ACE to guess the best mode based on the file extension.
2018-10-12 17:17:30 -07:00

306 lines
10 KiB
Ruby

require 'spec_helper'
describe Projects::MergeRequests::ConflictsController do
let(:project) { create(:project, :repository) }
let(:user) { project.owner }
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
let(:merge_request_with_conflicts) do
create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start', source_project: project, merge_status: :unchecked) do |mr|
mr.mark_as_unmergeable
end
end
before do
sign_in(user)
end
describe 'GET show' do
context 'when the conflicts cannot be resolved in the UI' do
before do
allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
.and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
get :show,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'returns a 200 status code' do
expect(response).to have_gitlab_http_status(:ok)
end
it 'returns JSON with a message' do
expect(json_response.keys).to contain_exactly('message', 'type')
end
end
context 'with valid conflicts' do
before do
get :show,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json'
end
it 'matches the schema' do
expect(response).to match_response_schema('conflicts')
end
it 'includes meta info about the MR' do
expect(json_response['commit_message']).to include('Merge branch')
expect(json_response['commit_sha']).to match(/\h{40}/)
expect(json_response['source_branch']).to eq(merge_request_with_conflicts.source_branch)
expect(json_response['target_branch']).to eq(merge_request_with_conflicts.target_branch)
end
it 'includes each file that has conflicts' do
filenames = json_response['files'].map { |file| file['new_path'] }
expect(filenames).to contain_exactly('files/ruby/popen.rb', 'files/ruby/regex.rb')
end
it 'splits files into sections with lines' do
json_response['files'].each do |file|
file['sections'].each do |section|
expect(section).to include('conflict', 'lines')
section['lines'].each do |line|
if section['conflict']
expect(line['type']).to be_in(%w(old new))
expect(line.values_at('old_line', 'new_line')).to contain_exactly(nil, a_kind_of(Integer))
else
if line['type'].nil?
expect(line['old_line']).not_to eq(nil)
expect(line['new_line']).not_to eq(nil)
else
expect(line['type']).to eq('match')
expect(line['old_line']).to eq(nil)
expect(line['new_line']).to eq(nil)
end
end
end
end
end
end
it 'has unique section IDs across files' do
section_ids = json_response['files'].flat_map do |file|
file['sections'].map { |section| section['id'] }.compact
end
expect(section_ids.uniq).to eq(section_ids)
end
end
end
describe 'GET conflict_for_path' do
def conflict_for_path(path)
get :conflict_for_path,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
old_path: path,
new_path: path,
format: 'json'
end
context 'when the conflicts cannot be resolved in the UI' do
before do
allow(Gitlab::Git::Conflict::Parser).to receive(:parse)
.and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
conflict_for_path('files/ruby/regex.rb')
end
it 'returns a 404 status code' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when the file does not exist cannot be resolved in the UI' do
before do
conflict_for_path('files/ruby/regexp.rb')
end
it 'returns a 404 status code' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'with an existing file' do
let(:path) { 'files/ruby/regex.rb' }
before do
conflict_for_path(path)
end
it 'returns a 200 status code' do
expect(response).to have_gitlab_http_status(:ok)
end
it 'returns the file in JSON format' do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path(path, path)
.content
expect(json_response).to include('old_path' => path,
'new_path' => path,
'blob_icon' => 'file-text-o',
'blob_path' => a_string_ending_with(path),
'content' => content)
end
end
end
context 'POST resolve_conflicts' do
let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
def resolve_conflicts(files)
post :resolve_conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project,
id: merge_request_with_conflicts.iid,
format: 'json',
files: files,
commit_message: 'Commit message'
end
context 'with valid params' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'creates a new commit on the branch' do
expect(original_head_sha).not_to eq(merge_request_with_conflicts.source_branch_head.sha)
expect(merge_request_with_conflicts.source_branch_head.message).to include('Commit message')
end
it 'returns an OK response' do
expect(response).to have_gitlab_http_status(:ok)
end
end
context 'when sections are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'sections' => {
'2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
}
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'has a message with the name of the first missing section' do
expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when files are missing' do
before do
resolved_files = [
{
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'has a message with the name of the missing file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
context 'when a file has identical content to the conflict' do
before do
content = MergeRequests::Conflicts::ListService.new(merge_request_with_conflicts)
.file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb')
.content
resolved_files = [
{
'new_path' => 'files/ruby/popen.rb',
'old_path' => 'files/ruby/popen.rb',
'content' => content
}, {
'new_path' => 'files/ruby/regex.rb',
'old_path' => 'files/ruby/regex.rb',
'sections' => {
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
'6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
}
}
]
resolve_conflicts(resolved_files)
end
it 'returns a 400 error' do
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'has a message with the path of the problem file' do
expect(json_response['message']).to include('files/ruby/popen.rb')
end
it 'does not create a new commit' do
expect(original_head_sha).to eq(merge_request_with_conflicts.source_branch_head.sha)
end
end
end
end