summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorJacob Vosmaer <contact@jacobvosmaer.nl>2016-04-15 11:07:25 +0200
committerJacob Vosmaer <contact@jacobvosmaer.nl>2016-04-15 11:07:25 +0200
commit2a9a9e147b8ccfbc974e9817d69c6a28c484772f (patch)
tree6a732ae82f856ac71e238729fdd6f383a06c36dd /spec
parenta1c8fdfbeef5a74dfdf86f1e7954a7a8eb8577eb (diff)
parentc795ef079cde695080ef34444899b77127db6075 (diff)
downloadgitlab-ce-2a9a9e147b8ccfbc974e9817d69c6a28c484772f.tar.gz
Merge branch 'master' of https://gitlab.com/gitlab-org/gitlab-ce into git-http-controller
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/groups/notification_settings_controller_spec.rb32
-rw-r--r--spec/controllers/profiles/keys_controller_spec.rb12
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb28
-rw-r--r--spec/controllers/projects/notification_settings_controller_spec.rb38
-rw-r--r--spec/factories/commits.rb12
-rw-r--r--spec/factories/oauth_access_tokens.rb22
-rw-r--r--spec/factories/oauth_applications.rb9
-rw-r--r--spec/factories/users.rb2
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb43
-rw-r--r--spec/features/issues/filter_issues_spec.rb31
-rw-r--r--spec/features/issues_spec.rb16
-rw-r--r--spec/features/merge_requests/edit_mr_spec.rb21
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb25
-rw-r--r--spec/features/profiles/oauth_applications_spec.rb39
-rw-r--r--spec/features/projects_spec.rb3
-rw-r--r--spec/features/search_spec.rb4
-rw-r--r--spec/helpers/notifications_helper_spec.rb37
-rw-r--r--spec/javascripts/fixtures/project_title.html.haml27
-rw-r--r--spec/javascripts/notes_spec.js.coffee1
-rw-r--r--spec/javascripts/project_title_spec.js.coffee20
-rw-r--r--spec/lib/award_emoji_spec.rb7
-rw-r--r--spec/lib/gitlab/metrics_spec.rb25
-rw-r--r--spec/lib/gitlab/note_data_builder_spec.rb3
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb37
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb143
-rw-r--r--spec/lib/gitlab_spec.rb17
-rw-r--r--spec/mailers/repository_check_mailer_spec.rb21
-rw-r--r--spec/models/issue_spec.rb17
-rw-r--r--spec/models/notification_setting_spec.rb17
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb262
-rw-r--r--spec/models/project_services/builds_email_service_spec.rb37
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb251
-rw-r--r--spec/models/repository_spec.rb8
-rw-r--r--spec/requests/api/group_members_spec.rb12
-rw-r--r--spec/requests/api/groups_spec.rb57
-rw-r--r--spec/requests/api/issues_spec.rb133
-rw-r--r--spec/requests/api/merge_requests_spec.rb42
-rw-r--r--spec/requests/api/notes_spec.rb13
-rw-r--r--spec/requests/api/projects_spec.rb48
-rw-r--r--spec/services/notification_service_spec.rb29
-rw-r--r--spec/services/projects/transfer_service_spec.rb23
-rw-r--r--spec/workers/post_receive_spec.rb43
-rw-r--r--spec/workers/repository_check/batch_worker_spec.rb39
-rw-r--r--spec/workers/repository_check/clear_worker_spec.rb17
44 files changed, 1456 insertions, 267 deletions
diff --git a/spec/controllers/groups/notification_settings_controller_spec.rb b/spec/controllers/groups/notification_settings_controller_spec.rb
new file mode 100644
index 00000000000..0786e45515a
--- /dev/null
+++ b/spec/controllers/groups/notification_settings_controller_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Groups::NotificationSettingsController do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
+ describe '#update' do
+ context 'when not authorized' do
+ it 'redirects to sign in page' do
+ put :update,
+ group_id: group.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ put :update,
+ group_id: group.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response.status).to eq 200
+ end
+ end
+ end
+end
diff --git a/spec/controllers/profiles/keys_controller_spec.rb b/spec/controllers/profiles/keys_controller_spec.rb
index b6573f105dc..3a82083717f 100644
--- a/spec/controllers/profiles/keys_controller_spec.rb
+++ b/spec/controllers/profiles/keys_controller_spec.rb
@@ -1,7 +1,17 @@
require 'spec_helper'
describe Profiles::KeysController do
- let(:user) { create(:user) }
+ let(:user) { create(:user) }
+
+ describe '#new' do
+ before { sign_in(user) }
+
+ it 'redirect to #index' do
+ get :new
+
+ expect(response).to redirect_to(profile_keys_path)
+ end
+ end
describe "#get_keys" do
describe "non existant user" do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 75e6b6f45a7..c54e83339a1 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -157,6 +157,34 @@ describe Projects::MergeRequestsController do
end
end
+ describe 'PUT #update' do
+ context 'there is no source project' do
+ let(:project) { create(:project) }
+ let(:fork_project) { create(:forked_project_with_submodules) }
+ let(:merge_request) { create(:merge_request, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) }
+
+ before do
+ fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
+ fork_project.save
+ merge_request.reload
+ fork_project.destroy
+ end
+
+ it 'closes MR without errors' do
+ post :update,
+ namespace_id: project.namespace.path,
+ project_id: project.path,
+ id: merge_request.iid,
+ merge_request: {
+ state_event: 'close'
+ }
+
+ expect(response).to redirect_to([merge_request.target_project.namespace.becomes(Namespace), merge_request.target_project, merge_request])
+ expect(merge_request.reload.closed?).to be_truthy
+ end
+ end
+ end
+
describe "DELETE #destroy" do
it "denies access to users unless they're admin or project owner" do
delete :destroy, namespace_id: project.namespace.path, project_id: project.path, id: merge_request.iid
diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb
new file mode 100644
index 00000000000..4908b545648
--- /dev/null
+++ b/spec/controllers/projects/notification_settings_controller_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe Projects::NotificationSettingsController do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ describe '#update' do
+ context 'when not authorized' do
+ it 'redirects to sign in page' do
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'when authorized' do
+ before do
+ sign_in(user)
+ end
+
+ it 'returns success' do
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response.status).to eq 200
+ end
+ end
+ end
+end
diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb
new file mode 100644
index 00000000000..ac6eb0a7897
--- /dev/null
+++ b/spec/factories/commits.rb
@@ -0,0 +1,12 @@
+require_relative '../support/repo_helpers'
+
+FactoryGirl.define do
+ factory :commit do
+ git_commit RepoHelpers.sample_commit
+ project factory: :empty_project
+
+ initialize_with do
+ new(git_commit, project)
+ end
+ end
+end
diff --git a/spec/factories/oauth_access_tokens.rb b/spec/factories/oauth_access_tokens.rb
new file mode 100644
index 00000000000..7700b15d538
--- /dev/null
+++ b/spec/factories/oauth_access_tokens.rb
@@ -0,0 +1,22 @@
+# == Schema Information
+#
+# Table name: oauth_access_tokens
+#
+# id :integer not null, primary key
+# resource_owner_id :integer
+# application_id :integer
+# token :string not null
+# refresh_token :string
+# expires_in :integer
+# revoked_at :datetime
+# created_at :datetime not null
+# scopes :string
+#
+
+FactoryGirl.define do
+ factory :oauth_access_token do
+ resource_owner
+ application
+ token '123456'
+ end
+end
diff --git a/spec/factories/oauth_applications.rb b/spec/factories/oauth_applications.rb
new file mode 100644
index 00000000000..d116a573830
--- /dev/null
+++ b/spec/factories/oauth_applications.rb
@@ -0,0 +1,9 @@
+FactoryGirl.define do
+ factory :oauth_application, class: 'Doorkeeper::Application', aliases: [:application] do
+ name { FFaker::Name.name }
+ uid { FFaker::Name.name }
+ redirect_uri { FFaker::Internet.uri('http') }
+ owner
+ owner_type 'User'
+ end
+end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index a5c60c51c5b..a9b2148bd2a 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -1,7 +1,7 @@
FactoryGirl.define do
sequence(:name) { FFaker::Name.name }
- factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator] do
+ factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator, :resource_owner] do
email { FFaker::Internet.email }
name
sequence(:username) { |n| "#{FFaker::Internet.user_name}#{n}" }
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
new file mode 100644
index 00000000000..661fb761809
--- /dev/null
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -0,0 +1,43 @@
+require 'rails_helper'
+
+feature 'Admin uses repository checks', feature: true do
+ before { login_as :admin }
+
+ scenario 'to trigger a single check' do
+ project = create(:empty_project)
+ visit_admin_project_page(project)
+
+ page.within('.repository-check') do
+ click_button 'Trigger repository check'
+ end
+
+ expect(page).to have_content('Repository check was triggered')
+ end
+
+ scenario 'to see a single failed repository check' do
+ project = create(:empty_project)
+ project.update_columns(
+ last_repository_check_failed: true,
+ last_repository_check_at: Time.now,
+ )
+ visit_admin_project_page(project)
+
+ page.within('.alert') do
+ expect(page.text).to match(/Last repository check \(.* ago\) failed/)
+ end
+ end
+
+ scenario 'to clear all repository checks', js: true do
+ visit admin_application_settings_path
+
+ expect(RepositoryCheck::ClearWorker).to receive(:perform_async)
+
+ click_link 'Clear all repository checks'
+
+ expect(page).to have_content('Started asynchronous removal of all repository check states.')
+ end
+
+ def visit_admin_project_page(project)
+ visit admin_namespace_project_path(project.namespace, project)
+ end
+end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 90822a8c123..69b22232f10 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -76,6 +76,37 @@ describe 'Filter issues', feature: true do
end
end
+ describe 'Filter issues for label from issues#index', js: true do
+ before do
+ visit namespace_project_issues_path(project.namespace, project)
+ find('.js-label-select').click
+ end
+
+ it 'should filter by any label' do
+ find('.dropdown-menu-labels a', text: 'Any Label').click
+ page.within '.labels-filter' do
+ expect(page).to have_content 'Any Label'
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content('Label')
+ end
+
+ it 'should filter by no label' do
+ find('.dropdown-menu-labels a', text: 'No Label').click
+ page.within '.labels-filter' do
+ expect(page).to have_content 'No Label'
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content('No Label')
+ end
+
+ it 'should filter by no label' do
+ find('.dropdown-menu-labels a', text: label.title).click
+ page.within '.labels-filter' do
+ expect(page).to have_content label.title
+ end
+ expect(find('.js-label-select .dropdown-toggle-text')).to have_content(label.title)
+ end
+ end
+
describe 'Filter issues for assignee and label from issues#index' do
before do
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 79000666ccc..1ce0024e93c 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -45,7 +45,7 @@ describe 'Issues', feature: true do
project: project)
end
- it 'allows user to select unasigned', js: true do
+ it 'allows user to select unassigned', js: true do
visit edit_namespace_project_issue_path(project.namespace, project, issue)
expect(page).to have_content "Assignee #{@user.name}"
@@ -64,6 +64,18 @@ describe 'Issues', feature: true do
end
end
+ describe 'Issue info' do
+ it 'excludes award_emoji from comment count' do
+ issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
+ create(:upvote_note, noteable: issue)
+
+ visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)
+
+ expect(page).to have_content 'foobar'
+ expect(page.all('.issue-no-comments').first.text).to eq "0"
+ end
+ end
+
describe 'Filter issue' do
before do
['foobar', 'barbaz', 'gitlab'].each do |title|
@@ -187,7 +199,7 @@ describe 'Issues', feature: true do
describe 'update assignee from issue#show' do
let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
- context 'by autorized user' do
+ context 'by authorized user' do
it 'allows user to select unassigned', js: true do
visit namespace_project_issue_path(project.namespace, project, issue)
diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb
new file mode 100644
index 00000000000..9e007ab7635
--- /dev/null
+++ b/spec/features/merge_requests/edit_mr_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+feature 'Edit Merge Request', feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, :with_diffs, source_project: project) }
+
+ before do
+ project.team << [user, :master]
+
+ login_as user
+
+ visit edit_namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ context 'editing a MR' do
+ it 'form should have class js-quick-submit' do
+ expect(page).to have_selector('.js-quick-submit')
+ end
+ end
+end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 5f855ccc701..389812ff7e1 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -4,6 +4,20 @@ describe 'Comments', feature: true do
include RepoHelpers
include WaitForAjax
+ describe 'On merge requests page', feature: true do
+ it 'excludes award_emoji from comment count' do
+ merge_request = create(:merge_request)
+ project = merge_request.source_project
+ create(:upvote_note, noteable: merge_request, project: project)
+
+ login_as :admin
+ visit namespace_project_merge_requests_path(project.namespace, project)
+
+ expect(merge_request.mr_and_commit_notes.count).to eq 1
+ expect(page.all('.merge-request-no-comments').first.text).to eq "0"
+ end
+ end
+
describe 'On a merge request', js: true, feature: true do
let!(:merge_request) { create(:merge_request) }
let!(:project) { merge_request.source_project }
@@ -129,6 +143,17 @@ describe 'Comments', feature: true do
end
end
end
+
+ describe 'comment info' do
+ it 'excludes award_emoji from comment count' do
+ create(:upvote_note, noteable: merge_request, project: project)
+
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+
+ expect(merge_request.mr_and_commit_notes.count).to eq 2
+ expect(find('.notes-tab span.badge').text).to eq "1"
+ end
+ end
end
describe 'On a merge request diff', js: true, feature: true do
diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb
new file mode 100644
index 00000000000..1a5a9059dbd
--- /dev/null
+++ b/spec/features/profiles/oauth_applications_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'Profile > Applications', feature: true do
+ let(:user) { create(:user) }
+
+ before do
+ login_as(user)
+ end
+
+ describe 'User manages applications', js: true do
+ it 'deletes an application' do
+ create(:oauth_application, owner: user)
+ visit oauth_applications_path
+
+ page.within('.oauth-applications') do
+ expect(page).to have_content('Your applications (1)')
+ click_button 'Destroy'
+ end
+
+ expect(page).to have_content('The application was deleted successfully')
+ expect(page).to have_content('Your applications (0)')
+ expect(page).to have_content('Authorized applications (0)')
+ end
+
+ it 'deletes an authorized application' do
+ create(:oauth_access_token, resource_owner: user)
+ visit oauth_applications_path
+
+ page.within('.oauth-authorized-applications') do
+ expect(page).to have_content('Authorized applications (1)')
+ click_button 'Revoke'
+ end
+
+ expect(page).to have_content('The application was revoked access.')
+ expect(page).to have_content('Your applications (0)')
+ expect(page).to have_content('Authorized applications (0)')
+ end
+ end
+end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index ed97b6cb577..782c0bfe666 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -100,8 +100,7 @@ feature 'Project', feature: true do
it 'click toggle and show dropdown', js: true do
find('.js-projects-dropdown-toggle').click
- wait_for_ajax
- expect(page).to have_css('.select2-results li', count: 1)
+ expect(page).to have_css('.dropdown-menu-projects .dropdown-content li', count: 1)
end
end
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index 3e6289a46b1..029a11ea43c 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -10,6 +10,10 @@ describe "Search", feature: true do
visit search_path
end
+ it 'top right search form is not present' do
+ expect(page).not_to have_selector('.search')
+ end
+
describe 'searching for Projects' do
it 'finds a project' do
page.within '.search-holder' do
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
index f1aba4cfdf3..9d5f009ebe1 100644
--- a/spec/helpers/notifications_helper_spec.rb
+++ b/spec/helpers/notifications_helper_spec.rb
@@ -2,34 +2,15 @@ require 'spec_helper'
describe NotificationsHelper do
describe 'notification_icon' do
- let(:notification) { double(disabled?: false, participating?: false, watch?: false) }
-
- context "disabled notification" do
- before { allow(notification).to receive(:disabled?).and_return(true) }
-
- it "has a red icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-off ns-mute"')
- end
- end
-
- context "participating notification" do
- before { allow(notification).to receive(:participating?).and_return(true) }
-
- it "has a blue icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-down ns-part"')
- end
- end
-
- context "watched notification" do
- before { allow(notification).to receive(:watch?).and_return(true) }
-
- it "has a green icon" do
- expect(notification_icon(notification)).to match('class="fa fa-volume-up ns-watch"')
- end
- end
+ it { expect(notification_icon(:disabled)).to match('class="fa fa-microphone-slash fa-fw"') }
+ it { expect(notification_icon(:participating)).to match('class="fa fa-volume-up fa-fw"') }
+ it { expect(notification_icon(:mention)).to match('class="fa fa-at fa-fw"') }
+ it { expect(notification_icon(:global)).to match('class="fa fa-globe fa-fw"') }
+ it { expect(notification_icon(:watch)).to match('class="fa fa-eye fa-fw"') }
+ end
- it "has a blue icon" do
- expect(notification_icon(notification)).to match('class="fa fa-circle-o ns-default"')
- end
+ describe 'notification_title' do
+ it { expect(notification_title(:watch)).to match('Watch') }
+ it { expect(notification_title(:mention)).to match('On mention') }
end
end
diff --git a/spec/javascripts/fixtures/project_title.html.haml b/spec/javascripts/fixtures/project_title.html.haml
index e5850b62659..4547feeb212 100644
--- a/spec/javascripts/fixtures/project_title.html.haml
+++ b/spec/javascripts/fixtures/project_title.html.haml
@@ -1,7 +1,20 @@
-%h1.title
- %a
- GitLab Org
- %a.project-item-select-holder{href: "/gitlab-org/gitlab-test"}
- GitLab Test
- %input#project_path.project-item-select.js-projects-dropdown.ajax-project-select{type: "hidden", name: "project_path", "data-include-groups" => "false"}
- %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle
+.header-content
+ %h1.title
+ %a
+ GitLab Org
+ %a.project-item-select-holder{href: "/gitlab-org/gitlab-test"}
+ GitLab Test
+ %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle{ "data-toggle" => "dropdown", "data-target" => ".header-content" }
+ .js-dropdown-menu-projects
+ .dropdown-menu.dropdown-select.dropdown-menu-projects
+ .dropdown-title
+ %span Go to a project
+ %button.dropdown-title-button.dropdown-menu-close{"aria-label" => "Close", type: "button"}
+ %i.fa.fa-times.dropdown-menu-close-icon
+ .dropdown-input
+ %input.dropdown-input-field{id: "", placeholder: "Search your projects", type: "search", value: ""}
+ %i.fa.fa-search.dropdown-input-search
+ %i.fa.fa-times.dropdown-input-clear.js-dropdown-input-clear{role: "button"}
+ .dropdown-content
+ .dropdown-loading
+ %i.fa.fa-spinner.fa-spin
diff --git a/spec/javascripts/notes_spec.js.coffee b/spec/javascripts/notes_spec.js.coffee
index 050b6e362c6..dd160e821b3 100644
--- a/spec/javascripts/notes_spec.js.coffee
+++ b/spec/javascripts/notes_spec.js.coffee
@@ -1,4 +1,5 @@
#= require notes
+#= require gl_form
window.gon = {}
window.disableButtonIfEmptyField = -> null
diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee
index 47c7b7febe3..3d8de2ff989 100644
--- a/spec/javascripts/project_title_spec.js.coffee
+++ b/spec/javascripts/project_title_spec.js.coffee
@@ -1,4 +1,6 @@
+#= require bootstrap
#= require select2
+#= require gl_dropdown
#= require api
#= require project_select
#= require project
@@ -14,9 +16,6 @@ describe 'Project Title', ->
fixture.load('project_title.html')
@project = new Project()
- spyOn(@project, 'changeProject').and.callFake (url) ->
- window.current_project_url = url
-
describe 'project list', ->
beforeEach =>
@projects_data = fixture.load('projects.json')[0]
@@ -29,18 +28,9 @@ describe 'Project Title', ->
it 'to show on toggle click', =>
$('.js-projects-dropdown-toggle').click()
-
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(true)
- expect($('.ajax-project-dropdown li').length).toBe(@projects_data.length)
+ expect($('.header-content').hasClass('open')).toBe(true)
it 'hide dropdown', ->
- $("#select2-drop-mask").click()
-
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false)
-
- it 'change project when clicking item', ->
- $('.js-projects-dropdown-toggle').click()
- $('.ajax-project-dropdown li:nth-child(2)').trigger('mouseup')
+ $(".dropdown-menu-close-icon").click()
- expect($('.title .select2-container').hasClass('select2-dropdown-open')).toBe(false)
- expect(window.current_project_url).toBe('http://localhost:3000/h5bp/html5-boilerplate')
+ expect($('.header-content').hasClass('open')).toBe(false)
diff --git a/spec/lib/award_emoji_spec.rb b/spec/lib/award_emoji_spec.rb
index 330678f7f16..88c22912950 100644
--- a/spec/lib/award_emoji_spec.rb
+++ b/spec/lib/award_emoji_spec.rb
@@ -16,4 +16,11 @@ describe AwardEmoji do
end
end
end
+
+ describe '.emoji_by_category' do
+ it "only contains known categories" do
+ undefined_categories = AwardEmoji.emoji_by_category.keys - AwardEmoji::CATEGORIES.keys
+ expect(undefined_categories).to be_empty
+ end
+ end
end
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index 3dee13e27f4..10177c0e8dd 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -98,4 +98,29 @@ describe Gitlab::Metrics do
end
end
end
+
+ describe '.tag_transaction' do
+ context 'without a transaction' do
+ it 'does nothing' do
+ expect_any_instance_of(Gitlab::Metrics::Transaction).
+ not_to receive(:add_tag)
+
+ Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ end
+ end
+
+ context 'with a transaction' do
+ let(:transaction) { Gitlab::Metrics::Transaction.new }
+
+ it 'adds the tag to the transaction' do
+ expect(Gitlab::Metrics).to receive(:current_transaction).
+ and_return(transaction)
+
+ expect(transaction).to receive(:add_tag).
+ with(:foo, 'bar')
+
+ Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/note_data_builder_spec.rb b/spec/lib/gitlab/note_data_builder_spec.rb
index da652677443..f093d0a0d8b 100644
--- a/spec/lib/gitlab/note_data_builder_spec.rb
+++ b/spec/lib/gitlab/note_data_builder_spec.rb
@@ -4,13 +4,12 @@ describe 'Gitlab::NoteDataBuilder', lib: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:data) { Gitlab::NoteDataBuilder.build(note, user) }
- let(:note_url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors
before(:each) do
expect(data).to have_key(:object_attributes)
expect(data[:object_attributes]).to have_key(:url)
- expect(data[:object_attributes][:url]).to eq(note_url)
+ expect(data[:object_attributes][:url]).to eq(Gitlab::UrlBuilder.build(note))
expect(data[:object_kind]).to eq('note')
expect(data[:user]).to eq(user.hook_attrs)
end
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 3a769acfdc0..6727a83e58a 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -15,20 +15,20 @@ describe Gitlab::OAuth::User, lib: true do
end
let(:ldap_user) { Gitlab::LDAP::Person.new(Net::LDAP::Entry.new, 'ldapmain') }
- describe :persisted? do
+ describe '#persisted?' do
let!(:existing_user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'my-provider') }
it "finds an existing user based on uid and provider (facebook)" do
expect( oauth_user.persisted? ).to be_truthy
end
- it "returns false if use is not found in database" do
+ it 'returns false if user is not found in database' do
allow(auth_hash).to receive(:uid).and_return('non-existing')
expect( oauth_user.persisted? ).to be_falsey
end
end
- describe :save do
+ describe '#save' do
def stub_omniauth_config(messages)
allow(Gitlab.config.omniauth).to receive_messages(messages)
end
@@ -40,8 +40,27 @@ describe Gitlab::OAuth::User, lib: true do
let(:provider) { 'twitter' }
describe 'signup' do
- shared_examples "to verify compliance with allow_single_sign_on" do
- context "with new allow_single_sign_on enabled syntax" do
+ shared_examples 'to verify compliance with allow_single_sign_on' do
+ context 'provider is marked as external' do
+ it 'should mark user as external' do
+ stub_omniauth_config(allow_single_sign_on: ['twitter'], external_providers: ['twitter'])
+ oauth_user.save
+ expect(gl_user).to be_valid
+ expect(gl_user.external).to be_truthy
+ end
+ end
+
+ context 'provider was external, now has been removed' do
+ it 'should mark existing user internal' do
+ create(:omniauth_user, extern_uid: 'my-uid', provider: 'twitter', external: true)
+ stub_omniauth_config(allow_single_sign_on: ['twitter'], external_providers: ['facebook'])
+ oauth_user.save
+ expect(gl_user).to be_valid
+ expect(gl_user.external).to be_falsey
+ end
+ end
+
+ context 'with new allow_single_sign_on enabled syntax' do
before { stub_omniauth_config(allow_single_sign_on: ['twitter']) }
it "creates a user from Omniauth" do
@@ -67,16 +86,16 @@ describe Gitlab::OAuth::User, lib: true do
end
end
- context "with new allow_single_sign_on disabled syntax" do
+ context 'with new allow_single_sign_on disabled syntax' do
before { stub_omniauth_config(allow_single_sign_on: []) }
- it "throws an error" do
+ it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
end
- context "with old allow_single_sign_on disabled (Default)" do
+ context 'with old allow_single_sign_on disabled (Default)' do
before { stub_omniauth_config(allow_single_sign_on: false) }
- it "throws an error" do
+ it 'throws an error' do
expect{ oauth_user.save }.to raise_error StandardError
end
end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index f023be6ae45..6ffc0d6e658 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -1,77 +1,110 @@
require 'spec_helper'
describe Gitlab::UrlBuilder, lib: true do
- describe 'When asking for an issue' do
- it 'returns the issue url' do
- issue = create(:issue)
- url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
- expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
- end
- end
+ describe '.build' do
+ context 'when passing a Commit' do
+ it 'returns a proper URL' do
+ commit = build_stubbed(:commit)
- describe 'When asking for an merge request' do
- it 'returns the merge request url' do
- merge_request = create(:merge_request)
- url = Gitlab::UrlBuilder.new(:merge_request).build(merge_request.id)
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
+ url = described_class.build(commit)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.path_with_namespace}/commit/#{commit.id}"
+ end
end
- end
- describe 'When asking for a note on commit' do
- let(:note) { create(:note_on_commit) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ context 'when passing an Issue' do
+ it 'returns a proper URL' do
+ issue = build_stubbed(:issue, iid: 42)
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ url = described_class.build(issue)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
+ end
end
- end
- describe 'When asking for a note on commit diff' do
- let(:note) { create(:note_on_commit_diff) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ context 'when passing a MergeRequest' do
+ it 'returns a proper URL' do
+ merge_request = build_stubbed(:merge_request, iid: 42)
+
+ url = described_class.build(merge_request)
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
+ end
end
- end
- describe 'When asking for a note on issue' do
- let(:issue) { create(:issue) }
- let(:note) { create(:note_on_issue, noteable_id: issue.id) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ context 'when passing a Note' do
+ context 'on a Commit' do
+ it 'returns a proper URL' do
+ note = build_stubbed(:note_on_commit)
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
- end
- end
+ url = described_class.build(note)
- describe 'When asking for a note on merge request' do
- let(:merge_request) { create(:merge_request) }
- let(:note) { create(:note_on_merge_request, noteable_id: merge_request.id) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
- end
- end
+ context 'on a CommitDiff' do
+ it 'returns a proper URL' do
+ note = build_stubbed(:note_on_commit_diff)
- describe 'When asking for a note on merge request diff' do
- let(:merge_request) { create(:merge_request) }
- let(:note) { create(:note_on_merge_request_diff, noteable_id: merge_request.id) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ url = described_class.build(note)
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
- end
- end
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
+
+ context 'on an Issue' do
+ it 'returns a proper URL' do
+ issue = create(:issue, iid: 42)
+ note = build_stubbed(:note_on_issue, noteable: issue)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a MergeRequest' do
+ it 'returns a proper URL' do
+ merge_request = create(:merge_request, iid: 42)
+ note = build_stubbed(:note_on_merge_request, noteable: merge_request)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a MergeRequestDiff' do
+ it 'returns a proper URL' do
+ merge_request = create(:merge_request, iid: 42)
+ note = build_stubbed(:note_on_merge_request_diff, noteable: merge_request)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a ProjectSnippet' do
+ it 'returns a proper URL' do
+ project_snippet = create(:project_snippet)
+ note = build_stubbed(:note_on_project_snippet, noteable: project_snippet)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
+ end
+ end
- describe 'When asking for a note on project snippet' do
- let(:snippet) { create(:project_snippet) }
- let(:note) { create(:note_on_project_snippet, noteable_id: snippet.id) }
- let(:url) { Gitlab::UrlBuilder.new(:note).build(note.id) }
+ context 'on another object' do
+ it 'returns a proper URL' do
+ project = build_stubbed(:project)
- it 'returns the note url' do
- expect(url).to eq "#{Settings.gitlab['url']}/#{snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
+ expect { described_class.build(project) }.
+ to raise_error(NotImplementedError, 'No URL builder defined for Project')
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb
new file mode 100644
index 00000000000..c59dfea5c55
--- /dev/null
+++ b/spec/lib/gitlab_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+describe Gitlab, lib: true do
+ describe '.com?' do
+ it 'is true when on GitLab.com' do
+ stub_config_setting(url: 'https://gitlab.com')
+
+ expect(described_class.com?).to eq true
+ end
+
+ it 'is false when not on GitLab.com' do
+ stub_config_setting(url: 'http://example.com')
+
+ expect(described_class.com?).to eq false
+ end
+ end
+end
diff --git a/spec/mailers/repository_check_mailer_spec.rb b/spec/mailers/repository_check_mailer_spec.rb
new file mode 100644
index 00000000000..583bf15176f
--- /dev/null
+++ b/spec/mailers/repository_check_mailer_spec.rb
@@ -0,0 +1,21 @@
+require 'rails_helper'
+
+describe RepositoryCheckMailer do
+ include EmailSpec::Matchers
+
+ describe '.notify' do
+ it 'emails all admins' do
+ admins = create_list(:admin, 3)
+
+ mail = described_class.notify(1)
+
+ expect(mail).to deliver_to admins.map(&:email)
+ end
+
+ it 'mentions the number of failed checks' do
+ mail = described_class.notify(3)
+
+ expect(mail).to have_subject '3 projects failed their last repository check'
+ end
+ end
+end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 15052aaca28..fac516f9568 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -191,12 +191,19 @@ describe Issue, models: true do
end
describe '#related_branches' do
- it "selects the right branches" do
+ it 'selects the right branches' do
allow(subject.project.repository).to receive(:branch_names).
- and_return(["mpempe", "#{subject.iid}mepmep", subject.to_branch_name])
+ and_return(['mpempe', "#{subject.iid}mepmep", subject.to_branch_name])
expect(subject.related_branches).to eq([subject.to_branch_name])
end
+
+ it 'excludes stable branches from the related branches' do
+ allow(subject.project.repository).to receive(:branch_names).
+ and_return(["#{subject.iid}-0-stable"])
+
+ expect(subject.related_branches).to eq []
+ end
end
it_behaves_like 'an editable mentionable' do
@@ -210,11 +217,11 @@ describe Issue, models: true do
let(:subject) { create :issue }
end
- describe "#to_branch_name" do
+ describe '#to_branch_name' do
let(:issue) { create(:issue, title: 'a' * 30) }
- it "starts with the issue iid" do
- expect(issue.to_branch_name).to match /-#{issue.iid}\z/
+ it 'starts with the issue iid' do
+ expect(issue.to_branch_name).to match /\A#{issue.iid}-a+\z/
end
end
end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
new file mode 100644
index 00000000000..295081e9da1
--- /dev/null
+++ b/spec/models/notification_setting_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+RSpec.describe NotificationSetting, type: :model do
+ describe "Associations" do
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:source) }
+ end
+
+ describe "Validation" 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
+end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
index c34b2487ecf..31b2c90122d 100644
--- a/spec/models/project_services/bamboo_service_spec.rb
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -21,74 +21,232 @@
require 'spec_helper'
describe BambooService, models: true do
- describe "Associations" do
+ describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
end
- describe "Execute" do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
-
- context "when a password was previously set" do
- before do
- @bamboo_service = BambooService.create(
- project: create(:project),
- properties: {
- bamboo_url: 'http://gitlab.com',
- username: 'mic',
- password: "password"
- }
- )
+ describe 'Validations' do
+ describe '#bamboo_url' do
+ it 'does not validate the presence of bamboo_url if service is not active' do
+ bamboo_service = service
+ bamboo_service.active = false
+
+ expect(bamboo_service).not_to validate_presence_of(:bamboo_url)
+ end
+
+ it 'validates the presence of bamboo_url if service is active' do
+ bamboo_service = service
+ bamboo_service.active = true
+
+ expect(bamboo_service).to validate_presence_of(:bamboo_url)
+ end
+ end
+
+ describe '#build_key' do
+ it 'does not validate the presence of build_key if service is not active' do
+ bamboo_service = service
+ bamboo_service.active = false
+
+ expect(bamboo_service).not_to validate_presence_of(:build_key)
end
-
- it "reset password if url changed" do
- @bamboo_service.bamboo_url = 'http://gitlab1.com'
- @bamboo_service.save
- expect(@bamboo_service.password).to be_nil
+
+ it 'validates the presence of build_key if service is active' do
+ bamboo_service = service
+ bamboo_service.active = true
+
+ expect(bamboo_service).to validate_presence_of(:build_key)
+ end
+ end
+
+ describe '#username' do
+ it 'does not validate the presence of username if service is not active' do
+ bamboo_service = service
+ bamboo_service.active = false
+
+ expect(bamboo_service).not_to validate_presence_of(:username)
+ end
+
+ it 'does not validate the presence of username if username is nil' do
+ bamboo_service = service
+ bamboo_service.active = true
+ bamboo_service.password = nil
+
+ expect(bamboo_service).not_to validate_presence_of(:username)
+ end
+
+ it 'validates the presence of username if service is active and username is present' do
+ bamboo_service = service
+ bamboo_service.active = true
+ bamboo_service.password = 'secret'
+
+ expect(bamboo_service).to validate_presence_of(:username)
end
-
- it "does not reset password if username changed" do
- @bamboo_service.username = "some_name"
- @bamboo_service.save
- expect(@bamboo_service.password).to eq("password")
+ end
+
+ describe '#password' do
+ it 'does not validate the presence of password if service is not active' do
+ bamboo_service = service
+ bamboo_service.active = false
+
+ expect(bamboo_service).not_to validate_presence_of(:password)
end
- it "does not reset password if new url is set together with password, even if it's the same password" do
- @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
- @bamboo_service.password = 'password'
- @bamboo_service.save
- expect(@bamboo_service.password).to eq("password")
- expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+ it 'does not validate the presence of password if username is nil' do
+ bamboo_service = service
+ bamboo_service.active = true
+ bamboo_service.username = nil
+
+ expect(bamboo_service).not_to validate_presence_of(:password)
end
- it "should reset password if url changed, even if setter called multiple times" do
- @bamboo_service.bamboo_url = 'http://gitlab1.com'
- @bamboo_service.bamboo_url = 'http://gitlab1.com'
- @bamboo_service.save
- expect(@bamboo_service.password).to be_nil
+ it 'validates the presence of password if service is active and username is present' do
+ bamboo_service = service
+ bamboo_service.active = true
+ bamboo_service.username = 'john'
+
+ expect(bamboo_service).to validate_presence_of(:password)
end
end
-
- context "when no password was previously set" do
- before do
- @bamboo_service = BambooService.create(
- project: create(:project),
- properties: {
- bamboo_url: 'http://gitlab.com',
- username: 'mic'
- }
- )
+ end
+
+ describe 'Callbacks' do
+ describe 'before_update :reset_password' do
+ context 'when a password was previously set' do
+ it 'resets password if url changed' do
+ bamboo_service = service
+
+ bamboo_service.bamboo_url = 'http://gitlab1.com'
+ bamboo_service.save
+
+ expect(bamboo_service.password).to be_nil
+ end
+
+ it 'does not reset password if username changed' do
+ bamboo_service = service
+
+ bamboo_service.username = 'some_name'
+ bamboo_service.save
+
+ expect(bamboo_service.password).to eq('password')
+ end
+
+ it "does not reset password if new url is set together with password, even if it's the same password" do
+ bamboo_service = service
+
+ bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+ bamboo_service.password = 'password'
+ bamboo_service.save
+
+ expect(bamboo_service.password).to eq('password')
+ expect(bamboo_service.bamboo_url).to eq('http://gitlab_edited.com')
+ end
end
- it "saves password if new url is set together with password" do
- @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
- @bamboo_service.password = 'password'
- @bamboo_service.save
- expect(@bamboo_service.password).to eq("password")
- expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+ it 'saves password if new url is set together with password when no password was previously set' do
+ bamboo_service = service
+ bamboo_service.password = nil
+
+ bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+ bamboo_service.password = 'password'
+ bamboo_service.save
+
+ expect(bamboo_service.password).to eq('password')
+ expect(bamboo_service.bamboo_url).to eq('http://gitlab_edited.com')
end
+ end
+ end
+
+ describe '#build_page' do
+ it 'returns a specific URL when status is 500' do
+ stub_request(status: 500)
+
+ expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/browse/foo')
+ end
+
+ it 'returns a specific URL when response has no results' do
+ stub_request(body: %Q({"results":{"results":{"size":"0"}}}))
+
+ expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/browse/foo')
+ end
+
+ it 'returns a build URL when bamboo_url has no trailing slash' do
+ stub_request(body: %Q({"results":{"results":{"result":{"planResultKey":{"key":"42"}}}}}))
+
+ expect(service(bamboo_url: 'http://gitlab.com').build_page('123', 'unused')).to eq('http://gitlab.com/browse/42')
+ end
+
+ it 'returns a build URL when bamboo_url has a trailing slash' do
+ stub_request(body: %Q({"results":{"results":{"result":{"planResultKey":{"key":"42"}}}}}))
+
+ expect(service(bamboo_url: 'http://gitlab.com/').build_page('123', 'unused')).to eq('http://gitlab.com/browse/42')
+ end
+ end
+
+ describe '#commit_status' do
+ it 'sets commit status to :error when status is 500' do
+ stub_request(status: 500)
+
+ expect(service.commit_status('123', 'unused')).to eq(:error)
+ end
+
+ it 'sets commit status to "pending" when status is 404' do
+ stub_request(status: 404)
+
+ expect(service.commit_status('123', 'unused')).to eq('pending')
+ end
+
+ it 'sets commit status to "pending" when response has no results' do
+ stub_request(body: %Q({"results":{"results":{"size":"0"}}}))
+
+ expect(service.commit_status('123', 'unused')).to eq('pending')
+ end
+
+ it 'sets commit status to "success" when build state contains Success' do
+ stub_request(build_state: 'YAY Success!')
+ expect(service.commit_status('123', 'unused')).to eq('success')
end
+
+ it 'sets commit status to "failed" when build state contains Failed' do
+ stub_request(build_state: 'NO Failed!')
+
+ expect(service.commit_status('123', 'unused')).to eq('failed')
+ end
+
+ it 'sets commit status to "pending" when build state contains Pending' do
+ stub_request(build_state: 'NO Pending!')
+
+ expect(service.commit_status('123', 'unused')).to eq('pending')
+ end
+
+ it 'sets commit status to :error when build state is unknown' do
+ stub_request(build_state: 'FOO BAR!')
+
+ expect(service.commit_status('123', 'unused')).to eq(:error)
+ end
+ end
+
+ def service(bamboo_url: 'http://gitlab.com')
+ described_class.create(
+ project: build_stubbed(:empty_project),
+ properties: {
+ bamboo_url: bamboo_url,
+ username: 'mic',
+ password: 'password',
+ build_key: 'foo'
+ }
+ )
+ end
+
+ def stub_request(status: 200, body: nil, build_state: 'success')
+ bamboo_full_url = 'http://mic:password@gitlab.com/rest/api/latest/result?label=123&os_authType=basic'
+ body ||= %Q({"results":{"results":{"result":{"buildState":"#{build_state}"}}}})
+
+ WebMock.stub_request(:get, bamboo_full_url).to_return(
+ status: status,
+ headers: { 'Content-Type' => 'application/json' },
+ body: body
+ )
end
end
diff --git a/spec/models/project_services/builds_email_service_spec.rb b/spec/models/project_services/builds_email_service_spec.rb
index 2ccbff553f0..7c23c2efccd 100644
--- a/spec/models/project_services/builds_email_service_spec.rb
+++ b/spec/models/project_services/builds_email_service_spec.rb
@@ -3,9 +3,10 @@ require 'spec_helper'
describe BuildsEmailService do
let(:build) { create(:ci_build) }
let(:data) { Gitlab::BuildDataBuilder.build(build) }
- let(:service) { BuildsEmailService.new }
+ let!(:project) { create(:project, :public, ci_id: 1) }
+ let(:service) { described_class.new(project: project, active: true) }
- describe :execute do
+ describe '#execute' do
it 'sends email' do
service.recipients = 'test@gitlab.com'
data[:build_status] = 'failed'
@@ -40,4 +41,36 @@ describe BuildsEmailService do
service.execute(data)
end
end
+
+ describe 'validations' do
+
+ context 'when pusher is not added' do
+ before { service.add_pusher = false }
+
+ it 'does not allow empty recipient input' do
+ service.recipients = ''
+ expect(service.valid?).to be false
+ end
+
+ it 'does allow non-empty recipient input' do
+ service.recipients = 'test@example.com'
+ expect(service.valid?).to be true
+ end
+
+ end
+
+ context 'when pusher is added' do
+ before { service.add_pusher = true }
+
+ it 'does allow empty recipient input' do
+ service.recipients = ''
+ expect(service.valid?).to be true
+ end
+
+ it 'does allow non-empty recipient input' do
+ service.recipients = 'test@example.com'
+ expect(service.valid?).to be true
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
index f26b47a856c..bc7423cee69 100644
--- a/spec/models/project_services/teamcity_service_spec.rb
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -21,73 +21,220 @@
require 'spec_helper'
describe TeamcityService, models: true do
- describe "Associations" do
+ describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
end
- describe "Execute" do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
-
- context "when a password was previously set" do
- before do
- @teamcity_service = TeamcityService.create(
- project: create(:project),
- properties: {
- teamcity_url: 'http://gitlab.com',
- username: 'mic',
- password: "password"
- }
- )
+ describe 'Validations' do
+ describe '#teamcity_url' do
+ it 'does not validate the presence of teamcity_url if service is not active' do
+ teamcity_service = service
+ teamcity_service.active = false
+
+ expect(teamcity_service).not_to validate_presence_of(:teamcity_url)
end
-
- it "reset password if url changed" do
- @teamcity_service.teamcity_url = 'http://gitlab1.com'
- @teamcity_service.save
- expect(@teamcity_service.password).to be_nil
+
+ it 'validates the presence of teamcity_url if service is active' do
+ teamcity_service = service
+ teamcity_service.active = true
+
+ expect(teamcity_service).to validate_presence_of(:teamcity_url)
+ end
+ end
+
+ describe '#build_type' do
+ it 'does not validate the presence of build_type if service is not active' do
+ teamcity_service = service
+ teamcity_service.active = false
+
+ expect(teamcity_service).not_to validate_presence_of(:build_type)
+ end
+
+ it 'validates the presence of build_type if service is active' do
+ teamcity_service = service
+ teamcity_service.active = true
+
+ expect(teamcity_service).to validate_presence_of(:build_type)
end
-
- it "does not reset password if username changed" do
- @teamcity_service.username = "some_name"
- @teamcity_service.save
- expect(@teamcity_service.password).to eq("password")
+ end
+
+ describe '#username' do
+ it 'does not validate the presence of username if service is not active' do
+ teamcity_service = service
+ teamcity_service.active = false
+
+ expect(teamcity_service).not_to validate_presence_of(:username)
end
- it "does not reset password if new url is set together with password, even if it's the same password" do
- @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
- @teamcity_service.password = 'password'
- @teamcity_service.save
- expect(@teamcity_service.password).to eq("password")
- expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+ it 'does not validate the presence of username if username is nil' do
+ teamcity_service = service
+ teamcity_service.active = true
+ teamcity_service.password = nil
+
+ expect(teamcity_service).not_to validate_presence_of(:username)
end
- it "should reset password if url changed, even if setter called multiple times" do
- @teamcity_service.teamcity_url = 'http://gitlab1.com'
- @teamcity_service.teamcity_url = 'http://gitlab1.com'
- @teamcity_service.save
- expect(@teamcity_service.password).to be_nil
+ it 'validates the presence of username if service is active and username is present' do
+ teamcity_service = service
+ teamcity_service.active = true
+ teamcity_service.password = 'secret'
+
+ expect(teamcity_service).to validate_presence_of(:username)
end
end
-
- context "when no password was previously set" do
- before do
- @teamcity_service = TeamcityService.create(
- project: create(:project),
- properties: {
- teamcity_url: 'http://gitlab.com',
- username: 'mic'
- }
- )
+
+ describe '#password' do
+ it 'does not validate the presence of password if service is not active' do
+ teamcity_service = service
+ teamcity_service.active = false
+
+ expect(teamcity_service).not_to validate_presence_of(:password)
+ end
+
+ it 'does not validate the presence of password if username is nil' do
+ teamcity_service = service
+ teamcity_service.active = true
+ teamcity_service.username = nil
+
+ expect(teamcity_service).not_to validate_presence_of(:password)
end
- it "saves password if new url is set together with password" do
- @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
- @teamcity_service.password = 'password'
- @teamcity_service.save
- expect(@teamcity_service.password).to eq("password")
- expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+ it 'validates the presence of password if service is active and username is present' do
+ teamcity_service = service
+ teamcity_service.active = true
+ teamcity_service.username = 'john'
+
+ expect(teamcity_service).to validate_presence_of(:password)
end
end
end
+
+ describe 'Callbacks' do
+ describe 'before_update :reset_password' do
+ context 'when a password was previously set' do
+ it 'resets password if url changed' do
+ teamcity_service = service
+
+ teamcity_service.teamcity_url = 'http://gitlab1.com'
+ teamcity_service.save
+
+ expect(teamcity_service.password).to be_nil
+ end
+
+ it 'does not reset password if username changed' do
+ teamcity_service = service
+
+ teamcity_service.username = 'some_name'
+ teamcity_service.save
+
+ expect(teamcity_service.password).to eq('password')
+ end
+
+ it "does not reset password if new url is set together with password, even if it's the same password" do
+ teamcity_service = service
+
+ teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+ teamcity_service.password = 'password'
+ teamcity_service.save
+
+ expect(teamcity_service.password).to eq('password')
+ expect(teamcity_service.teamcity_url).to eq('http://gitlab_edited.com')
+ end
+ end
+
+ it 'saves password if new url is set together with password when no password was previously set' do
+ teamcity_service = service
+ teamcity_service.password = nil
+
+ teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+ teamcity_service.password = 'password'
+ teamcity_service.save
+
+ expect(teamcity_service.password).to eq('password')
+ expect(teamcity_service.teamcity_url).to eq('http://gitlab_edited.com')
+ end
+ end
+ end
+
+ describe '#build_page' do
+ it 'returns a specific URL when status is 500' do
+ stub_request(status: 500)
+
+ expect(service.build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildTypeId=foo')
+ end
+
+ it 'returns a build URL when teamcity_url has no trailing slash' do
+ stub_request(body: %Q({"build":{"id":"666"}}))
+
+ expect(service(teamcity_url: 'http://gitlab.com').build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildId=666&buildTypeId=foo')
+ end
+
+ it 'returns a build URL when teamcity_url has a trailing slash' do
+ stub_request(body: %Q({"build":{"id":"666"}}))
+
+ expect(service(teamcity_url: 'http://gitlab.com/').build_page('123', 'unused')).to eq('http://gitlab.com/viewLog.html?buildId=666&buildTypeId=foo')
+ end
+ end
+
+ describe '#commit_status' do
+ it 'sets commit status to :error when status is 500' do
+ stub_request(status: 500)
+
+ expect(service.commit_status('123', 'unused')).to eq(:error)
+ end
+
+ it 'sets commit status to "pending" when status is 404' do
+ stub_request(status: 404)
+
+ expect(service.commit_status('123', 'unused')).to eq('pending')
+ end
+
+ it 'sets commit status to "success" when build status contains SUCCESS' do
+ stub_request(build_status: 'YAY SUCCESS!')
+
+ expect(service.commit_status('123', 'unused')).to eq('success')
+ end
+
+ it 'sets commit status to "failed" when build status contains FAILURE' do
+ stub_request(build_status: 'NO FAILURE!')
+
+ expect(service.commit_status('123', 'unused')).to eq('failed')
+ end
+
+ it 'sets commit status to "pending" when build status contains Pending' do
+ stub_request(build_status: 'NO Pending!')
+
+ expect(service.commit_status('123', 'unused')).to eq('pending')
+ end
+
+ it 'sets commit status to :error when build status is unknown' do
+ stub_request(build_status: 'FOO BAR!')
+
+ expect(service.commit_status('123', 'unused')).to eq(:error)
+ end
+ end
+
+ def service(teamcity_url: 'http://gitlab.com')
+ described_class.create(
+ project: build_stubbed(:empty_project),
+ properties: {
+ teamcity_url: teamcity_url,
+ username: 'mic',
+ password: 'password',
+ build_type: 'foo'
+ }
+ )
+ end
+
+ def stub_request(status: 200, body: nil, build_status: 'success')
+ teamcity_full_url = 'http://mic:password@gitlab.com/httpAuth/app/rest/builds/branch:unspecified:any,number:123'
+ body ||= %Q({"build":{"status":"#{build_status}","id":"666"}})
+
+ WebMock.stub_request(:get, teamcity_full_url).to_return(
+ status: status,
+ headers: { 'Content-Type' => 'application/json' },
+ body: body
+ )
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 4e49c413f23..86f68b3a0a0 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -94,6 +94,12 @@ describe Repository, models: true do
it { is_expected.to be_an Array }
+ it 'regex-escapes the query string' do
+ results = repository.search_files("test\\", 'master')
+
+ expect(results.first).not_to start_with('fatal:')
+ end
+
describe 'result' do
subject { results.first }
@@ -393,6 +399,8 @@ describe Repository, models: true do
describe '#expire_cache' do
it 'expires all caches' do
expect(repository).to receive(:expire_branch_cache)
+ expect(repository).to receive(:expire_branch_count_cache)
+ expect(repository).to receive(:expire_tag_count_cache)
repository.expire_cache
end
diff --git a/spec/requests/api/group_members_spec.rb b/spec/requests/api/group_members_spec.rb
index 3e8b4aa1f88..96d89e69209 100644
--- a/spec/requests/api/group_members_spec.rb
+++ b/spec/requests/api/group_members_spec.rb
@@ -42,9 +42,10 @@ describe API::API, api: true do
end
end
- it "users not part of the group should get access error" do
+ it 'users not part of the group should get access error' do
get api("/groups/#{group_with_members.id}/members", stranger)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
end
@@ -165,12 +166,13 @@ describe API::API, api: true do
end
end
- describe "DELETE /groups/:id/members/:user_id" do
- context "when not a member of the group" do
+ describe 'DELETE /groups/:id/members/:user_id' do
+ context 'when not a member of the group' do
it "should not delete guest's membership of group_with_members" do
random_user = create(:user)
delete api("/groups/#{group_with_members.id}/members/#{owner.id}", random_user)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 41c9cacd455..37ddab83c30 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -61,7 +61,8 @@ describe API::API, api: true do
it "should not return a group not attached to user1" do
get api("/groups/#{group2.id}", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
@@ -92,9 +93,54 @@ describe API::API, api: true do
it 'should not return a group not attached to user1' do
get api("/groups/#{group2.path}", user1)
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ describe 'PUT /groups/:id' do
+ let(:new_group_name) { 'New Group'}
+
+ context 'when authenticated as the group owner' do
+ it 'updates the group' do
+ put api("/groups/#{group1.id}", user1), name: new_group_name
+
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(new_group_name)
+ end
+
+ it 'returns 404 for a non existing group' do
+ put api('/groups/1328', user1)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when authenticated as the admin' do
+ it 'updates the group' do
+ put api("/groups/#{group1.id}", admin), name: new_group_name
+
+ expect(response.status).to eq(200)
+ expect(json_response['name']).to eq(new_group_name)
+ end
+ end
+
+ context 'when authenticated as an user that can see the group' do
+ it 'does not updates the group' do
+ put api("/groups/#{group1.id}", user2), name: new_group_name
+
expect(response.status).to eq(403)
end
end
+
+ context 'when authenticated as an user that cannot see the group' do
+ it 'returns 404 when trying to update the group' do
+ put api("/groups/#{group2.id}", user1), name: new_group_name
+
+ expect(response.status).to eq(404)
+ end
+ end
end
describe "GET /groups/:id/projects" do
@@ -113,7 +159,8 @@ describe API::API, api: true do
it "should not return a group not attached to user1" do
get api("/groups/#{group2.id}/projects", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
@@ -145,7 +192,8 @@ describe API::API, api: true do
it 'should not return a group not attached to user1' do
get api("/groups/#{group2.path}/projects", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
end
@@ -203,7 +251,8 @@ describe API::API, api: true do
it "should not remove a group not attached to user1" do
delete api("/groups/#{group2.id}", user1)
- expect(response.status).to eq(403)
+
+ expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 822d3ad3017..f88e39cad9e 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -3,11 +3,12 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
+ let(:user2) { create(:user) }
let(:non_member) { create(:user) }
let(:author) { create(:author) }
let(:assignee) { create(:assignee) }
let(:admin) { create(:user, :admin) }
- let!(:project) { create(:project, :public, namespace: user.namespace ) }
+ let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
let!(:closed_issue) do
create :closed_issue,
author: user,
@@ -320,13 +321,13 @@ describe API::API, api: true do
end
context 'when an admin or owner makes the request' do
- it "accepts the creation date to be set" do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
post api("/projects/#{project.id}/issues", user),
- title: 'new issue', labels: 'label, label2', created_at: 2.weeks.ago
+ title: 'new issue', labels: 'label, label2', created_at: creation_time
expect(response.status).to eq(201)
- # this take about a second, so probably not equal
- expect(Time.parse(json_response['created_at'])).to be <= 2.weeks.ago
+ expect(Time.parse(json_response['created_at'])).to be_within(1.second).of(creation_time)
end
end
end
@@ -477,6 +478,18 @@ describe API::API, api: true do
expect(json_response['labels']).to include 'label2'
expect(json_response['state']).to eq "closed"
end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the update date to be set' do
+ update_time = 2.weeks.ago
+ put api("/projects/#{project.id}/issues/#{issue.id}", user),
+ labels: 'label3', state_event: 'close', updated_at: update_time
+ expect(response.status).to eq(200)
+
+ expect(json_response['labels']).to include 'label3'
+ expect(Time.parse(json_response['updated_at'])).to be_within(1.second).of(update_time)
+ end
+ end
end
describe "DELETE /projects/:id/issues/:issue_id" do
@@ -501,4 +514,114 @@ describe API::API, api: true do
end
end
end
+
+ describe '/projects/:id/issues/:issue_id/move' do
+ let!(:target_project) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace ) }
+ let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace ) }
+
+ it 'moves an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(201)
+ expect(json_response['project_id']).to eq(target_project.id)
+ end
+
+ context 'when source and target projects are the same' do
+ it 'returns 400 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: project.id
+
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Cannot move issue to project it originates from!')
+ end
+ end
+
+ context 'when the user does not have the permission to move issues' do
+ it 'returns 400 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: target_project2.id
+
+ expect(response.status).to eq(400)
+ expect(json_response['message']).to eq('Cannot move issue due to insufficient permissions!')
+ end
+ end
+
+ it 'moves the issue to another namespace if I am admin' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", admin),
+ to_project_id: target_project2.id
+
+ expect(response.status).to eq(201)
+ expect(json_response['project_id']).to eq(target_project2.id)
+ end
+
+ context 'when issue does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/123/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when source project does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/123/issues/#{issue.id}/move", user),
+ to_project_id: target_project.id
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ context 'when target project does not exist' do
+ it 'returns 404 when trying to move an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/move", user),
+ to_project_id: 123
+
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ describe 'POST :id/issues/:issue_id/subscription' do
+ it 'subscribes to an issue' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/subscription", user2)
+
+ expect(response.status).to eq(201)
+ expect(json_response['subscribed']).to eq(true)
+ end
+
+ it 'returns 304 if already subscribed' do
+ post api("/projects/#{project.id}/issues/#{issue.id}/subscription", user)
+
+ expect(response.status).to eq(304)
+ end
+
+ it 'returns 404 if the issue is not found' do
+ post api("/projects/#{project.id}/issues/123/subscription", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe 'DELETE :id/issues/:issue_id/subscription' do
+ it 'unsubscribes from an issue' do
+ delete api("/projects/#{project.id}/issues/#{issue.id}/subscription", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response['subscribed']).to eq(false)
+ end
+
+ it 'returns 304 if not subscribed' do
+ delete api("/projects/#{project.id}/issues/#{issue.id}/subscription", user2)
+
+ expect(response.status).to eq(304)
+ end
+
+ it 'returns 404 if the issue is not found' do
+ delete api("/projects/#{project.id}/issues/123/subscription", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 25fa30b2f21..1fa7e76894f 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -516,6 +516,48 @@ describe API::API, api: true do
end
end
+ describe 'POST :id/merge_requests/:merge_request_id/subscription' do
+ it 'subscribes to a merge request' do
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
+
+ expect(response.status).to eq(201)
+ expect(json_response['subscribed']).to eq(true)
+ end
+
+ it 'returns 304 if already subscribed' do
+ post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
+
+ expect(response.status).to eq(304)
+ end
+
+ it 'returns 404 if the merge request is not found' do
+ post api("/projects/#{project.id}/merge_requests/123/subscription", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe 'DELETE :id/merge_requests/:merge_request_id/subscription' do
+ it 'unsubscribes from a merge request' do
+ delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", user)
+
+ expect(response.status).to eq(200)
+ expect(json_response['subscribed']).to eq(false)
+ end
+
+ it 'returns 304 if not subscribed' do
+ delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", admin)
+
+ expect(response.status).to eq(304)
+ end
+
+ it 'returns 404 if the merge request is not found' do
+ post api("/projects/#{project.id}/merge_requests/123/subscription", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
def mr_with_later_created_and_updated_at_time
merge_request
merge_request.created_at += 1.hour
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index a467bc935af..ec9eda0a2ed 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -158,6 +158,19 @@ describe API::API, api: true do
post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
expect(response.status).to eq(401)
end
+
+ context 'when an admin or owner makes the request' do
+ it 'accepts the creation date to be set' do
+ creation_time = 2.weeks.ago
+ post api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
+ body: 'hi!', created_at: creation_time
+ expect(response.status).to eq(201)
+ expect(json_response['body']).to eq('hi!')
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(Time.parse(json_response['created_at'])).to be_within(1.second).of(creation_time)
+ end
+ end
+
end
context "when noteable is a Snippet" do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index be2034e0f39..fccd08bd6da 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1020,6 +1020,54 @@ describe API::API, api: true do
end
end
+ describe 'POST /projects/:id/star' do
+ context 'on an unstarred project' do
+ it 'stars the project' do
+ expect { post api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(1)
+
+ expect(response.status).to eq(201)
+ expect(json_response['star_count']).to eq(1)
+ end
+ end
+
+ context 'on a starred project' do
+ before do
+ user.toggle_star(project)
+ project.reload
+ end
+
+ it 'does not modify the star count' do
+ expect { post api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count }
+
+ expect(response.status).to eq(304)
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/star' do
+ context 'on a starred project' do
+ before do
+ user.toggle_star(project)
+ project.reload
+ end
+
+ it 'unstars the project' do
+ expect { delete api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(-1)
+
+ expect(response.status).to eq(200)
+ expect(json_response['star_count']).to eq(0)
+ end
+ end
+
+ context 'on an unstarred project' do
+ it 'does not modify the star count' do
+ expect { delete api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count }
+
+ expect(response.status).to eq(304)
+ end
+ end
+ end
+
describe 'DELETE /projects/:id' do
context 'when authenticated as user' do
it 'should remove project' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 0f2aa3ae73c..d7c72dc0811 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -88,12 +88,9 @@ describe NotificationService, services: true do
note.project.namespace_id = group.id
note.project.group.add_user(@u_watcher, GroupMember::MASTER)
note.project.save
- user_project = note.project.project_members.find_by_user_id(@u_watcher.id)
- user_project.notification_level = Notification::N_PARTICIPATING
- user_project.save
- group_member = note.project.group.group_members.find_by_user_id(@u_watcher.id)
- group_member.notification_level = Notification::N_GLOBAL
- group_member.save
+
+ @u_watcher.notification_settings_for(note.project).participating!
+ @u_watcher.notification_settings_for(note.project.group).global!
ActionMailer::Base.deliveries.clear
end
@@ -215,7 +212,7 @@ describe NotificationService, services: true do
end
it do
- @u_committer.update_attributes(notification_level: Notification::N_MENTION)
+ @u_committer.update_attributes(notification_level: :mention)
notification.new_note(note)
should_not_email(@u_committer)
end
@@ -246,7 +243,7 @@ describe NotificationService, services: true do
end
it do
- issue.assignee.update_attributes(notification_level: Notification::N_MENTION)
+ issue.assignee.update_attributes(notification_level: :mention)
notification.new_issue(issue, @u_disabled)
should_not_email(issue.assignee)
@@ -596,13 +593,13 @@ describe NotificationService, services: true do
end
def build_team(project)
- @u_watcher = create(:user, notification_level: Notification::N_WATCH)
- @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
- @u_participant_mentioned = create(:user, username: 'participant', notification_level: Notification::N_PARTICIPATING)
- @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
- @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION)
+ @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: Notification::N_PARTICIPATING)
+ @u_not_mentioned = create(:user, username: 'regular', notification_level: :participating)
@u_outsider_mentioned = create(:user, username: 'outsider')
project.team << [@u_watcher, :master]
@@ -617,8 +614,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: Notification::N_PARTICIPATING)
- @watcher_and_subscriber = create(:user, notification_level: Notification::N_WATCH)
+ @subscribed_participant = create(:user, username: 'subscribed_participant', notification_level: :participating)
+ @watcher_and_subscriber = create(:user, notification_level: :watch)
project.team << [@subscribed_participant, :master]
project.team << [@subscriber, :master]
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index c46259431aa..06017317339 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -38,4 +38,27 @@ describe Projects::TransferService, services: true do
def transfer_project(project, user, new_namespace)
Projects::TransferService.new(project, user).execute(new_namespace)
end
+
+ context 'visibility level' do
+ let(:internal_group) { create(:group, :internal) }
+
+ before { internal_group.add_owner(user) }
+
+ context 'when namespace visibility level < project visibility level' do
+ let(:public_project) { create(:project, :public, namespace: user.namespace) }
+
+ before { transfer_project(public_project, user, internal_group) }
+
+ it { expect(public_project.visibility_level).to eq(internal_group.visibility_level) }
+ end
+
+ context 'when namespace visibility level > project visibility level' do
+ let(:private_project) { create(:project, :private, namespace: user.namespace) }
+
+ before { transfer_project(private_project, user, internal_group) }
+
+ it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) }
+ end
+ end
+
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 0265dbe9c66..94ff3457902 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -4,6 +4,9 @@ describe PostReceive do
let(:changes) { "123456 789012 refs/heads/tést\n654321 210987 refs/tags/tag" }
let(:wrongly_encoded_changes) { changes.encode("ISO-8859-1").force_encoding("UTF-8") }
let(:base64_changes) { Base64.encode64(wrongly_encoded_changes) }
+ let(:project) { create(:project) }
+ let(:key) { create(:key, user: project.owner) }
+ let(:key_id) { key.shell_id }
context "as a resque worker" do
it "reponds to #perform" do
@@ -11,11 +14,43 @@ describe PostReceive do
end
end
- context "webhook" do
- let(:project) { create(:project) }
- let(:key) { create(:key, user: project.owner) }
- let(:key_id) { key.shell_id }
+ describe "#process_project_changes" do
+ before do
+ allow_any_instance_of(Gitlab::GitPostReceive).to receive(:identify).and_return(project.owner)
+ end
+ context "branches" do
+ let(:changes) { "123456 789012 refs/heads/tést" }
+
+ it "should call GitTagPushService" do
+ expect_any_instance_of(GitPushService).to receive(:execute).and_return(true)
+ expect_any_instance_of(GitTagPushService).not_to receive(:execute)
+ PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ end
+ end
+
+ context "tags" do
+ let(:changes) { "123456 789012 refs/tags/tag" }
+
+ it "should call GitTagPushService" do
+ expect_any_instance_of(GitPushService).not_to receive(:execute)
+ expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true)
+ PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ end
+ end
+
+ context "merge-requests" do
+ let(:changes) { "123456 789012 refs/merge-requests/123" }
+
+ it "should not call any of the services" do
+ expect_any_instance_of(GitPushService).not_to receive(:execute)
+ expect_any_instance_of(GitTagPushService).not_to receive(:execute)
+ PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ end
+ end
+ end
+
+ context "webhook" do
it "fetches the correct project" do
expect(Project).to receive(:find_with_namespace).with(project.path_with_namespace).and_return(project)
PostReceive.new.perform(pwd(project), key_id, base64_changes)
diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb
new file mode 100644
index 00000000000..f486e45ddad
--- /dev/null
+++ b/spec/workers/repository_check/batch_worker_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe RepositoryCheck::BatchWorker do
+ subject { described_class.new }
+
+ it 'prefers projects that have never been checked' do
+ projects = create_list(:project, 3)
+ projects[0].update_column(:last_repository_check_at, 4.months.ago)
+ projects[2].update_column(:last_repository_check_at, 3.months.ago)
+
+ expect(subject.perform).to eq(projects.values_at(1, 0, 2).map(&:id))
+ end
+
+ it 'sorts projects by last_repository_check_at' do
+ projects = create_list(:project, 3)
+ projects[0].update_column(:last_repository_check_at, 2.months.ago)
+ projects[1].update_column(:last_repository_check_at, 4.months.ago)
+ projects[2].update_column(:last_repository_check_at, 3.months.ago)
+
+ expect(subject.perform).to eq(projects.values_at(1, 2, 0).map(&:id))
+ end
+
+ it 'excludes projects that were checked recently' do
+ projects = create_list(:project, 3)
+ projects[0].update_column(:last_repository_check_at, 2.days.ago)
+ projects[1].update_column(:last_repository_check_at, 2.months.ago)
+ projects[2].update_column(:last_repository_check_at, 3.days.ago)
+
+ expect(subject.perform).to eq([projects[1].id])
+ end
+
+ it 'does nothing when repository checks are disabled' do
+ create(:empty_project)
+ current_settings = double('settings', repository_checks_enabled: false)
+ expect(subject).to receive(:current_settings) { current_settings }
+
+ expect(subject.perform).to eq(nil)
+ end
+end
diff --git a/spec/workers/repository_check/clear_worker_spec.rb b/spec/workers/repository_check/clear_worker_spec.rb
new file mode 100644
index 00000000000..a3b70c74787
--- /dev/null
+++ b/spec/workers/repository_check/clear_worker_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe RepositoryCheck::ClearWorker do
+ it 'clears repository check columns' do
+ project = create(:empty_project)
+ project.update_columns(
+ last_repository_check_failed: true,
+ last_repository_check_at: Time.now,
+ )
+
+ described_class.new.perform
+ project.reload
+
+ expect(project.last_repository_check_failed).to be_nil
+ expect(project.last_repository_check_at).to be_nil
+ end
+end