summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/notes.rb5
-rw-r--r--spec/features/issues/reset_filters_spec.rb81
-rw-r--r--spec/features/merge_requests/merge_request_versions_spec.rb43
-rw-r--r--spec/features/merge_requests/update_merge_requests_spec.rb132
-rw-r--r--spec/features/projects/builds_spec.rb20
-rw-r--r--spec/features/triggers_spec.rb2
-rw-r--r--spec/features/users/snippets_spec.rb29
-rw-r--r--spec/finders/pipelines_finder_spec.rb51
-rw-r--r--spec/helpers/git_helper_spec.rb9
-rw-r--r--spec/helpers/nav_helper_spec.rb25
-rw-r--r--spec/helpers/projects_helper_spec.rb44
-rw-r--r--spec/helpers/search_helper_spec.rb4
-rw-r--r--spec/javascripts/fixtures/comments.html.haml21
-rw-r--r--spec/javascripts/notes_spec.js57
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb35
-rw-r--r--spec/lib/gitlab/ci/config/node/cache_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/node/factory_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/config/node/global_spec.rb81
-rw-r--r--spec/lib/gitlab/ci/config/node/job_spec.rb88
-rw-r--r--spec/lib/gitlab/ci/config/node/jobs_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/config/node/null_spec.rb41
-rw-r--r--spec/lib/gitlab/ci/config/node/script_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/node/undefined_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/config/node/unspecified_spec.rb32
-rw-r--r--spec/lib/gitlab/conflict/parser_spec.rb4
-rw-r--r--spec/lib/gitlab/gitlab_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/search_results_spec.rb18
-rw-r--r--spec/lib/gitlab/snippet_search_results_spec.rb6
-rw-r--r--spec/models/diff_note_spec.rb37
-rw-r--r--spec/models/discussion_spec.rb96
-rw-r--r--spec/models/repository_spec.rb45
-rw-r--r--spec/requests/api/fork_spec.rb66
-rw-r--r--spec/requests/api/lint_spec.rb49
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb (renamed from spec/services/issues/bulk_update_service_spec.rb)6
-rw-r--r--spec/support/db_cleaner.rb2
-rw-r--r--spec/views/projects/builds/show.html.haml_spec.rb12
-rw-r--r--spec/workers/prune_old_events_worker_spec.rb24
37 files changed, 976 insertions, 241 deletions
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 83e38095feb..6919002dedc 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -28,6 +28,11 @@ FactoryGirl.define do
diff_refs: noteable.diff_refs
)
end
+
+ trait :resolved do
+ resolved_at { Time.now }
+ resolved_by { create(:user) }
+ end
end
factory :diff_note_on_commit, traits: [:on_commit], class: DiffNote do
diff --git a/spec/features/issues/reset_filters_spec.rb b/spec/features/issues/reset_filters_spec.rb
new file mode 100644
index 00000000000..41f218eaa8b
--- /dev/null
+++ b/spec/features/issues/reset_filters_spec.rb
@@ -0,0 +1,81 @@
+require 'rails_helper'
+
+feature 'Issues filter reset button', feature: true, js: true do
+ include WaitForAjax
+ include IssueHelpers
+
+ let!(:project) { create(:project, :public) }
+ let!(:user) { create(:user)}
+ let!(:milestone) { create(:milestone, project: project) }
+ let!(:bug) { create(:label, project: project, name: 'bug')}
+ let!(:issue1) { create(:issue, project: project, milestone: milestone, author: user, assignee: user, title: 'Feature')}
+ let!(:issue2) { create(:labeled_issue, project: project, labels: [bug], title: 'Bugfix1')}
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ context 'when a milestone filter has been applied' do
+ it 'resets the milestone filter' do
+ visit_issues(project, milestone_title: milestone.title)
+ expect(page).to have_css('.issue', count: 1)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ context 'when a label filter has been applied' do
+ it 'resets the label filter' do
+ visit_issues(project, label_name: bug.name)
+ expect(page).to have_css('.issue', count: 1)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ context 'when a text search has been conducted' do
+ it 'resets the text search filter' do
+ visit_issues(project, issue_search: 'Bug')
+ expect(page).to have_css('.issue', count: 1)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ context 'when author filter has been applied' do
+ it 'resets the author filter' do
+ visit_issues(project, author_id: user.id)
+ expect(page).to have_css('.issue', count: 1)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ context 'when assignee filter has been applied' do
+ it 'resets the assignee filter' do
+ visit_issues(project, assignee_id: user.id)
+ expect(page).to have_css('.issue', count: 1)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ context 'when all filters have been applied' do
+ it 'resets all filters' do
+ visit_issues(project, assignee_id: user.id, author_id: user.id, milestone_title: milestone.title, label_name: bug.name, issue_search: 'Bug')
+ expect(page).to have_css('.issue', count: 0)
+
+ reset_filters
+ expect(page).to have_css('.issue', count: 2)
+ end
+ end
+
+ def reset_filters
+ find('.reset-filters').click
+ end
+end
diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb
index 577c910f11b..9e759de3752 100644
--- a/spec/features/merge_requests/merge_request_versions_spec.rb
+++ b/spec/features/merge_requests/merge_request_versions_spec.rb
@@ -11,8 +11,8 @@ feature 'Merge Request versions', js: true, feature: true do
end
it 'show the latest version of the diff' do
- page.within '.mr-version-switch' do
- expect(page).to have_content 'Version: latest'
+ page.within '.mr-version-dropdown' do
+ expect(page).to have_content 'latest version'
end
expect(page).to have_content '8 changed files'
@@ -20,18 +20,49 @@ feature 'Merge Request versions', js: true, feature: true do
describe 'switch between versions' do
before do
- page.within '.mr-version-switch' do
+ page.within '.mr-version-dropdown' do
find('.btn-link').click
- click_link '6f6d7e7e'
+ click_link 'version 1'
end
end
it 'should show older version' do
- page.within '.mr-version-switch' do
- expect(page).to have_content 'Version: 6f6d7e7e'
+ page.within '.mr-version-dropdown' do
+ expect(page).to have_content 'version 1'
end
expect(page).to have_content '5 changed files'
end
+
+ it 'show the message about disabled comments' do
+ expect(page).to have_content 'Comments are disabled'
+ end
+ end
+
+ describe 'compare with older version' do
+ before do
+ page.within '.mr-version-compare-dropdown' do
+ find('.btn-link').click
+ click_link 'version 1'
+ end
+ end
+
+ it 'should has correct value in the compare dropdown' do
+ page.within '.mr-version-compare-dropdown' do
+ expect(page).to have_content 'version 1'
+ end
+ end
+
+ it 'show the message about disabled comments' do
+ expect(page).to have_content 'Comments are disabled'
+ end
+
+ it 'show diff between new and old version' do
+ expect(page).to have_content '4 changed files with 15 additions and 6 deletions'
+ end
+
+ it 'show diff between new and old version' do
+ expect(page).to have_content '4 changed files with 15 additions and 6 deletions'
+ end
end
end
diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb
new file mode 100644
index 00000000000..b56fdfe5611
--- /dev/null
+++ b/spec/features/merge_requests/update_merge_requests_spec.rb
@@ -0,0 +1,132 @@
+require 'rails_helper'
+
+feature 'Multiple merge requests updating from merge_requests#index', feature: true do
+ include WaitForAjax
+
+ let!(:user) { create(:user)}
+ let!(:project) { create(:project) }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
+
+ before do
+ project.team << [user, :master]
+ login_as(user)
+ end
+
+ context 'status', js: true do
+ describe 'close merge request' do
+ before do
+ visit namespace_project_merge_requests_path(project.namespace, project)
+ end
+
+ it 'closes merge request' do
+ change_status('Closed')
+
+ expect(page).to have_selector('.merge-request', count: 0)
+ end
+ end
+
+ describe 'reopen merge request' do
+ before do
+ merge_request.close
+ visit namespace_project_merge_requests_path(project.namespace, project, state: 'closed')
+ end
+
+ it 'reopens merge request' do
+ change_status('Open')
+
+ expect(page).to have_selector('.merge-request', count: 0)
+ end
+ end
+ end
+
+ context 'assignee', js: true do
+ describe 'set assignee' do
+ before do
+ visit namespace_project_merge_requests_path(project.namespace, project)
+ end
+
+ it "updates merge request with assignee" do
+ change_assignee(user.name)
+
+ page.within('.merge-request .controls') do
+ expect(find('.author_link')["title"]).to have_content(user.name)
+ end
+ end
+ end
+
+ describe 'remove assignee' do
+ before do
+ merge_request.assignee = user
+ merge_request.save
+ visit namespace_project_merge_requests_path(project.namespace, project)
+ end
+
+ it "removes assignee from the merge request" do
+ change_assignee('Unassigned')
+
+ expect(find('.merge-request .controls')).not_to have_css('.author_link')
+ end
+ end
+ end
+
+ context 'milestone', js: true do
+ let(:milestone) { create(:milestone, project: project) }
+
+ describe 'set milestone' do
+ before do
+ visit namespace_project_merge_requests_path(project.namespace, project)
+ end
+
+ it "updates merge request with milestone" do
+ change_milestone(milestone.title)
+
+ expect(find('.merge-request')).to have_content milestone.title
+ end
+ end
+
+ describe 'unset milestone' do
+ before do
+ merge_request.milestone = milestone
+ merge_request.save
+ visit namespace_project_merge_requests_path(project.namespace, project)
+ end
+
+ it "removes milestone from the merge request" do
+ change_milestone("No Milestone")
+
+ expect(find('.merge-request')).not_to have_content milestone.title
+ end
+ end
+ end
+
+ def change_status(text)
+ find('#check_all_issues').click
+ find('.js-issue-status').click
+ find('.dropdown-menu-status a', text: text).click
+ click_update_merge_requests_button
+ end
+
+ def change_assignee(text)
+ find('#check_all_issues').click
+ find('.js-update-assignee').click
+ wait_for_ajax
+
+ page.within '.dropdown-menu-user' do
+ click_link text
+ end
+
+ click_update_merge_requests_button
+ end
+
+ def change_milestone(text)
+ find('#check_all_issues').click
+ find('.issues_bulk_update .js-milestone-select').click
+ find('.dropdown-menu-milestone a', text: text).click
+ click_update_merge_requests_button
+ end
+
+ def click_update_merge_requests_button
+ find('.update_selected_issues').click
+ wait_for_ajax
+ end
+end
diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb
index d5d571e49bc..d1685f95503 100644
--- a/spec/features/projects/builds_spec.rb
+++ b/spec/features/projects/builds_spec.rb
@@ -164,6 +164,26 @@ describe "Builds" do
expect(page).to have_link 'Raw'
end
end
+
+ describe 'Variables' do
+ before do
+ @trigger_request = create :ci_trigger_request_with_variables
+ @build = create :ci_build, pipeline: @commit, trigger_request: @trigger_request
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ end
+
+ it 'shows variable key and value after click', js: true do
+ expect(page).to have_css('.reveal-variables')
+ expect(page).not_to have_css('.js-build-variable')
+ expect(page).not_to have_css('.js-build-value')
+
+ click_button 'Reveal Variables'
+
+ expect(page).not_to have_css('.reveal-variables')
+ expect(page).to have_selector('.js-build-variable', text: 'TRIGGER_KEY_1')
+ expect(page).to have_selector('.js-build-value', text: 'TRIGGER_VALUE_1')
+ end
+ end
end
describe "POST /:project/builds/:id/cancel" do
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 3cbc8253ad6..72354834c5a 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -12,7 +12,7 @@ describe 'Triggers' do
context 'create a trigger' do
before do
- click_on 'Add Trigger'
+ click_on 'Add trigger'
expect(@project.triggers.count).to eq(1)
end
diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb
new file mode 100644
index 00000000000..356a8d668b0
--- /dev/null
+++ b/spec/features/users/snippets_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe 'Snippets tab on a user profile', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+
+ context 'when the user has snippets' do
+ before do
+ create_list(:snippet, 25, :public, author: user)
+
+ visit user_path(user)
+ page.within('.user-profile-nav') { click_link 'Snippets' }
+ wait_for_ajax
+ end
+
+ it 'is limited to 20 items per page' do
+ expect(page.all('.snippets-list-holder .snippet-row').count).to eq(20)
+ end
+
+ context 'clicking on the link to the second page' do
+ before { click_link('2') }
+
+ it 'shows the remaining snippets' do
+ expect(page.all('.snippets-list-holder .snippet-row').count).to eq(5)
+ end
+ end
+ end
+end
diff --git a/spec/finders/pipelines_finder_spec.rb b/spec/finders/pipelines_finder_spec.rb
new file mode 100644
index 00000000000..7100266ab55
--- /dev/null
+++ b/spec/finders/pipelines_finder_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe PipelinesFinder do
+ let(:project) { create(:project) }
+
+ let!(:tag_pipeline) { create(:ci_pipeline, project: project, ref: 'v1.0.0') }
+ let!(:branch_pipeline) { create(:ci_pipeline, project: project) }
+
+ subject { described_class.new(project).execute(params) }
+
+ describe "#execute" do
+ context 'when a scope is passed' do
+ context 'when scope is nil' do
+ let(:params) { { scope: nil } }
+
+ it 'selects all pipelines' do
+ expect(subject.count).to be 2
+ expect(subject).to include tag_pipeline
+ expect(subject).to include branch_pipeline
+ end
+ end
+
+ context 'when selecting branches' do
+ let(:params) { { scope: 'branches' } }
+
+ it 'excludes tags' do
+ expect(subject).not_to include tag_pipeline
+ expect(subject).to include branch_pipeline
+ end
+ end
+
+ context 'when selecting tags' do
+ let(:params) { { scope: 'tags' } }
+
+ it 'excludes branches' do
+ expect(subject).to include tag_pipeline
+ expect(subject).not_to include branch_pipeline
+ end
+ end
+ end
+
+ # Scoping to running will speed up the test as it doesn't hit the FS
+ let(:params) { { scope: 'running' } }
+
+ it 'orders in descending order on ID' do
+ create(:ci_pipeline, project: project, ref: 'feature')
+
+ expect(subject.map(&:id)).to eq [3, 2, 1]
+ end
+ end
+end
diff --git a/spec/helpers/git_helper_spec.rb b/spec/helpers/git_helper_spec.rb
new file mode 100644
index 00000000000..9b1ef1e05a2
--- /dev/null
+++ b/spec/helpers/git_helper_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+describe GitHelper do
+ describe '#short_sha' do
+ let(:short_sha) { helper.short_sha('d4e043f6c20749a3ab3f4b8e23f2a8979f4b9100') }
+
+ it { expect(short_sha).to eq('d4e043f6') }
+ end
+end
diff --git a/spec/helpers/nav_helper_spec.rb b/spec/helpers/nav_helper_spec.rb
deleted file mode 100644
index e4d18d8bfc6..00000000000
--- a/spec/helpers/nav_helper_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'spec_helper'
-
-# Specs in this file have access to a helper object that includes
-# the NavHelper. For example:
-#
-# describe NavHelper do
-# describe "string concat" do
-# it "concats two strings with spaces" do
-# expect(helper.concat_strings("this","that")).to eq("this that")
-# end
-# end
-# end
-describe NavHelper do
- describe '#nav_menu_collapsed?' do
- it 'returns true when the nav is collapsed in the cookie' do
- helper.request.cookies[:collapsed_nav] = 'true'
- expect(helper.nav_menu_collapsed?).to eq true
- end
-
- it 'returns false when the nav is not collapsed in the cookie' do
- helper.request.cookies[:collapsed_nav] = 'false'
- expect(helper.nav_menu_collapsed?).to eq false
- end
- end
-end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 284b58d8d5c..70032e7df94 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -174,4 +174,48 @@ describe ProjectsHelper do
end
end
end
+
+ describe "#project_feature_access_select" do
+ let(:project) { create(:empty_project, :public) }
+ let(:user) { create(:user) }
+
+ context "when project is internal or public" do
+ it "shows all options" do
+ helper.instance_variable_set(:@project, project)
+ result = helper.project_feature_access_select(:issues_access_level)
+ expect(result).to include("Disabled")
+ expect(result).to include("Only team members")
+ expect(result).to include("Everyone with access")
+ end
+ end
+
+ context "when project is private" do
+ before { project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
+
+ it "shows only allowed options" do
+ helper.instance_variable_set(:@project, project)
+ result = helper.project_feature_access_select(:issues_access_level)
+ expect(result).to include("Disabled")
+ expect(result).to include("Only team members")
+ expect(result).not_to include("Everyone with access")
+ end
+ end
+
+ context "when project moves from public to private" do
+ before do
+ project.project_feature.update_attributes(issues_access_level: ProjectFeature::ENABLED)
+ project.update_attributes(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it "shows the highest allowed level selected" do
+ helper.instance_variable_set(:@project, project)
+ result = helper.project_feature_access_select(:issues_access_level)
+
+ expect(result).to include("Disabled")
+ expect(result).to include("Only team members")
+ expect(result).not_to include("Everyone with access")
+ expect(result).to have_selector('option[selected]', text: "Only team members")
+ end
+ end
+ end
end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index b0bb991539b..4b2ca3514f8 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -32,6 +32,10 @@ describe SearchHelper do
expect(search_autocomplete_opts("adm").size).to eq(1)
end
+ it "does not allow regular expression in search term" do
+ expect(search_autocomplete_opts("(webhooks|api)").size).to eq(0)
+ end
+
it "includes the user's groups" do
create(:group).add_owner(user)
expect(search_autocomplete_opts("gro").size).to eq(1)
diff --git a/spec/javascripts/fixtures/comments.html.haml b/spec/javascripts/fixtures/comments.html.haml
new file mode 100644
index 00000000000..cc1f8f15c21
--- /dev/null
+++ b/spec/javascripts/fixtures/comments.html.haml
@@ -0,0 +1,21 @@
+.flash-container.timeline-content
+.timeline-icon.hidden-xs.hidden-sm
+ %a.author_link
+ %img
+.timeline-content.timeline-content-form
+ %form.new-note.js-quick-submit.common-note-form.gfm-form.js-main-target-form
+ .md-area
+ .md-header
+ .md-write-holder
+ .zen-backdrop.div-dropzone-wrapper
+ .div-dropzone-wrapper
+ .div-dropzone.dz-clickable
+ %textarea.note-textarea.js-note-text.js-gfm-input.js-autosize.markdown-area
+ .note-form-actions.clearfix
+ %input.btn.btn-nr.btn-create.append-right-10.comment-btn.js-comment-button{ type: 'submit' }
+ %a.btn.btn-nr.btn-reopen.btn-comment.js-note-target-reopen
+ Reopen issue
+ %a.btn.btn-nr.btn-close.btn-comment.js-note-target-close
+ Close issue
+ %a.btn.btn-cancel.js-note-discard
+ Discard draft \ No newline at end of file
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index 14dc6bfdfde..a588f403dd5 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -1,8 +1,7 @@
-
/*= require notes */
-
-
+/*= require autosize */
/*= require gl_form */
+/*= require lib/utils/text_utility */
(function() {
window.gon || (window.gon = {});
@@ -12,29 +11,63 @@
};
describe('Notes', function() {
- return describe('task lists', function() {
+ describe('task lists', function() {
fixture.preload('issue_note.html');
+
beforeEach(function() {
fixture.load('issue_note.html');
$('form').on('submit', function(e) {
- return e.preventDefault();
+ e.preventDefault();
});
- return this.notes = new Notes();
+ this.notes = new Notes();
});
+
it('modifies the Markdown field', function() {
$('input[type=checkbox]').attr('checked', true).trigger('change');
- return expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
+ expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
});
- return it('submits the form on tasklist:changed', function() {
- var submitted;
- submitted = false;
+
+ it('submits the form on tasklist:changed', function() {
+ var submitted = false;
$('form').on('submit', function(e) {
submitted = true;
- return e.preventDefault();
+ e.preventDefault();
});
+
$('.js-task-list-field').trigger('tasklist:changed');
- return expect(submitted).toBe(true);
+ expect(submitted).toBe(true);
+ });
+ });
+
+ describe('comments', function() {
+ var commentsTemplate = 'comments.html';
+ var textarea = '.js-note-text';
+ fixture.preload(commentsTemplate);
+
+ beforeEach(function() {
+ fixture.load(commentsTemplate);
+ this.notes = new Notes();
+
+ this.autoSizeSpy = spyOnEvent($(textarea), 'autosize:update');
+ spyOn(this.notes, 'renderNote').and.stub();
+
+ $(textarea).data('autosave', {
+ reset: function() {}
+ });
+
+ $('form').on('submit', function(e) {
+ e.preventDefault();
+ $('.js-main-target-form').trigger('ajax:success');
+ });
});
+
+ it('autosizes after comment submission', function() {
+ $(textarea).text('This is an example comment note');
+ expect(this.autoSizeSpy).not.toHaveBeenTriggered();
+
+ $('.js-comment-button').click();
+ expect(this.autoSizeSpy).toHaveBeenTriggered();
+ })
});
});
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index be51d942af7..af192664b33 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -1250,5 +1250,40 @@ EOT
end
end
end
+
+ describe "#validation_message" do
+ context "when the YAML could not be parsed" do
+ it "returns an error about invalid configutaion" do
+ content = YAML.dump("invalid: yaml: test")
+
+ expect(GitlabCiYamlProcessor.validation_message(content))
+ .to eq "Invalid configuration format"
+ end
+ end
+
+ context "when the tags parameter is invalid" do
+ it "returns an error about invalid tags" do
+ content = YAML.dump({ rspec: { script: "test", tags: "mysql" } })
+
+ expect(GitlabCiYamlProcessor.validation_message(content))
+ .to eq "jobs:rspec tags should be an array of strings"
+ end
+ end
+
+ context "when YAML content is empty" do
+ it "returns an error about missing content" do
+ expect(GitlabCiYamlProcessor.validation_message(''))
+ .to eq "Please provide content of .gitlab-ci.yml"
+ end
+ end
+
+ context "when the YAML is valid" do
+ it "does not return any errors" do
+ content = File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+
+ expect(GitlabCiYamlProcessor.validation_message(content)).to be_nil
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/node/cache_spec.rb b/spec/lib/gitlab/ci/config/node/cache_spec.rb
index 50f619ce26e..e251210949c 100644
--- a/spec/lib/gitlab/ci/config/node/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/cache_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Ci::Config::Node::Cache do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.process! }
+ before { entry.compose! }
context 'when entry config value is correct' do
let(:config) do
diff --git a/spec/lib/gitlab/ci/config/node/factory_spec.rb b/spec/lib/gitlab/ci/config/node/factory_spec.rb
index d26185ba585..a699089c563 100644
--- a/spec/lib/gitlab/ci/config/node/factory_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/factory_spec.rb
@@ -65,7 +65,8 @@ describe Gitlab::Ci::Config::Node::Factory do
.value(nil)
.create!
- expect(entry).to be_an_instance_of Gitlab::Ci::Config::Node::Undefined
+ expect(entry)
+ .to be_an_instance_of Gitlab::Ci::Config::Node::Unspecified
end
end
diff --git a/spec/lib/gitlab/ci/config/node/global_spec.rb b/spec/lib/gitlab/ci/config/node/global_spec.rb
index 2f87d270b36..12232ff7e2f 100644
--- a/spec/lib/gitlab/ci/config/node/global_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/global_spec.rb
@@ -14,7 +14,7 @@ describe Gitlab::Ci::Config::Node::Global do
end
context 'when hash is valid' do
- context 'when all entries defined' do
+ context 'when some entries defined' do
let(:hash) do
{ before_script: ['ls', 'pwd'],
image: 'ruby:2.2',
@@ -24,11 +24,11 @@ describe Gitlab::Ci::Config::Node::Global do
stages: ['build', 'pages'],
cache: { key: 'k', untracked: true, paths: ['public/'] },
rspec: { script: %w[rspec ls] },
- spinach: { script: 'spinach' } }
+ spinach: { before_script: [], variables: {}, script: 'spinach' } }
end
- describe '#process!' do
- before { global.process! }
+ describe '#compose!' do
+ before { global.compose! }
it 'creates nodes hash' do
expect(global.descendants).to be_an Array
@@ -59,7 +59,7 @@ describe Gitlab::Ci::Config::Node::Global do
end
end
- context 'when not processed' do
+ context 'when not composed' do
describe '#before_script' do
it 'returns nil' do
expect(global.before_script).to be nil
@@ -73,8 +73,14 @@ describe Gitlab::Ci::Config::Node::Global do
end
end
- context 'when processed' do
- before { global.process! }
+ context 'when composed' do
+ before { global.compose! }
+
+ describe '#errors' do
+ it 'has no errors' do
+ expect(global.errors).to be_empty
+ end
+ end
describe '#before_script' do
it 'returns correct script' do
@@ -137,10 +143,24 @@ describe Gitlab::Ci::Config::Node::Global do
expect(global.jobs).to eq(
rspec: { name: :rspec,
script: %w[rspec ls],
- stage: 'test' },
+ before_script: ['ls', 'pwd'],
+ commands: "ls\npwd\nrspec\nls",
+ image: 'ruby:2.2',
+ services: ['postgres:9.1', 'mysql:5.5'],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'] },
+ variables: { VAR: 'value' },
+ after_script: ['make clean'] },
spinach: { name: :spinach,
+ before_script: [],
script: %w[spinach],
- stage: 'test' }
+ commands: 'spinach',
+ image: 'ruby:2.2',
+ services: ['postgres:9.1', 'mysql:5.5'],
+ stage: 'test',
+ cache: { key: 'k', untracked: true, paths: ['public/'] },
+ variables: {},
+ after_script: ['make clean'] },
)
end
end
@@ -148,17 +168,20 @@ describe Gitlab::Ci::Config::Node::Global do
end
context 'when most of entires not defined' do
- let(:hash) { { cache: { key: 'a' }, rspec: { script: %w[ls] } } }
- before { global.process! }
+ before { global.compose! }
+
+ let(:hash) do
+ { cache: { key: 'a' }, rspec: { script: %w[ls] } }
+ end
describe '#nodes' do
it 'instantizes all nodes' do
expect(global.descendants.count).to eq 8
end
- it 'contains undefined nodes' do
+ it 'contains unspecified nodes' do
expect(global.descendants.first)
- .to be_an_instance_of Gitlab::Ci::Config::Node::Undefined
+ .to be_an_instance_of Gitlab::Ci::Config::Node::Unspecified
end
end
@@ -188,8 +211,11 @@ describe Gitlab::Ci::Config::Node::Global do
# details.
#
context 'when entires specified but not defined' do
- let(:hash) { { variables: nil, rspec: { script: 'rspec' } } }
- before { global.process! }
+ before { global.compose! }
+
+ let(:hash) do
+ { variables: nil, rspec: { script: 'rspec' } }
+ end
describe '#variables' do
it 'undefined entry returns a default value' do
@@ -200,7 +226,7 @@ describe Gitlab::Ci::Config::Node::Global do
end
context 'when hash is not valid' do
- before { global.process! }
+ before { global.compose! }
let(:hash) do
{ before_script: 'ls' }
@@ -247,4 +273,27 @@ describe Gitlab::Ci::Config::Node::Global do
expect(global.specified?).to be true
end
end
+
+ describe '#[]' do
+ before { global.compose! }
+
+ let(:hash) do
+ { cache: { key: 'a' }, rspec: { script: 'ls' } }
+ end
+
+ context 'when node exists' do
+ it 'returns correct entry' do
+ expect(global[:cache])
+ .to be_an_instance_of Gitlab::Ci::Config::Node::Cache
+ expect(global[:jobs][:rspec][:script].value).to eq ['ls']
+ end
+ end
+
+ context 'when node does not exist' do
+ it 'always return unspecified node' do
+ expect(global[:some][:unknown][:node])
+ .not_to be_specified
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/node/job_spec.rb b/spec/lib/gitlab/ci/config/node/job_spec.rb
index 1484fb60dd8..91f676dae03 100644
--- a/spec/lib/gitlab/ci/config/node/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/job_spec.rb
@@ -3,9 +3,9 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Node::Job do
let(:entry) { described_class.new(config, name: :rspec) }
- before { entry.process! }
-
describe 'validations' do
+ before { entry.compose! }
+
context 'when entry config value is correct' do
let(:config) { { script: 'rspec' } }
@@ -59,28 +59,82 @@ describe Gitlab::Ci::Config::Node::Job do
end
end
- describe '#value' do
- context 'when entry is correct' do
+ describe '#relevant?' do
+ it 'is a relevant entry' do
+ expect(entry).to be_relevant
+ end
+ end
+
+ describe '#compose!' do
+ let(:unspecified) { double('unspecified', 'specified?' => false) }
+
+ let(:specified) do
+ double('specified', 'specified?' => true, value: 'specified')
+ end
+
+ let(:deps) { double('deps', '[]' => unspecified) }
+
+ context 'when job config overrides global config' do
+ before { entry.compose!(deps) }
+
let(:config) do
- { before_script: %w[ls pwd],
- script: 'rspec',
- after_script: %w[cleanup] }
+ { image: 'some_image', cache: { key: 'test' } }
+ end
+
+ it 'overrides global config' do
+ expect(entry[:image].value).to eq 'some_image'
+ expect(entry[:cache].value).to eq(key: 'test')
+ end
+ end
+
+ context 'when job config does not override global config' do
+ before do
+ allow(deps).to receive('[]').with(:image).and_return(specified)
+ entry.compose!(deps)
end
- it 'returns correct value' do
- expect(entry.value)
- .to eq(name: :rspec,
- before_script: %w[ls pwd],
- script: %w[rspec],
- stage: 'test',
- after_script: %w[cleanup])
+ let(:config) { { script: 'ls', cache: { key: 'test' } } }
+
+ it 'uses config from global entry' do
+ expect(entry[:image].value).to eq 'specified'
+ expect(entry[:cache].value).to eq(key: 'test')
end
end
end
- describe '#relevant?' do
- it 'is a relevant entry' do
- expect(entry).to be_relevant
+ context 'when composed' do
+ before { entry.compose! }
+
+ describe '#value' do
+ before { entry.compose! }
+
+ context 'when entry is correct' do
+ let(:config) do
+ { before_script: %w[ls pwd],
+ script: 'rspec',
+ after_script: %w[cleanup] }
+ end
+
+ it 'returns correct value' do
+ expect(entry.value)
+ .to eq(name: :rspec,
+ before_script: %w[ls pwd],
+ script: %w[rspec],
+ commands: "ls\npwd\nrspec",
+ stage: 'test',
+ after_script: %w[cleanup])
+ end
+ end
+ end
+
+ describe '#commands' do
+ let(:config) do
+ { before_script: %w[ls pwd], script: 'rspec' }
+ end
+
+ it 'returns a string of commands concatenated with new line character' do
+ expect(entry.commands).to eq "ls\npwd\nrspec"
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/node/jobs_spec.rb b/spec/lib/gitlab/ci/config/node/jobs_spec.rb
index ae2c88aac37..929809339ef 100644
--- a/spec/lib/gitlab/ci/config/node/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/jobs_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::Ci::Config::Node::Jobs do
let(:entry) { described_class.new(config) }
describe 'validations' do
- before { entry.process! }
+ before { entry.compose! }
context 'when entry config value is correct' do
let(:config) { { rspec: { script: 'rspec' } } }
@@ -47,8 +47,8 @@ describe Gitlab::Ci::Config::Node::Jobs do
end
end
- context 'when valid job entries processed' do
- before { entry.process! }
+ context 'when valid job entries composed' do
+ before { entry.compose! }
let(:config) do
{ rspec: { script: 'rspec' },
@@ -61,9 +61,11 @@ describe Gitlab::Ci::Config::Node::Jobs do
expect(entry.value).to eq(
rspec: { name: :rspec,
script: %w[rspec],
+ commands: 'rspec',
stage: 'test' },
spinach: { name: :spinach,
script: %w[spinach],
+ commands: 'spinach',
stage: 'test' })
end
end
diff --git a/spec/lib/gitlab/ci/config/node/null_spec.rb b/spec/lib/gitlab/ci/config/node/null_spec.rb
deleted file mode 100644
index 1ab5478dcfa..00000000000
--- a/spec/lib/gitlab/ci/config/node/null_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Ci::Config::Node::Null do
- let(:null) { described_class.new(nil) }
-
- describe '#leaf?' do
- it 'is leaf node' do
- expect(null).to be_leaf
- end
- end
-
- describe '#valid?' do
- it 'is always valid' do
- expect(null).to be_valid
- end
- end
-
- describe '#errors' do
- it 'is does not contain errors' do
- expect(null.errors).to be_empty
- end
- end
-
- describe '#value' do
- it 'returns nil' do
- expect(null.value).to eq nil
- end
- end
-
- describe '#relevant?' do
- it 'is not relevant' do
- expect(null.relevant?).to eq false
- end
- end
-
- describe '#specified?' do
- it 'is not defined' do
- expect(null.specified?).to eq false
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/config/node/script_spec.rb b/spec/lib/gitlab/ci/config/node/script_spec.rb
index ee7395362a9..219a7e981d3 100644
--- a/spec/lib/gitlab/ci/config/node/script_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/script_spec.rb
@@ -3,9 +3,7 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Node::Script do
let(:entry) { described_class.new(config) }
- describe '#process!' do
- before { entry.process! }
-
+ describe 'validations' do
context 'when entry config value is correct' do
let(:config) { ['ls', 'pwd'] }
diff --git a/spec/lib/gitlab/ci/config/node/undefined_spec.rb b/spec/lib/gitlab/ci/config/node/undefined_spec.rb
index 2d43e1c1a9d..6bde8602963 100644
--- a/spec/lib/gitlab/ci/config/node/undefined_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/undefined_spec.rb
@@ -1,32 +1,41 @@
require 'spec_helper'
describe Gitlab::Ci::Config::Node::Undefined do
- let(:undefined) { described_class.new(entry) }
- let(:entry) { spy('Entry') }
+ let(:entry) { described_class.new }
+
+ describe '#leaf?' do
+ it 'is leaf node' do
+ expect(entry).to be_leaf
+ end
+ end
describe '#valid?' do
- it 'delegates method to entry' do
- expect(undefined.valid).to eq entry
+ it 'is always valid' do
+ expect(entry).to be_valid
end
end
describe '#errors' do
- it 'delegates method to entry' do
- expect(undefined.errors).to eq entry
+ it 'is does not contain errors' do
+ expect(entry.errors).to be_empty
end
end
describe '#value' do
- it 'delegates method to entry' do
- expect(undefined.value).to eq entry
+ it 'returns nil' do
+ expect(entry.value).to eq nil
end
end
- describe '#specified?' do
- it 'is always false' do
- allow(entry).to receive(:specified?).and_return(true)
+ describe '#relevant?' do
+ it 'is not relevant' do
+ expect(entry.relevant?).to eq false
+ end
+ end
- expect(undefined.specified?).to be false
+ describe '#specified?' do
+ it 'is not defined' do
+ expect(entry.specified?).to eq false
end
end
end
diff --git a/spec/lib/gitlab/ci/config/node/unspecified_spec.rb b/spec/lib/gitlab/ci/config/node/unspecified_spec.rb
new file mode 100644
index 00000000000..ba3ceef24ce
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/node/unspecified_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Config::Node::Unspecified do
+ let(:unspecified) { described_class.new(entry) }
+ let(:entry) { spy('Entry') }
+
+ describe '#valid?' do
+ it 'delegates method to entry' do
+ expect(unspecified.valid?).to eq entry
+ end
+ end
+
+ describe '#errors' do
+ it 'delegates method to entry' do
+ expect(unspecified.errors).to eq entry
+ end
+ end
+
+ describe '#value' do
+ it 'delegates method to entry' do
+ expect(unspecified.value).to eq entry
+ end
+ end
+
+ describe '#specified?' do
+ it 'is always false' do
+ allow(entry).to receive(:specified?).and_return(true)
+
+ expect(unspecified.specified?).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb
index a1d2ca1e272..16eb3766356 100644
--- a/spec/lib/gitlab/conflict/parser_spec.rb
+++ b/spec/lib/gitlab/conflict/parser_spec.rb
@@ -179,8 +179,8 @@ CONFLICT
to raise_error(Gitlab::Conflict::Parser::UnmergeableFile)
end
- it 'raises UnmergeableFile when the file is over 100 KB' do
- expect { parse_text('a' * 102401) }.
+ it 'raises UnmergeableFile when the file is over 200 KB' do
+ expect { parse_text('a' * 204801) }.
to raise_error(Gitlab::Conflict::Parser::UnmergeableFile)
end
diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb
index d3f1deb3837..9b499b593d3 100644
--- a/spec/lib/gitlab/gitlab_import/importer_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb
@@ -13,6 +13,7 @@ describe Gitlab::GitlabImport::Importer, lib: true do
'title' => 'Issue',
'description' => 'Lorem ipsum',
'state' => 'opened',
+ 'confidential' => true,
'author' => {
'id' => 283999,
'name' => 'John Doe'
@@ -34,6 +35,7 @@ describe Gitlab::GitlabImport::Importer, lib: true do
title: 'Issue',
description: "*Created by: John Doe*\n\nLorem ipsum",
state: 'opened',
+ confidential: true,
author_id: project.creator_id
}
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index 8a656ab0ee9..dfbefad6367 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -12,12 +12,6 @@ describe Gitlab::SearchResults do
let!(:milestone) { create(:milestone, project: project, title: 'foo') }
let(:results) { described_class.new(user, Project.all, 'foo') }
- describe '#total_count' do
- it 'returns the total amount of search hits' do
- expect(results.total_count).to eq(4)
- end
- end
-
describe '#projects_count' do
it 'returns the total amount of projects' do
expect(results.projects_count).to eq(1)
@@ -42,18 +36,6 @@ describe Gitlab::SearchResults do
end
end
- describe '#empty?' do
- it 'returns true when there are no search results' do
- allow(results).to receive(:total_count).and_return(0)
-
- expect(results.empty?).to eq(true)
- end
-
- it 'returns false when there are search results' do
- expect(results.empty?).to eq(false)
- end
- end
-
describe 'confidential issues' do
let(:project_1) { create(:empty_project) }
let(:project_2) { create(:empty_project) }
diff --git a/spec/lib/gitlab/snippet_search_results_spec.rb b/spec/lib/gitlab/snippet_search_results_spec.rb
index e86b9ef6a63..b661a894c0c 100644
--- a/spec/lib/gitlab/snippet_search_results_spec.rb
+++ b/spec/lib/gitlab/snippet_search_results_spec.rb
@@ -5,12 +5,6 @@ describe Gitlab::SnippetSearchResults do
let(:results) { described_class.new(Snippet.all, 'foo') }
- describe '#total_count' do
- it 'returns the total amount of search hits' do
- expect(results.total_count).to eq(2)
- end
- end
-
describe '#snippet_titles_count' do
it 'returns the amount of matched snippet titles' do
expect(results.snippet_titles_count).to eq(1)
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 6a640474cfe..3db5937a4f3 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -31,6 +31,43 @@ describe DiffNote, models: true do
subject { create(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request) }
+ describe ".resolve!" do
+ let(:current_user) { create(:user) }
+ let!(:commit_note) { create(:diff_note_on_commit) }
+ let!(:resolved_note) { create(:diff_note_on_merge_request, :resolved) }
+ let!(:unresolved_note) { create(:diff_note_on_merge_request) }
+
+ before do
+ described_class.resolve!(current_user)
+
+ commit_note.reload
+ resolved_note.reload
+ unresolved_note.reload
+ end
+
+ it 'resolves only the resolvable, not yet resolved notes' do
+ expect(commit_note.resolved_at).to be_nil
+ expect(resolved_note.resolved_by).not_to eq(current_user)
+ expect(unresolved_note.resolved_at).not_to be_nil
+ expect(unresolved_note.resolved_by).to eq(current_user)
+ end
+ end
+
+ describe ".unresolve!" do
+ let!(:resolved_note) { create(:diff_note_on_merge_request, :resolved) }
+
+ before do
+ described_class.unresolve!
+
+ resolved_note.reload
+ end
+
+ it 'unresolves the resolved notes' do
+ expect(resolved_note.resolved_by).to be_nil
+ expect(resolved_note.resolved_at).to be_nil
+ end
+ end
+
describe "#position=" do
context "when provided a string" do
it "sets the position" do
diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb
index 179f2e73662..0142706d140 100644
--- a/spec/models/discussion_spec.rb
+++ b/spec/models/discussion_spec.rb
@@ -238,27 +238,19 @@ describe Discussion, model: true do
context "when resolvable" do
let(:user) { create(:user) }
+ let(:second_note) { create(:diff_note_on_commit) } # unresolvable
before do
allow(subject).to receive(:resolvable?).and_return(true)
-
- allow(first_note).to receive(:resolvable?).and_return(true)
- allow(second_note).to receive(:resolvable?).and_return(false)
- allow(third_note).to receive(:resolvable?).and_return(true)
end
context "when all resolvable notes are resolved" do
before do
first_note.resolve!(user)
third_note.resolve!(user)
- end
- it "calls resolve! on every resolvable note" do
- expect(first_note).to receive(:resolve!).with(current_user)
- expect(second_note).not_to receive(:resolve!)
- expect(third_note).to receive(:resolve!).with(current_user)
-
- subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
end
it "doesn't change resolved_at on the resolved notes" do
@@ -309,46 +301,44 @@ describe Discussion, model: true do
first_note.resolve!(user)
end
- it "calls resolve! on every resolvable note" do
- expect(first_note).to receive(:resolve!).with(current_user)
- expect(second_note).not_to receive(:resolve!)
- expect(third_note).to receive(:resolve!).with(current_user)
-
- subject.resolve!(current_user)
- end
-
it "doesn't change resolved_at on the resolved note" do
expect(first_note.resolved_at).not_to be_nil
- expect { subject.resolve!(current_user) }.not_to change { first_note.resolved_at }
+ expect { subject.resolve!(current_user) }.
+ not_to change { first_note.reload.resolved_at }
end
it "doesn't change resolved_by on the resolved note" do
expect(first_note.resolved_by).to eq(user)
- expect { subject.resolve!(current_user) }.not_to change { first_note.resolved_by }
+ expect { subject.resolve!(current_user) }.
+ not_to change { first_note.reload && first_note.resolved_by }
end
it "doesn't change the resolved state on the resolved note" do
expect(first_note.resolved?).to be true
- expect { subject.resolve!(current_user) }.not_to change { first_note.resolved? }
+ expect { subject.resolve!(current_user) }.
+ not_to change { first_note.reload && first_note.resolved? }
end
it "sets resolved_at on the unresolved note" do
subject.resolve!(current_user)
+ third_note.reload
expect(third_note.resolved_at).not_to be_nil
end
it "sets resolved_by on the unresolved note" do
subject.resolve!(current_user)
+ third_note.reload
expect(third_note.resolved_by).to eq(current_user)
end
it "marks the unresolved note as resolved" do
subject.resolve!(current_user)
+ third_note.reload
expect(third_note.resolved?).to be true
end
@@ -373,16 +363,10 @@ describe Discussion, model: true do
end
context "when no resolvable notes are resolved" do
- it "calls resolve! on every resolvable note" do
- expect(first_note).to receive(:resolve!).with(current_user)
- expect(second_note).not_to receive(:resolve!)
- expect(third_note).to receive(:resolve!).with(current_user)
-
- subject.resolve!(current_user)
- end
-
it "sets resolved_at on the unresolved notes" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(first_note.resolved_at).not_to be_nil
expect(third_note.resolved_at).not_to be_nil
@@ -390,6 +374,8 @@ describe Discussion, model: true do
it "sets resolved_by on the unresolved notes" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(first_note.resolved_by).to eq(current_user)
expect(third_note.resolved_by).to eq(current_user)
@@ -397,6 +383,8 @@ describe Discussion, model: true do
it "marks the unresolved notes as resolved" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(first_note.resolved?).to be true
expect(third_note.resolved?).to be true
@@ -404,18 +392,24 @@ describe Discussion, model: true do
it "sets resolved_at" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(subject.resolved_at).not_to be_nil
end
it "sets resolved_by" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(subject.resolved_by).to eq(current_user)
end
it "marks as resolved" do
subject.resolve!(current_user)
+ first_note.reload
+ third_note.reload
expect(subject.resolved?).to be true
end
@@ -451,16 +445,10 @@ describe Discussion, model: true do
third_note.resolve!(user)
end
- it "calls unresolve! on every resolvable note" do
- expect(first_note).to receive(:unresolve!)
- expect(second_note).not_to receive(:unresolve!)
- expect(third_note).to receive(:unresolve!)
-
- subject.unresolve!
- end
-
it "unsets resolved_at on the resolved notes" do
subject.unresolve!
+ first_note.reload
+ third_note.reload
expect(first_note.resolved_at).to be_nil
expect(third_note.resolved_at).to be_nil
@@ -468,6 +456,8 @@ describe Discussion, model: true do
it "unsets resolved_by on the resolved notes" do
subject.unresolve!
+ first_note.reload
+ third_note.reload
expect(first_note.resolved_by).to be_nil
expect(third_note.resolved_by).to be_nil
@@ -475,6 +465,8 @@ describe Discussion, model: true do
it "unmarks the resolved notes as resolved" do
subject.unresolve!
+ first_note.reload
+ third_note.reload
expect(first_note.resolved?).to be false
expect(third_note.resolved?).to be false
@@ -482,12 +474,16 @@ describe Discussion, model: true do
it "unsets resolved_at" do
subject.unresolve!
+ first_note.reload
+ third_note.reload
expect(subject.resolved_at).to be_nil
end
it "unsets resolved_by" do
subject.unresolve!
+ first_note.reload
+ third_note.reload
expect(subject.resolved_by).to be_nil
end
@@ -504,40 +500,22 @@ describe Discussion, model: true do
first_note.resolve!(user)
end
- it "calls unresolve! on every resolvable note" do
- expect(first_note).to receive(:unresolve!)
- expect(second_note).not_to receive(:unresolve!)
- expect(third_note).to receive(:unresolve!)
-
- subject.unresolve!
- end
-
it "unsets resolved_at on the resolved note" do
subject.unresolve!
- expect(first_note.resolved_at).to be_nil
+ expect(subject.first_note.resolved_at).to be_nil
end
it "unsets resolved_by on the resolved note" do
subject.unresolve!
- expect(first_note.resolved_by).to be_nil
+ expect(subject.first_note.resolved_by).to be_nil
end
it "unmarks the resolved note as resolved" do
subject.unresolve!
- expect(first_note.resolved?).to be false
- end
- end
-
- context "when no resolvable notes are resolved" do
- it "calls unresolve! on every resolvable note" do
- expect(first_note).to receive(:unresolve!)
- expect(second_note).not_to receive(:unresolve!)
- expect(third_note).to receive(:unresolve!)
-
- subject.unresolve!
+ expect(subject.first_note.resolved?).to be false
end
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index afc7dc5db81..7624050878e 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -441,7 +441,7 @@ describe Repository, models: true do
end
end
- describe '#commit_with_hooks' do
+ describe '#update_branch_with_hooks' do
let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev
@@ -454,31 +454,64 @@ describe Repository, models: true do
it 'runs without errors' do
expect do
- repository.commit_with_hooks(user, 'feature') { new_rev }
+ repository.update_branch_with_hooks(user, 'feature') { new_rev }
end.not_to raise_error
end
it 'ensures the autocrlf Git option is set to :input' do
expect(repository).to receive(:update_autocrlf_option)
- repository.commit_with_hooks(user, 'feature') { new_rev }
+ repository.update_branch_with_hooks(user, 'feature') { new_rev }
end
context "when the branch wasn't empty" do
it 'updates the head' do
expect(repository.find_branch('feature').target.id).to eq(old_rev)
- repository.commit_with_hooks(user, 'feature') { new_rev }
+ repository.update_branch_with_hooks(user, 'feature') { new_rev }
expect(repository.find_branch('feature').target.id).to eq(new_rev)
end
end
end
+ context 'when the update adds more than one commit' do
+ it 'runs without errors' do
+ old_rev = '33f3729a45c02fc67d00adb1b8bca394b0e761d9'
+
+ # old_rev is an ancestor of new_rev
+ expect(repository.rugged.merge_base(old_rev, new_rev)).to eq(old_rev)
+
+ # old_rev is not a direct ancestor (parent) of new_rev
+ expect(repository.rugged.lookup(new_rev).parent_ids).not_to include(old_rev)
+
+ branch = 'feature-ff-target'
+ repository.add_branch(user, branch, old_rev)
+
+ expect { repository.update_branch_with_hooks(user, branch) { new_rev } }.not_to raise_error
+ end
+ end
+
+ context 'when the update would remove commits from the target branch' do
+ it 'raises an exception' do
+ branch = 'master'
+ old_rev = repository.find_branch(branch).target.sha
+
+ # The 'master' branch is NOT an ancestor of new_rev.
+ expect(repository.rugged.merge_base(old_rev, new_rev)).not_to eq(old_rev)
+
+ # Updating 'master' to new_rev would lose the commits on 'master' that
+ # are not contained in new_rev. This should not be allowed.
+ expect do
+ repository.update_branch_with_hooks(user, branch) { new_rev }
+ end.to raise_error(Repository::CommitError)
+ end
+ end
+
context 'when pre hooks failed' do
it 'gets an error' do
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
expect do
- repository.commit_with_hooks(user, 'feature') { new_rev }
+ repository.update_branch_with_hooks(user, 'feature') { new_rev }
end.to raise_error(GitHooksService::PreReceiveError)
end
end
@@ -497,7 +530,7 @@ describe Repository, models: true do
expect(repository).to receive(:expire_has_visible_content_cache)
expect(repository).to receive(:expire_branch_count_cache)
- repository.commit_with_hooks(user, 'new-feature') { new_rev }
+ repository.update_branch_with_hooks(user, 'new-feature') { new_rev }
end
end
diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb
index f802fcd2d2e..06e3a2183c0 100644
--- a/spec/requests/api/fork_spec.rb
+++ b/spec/requests/api/fork_spec.rb
@@ -6,6 +6,12 @@ describe API::API, api: true do
let(:user2) { create(:user) }
let(:user3) { create(:user) }
let(:admin) { create(:admin) }
+ let(:group) { create(:group) }
+ let(:group2) do
+ group = create(:group, name: 'group2_name')
+ group.add_owner(user2)
+ group
+ end
let(:project) do
create(:project, creator_id: user.id, namespace: user.namespace)
@@ -22,6 +28,7 @@ describe API::API, api: true do
context 'when authenticated' do
it 'forks if user has sufficient access to project' do
post api("/projects/fork/#{project.id}", user2)
+
expect(response).to have_http_status(201)
expect(json_response['name']).to eq(project.name)
expect(json_response['path']).to eq(project.path)
@@ -32,6 +39,7 @@ describe API::API, api: true do
it 'forks if user is admin' do
post api("/projects/fork/#{project.id}", admin)
+
expect(response).to have_http_status(201)
expect(json_response['name']).to eq(project.name)
expect(json_response['path']).to eq(project.path)
@@ -42,12 +50,14 @@ describe API::API, api: true do
it 'fails on missing project access for the project to fork' do
post api("/projects/fork/#{project.id}", user3)
+
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Project Not Found')
end
it 'fails if forked project exists in the user namespace' do
post api("/projects/fork/#{project.id}", user)
+
expect(response).to have_http_status(409)
expect(json_response['message']['name']).to eq(['has already been taken'])
expect(json_response['message']['path']).to eq(['has already been taken'])
@@ -55,14 +65,70 @@ describe API::API, api: true do
it 'fails if project to fork from does not exist' do
post api('/projects/fork/424242', user)
+
expect(response).to have_http_status(404)
expect(json_response['message']).to eq('404 Project Not Found')
end
+
+ it 'forks with explicit own user namespace id' do
+ post api("/projects/fork/#{project.id}", user2), namespace: user2.namespace.id
+
+ expect(response).to have_http_status(201)
+ expect(json_response['owner']['id']).to eq(user2.id)
+ end
+
+ it 'forks with explicit own user name as namespace' do
+ post api("/projects/fork/#{project.id}", user2), namespace: user2.username
+
+ expect(response).to have_http_status(201)
+ expect(json_response['owner']['id']).to eq(user2.id)
+ end
+
+ it 'forks to another user when admin' do
+ post api("/projects/fork/#{project.id}", admin), namespace: user2.username
+
+ expect(response).to have_http_status(201)
+ expect(json_response['owner']['id']).to eq(user2.id)
+ end
+
+ it 'fails if trying to fork to another user when not admin' do
+ post api("/projects/fork/#{project.id}", user2), namespace: admin.namespace.id
+
+ expect(response).to have_http_status(409)
+ end
+
+ it 'fails if trying to fork to non-existent namespace' do
+ post api("/projects/fork/#{project.id}", user2), namespace: 42424242
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Target Namespace Not Found')
+ end
+
+ it 'forks to owned group' do
+ post api("/projects/fork/#{project.id}", user2), namespace: group2.name
+
+ expect(response).to have_http_status(201)
+ expect(json_response['namespace']['name']).to eq(group2.name)
+ end
+
+ it 'fails to fork to not owned group' do
+ post api("/projects/fork/#{project.id}", user2), namespace: group.name
+
+ expect(response).to have_http_status(409)
+ end
+
+ it 'forks to not owned group when admin' do
+ post api("/projects/fork/#{project.id}", admin), namespace: group.name
+
+ expect(response).to have_http_status(201)
+ expect(json_response['namespace']['name']).to eq(group.name)
+ end
end
context 'when unauthenticated' do
it 'returns authentication error' do
post api("/projects/fork/#{project.id}")
+
expect(response).to have_http_status(401)
expect(json_response['message']).to eq('401 Unauthorized')
end
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
new file mode 100644
index 00000000000..391fc13a380
--- /dev/null
+++ b/spec/requests/api/lint_spec.rb
@@ -0,0 +1,49 @@
+require 'spec_helper'
+
+describe API::Lint, api: true do
+ include ApiHelpers
+
+ describe 'POST /ci/lint' do
+ context 'with valid .gitlab-ci.yaml content' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ end
+
+ it 'passes validation' do
+ post api('/ci/lint'), { content: yaml_content }
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Hash
+ expect(json_response['status']).to eq('valid')
+ expect(json_response['errors']).to eq([])
+ end
+ end
+
+ context 'with an invalid .gitlab_ci.yml' do
+ it 'responds with errors about invalid syntax' do
+ post api('/ci/lint'), { content: 'invalid content' }
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to eq('invalid')
+ expect(json_response['errors']).to eq(['Invalid configuration format'])
+ end
+
+ it "responds with errors about invalid configuration" do
+ post api('/ci/lint'), { content: '{ image: "ruby:2.1", services: ["postgres"] }' }
+
+ expect(response).to have_http_status(200)
+ expect(json_response['status']).to eq('invalid')
+ expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
+ end
+ end
+
+ context 'without the content parameter' do
+ it 'responds with validation error about missing content' do
+ post api('/ci/lint')
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('content is missing')
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index ac08aa53b0b..6f7ce8ca992 100644
--- a/spec/services/issues/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -1,14 +1,14 @@
require 'spec_helper'
-describe Issues::BulkUpdateService, services: true do
+describe Issuable::BulkUpdateService, services: true do
let(:user) { create(:user) }
let(:project) { create(:empty_project, namespace: user.namespace) }
def bulk_update(issues, extra_params = {})
bulk_update_params = extra_params
- .reverse_merge(issues_ids: Array(issues).map(&:id).join(','))
+ .reverse_merge(issuable_ids: Array(issues).map(&:id).join(','))
- Issues::BulkUpdateService.new(project, user, bulk_update_params).execute
+ Issuable::BulkUpdateService.new(project, user, bulk_update_params).execute('issue')
end
describe 'close issues' do
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index e0dbc9aa84c..ac38e31b77e 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -15,7 +15,7 @@ RSpec.configure do |config|
DatabaseCleaner.start
end
- config.after(:each) do
+ config.append_after(:each) do
DatabaseCleaner.clean
end
end
diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb
index 464051063d8..446ba3bfa14 100644
--- a/spec/views/projects/builds/show.html.haml_spec.rb
+++ b/spec/views/projects/builds/show.html.haml_spec.rb
@@ -59,14 +59,10 @@ describe 'projects/builds/show' do
end
it 'shows trigger variables in separate lines' do
- expect(rendered).to have_css('code', text: variable_regexp('TRIGGER_KEY_1', 'TRIGGER_VALUE_1'))
- expect(rendered).to have_css('code', text: variable_regexp('TRIGGER_KEY_2', 'TRIGGER_VALUE_2'))
+ expect(rendered).to have_css('.js-build-variable', visible: false, text: 'TRIGGER_KEY_1')
+ expect(rendered).to have_css('.js-build-variable', visible: false, text: 'TRIGGER_KEY_2')
+ expect(rendered).to have_css('.js-build-value', visible: false, text: 'TRIGGER_VALUE_1')
+ expect(rendered).to have_css('.js-build-value', visible: false, text: 'TRIGGER_VALUE_2')
end
end
-
- private
-
- def variable_regexp(key, value)
- /\A#{Regexp.escape("#{key}=#{value}")}\Z/
- end
end
diff --git a/spec/workers/prune_old_events_worker_spec.rb b/spec/workers/prune_old_events_worker_spec.rb
new file mode 100644
index 00000000000..35e1518a35e
--- /dev/null
+++ b/spec/workers/prune_old_events_worker_spec.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+
+describe PruneOldEventsWorker do
+ describe '#perform' do
+ let!(:expired_event) { create(:event, author_id: 0, created_at: 13.months.ago) }
+ let!(:not_expired_event) { create(:event, author_id: 0, created_at: 1.day.ago) }
+ let!(:exactly_12_months_event) { create(:event, author_id: 0, created_at: 12.months.ago) }
+
+ it 'prunes events older than 12 months' do
+ expect { subject.perform }.to change { Event.count }.by(-1)
+ expect(Event.find_by(id: expired_event.id)).to be_nil
+ end
+
+ it 'leaves fresh events' do
+ subject.perform
+ expect(not_expired_event.reload).to be_present
+ end
+
+ it 'leaves events from exactly 12 months ago' do
+ subject.perform
+ expect(exactly_12_months_event).to be_present
+ end
+ end
+end