Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorLin Jen-Shin <godfat@godfat.org>2016-10-18 12:29:51 +0300
committerLin Jen-Shin <godfat@godfat.org>2016-10-18 12:29:51 +0300
commitb3d401adcd02bcb351fe23c33e5bb4863e77bcd4 (patch)
treece46c9909a58006aa027b8da5671af163e18486f /spec
parent88328c5729182bf6289b5f34ed3eb2a23098df25 (diff)
parent4e6af0c3fa335d138343dce3e0216303a9b1cd79 (diff)
Merge remote-tracking branch 'upstream/master' into retry-cancelled-pipelines
* upstream/master: (58 commits) Update endpoint to username validator change border color to variable Add todo for deprecated user routes and more information about deprecation to changelog Provide better error message to the user Apply better hierarchy to markdown headers and issue/mr titles Swapped button text manipulation outcomes for the toggle query Fixed find file keyboard navigation Update CHANGELOG for 8.12.7 Added download-button class and applied button margin Enable activerecord_sane_schema_dumper for test Updated logo from @luke Fix broken specs on MySQL after https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6896 Fix Test Env (proper error handling when gitlab-shell is not clonned) Fix randomly crashing spinach test for merge request [Great spinach fix] Replace gsub with delete Remove carriage returns from commit description as summary is on a newline and will always include carriage returns Convert due_date_select.js filetype to es6. Stop directly parsing due_date with Date.parse, prefer parsing implicitly. Improve spec for pipeline metrics worker Add Pipeline metrics worker ...
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb173
-rw-r--r--spec/features/atom/users_spec.rb2
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb137
-rw-r--r--spec/features/projects/files/find_file_keyboard_spec.rb42
-rw-r--r--spec/features/users_spec.rb12
-rw-r--r--spec/fixtures/api/schemas/conflicts.json137
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb6
-rw-r--r--spec/lib/banzai/pipeline/description_pipeline_spec.rb12
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb11
-rw-r--r--spec/models/ci/pipeline_spec.rb27
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb12
-rw-r--r--spec/routing/routing_spec.rb12
-rw-r--r--spec/services/merge_requests/resolve_service_spec.rb141
-rw-r--r--spec/support/test_env.rb8
-rw-r--r--spec/workers/pipeline_metrics_worker_spec.rb46
16 files changed, 706 insertions, 74 deletions
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index d509f0f2b96..d6980471ea4 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -570,7 +570,7 @@ describe Projects::MergeRequestsController do
context 'when the conflicts cannot be resolved in the UI' do
before do
allow_any_instance_of(Gitlab::Conflict::Parser).
- to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnexpectedDelimiter)
+ to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
get :conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
@@ -597,6 +597,10 @@ describe Projects::MergeRequestsController do
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}/)
@@ -658,26 +662,97 @@ describe Projects::MergeRequestsController do
end
end
+ describe 'GET conflict_for_path' do
+ let(:json_response) { JSON.parse(response.body) }
+
+ 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.to_param,
+ 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_any_instance_of(Gitlab::Conflict::Parser).
+ to receive(:parse).and_raise(Gitlab::Conflict::Parser::UnmergeableFile)
+
+ conflict_for_path('files/ruby/regex.rb')
+ end
+
+ it 'returns a 404 status code' do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context 'when the file does not exist cannot be resolved in the UI' do
+ before { conflict_for_path('files/ruby/regexp.rb') }
+
+ it 'returns a 404 status code' do
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context 'with an existing file' do
+ let(:path) { 'files/ruby/regex.rb' }
+
+ before { conflict_for_path(path) }
+
+ it 'returns a 200 status code' do
+ expect(response).to have_http_status(:ok)
+ end
+
+ it 'returns the file in JSON format' do
+ content = merge_request_with_conflicts.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),
+ 'blob_ace_mode' => 'ruby',
+ 'content' => content)
+ end
+ end
+ end
+
context 'POST resolve_conflicts' do
let(:json_response) { JSON.parse(response.body) }
let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha }
- def resolve_conflicts(sections)
+ def resolve_conflicts(files)
post :resolve_conflicts,
namespace_id: merge_request_with_conflicts.project.namespace.to_param,
project_id: merge_request_with_conflicts.project.to_param,
id: merge_request_with_conflicts.iid,
format: 'json',
- sections: sections,
+ files: files,
commit_message: 'Commit message'
end
context 'with valid params' do
before do
- resolve_conflicts('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin')
+ 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
@@ -692,7 +767,23 @@ describe Projects::MergeRequestsController do
context 'when sections are missing' do
before do
- resolve_conflicts('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head')
+ 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
@@ -700,7 +791,71 @@ describe Projects::MergeRequestsController do
end
it 'has a message with the name of the first missing section' do
- expect(json_response['message']).to include('6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9')
+ 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_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
+ resolved_files = [
+ {
+ 'new_path' => 'files/ruby/popen.rb',
+ 'old_path' => 'files/ruby/popen.rb',
+ 'content' => merge_request_with_conflicts.conflicts.file_for_path('files/ruby/popen.rb', 'files/ruby/popen.rb').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_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
diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb
index a8833194421..f8c3ccb416b 100644
--- a/spec/features/atom/users_spec.rb
+++ b/spec/features/atom/users_spec.rb
@@ -53,7 +53,7 @@ describe "User Feed", feature: true do
end
it 'has XHTML summaries in issue descriptions' do
- expect(body).to match /we have a bug!<\/p>\n\n<hr ?\/>\n\n<p>I guess/
+ expect(body).to match /we have a bug!<\/p>\n\n<hr ?\/>\n\n<p dir="auto">I guess/
end
it 'has XHTML summaries in notes' do
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 759edf8ec80..d258ff52bbb 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -12,29 +12,139 @@ feature 'Merge request conflict resolution', js: true, feature: true do
end
end
- context 'when a merge request can be resolved in the UI' do
- let(:merge_request) { create_merge_request('conflict-resolvable') }
+ shared_examples "conflicts are resolved in Interactive mode" do
+ it 'conflicts are resolved in Interactive mode' do
+ within find('.files-wrapper .diff-file', text: 'files/ruby/popen.rb') do
+ click_button 'Use ours'
+ end
+
+ within find('.files-wrapper .diff-file', text: 'files/ruby/regex.rb') do
+ all('button', text: 'Use ours').each do |button|
+ button.click
+ end
+ end
+
+ click_button 'Commit conflict resolution'
+ wait_for_ajax
+
+ expect(page).to have_content('All merge conflicts were resolved')
+ merge_request.reload_diff
+
+ click_on 'Changes'
+ wait_for_ajax
+
+ within find('.diff-file', text: 'files/ruby/popen.rb') do
+ expect(page).to have_selector('.line_content.new', text: "vars = { 'PWD' => path }")
+ expect(page).to have_selector('.line_content.new', text: "options = { chdir: path }")
+ end
+
+ within find('.diff-file', text: 'files/ruby/regex.rb') do
+ expect(page).to have_selector('.line_content.new', text: "def username_regexp")
+ expect(page).to have_selector('.line_content.new', text: "def project_name_regexp")
+ expect(page).to have_selector('.line_content.new', text: "def path_regexp")
+ expect(page).to have_selector('.line_content.new', text: "def archive_formats_regexp")
+ expect(page).to have_selector('.line_content.new', text: "def git_reference_regexp")
+ expect(page).to have_selector('.line_content.new', text: "def default_regexp")
+ end
+ end
+ end
+ shared_examples "conflicts are resolved in Edit inline mode" do
+ it 'conflicts are resolved in Edit inline mode' do
+ expect(find('#conflicts')).to have_content('popen.rb')
+
+ within find('.files-wrapper .diff-file', text: 'files/ruby/popen.rb') do
+ click_button 'Edit inline'
+ wait_for_ajax
+ execute_script('ace.edit($(".files-wrapper .diff-file pre")[0]).setValue("One morning");')
+ end
+
+ within find('.files-wrapper .diff-file', text: 'files/ruby/regex.rb') do
+ click_button 'Edit inline'
+ wait_for_ajax
+ execute_script('ace.edit($(".files-wrapper .diff-file pre")[1]).setValue("Gregor Samsa woke from troubled dreams");')
+ end
+
+ click_button 'Commit conflict resolution'
+ wait_for_ajax
+ expect(page).to have_content('All merge conflicts were resolved')
+ merge_request.reload_diff
+
+ click_on 'Changes'
+ wait_for_ajax
+
+ expect(page).to have_content('One morning')
+ expect(page).to have_content('Gregor Samsa woke from troubled dreams')
+ end
+ end
+
+ context 'can be resolved in the UI' do
before do
project.team << [user, :developer]
login_as(user)
-
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
end
- it 'shows a link to the conflict resolution page' do
- expect(page).to have_link('conflicts', href: /\/conflicts\Z/)
+ context 'the conflicts are resolvable' do
+ let(:merge_request) { create_merge_request('conflict-resolvable') }
+
+ before { visit namespace_project_merge_request_path(project.namespace, project, merge_request) }
+
+ it 'shows a link to the conflict resolution page' do
+ expect(page).to have_link('conflicts', href: /\/conflicts\Z/)
+ end
+
+ context 'in Inline view mode' do
+ before { click_link('conflicts', href: /\/conflicts\Z/) }
+
+ include_examples "conflicts are resolved in Interactive mode"
+ include_examples "conflicts are resolved in Edit inline mode"
+ end
+
+ context 'in Parallel view mode' do
+ before do
+ click_link('conflicts', href: /\/conflicts\Z/)
+ click_button 'Side-by-side'
+ end
+
+ include_examples "conflicts are resolved in Interactive mode"
+ include_examples "conflicts are resolved in Edit inline mode"
+ end
end
- context 'visiting the conflicts resolution page' do
- before { click_link('conflicts', href: /\/conflicts\Z/) }
+ context 'the conflict contain markers' do
+ let(:merge_request) { create_merge_request('conflict-contains-conflict-markers') }
- it 'shows the conflicts' do
- begin
- expect(find('#conflicts')).to have_content('popen.rb')
- rescue Capybara::Poltergeist::JavascriptError
- retry
+ before do
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ click_link('conflicts', href: /\/conflicts\Z/)
+ end
+
+ it 'conflicts can not be resolved in Interactive mode' do
+ within find('.files-wrapper .diff-file', text: 'files/markdown/ruby-style-guide.md') do
+ expect(page).not_to have_content 'Interactive mode'
+ expect(page).not_to have_content 'Edit inline'
+ end
+ end
+
+ it 'conflicts are resolved in Edit inline mode' do
+ within find('.files-wrapper .diff-file', text: 'files/markdown/ruby-style-guide.md') do
+ wait_for_ajax
+ execute_script('ace.edit($(".files-wrapper .diff-file pre")[0]).setValue("Gregor Samsa woke from troubled dreams");')
end
+
+ click_button 'Commit conflict resolution'
+ wait_for_ajax
+
+ expect(page).to have_content('All merge conflicts were resolved')
+
+ merge_request.reload_diff
+
+ click_on 'Changes'
+ wait_for_ajax
+ find('.click-to-expand').click
+ wait_for_ajax
+
+ expect(page).to have_content('Gregor Samsa woke from troubled dreams')
end
end
end
@@ -42,7 +152,6 @@ feature 'Merge request conflict resolution', js: true, feature: true do
UNRESOLVABLE_CONFLICTS = {
'conflict-too-large' => 'when the conflicts contain a large file',
'conflict-binary-file' => 'when the conflicts contain a binary file',
- 'conflict-contains-conflict-markers' => 'when the conflicts contain a file with ambiguous conflict markers',
'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another',
'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file',
}
diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb
new file mode 100644
index 00000000000..fc88fd74af8
--- /dev/null
+++ b/spec/features/projects/files/find_file_keyboard_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+feature 'Find file keyboard shortcuts', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ before do
+ project.team << [user, :master]
+ login_as user
+
+ visit namespace_project_find_file_path(project.namespace, project, project.repository.root_ref)
+
+ wait_for_ajax
+ end
+
+ it 'opens file when pressing enter key' do
+ fill_in 'file_find', with: 'CHANGELOG'
+
+ find('#file_find').native.send_keys(:enter)
+
+ expect(page).to have_selector('.blob-content-holder')
+
+ page.within('.file-title') do
+ expect(page).to have_content('CHANGELOG')
+ end
+ end
+
+ it 'navigates files with arrow keys' do
+ fill_in 'file_find', with: 'application.'
+
+ find('#file_find').native.send_keys(:down)
+ find('#file_find').native.send_keys(:enter)
+
+ expect(page).to have_selector('.blob-content-holder')
+
+ page.within('.file-title') do
+ expect(page).to have_content('application.js')
+ end
+ end
+end
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index ec4c4d62f53..111ca7f7a70 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -51,6 +51,18 @@ feature 'Users', feature: true, js: true do
expect(current_path).to eq user_path(user)
expect(page).to have_text(user.name)
end
+
+ scenario '/u/user1/groups redirects to user groups page' do
+ visit '/u/user1/groups'
+
+ expect(current_path).to eq user_groups_path(user)
+ end
+
+ scenario '/u/user1/projects redirects to user projects page' do
+ visit '/u/user1/projects'
+
+ expect(current_path).to eq user_projects_path(user)
+ end
end
feature 'username validation' do
diff --git a/spec/fixtures/api/schemas/conflicts.json b/spec/fixtures/api/schemas/conflicts.json
new file mode 100644
index 00000000000..a947783d505
--- /dev/null
+++ b/spec/fixtures/api/schemas/conflicts.json
@@ -0,0 +1,137 @@
+{
+ "type": "object",
+ "required": [
+ "commit_message",
+ "commit_sha",
+ "source_branch",
+ "target_branch",
+ "files"
+ ],
+ "properties": {
+ "commit_message": {"type": "string"},
+ "commit_sha": {"type": "string", "pattern": "^[0-9a-f]{40}$"},
+ "source_branch": {"type": "string"},
+ "target_branch": {"type": "string"},
+ "files": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ { "$ref": "#/definitions/conflict-text-with-sections" },
+ { "$ref": "#/definitions/conflict-text-for-editor" }
+ ]
+ }
+ }
+ },
+ "definitions": {
+ "conflict-base": {
+ "type": "object",
+ "required": [
+ "old_path",
+ "new_path",
+ "blob_icon",
+ "blob_path"
+ ],
+ "properties": {
+ "old_path": {"type": "string"},
+ "new_path": {"type": "string"},
+ "blob_icon": {"type": "string"},
+ "blob_path": {"type": "string"}
+ }
+ },
+ "conflict-text-for-editor": {
+ "allOf": [
+ {"$ref": "#/definitions/conflict-base"},
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "content_path"
+ ],
+ "properties": {
+ "type": {"type": {"enum": ["text-editor"]}},
+ "content_path": {"type": "string"}
+ }
+ }
+ ]
+ },
+ "conflict-text-with-sections": {
+ "allOf": [
+ {"$ref": "#/definitions/conflict-base"},
+ {
+ "type": "object",
+ "required": [
+ "type",
+ "content_path",
+ "sections"
+ ],
+ "properties": {
+ "type": {"type": {"enum": ["text"]}},
+ "content_path": {"type": "string"},
+ "sections": {
+ "type": "array",
+ "items": {
+ "oneOf": [
+ { "$ref": "#/definitions/section-context" },
+ { "$ref": "#/definitions/section-conflict" }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ },
+ "section-base": {
+ "type": "object",
+ "required": [
+ "conflict",
+ "lines"
+ ],
+ "properties": {
+ "conflict": {"type": "boolean"},
+ "lines": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "old_line",
+ "new_line",
+ "text",
+ "rich_text"
+ ],
+ "properties": {
+ "type": {"type": "string"},
+ "old_line": {"type": "string"},
+ "new_line": {"type": "string"},
+ "text": {"type": "string"},
+ "rich_text": {"type": "string"}
+ }
+ }
+ }
+ }
+ },
+ "section-context": {
+ "allOf": [
+ {"$ref": "#/definitions/section-base"},
+ {
+ "type": "object",
+ "properties": {
+ "conflict": {"enum": [false]}
+ }
+ }
+ ]
+ },
+ "section-conflict": {
+ "allOf": [
+ {"$ref": "#/definitions/section-base"},
+ {
+ "type": "object",
+ "required": ["id"],
+ "properties": {
+ "conflict": {"enum": [true]},
+ "id": {"type": "string"}
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 90da78a67dd..6bcda87c999 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -24,7 +24,7 @@ describe Banzai::ObjectRenderer do
with(an_instance_of(Array)).
and_call_original
- expect(object).to receive(:redacted_note_html=).with('<p>hello</p>')
+ expect(object).to receive(:redacted_note_html=).with('<p dir="auto">hello</p>')
expect(object).to receive(:user_visible_reference_count=).with(0)
renderer.render([object], :note)
@@ -92,10 +92,10 @@ describe Banzai::ObjectRenderer do
docs = renderer.render_attributes(objects, :note)
expect(docs[0]).to be_an_instance_of(Nokogiri::HTML::DocumentFragment)
- expect(docs[0].to_html).to eq('<p>hello</p>')
+ expect(docs[0].to_html).to eq('<p dir="auto">hello</p>')
expect(docs[1]).to be_an_instance_of(Nokogiri::HTML::DocumentFragment)
- expect(docs[1].to_html).to eq('<p>bye</p>')
+ expect(docs[1].to_html).to eq('<p dir="auto">bye</p>')
end
it 'returns when no objects to render' do
diff --git a/spec/lib/banzai/pipeline/description_pipeline_spec.rb b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
index 76f42071810..8cce1b96698 100644
--- a/spec/lib/banzai/pipeline/description_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/description_pipeline_spec.rb
@@ -4,11 +4,11 @@ describe Banzai::Pipeline::DescriptionPipeline do
def parse(html)
# When we pass HTML to Redcarpet, it gets wrapped in `p` tags...
# ...except when we pass it pre-wrapped text. Rabble rabble.
- unwrap = !html.start_with?('<p>')
+ unwrap = !html.start_with?('<p ')
output = described_class.to_html(html, project: spy)
- output.gsub!(%r{\A<p>(.*)</p>(.*)\z}, '\1\2') if unwrap
+ output.gsub!(%r{\A<p dir="auto">(.*)</p>(.*)\z}, '\1\2') if unwrap
output
end
@@ -27,11 +27,17 @@ describe Banzai::Pipeline::DescriptionPipeline do
end
end
- %w(b i strong em a ins del sup sub p).each do |elem|
+ %w(b i strong em a ins del sup sub).each do |elem|
it "still allows '#{elem}' elements" do
exp = act = "<#{elem}>Description</#{elem}>"
expect(parse(act).strip).to eq exp
end
end
+
+ it "still allows 'p' elements" do
+ exp = act = "<p dir=\"auto\">Description</p>"
+
+ expect(parse(act).strip).to eq exp
+ end
end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 60020487061..648d342ecf8 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -257,5 +257,16 @@ FILE
it 'includes the blob icon for the file' do
expect(conflict_file.as_json[:blob_icon]).to eq('file-text-o')
end
+
+ context 'with the full_content option passed' do
+ it 'includes the full content of the conflict' do
+ expect(conflict_file.as_json(full_content: true)).to have_key(:content)
+ end
+
+ it 'includes the detected language of the conflict file' do
+ expect(conflict_file.as_json(full_content: true)[:blob_ace_mode]).
+ to eq('ruby')
+ end
+ end
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 4e0ce10603d..43397c5ae39 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -201,33 +201,24 @@ describe Ci::Pipeline, models: true do
end
end
- describe "merge request metrics" do
+ describe 'merge request metrics' do
let(:project) { FactoryGirl.create :project }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
- context 'when transitioning to running' do
- it 'records the build start time' do
- time = Time.now
- Timecop.freeze(time) { build.run }
-
- expect(merge_request.reload.metrics.latest_build_started_at).to be_within(1.second).of(time)
- end
-
- it 'clears the build end time' do
- build.run
+ before do
+ expect(PipelineMetricsWorker).to receive(:perform_async).with(pipeline.id)
+ end
- expect(merge_request.reload.metrics.latest_build_finished_at).to be_nil
+ context 'when transitioning to running' do
+ it 'schedules metrics workers' do
+ pipeline.run
end
end
context 'when transitioning to success' do
- it 'records the build end time' do
- build.run
- time = Time.now
- Timecop.freeze(time) { build.success }
-
- expect(merge_request.reload.metrics.latest_build_finished_at).to be_within(1.second).of(time)
+ it 'schedules metrics workers' do
+ pipeline.succeed
end
end
end
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 15cd3a7ed70..2e3702f7520 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -64,7 +64,7 @@ describe CacheMarkdownField do
let(:html) { "<p><code>Foo</code></p>" }
let(:updated_markdown) { "`Bar`" }
- let(:updated_html) { "<p><code>Bar</code></p>" }
+ let(:updated_html) { "<p dir=\"auto\"><code>Bar</code></p>" }
subject { ThingWithMarkdownFields.new(foo: markdown, foo_html: html) }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 5884b4cff8c..91a423b670c 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1155,12 +1155,6 @@ describe MergeRequest, models: true do
expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
end
- it 'returns a falsey value when the conflicts contain a file with ambiguous conflict markers' do
- merge_request = create_merge_request('conflict-contains-conflict-markers')
-
- expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey
- end
-
it 'returns a falsey value when the conflicts contain a file edited in one branch and deleted in another' do
merge_request = create_merge_request('conflict-missing-side')
@@ -1172,6 +1166,12 @@ describe MergeRequest, models: true do
expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_truthy
end
+
+ it 'returns a truthy value when the conflicts have to be resolved in an editor' do
+ merge_request = create_merge_request('conflict-contains-conflict-markers')
+
+ expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_truthy
+ end
end
describe "#forked_source_project_missing?" do
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 488dc1a63b0..c18a2d55e43 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -15,27 +15,27 @@ describe UsersController, "routing" do
end
it "to #groups" do
- expect(get("/u/User/groups")).to route_to('users#groups', username: 'User')
+ expect(get("/users/User/groups")).to route_to('users#groups', username: 'User')
end
it "to #projects" do
- expect(get("/u/User/projects")).to route_to('users#projects', username: 'User')
+ expect(get("/users/User/projects")).to route_to('users#projects', username: 'User')
end
it "to #contributed" do
- expect(get("/u/User/contributed")).to route_to('users#contributed', username: 'User')
+ expect(get("/users/User/contributed")).to route_to('users#contributed', username: 'User')
end
it "to #snippets" do
- expect(get("/u/User/snippets")).to route_to('users#snippets', username: 'User')
+ expect(get("/users/User/snippets")).to route_to('users#snippets', username: 'User')
end
it "to #calendar" do
- expect(get("/u/User/calendar")).to route_to('users#calendar', username: 'User')
+ expect(get("/users/User/calendar")).to route_to('users#calendar', username: 'User')
end
it "to #calendar_activities" do
- expect(get("/u/User/calendar_activities")).to route_to('users#calendar_activities', username: 'User')
+ expect(get("/users/User/calendar_activities")).to route_to('users#calendar_activities', username: 'User')
end
end
diff --git a/spec/services/merge_requests/resolve_service_spec.rb b/spec/services/merge_requests/resolve_service_spec.rb
index d71932458fa..388abb6a0df 100644
--- a/spec/services/merge_requests/resolve_service_spec.rb
+++ b/spec/services/merge_requests/resolve_service_spec.rb
@@ -24,15 +24,26 @@ describe MergeRequests::ResolveService do
end
describe '#execute' do
- context 'with valid params' do
+ context 'with section params' do
let(:params) do
{
- sections: {
- '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
- '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
- },
+ files: [
+ {
+ old_path: 'files/ruby/popen.rb',
+ new_path: 'files/ruby/popen.rb',
+ sections: {
+ '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head'
+ }
+ }, {
+ old_path: 'files/ruby/regex.rb',
+ new_path: 'files/ruby/regex.rb',
+ sections: {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
+ }
+ }
+ ],
commit_message: 'This is a commit message!'
}
end
@@ -49,7 +60,7 @@ describe MergeRequests::ResolveService do
it 'creates a commit with the correct parents' do
expect(merge_request.source_branch_head.parents.map(&:id)).
to eq(['1450cd639e0bc6721eb02800169e464f212cde06',
- '75284c70dd26c87f2a3fb65fd5a1f0b0138d3a6b'])
+ '824be604a34828eb682305f0d963056cfac87b2d'])
end
end
@@ -74,8 +85,96 @@ describe MergeRequests::ResolveService do
end
end
- context 'when a resolution is missing' do
- let(:invalid_params) { { sections: { '2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_14' => 'head' } } }
+ context 'with content and sections params' do
+ let(:popen_content) { "class Popen\nend" }
+
+ let(:params) do
+ {
+ files: [
+ {
+ old_path: 'files/ruby/popen.rb',
+ new_path: 'files/ruby/popen.rb',
+ content: popen_content
+ }, {
+ old_path: 'files/ruby/regex.rb',
+ new_path: 'files/ruby/regex.rb',
+ sections: {
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_21_21' => 'origin',
+ '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_49_49' => 'origin'
+ }
+ }
+ ],
+ commit_message: 'This is a commit message!'
+ }
+ end
+
+ before do
+ MergeRequests::ResolveService.new(project, user, params).execute(merge_request)
+ end
+
+ it 'creates a commit with the message' do
+ expect(merge_request.source_branch_head.message).to eq(params[:commit_message])
+ end
+
+ it 'creates a commit with the correct parents' do
+ expect(merge_request.source_branch_head.parents.map(&:id)).
+ to eq(['1450cd639e0bc6721eb02800169e464f212cde06',
+ '824be604a34828eb682305f0d963056cfac87b2d'])
+ end
+
+ it 'sets the content to the content given' do
+ blob = merge_request.source_project.repository.blob_at(merge_request.source_branch_head.sha,
+ 'files/ruby/popen.rb')
+
+ expect(blob.data).to eq(popen_content)
+ end
+ end
+
+ context 'when a resolution section is missing' do
+ let(:invalid_params) do
+ {
+ files: [
+ {
+ old_path: 'files/ruby/popen.rb',
+ new_path: 'files/ruby/popen.rb',
+ content: ''
+ }, {
+ old_path: 'files/ruby/regex.rb',
+ new_path: 'files/ruby/regex.rb',
+ sections: { '6eb14e00385d2fb284765eb1cd8d420d33d63fc9_9_9' => 'head' }
+ }
+ ],
+ commit_message: 'This is a commit message!'
+ }
+ end
+
+ let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
+
+ it 'raises a MissingResolution error' do
+ expect { service.execute(merge_request) }.
+ to raise_error(Gitlab::Conflict::File::MissingResolution)
+ end
+ end
+
+ context 'when the content of a file is unchanged' do
+ let(:invalid_params) do
+ {
+ files: [
+ {
+ old_path: 'files/ruby/popen.rb',
+ new_path: 'files/ruby/popen.rb',
+ content: ''
+ }, {
+ old_path: 'files/ruby/regex.rb',
+ new_path: 'files/ruby/regex.rb',
+ content: merge_request.conflicts.file_for_path('files/ruby/regex.rb', 'files/ruby/regex.rb').content
+ }
+ ],
+ commit_message: 'This is a commit message!'
+ }
+ end
+
let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
it 'raises a MissingResolution error' do
@@ -83,5 +182,27 @@ describe MergeRequests::ResolveService do
to raise_error(Gitlab::Conflict::File::MissingResolution)
end
end
+
+ context 'when a file is missing' do
+ let(:invalid_params) do
+ {
+ files: [
+ {
+ old_path: 'files/ruby/popen.rb',
+ new_path: 'files/ruby/popen.rb',
+ content: ''
+ }
+ ],
+ commit_message: 'This is a commit message!'
+ }
+ end
+
+ let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
+
+ it 'raises a MissingFiles error' do
+ expect { service.execute(merge_request) }.
+ to raise_error(MergeRequests::ResolveService::MissingFiles)
+ end
+ end
end
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index ad8ae763f6d..c79975d8667 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -27,10 +27,10 @@ module TestEnv
'expand-collapse-lines' => '238e82d',
'video' => '8879059',
'crlf-diff' => '5938907',
- 'conflict-start' => '75284c7',
+ 'conflict-start' => '824be60',
'conflict-resolvable' => '1450cd6',
'conflict-binary-file' => '259a6fb',
- 'conflict-contains-conflict-markers' => '5e0964c',
+ 'conflict-contains-conflict-markers' => '78a3086',
'conflict-missing-side' => 'eb227b3',
'conflict-non-utf8' => 'd0a293c',
'conflict-too-large' => '39fa04f',
@@ -98,7 +98,9 @@ module TestEnv
def setup_gitlab_shell
unless File.directory?(Gitlab.config.gitlab_shell.path)
- `rake gitlab:shell:install`
+ unless system('rake', 'gitlab:shell:install')
+ raise 'Can`t clone gitlab-shell'
+ end
end
end
diff --git a/spec/workers/pipeline_metrics_worker_spec.rb b/spec/workers/pipeline_metrics_worker_spec.rb
new file mode 100644
index 00000000000..232478c9735
--- /dev/null
+++ b/spec/workers/pipeline_metrics_worker_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+describe PipelineMetricsWorker do
+ let(:project) { create(:project) }
+ let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
+
+ let(:pipeline) do
+ create(:ci_empty_pipeline,
+ status: status,
+ project: project,
+ ref: 'master',
+ sha: project.repository.commit('master').id,
+ started_at: 1.hour.ago,
+ finished_at: Time.now)
+ end
+
+ describe '#perform' do
+ subject { described_class.new.perform(pipeline.id) }
+
+ context 'when pipeline is running' do
+ let(:status) { 'running' }
+
+ it 'records the build start time' do
+ subject
+
+ expect(merge_request.reload.metrics.latest_build_started_at).to be_within(1.second).of(pipeline.started_at)
+ end
+
+ it 'clears the build end time' do
+ subject
+
+ expect(merge_request.reload.metrics.latest_build_finished_at).to be_nil
+ end
+ end
+
+ context 'when pipeline succeeded' do
+ let(:status) { 'success' }
+
+ it 'records the build end time' do
+ subject
+
+ expect(merge_request.reload.metrics.latest_build_finished_at).to be_within(1.second).of(pipeline.finished_at)
+ end
+ end
+ end
+end