summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-06-13 16:05:43 +0200
committerKamil Trzcinski <ayufan@ayufan.eu>2016-06-13 16:05:43 +0200
commit0fab7b11baf9971d0f82bbe234720e0bbaf22b6e (patch)
treec95214c24a44cc4f1d71e56363ba870d1c0645da /spec
parentbb3fc8c72c2a3af7873cabf9ae3e951376e7ac9e (diff)
parent57ebd3996eb5d8ff85c5899c7a7f351272655562 (diff)
downloadgitlab-ce-0fab7b11baf9971d0f82bbe234720e0bbaf22b6e.tar.gz
Merge remote-tracking branch 'origin/master' into artifacts-when
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/import/bitbucket_controller_spec.rb1
-rw-r--r--spec/controllers/import/fogbugz_controller_spec.rb1
-rw-r--r--spec/controllers/import/github_controller_spec.rb1
-rw-r--r--spec/controllers/import/gitlab_controller_spec.rb1
-rw-r--r--spec/controllers/import/gitorious_controller_spec.rb1
-rw-r--r--spec/controllers/import/google_code_controller_spec.rb1
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb2
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb2
-rw-r--r--spec/controllers/projects/repositories_controller_spec.rb5
-rw-r--r--spec/factories/wiki_pages.rb2
-rw-r--r--spec/features/builds_spec.rb23
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb46
-rw-r--r--spec/features/issues/filter_by_labels_spec.rb15
-rw-r--r--spec/features/issues/filter_issues_spec.rb36
-rw-r--r--spec/features/issues_spec.rb12
-rw-r--r--spec/features/markdown_spec.rb13
-rw-r--r--spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb105
-rw-r--r--spec/features/profiles/preferences_spec.rb8
-rw-r--r--spec/features/projects/commits/cherry_pick_spec.rb1
-rw-r--r--spec/fixtures/markdown.md.erb2
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb3
-rw-r--r--spec/javascripts/awards_handler_spec.js.coffee13
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb85
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb108
-rw-r--r--spec/lib/disable_email_interceptor_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/client_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb4
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb13
-rw-r--r--spec/lib/gitlab/gitlab_import/client_spec.rb4
-rw-r--r--spec/lib/gitlab/saml/user_spec.rb18
-rw-r--r--spec/lib/gitlab/sanitizers/svg_spec.rb94
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb2
-rw-r--r--spec/models/build_spec.rb2
-rw-r--r--spec/models/concerns/issuable_spec.rb26
-rw-r--r--spec/models/merge_request_spec.rb153
-rw-r--r--spec/models/notification_setting_spec.rb1
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb2
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb2
-rw-r--r--spec/models/project_spec.rb96
-rw-r--r--spec/models/service_spec.rb33
-rw-r--r--spec/requests/api/merge_requests_spec.rb24
-rw-r--r--spec/requests/ci/api/builds_spec.rb2
-rw-r--r--spec/requests/git_http_spec.rb83
-rw-r--r--spec/services/notification_service_spec.rb301
-rw-r--r--spec/services/projects/import_service_spec.rb2
-rw-r--r--spec/services/todo_service_spec.rb30
-rw-r--r--spec/support/import_spec_helper.rb (renamed from spec/controllers/import/import_spec_helper.rb)2
-rw-r--r--spec/support/markdown_feature.rb4
48 files changed, 1200 insertions, 193 deletions
diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb
index 81c03c9059b..07bf8d2d1c3 100644
--- a/spec/controllers/import/bitbucket_controller_spec.rb
+++ b/spec/controllers/import/bitbucket_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::BitbucketController do
include ImportSpecHelper
diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb
index 27b11267d2a..5f0f6dea821 100644
--- a/spec/controllers/import/fogbugz_controller_spec.rb
+++ b/spec/controllers/import/fogbugz_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::FogbugzController do
include ImportSpecHelper
diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb
index bcc713dce2a..c55a3c28208 100644
--- a/spec/controllers/import/github_controller_spec.rb
+++ b/spec/controllers/import/github_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::GithubController do
include ImportSpecHelper
diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb
index 198d006af76..e8cf6aa7767 100644
--- a/spec/controllers/import/gitlab_controller_spec.rb
+++ b/spec/controllers/import/gitlab_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::GitlabController do
include ImportSpecHelper
diff --git a/spec/controllers/import/gitorious_controller_spec.rb b/spec/controllers/import/gitorious_controller_spec.rb
index 7cb1b85a46d..4ae2b78e11c 100644
--- a/spec/controllers/import/gitorious_controller_spec.rb
+++ b/spec/controllers/import/gitorious_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::GitoriousController do
include ImportSpecHelper
diff --git a/spec/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb
index 66088139a69..4241db6e771 100644
--- a/spec/controllers/import/google_code_controller_spec.rb
+++ b/spec/controllers/import/google_code_controller_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-require_relative 'import_spec_helper'
describe Import::GoogleCodeController do
include ImportSpecHelper
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 1301574f489..4b408c03703 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -91,7 +91,7 @@ describe Projects::MergeRequestsController do
id: merge_request.iid,
format: :diff)
- expect(response.headers['Gitlab-Workhorse-Send-Data']).to start_with("git-diff:")
+ expect(response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-diff:")
end
end
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index fb29274c687..33c35161da3 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -17,6 +17,7 @@ describe Projects::RawController do
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
expect(response.header['Content-Disposition']).
to eq("inline")
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-blob:")
end
end
@@ -31,6 +32,7 @@ describe Projects::RawController do
expect(response.status).to eq(200)
expect(response.header['Content-Type']).to eq('image/jpeg')
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-blob:")
end
end
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 0ddbec9eac2..aad62cf20e3 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -20,10 +20,11 @@ describe Projects::RepositoriesController do
project.team << [user, :developer]
sign_in(user)
end
- it "uses Gitlab::Workhorse" do
- expect(Gitlab::Workhorse).to receive(:send_git_archive).with(project, "master", "zip")
+ it "uses Gitlab::Workhorse" do
get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
+
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("git-archive:")
end
context "when the service raises an error" do
diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb
index 938ccf2306b..efa6cbe5bb1 100644
--- a/spec/factories/wiki_pages.rb
+++ b/spec/factories/wiki_pages.rb
@@ -2,7 +2,7 @@ require 'ostruct'
FactoryGirl.define do
factory :wiki_page do
- page = OpenStruct.new(url_path: 'some-name')
+ page { OpenStruct.new(url_path: 'some-name') }
association :wiki, factory: :project_wiki, strategy: :build
initialize_with { new(wiki, page, true) }
end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index df221ab1f3b..b8ecc356b4d 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -93,9 +93,7 @@ describe "Builds" do
end
it 'has button to download artifacts' do
- page.within('.artifacts') do
- expect(page).to have_content 'Download'
- end
+ expect(page).to have_content 'Download'
end
end
@@ -107,9 +105,7 @@ describe "Builds" do
end
it do
- page.within('.build-controls') do
- expect(page).to have_link 'Raw'
- end
+ expect(page).to have_link 'Raw'
end
end
end
@@ -165,15 +161,10 @@ describe "Builds" do
end
describe "GET /:project/builds/:id/download" do
- context "Build from project" do
- before do
- @build.update_attributes(artifacts_file: artifacts_file)
- visit namespace_project_build_path(@project.namespace, @project, @build)
- page.within('.artifacts') { click_link 'Download' }
- end
-
- it { expect(page.status_code).to eq(200) }
- it { expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) }
+ before do
+ @build.update_attributes(artifacts_file: artifacts_file)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ click_link 'Download'
end
context "Build from other project" do
@@ -193,7 +184,7 @@ describe "Builds" do
@build.run!
@build.trace = 'BUILD TRACE'
visit namespace_project_build_path(@project.namespace, @project, @build)
- page.within('.build-controls') { click_link 'Raw' }
+ page.within('.js-build-sidebar') { click_link 'Raw' }
end
it 'sends the right headers' do
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
new file mode 100644
index 00000000000..365cb445df1
--- /dev/null
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+feature 'Tooltips on .timeago dates', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:created_date) { Date.yesterday.to_time }
+ let(:expected_format) { created_date.strftime('%b %-d, %Y %l:%M%P UTC') }
+
+ context 'on the activity tab' do
+ before do
+ project.team << [user, :master]
+
+ Event.create( project: project, author_id: user.id, action: Event::JOINED,
+ updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+
+ context 'on the snippets tab' do
+ before do
+ project.team << [user, :master]
+ create(:snippet, author: user, updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_snippets_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+end
diff --git a/spec/features/issues/filter_by_labels_spec.rb b/spec/features/issues/filter_by_labels_spec.rb
index 0ec8b6b180a..16c619c9288 100644
--- a/spec/features/issues/filter_by_labels_spec.rb
+++ b/spec/features/issues/filter_by_labels_spec.rb
@@ -199,4 +199,19 @@ feature 'Issue filtering by Labels', feature: true do
end
end
end
+
+ context 'dropdown filtering', js: true do
+ it 'should filter by label name' do
+ page.within '.labels-filter' do
+ click_button 'Label'
+ wait_for_ajax
+ fill_in 'label-name', with: 'bug'
+
+ page.within '.dropdown-content' do
+ expect(page).not_to have_content 'enhancement'
+ expect(page).to have_content 'bug'
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 7efbaaa048c..1f0594e6b02 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -294,40 +294,4 @@ describe 'Filter issues', feature: true do
end
end
end
-
- describe 'filter by any author', js: true do
- before do
- user2 = create(:user, name: "tester")
- create(:issue, project: project, author: user)
- create(:issue, project: project, author: user2)
-
- visit namespace_project_issues_path(project.namespace, project)
- end
-
- it 'should show filter by any author link' do
- click_button "Author"
- fill_in "Search authors", with: "tester"
-
- page.within ".dropdown-menu-author" do
- expect(page).to have_content "tester"
- end
- end
-
- it 'should show filter issues by any author' do
- page.within '.issues-list' do
- expect(page).to have_selector ".issue", count: 2
- end
-
- click_button "Author"
- fill_in "Search authors", with: "tester"
-
- page.within ".dropdown-menu-author" do
- click_link "tester"
- end
-
- page.within '.issues-list' do
- expect(page).to have_selector ".issue", count: 1
- end
- end
- end
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 460d7f82b36..f6fb6a72d22 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -75,12 +75,13 @@ describe 'Issues', feature: true do
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
- page.within '.datepicker' do
+ page.within '.ui-datepicker' do
click_link date.day
end
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
click_button 'Submit issue'
@@ -100,18 +101,19 @@ describe 'Issues', feature: true do
it 'should save with due date' do
date = Date.today.at_beginning_of_month
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
date = date.tomorrow
fill_in 'issue_title', with: 'bug 345'
fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
- page.within '.datepicker' do
+ page.within '.ui-datepicker' do
click_link date.day
end
- expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+ expect(find('#issuable-due-date').value).to eq date.to_s
click_button 'Save changes'
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 7663d193354..09ccc77c101 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -165,17 +165,27 @@ describe 'GitLab Markdown', feature: true do
describe 'ExternalLinkFilter' do
it 'adds nofollow to external link' do
link = doc.at_css('a:contains("Google")')
+
expect(link.attr('rel')).to include('nofollow')
end
it 'adds noreferrer to external link' do
link = doc.at_css('a:contains("Google")')
+
expect(link.attr('rel')).to include('noreferrer')
end
+ it 'adds _blank to target attribute for external links' do
+ link = doc.at_css('a:contains("Google")')
+
+ expect(link.attr('target')).to match('_blank')
+ end
+
it 'ignores internal link' do
link = doc.at_css('a:contains("GitLab Root")')
+
expect(link.attr('rel')).not_to match 'nofollow'
+ expect(link.attr('target')).not_to match '_blank'
end
end
end
@@ -231,13 +241,14 @@ describe 'GitLab Markdown', feature: true do
context 'wiki pipeline' do
before do
@project_wiki = @feat.project_wiki
+ @project_wiki_page = @feat.project_wiki_page
file = Gollum::File.new(@project_wiki.wiki)
expect(file).to receive(:path).and_return('images/example.jpg')
expect(@project_wiki).to receive(:find_file).with('images/example.jpg').and_return(file)
allow(@project_wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
- @html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki })
+ @html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki, page_slug: @project_wiki_page.slug })
end
it_behaves_like 'all pipelines'
diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb
new file mode 100644
index 00000000000..65e9185ec24
--- /dev/null
+++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb
@@ -0,0 +1,105 @@
+require 'spec_helper'
+
+feature 'Only allow merge requests to be merged if the build succeeds', feature: true do
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request_with_diffs, source_project: project) }
+
+ before do
+ login_as merge_request.author
+
+ project.team << [merge_request.author, :master]
+ end
+
+ context 'project does not have CI enabled' do
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+
+ context 'when project has CI enabled' do
+ let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+
+ context 'when merge requests can only be merged if the build succeeds' do
+ before do
+ project.update_attribute(:only_allow_merge_if_build_succeeds, true)
+ end
+
+ context 'when CI is running' do
+ before { pipeline.update_column(:status, :running) }
+
+ it 'does not allow to merge immediately' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Merge When Build Succeeds'
+ expect(page).not_to have_button 'Select Merge Moment'
+ end
+ end
+
+ context 'when CI failed' do
+ before { pipeline.update_column(:status, :failed) }
+
+ it 'does not allow MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).not_to have_button 'Accept Merge Request'
+ expect(page).to have_content('Please retry the build or push a new commit to fix the failure.')
+ end
+ end
+
+ context 'when CI succeeded' do
+ before { pipeline.update_column(:status, :success) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+ end
+
+ context 'when merge requests can be merged when the build failed' do
+ before do
+ project.update_attribute(:only_allow_merge_if_build_succeeds, false)
+ end
+
+ context 'when CI is running' do
+ before { pipeline.update_column(:status, :running) }
+
+ it 'allows MR to be merged immediately', js: true do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Merge When Build Succeeds'
+
+ click_button 'Select Merge Moment'
+ expect(page).to have_content 'Merge Immediately'
+ end
+ end
+
+ context 'when CI failed' do
+ before { pipeline.update_column(:status, :failed) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+
+ context 'when CI succeeded' do
+ before { pipeline.update_column(:status, :success) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+ end
+ end
+
+ def visit_merge_request(merge_request)
+ visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ end
+end
diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb
index 8f645438cff..787bf42d048 100644
--- a/spec/features/profiles/preferences_spec.rb
+++ b/spec/features/profiles/preferences_spec.rb
@@ -54,7 +54,7 @@ describe 'Profile > Preferences', feature: true do
end
end
- describe 'User changes their default dashboard' do
+ describe 'User changes their default dashboard', js: true do
it 'creates a flash message' do
select 'Starred Projects', from: 'user_dashboard'
click_button 'Save'
@@ -66,8 +66,10 @@ describe 'Profile > Preferences', feature: true do
select 'Starred Projects', from: 'user_dashboard'
click_button 'Save'
- click_link 'Dashboard'
- expect(page.current_path).to eq starred_dashboard_projects_path
+ allowing_for_delay do
+ find('#logo').click
+ expect(page.current_path).to eq starred_dashboard_projects_path
+ end
click_link 'Your Projects'
expect(page.current_path).to eq dashboard_projects_path
diff --git a/spec/features/projects/commits/cherry_pick_spec.rb b/spec/features/projects/commits/cherry_pick_spec.rb
index 0559b02f321..f88c0616b52 100644
--- a/spec/features/projects/commits/cherry_pick_spec.rb
+++ b/spec/features/projects/commits/cherry_pick_spec.rb
@@ -16,6 +16,7 @@ describe 'Cherry-pick Commits' do
it do
visit namespace_project_commit_path(project.namespace, project, master_pickable_commit.id)
find("a[href='#modal-cherry-pick-commit']").click
+ expect(page).not_to have_content('v1.0.0') # Only branches, not tags
page.within('#modal-cherry-pick-commit') do
uncheck 'create_merge_request'
click_button 'Cherry-pick'
diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb
index 34ce7c4f033..c75d28d9801 100644
--- a/spec/fixtures/markdown.md.erb
+++ b/spec/fixtures/markdown.md.erb
@@ -136,7 +136,7 @@ But it shouldn't autolink text inside certain tags:
### ExternalLinkFilter
-External links get a `rel="nofollow"` attribute:
+External links get a `rel="nofollow noreferrer"` and `target="_blank"` attributes:
- [Google](https://google.com/)
- [GitLab Root](<%= Gitlab.config.gitlab.url %>)
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 13de88e2f21..ade5c3b02d9 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -121,13 +121,14 @@ describe GitlabMarkdownHelper do
before do
@wiki = double('WikiPage')
allow(@wiki).to receive(:content).and_return('wiki content')
+ allow(@wiki).to receive(:slug).and_return('nested/page')
helper.instance_variable_set(:@project_wiki, @wiki)
end
it "should use Wiki pipeline for markdown files" do
allow(@wiki).to receive(:format).and_return(:markdown)
- expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki)
+ expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki, page_slug: "nested/page")
helper.render_wiki_content(@wiki)
end
diff --git a/spec/javascripts/awards_handler_spec.js.coffee b/spec/javascripts/awards_handler_spec.js.coffee
index 0bd6d696387..ba191199dc7 100644
--- a/spec/javascripts/awards_handler_spec.js.coffee
+++ b/spec/javascripts/awards_handler_spec.js.coffee
@@ -3,10 +3,11 @@
#= require jquery.cookie
#= require ./fixtures/emoji_menu
-awardsHandler = null
-window.gl or= {}
-gl.emojiAliases = -> return { '+1': 'thumbsup', '-1': 'thumbsdown' }
-gl.awardMenuUrl = '/emojis'
+awardsHandler = null
+window.gl or= {}
+window.gon or= {}
+gl.emojiAliases = -> return { '+1': 'thumbsup', '-1': 'thumbsdown' }
+gon.award_menu_url = '/emojis'
lazyAssert = (done, assertFn) ->
@@ -25,9 +26,7 @@ describe 'AwardsHandler', ->
fixture.load 'awards_handler.html'
awardsHandler = new AwardsHandler
spyOn(awardsHandler, 'postEmoji').and.callFake (url, emoji, cb) => cb()
- spyOn(jQuery, 'get').and.callFake (req, cb) ->
- expect(req).toBe '/emojis'
- cb window.emojiMenu
+ spyOn(jQuery, 'get').and.callFake (req, cb) -> cb window.emojiMenu
describe '::showEmojiMenu', ->
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
deleted file mode 100644
index 185abbb2108..00000000000
--- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-require 'spec_helper'
-
-describe Banzai::Filter::WikiLinkFilter, lib: true do
- include FilterSpecHelper
-
- let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
- let(:project) { build_stubbed(:empty_project, :public, name: "wiki_link_project", namespace: namespace) }
- let(:user) { double }
- let(:project_wiki) { ProjectWiki.new(project, user) }
-
- describe "links within the wiki (relative)" do
- describe "hierarchical links to the current directory" do
- it "doesn't rewrite non-file links" do
- link = "<a href='./page'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('./page')
- end
-
- it "doesn't rewrite file links" do
- link = "<a href='./page.md'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('./page.md')
- end
- end
-
- describe "hierarchical links to the parent directory" do
- it "doesn't rewrite non-file links" do
- link = "<a href='../page'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('../page')
- end
-
- it "doesn't rewrite file links" do
- link = "<a href='../page.md'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('../page.md')
- end
- end
-
- describe "hierarchical links to a sub-directory" do
- it "doesn't rewrite non-file links" do
- link = "<a href='./subdirectory/page'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('./subdirectory/page')
- end
-
- it "doesn't rewrite file links" do
- link = "<a href='./subdirectory/page.md'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('./subdirectory/page.md')
- end
- end
-
- describe "non-hierarchical links" do
- it 'rewrites non-file links to be at the scope of the wiki root' do
- link = "<a href='page'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to match('/wiki_link_ns/wiki_link_project/wikis/page')
- end
-
- it "doesn't rewrite file links" do
- link = "<a href='page.md'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('page.md')
- end
- end
- end
-
- describe "links outside the wiki (absolute)" do
- it "doesn't rewrite links" do
- link = "<a href='http://example.com/page'>Link to Page</a>"
- filtered_link = filter(link, project_wiki: project_wiki).children[0]
-
- expect(filtered_link.attribute('href').value).to eq('http://example.com/page')
- end
- end
-end
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index 7aa1b4a3bf6..72bc6a0b704 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -50,4 +50,112 @@ describe Banzai::Pipeline::WikiPipeline do
end
end
end
+
+ describe "Links" do
+ let(:namespace) { create(:namespace, name: "wiki_link_ns") }
+ let(:project) { create(:empty_project, :public, name: "wiki_link_project", namespace: namespace) }
+ let(:project_wiki) { ProjectWiki.new(project, double(:user)) }
+ let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
+
+ { "when GitLab is hosted at a root URL" => '/',
+ "when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
+
+ context test_name do
+ before do
+ allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root)
+ end
+
+ describe "linking to pages within the wiki" do
+ context "when creating hierarchical links to the current directory" do
+ it "rewrites non-file links to be at the scope of the current directory" do
+ markdown = "[Page](./page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](./page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
+ end
+ end
+
+ context "when creating hierarchical links to the parent directory" do
+ it "rewrites non-file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the parent directory" do
+ markdown = "[Link to Page](../page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page.md\"")
+ end
+ end
+
+ context "when creating hierarchical links to a sub-directory" do
+ it "rewrites non-file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the sub-directory" do
+ markdown = "[Link to Page](./subdirectory/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page.md\"")
+ end
+ end
+
+ describe "when creating non-hierarchical links" do
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
+ end
+
+ it "rewrites file links to be at the scope of the current directory" do
+ markdown = "[Link to Page](page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
+ end
+ end
+
+ describe "when creating root links" do
+ it 'rewrites non-file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
+ end
+
+ it 'rewrites file links to be at the scope of the wiki root' do
+ markdown = "[Link to Page](/page.md)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page.md\"")
+ end
+ end
+ end
+
+ describe "linking to pages outside the wiki (absolute)" do
+ it "doesn't rewrite links" do
+ markdown = "[Link to Page](http://example.com/page)"
+ output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
+
+ expect(output).to include('href="http://example.com/page"')
+ end
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb
index c2a7b20b84d..309a88151cf 100644
--- a/spec/lib/disable_email_interceptor_spec.rb
+++ b/spec/lib/disable_email_interceptor_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe DisableEmailInterceptor, lib: true do
before do
- ActionMailer::Base.register_interceptor(DisableEmailInterceptor)
+ Mail.register_interceptor(DisableEmailInterceptor)
end
it 'should not send emails' do
@@ -14,7 +14,7 @@ describe DisableEmailInterceptor, lib: true do
# Removing interceptor from the list because unregister_interceptor is
# implemented in later version of mail gem
# See: https://github.com/mikel/mail/pull/705
- Mail.class_variable_set(:@@delivery_interceptors, [])
+ Mail.unregister_interceptor(DisableEmailInterceptor)
end
def deliver_mail
diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb
index 7718689e6d4..760d66a1488 100644
--- a/spec/lib/gitlab/bitbucket_import/client_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb
@@ -1,12 +1,14 @@
require 'spec_helper'
describe Gitlab::BitbucketImport::Client, lib: true do
+ include ImportSpecHelper
+
let(:token) { '123456' }
let(:secret) { 'secret' }
let(:client) { Gitlab::BitbucketImport::Client.new(token, secret) }
before do
- Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "bitbucket")
+ stub_omniauth_provider('bitbucket')
end
it 'all OAuth client options are symbols' do
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 1a833f255a5..aa00f32becb 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -1,8 +1,10 @@
require 'spec_helper'
describe Gitlab::BitbucketImport::Importer, lib: true do
+ include ImportSpecHelper
+
before do
- Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "bitbucket")
+ stub_omniauth_provider('bitbucket')
end
let(:statuses) do
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 83ddabe6b0b..1ec539066a7 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -120,6 +120,19 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
model.add_column_with_default(:projects, :foo, :integer, default: 10)
end.to raise_error(RuntimeError)
end
+
+ it 'removes the added column whenever changing a column NULL constraint fails' do
+ expect(model).to receive(:change_column_null).
+ with(:projects, :foo, false).
+ and_raise(RuntimeError)
+
+ expect(model).to receive(:remove_column).
+ with(:projects, :foo)
+
+ expect do
+ model.add_column_with_default(:projects, :foo, :integer, default: 10)
+ end.to raise_error(RuntimeError)
+ end
end
context 'inside a transaction' do
diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb
index e6831e7c383..cd8e805466a 100644
--- a/spec/lib/gitlab/gitlab_import/client_spec.rb
+++ b/spec/lib/gitlab/gitlab_import/client_spec.rb
@@ -1,11 +1,13 @@
require 'spec_helper'
describe Gitlab::GitlabImport::Client, lib: true do
+ include ImportSpecHelper
+
let(:token) { '123456' }
let(:client) { Gitlab::GitlabImport::Client.new(token) }
before do
- Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "gitlab")
+ stub_omniauth_provider('gitlab')
end
it 'all OAuth2 client options are symbols' do
diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb
index c2a51d9249c..84c21ceefd9 100644
--- a/spec/lib/gitlab/saml/user_spec.rb
+++ b/spec/lib/gitlab/saml/user_spec.rb
@@ -145,6 +145,7 @@ describe Gitlab::Saml::User, lib: true do
allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) }
allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
+ allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user)
end
context 'and no account for the LDAP user' do
@@ -177,6 +178,23 @@ describe Gitlab::Saml::User, lib: true do
])
end
end
+
+ context 'user has SAML user, and wants to add their LDAP identity' do
+ it 'adds the LDAP identity to the existing SAML user' do
+ create(:omniauth_user, email: 'john@mail.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'saml', username: 'john')
+ local_hash = OmniAuth::AuthHash.new(uid: 'uid=user1,ou=People,dc=example', provider: provider, info: info_hash)
+ local_saml_user = described_class.new(local_hash)
+ local_saml_user.save
+ local_gl_user = local_saml_user.gl_user
+
+ expect(local_gl_user).to be_valid
+ expect(local_gl_user.identities.length).to eql 2
+ identities_as_hash = local_gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
+ expect(identities_as_hash).to match_array([ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
+ { provider: 'saml', extern_uid: 'uid=user1,ou=People,dc=example' }
+ ])
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/sanitizers/svg_spec.rb b/spec/lib/gitlab/sanitizers/svg_spec.rb
new file mode 100644
index 00000000000..030c2063ab2
--- /dev/null
+++ b/spec/lib/gitlab/sanitizers/svg_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+describe Gitlab::Sanitizers::SVG do
+ let(:scrubber) { Gitlab::Sanitizers::SVG::Scrubber.new }
+ let(:namespace) { double(Nokogiri::XML::Namespace, prefix: 'xlink', href: 'http://www.w3.org/1999/xlink') }
+ let(:namespaced_attr) { double(Nokogiri::XML::Attr, name: 'href', namespace: namespace, value: '#awesome_id') }
+
+ describe '.clean' do
+ let(:input_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'unsanitized.svg') }
+ let(:data) { open(input_svg_path).read }
+ let(:sanitized_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'sanitized.svg') }
+ let(:sanitized) { open(sanitized_svg_path).read }
+
+ it 'delegates sanitization to scrubber' do
+ expect_any_instance_of(Gitlab::Sanitizers::SVG::Scrubber).to receive(:scrub).at_least(:once)
+ described_class.clean(data)
+ end
+
+ it 'returns sanitized data' do
+ expect(described_class.clean(data)).to eq(sanitized)
+ end
+ end
+
+ context 'scrubber' do
+ describe '#scrub' do
+ let(:invalid_element) { double(Nokogiri::XML::Node, name: 'invalid', value: 'invalid') }
+ let(:invalid_attribute) { double(Nokogiri::XML::Attr, name: 'invalid', namespace: nil) }
+ let(:valid_element) { double(Nokogiri::XML::Node, name: 'use') }
+
+ it 'removes an invalid element' do
+ expect(invalid_element).to receive(:unlink)
+
+ scrubber.scrub(invalid_element)
+ end
+
+ it 'removes an invalid attribute' do
+ allow(valid_element).to receive(:attribute_nodes) { [invalid_attribute] }
+ expect(invalid_attribute).to receive(:unlink)
+
+ scrubber.scrub(valid_element)
+ end
+
+ it 'accepts valid element' do
+ allow(valid_element).to receive(:attribute_nodes) { [namespaced_attr] }
+ expect(valid_element).not_to receive(:unlink)
+
+ scrubber.scrub(valid_element)
+ end
+
+ it 'accepts valid namespaced attributes' do
+ allow(valid_element).to receive(:attribute_nodes) { [namespaced_attr] }
+ expect(namespaced_attr).not_to receive(:unlink)
+
+ scrubber.scrub(valid_element)
+ end
+ end
+
+ describe '#attribute_name_with_namespace' do
+ it 'returns name with prefix when attribute is namespaced' do
+ expect(scrubber.attribute_name_with_namespace(namespaced_attr)).to eq('xlink:href')
+ end
+ end
+
+ describe '#unsafe_href?' do
+ let(:unsafe_attr) { double(Nokogiri::XML::Attr, name: 'href', namespace: namespace, value: 'http://evilsite.example.com/random.svg') }
+
+ it 'returns true if href attribute is an external url' do
+ expect(scrubber.unsafe_href?(unsafe_attr)).to be_truthy
+ end
+
+ it 'returns false if href atttribute is an internal reference' do
+ expect(scrubber.unsafe_href?(namespaced_attr)).to be_falsey
+ end
+ end
+
+ describe '#data_attribute?' do
+ let(:data_attr) { double(Nokogiri::XML::Attr, name: 'data-gitlab', namespace: nil, value: 'gitlab is awesome') }
+ let(:namespaced_attr) { double(Nokogiri::XML::Attr, name: 'data-gitlab', namespace: namespace, value: 'gitlab is awesome') }
+ let(:other_attr) { double(Nokogiri::XML::Attr, name: 'something', namespace: nil, value: 'content') }
+
+ it 'returns true if is a valid data attribute' do
+ expect(scrubber.data_attribute?(data_attr)).to be_truthy
+ end
+
+ it 'returns false if attribute is namespaced' do
+ expect(scrubber.data_attribute?(namespaced_attr)).to be_falsey
+ end
+
+ it 'returns false if not a data attribute' do
+ expect(scrubber.data_attribute?(other_attr)).to be_falsey
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index d940bf05061..c5c1402e8fc 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -11,7 +11,7 @@ describe Gitlab::Workhorse, lib: true do
end
it "raises an error" do
- expect { subject.send_git_archive(project, "master", "zip") }.to raise_error(RuntimeError)
+ expect { subject.send_git_archive(project.repository, ref: "master", format: "zip") }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 7660ea2659c..2beb6cc598d 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -219,7 +219,7 @@ describe Ci::Build, models: true do
context 'and trigger variables' do
let(:trigger) { create(:ci_trigger, project: project) }
- let(:trigger_request) { create(:ci_trigger_request_with_variables, commit: pipeline, trigger: trigger) }
+ let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) }
let(:trigger_variables) do
[
{ key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index dd03d64f750..efbcbf72f76 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -10,6 +10,16 @@ describe Issue, "Issuable" do
it { is_expected.to belong_to(:assignee) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) }
+
+ context 'Notes' do
+ let!(:note) { create(:note, noteable: issue, project: issue.project) }
+ let(:scoped_issue) { Issue.includes(notes: :author).find(issue.id) }
+
+ it 'indicates if the notes have their authors loaded' do
+ expect(issue.notes).not_to be_authors_loaded
+ expect(scoped_issue.notes).to be_authors_loaded
+ end
+ end
end
describe 'Included modules' do
@@ -245,6 +255,22 @@ describe Issue, "Issuable" do
end
end
+ describe '#user_notes_count' do
+ let(:project) { create(:project) }
+ let(:issue1) { create(:issue, project: project) }
+ let(:issue2) { create(:issue, project: project) }
+
+ before do
+ create_list(:note, 3, noteable: issue1, project: project)
+ create_list(:note, 6, noteable: issue2, project: project)
+ end
+
+ it 'counts the user notes' do
+ expect(issue1.user_notes_count).to be(3)
+ expect(issue2.user_notes_count).to be(6)
+ end
+ end
+
describe "votes" do
let(:project) { issue.project }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 1b7cbc3efda..3b199f4d98d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -455,4 +455,157 @@ describe MergeRequest, models: true do
expect(user2.assigned_open_merge_request_count).to eq(1)
end
end
+
+ describe '#check_if_can_be_merged' do
+ let(:project) { create(:project, only_allow_merge_if_build_succeeds: true) }
+
+ subject { create(:merge_request, source_project: project, merge_status: :unchecked) }
+
+ context 'when it is not broken and has no conflicts' do
+ it 'is marked as mergeable' do
+ allow(subject).to receive(:broken?) { false }
+ allow(project).to receive_message_chain(:repository, :can_be_merged?) { true }
+
+ expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('can_be_merged')
+ end
+ end
+
+ context 'when broken' do
+ before { allow(subject).to receive(:broken?) { true } }
+
+ it 'becomes unmergeable' do
+ expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
+ end
+ end
+
+ context 'when it has conflicts' do
+ before do
+ allow(subject).to receive(:broken?) { false }
+ allow(project).to receive_message_chain(:repository, :can_be_merged?) { false }
+ end
+
+ it 'becomes unmergeable' do
+ expect { subject.check_if_can_be_merged }.to change { subject.merge_status }.to('cannot_be_merged')
+ end
+ end
+ end
+
+ describe '#mergeable?' do
+ let(:project) { create(:project) }
+
+ subject { create(:merge_request, source_project: project) }
+
+ it 'returns false if #mergeable_state? is false' do
+ expect(subject).to receive(:mergeable_state?) { false }
+
+ expect(subject.mergeable?).to be_falsey
+ end
+
+ it 'return true if #mergeable_state? is true and the MR #can_be_merged? is true' do
+ allow(subject).to receive(:mergeable_state?) { true }
+ expect(subject).to receive(:check_if_can_be_merged)
+ expect(subject).to receive(:can_be_merged?) { true }
+
+ expect(subject.mergeable?).to be_truthy
+ end
+ end
+
+ describe '#mergeable_state?' do
+ let(:project) { create(:project) }
+
+ subject { create(:merge_request, source_project: project) }
+
+ it 'checks if merge request can be merged' do
+ allow(subject).to receive(:mergeable_ci_state?) { true }
+ expect(subject).to receive(:check_if_can_be_merged)
+
+ subject.mergeable?
+ end
+
+ context 'when not open' do
+ before { subject.close }
+
+ it 'returns false' do
+ expect(subject.mergeable_state?).to be_falsey
+ end
+ end
+
+ context 'when working in progress' do
+ before { subject.title = 'WIP MR' }
+
+ it 'returns false' do
+ expect(subject.mergeable_state?).to be_falsey
+ end
+ end
+
+ context 'when broken' do
+ before { allow(subject).to receive(:broken?) { true } }
+
+ it 'returns false' do
+ expect(subject.mergeable_state?).to be_falsey
+ end
+ end
+
+ context 'when failed' do
+ before { allow(subject).to receive(:broken?) { false } }
+
+ context 'when project settings restrict to merge only if build succeeds and build failed' do
+ before do
+ project.only_allow_merge_if_build_succeeds = true
+ allow(subject).to receive(:mergeable_ci_state?) { false }
+ end
+
+ it 'returns false' do
+ expect(subject.mergeable_state?).to be_falsey
+ end
+ end
+ end
+ end
+
+ describe '#mergeable_ci_state?' do
+ let(:project) { create(:empty_project, only_allow_merge_if_build_succeeds: true) }
+ let(:pipeline) { create(:ci_empty_pipeline) }
+
+ subject { build(:merge_request, target_project: project) }
+
+ context 'when it is only allowed to merge when build is green' do
+ context 'and a failed pipeline is associated' do
+ before do
+ pipeline.statuses << create(:commit_status, status: 'failed', project: project)
+ allow(subject).to receive(:pipeline) { pipeline }
+ end
+
+ it { expect(subject.mergeable_ci_state?).to be_falsey }
+ end
+
+ context 'when no pipeline is associated' do
+ before do
+ allow(subject).to receive(:pipeline) { nil }
+ end
+
+ it { expect(subject.mergeable_ci_state?).to be_truthy }
+ end
+ end
+
+ context 'when merges are not restricted to green builds' do
+ subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_build_succeeds: false)) }
+
+ context 'and a failed pipeline is associated' do
+ before do
+ pipeline.statuses << create(:commit_status, status: 'failed', project: project)
+ allow(subject).to receive(:pipeline) { pipeline }
+ end
+
+ it { expect(subject.mergeable_ci_state?).to be_truthy }
+ end
+
+ context 'when no pipeline is associated' do
+ before do
+ allow(subject).to receive(:pipeline) { nil }
+ end
+
+ it { expect(subject.mergeable_ci_state?).to be_truthy }
+ end
+ end
+ end
end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 295081e9da1..4e24e89b008 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -10,7 +10,6 @@ RSpec.describe NotificationSetting, type: :model do
subject { NotificationSetting.new(source_id: 1, source_type: 'Project') }
it { is_expected.to validate_presence_of(:user) }
- it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:level) }
it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) }
end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index e771f35811e..ec81f05fc7a 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -194,7 +194,7 @@ describe BambooService, models: true do
def service(bamboo_url: 'http://gitlab.com')
described_class.create(
- project: build_stubbed(:empty_project),
+ project: create(:empty_project),
properties: {
bamboo_url: bamboo_url,
username: 'mic',
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index ad24b895170..24a708ca849 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -182,7 +182,7 @@ describe TeamcityService, models: true do
def service(teamcity_url: 'http://gitlab.com')
described_class.create(
- project: build_stubbed(:empty_project),
+ project: create(:empty_project),
properties: {
teamcity_url: teamcity_url,
username: 'mic',
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 553556ed326..f3590f72cfe 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -258,6 +258,69 @@ describe Project, models: true do
end
end
+ describe :external_issue_tracker do
+ let(:project) { create(:project) }
+ let(:ext_project) { create(:redmine_project) }
+
+ context 'on existing projects with no value for has_external_issue_tracker' do
+ before(:each) do
+ project.update_column(:has_external_issue_tracker, nil)
+ ext_project.update_column(:has_external_issue_tracker, nil)
+ end
+
+ it 'updates the has_external_issue_tracker boolean' do
+ expect do
+ project.external_issue_tracker
+ end.to change { project.reload.has_external_issue_tracker }.to(false)
+
+ expect do
+ ext_project.external_issue_tracker
+ end.to change { ext_project.reload.has_external_issue_tracker }.to(true)
+ end
+ end
+
+ it 'returns nil and does not query services when there is no external issue tracker' do
+ project.build_missing_services
+ project.reload
+
+ expect(project).not_to receive(:services)
+
+ expect(project.external_issue_tracker).to eq(nil)
+ end
+
+ it 'retrieves external_issue_tracker querying services and cache it when there is external issue tracker' do
+ ext_project.reload # Factory returns a project with changed attributes
+ ext_project.build_missing_services
+ ext_project.reload
+
+ expect(ext_project).to receive(:services).once.and_call_original
+
+ 2.times { expect(ext_project.external_issue_tracker).to be_a_kind_of(RedmineService) }
+ end
+ end
+
+ describe :cache_has_external_issue_tracker do
+ let(:project) { create(:project) }
+
+ it 'stores true if there is any external_issue_tracker' do
+ services = double(:service, external_issue_trackers: [RedmineService.new])
+ expect(project).to receive(:services).and_return(services)
+
+ expect do
+ project.cache_has_external_issue_tracker
+ end.to change { project.has_external_issue_tracker}.to(true)
+ end
+
+ it 'stores false if there is no external_issue_tracker' do
+ services = double(:service, external_issue_trackers: [])
+ expect(project).to receive(:services).and_return(services)
+
+ expect do
+ project.cache_has_external_issue_tracker
+ end.to change { project.has_external_issue_tracker}.to(false)
+ end
+ end
+
describe :can_have_issues_tracker_id? do
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
@@ -859,4 +922,37 @@ describe Project, models: true do
it { is_expected.to be_falsey }
end
end
+
+ describe '.where_paths_in' do
+ context 'without any paths' do
+ it 'returns an empty relation' do
+ expect(Project.where_paths_in([])).to eq([])
+ end
+ end
+
+ context 'without any valid paths' do
+ it 'returns an empty relation' do
+ expect(Project.where_paths_in(%w[foo])).to eq([])
+ end
+ end
+
+ context 'with valid paths' do
+ let!(:project1) { create(:project) }
+ let!(:project2) { create(:project) }
+
+ it 'returns the projects matching the paths' do
+ projects = Project.where_paths_in([project1.path_with_namespace,
+ project2.path_with_namespace])
+
+ expect(projects).to contain_exactly(project1, project2)
+ end
+
+ it 'returns projects regardless of the casing of paths' do
+ projects = Project.where_paths_in([project1.path_with_namespace.upcase,
+ project2.path_with_namespace.upcase])
+
+ expect(projects).to contain_exactly(project1, project2)
+ end
+ end
+ end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 8592e112c50..2f000dbc01a 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -204,4 +204,37 @@ describe Service, models: true do
expect(service.bamboo_url_was).to be_nil
end
end
+
+ describe "callbacks" do
+ let(:project) { create(:project) }
+ let!(:service) do
+ RedmineService.new(
+ project: project,
+ active: true,
+ properties: {
+ project_url: 'http://redmine/projects/project_name_in_redmine',
+ issues_url: "http://redmine/#{project.id}/project_name_in_redmine/:id",
+ new_issue_url: 'http://redmine/projects/project_name_in_redmine/issues/new'
+ }
+ )
+ end
+
+ describe "on create" do
+ it "updates the has_external_issue_tracker boolean" do
+ expect do
+ service.save!
+ end.to change { service.project.has_external_issue_tracker }.from(nil).to(true)
+ end
+ end
+
+ describe "on update" do
+ it "updates the has_external_issue_tracker boolean" do
+ service.save!
+
+ expect do
+ service.update_attributes(active: false)
+ end.to change { service.project.has_external_issue_tracker }.from(true).to(false)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 9da69a913a8..5896b93603f 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -419,6 +419,15 @@ describe API::API, api: true do
expect(json_response['message']).to eq('405 Method Not Allowed')
end
+ it 'returns 405 if the build failed for a merge request that requires success' do
+ allow_any_instance_of(MergeRequest).to receive(:mergeable_ci_state?).and_return(false)
+
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user)
+
+ expect(response.status).to eq(405)
+ expect(json_response['message']).to eq('405 Method Not Allowed')
+ end
+
it "should return 401 if user has no permissions to merge" do
user2 = create(:user)
project.team << [user2, :reporter]
@@ -554,6 +563,21 @@ describe API::API, api: true do
expect(json_response).to be_an Array
expect(json_response.length).to eq(0)
end
+
+ it 'handles external issues' do
+ jira_project = create(:jira_project, :public, name: 'JIR_EXT1')
+ issue = ExternalIssue.new("#{jira_project.name}-123", jira_project)
+ merge_request = create(:merge_request, :simple, author: user, assignee: user, source_project: jira_project)
+ merge_request.update_attribute(:description, "Closes #{issue.to_reference(jira_project)}")
+
+ get api("/projects/#{jira_project.id}/merge_requests/#{merge_request.id}/closes_issues", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['title']).to eq(issue.title)
+ expect(json_response.first['id']).to eq(issue.id)
+ end
end
describe 'POST :id/merge_requests/:merge_request_id/subscription' do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 88271642532..e8508f8f950 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -85,7 +85,7 @@ describe Ci::API::API do
trigger = FactoryGirl.create(:ci_trigger, project: project)
pipeline = FactoryGirl.create(:ci_pipeline, project: project, ref: 'master')
- trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: pipeline, trigger: trigger)
+ trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger)
pipeline.create_builds(nil, trigger_request)
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 594a60a4340..c44a4a7a1fc 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -2,7 +2,7 @@ require "spec_helper"
describe 'Git HTTP requests', lib: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, path: 'project.git-project') }
it "gives WWW-Authenticate hints" do
clone_get('doesnt/exist.git')
@@ -268,6 +268,87 @@ describe 'Git HTTP requests', lib: true do
end
end
+ context "when the project path doesn't end in .git" do
+ context "GET info/refs" do
+ let(:path) { "/#{project.path_with_namespace}/info/refs" }
+
+ context "when no params are added" do
+ before { get path }
+
+ it "redirects to the .git suffix version" do
+ expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs")
+ end
+ end
+
+ context "when the upload-pack service is requested" do
+ let(:params) { { service: 'git-upload-pack' } }
+ before { get path, params }
+
+ it "redirects to the .git suffix version" do
+ expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
+ end
+ end
+
+ context "when the receive-pack service is requested" do
+ let(:params) { { service: 'git-receive-pack' } }
+ before { get path, params }
+
+ it "redirects to the .git suffix version" do
+ expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}")
+ end
+ end
+
+ context "when the params are anything else" do
+ let(:params) { { service: 'git-implode-pack' } }
+ before { get path, params }
+
+ it "redirects to the sign-in page" do
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+
+ context "POST git-upload-pack" do
+ it "fails to find a route" do
+ expect { clone_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
+ end
+ end
+
+ context "POST git-receive-pack" do
+ it "failes to find a route" do
+ expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError)
+ end
+ end
+ end
+
+ context "retrieving an info/refs file" do
+ before { project.update_attribute(:visibility_level, Project::PUBLIC) }
+
+ context "when the file exists" do
+ before do
+ # Provide a dummy file in its place
+ allow_any_instance_of(Repository).to receive(:blob_at).and_call_original
+ allow_any_instance_of(Repository).to receive(:blob_at).with('5937ac0a7beb003549fc5fd26fc247adbce4a52e', 'info/refs') do
+ Gitlab::Git::Blob.find(project.repository, 'master', '.gitignore')
+ end
+
+ get "/#{project.path_with_namespace}/blob/master/info/refs"
+ end
+
+ it "returns the file" do
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context "when the file exists" do
+ before { get "/#{project.path_with_namespace}/blob/master/info/refs" }
+
+ it "returns not found" do
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
def clone_get(project, options={})
get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password))
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index cef5e0d8659..b99e02ba678 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -72,6 +72,7 @@ describe NotificationService, services: true do
should_not_email(@u_disabled)
should_not_email(@unsubscriber)
should_not_email(@u_outsider_mentioned)
+ should_not_email(@u_lazy_participant)
end
it 'filters out "mentioned in" notes' do
@@ -80,6 +81,20 @@ describe NotificationService, services: true do
expect(Notify).not_to receive(:note_issue_email)
notification.new_note(mentioned_note)
end
+
+ context 'participating' do
+ context 'by note' do
+ before do
+ ActionMailer::Base.deliveries.clear
+ note.author = @u_lazy_participant
+ note.save
+ notification.new_note(note)
+ end
+
+
+ it { should_not_email(@u_lazy_participant) }
+ end
+ end
end
describe 'new note on issue in project that belongs to a group' do
@@ -106,6 +121,7 @@ describe NotificationService, services: true do
should_not_email(note.author)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
end
end
@@ -235,6 +251,7 @@ describe NotificationService, services: true do
should_not_email(note.author)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it do
@@ -248,10 +265,11 @@ describe NotificationService, services: true do
should_not_email(note.author)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it do
- @u_committer.update_attributes(notification_level: :mention)
+ @u_committer = create_global_setting_for(@u_committer, :mention)
notification.new_note(note)
should_not_email(@u_committer)
end
@@ -280,10 +298,11 @@ describe NotificationService, services: true do
should_not_email(@u_mentioned)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it do
- issue.assignee.update_attributes(notification_level: :mention)
+ create_global_setting_for(issue.assignee, :mention)
notification.new_issue(issue, @u_disabled)
should_not_email(issue.assignee)
@@ -341,6 +360,7 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it 'emails previous assignee even if he has the "on mention" notif level' do
@@ -356,6 +376,7 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it 'emails new assignee even if he has the "on mention" notif level' do
@@ -371,6 +392,7 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it 'emails new assignee' do
@@ -386,6 +408,7 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it 'does not email new assignee if they are the current user' do
@@ -401,6 +424,35 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ issue.update_attribute(:assignee, @u_lazy_participant)
+ notification.reassigned_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.reassigned_issue(issue, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ issue.author = @u_lazy_participant
+ notification.reassigned_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
@@ -479,6 +531,35 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ issue.update_attribute(:assignee, @u_lazy_participant)
+ notification.close_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.close_issue(issue, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ issue.author = @u_lazy_participant
+ notification.close_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
@@ -495,6 +576,35 @@ describe NotificationService, services: true do
should_email(@watcher_and_subscriber)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ issue.update_attribute(:assignee, @u_lazy_participant)
+ notification.reopen_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.reopen_issue(issue, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ issue.author = @u_lazy_participant
+ notification.reopen_issue(issue, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
end
@@ -520,6 +630,7 @@ describe NotificationService, services: true do
should_email(@u_guest_watcher)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
end
it "emails subscribers of the merge request's labels" do
@@ -530,6 +641,36 @@ describe NotificationService, services: true do
should_email(subscriber)
end
+
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ merge_request.update_attribute(:assignee, @u_lazy_participant)
+ notification.new_merge_request(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.new_merge_request(merge_request, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ merge_request.author = @u_lazy_participant
+ merge_request.save
+ notification.new_merge_request(merge_request, @u_disabled)
+ end
+
+ it { should_not_email(@u_lazy_participant) }
+ end
+ end
end
describe '#reassigned_merge_request' do
@@ -545,6 +686,36 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ merge_request.update_attribute(:assignee, @u_lazy_participant)
+ notification.reassigned_merge_request(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.reassigned_merge_request(merge_request, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ merge_request.author = @u_lazy_participant
+ merge_request.save
+ notification.reassigned_merge_request(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
@@ -572,6 +743,7 @@ describe NotificationService, services: true do
should_not_email(@watcher_and_subscriber)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
+ should_not_email(@u_lazy_participant)
should_not_email(subscriber_to_label)
should_email(subscriber_to_label2)
end
@@ -590,6 +762,36 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ merge_request.update_attribute(:assignee, @u_lazy_participant)
+ notification.close_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.close_mr(merge_request, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ merge_request.author = @u_lazy_participant
+ merge_request.save
+ notification.close_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
@@ -606,6 +808,36 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ merge_request.update_attribute(:assignee, @u_lazy_participant)
+ notification.merge_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.merge_mr(merge_request, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ merge_request.author = @u_lazy_participant
+ merge_request.save
+ notification.merge_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
@@ -622,6 +854,36 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ context 'participating' do
+ context 'by assignee' do
+ before do
+ merge_request.update_attribute(:assignee, @u_lazy_participant)
+ notification.reopen_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by note' do
+ let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) }
+
+ before { notification.reopen_mr(merge_request, @u_disabled) }
+
+ it { should_email(@u_lazy_participant) }
+ end
+
+ context 'by author' do
+ before do
+ merge_request.author = @u_lazy_participant
+ merge_request.save
+ notification.reopen_mr(merge_request, @u_disabled)
+ end
+
+ it { should_email(@u_lazy_participant) }
+ end
end
end
end
@@ -640,6 +902,7 @@ describe NotificationService, services: true do
should_email(@u_watcher)
should_email(@u_participating)
+ should_email(@u_lazy_participant)
should_not_email(@u_guest_watcher)
should_not_email(@u_disabled)
end
@@ -647,14 +910,19 @@ describe NotificationService, services: true do
end
def build_team(project)
- @u_watcher = create(:user, notification_level: :watch)
- @u_participating = create(:user, notification_level: :participating)
- @u_participant_mentioned = create(:user, username: 'participant', notification_level: :participating)
- @u_disabled = create(:user, notification_level: :disabled)
- @u_mentioned = create(:user, username: 'mention', notification_level: :mention)
- @u_committer = create(:user, username: 'committer')
- @u_not_mentioned = create(:user, username: 'regular', notification_level: :participating)
- @u_outsider_mentioned = create(:user, username: 'outsider')
+ @u_watcher = create_global_setting_for(create(:user), :watch)
+ @u_participating = create_global_setting_for(create(:user), :participating)
+ @u_participant_mentioned = create_global_setting_for(create(:user, username: 'participant'), :participating)
+ @u_disabled = create_global_setting_for(create(:user), :disabled)
+ @u_mentioned = create_global_setting_for(create(:user, username: 'mention'), :mention)
+ @u_committer = create(:user, username: 'committer')
+ @u_not_mentioned = create_global_setting_for(create(:user, username: 'regular'), :participating)
+ @u_outsider_mentioned = create(:user, username: 'outsider')
+
+ # User to be participant by default
+ # This user does not contain any record in notification settings table
+ # It should be treated with a :participating notification_level
+ @u_lazy_participant = create(:user, username: 'lazy-participant')
create_guest_watcher
@@ -665,6 +933,15 @@ describe NotificationService, services: true do
project.team << [@u_mentioned, :master]
project.team << [@u_committer, :master]
project.team << [@u_not_mentioned, :master]
+ project.team << [@u_lazy_participant, :master]
+ end
+
+ def create_global_setting_for(user, level)
+ setting = user.global_notification_setting
+ setting.level = level
+ setting.save
+
+ user
end
def create_guest_watcher
@@ -677,8 +954,8 @@ describe NotificationService, services: true do
def add_users_with_subscription(project, issuable)
@subscriber = create :user
@unsubscriber = create :user
- @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: :participating)
- @watcher_and_subscriber = create(:user, notification_level: :watch)
+ @subscribed_participant = create_global_setting_for(create(:user, username: 'subscribed_participant'), :participating)
+ @watcher_and_subscriber = create_global_setting_for(create(:user), :watch)
project.team << [@subscribed_participant, :master]
project.team << [@subscriber, :master]
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index 9d90bfceb73..068c9a1219c 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -124,7 +124,7 @@ describe Projects::ImportService, services: true do
}
)
- Gitlab.config.omniauth.providers << provider
+ allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
end
end
end
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 6e7ecbd39ba..489c920f19f 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -18,7 +18,7 @@ describe TodoService, services: true do
end
describe 'Issues' do
- let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: mentions) }
+ let(:issue) { create(:issue, project: project, assignee: john_doe, author: author, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:unassigned_issue) { create(:issue, project: project, assignee: nil) }
let(:confidential_issue) { create(:issue, :confidential, project: project, author: author, assignee: assignee, description: mentions) }
@@ -101,6 +101,19 @@ describe TodoService, services: true do
should_create_todo(user: admin, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
should_not_create_todo(user: john_doe, target: confidential_issue, author: john_doe, action: Todo::MENTIONED)
end
+
+ it 'does not create todo when when tasks are marked as completed' do
+ issue.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
+
+ service.update_issue(issue, author)
+
+ should_not_create_todo(user: admin, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: assignee, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: author, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: john_doe, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: member, target: issue, action: Todo::MENTIONED)
+ should_not_create_todo(user: non_member, target: issue, action: Todo::MENTIONED)
+ end
end
describe '#close_issue' do
@@ -210,7 +223,7 @@ describe TodoService, services: true do
end
describe 'Merge Requests' do
- let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: mentions) }
+ let(:mr_assigned) { create(:merge_request, source_project: project, author: author, assignee: john_doe, description: "- [ ] Task 1\n- [ ] Task 2 #{mentions}") }
let(:mr_unassigned) { create(:merge_request, source_project: project, author: author, assignee: nil) }
describe '#new_merge_request' do
@@ -253,6 +266,19 @@ describe TodoService, services: true do
expect { service.update_merge_request(mr_assigned, author) }.not_to change(member.todos, :count)
end
+
+ it 'does not create todo when when tasks are marked as completed' do
+ mr_assigned.update(description: "- [x] Task 1\n- [X] Task 2 #{mentions}")
+
+ service.update_merge_request(mr_assigned, author)
+
+ should_not_create_todo(user: admin, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: assignee, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: author, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: john_doe, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: member, target: mr_assigned, action: Todo::MENTIONED)
+ should_not_create_todo(user: non_member, target: mr_assigned, action: Todo::MENTIONED)
+ end
end
describe '#close_merge_request' do
diff --git a/spec/controllers/import/import_spec_helper.rb b/spec/support/import_spec_helper.rb
index 9d7648e25a7..6710962f082 100644
--- a/spec/controllers/import/import_spec_helper.rb
+++ b/spec/support/import_spec_helper.rb
@@ -28,6 +28,6 @@ module ImportSpecHelper
app_id: 'asd123',
app_secret: 'asd123'
)
- Gitlab.config.omniauth.providers << provider
+ allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
end
end
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index 7fc6d6fcc5e..a79386b5db9 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -32,6 +32,10 @@ class MarkdownFeature
@project_wiki ||= ProjectWiki.new(project, user)
end
+ def project_wiki_page
+ @project_wiki_page ||= build(:wiki_page, wiki: project_wiki)
+ end
+
def issue
@issue ||= create(:issue, project: project)
end