summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorRegis <boudinot.regis@yahoo.com>2017-01-02 16:24:37 -0700
committerRegis <boudinot.regis@yahoo.com>2017-01-02 16:24:37 -0700
commit0a074f2e091d8b2f1bce49e50ecf69b667c62dc2 (patch)
tree314027556f06514278a4f83f35813c00b2d5418f /spec
parent588219352c99213d099aff72f32d6ad9ec4830d4 (diff)
parentde25604fbca2f7005754d821d571bbcb1cc510ac (diff)
downloadgitlab-ce-0a074f2e091d8b2f1bce49e50ecf69b667c62dc2.tar.gz
fix pipelines/index.html.haml merge conflict
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/dashboard/todos_controller_spec.rb37
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb32
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb30
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb22
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb22
-rw-r--r--spec/factories/lfs_objects.rb2
-rw-r--r--spec/factories/project_statistics.rb6
-rw-r--r--spec/features/admin/admin_groups_spec.rb10
-rw-r--r--spec/features/admin/admin_users_spec.rb17
-rw-r--r--spec/features/auto_deploy_spec.rb14
-rw-r--r--spec/features/boards/boards_spec.rb6
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb2
-rw-r--r--spec/features/groups_spec.rb13
-rw-r--r--spec/features/issuables/default_sort_order_spec.rb10
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb25
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb8
-rw-r--r--spec/features/merge_requests/closes_issues_spec.rb4
-rw-r--r--spec/features/merge_requests/merge_request_versions_spec.rb4
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb6
-rw-r--r--spec/features/milestones/milestones_spec.rb6
-rw-r--r--spec/features/projects/features_visibility_spec.rb11
-rw-r--r--spec/features/tags/master_creates_tag_spec.rb2
-rw-r--r--spec/features/u2f_spec.rb119
-rw-r--r--spec/helpers/storage_helper_spec.rb21
-rw-r--r--spec/javascripts/fixtures/project_title.html.haml2
-rw-r--r--spec/javascripts/project_title_spec.js1
-rw-r--r--spec/javascripts/u2f/authenticate_spec.js23
-rw-r--r--spec/lib/banzai/reference_parser/external_issue_parser_spec.rb12
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb19
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb2
-rw-r--r--spec/lib/gitlab/git_access_spec.rb40
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/migrations/remove_dot_git_from_usernames.rb29
-rw-r--r--spec/migrations/rename_reserved_project_names_spec.rb47
-rw-r--r--spec/models/ci/build_spec.rb26
-rw-r--r--spec/models/ci/pipeline_spec.rb13
-rw-r--r--spec/models/concerns/issuable_spec.rb39
-rw-r--r--spec/models/deploy_key_spec.rb14
-rw-r--r--spec/models/group_spec.rb11
-rw-r--r--spec/models/key_spec.rb14
-rw-r--r--spec/models/lfs_objects_project_spec.rb36
-rw-r--r--spec/models/merge_request_spec.rb10
-rw-r--r--spec/models/namespace_spec.rb45
-rw-r--r--spec/models/project_spec.rb21
-rw-r--r--spec/models/project_statistics_spec.rb160
-rw-r--r--spec/policies/group_policy_spec.rb66
-rw-r--r--spec/requests/api/groups_spec.rb33
-rw-r--r--spec/requests/api/helpers_spec.rb4
-rw-r--r--spec/requests/api/projects_spec.rb56
-rw-r--r--spec/requests/api/settings_spec.rb3
-rw-r--r--spec/requests/git_http_spec.rb16
-rw-r--r--spec/routing/admin_routing_spec.rb10
-rw-r--r--spec/services/git_push_service_spec.rb4
-rw-r--r--spec/services/groups/create_service_spec.rb31
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb12
-rw-r--r--spec/services/issues/create_service_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb11
-rw-r--r--spec/services/merge_requests/create_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_request_diff_cache_service_spec.rb1
-rw-r--r--spec/services/notes/slash_commands_service_spec.rb2
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb37
-rw-r--r--spec/support/fake_u2f_device.rb3
-rw-r--r--spec/support/features/issuable_slash_commands_shared_examples.rb22
-rw-r--r--spec/support/services/issuable_create_service_shared_examples.rb52
-rw-r--r--spec/support/services/issuable_create_service_slash_commands_shared_examples.rb4
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb52
-rw-r--r--spec/workers/project_cache_worker_spec.rb42
69 files changed, 1287 insertions, 175 deletions
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
new file mode 100644
index 00000000000..288984cfba9
--- /dev/null
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Dashboard::TodosController do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:todo_service) { TodoService.new }
+
+ describe 'GET #index' do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ context 'when using pagination' do
+ let(:last_page) { user.todos.page().total_pages }
+ let!(:issues) { create_list(:issue, 2, project: project, assignee: user) }
+
+ before do
+ issues.each { |issue| todo_service.new_issue(issue, user) }
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+ end
+
+ it 'redirects to last_page if page number is larger than number of pages' do
+ get :index, page: (last_page + 1).to_param
+
+ expect(response).to redirect_to(dashboard_todos_path(page: last_page))
+ end
+
+ it 'redirects to correspondent page' do
+ get :index, page: last_page
+
+ expect(assigns(:todos).current_page).to eq(last_page)
+ expect(response).to have_http_status(200)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 3efef757ae2..f35c5d992d9 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -1,7 +1,7 @@
require 'rails_helper'
describe Projects::BlobController do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
let(:user) { create(:user) }
before do
@@ -84,5 +84,35 @@ describe Projects::BlobController do
end
end
end
+
+ context 'when user has forked project' do
+ let(:guest) { create(:user) }
+ let!(:forked_project) { Projects::ForkService.new(project, guest).execute }
+ let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, source_branch: "fork-test-1", target_branch: "master") }
+
+ before { sign_in(guest) }
+
+ it "redirects to forked project new merge request" do
+ default_params[:target_branch] = "fork-test-1"
+ default_params[:create_merge_request] = 1
+
+ allow_any_instance_of(Files::UpdateService).to receive(:commit).and_return(:success)
+
+ put :update, default_params
+
+ expect(response).to redirect_to(
+ new_namespace_project_merge_request_path(
+ forked_project.namespace,
+ forked_project,
+ merge_request: {
+ source_project_id: forked_project.id,
+ target_project_id: project.id,
+ source_branch: "fork-test-1",
+ target_branch: "master"
+ }
+ )
+ )
+ end
+ end
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index dbe5ddccbcf..e2321f2034b 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -52,6 +52,36 @@ describe Projects::IssuesController do
expect(response).to have_http_status(404)
end
end
+
+ context 'with page param' do
+ let(:last_page) { project.issues.page().total_pages }
+ let!(:issue_list) { create_list(:issue, 2, project: project) }
+
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+ end
+
+ it 'redirects to last_page if page number is larger than number of pages' do
+ get :index,
+ namespace_id: project.namespace.path.to_param,
+ project_id: project.path.to_param,
+ page: (last_page + 1).to_param
+
+ expect(response).to redirect_to(namespace_project_issues_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope]))
+ end
+
+ it 'redirects to specified page' do
+ get :index,
+ namespace_id: project.namespace.path.to_param,
+ project_id: project.path.to_param,
+ page: last_page.to_param
+
+ expect(assigns(:issues).current_page).to eq(last_page)
+ expect(response).to have_http_status(200)
+ end
+ end
end
describe 'GET #new' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 440b897ddc6..2a411d78395 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -127,11 +127,29 @@ describe Projects::MergeRequestsController do
end
describe 'GET index' do
- def get_merge_requests
+ def get_merge_requests(page = nil)
get :index,
namespace_id: project.namespace.to_param,
project_id: project.to_param,
- state: 'opened'
+ state: 'opened', page: page.to_param
+ end
+
+ context 'when page param' do
+ let(:last_page) { project.merge_requests.page().total_pages }
+ let!(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
+
+ it 'redirects to last_page if page number is larger than number of pages' do
+ get_merge_requests(last_page + 1)
+
+ expect(response).to redirect_to(namespace_project_merge_requests_path(page: last_page, state: controller.params[:state], scope: controller.params[:scope]))
+ end
+
+ it 'redirects to specified page' do
+ get_merge_requests(last_page)
+
+ expect(assigns(:merge_requests).current_page).to eq(last_page)
+ expect(response).to have_http_status(200)
+ end
end
context 'when filtering by opened state' do
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index 72a3ebf2ebd..32b0e42c3cd 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -11,6 +11,28 @@ describe Projects::SnippetsController do
end
describe 'GET #index' do
+ context 'when page param' do
+ let(:last_page) { project.snippets.page().total_pages }
+ let!(:project_snippet) { create(:project_snippet, :public, project: project, author: user) }
+
+ it 'redirects to last_page if page number is larger than number of pages' do
+ get :index,
+ namespace_id: project.namespace.path,
+ project_id: project.path, page: (last_page + 1).to_param
+
+ expect(response).to redirect_to(namespace_project_snippets_path(page: last_page))
+ end
+
+ it 'redirects to specified page' do
+ get :index,
+ namespace_id: project.namespace.path,
+ project_id: project.path, page: last_page.to_param
+
+ expect(assigns(:snippets).current_page).to eq(last_page)
+ expect(response).to have_http_status(200)
+ end
+ end
+
context 'when the project snippet is private' do
let!(:project_snippet) { create(:project_snippet, :private, project: project, author: user) }
diff --git a/spec/factories/lfs_objects.rb b/spec/factories/lfs_objects.rb
index a81645acd2b..477fab9e964 100644
--- a/spec/factories/lfs_objects.rb
+++ b/spec/factories/lfs_objects.rb
@@ -2,7 +2,7 @@ include ActionDispatch::TestProcess
FactoryGirl.define do
factory :lfs_object do
- oid "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80"
+ sequence(:oid) { |n| "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a%05x" % n }
size 499013
end
diff --git a/spec/factories/project_statistics.rb b/spec/factories/project_statistics.rb
new file mode 100644
index 00000000000..72d43096216
--- /dev/null
+++ b/spec/factories/project_statistics.rb
@@ -0,0 +1,6 @@
+FactoryGirl.define do
+ factory :project_statistics do
+ project { create :project }
+ namespace { project.namespace }
+ end
+end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index 0aa01fc499a..9c19db6b420 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -17,6 +17,16 @@ feature 'Admin Groups', feature: true do
end
end
+ describe 'show a group' do
+ scenario 'shows the group' do
+ group = create(:group, :private)
+
+ visit admin_group_path(group)
+
+ expect(page).to have_content("Group: #{group.name}")
+ end
+ end
+
describe 'group edit' do
scenario 'shows the visibility level radio populated with the group visibility_level value' do
group = create(:group, :private)
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index e31325ce47b..55ffc6761f8 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Admin::Users", feature: true do
+ include WaitForAjax
+
before { login_as :admin }
describe "GET /admin/users" do
@@ -252,5 +254,20 @@ describe "Admin::Users", feature: true do
end
expect(page).to have_content @project.name
end
+
+ it 'shows the group access level' do
+ within(:css, '.append-bottom-default + .panel') do
+ expect(page).to have_content 'Developer'
+ end
+ end
+
+ it 'allows group membership to be revoked', js: true do
+ page.within(first('.group_member')) do
+ find('.btn-remove').click
+ end
+ wait_for_ajax
+
+ expect(page).not_to have_selector('.group_member')
+ end
end
end
diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb
index 92f1ab90881..ea7a97d1d4f 100644
--- a/spec/features/auto_deploy_spec.rb
+++ b/spec/features/auto_deploy_spec.rb
@@ -26,7 +26,7 @@ describe 'Auto deploy' do
it 'does not show a button to set up auto deploy' do
visit namespace_project_path(project.namespace, project)
- expect(page).to have_no_content('Set up autodeploy')
+ expect(page).to have_no_content('Set up auto deploy')
end
end
@@ -37,11 +37,11 @@ describe 'Auto deploy' do
end
it 'shows a button to set up auto deploy' do
- expect(page).to have_link('Set up autodeploy')
+ expect(page).to have_link('Set up auto deploy')
end
- it 'includes Kubernetes as an available template', js: true do
- click_link 'Set up autodeploy'
+ it 'includes OpenShift as an available template', js: true do
+ click_link 'Set up auto deploy'
click_button 'Choose a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do
@@ -49,8 +49,8 @@ describe 'Auto deploy' do
end
end
- it 'creates a merge request using "autodeploy" branch', js: true do
- click_link 'Set up autodeploy'
+ it 'creates a merge request using "auto-deploy" branch', js: true do
+ click_link 'Set up auto deploy'
click_button 'Choose a GitLab CI Yaml template'
within '.gitlab-ci-yml-selector' do
click_on 'OpenShift'
@@ -58,7 +58,7 @@ describe 'Auto deploy' do
wait_for_ajax
click_button 'Commit Changes'
- expect(page).to have_content('New Merge Request From autodeploy into master')
+ expect(page).to have_content('New Merge Request From auto-deploy into master')
end
end
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 973d5b286e9..bfac5a1b8ab 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -109,7 +109,7 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'search backlog list' do
- page.within('#js-boards-seach') do
+ page.within('#js-boards-search') do
find('.form-control').set(issue1.title)
end
@@ -122,7 +122,7 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'search done list' do
- page.within('#js-boards-seach') do
+ page.within('#js-boards-search') do
find('.form-control').set(issue8.title)
end
@@ -135,7 +135,7 @@ describe 'Issue Boards', feature: true, js: true do
end
it 'search list' do
- page.within('#js-boards-seach') do
+ page.within('#js-boards-search') do
find('.form-control').set(issue5.title)
end
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index 44dfc2dff45..dc9d09fa396 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -6,7 +6,7 @@ feature 'Tooltips on .timeago dates', feature: true, js: true do
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') }
+ let(:expected_format) { created_date.strftime('%b %-d, %Y %l:%M%P') }
context 'on the activity tab' do
before do
diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb
index 4b19886274e..a515c92db37 100644
--- a/spec/features/groups_spec.rb
+++ b/spec/features/groups_spec.rb
@@ -107,4 +107,17 @@ feature 'Group', feature: true do
expect(page).to have_css('.group-home-desc a[rel]')
end
end
+
+ describe 'group page with nested groups', js: true do
+ let!(:group) { create(:group) }
+ let!(:nested_group) { create(:group, parent: group) }
+ let!(:path) { group_path(group) }
+
+ it 'has nested groups tab with nested groups inside' do
+ visit path
+ click_link 'Subgroups'
+
+ expect(page).to have_content(nested_group.full_name)
+ end
+ end
end
diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb
index 9a2b879e789..73553f97d6f 100644
--- a/spec/features/issuables/default_sort_order_spec.rb
+++ b/spec/features/issuables/default_sort_order_spec.rb
@@ -180,16 +180,10 @@ describe 'Projects > Issuables > Default sort order', feature: true do
end
def visit_merge_requests_with_state(project, state)
- visit_merge_requests project
- visit_issuables_with_state state
+ visit_merge_requests project, state: state
end
def visit_issues_with_state(project, state)
- visit_issues project
- visit_issuables_with_state state
- end
-
- def visit_issuables_with_state(state)
- within('.issues-state-filters') { find("span", text: state.titleize).click }
+ visit_issues project, state: state
end
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index d0294908d2c..82c9bd0e6e6 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -47,7 +47,19 @@ feature 'GFM autocomplete', feature: true, js: true do
expect_to_wrap(true, label_item, note, label.title)
end
- it "does not show drpdown when preceded with a special character" do
+ it "shows dropdown after a new line" do
+ note = find('#note_note')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('test')
+ note.native.send_keys(:enter)
+ note.native.send_keys(:enter)
+ note.native.send_keys('@')
+ end
+
+ expect(page).to have_selector('.atwho-container')
+ end
+
+ it "does not show dropdown when preceded with a special character" do
note = find('#note_note')
page.within '.timeline-content-form' do
note.native.send_keys('')
@@ -65,6 +77,17 @@ feature 'GFM autocomplete', feature: true, js: true do
expect(page).to have_selector('.atwho-container', visible: false)
end
+ it "does not throw an error if no labels exist" do
+ note = find('#note_note')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('')
+ note.native.send_keys('~')
+ note.click
+ end
+
+ expect(page).to have_selector('.atwho-container', visible: false)
+ end
+
it 'doesn\'t wrap for assignee values' do
note = find('#note_note')
page.within '.timeline-content-form' do
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index 3f2da1c380c..31f75512f4a 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -30,7 +30,7 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
write_note("/due 2016-08-28")
expect(page).not_to have_content '/due 2016-08-28'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
issue.reload
@@ -51,7 +51,7 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
write_note("/due 2016-08-28")
expect(page).to have_content '/due 2016-08-28'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
issue.reload
@@ -70,7 +70,7 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
write_note("/remove_due_date")
expect(page).not_to have_content '/remove_due_date'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
issue.reload
@@ -91,7 +91,7 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
write_note("/remove_due_date")
expect(page).to have_content '/remove_due_date'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
issue.reload
diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb
index dc32c8f7373..c73065cdce1 100644
--- a/spec/features/merge_requests/closes_issues_spec.rb
+++ b/spec/features/merge_requests/closes_issues_spec.rb
@@ -41,7 +41,7 @@ feature 'Merge Request closing issues message', feature: true do
let(:merge_request_description) { "Description\n\nRefers to #{issue_1.to_reference} and #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Issues #{issue_1.to_reference} and #{issue_2.to_reference} are mentioned but will not closed.")
+ expect(page).to have_content("Issues #{issue_1.to_reference} and #{issue_2.to_reference} are mentioned but will not be closed.")
end
end
@@ -49,7 +49,7 @@ feature 'Merge Request closing issues message', feature: true do
let(:merge_request_description) { "Description\n\ncloses #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" }
it 'does not display closing issue message' do
- expect(page).to have_content("Accepting this merge request will close issue #{issue_1.to_reference}. Issue #{issue_2.to_reference} is mentioned but will not closed.")
+ expect(page).to have_content("Accepting this merge request will close issue #{issue_1.to_reference}. Issue #{issue_2.to_reference} is mentioned but will not be closed.")
end
end
end
diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb
index 09451f41de4..cd2272dd38f 100644
--- a/spec/features/merge_requests/merge_request_versions_spec.rb
+++ b/spec/features/merge_requests/merge_request_versions_spec.rb
@@ -24,7 +24,7 @@ feature 'Merge Request versions', js: true, feature: true do
before do
page.within '.mr-version-dropdown' do
find('.btn-default').click
- click_link 'version 1'
+ find(:link, 'version 1').trigger('click')
end
end
@@ -45,7 +45,7 @@ feature 'Merge Request versions', js: true, feature: true do
before do
page.within '.mr-version-compare-dropdown' do
find('.btn-default').click
- click_link 'version 1'
+ find(:link, 'version 1').trigger('click')
end
end
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index 7b8af555f0e..b1b3a47a1ce 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -31,7 +31,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
write_note("/wip")
expect(page).not_to have_content '/wip'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(merge_request.reload.work_in_progress?).to eq true
end
@@ -42,7 +42,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
write_note("/wip")
expect(page).not_to have_content '/wip'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(merge_request.reload.work_in_progress?).to eq false
end
@@ -61,7 +61,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do
write_note("/wip")
expect(page).not_to have_content '/wip'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
expect(merge_request.reload.work_in_progress?).to eq false
end
diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb
index 8b603f51545..aadd72a9f8e 100644
--- a/spec/features/milestones/milestones_spec.rb
+++ b/spec/features/milestones/milestones_spec.rb
@@ -1,6 +1,8 @@
require 'rails_helper'
describe 'Milestone draggable', feature: true, js: true do
+ include WaitForAjax
+
let(:milestone) { create(:milestone, project: project, title: 8.14) }
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
@@ -74,6 +76,8 @@ describe 'Milestone draggable', feature: true, js: true do
visit namespace_project_milestone_path(project.namespace, project, milestone)
issue.drag_to(issue_target)
+
+ wait_for_ajax
end
def create_and_drag_merge_request(params = {})
@@ -82,5 +86,7 @@ describe 'Milestone draggable', feature: true, js: true do
visit namespace_project_milestone_path(project.namespace, project, milestone)
page.find("a[href='#tab-merge-requests']").click
merge_request.drag_to(merge_request_target)
+
+ wait_for_ajax
end
end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index 3bb33394be7..9079350186d 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -42,6 +42,17 @@ describe 'Edit Project Settings', feature: true do
end
end
+ context "When external issue tracker is enabled" do
+ it "does not hide issues tab" do
+ project.project_feature.update(issues_access_level: ProjectFeature::DISABLED)
+ allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new)
+
+ visit namespace_project_path(project.namespace, project)
+
+ expect(page).to have_selector(".shortcuts-issues")
+ end
+ end
+
context "pipelines subtabs" do
it "shows builds when enabled" do
visit namespace_project_pipelines_path(project.namespace, project)
diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb
index 08a97085a9c..ca25c696f75 100644
--- a/spec/features/tags/master_creates_tag_spec.rb
+++ b/spec/features/tags/master_creates_tag_spec.rb
@@ -34,7 +34,7 @@ feature 'Master creates tag', feature: true do
expect(current_path).to eq(
namespace_project_tag_path(project.namespace, project, 'v3.0'))
expect(page).to have_content 'v3.0'
- page.within 'pre.body' do
+ page.within 'pre.wrap' do
expect(page).to have_content "Awesome tag message\n\n- hello\n- world"
end
end
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index be21b403084..a8d00bb8e5a 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -45,12 +45,12 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
it 'allows registering a new device with a name' do
visit profile_account_path
manage_two_factor_authentication
- expect(page.body).to match("You've already enabled two-factor authentication using mobile")
+ expect(page).to have_content("You've already enabled two-factor authentication using mobile")
u2f_device = register_u2f_device
- expect(page.body).to match(u2f_device.name)
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content(u2f_device.name)
+ expect(page).to have_content('Your U2F device was registered')
end
it 'allows registering more than one device' do
@@ -59,30 +59,30 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
# First device
manage_two_factor_authentication
first_device = register_u2f_device
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content('Your U2F device was registered')
# Second device
second_device = register_u2f_device
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content('Your U2F device was registered')
- expect(page.body).to match(first_device.name)
- expect(page.body).to match(second_device.name)
+ expect(page).to have_content(first_device.name)
+ expect(page).to have_content(second_device.name)
expect(U2fRegistration.count).to eq(2)
end
it 'allows deleting a device' do
visit profile_account_path
manage_two_factor_authentication
- expect(page.body).to match("You've already enabled two-factor authentication using mobile")
+ expect(page).to have_content("You've already enabled two-factor authentication using mobile")
first_u2f_device = register_u2f_device
second_u2f_device = register_u2f_device
click_on "Delete", match: :first
- expect(page.body).to match('Successfully deleted')
+ expect(page).to have_content('Successfully deleted')
expect(page.body).not_to match(first_u2f_device.name)
- expect(page.body).to match(second_u2f_device.name)
+ expect(page).to have_content(second_u2f_device.name)
end
end
@@ -91,7 +91,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
visit profile_account_path
manage_two_factor_authentication
u2f_device = register_u2f_device
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content('Your U2F device was registered')
logout
# Second user
@@ -100,7 +100,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
visit profile_account_path
manage_two_factor_authentication
register_u2f_device(u2f_device)
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content('Your U2F device was registered')
expect(U2fRegistration.count).to eq(2)
end
@@ -117,8 +117,8 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
click_on 'Register U2F Device'
expect(U2fRegistration.count).to eq(0)
- expect(page.body).to match("The form contains the following error")
- expect(page.body).to match("did not send a valid JSON response")
+ expect(page).to have_content("The form contains the following error")
+ expect(page).to have_content("did not send a valid JSON response")
end
it "allows retrying registration" do
@@ -130,12 +130,12 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
click_on 'Setup New U2F Device'
expect(page).to have_content('Your device was successfully set up')
click_on 'Register U2F Device'
- expect(page.body).to match("The form contains the following error")
+ expect(page).to have_content("The form contains the following error")
# Successful registration
register_u2f_device
- expect(page.body).to match('Your U2F device was registered')
+ expect(page).to have_content('Your U2F device was registered')
expect(U2fRegistration.count).to eq(1)
end
end
@@ -160,10 +160,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
login_with(user)
@u2f_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
- expect(page.body).to match('href="/users/sign_out"')
+
+ expect(page).to have_content('We heard back from your U2F device')
+ expect(page).to have_css('.sign-out-link', visible: false)
end
end
@@ -173,11 +172,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
login_with(user)
@u2f_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
- expect(page.body).to match('href="/users/sign_out"')
+ expect(page).to have_content('We heard back from your U2F device')
+ expect(page).to have_css('.sign-out-link', visible: false)
end
end
@@ -185,8 +182,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
login_with(user, remember: true)
@u2f_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
+ expect(page).to have_content('We heard back from your U2F device')
within 'div#js-authenticate-u2f' do
field = first('input#user_remember_me', visible: false)
@@ -208,11 +204,8 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
# Try authenticating user with the old U2F device
login_as(current_user)
@u2f_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
-
- expect(page.body).to match('Authentication via U2F device failed')
+ expect(page).to have_content('We heard back from your U2F device')
+ expect(page).to have_content('Authentication via U2F device failed')
end
end
@@ -229,11 +222,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
# Try authenticating user with the same U2F device
login_as(current_user)
@u2f_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
+ expect(page).to have_content('We heard back from your U2F device')
- expect(page.body).to match('href="/users/sign_out"')
+ expect(page).to have_css('.sign-out-link', visible: false)
end
end
end
@@ -243,11 +234,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
unregistered_device = FakeU2fDevice.new(page, FFaker::Name.first_name)
login_as(user)
unregistered_device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
+ expect(page).to have_content('We heard back from your U2F device')
- expect(page.body).to match('Authentication via U2F device failed')
+ expect(page).to have_content('Authentication via U2F device failed')
end
end
@@ -270,11 +259,9 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
[first_device, second_device].each do |device|
login_as(user)
device.respond_to_u2f_authentication
- click_on "Sign in via U2F device"
- expect(page.body).to match('We heard back from your U2F device')
- click_on "Authenticate via U2F Device"
+ expect(page).to have_content('We heard back from your U2F device')
- expect(page.body).to match('href="/users/sign_out"')
+ expect(page).to have_css('.sign-out-link', visible: false)
logout
end
@@ -299,4 +286,50 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
end
end
end
+
+ describe 'fallback code authentication' do
+ let(:user) { create(:user) }
+
+ def assert_fallback_ui(page)
+ expect(page).to have_button('Verify code')
+ expect(page).to have_css('#user_otp_attempt')
+ expect(page).not_to have_link('Sign in via 2FA code')
+ expect(page).not_to have_css('#js-authenticate-u2f')
+ end
+
+ before do
+ # Register and logout
+ login_as(user)
+ user.update_attribute(:otp_required_for_login, true)
+ visit profile_account_path
+ end
+
+ describe 'when no u2f device is registered' do
+ before do
+ logout
+ login_with(user)
+ end
+
+ it 'shows the fallback otp code UI' do
+ assert_fallback_ui(page)
+ end
+ end
+
+ describe 'when a u2f device is registered' do
+ before do
+ manage_two_factor_authentication
+ @u2f_device = register_u2f_device
+ logout
+ login_with(user)
+ end
+
+ it 'provides a button that shows the fallback otp code UI' do
+ expect(page).to have_link('Sign in via 2FA code')
+
+ click_link('Sign in via 2FA code')
+
+ assert_fallback_ui(page)
+ end
+ end
+ end
end
diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb
new file mode 100644
index 00000000000..4627a1e1872
--- /dev/null
+++ b/spec/helpers/storage_helper_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe StorageHelper do
+ describe '#storage_counter' do
+ it 'formats bytes to one decimal place' do
+ expect(helper.storage_counter(1.23.megabytes)).to eq '1.2 MB'
+ end
+
+ it 'does not add decimals for sizes < 1 MB' do
+ expect(helper.storage_counter(23.5.kilobytes)).to eq '24 KB'
+ end
+
+ it 'does not add decimals for zeroes' do
+ expect(helper.storage_counter(2.megabytes)).to eq '2 MB'
+ end
+
+ it 'uses commas as thousands separator' do
+ expect(helper.storage_counter(100_000_000_000_000_000)).to eq '90,949.5 TB'
+ end
+ end
+end
diff --git a/spec/javascripts/fixtures/project_title.html.haml b/spec/javascripts/fixtures/project_title.html.haml
index 4547feeb212..9d1f7877116 100644
--- a/spec/javascripts/fixtures/project_title.html.haml
+++ b/spec/javascripts/fixtures/project_title.html.haml
@@ -4,7 +4,7 @@
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" }
+ %i.fa.chevron-down.dropdown-toggle-caret.js-projects-dropdown-toggle{ "data-toggle" => "dropdown", "data-target" => ".header-content", "data-order-by" => "last_activity_at" }
.js-dropdown-menu-projects
.dropdown-menu.dropdown-select.dropdown-menu-projects
.dropdown-title
diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js
index bb802a4b5e3..216b77f37c0 100644
--- a/spec/javascripts/project_title_spec.js
+++ b/spec/javascripts/project_title_spec.js
@@ -26,6 +26,7 @@
var fakeAjaxResponse = function fakeAjaxResponse(req) {
var d;
expect(req.url).toBe('/api/v3/projects.json?simple=true');
+ expect(req.data).toEqual({ search: '', order_by: 'last_activity_at', per_page: 20 });
d = $.Deferred();
d.resolve(this.projects_data);
return d.promise();
diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js
index a8874ab12d3..064d18519ea 100644
--- a/spec/javascripts/u2f/authenticate_spec.js
+++ b/spec/javascripts/u2f/authenticate_spec.js
@@ -14,18 +14,19 @@
beforeEach(function() {
this.u2fDevice = new MockU2FDevice;
this.container = $("#js-authenticate-u2f");
- this.component = new U2FAuthenticate(this.container, {
- sign_requests: []
- }, "token");
+ this.component = new window.gl.U2FAuthenticate(
+ this.container,
+ '#js-login-u2f-form',
+ {
+ sign_requests: []
+ },
+ document.querySelector('#js-login-2fa-device'),
+ document.querySelector('.js-2fa-form')
+ );
return this.component.start();
});
it('allows authenticating via a U2F device', function() {
- var authenticatedMessage, deviceResponse, inProgressMessage, setupButton, setupMessage;
- setupButton = this.container.find("#js-login-u2f-device");
- setupMessage = this.container.find("p");
- expect(setupMessage.text()).toContain('Insert your security key');
- expect(setupButton.text()).toBe('Sign in via U2F device');
- setupButton.trigger('click');
+ var authenticatedMessage, deviceResponse, inProgressMessage;
inProgressMessage = this.container.find("p");
expect(inProgressMessage.text()).toContain("Trying to communicate with your device");
this.u2fDevice.respondToAuthenticateRequest({
@@ -33,7 +34,7 @@
});
authenticatedMessage = this.container.find("p");
deviceResponse = this.container.find('#js-device-response');
- expect(authenticatedMessage.text()).toContain("Click this button to authenticate with the GitLab server");
+ expect(authenticatedMessage.text()).toContain('We heard back from your U2F device. You have been authenticated.');
return expect(deviceResponse.val()).toBe('{"deviceData":"this is data from the device"}');
});
return describe("errors", function() {
@@ -62,7 +63,7 @@
deviceData: "this is data from the device"
});
authenticatedMessage = this.container.find("p");
- return expect(authenticatedMessage.text()).toContain("Click this button to authenticate with the GitLab server");
+ return expect(authenticatedMessage.text()).toContain("We heard back from your U2F device. You have been authenticated.");
});
});
});
diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
index 50a5d1a19ba..0af36776a54 100644
--- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb
@@ -12,7 +12,17 @@ describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do
context 'when the link has a data-issue attribute' do
before { link['data-external-issue'] = 123 }
- it_behaves_like "referenced feature visibility", "issues"
+ levels = [ProjectFeature::DISABLED, ProjectFeature::PRIVATE, ProjectFeature::ENABLED]
+
+ levels.each do |level|
+ it "creates reference when the feature is #{level}" do
+ project.project_feature.update(issues_access_level: level)
+
+ visible_nodes = subject.nodes_visible_to_user(user, [link])
+
+ expect(visible_nodes).to include(link)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index 2a680f03476..f2bc15d39d7 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -1,21 +1,30 @@
require 'spec_helper'
describe Gitlab::Diff::FileCollection::MergeRequestDiff do
- let(:merge_request) { create :merge_request }
+ let(:merge_request) { create(:merge_request) }
+ let(:diff_files) { described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files }
- it 'does not hightlight binary files' do
+ it 'does not highlight binary files' do
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => false))
expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
- described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files
+ diff_files
end
- it 'does not hightlight file if blob is not accessable' do
+ it 'does not highlight file if blob is not accessable' do
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
- described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files
+ diff_files
+ end
+
+ it 'does not files marked as undiffable in .gitattributes' do
+ allow_any_instance_of(Repository).to receive(:diffable?).and_return(false)
+
+ expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
+
+ diff_files
end
end
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index c7a0139d32a..28698e89c33 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -88,8 +88,6 @@ describe Gitlab::Email::ReplyParser, lib: true do
expect(test_parse_body(fixture_file("emails/inline_reply.eml"))).
to eq(
<<-BODY.strip_heredoc.chomp
- On Wed, Oct 8, 2014 at 11:12 AM, techAPJ <info@unconfigured.discourse.org> wrote:
-
> techAPJ <https://meta.discourse.org/users/techapj>
> November 28
>
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index f1d0a190002..44b84afde47 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -50,7 +50,7 @@ describe Gitlab::GitAccess, lib: true do
end
end
- describe 'download_access_check' do
+ describe '#check_download_access!' do
subject { access.check('git-upload-pack', '_any') }
describe 'master permissions' do
@@ -82,7 +82,7 @@ describe Gitlab::GitAccess, lib: true do
end
end
- describe 'without acccess to project' do
+ describe 'without access to project' do
context 'pull code' do
it { expect(subject.allowed?).to be_falsey }
end
@@ -112,7 +112,7 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'deploy key permissions' do
- let(:key) { create(:deploy_key) }
+ let(:key) { create(:deploy_key, user: user) }
let(:actor) { key }
context 'pull code' do
@@ -136,7 +136,7 @@ describe Gitlab::GitAccess, lib: true do
end
context 'from private project' do
- let(:project) { create(:project, :internal) }
+ let(:project) { create(:project, :private) }
it { expect(subject).not_to be_allowed }
end
@@ -183,7 +183,7 @@ describe Gitlab::GitAccess, lib: true do
end
end
- describe 'push_access_check' do
+ describe '#check_push_access!' do
before { merge_into_protected_branch }
let(:unprotected_branch) { FFaker::Internet.user_name }
@@ -231,7 +231,7 @@ describe Gitlab::GitAccess, lib: true do
permissions_matrix[role].each do |action, allowed|
context action do
- subject { access.push_access_check(changes[action]) }
+ subject { access.send(:check_push_access!, changes[action]) }
it { expect(subject.allowed?).to allowed ? be_truthy : be_falsey }
end
end
@@ -353,13 +353,13 @@ describe Gitlab::GitAccess, lib: true do
end
end
- shared_examples 'can not push code' do
+ shared_examples 'pushing code' do |can|
subject { access.check('git-receive-pack', '_any') }
context 'when project is authorized' do
before { authorize }
- it { expect(subject).not_to be_allowed }
+ it { expect(subject).public_send(can, be_allowed) }
end
context 'when unauthorized' do
@@ -386,7 +386,7 @@ describe Gitlab::GitAccess, lib: true do
describe 'build authentication abilities' do
let(:authentication_abilities) { build_authentication_abilities }
- it_behaves_like 'can not push code' do
+ it_behaves_like 'pushing code', :not_to do
def authorize
project.team << [user, :reporter]
end
@@ -394,12 +394,26 @@ describe Gitlab::GitAccess, lib: true do
end
describe 'deploy key permissions' do
- let(:key) { create(:deploy_key) }
+ let(:key) { create(:deploy_key, user: user, can_push: can_push) }
let(:actor) { key }
- it_behaves_like 'can not push code' do
- def authorize
- key.projects << project
+ context 'when deploy_key can push' do
+ let(:can_push) { true }
+
+ it_behaves_like 'pushing code', :to do
+ def authorize
+ key.projects << project
+ end
+ end
+ end
+
+ context 'when deploy_key cannot push' do
+ let(:can_push) { false }
+
+ it_behaves_like 'pushing code', :not_to do
+ def authorize
+ key.projects << project
+ end
end
end
end
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 578db51631e..a5d172233cc 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -27,7 +27,7 @@ describe Gitlab::GitAccessWiki, lib: true do
['6f6d7e7ed 570e7b2ab refs/heads/master']
end
- describe '#download_access_check' do
+ describe '#access_check_download!' do
subject { access.check('git-upload-pack', '_any') }
before do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index f420d71dee2..ceed9c942c1 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -192,6 +192,7 @@ project:
- authorized_users
- project_authorizations
- route
+- statistics
award_emoji:
- awardable
- user
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 78d6b2c5032..ac26c831fd0 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -247,6 +247,7 @@ DeployKey:
- type
- fingerprint
- public
+- can_push
Service:
- id
- type
diff --git a/spec/migrations/remove_dot_git_from_usernames.rb b/spec/migrations/remove_dot_git_from_usernames.rb
new file mode 100644
index 00000000000..1b1d2adc463
--- /dev/null
+++ b/spec/migrations/remove_dot_git_from_usernames.rb
@@ -0,0 +1,29 @@
+# encoding: utf-8
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20161226122833_remove_dot_git_from_usernames.rb')
+
+describe RemoveDotGitFromUsernames do
+ let(:user) { create(:user) }
+
+ describe '#up' do
+ let(:migration) { described_class.new }
+
+ before do
+ namespace = user.namespace
+ namespace.path = 'test.git'
+ namespace.save!(validate: false)
+
+ user.username = 'test.git'
+ user.save!(validate: false)
+ end
+
+ it 'renames user with .git in username' do
+ migration.up
+
+ expect(user.reload.username).to eq('test_git')
+ expect(user.namespace.reload.path).to eq('test_git')
+ expect(user.namespace.route.path).to eq('test_git')
+ end
+ end
+end
diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb
new file mode 100644
index 00000000000..4fb7ed36884
--- /dev/null
+++ b/spec/migrations/rename_reserved_project_names_spec.rb
@@ -0,0 +1,47 @@
+# encoding: utf-8
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20161221153951_rename_reserved_project_names.rb')
+
+# This migration uses multiple threads, and thus different transactions. This
+# means data created in this spec may not be visible to some threads. To work
+# around this we use the TRUNCATE cleaning strategy.
+describe RenameReservedProjectNames, truncate: true do
+ let(:migration) { described_class.new }
+ let!(:project) { create(:empty_project) }
+
+ before do
+ project.path = 'projects'
+ project.save!(validate: false)
+ end
+
+ describe '#up' do
+ context 'when project repository exists' do
+ before { project.create_repository }
+
+ context 'when no exception is raised' do
+ it 'renames project with reserved names' do
+ migration.up
+
+ expect(project.reload.path).to eq('projects0')
+ end
+ end
+
+ context 'when exception is raised during rename' do
+ before do
+ allow(project).to receive(:rename_repo).and_raise(StandardError)
+ end
+
+ it 'captures exception from project rename' do
+ expect { migration.up }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when project repository does not exist' do
+ it 'does not raise error' do
+ expect { migration.up }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index a7e90c8a381..7e1d1126b97 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -85,4 +85,30 @@ describe Ci::Build, models: true do
it { expect(build.trace_file_path).to eq(build.old_path_to_trace) }
end
end
+
+ describe '#update_project_statistics' do
+ let!(:build) { create(:ci_build, artifacts_size: 23) }
+
+ it 'updates project statistics when the artifact size changes' do
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(build.project_id, [], [:build_artifacts_size])
+
+ build.artifacts_size = 42
+ build.save!
+ end
+
+ it 'does not update project statistics when the artifact size stays the same' do
+ expect(ProjectCacheWorker).not_to receive(:perform_async)
+
+ build.name = 'changed'
+ build.save!
+ end
+
+ it 'updates project statistics when the build is destroyed' do
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(build.project_id, [], [:build_artifacts_size])
+
+ build.destroy
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 79341d43c08..d1aee27057a 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -464,6 +464,19 @@ describe Ci::Pipeline, models: true do
end
end
+ describe '.latest_successful_for' do
+ include_context 'with some outdated pipelines'
+
+ let!(:latest_successful_pipeline) do
+ create_pipeline(:success, 'ref', 'D')
+ end
+
+ it 'returns the latest successful pipeline' do
+ expect(described_class.latest_successful_for('ref')).
+ to eq(latest_successful_pipeline)
+ end
+ end
+
describe '#status' do
let!(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') }
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 4fa06a8c60a..1078c959419 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -44,6 +44,45 @@ describe Issue, "Issuable" do
it { expect(described_class).to respond_to(:assigned) }
end
+ describe "before_save" do
+ describe "#update_cache_counts" do
+ context "when previous assignee exists" do
+ before do
+ assignee = create(:user)
+ issue.project.team << [assignee, :developer]
+ issue.update(assignee: assignee)
+ end
+
+ it "updates cache counts for new assignee" do
+ user = create(:user)
+
+ expect(user).to receive(:update_cache_counts)
+
+ issue.update(assignee: user)
+ end
+
+ it "updates cache counts for previous assignee" do
+ old_assignee = issue.assignee
+ allow(User).to receive(:find_by_id).with(old_assignee.id).and_return(old_assignee)
+
+ expect(old_assignee).to receive(:update_cache_counts)
+
+ issue.update(assignee: nil)
+ end
+ end
+
+ context "when previous assignee does not exist" do
+ before{ issue.update(assignee: nil) }
+
+ it "updates cache count for the new assignee" do
+ expect_any_instance_of(User).to receive(:update_cache_counts)
+
+ issue.update(assignee: user)
+ end
+ end
+ end
+ end
+
describe ".search" do
let!(:searchable_issue) { create(:issue, title: "Searchable issue") }
diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb
index 93623e8e99b..8ef8218cf74 100644
--- a/spec/models/deploy_key_spec.rb
+++ b/spec/models/deploy_key_spec.rb
@@ -1,8 +1,22 @@
require 'spec_helper'
describe DeployKey, models: true do
+ include EmailHelpers
+
describe "Associations" do
it { is_expected.to have_many(:deploy_keys_projects) }
it { is_expected.to have_many(:projects) }
end
+
+ describe 'notification' do
+ let(:user) { create(:user) }
+
+ it 'does not send a notification' do
+ perform_enqueued_jobs do
+ create(:deploy_key, user: user)
+ end
+
+ should_not_email(user)
+ end
+ end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 7d5ecfbaa64..45fe927202b 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -277,4 +277,15 @@ describe Group, models: true do
it { is_expected.to be_valid }
it { expect(subject.parent).to be_kind_of(Group) }
end
+
+ describe '#members_with_parents' do
+ let!(:group) { create(:group, :nested) }
+ let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) }
+ let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }
+
+ it 'returns parents members' do
+ expect(group.members_with_parents).to include(developer)
+ expect(group.members_with_parents).to include(master)
+ end
+ end
end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 2a33d819138..7758b7ffa97 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Key, models: true do
+ include EmailHelpers
+
describe "Associations" do
it { is_expected.to belong_to(:user) }
end
@@ -96,4 +98,16 @@ describe Key, models: true do
expect(described_class.new(key: " #{valid_key} ").key).to eq(valid_key)
end
end
+
+ describe 'notification' do
+ let(:user) { create(:user) }
+
+ it 'sends a notification' do
+ perform_enqueued_jobs do
+ create(:key, user: user)
+ end
+
+ should_email(user)
+ end
+ end
end
diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb
new file mode 100644
index 00000000000..7bc278e350f
--- /dev/null
+++ b/spec/models/lfs_objects_project_spec.rb
@@ -0,0 +1,36 @@
+require 'spec_helper'
+
+describe LfsObjectsProject, models: true do
+ subject { create(:lfs_objects_project, project: project) }
+ let(:project) { create(:empty_project) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:lfs_object) }
+ end
+
+ describe 'validation' do
+ it { is_expected.to validate_presence_of(:lfs_object_id) }
+ it { is_expected.to validate_uniqueness_of(:lfs_object_id).scoped_to(:project_id).with_message("already exists in project") }
+
+ it { is_expected.to validate_presence_of(:project_id) }
+ end
+
+ describe '#update_project_statistics' do
+ it 'updates project statistics when the object is added' do
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(project.id, [], [:lfs_objects_size])
+
+ subject.save!
+ end
+
+ it 'updates project statistics when the object is removed' do
+ subject.save!
+
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(project.id, [], [:lfs_objects_size])
+
+ subject.destroy
+ end
+ end
+end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 5da00a8636a..646e6c6dbb3 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -283,12 +283,16 @@ describe MergeRequest, models: true do
end
describe '#issues_mentioned_but_not_closing' do
- it 'detects issues mentioned in description but not closed' do
- mentioned_issue = create(:issue, project: subject.project)
+ let(:closing_issue) { create :issue, project: subject.project }
+ let(:mentioned_issue) { create :issue, project: subject.project }
+
+ let(:commit) { double('commit', safe_message: "Fixes #{closing_issue.to_reference}") }
+ it 'detects issues mentioned in description but not closed' do
subject.project.team << [subject.author, :developer]
- subject.description = "Is related to #{mentioned_issue.to_reference}"
+ subject.description = "Is related to #{mentioned_issue.to_reference} and #{closing_issue.to_reference}"
+ allow(subject).to receive(:commits).and_return([commit])
allow(subject.project).to receive(:default_branch).
and_return(subject.target_branch)
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 9fd06bb6b23..600538ff5f4 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -4,6 +4,7 @@ describe Namespace, models: true do
let!(:namespace) { create(:namespace) }
it { is_expected.to have_many :projects }
+ it { is_expected.to have_many :project_statistics }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) }
@@ -57,6 +58,50 @@ describe Namespace, models: true do
end
end
+ describe '.with_statistics' do
+ let(:namespace) { create :namespace }
+
+ let(:project1) do
+ create(:empty_project,
+ namespace: namespace,
+ statistics: build(:project_statistics,
+ storage_size: 606,
+ repository_size: 101,
+ lfs_objects_size: 202,
+ build_artifacts_size: 303))
+ end
+
+ let(:project2) do
+ create(:empty_project,
+ namespace: namespace,
+ statistics: build(:project_statistics,
+ storage_size: 60,
+ repository_size: 10,
+ lfs_objects_size: 20,
+ build_artifacts_size: 30))
+ end
+
+ it "sums all project storage counters in the namespace" do
+ project1
+ project2
+ statistics = Namespace.with_statistics.find(namespace.id)
+
+ expect(statistics.storage_size).to eq 666
+ expect(statistics.repository_size).to eq 111
+ expect(statistics.lfs_objects_size).to eq 222
+ expect(statistics.build_artifacts_size).to eq 333
+ end
+
+ it "correctly handles namespaces without projects" do
+ statistics = Namespace.with_statistics.find(namespace.id)
+
+ expect(statistics.storage_size).to eq 0
+ expect(statistics.repository_size).to eq 0
+ expect(statistics.lfs_objects_size).to eq 0
+ expect(statistics.build_artifacts_size).to eq 0
+ end
+ end
+
describe '#move_dir' do
before do
@namespace = create :namespace
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 88d5d14f855..fb225eb7625 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -49,6 +49,7 @@ describe Project, models: true do
it { is_expected.to have_one(:gitlab_issue_tracker_service).dependent(:destroy) }
it { is_expected.to have_one(:external_wiki_service).dependent(:destroy) }
it { is_expected.to have_one(:project_feature).dependent(:destroy) }
+ it { is_expected.to have_one(:statistics).class_name('ProjectStatistics').dependent(:delete) }
it { is_expected.to have_one(:import_data).class_name('ProjectImportData').dependent(:destroy) }
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) }
@@ -1729,6 +1730,26 @@ describe Project, models: true do
end
end
+ describe '#update_project_statistics' do
+ let(:project) { create(:empty_project) }
+
+ it "is called after creation" do
+ expect(project.statistics).to be_a ProjectStatistics
+ expect(project.statistics).to be_persisted
+ end
+
+ it "copies the namespace_id" do
+ expect(project.statistics.namespace_id).to eq project.namespace_id
+ end
+
+ it "updates the namespace_id when changed" do
+ namespace = create(:namespace)
+ project.update(namespace: namespace)
+
+ expect(project.statistics.namespace_id).to eq namespace.id
+ end
+ end
+
def enable_lfs
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
end
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
new file mode 100644
index 00000000000..77403cc9eb0
--- /dev/null
+++ b/spec/models/project_statistics_spec.rb
@@ -0,0 +1,160 @@
+require 'rails_helper'
+
+describe ProjectStatistics, models: true do
+ let(:project) { create :empty_project }
+ let(:statistics) { project.statistics }
+
+ describe 'constants' do
+ describe 'STORAGE_COLUMNS' do
+ it 'is an array of symbols' do
+ expect(described_class::STORAGE_COLUMNS).to be_kind_of Array
+ expect(described_class::STORAGE_COLUMNS.map(&:class).uniq).to eq [Symbol]
+ end
+ end
+
+ describe 'STATISTICS_COLUMNS' do
+ it 'is an array of symbols' do
+ expect(described_class::STATISTICS_COLUMNS).to be_kind_of Array
+ expect(described_class::STATISTICS_COLUMNS.map(&:class).uniq).to eq [Symbol]
+ end
+
+ it 'includes all storage columns' do
+ expect(described_class::STATISTICS_COLUMNS & described_class::STORAGE_COLUMNS).to eq described_class::STORAGE_COLUMNS
+ end
+ end
+ end
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:namespace) }
+ end
+
+ describe 'statistics columns' do
+ it "support values up to 8 exabytes" do
+ statistics.update!(
+ commit_count: 8.exabytes - 1,
+ repository_size: 2.exabytes,
+ lfs_objects_size: 2.exabytes,
+ build_artifacts_size: 4.exabytes - 1,
+ )
+
+ statistics.reload
+
+ expect(statistics.commit_count).to eq(8.exabytes - 1)
+ expect(statistics.repository_size).to eq(2.exabytes)
+ expect(statistics.lfs_objects_size).to eq(2.exabytes)
+ expect(statistics.build_artifacts_size).to eq(4.exabytes - 1)
+ expect(statistics.storage_size).to eq(8.exabytes - 1)
+ end
+ end
+
+ describe '#total_repository_size' do
+ it "sums repository and LFS object size" do
+ statistics.repository_size = 2
+ statistics.lfs_objects_size = 3
+ statistics.build_artifacts_size = 4
+
+ expect(statistics.total_repository_size).to eq 5
+ end
+ end
+
+ describe '#refresh!' do
+ before do
+ allow(statistics).to receive(:update_commit_count)
+ allow(statistics).to receive(:update_repository_size)
+ allow(statistics).to receive(:update_lfs_objects_size)
+ allow(statistics).to receive(:update_build_artifacts_size)
+ allow(statistics).to receive(:update_storage_size)
+ end
+
+ context "without arguments" do
+ before do
+ statistics.refresh!
+ end
+
+ it "sums all counters" do
+ expect(statistics).to have_received(:update_commit_count)
+ expect(statistics).to have_received(:update_repository_size)
+ expect(statistics).to have_received(:update_lfs_objects_size)
+ expect(statistics).to have_received(:update_build_artifacts_size)
+ end
+ end
+
+ context "when passing an only: argument" do
+ before do
+ statistics.refresh! only: [:lfs_objects_size]
+ end
+
+ it "only updates the given columns" do
+ expect(statistics).to have_received(:update_lfs_objects_size)
+ expect(statistics).not_to have_received(:update_commit_count)
+ expect(statistics).not_to have_received(:update_repository_size)
+ expect(statistics).not_to have_received(:update_build_artifacts_size)
+ end
+ end
+ end
+
+ describe '#update_commit_count' do
+ before do
+ allow(project.repository).to receive(:commit_count).and_return(23)
+ statistics.update_commit_count
+ end
+
+ it "stores the number of commits in the repository" do
+ expect(statistics.commit_count).to eq 23
+ end
+ end
+
+ describe '#update_repository_size' do
+ before do
+ allow(project.repository).to receive(:size).and_return(12.megabytes)
+ statistics.update_repository_size
+ end
+
+ it "stores the size of the repository" do
+ expect(statistics.repository_size).to eq 12.megabytes
+ end
+ end
+
+ describe '#update_lfs_objects_size' do
+ let!(:lfs_object1) { create(:lfs_object, size: 23.megabytes) }
+ let!(:lfs_object2) { create(:lfs_object, size: 34.megabytes) }
+ let!(:lfs_objects_project1) { create(:lfs_objects_project, project: project, lfs_object: lfs_object1) }
+ let!(:lfs_objects_project2) { create(:lfs_objects_project, project: project, lfs_object: lfs_object2) }
+
+ before do
+ statistics.update_lfs_objects_size
+ end
+
+ it "stores the size of related LFS objects" do
+ expect(statistics.lfs_objects_size).to eq 57.megabytes
+ end
+ end
+
+ describe '#update_build_artifacts_size' do
+ let!(:pipeline) { create(:ci_pipeline, project: project) }
+ let!(:build1) { create(:ci_build, pipeline: pipeline, artifacts_size: 45.megabytes) }
+ let!(:build2) { create(:ci_build, pipeline: pipeline, artifacts_size: 56.megabytes) }
+
+ before do
+ statistics.update_build_artifacts_size
+ end
+
+ it "stores the size of related build artifacts" do
+ expect(statistics.build_artifacts_size).to eq 101.megabytes
+ end
+ end
+
+ describe '#update_storage_size' do
+ it "sums all storage counters" do
+ statistics.update!(
+ repository_size: 2,
+ lfs_objects_size: 3,
+ )
+
+ statistics.reload
+
+ expect(statistics.storage_size).to eq 5
+ end
+ end
+end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index a20ac303a53..5c34ff04152 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -105,4 +105,70 @@ describe GroupPolicy, models: true do
is_expected.to include(*owner_permissions)
end
end
+
+ describe 'private nested group inherit permissions' do
+ let(:nested_group) { create(:group, :private, parent: group) }
+
+ subject { described_class.abilities(current_user, nested_group).to_set }
+
+ context 'with no user' do
+ let(:current_user) { nil }
+
+ it do
+ is_expected.not_to include(:read_group)
+ is_expected.not_to include(*master_permissions)
+ is_expected.not_to include(*owner_permissions)
+ end
+ end
+
+ context 'guests' do
+ let(:current_user) { guest }
+
+ it do
+ is_expected.to include(:read_group)
+ is_expected.not_to include(*master_permissions)
+ is_expected.not_to include(*owner_permissions)
+ end
+ end
+
+ context 'reporter' do
+ let(:current_user) { reporter }
+
+ it do
+ is_expected.to include(:read_group)
+ is_expected.not_to include(*master_permissions)
+ is_expected.not_to include(*owner_permissions)
+ end
+ end
+
+ context 'developer' do
+ let(:current_user) { developer }
+
+ it do
+ is_expected.to include(:read_group)
+ is_expected.not_to include(*master_permissions)
+ is_expected.not_to include(*owner_permissions)
+ end
+ end
+
+ context 'master' do
+ let(:current_user) { master }
+
+ it do
+ is_expected.to include(:read_group)
+ is_expected.to include(*master_permissions)
+ is_expected.not_to include(*owner_permissions)
+ end
+ end
+
+ context 'owner' do
+ let(:current_user) { owner }
+
+ it do
+ is_expected.to include(:read_group)
+ is_expected.to include(*master_permissions)
+ is_expected.to include(*owner_permissions)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index cdeb965b413..0e8d6faea27 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -35,6 +35,14 @@ describe API::Groups, api: true do
expect(json_response.length).to eq(1)
expect(json_response.first['name']).to eq(group1.name)
end
+
+ it "does not include statistics" do
+ get api("/groups", user1), statistics: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include 'statistics'
+ end
end
context "when authenticated as admin" do
@@ -44,6 +52,31 @@ describe API::Groups, api: true do
expect(json_response).to be_an Array
expect(json_response.length).to eq(2)
end
+
+ it "does not include statistics by default" do
+ get api("/groups", admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include('statistics')
+ end
+
+ it "includes statistics if requested" do
+ attributes = {
+ storage_size: 702,
+ repository_size: 123,
+ lfs_objects_size: 234,
+ build_artifacts_size: 345,
+ }
+
+ project1.statistics.update!(attributes)
+
+ get api("/groups", admin), statistics: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['statistics']).to eq attributes.stringify_keys
+ end
end
context "when using skip_groups in request" do
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index c3d7ac3eef8..b8ee2293a33 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -396,7 +396,7 @@ describe API::Helpers, api: true do
%w[HEAD GET].each do |method_name|
context "method is #{method_name}" do
before do
- expect_any_instance_of(self.class).to receive(:route).and_return(double(route_method: method_name))
+ expect_any_instance_of(self.class).to receive(:route).and_return(double(request_method: method_name))
end
it 'does not raise an error' do
@@ -410,7 +410,7 @@ describe API::Helpers, api: true do
%w[POST PUT PATCH DELETE].each do |method_name|
context "method is #{method_name}" do
before do
- expect_any_instance_of(self.class).to receive(:route).and_return(double(route_method: method_name))
+ expect_any_instance_of(self.class).to receive(:route).and_return(double(request_method: method_name))
end
it 'calls authenticate!' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 8304c408064..f5788d15f93 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -49,7 +49,7 @@ describe API::Projects, api: true do
end
end
- context 'when authenticated' do
+ context 'when authenticated as regular user' do
it 'returns an array of projects' do
get api('/projects', user)
expect(response).to have_http_status(200)
@@ -172,6 +172,22 @@ describe API::Projects, api: true do
end
end
end
+
+ it "does not include statistics by default" do
+ get api('/projects/all', admin)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include('statistics')
+ end
+
+ it "includes statistics if requested" do
+ get api('/projects/all', admin), statistics: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first).to include 'statistics'
+ end
end
end
@@ -196,6 +212,32 @@ describe API::Projects, api: true do
expect(json_response.first['name']).to eq(project4.name)
expect(json_response.first['owner']['username']).to eq(user4.username)
end
+
+ it "does not include statistics by default" do
+ get api('/projects/owned', user4)
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include('statistics')
+ end
+
+ it "includes statistics if requested" do
+ attributes = {
+ commit_count: 23,
+ storage_size: 702,
+ repository_size: 123,
+ lfs_objects_size: 234,
+ build_artifacts_size: 345,
+ }
+
+ project4.statistics.update!(attributes)
+
+ get api('/projects/owned', user4), statistics: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ expect(json_response.first['statistics']).to eq attributes.stringify_keys
+ end
end
end
@@ -630,6 +672,18 @@ describe API::Projects, api: true do
expect(json_response['name']).to eq(project.name)
end
+ it 'exposes namespace fields' do
+ get api("/projects/#{project.id}", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['namespace']).to eq({
+ 'id' => user.namespace.id,
+ 'name' => user.namespace.name,
+ 'path' => user.namespace.path,
+ 'kind' => user.namespace.kind,
+ })
+ end
+
describe 'permissions' do
context 'all projects' do
before { project.team << [user, :master] }
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 9a8d633d657..ad9d8a25af4 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -44,8 +44,7 @@ describe API::Settings, 'Settings', api: true do
put api("/application/settings", admin), koding_enabled: true
expect(response).to have_http_status(400)
- expect(json_response['message']).to have_key('koding_url')
- expect(json_response['message']['koding_url']).to include "can't be blank"
+ expect(json_response['error']).to eq('koding_url is missing')
end
end
end
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index d71bb08c218..5abda28e26f 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -371,12 +371,26 @@ describe 'Git HTTP requests', lib: true do
shared_examples 'can download code only' do
it 'downloads get status 200' do
- clone_get "#{project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token
+ allow_any_instance_of(Repository).
+ to receive(:exists?).and_return(true)
+
+ clone_get "#{project.path_with_namespace}.git",
+ user: 'gitlab-ci-token', password: build.token
expect(response).to have_http_status(200)
expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
+ it 'downloads from non-existing repository and gets 403' do
+ allow_any_instance_of(Repository).
+ to receive(:exists?).and_return(false)
+
+ clone_get "#{project.path_with_namespace}.git",
+ user: 'gitlab-ci-token', password: build.token
+
+ expect(response).to have_http_status(403)
+ end
+
it 'uploads get status 403' do
push_get "#{project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 661b671301e..99c44bde151 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -122,12 +122,18 @@ describe Admin::HealthCheckController, "routing" do
end
describe Admin::GroupsController, "routing" do
+ let(:name) { 'complex.group-namegit' }
+
it "to #index" do
expect(get("/admin/groups")).to route_to('admin/groups#index')
end
it "to #show" do
- expect(get("/admin/groups/gitlab")).to route_to('admin/groups#show', id: 'gitlab')
- expect(get("/admin/groups/gitlab/subgroup")).to route_to('admin/groups#show', id: 'gitlab/subgroup')
+ expect(get("/admin/groups/#{name}")).to route_to('admin/groups#show', id: name)
+ expect(get("/admin/groups/#{name}/subgroup")).to route_to('admin/groups#show', id: "#{name}/subgroup")
+ end
+
+ it "to #edit" do
+ expect(get("/admin/groups/#{name}/edit")).to route_to('admin/groups#edit', id: name)
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 3303e808a9c..2a0f00ce937 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -583,7 +583,7 @@ describe GitPushService, services: true do
service.push_commits = [commit]
expect(ProjectCacheWorker).to receive(:perform_async).
- with(project.id, %i(readme))
+ with(project.id, %i(readme), %i(commit_count repository_size))
service.update_caches
end
@@ -596,7 +596,7 @@ describe GitPushService, services: true do
it 'does not flush any conditional caches' do
expect(ProjectCacheWorker).to receive(:perform_async).
- with(project.id, []).
+ with(project.id, [], %i(commit_count repository_size)).
and_call_original
service.update_caches
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index 71a0b8e2a12..14717a7455d 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -1,11 +1,12 @@
require 'spec_helper'
-describe Groups::CreateService, services: true do
- let!(:user) { create(:user) }
+describe Groups::CreateService, '#execute', services: true do
+ let!(:user) { create(:user) }
let!(:group_params) { { path: "group_path", visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
- describe "execute" do
- let!(:service) { described_class.new(user, group_params ) }
+ describe 'visibility level restrictions' do
+ let!(:service) { described_class.new(user, group_params) }
+
subject { service.execute }
context "create groups without restricted visibility level" do
@@ -14,7 +15,29 @@ describe Groups::CreateService, services: true do
context "cannot create group with restricted visibility level" do
before { allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
+
it { is_expected.not_to be_persisted }
end
end
+
+ describe 'creating subgroup' do
+ let!(:group) { create(:group) }
+ let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
+
+ subject { service.execute }
+
+ context 'as group owner' do
+ before { group.add_owner(user) }
+
+ it { is_expected.to be_persisted }
+ end
+
+ context 'as guest' do
+ it 'does not save group and returns an error' do
+ is_expected.not_to be_persisted
+ expect(subject.errors[:parent_id].first).to eq('manage access required to create subgroup')
+ expect(subject.parent_id).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index 5f3020b6525..0475f38fe5e 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -52,7 +52,10 @@ describe Issuable::BulkUpdateService, services: true do
context 'when the new assignee ID is a valid user' do
it 'succeeds' do
- result = bulk_update(issue, assignee_id: create(:user).id)
+ new_assignee = create(:user)
+ project.team << [new_assignee, :developer]
+
+ result = bulk_update(issue, assignee_id: new_assignee.id)
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(1)
@@ -60,15 +63,16 @@ describe Issuable::BulkUpdateService, services: true do
it 'updates the assignee to the use ID passed' do
assignee = create(:user)
+ project.team << [assignee, :developer]
expect { bulk_update(issue, assignee_id: assignee.id) }
.to change { issue.reload.assignee }.from(user).to(assignee)
end
end
- context 'when the new assignee ID is -1' do
- it 'unassigns the issues' do
- expect { bulk_update(issue, assignee_id: -1) }
+ context "when the new assignee ID is #{IssuableFinder::NONE}" do
+ it "unassigns the issues" do
+ expect { bulk_update(issue, assignee_id: IssuableFinder::NONE) }
.to change { issue.reload.assignee }.to(nil)
end
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 8bde61ee336..ac3834c32ff 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -135,6 +135,8 @@ describe Issues::CreateService, services: true do
end
end
+ it_behaves_like 'issuable create service'
+
it_behaves_like 'new issuable record that supports slash commands'
context 'for a merge request' do
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index eafbea46905..d83b09fd32c 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -142,6 +142,17 @@ describe Issues::UpdateService, services: true do
update_issue(confidential: true)
end
+
+ it 'does not update assignee_id with unauthorized users' do
+ project.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ update_issue(confidential: true)
+ non_member = create(:user)
+ original_assignee = issue.assignee
+
+ update_issue(assignee_id: non_member.id)
+
+ expect(issue.reload.assignee_id).to eq(original_assignee.id)
+ end
end
context 'todos' do
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index b8142889075..673c0bd6c9c 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -84,6 +84,8 @@ describe MergeRequests::CreateService, services: true do
end
end
+ it_behaves_like 'issuable create service'
+
context 'while saving references to issues that the created merge request closes' do
let(:first_issue) { create(:issue, project: project) }
let(:second_issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
index 05cdbe5287a..35804d41b46 100644
--- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
+++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
@@ -11,6 +11,7 @@ describe MergeRequests::MergeRequestDiffCacheService do
expect(Rails.cache).to receive(:read).with(cache_key).and_return({})
expect(Rails.cache).to receive(:write).with(cache_key, anything)
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => true))
+ allow_any_instance_of(Repository).to receive(:diffable?).and_return(true)
subject.execute(merge_request)
end
diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/slash_commands_service_spec.rb
index d1099884a02..960b5cd5e6f 100644
--- a/spec/services/notes/slash_commands_service_spec.rb
+++ b/spec/services/notes/slash_commands_service_spec.rb
@@ -5,6 +5,8 @@ describe Notes::SlashCommandsService, services: true do
let(:project) { create(:empty_project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
+
+ before { project.team << [assignee, :master] }
end
shared_examples 'note on noteable that does not support slash commands' do
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index 72c8f7cd8ec..1f6919151de 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -54,12 +54,37 @@ describe Users::RefreshAuthorizedProjectsService do
end
describe '#update_authorizations' do
- it 'does nothing when there are no rows to add and remove' do
- expect(user).not_to receive(:remove_project_authorizations)
- expect(ProjectAuthorization).not_to receive(:insert_authorizations)
- expect(user).not_to receive(:set_authorized_projects_column)
+ context 'when there are no rows to add and remove' do
+ it 'does not change authorizations' do
+ expect(user).not_to receive(:remove_project_authorizations)
+ expect(ProjectAuthorization).not_to receive(:insert_authorizations)
- service.update_authorizations([], [])
+ service.update_authorizations([], [])
+ end
+
+ context 'when the authorized projects column is not set' do
+ before do
+ user.update!(authorized_projects_populated: nil)
+ end
+
+ it 'populates the authorized projects column' do
+ service.update_authorizations([], [])
+
+ expect(user.authorized_projects_populated).to eq true
+ end
+ end
+
+ context 'when the authorized projects column is set' do
+ before do
+ user.update!(authorized_projects_populated: true)
+ end
+
+ it 'does nothing' do
+ expect(user).not_to receive(:set_authorized_projects_column)
+
+ service.update_authorizations([], [])
+ end
+ end
end
it 'removes authorizations that should be removed' do
@@ -84,7 +109,7 @@ describe Users::RefreshAuthorizedProjectsService do
it 'populates the authorized projects column' do
# make sure we start with a nil value no matter what the default in the
# factory may be.
- user.update(authorized_projects_populated: nil)
+ user.update!(authorized_projects_populated: nil)
service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]])
diff --git a/spec/support/fake_u2f_device.rb b/spec/support/fake_u2f_device.rb
index 8c407b867fe..a7605cd483a 100644
--- a/spec/support/fake_u2f_device.rb
+++ b/spec/support/fake_u2f_device.rb
@@ -5,7 +5,7 @@ class FakeU2fDevice
@page = page
@name = name
end
-
+
def respond_to_u2f_registration
app_id = @page.evaluate_script('gon.u2f.app_id')
challenges = @page.evaluate_script('gon.u2f.challenges')
@@ -28,6 +28,7 @@ class FakeU2fDevice
u2f.sign = function(appId, challenges, signRequests, callback) {
callback(#{json_response});
};
+ window.gl.u2fAuthenticate.start();
")
end
diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb
index 194620d0a68..a4713e53f63 100644
--- a/spec/support/features/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/features/issuable_slash_commands_shared_examples.rb
@@ -76,7 +76,7 @@ shared_examples 'issuable record that supports slash commands in its description
expect(page).not_to have_content '/assign @bob'
expect(page).not_to have_content '/label ~bug'
expect(page).not_to have_content '/milestone %"ASAP"'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
issuable.reload
@@ -97,7 +97,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/close")
expect(page).not_to have_content '/close'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(issuable.reload).to be_closed
end
@@ -114,7 +114,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/close")
expect(page).not_to have_content '/close'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
expect(issuable).to be_open
end
@@ -132,7 +132,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/reopen")
expect(page).not_to have_content '/reopen'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(issuable.reload).to be_open
end
@@ -149,7 +149,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/reopen")
expect(page).not_to have_content '/reopen'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
expect(issuable).to be_closed
end
@@ -162,7 +162,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/title Awesome new title")
expect(page).not_to have_content '/title'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(issuable.reload.title).to eq 'Awesome new title'
end
@@ -179,7 +179,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/title Awesome new title")
expect(page).not_to have_content '/title'
- expect(page).not_to have_content 'Your commands have been executed!'
+ expect(page).not_to have_content 'Commands applied'
expect(issuable.reload.title).not_to eq 'Awesome new title'
end
@@ -191,7 +191,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/todo")
expect(page).not_to have_content '/todo'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
todos = TodosFinder.new(master).execute
todo = todos.first
@@ -222,7 +222,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/done")
expect(page).not_to have_content '/done'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(todo.reload).to be_done
end
@@ -235,7 +235,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/subscribe")
expect(page).not_to have_content '/subscribe'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(issuable.subscribed?(master, project)).to be_truthy
end
@@ -252,7 +252,7 @@ shared_examples 'issuable record that supports slash commands in its description
write_note("/unsubscribe")
expect(page).not_to have_content '/unsubscribe'
- expect(page).to have_content 'Your commands have been executed!'
+ expect(page).to have_content 'Commands applied'
expect(issuable.subscribed?(master, project)).to be_falsy
end
diff --git a/spec/support/services/issuable_create_service_shared_examples.rb b/spec/support/services/issuable_create_service_shared_examples.rb
new file mode 100644
index 00000000000..93c0267d2db
--- /dev/null
+++ b/spec/support/services/issuable_create_service_shared_examples.rb
@@ -0,0 +1,52 @@
+shared_examples 'issuable create service' do
+ context 'asssignee_id' do
+ let(:assignee) { create(:user) }
+
+ before { project.team << [user, :master] }
+
+ it 'removes assignee_id when user id is invalid' do
+ opts = { title: 'Title', description: 'Description', assignee_id: -1 }
+
+ issuable = described_class.new(project, user, opts).execute
+
+ expect(issuable.assignee_id).to be_nil
+ end
+
+ it 'removes assignee_id when user id is 0' do
+ opts = { title: 'Title', description: 'Description', assignee_id: 0 }
+
+ issuable = described_class.new(project, user, opts).execute
+
+ expect(issuable.assignee_id).to be_nil
+ end
+
+ it 'saves assignee when user id is valid' do
+ project.team << [assignee, :master]
+ opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
+
+ issuable = described_class.new(project, user, opts).execute
+
+ expect(issuable.assignee_id).to eq(assignee.id)
+ end
+
+ context "when issuable feature is private" do
+ before do
+ project.project_feature.update(issues_access_level: ProjectFeature::PRIVATE)
+ project.project_feature.update(merge_requests_access_level: ProjectFeature::PRIVATE)
+ end
+
+ levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
+
+ levels.each do |level|
+ it "removes not authorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
+ project.update(visibility_level: level)
+ opts = { title: 'Title', description: 'Description', assignee_id: assignee.id }
+
+ issuable = described_class.new(project, user, opts).execute
+
+ expect(issuable.assignee_id).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
index 5f9645ed44f..dd54b0addda 100644
--- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
+++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb
@@ -11,6 +11,8 @@ shared_examples 'new issuable record that supports slash commands' do
let(:params) { base_params.merge(defined?(default_params) ? default_params : {}).merge(example_params) }
let(:issuable) { described_class.new(project, user, params).execute }
+ before { project.team << [assignee, :master ] }
+
context 'with labels in command only' do
let(:example_params) do
{
@@ -55,7 +57,7 @@ shared_examples 'new issuable record that supports slash commands' do
context 'with assignee and milestone in params and command' do
let(:example_params) do
{
- assignee: build_stubbed(:user),
+ assignee: create(:user),
milestone_id: double(:milestone),
description: %(/assign @#{assignee.username}\n/milestone %"#{milestone.name}")
}
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index a3336755773..49cea1e608c 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -1,4 +1,8 @@
shared_examples 'issuable update service' do
+ def update_issuable(opts)
+ described_class.new(project, user, opts).execute(open_issuable)
+ end
+
context 'changing state' do
before { expect(project).to receive(:execute_hooks).once }
@@ -14,4 +18,52 @@ shared_examples 'issuable update service' do
end
end
end
+
+ context 'asssignee_id' do
+ it 'does not update assignee when assignee_id is invalid' do
+ open_issuable.update(assignee_id: user.id)
+
+ update_issuable(assignee_id: -1)
+
+ expect(open_issuable.reload.assignee).to eq(user)
+ end
+
+ it 'unassigns assignee when user id is 0' do
+ open_issuable.update(assignee_id: user.id)
+
+ update_issuable(assignee_id: 0)
+
+ expect(open_issuable.assignee_id).to be_nil
+ end
+
+ it 'saves assignee when user id is valid' do
+ update_issuable(assignee_id: user.id)
+
+ expect(open_issuable.assignee_id).to eq(user.id)
+ end
+
+ it 'does not update assignee_id when user cannot read issue' do
+ non_member = create(:user)
+ original_assignee = open_issuable.assignee
+
+ update_issuable(assignee_id: non_member.id)
+
+ expect(open_issuable.assignee_id).to eq(original_assignee.id)
+ end
+
+ context "when issuable feature is private" do
+ levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC]
+
+ levels.each do |level|
+ it "does not update with unauthorized assignee when project is #{Gitlab::VisibilityLevel.level_name(level)}" do
+ assignee = create(:user)
+ project.update(visibility_level: level)
+ feature_visibility_attr = :"#{open_issuable.model_name.plural}_access_level"
+ project.project_feature.update_attribute(feature_visibility_attr, ProjectFeature::PRIVATE)
+
+ expect{ update_issuable(assignee_id: assignee) }.not_to change{ open_issuable.assignee }
+ end
+ end
+ end
+ end
end
diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb
index 855c28b584e..f4f63b57a5f 100644
--- a/spec/workers/project_cache_worker_spec.rb
+++ b/spec/workers/project_cache_worker_spec.rb
@@ -1,8 +1,9 @@
require 'spec_helper'
describe ProjectCacheWorker do
- let(:project) { create(:project) }
let(:worker) { described_class.new }
+ let(:project) { create(:project) }
+ let(:statistics) { project.statistics }
describe '#perform' do
before do
@@ -12,7 +13,7 @@ describe ProjectCacheWorker do
context 'with a non-existing project' do
it 'does nothing' do
- expect(worker).not_to receive(:update_repository_size)
+ expect(worker).not_to receive(:update_statistics)
worker.perform(-1)
end
@@ -22,24 +23,19 @@ describe ProjectCacheWorker do
it 'does nothing' do
allow_any_instance_of(Repository).to receive(:exists?).and_return(false)
- expect(worker).not_to receive(:update_repository_size)
+ expect(worker).not_to receive(:update_statistics)
worker.perform(project.id)
end
end
context 'with an existing project' do
- it 'updates the repository size' do
- expect(worker).to receive(:update_repository_size).and_call_original
-
- worker.perform(project.id)
- end
-
- it 'updates the commit count' do
- expect_any_instance_of(Project).to receive(:update_commit_count).
- and_call_original
+ it 'updates the project statistics' do
+ expect(worker).to receive(:update_statistics)
+ .with(kind_of(Project), %i(repository_size))
+ .and_call_original
- worker.perform(project.id)
+ worker.perform(project.id, [], %w(repository_size))
end
it 'refreshes the method caches' do
@@ -47,33 +43,35 @@ describe ProjectCacheWorker do
with(%i(readme)).
and_call_original
- worker.perform(project.id, %i(readme))
+ worker.perform(project.id, %w(readme))
end
end
end
- describe '#update_repository_size' do
+ describe '#update_statistics' do
context 'when a lease could not be obtained' do
it 'does not update the repository size' do
allow(worker).to receive(:try_obtain_lease_for).
- with(project.id, :update_repository_size).
+ with(project.id, :update_statistics).
and_return(false)
- expect(project).not_to receive(:update_repository_size)
+ expect(statistics).not_to receive(:refresh!)
- worker.update_repository_size(project)
+ worker.update_statistics(project)
end
end
context 'when a lease could be obtained' do
- it 'updates the repository size' do
+ it 'updates the project statistics' do
allow(worker).to receive(:try_obtain_lease_for).
- with(project.id, :update_repository_size).
+ with(project.id, :update_statistics).
and_return(true)
- expect(project).to receive(:update_repository_size).and_call_original
+ expect(statistics).to receive(:refresh!)
+ .with(only: %i(repository_size))
+ .and_call_original
- worker.update_repository_size(project)
+ worker.update_statistics(project, %i(repository_size))
end
end
end