summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/clusters/gcp_controller_spec.rb7
-rw-r--r--spec/factories/protected_branches.rb1
-rw-r--r--spec/factories/redirect_routes.rb15
-rw-r--r--spec/features/copy_as_gfm_spec.rb2
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb1
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb36
-rw-r--r--spec/features/projects/commits/user_browses_commits_spec.rb15
-rw-r--r--spec/features/projects/tree/create_directory_spec.rb2
-rw-r--r--spec/features/projects/tree/create_file_spec.rb2
-rw-r--r--spec/features/projects/tree/upload_file_spec.rb2
-rw-r--r--spec/fixtures/api/schemas/entities/issue.json1
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json1
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/pipelines.json4
-rw-r--r--spec/javascripts/boards/list_spec.js2
-rw-r--r--spec/javascripts/boards/mock_data.js1
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js1
-rw-r--r--spec/javascripts/deploy_keys/components/app_spec.js1
-rw-r--r--spec/javascripts/environments/environments_app_spec.js1
-rw-r--r--spec/javascripts/environments/folder/environments_folder_view_spec.js1
-rw-r--r--spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js1
-rw-r--r--spec/javascripts/groups/components/app_spec.js66
-rw-r--r--spec/javascripts/groups/components/item_actions_spec.js40
-rw-r--r--spec/javascripts/issue_show/components/fields/description_template_spec.js2
-rw-r--r--spec/javascripts/issue_show/components/form_spec.js2
-rw-r--r--spec/javascripts/merge_request_notes_spec.js1
-rw-r--r--spec/javascripts/notes/components/comment_form_spec.js10
-rw-r--r--spec/javascripts/notes/components/note_app_spec.js1
-rw-r--r--spec/javascripts/notes/components/note_form_spec.js9
-rw-r--r--spec/javascripts/notes/components/noteable_note_spec.js2
-rw-r--r--spec/javascripts/notes/mock_data.js2
-rw-r--r--spec/javascripts/notes_spec.js1
-rw-r--r--spec/javascripts/oauth_remember_me_spec.js2
-rw-r--r--spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js (renamed from spec/javascripts/abuse_reports_spec.js)2
-rw-r--r--spec/javascripts/pipelines/pipeline_details_mediator_spec.js1
-rw-r--r--spec/javascripts/pipelines/pipelines_spec.js1
-rw-r--r--spec/javascripts/pipelines/stage_spec.js1
-rw-r--r--spec/javascripts/registry/components/app_spec.js1
-rw-r--r--spec/javascripts/sidebar/mock_data.js2
-rw-r--r--spec/javascripts/sidebar/sidebar_assignees_spec.js1
-rw-r--r--spec/javascripts/sidebar/sidebar_mediator_spec.js1
-rw-r--r--spec/javascripts/sidebar/sidebar_move_issue_spec.js1
-rw-r--r--spec/javascripts/signin_tabs_memoizer_spec.js2
-rw-r--r--spec/javascripts/smart_interval_spec.js1
-rw-r--r--spec/javascripts/test_bundle.js2
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js1
-rw-r--r--spec/javascripts/vue_shared/components/clipboard_button_spec.js31
-rw-r--r--spec/javascripts/vue_shared/components/user_avatar/user_avatar_link_spec.js1
-rw-r--r--spec/javascripts/zen_mode_spec.js2
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb48
-rw-r--r--spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb50
-rw-r--r--spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb5
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb6
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb66
-rw-r--r--spec/lib/gitlab/hook_data/issue_builder_spec.rb1
-rw-r--r--spec/lib/gitlab/hook_data/merge_request_builder_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/project.group.json2
-rw-r--r--spec/lib/gitlab/import_export/project.json20
-rw-r--r--spec/lib/gitlab/import_export/project.light.json1
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml5
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb14
-rw-r--r--spec/migrations/remove_soft_removed_objects_spec.rb77
-rw-r--r--spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb6
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb1
-rw-r--r--spec/models/issue_spec.rb5
-rw-r--r--spec/models/merge_request_spec.rb57
-rw-r--r--spec/models/namespace_spec.rb11
-rw-r--r--spec/models/project_spec.rb5
-rw-r--r--spec/models/route_spec.rb60
-rw-r--r--spec/requests/api/commit_statuses_spec.rb1
-rw-r--r--spec/requests/api/merge_requests_spec.rb43
-rw-r--r--spec/requests/api/runner_spec.rb1
-rw-r--r--spec/rubocop/cop/line_break_around_conditional_block_spec.rb411
-rw-r--r--spec/services/check_gcp_project_billing_service_spec.rb21
-rw-r--r--spec/services/issues/move_service_spec.rb12
-rw-r--r--spec/services/merge_requests/build_service_spec.rb26
-rw-r--r--spec/services/merge_requests/rebase_service_spec.rb108
-rw-r--r--spec/services/projects/transfer_service_spec.rb1
-rw-r--r--spec/services/system_note_service_spec.rb1
-rw-r--r--spec/services/users/destroy_service_spec.rb2
-rw-r--r--spec/support/features/discussion_comments_shared_example.rb2
-rw-r--r--spec/support/filtered_search_helpers.rb2
-rwxr-xr-xspec/support/generate-seed-repo-rb1
-rw-r--r--spec/support/google_api/cloud_platform_helpers.rb47
-rw-r--r--spec/support/matchers/access_matchers_for_controller.rb1
-rw-r--r--spec/support/select2_helper.rb1
-rw-r--r--spec/support/stub_env.rb1
-rw-r--r--spec/support/test_env.rb1
-rw-r--r--spec/support/wait_for_requests.rb1
-rw-r--r--spec/views/projects/buttons/_dropdown.html.haml_spec.rb39
-rw-r--r--spec/workers/check_gcp_project_billing_worker_spec.rb2
90 files changed, 1192 insertions, 260 deletions
diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb
index be19fa93183..775f9db1c6e 100644
--- a/spec/controllers/projects/clusters/gcp_controller_spec.rb
+++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb
@@ -137,11 +137,14 @@ describe Projects::Clusters::GcpController do
context 'when access token is valid' do
before do
stub_google_api_validate_token
+ allow_any_instance_of(described_class).to receive(:authorize_google_project_billing)
end
context 'when google project billing is enabled' do
before do
- stub_google_project_billing_status
+ redis_double = double
+ allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double)
+ allow(redis_double).to receive(:get).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for('token')).and_return('true')
end
it 'creates a new cluster' do
@@ -158,7 +161,7 @@ describe Projects::Clusters::GcpController do
it 'renders the cluster form with an error' do
go
- expect(response).to set_flash[:error]
+ expect(response).to set_flash[:alert]
expect(response).to render_template('new')
end
end
diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb
index 39460834d06..60956511834 100644
--- a/spec/factories/protected_branches.rb
+++ b/spec/factories/protected_branches.rb
@@ -53,6 +53,7 @@ FactoryBot.define do
if evaluator.default_access_level && evaluator.default_push_level
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER)
end
+
if evaluator.default_access_level && evaluator.default_merge_level
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER)
end
diff --git a/spec/factories/redirect_routes.rb b/spec/factories/redirect_routes.rb
new file mode 100644
index 00000000000..c29c81c5df9
--- /dev/null
+++ b/spec/factories/redirect_routes.rb
@@ -0,0 +1,15 @@
+FactoryBot.define do
+ factory :redirect_route do
+ sequence(:path) { |n| "redirect#{n}" }
+ source factory: :group
+ permanent false
+
+ trait :permanent do
+ permanent true
+ end
+
+ trait :temporary do
+ permanent false
+ end
+ end
+end
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index d8f1a919522..f82ed6300cc 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -750,7 +750,7 @@ describe 'Copy as GFM', :js do
js = <<-JS.strip_heredoc
(function(selector) {
var els = document.querySelectorAll(selector);
- var htmls = _.map(els, function(el) { return el.outerHTML; });
+ var htmls = [].slice.call(els).map(function(el) { return el.outerHTML; });
return htmls.join("\\n");
})("#{escape_javascript(selector)}")
JS
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index 587ece22ec7..cf283119f36 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -377,6 +377,7 @@ feature 'Issues > Labels bulk assignment' do
items.map do |item|
click_link item
end
+
if unmark
items.map do |item|
# Make sure we are unmarking the item no matter the state it has currently
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 523cc08496b..8953b30bebf 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -13,6 +13,8 @@ feature 'Gcp Cluster', :js do
end
context 'when user has signed with Google' do
+ let(:project_id) { 'test-project-1234' }
+
before do
allow_any_instance_of(Projects::Clusters::GcpController)
.to receive(:token_in_session).and_return('token')
@@ -23,7 +25,7 @@ feature 'Gcp Cluster', :js do
context 'when user has a GCP project with billing enabled' do
before do
allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing)
- stub_google_project_billing_status
+ allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return('true')
end
context 'when user does not have a cluster and visits cluster index page' do
@@ -131,15 +133,41 @@ feature 'Gcp Cluster', :js do
context 'when user does not have a GCP project with billing enabled' do
before do
+ allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing)
+ allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return('false')
+
visit project_clusters_path(project)
click_link 'Add cluster'
click_link 'Create on GKE'
+
+ fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123'
+ fill_in 'cluster_name', with: 'dev-cluster'
+ click_button 'Create cluster'
+ end
+
+ it 'user sees form with error' do
+ expect(page).to have_content('Please enable billing for one of your projects to be able to create a cluster, then try again.')
+ end
+ end
+
+ context 'when gcp billing status is not in redis' do
+ before do
+ allow_any_instance_of(Projects::Clusters::GcpController).to receive(:authorize_google_project_billing)
+ allow_any_instance_of(Projects::Clusters::GcpController).to receive(:google_project_billing_status).and_return(nil)
+
+ visit project_clusters_path(project)
+
+ click_link 'Add cluster'
+ click_link 'Create on GKE'
+
+ fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123'
+ fill_in 'cluster_name', with: 'dev-cluster'
+ click_button 'Create cluster'
end
- it 'user sees a check page' do
- pending 'the frontend still has not been implemented'
- expect(page).to have_link('Continue')
+ it 'user sees form with error' do
+ expect(page).to have_content('We could not verify that one of your projects on GCP has billing enabled. Please try again.')
end
end
end
diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb
index 41f3c15a94c..b650c1f4197 100644
--- a/spec/features/projects/commits/user_browses_commits_spec.rb
+++ b/spec/features/projects/commits/user_browses_commits_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'User broweses commits' do
+describe 'User browses commits' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, namespace: user.namespace) }
@@ -31,6 +31,19 @@ describe 'User broweses commits' do
check_author_link(RepoHelpers.sample_commit.author_email, user)
end
end
+
+ context 'when the blob does not exist' do
+ let(:commit) { create(:commit, project: project) }
+
+ it 'shows a blank label' do
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:raw_binary?).and_return(true)
+
+ visit(project_commit_path(project, commit))
+
+ expect(find('.diff-file-changes', visible: false)).to have_content('No file name available')
+ end
+ end
end
private
diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb
index 3f6d16c8acf..0c67196f53e 100644
--- a/spec/features/projects/tree/create_directory_spec.rb
+++ b/spec/features/projects/tree/create_directory_spec.rb
@@ -14,7 +14,7 @@ feature 'Multi-file editor new directory', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb
index ba71eef07f4..85f7318c05d 100644
--- a/spec/features/projects/tree/create_file_spec.rb
+++ b/spec/features/projects/tree/create_file_spec.rb
@@ -14,7 +14,7 @@ feature 'Multi-file editor new file', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
diff --git a/spec/features/projects/tree/upload_file_spec.rb b/spec/features/projects/tree/upload_file_spec.rb
index 9fbb1dbd0e8..f81e8677e92 100644
--- a/spec/features/projects/tree/upload_file_spec.rb
+++ b/spec/features/projects/tree/upload_file_spec.rb
@@ -16,7 +16,7 @@ feature 'Multi-file editor upload file', :js do
wait_for_requests
- click_link('Multi Edit')
+ click_link('Web IDE')
wait_for_requests
end
diff --git a/spec/fixtures/api/schemas/entities/issue.json b/spec/fixtures/api/schemas/entities/issue.json
index 3d3329a3406..38467b4ca20 100644
--- a/spec/fixtures/api/schemas/entities/issue.json
+++ b/spec/fixtures/api/schemas/entities/issue.json
@@ -28,7 +28,6 @@
"confidential": { "type": "boolean" },
"discussion_locked": { "type": ["boolean", "null"] },
"updated_by_id": { "type": ["string", "null"] },
- "deleted_at": { "type": ["string", "null"] },
"time_estimate": { "type": "integer" },
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["integer", "null"] },
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 7f662098216..05461787f06 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -13,7 +13,6 @@
"updated_by_id": { "type": ["string", "null"] },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
- "deleted_at": { "type": ["string", "null"] },
"time_estimate": { "type": "integer" },
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["integer", "null"] },
diff --git a/spec/fixtures/api/schemas/public_api/v4/pipelines.json b/spec/fixtures/api/schemas/public_api/v4/pipelines.json
new file mode 100644
index 00000000000..8b08a00f708
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/pipelines.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "pipeline/basic.json" }
+}
diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js
index 645ce831b53..e5e7b48228b 100644
--- a/spec/javascripts/boards/list_spec.js
+++ b/spec/javascripts/boards/list_spec.js
@@ -5,7 +5,7 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
-
+import _ from 'underscore';
import '~/boards/models/issue';
import '~/boards/models/label';
import '~/boards/models/list';
diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js
index 9ae2d535398..0671facb285 100644
--- a/spec/javascripts/boards/mock_data.js
+++ b/spec/javascripts/boards/mock_data.js
@@ -1,5 +1,6 @@
/* global BoardService */
/* eslint-disable comma-dangle, no-unused-vars, quote-props */
+import _ from 'underscore';
export const listObj = {
id: 300,
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index 9fc047b1f5e..d62c2966a8b 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import pipelinesTable from '~/commit/pipelines/pipelines_table.vue';
diff --git a/spec/javascripts/deploy_keys/components/app_spec.js b/spec/javascripts/deploy_keys/components/app_spec.js
index 0ca9290d3d2..b870f87eab9 100644
--- a/spec/javascripts/deploy_keys/components/app_spec.js
+++ b/spec/javascripts/deploy_keys/components/app_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import eventHub from '~/deploy_keys/eventhub';
import deployKeysApp from '~/deploy_keys/components/app.vue';
diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js
index d02adb25b4e..a41a4e5a3f7 100644
--- a/spec/javascripts/environments/environments_app_spec.js
+++ b/spec/javascripts/environments/environments_app_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import environmentsComponent from '~/environments/components/environments_app.vue';
import { environment, folder } from './mock_data';
diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js b/spec/javascripts/environments/folder/environments_folder_view_spec.js
index 4ea4d9d7499..a085074d312 100644
--- a/spec/javascripts/environments/folder/environments_folder_view_spec.js
+++ b/spec/javascripts/environments/folder/environments_folder_view_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
import { environmentsList } from '../mock_data';
diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
index 2ecb64d84b5..0684c3498a2 100644
--- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
+++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js
index 97e39f6411b..8338efe915b 100644
--- a/spec/javascripts/groups/components/app_spec.js
+++ b/spec/javascripts/groups/components/app_spec.js
@@ -256,6 +256,36 @@ describe('AppComponent', () => {
});
});
+ describe('showLeaveGroupModal', () => {
+ it('caches candidate group (as props) which is to be left', () => {
+ const group = Object.assign({}, mockParentGroupItem);
+ expect(vm.targetGroup).toBe(null);
+ expect(vm.targetParentGroup).toBe(null);
+ vm.showLeaveGroupModal(group, mockParentGroupItem);
+ expect(vm.targetGroup).not.toBe(null);
+ expect(vm.targetParentGroup).not.toBe(null);
+ });
+
+ it('updates props which show modal confirmation dialog', () => {
+ const group = Object.assign({}, mockParentGroupItem);
+ expect(vm.showModal).toBeFalsy();
+ expect(vm.groupLeaveConfirmationMessage).toBe('');
+ vm.showLeaveGroupModal(group, mockParentGroupItem);
+ expect(vm.showModal).toBeTruthy();
+ expect(vm.groupLeaveConfirmationMessage).toBe(`Are you sure you want to leave the "${group.fullName}" group?`);
+ });
+ });
+
+ describe('hideLeaveGroupModal', () => {
+ it('hides modal confirmation which is shown before leaving the group', () => {
+ const group = Object.assign({}, mockParentGroupItem);
+ vm.showLeaveGroupModal(group, mockParentGroupItem);
+ expect(vm.showModal).toBeTruthy();
+ vm.hideLeaveGroupModal();
+ expect(vm.showModal).toBeFalsy();
+ });
+ });
+
describe('leaveGroup', () => {
let groupItem;
let childGroupItem;
@@ -265,21 +295,24 @@ describe('AppComponent', () => {
groupItem.children = mockChildren;
childGroupItem = groupItem.children[0];
groupItem.isChildrenLoading = false;
+ vm.targetGroup = childGroupItem;
+ vm.targetParentGroup = groupItem;
});
- it('should leave group and remove group item from tree', (done) => {
+ it('hides modal confirmation leave group and remove group item from tree', (done) => {
const notice = `You left the "${childGroupItem.fullName}" group.`;
spyOn(vm.service, 'leaveGroup').and.returnValue(returnServicePromise({ notice }));
spyOn(vm.store, 'removeGroup').and.callThrough();
spyOn(window, 'Flash');
spyOn($, 'scrollTo');
- vm.leaveGroup(childGroupItem, groupItem);
- expect(childGroupItem.isBeingRemoved).toBeTruthy();
- expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
+ vm.leaveGroup();
+ expect(vm.showModal).toBeFalsy();
+ expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
+ expect(vm.service.leaveGroup).toHaveBeenCalledWith(vm.targetGroup.leavePath);
setTimeout(() => {
expect($.scrollTo).toHaveBeenCalledWith(0);
- expect(vm.store.removeGroup).toHaveBeenCalledWith(childGroupItem, groupItem);
+ expect(vm.store.removeGroup).toHaveBeenCalledWith(vm.targetGroup, vm.targetParentGroup);
expect(window.Flash).toHaveBeenCalledWith(notice, 'notice');
done();
}, 0);
@@ -291,13 +324,13 @@ describe('AppComponent', () => {
spyOn(vm.store, 'removeGroup').and.callThrough();
spyOn(window, 'Flash');
- vm.leaveGroup(childGroupItem, groupItem);
- expect(childGroupItem.isBeingRemoved).toBeTruthy();
+ vm.leaveGroup();
+ expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
setTimeout(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
expect(window.Flash).toHaveBeenCalledWith(message);
- expect(childGroupItem.isBeingRemoved).toBeFalsy();
+ expect(vm.targetGroup.isBeingRemoved).toBeFalsy();
done();
}, 0);
});
@@ -309,12 +342,12 @@ describe('AppComponent', () => {
spyOn(window, 'Flash');
vm.leaveGroup(childGroupItem, groupItem);
- expect(childGroupItem.isBeingRemoved).toBeTruthy();
+ expect(vm.targetGroup.isBeingRemoved).toBeTruthy();
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
setTimeout(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
expect(window.Flash).toHaveBeenCalledWith(message);
- expect(childGroupItem.isBeingRemoved).toBeFalsy();
+ expect(vm.targetGroup.isBeingRemoved).toBeFalsy();
done();
}, 0);
});
@@ -364,7 +397,7 @@ describe('AppComponent', () => {
Vue.nextTick(() => {
expect(eventHub.$on).toHaveBeenCalledWith('fetchPage', jasmine.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('toggleChildren', jasmine.any(Function));
- expect(eventHub.$on).toHaveBeenCalledWith('leaveGroup', jasmine.any(Function));
+ expect(eventHub.$on).toHaveBeenCalledWith('showLeaveGroupModal', jasmine.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('updatePagination', jasmine.any(Function));
expect(eventHub.$on).toHaveBeenCalledWith('updateGroups', jasmine.any(Function));
newVm.$destroy();
@@ -404,7 +437,7 @@ describe('AppComponent', () => {
Vue.nextTick(() => {
expect(eventHub.$off).toHaveBeenCalledWith('fetchPage', jasmine.any(Function));
expect(eventHub.$off).toHaveBeenCalledWith('toggleChildren', jasmine.any(Function));
- expect(eventHub.$off).toHaveBeenCalledWith('leaveGroup', jasmine.any(Function));
+ expect(eventHub.$off).toHaveBeenCalledWith('showLeaveGroupModal', jasmine.any(Function));
expect(eventHub.$off).toHaveBeenCalledWith('updatePagination', jasmine.any(Function));
expect(eventHub.$off).toHaveBeenCalledWith('updateGroups', jasmine.any(Function));
done();
@@ -439,5 +472,14 @@ describe('AppComponent', () => {
done();
});
});
+
+ it('renders modal confirmation dialog', () => {
+ vm.groupLeaveConfirmationMessage = 'Are you sure you want to leave the "foo" group?';
+ vm.showModal = true;
+ const modalDialogEl = vm.$el.querySelector('.modal');
+ expect(modalDialogEl).not.toBe(null);
+ expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
+ expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
+ });
});
});
diff --git a/spec/javascripts/groups/components/item_actions_spec.js b/spec/javascripts/groups/components/item_actions_spec.js
index 6d6fb410859..acccbe639c4 100644
--- a/spec/javascripts/groups/components/item_actions_spec.js
+++ b/spec/javascripts/groups/components/item_actions_spec.js
@@ -26,32 +26,12 @@ describe('ItemActionsComponent', () => {
vm.$destroy();
});
- describe('computed', () => {
- describe('leaveConfirmationMessage', () => {
- it('should return appropriate string for leave group confirmation', () => {
- expect(vm.leaveConfirmationMessage).toBe('Are you sure you want to leave the "platform / hardware" group?');
- });
- });
- });
-
describe('methods', () => {
describe('onLeaveGroup', () => {
- it('should change `modalStatus` prop to `true` which shows confirmation dialog', () => {
- expect(vm.modalStatus).toBeFalsy();
- vm.onLeaveGroup();
- expect(vm.modalStatus).toBeTruthy();
- });
- });
-
- describe('leaveGroup', () => {
- it('should change `modalStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => {
+ it('emits `showLeaveGroupModal` event with `group` and `parentGroup` props', () => {
spyOn(eventHub, '$emit');
- vm.modalStatus = true;
-
- vm.leaveGroup();
-
- expect(vm.modalStatus).toBeFalsy();
- expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup);
+ vm.onLeaveGroup();
+ expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', vm.group, vm.parentGroup);
});
});
});
@@ -72,7 +52,8 @@ describe('ItemActionsComponent', () => {
expect(editBtn.getAttribute('href')).toBe(group.editPath);
expect(editBtn.getAttribute('aria-label')).toBe('Edit group');
expect(editBtn.dataset.originalTitle).toBe('Edit group');
- expect(editBtn.querySelector('i.fa.fa-cogs')).toBeDefined();
+ expect(editBtn.querySelectorAll('svg use').length).not.toBe(0);
+ expect(editBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#settings');
newVm.$destroy();
});
@@ -88,17 +69,10 @@ describe('ItemActionsComponent', () => {
expect(leaveBtn.getAttribute('href')).toBe(group.leavePath);
expect(leaveBtn.getAttribute('aria-label')).toBe('Leave this group');
expect(leaveBtn.dataset.originalTitle).toBe('Leave this group');
- expect(leaveBtn.querySelector('i.fa.fa-sign-out')).toBeDefined();
+ expect(leaveBtn.querySelectorAll('svg use').length).not.toBe(0);
+ expect(leaveBtn.querySelector('svg use').getAttribute('xlink:href')).toContain('#leave');
newVm.$destroy();
});
-
- it('should show modal dialog when `modalStatus` is set to `true`', () => {
- vm.modalStatus = true;
- const modalDialogEl = vm.$el.querySelector('.modal');
- expect(modalDialogEl).toBeDefined();
- expect(modalDialogEl.querySelector('.modal-title').innerText.trim()).toBe('Are you sure?');
- expect(modalDialogEl.querySelector('.btn.btn-warning').innerText.trim()).toBe('Leave');
- });
});
});
diff --git a/spec/javascripts/issue_show/components/fields/description_template_spec.js b/spec/javascripts/issue_show/components/fields/description_template_spec.js
index 2b7ee65094b..30441faf844 100644
--- a/spec/javascripts/issue_show/components/fields/description_template_spec.js
+++ b/spec/javascripts/issue_show/components/fields/description_template_spec.js
@@ -1,7 +1,5 @@
import Vue from 'vue';
import descriptionTemplate from '~/issue_show/components/fields/description_template.vue';
-import '~/templates/issuable_template_selector';
-import '~/templates/issuable_template_selectors';
describe('Issue description template component', () => {
let vm;
diff --git a/spec/javascripts/issue_show/components/form_spec.js b/spec/javascripts/issue_show/components/form_spec.js
index 000b53af016..50ce019c32a 100644
--- a/spec/javascripts/issue_show/components/form_spec.js
+++ b/spec/javascripts/issue_show/components/form_spec.js
@@ -1,7 +1,5 @@
import Vue from 'vue';
import formComponent from '~/issue_show/components/form.vue';
-import '~/templates/issuable_template_selector';
-import '~/templates/issuable_template_selectors';
describe('Inline edit form component', () => {
let vm;
diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js
index e983e4de3fc..5d0ee91d977 100644
--- a/spec/javascripts/merge_request_notes_spec.js
+++ b/spec/javascripts/merge_request_notes_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js
index 20e352dd8bd..104d03377b6 100644
--- a/spec/javascripts/notes/components/comment_form_spec.js
+++ b/spec/javascripts/notes/components/comment_form_spec.js
@@ -139,13 +139,21 @@ describe('issue_comment_form component', () => {
});
describe('event enter', () => {
- it('should save note when cmd/ctrl+enter is pressed', () => {
+ it('should save note when cmd+enter is pressed', () => {
spyOn(vm, 'handleSave').and.callThrough();
vm.$el.querySelector('.js-main-target-form textarea').value = 'Foo';
vm.$el.querySelector('.js-main-target-form textarea').dispatchEvent(keyboardDownEvent(13, true));
expect(vm.handleSave).toHaveBeenCalled();
});
+
+ it('should save note when ctrl+enter is pressed', () => {
+ spyOn(vm, 'handleSave').and.callThrough();
+ vm.$el.querySelector('.js-main-target-form textarea').value = 'Foo';
+ vm.$el.querySelector('.js-main-target-form textarea').dispatchEvent(keyboardDownEvent(13, false, true));
+
+ expect(vm.handleSave).toHaveBeenCalled();
+ });
});
});
diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js
index 7c8d6685ee1..36c56cd3862 100644
--- a/spec/javascripts/notes/components/note_app_spec.js
+++ b/spec/javascripts/notes/components/note_app_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import notesApp from '~/notes/components/notes_app.vue';
import service from '~/notes/services/notes_service';
diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js
index 86e9e2a32a9..f841a408d09 100644
--- a/spec/javascripts/notes/components/note_form_spec.js
+++ b/spec/javascripts/notes/components/note_form_spec.js
@@ -69,13 +69,20 @@ describe('issue_note_form component', () => {
});
describe('enter', () => {
- it('should submit note', () => {
+ it('should save note when cmd+enter is pressed', () => {
spyOn(vm, 'handleUpdate').and.callThrough();
vm.$el.querySelector('textarea').value = 'Foo';
vm.$el.querySelector('textarea').dispatchEvent(keyboardDownEvent(13, true));
expect(vm.handleUpdate).toHaveBeenCalled();
});
+ it('should save note when ctrl+enter is pressed', () => {
+ spyOn(vm, 'handleUpdate').and.callThrough();
+ vm.$el.querySelector('textarea').value = 'Foo';
+ vm.$el.querySelector('textarea').dispatchEvent(keyboardDownEvent(13, false, true));
+
+ expect(vm.handleUpdate).toHaveBeenCalled();
+ });
});
});
diff --git a/spec/javascripts/notes/components/noteable_note_spec.js b/spec/javascripts/notes/components/noteable_note_spec.js
index c8a6cb7e612..cb63b64724d 100644
--- a/spec/javascripts/notes/components/noteable_note_spec.js
+++ b/spec/javascripts/notes/components/noteable_note_spec.js
@@ -1,4 +1,4 @@
-
+import _ from 'underscore';
import Vue from 'vue';
import store from '~/notes/stores';
import issueNote from '~/notes/components/noteable_note.vue';
diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js
index 6b608adff15..b020a1020df 100644
--- a/spec/javascripts/notes/mock_data.js
+++ b/spec/javascripts/notes/mock_data.js
@@ -29,7 +29,6 @@ export const noteableDataMock = {
can_create_note: true,
can_update: true,
},
- deleted_at: null,
description: '',
due_date: null,
human_time_estimate: null,
@@ -283,7 +282,6 @@ export const loggedOutnoteableData = {
"updated_by_id": 1,
"created_at": "2017-02-07T10:11:18.395Z",
"updated_at": "2017-08-08T10:22:51.564Z",
- "deleted_at": null,
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index 167f074fb9b..a40821a5693 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -1,4 +1,5 @@
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
+import _ from 'underscore';
import * as urlUtils from '~/lib/utils/url_utility';
import 'autosize';
import '~/gl_form';
diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js
index f90e0093d25..b24563f738b 100644
--- a/spec/javascripts/oauth_remember_me_spec.js
+++ b/spec/javascripts/oauth_remember_me_spec.js
@@ -1,4 +1,4 @@
-import OAuthRememberMe from '~/oauth_remember_me';
+import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me';
describe('OAuthRememberMe', () => {
preloadFixtures('static/oauth_remember_me.html.raw');
diff --git a/spec/javascripts/abuse_reports_spec.js b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
index 7f6b5873011..d2386077aa6 100644
--- a/spec/javascripts/abuse_reports_spec.js
+++ b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js
@@ -1,5 +1,5 @@
import '~/lib/utils/text_utility';
-import AbuseReports from '~/abuse_reports';
+import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports';
describe('Abuse Reports', () => {
const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw';
diff --git a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js b/spec/javascripts/pipelines/pipeline_details_mediator_spec.js
index 9fec2f61f78..bc6413a159f 100644
--- a/spec/javascripts/pipelines/pipeline_details_mediator_spec.js
+++ b/spec/javascripts/pipelines/pipeline_details_mediator_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import PipelineMediator from '~/pipelines/pipeline_details_mediatior';
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index 367b42cefb0..a99ebc4e51a 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import pipelinesComp from '~/pipelines/components/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js
index 1b96b2e3d51..61c2f783acc 100644
--- a/spec/javascripts/pipelines/stage_spec.js
+++ b/spec/javascripts/pipelines/stage_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import stage from '~/pipelines/components/stage.vue';
diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js
index 87259fe0bab..6a8a85e3dfb 100644
--- a/spec/javascripts/registry/components/app_spec.js
+++ b/spec/javascripts/registry/components/app_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import registry from '~/registry/components/app.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 3b094d20838..7bc591d2d47 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -15,7 +15,6 @@ const RESPONSE_MAP = {
updated_by_id: 1,
created_at: '2017-02-02T21: 49: 49.664Z',
updated_at: '2017-05-03T22: 26: 03.760Z',
- deleted_at: null,
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
@@ -153,7 +152,6 @@ const RESPONSE_MAP = {
updated_by_id: 1,
created_at: '2017-06-27T19:54:42.437Z',
updated_at: '2017-08-18T03:39:49.222Z',
- deleted_at: null,
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js
index b97e24d9dcf..6bb6d639f24 100644
--- a/spec/javascripts/sidebar/sidebar_assignees_spec.js
+++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees';
import SidebarMediator from '~/sidebar/sidebar_mediator';
diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js
index 9efd109b996..afa18cc127e 100644
--- a/spec/javascripts/sidebar/sidebar_mediator_spec.js
+++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import * as urlUtils from '~/lib/utils/url_utility';
import SidebarMediator from '~/sidebar/sidebar_mediator';
diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js
index 8b0d51bbcc8..97f762d07a7 100644
--- a/spec/javascripts/sidebar/sidebar_move_issue_spec.js
+++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarStore from '~/sidebar/stores/sidebar_store';
diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js
index a53e8a94d89..c4f500788b2 100644
--- a/spec/javascripts/signin_tabs_memoizer_spec.js
+++ b/spec/javascripts/signin_tabs_memoizer_spec.js
@@ -1,5 +1,5 @@
import AccessorUtilities from '~/lib/utils/accessor';
-import SigninTabsMemoizer from '~/signin_tabs_memoizer';
+import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer';
(() => {
describe('SigninTabsMemoizer', () => {
diff --git a/spec/javascripts/smart_interval_spec.js b/spec/javascripts/smart_interval_spec.js
index 1c87fcec245..7265e1b6cb5 100644
--- a/spec/javascripts/smart_interval_spec.js
+++ b/spec/javascripts/smart_interval_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import SmartInterval from '~/smart_interval';
describe('SmartInterval', function () {
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 6897c991066..2f6691df9cd 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -1,6 +1,5 @@
/* eslint-disable jasmine/no-global-setup */
import $ from 'jquery';
-import _ from 'underscore';
import 'jasmine-jquery';
import '~/commons';
@@ -31,7 +30,6 @@ jasmine.getJSONFixtures().fixturesPath = '/base/spec/javascripts/fixtures';
// globalize common libraries
window.$ = window.jQuery = $;
-window._ = _;
// stub expected globals
window.gl = window.gl || {};
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index ca29c9fee32..ae494267659 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -14,7 +14,6 @@ export default {
"updated_by_id": null,
"created_at": "2017-04-07T12:27:26.718Z",
"updated_at": "2017-04-07T15:39:25.852Z",
- "deleted_at": null,
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
diff --git a/spec/javascripts/vue_shared/components/clipboard_button_spec.js b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
new file mode 100644
index 00000000000..08e4e1f8337
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/clipboard_button_spec.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('clipboard button', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(clipboardButton);
+ vm = mountComponent(Component, {
+ text: 'copy me',
+ title: 'Copy this value into Clipboard!',
+ });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders a button for clipboard', () => {
+ expect(vm.$el.tagName).toEqual('BUTTON');
+ expect(vm.$el.getAttribute('data-clipboard-text')).toEqual('copy me');
+ expect(vm.$el.querySelector('i').className).toEqual('fa fa-clipboard');
+ });
+
+ it('should have a tooltip with default values', () => {
+ expect(vm.$el.getAttribute('data-original-title')).toEqual('Copy this value into Clipboard!');
+ expect(vm.$el.getAttribute('data-placement')).toEqual('top');
+ expect(vm.$el.getAttribute('data-container')).toEqual(null);
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_link_spec.js b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_link_spec.js
index 8450ad9dbcb..adf80d0c2bb 100644
--- a/spec/javascripts/vue_shared/components/user_avatar/user_avatar_link_spec.js
+++ b/spec/javascripts/vue_shared/components/user_avatar/user_avatar_link_spec.js
@@ -1,3 +1,4 @@
+import _ from 'underscore';
import Vue from 'vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js
index 45a0bb0650f..8edba1f47a3 100644
--- a/spec/javascripts/zen_mode_spec.js
+++ b/spec/javascripts/zen_mode_spec.js
@@ -1,4 +1,4 @@
-/* global Mousetrap */
+import Mousetrap from 'mousetrap';
import Dropzone from 'dropzone';
import ZenMode from '~/zen_mode';
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index f38f0776303..7e17457ce70 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -8,7 +8,8 @@ describe Banzai::Filter::RelativeLinkFilter do
group: group,
project_wiki: project_wiki,
ref: ref,
- requested_path: requested_path
+ requested_path: requested_path,
+ only_path: only_path
})
described_class.call(doc, contexts)
@@ -37,6 +38,7 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:commit) { project.commit(ref) }
let(:project_wiki) { nil }
let(:requested_path) { '/' }
+ let(:only_path) { true }
shared_examples :preserve_unchanged do
it 'does not modify any relative URL in anchor' do
@@ -240,26 +242,35 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:commit) { nil }
let(:ref) { nil }
let(:requested_path) { nil }
+ let(:upload_path) { '/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg' }
+ let(:relative_path) { "/#{project.full_path}#{upload_path}" }
context 'to a project upload' do
+ context 'with an absolute URL' do
+ let(:absolute_path) { Gitlab.config.gitlab.url + relative_path }
+ let(:only_path) { false }
+
+ it 'rewrites the link correctly' do
+ doc = filter(link(upload_path))
+
+ expect(doc.at_css('a')['href']).to eq(absolute_path)
+ end
+ end
+
it 'rebuilds relative URL for a link' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(link(upload_path))
+ expect(doc.at_css('a')['href']).to eq(relative_path)
- doc = filter(nested(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
- expect(doc.at_css('a')['href'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(nested(link(upload_path)))
+ expect(doc.at_css('a')['href']).to eq(relative_path)
end
it 'rebuilds relative URL for an image' do
- doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(image(upload_path))
+ expect(doc.at_css('img')['src']).to eq(relative_path)
- doc = filter(nested(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
- expect(doc.at_css('img')['src'])
- .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ doc = filter(nested(image(upload_path)))
+ expect(doc.at_css('img')['src']).to eq(relative_path)
end
it 'does not modify absolute URL' do
@@ -288,6 +299,17 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:project) { nil }
let(:relative_path) { "/groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" }
+ context 'with an absolute URL' do
+ let(:absolute_path) { Gitlab.config.gitlab.url + relative_path }
+ let(:only_path) { false }
+
+ it 'rewrites the link correctly' do
+ doc = filter(upload_link)
+
+ expect(doc.at_css('a')['href']).to eq(absolute_path)
+ end
+ end
+
it 'rewrites the link correctly' do
doc = filter(upload_link)
diff --git a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
new file mode 100644
index 00000000000..21a791f5695
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount, :migration, schema: 20180105212544 do
+ let(:projects_table) { table(:projects) }
+ let(:merge_requests_table) { table(:merge_requests) }
+ let(:merge_request_diffs_table) { table(:merge_request_diffs) }
+ let(:merge_request_diff_commits_table) { table(:merge_request_diff_commits) }
+
+ let(:project) { projects_table.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce') }
+ let(:merge_request) do
+ merge_requests_table.create!(target_project_id: project.id,
+ target_branch: 'master',
+ source_project_id: project.id,
+ source_branch: 'mr name',
+ title: 'mr name')
+ end
+
+ def create_diff!(name, commits: 0)
+ mr_diff = merge_request_diffs_table.create!(
+ merge_request_id: merge_request.id)
+
+ commits.times do |i|
+ merge_request_diff_commits_table.create!(
+ merge_request_diff_id: mr_diff.id,
+ relative_order: i, sha: i)
+ end
+
+ mr_diff
+ end
+
+ describe '#perform' do
+ it 'migrates diffs that have no commits' do
+ diff = create_diff!('with_multiple_commits', commits: 0)
+
+ subject.perform(diff.id, diff.id)
+
+ expect(diff.reload.commits_count).to eq(0)
+ end
+
+ it 'migrates multiple diffs to the correct values' do
+ diffs = Array.new(3).map.with_index { |_, i| create_diff!(i, commits: 3) }
+
+ subject.perform(diffs.first.id, diffs.last.id)
+
+ diffs.each do |diff|
+ expect(diff.reload.commits_count).to eq(3)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
index 84d9e635810..98730602863 100644
--- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
+++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
@@ -10,6 +10,11 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :t
let(:merge_request_diff) { MergeRequest.find(merge_request.id).create_merge_request_diff }
let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) }
+ before do
+ allow_any_instance_of(MergeRequestDiff)
+ .to receive(:commits_count=).and_return(nil)
+ end
+
def diffs_to_hashes(diffs)
diffs.as_json(only: Gitlab::Git::Diff::SERIALIZE_KEYS).map(&:with_indifferent_access)
end
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb
index dfe3b31f1c0..e99257e3481 100644
--- a/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb
@@ -1,6 +1,12 @@
require 'rails_helper'
describe Gitlab::BackgroundMigration::PopulateMergeRequestMetricsWithEventsData, :migration, schema: 20171128214150 do
+ # commits_count attribute is added in a next migration
+ before do
+ allow_any_instance_of(MergeRequestDiff)
+ .to receive(:commits_count=).and_return(nil)
+ end
+
describe '#perform' do
let(:mr_with_event) { create(:merge_request) }
let!(:merged_event) { create(:event, :merged, target: mr_with_event) }
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index f346a345f00..f4e781c599e 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1283,48 +1283,58 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#merged_branch_names' do
- context 'when branch names are passed' do
- it 'only returns the names we are asking' do
- names = repository.merged_branch_names(%w[merge-test])
+ shared_examples 'finding merged branch names' do
+ context 'when branch names are passed' do
+ it 'only returns the names we are asking' do
+ names = repository.merged_branch_names(%w[merge-test])
- expect(names).to contain_exactly('merge-test')
- end
+ expect(names).to contain_exactly('merge-test')
+ end
- it 'does not return unmerged branch names' do
- names = repository.merged_branch_names(%w[feature])
+ it 'does not return unmerged branch names' do
+ names = repository.merged_branch_names(%w[feature])
- expect(names).to be_empty
+ expect(names).to be_empty
+ end
end
- end
- context 'when no root ref is available' do
- it 'returns empty list' do
- project = create(:project, :empty_repo)
+ context 'when no root ref is available' do
+ it 'returns empty list' do
+ project = create(:project, :empty_repo)
- names = project.repository.merged_branch_names(%w[feature])
+ names = project.repository.merged_branch_names(%w[feature])
- expect(names).to be_empty
+ expect(names).to be_empty
+ end
end
- end
- context 'when no branch names are specified' do
- before do
- repository.create_branch('identical', 'master')
- end
+ context 'when no branch names are specified' do
+ before do
+ repository.create_branch('identical', 'master')
+ end
- after do
- ensure_seeds
- end
+ after do
+ ensure_seeds
+ end
- it 'returns all merged branch names except for identical one' do
- names = repository.merged_branch_names
+ it 'returns all merged branch names except for identical one' do
+ names = repository.merged_branch_names
- expect(names).to include('merge-test')
- expect(names).to include('fix-mode')
- expect(names).not_to include('feature')
- expect(names).not_to include('identical')
+ expect(names).to include('merge-test')
+ expect(names).to include('fix-mode')
+ expect(names).not_to include('feature')
+ expect(names).not_to include('identical')
+ end
end
end
+
+ context 'when Gitaly merged_branch_names feature is enabled' do
+ it_behaves_like 'finding merged branch names'
+ end
+
+ context 'when Gitaly merged_branch_names feature is disabled', :disable_gitaly do
+ it_behaves_like 'finding merged branch names'
+ end
end
describe "#ls_files" do
diff --git a/spec/lib/gitlab/hook_data/issue_builder_spec.rb b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
index aeacd577d18..506b2c0be20 100644
--- a/spec/lib/gitlab/hook_data/issue_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/issue_builder_spec.rb
@@ -14,7 +14,6 @@ describe Gitlab::HookData::IssueBuilder do
closed_at
confidential
created_at
- deleted_at
description
due_date
id
diff --git a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
index 78475403f9e..b61614e4790 100644
--- a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
@@ -12,7 +12,6 @@ describe Gitlab::HookData::MergeRequestBuilder do
assignee_id
author_id
created_at
- deleted_at
description
head_pipeline_id
id
diff --git a/spec/lib/gitlab/import_export/project.group.json b/spec/lib/gitlab/import_export/project.group.json
index 82a1fbd2fc5..1a561e81e4a 100644
--- a/spec/lib/gitlab/import_export/project.group.json
+++ b/spec/lib/gitlab/import_export/project.group.json
@@ -54,7 +54,6 @@
"iid": 1,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
@@ -134,7 +133,6 @@
"iid": 2,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 7580b62cfc0..4cf33778d15 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -56,7 +56,6 @@
"iid": 10,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"test_ee_field": "test",
@@ -350,7 +349,6 @@
"iid": 9,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"milestone": {
@@ -586,7 +584,6 @@
"iid": 8,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"label_links": [
@@ -820,7 +817,6 @@
"iid": 7,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1033,7 +1029,6 @@
"iid": 6,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1246,7 +1241,6 @@
"iid": 5,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1459,7 +1453,6 @@
"iid": 4,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1672,7 +1665,6 @@
"iid": 3,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -1885,7 +1877,6 @@
"iid": 2,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -2098,7 +2089,6 @@
"iid": 1,
"updated_by_id": null,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"notes": [
@@ -2504,7 +2494,6 @@
"merge_when_pipeline_succeeds": true,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 671,
@@ -2948,7 +2937,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 679,
@@ -3228,7 +3216,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 777,
@@ -3508,7 +3495,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 785,
@@ -4198,7 +4184,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 793,
@@ -4734,7 +4719,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 801,
@@ -5223,7 +5207,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 809,
@@ -5478,7 +5461,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 817,
@@ -6168,7 +6150,6 @@
"merge_when_pipeline_succeeds": false,
"merge_user_id": null,
"merge_commit_sha": null,
- "deleted_at": null,
"notes": [
{
"id": 825,
@@ -6968,7 +6949,6 @@
"id": 123,
"token": "cdbfasdf44a5958c83654733449e585",
"project_id": 5,
- "deleted_at": null,
"created_at": "2017-01-16T15:25:28.637Z",
"updated_at": "2017-01-16T15:25:28.637Z"
}
diff --git a/spec/lib/gitlab/import_export/project.light.json b/spec/lib/gitlab/import_export/project.light.json
index 02450478a77..5dbf0ed289b 100644
--- a/spec/lib/gitlab/import_export/project.light.json
+++ b/spec/lib/gitlab/import_export/project.light.json
@@ -54,7 +54,6 @@
"iid": 20,
"updated_by_id": 1,
"confidential": false,
- "deleted_at": null,
"due_date": null,
"moved_to_id": null,
"lock_version": null,
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index ec577903eb5..5a33fa3fd53 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -14,7 +14,6 @@ Issue:
- iid
- updated_by_id
- confidential
-- deleted_at
- closed_at
- due_date
- moved_to_id
@@ -159,7 +158,6 @@ MergeRequest:
- merge_when_pipeline_succeeds
- merge_user_id
- merge_commit_sha
-- deleted_at
- in_progress_merge_commit_sha
- lock_version
- milestone_id
@@ -180,6 +178,7 @@ MergeRequestDiff:
- real_size
- head_commit_sha
- start_commit_sha
+- commits_count
MergeRequestDiffCommit:
- merge_request_diff_id
- relative_order
@@ -293,7 +292,6 @@ Ci::Trigger:
- id
- token
- project_id
-- deleted_at
- created_at
- updated_at
- owner_id
@@ -309,7 +307,6 @@ Ci::PipelineSchedule:
- project_id
- owner_id
- active
-- deleted_at
- created_at
- updated_at
Clusters::Cluster:
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 249c77dc636..2e7a0265a0b 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -26,11 +26,16 @@ describe Gitlab::Workhorse do
'GitalyRepository' => repository.gitaly_repository.to_h.deep_stringify_keys
)
end
+ let(:cache_disabled) { false }
subject do
described_class.send_git_archive(repository, ref: ref, format: format)
end
+ before do
+ allow(described_class).to receive(:git_archive_cache_disabled?).and_return(cache_disabled)
+ end
+
context 'when Gitaly workhorse_archive feature is enabled' do
it 'sets the header correctly' do
key, command, params = decode_workhorse_header(subject)
@@ -39,6 +44,15 @@ describe Gitlab::Workhorse do
expect(command).to eq('git-archive')
expect(params).to include(gitaly_params)
end
+
+ context 'when archive caching is disabled' do
+ let(:cache_disabled) { true }
+
+ it 'tells workhorse not to use the cache' do
+ _, _, params = decode_workhorse_header(subject)
+ expect(params).to include({ 'DisableCache' => true })
+ end
+ end
end
context 'when Gitaly workhorse_archive feature is disabled', :skip_gitaly_mock do
diff --git a/spec/migrations/remove_soft_removed_objects_spec.rb b/spec/migrations/remove_soft_removed_objects_spec.rb
new file mode 100644
index 00000000000..ec089f9106d
--- /dev/null
+++ b/spec/migrations/remove_soft_removed_objects_spec.rb
@@ -0,0 +1,77 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20171207150343_remove_soft_removed_objects.rb')
+
+describe RemoveSoftRemovedObjects, :migration do
+ describe '#up' do
+ it 'removes various soft removed objects' do
+ 5.times do
+ create_with_deleted_at(:issue)
+ end
+
+ regular_issue = create(:issue)
+
+ run_migration
+
+ expect(Issue.count).to eq(1)
+ expect(Issue.first).to eq(regular_issue)
+ end
+
+ it 'removes the temporary indexes once soft removed data has been removed' do
+ migration = described_class.new
+
+ run_migration
+
+ disable_migrations_output do
+ expect(migration.temporary_index_exists?(Issue)).to eq(false)
+ end
+ end
+
+ it 'removes routes of soft removed personal namespaces' do
+ namespace = create_with_deleted_at(:namespace)
+ group = create(:group)
+
+ expect(Route.where(source: namespace).exists?).to eq(true)
+ expect(Route.where(source: group).exists?).to eq(true)
+
+ run_migration
+
+ expect(Route.where(source: namespace).exists?).to eq(false)
+ expect(Route.where(source: group).exists?).to eq(true)
+ end
+
+ it 'schedules the removal of soft removed groups' do
+ group = create_with_deleted_at(:group)
+ admin = create(:user, admin: true)
+
+ expect_any_instance_of(GroupDestroyWorker)
+ .to receive(:perform)
+ .with(group.id, admin.id)
+
+ run_migration
+ end
+
+ it 'does not remove soft removed groups when no admin user could be found' do
+ create_with_deleted_at(:group)
+
+ expect_any_instance_of(GroupDestroyWorker)
+ .not_to receive(:perform)
+
+ run_migration
+ end
+ end
+
+ def run_migration
+ disable_migrations_output do
+ migrate!
+ end
+ end
+
+ def create_with_deleted_at(*args)
+ row = create(*args)
+
+ # We set "deleted_at" this way so we don't run into any column cache issues.
+ row.class.where(id: row.id).update_all(deleted_at: 1.year.ago)
+
+ row
+ end
+end
diff --git a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
index 2e6b2cff0ab..7494624066a 100644
--- a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
+++ b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb
@@ -2,6 +2,12 @@ require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20171128214150_schedule_populate_merge_request_metrics_with_events_data.rb')
describe SchedulePopulateMergeRequestMetricsWithEventsData, :migration, :sidekiq do
+ # commits_count attribute is added in a next migration
+ before do
+ allow_any_instance_of(MergeRequestDiff)
+ .to receive(:commits_count=).and_return(nil)
+ end
+
let!(:mrs) { create_list(:merge_request, 3) }
it 'correctly schedules background migrations' do
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 9a278212efc..8ee15f0e734 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -12,7 +12,6 @@ describe Ci::PipelineSchedule do
it { is_expected.to respond_to(:cron_timezone) }
it { is_expected.to respond_to(:description) }
it { is_expected.to respond_to(:next_run_at) }
- it { is_expected.to respond_to(:deleted_at) }
describe 'validations' do
it 'does not allow invalid cron patters' do
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 5ced000cdb6..f5c9f551e65 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -18,11 +18,6 @@ describe Issue do
subject { create(:issue) }
- describe "act_as_paranoid" do
- it { is_expected.to have_db_column(:deleted_at) }
- it { is_expected.to have_db_index(:deleted_at) }
- end
-
describe 'callbacks' do
describe '#ensure_metrics' do
it 'creates metrics after saving' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 07b3e1c1758..8ff82c4f791 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -24,11 +24,6 @@ describe MergeRequest do
it { is_expected.to include_module(Taskable) }
end
- describe "act_as_paranoid" do
- it { is_expected.to have_db_column(:deleted_at) }
- it { is_expected.to have_db_index(:deleted_at) }
- end
-
describe 'validation' do
it { is_expected.to validate_presence_of(:target_branch) }
it { is_expected.to validate_presence_of(:source_branch) }
@@ -1915,38 +1910,44 @@ describe MergeRequest do
end
describe '#rebase_in_progress?' do
- # Create merge request and project before we stub file calls
- before do
- subject
- end
+ shared_examples 'checking whether a rebase is in progress' do
+ let(:repo_path) { subject.source_project.repository.path }
+ let(:rebase_path) { File.join(repo_path, "gitlab-worktree", "rebase-#{subject.id}") }
- it 'returns true when there is a current rebase directory' do
- allow(File).to receive(:exist?).and_return(true)
- allow(File).to receive(:mtime).and_return(Time.now)
+ before do
+ system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{rebase_path} master))
+ end
- expect(subject.rebase_in_progress?).to be_truthy
- end
+ it 'returns true when there is a current rebase directory' do
+ expect(subject.rebase_in_progress?).to be_truthy
+ end
- it 'returns false when there is no rebase directory' do
- allow(File).to receive(:exist?).and_return(false)
+ it 'returns false when there is no rebase directory' do
+ FileUtils.rm_rf(rebase_path)
- expect(subject.rebase_in_progress?).to be_falsey
- end
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
+
+ it 'returns false when the rebase directory has expired' do
+ time = 20.minutes.ago.to_time
+ File.utime(time, time, rebase_path)
+
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
- it 'returns false when the rebase directory has expired' do
- allow(File).to receive(:exist?).and_return(true)
- allow(File).to receive(:mtime).and_return(20.minutes.ago)
+ it 'returns false when the source project has been removed' do
+ allow(subject).to receive(:source_project).and_return(nil)
- expect(subject.rebase_in_progress?).to be_falsey
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
end
- it 'returns false when the source project has been removed' do
- allow(subject).to receive(:source_project).and_return(nil)
- allow(File).to receive(:exist?).and_return(true)
- allow(File).to receive(:mtime).and_return(Time.now)
+ context 'when Gitaly rebase_in_progress is enabled' do
+ it_behaves_like 'checking whether a rebase is in progress'
+ end
- expect(File).not_to have_received(:exist?)
- expect(subject.rebase_in_progress?).to be_falsey
+ context 'when Gitaly rebase_in_progress is enabled', :disable_gitaly do
+ it_behaves_like 'checking whether a rebase is in progress'
end
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index b3f160f3119..c3673a0e2a3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -410,17 +410,6 @@ describe Namespace do
end
end
- describe '#soft_delete_without_removing_associations' do
- let(:project1) { create(:project_empty_repo, namespace: namespace) }
-
- it 'updates the deleted_at timestamp but preserves projects' do
- namespace.soft_delete_without_removing_associations
-
- expect(Project.all).to include(project1)
- expect(namespace.deleted_at).not_to be_nil
- end
- end
-
describe '#user_ids_for_project_authorizations' do
it 'returns the user IDs for which to refresh authorizations' do
expect(namespace.user_ids_for_project_authorizations)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 00afa09f1a3..78223c44999 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1871,9 +1871,8 @@ describe Project do
end
it 'creates the new reference with rugged' do
- expect(project.repository.rugged.references).to receive(:create).with('HEAD',
- "refs/heads/#{project.default_branch}",
- force: true)
+ expect(project.repository.raw_repository).to receive(:write_ref).with('HEAD', "refs/heads/#{project.default_branch}", shell: false)
+
project.change_head(project.default_branch)
end
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index ddad6862a63..8a3b1034f3c 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -16,6 +16,66 @@ describe Route do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
+
+ describe '#ensure_permanent_paths' do
+ context 'when the route is not yet persisted' do
+ let(:new_route) { described_class.new(path: 'foo', source: build(:group)) }
+
+ context 'when permanent conflicting redirects exist' do
+ it 'is invalid' do
+ redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
+ redirect.save!(validate: false)
+
+ expect(new_route.valid?).to be_falsey
+ expect(new_route.errors.first[1]).to eq('foo has been taken before. Please use another one')
+ end
+ end
+
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(new_route.valid?).to be_truthy
+ end
+ end
+ end
+
+ context 'when path has changed' do
+ before do
+ route.path = 'foo'
+ end
+
+ context 'when permanent conflicting redirects exist' do
+ it 'is invalid' do
+ redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
+ redirect.save!(validate: false)
+
+ expect(route.valid?).to be_falsey
+ expect(route.errors.first[1]).to eq('foo has been taken before. Please use another one')
+ end
+ end
+
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(route.valid?).to be_truthy
+ end
+ end
+ end
+
+ context 'when path has not changed' do
+ context 'when permanent conflicting redirects exist' do
+ it 'is valid' do
+ redirect = build(:redirect_route, :permanent, path: 'git_lab/foo/bar')
+ redirect.save!(validate: false)
+
+ expect(route.valid?).to be_truthy
+ end
+ end
+ context 'when no permanent conflicting redirects exist' do
+ it 'is valid' do
+ expect(route.valid?).to be_truthy
+ end
+ end
+ end
+ end
end
describe 'callbacks' do
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index ffa17d296e8..f246bb79ab7 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -142,6 +142,7 @@ describe API::CommitStatuses do
expect(json_response['ref']).not_to be_empty
expect(json_response['target_url']).to be_nil
expect(json_response['description']).to be_nil
+
if status == 'failed'
expect(CommitStatus.find(json_response['id'])).to be_api_failure
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 0c9fbb1f187..4eae3e50602 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -551,6 +551,49 @@ describe API::MergeRequests do
end
end
+ describe 'GET /projects/:id/merge_requests/:merge_request_iid/pipelines' do
+ context 'when authorized' do
+ let!(:pipeline) { create(:ci_empty_pipeline, project: project, user: user, ref: merge_request.source_branch, sha: merge_request.diff_head_sha) }
+ let!(:pipeline2) { create(:ci_empty_pipeline, project: project) }
+
+ it 'returns a paginated array of corresponding pipelines' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines")
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['id']).to eq(pipeline.id)
+ end
+
+ it 'exposes basic attributes' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines")
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to match_response_schema('public_api/v4/pipelines')
+ end
+
+ it 'returns 404 if MR does not exist' do
+ get api("/projects/#{project.id}/merge_requests/777/pipelines")
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'when unauthorized' do
+ it 'returns 403' do
+ project = create(:project, public_builds: false)
+ merge_request = create(:merge_request, :simple, source_project: project)
+ guest = create(:user)
+ project.add_guest(guest)
+
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/pipelines", guest)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+ end
+
describe "POST /projects/:id/merge_requests" do
context 'between branches projects' do
it "returns merge_request" do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 679d391caa5..cb66d23b77c 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -1142,6 +1142,7 @@ describe API::Runner do
else
{ 'file' => file }
end
+
post api("/jobs/#{job.id}/artifacts"), params, headers
end
end
diff --git a/spec/rubocop/cop/line_break_around_conditional_block_spec.rb b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb
new file mode 100644
index 00000000000..7ddf9141fcd
--- /dev/null
+++ b/spec/rubocop/cop/line_break_around_conditional_block_spec.rb
@@ -0,0 +1,411 @@
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../rubocop/cop/line_break_around_conditional_block'
+
+describe RuboCop::Cop::LineBreakAroundConditionalBlock do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ shared_examples 'examples with conditional' do |conditional|
+ it "flags violation for #{conditional} without line break before" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses.size).to eq(1)
+ offense = cop.offenses.first
+
+ expect(offense.line).to eq(2)
+ expect(cop.highlights).to eq(["#{conditional} condition\n do_something_more\nend"])
+ expect(offense.message).to eq('Add a line break around conditional blocks')
+ end
+
+ it "flags violation for #{conditional} without line break after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ do_something_more
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses.size).to eq(1)
+ offense = cop.offenses.first
+
+ expect(offense.line).to eq(1)
+ expect(cop.highlights).to eq(["#{conditional} condition\n do_something\nend"])
+ expect(offense.message).to eq('Add a line break around conditional blocks')
+ end
+
+ it "doesn't flag violation for #{conditional} with line break before and after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a method definition" do
+ source = <<~RUBY
+ def a_method
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a class definition" do
+ source = <<~RUBY
+ class Foo
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a module definition" do
+ source = <<~RUBY
+ module Foo
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a begin definition" do
+ source = <<~RUBY
+ begin
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an assign/begin definition" do
+ source = <<~RUBY
+ @project ||= begin
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a block definition" do
+ source = <<~RUBY
+ on_block(param_a) do |item|
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a block definition using brackets" do
+ source = <<~RUBY
+ on_block(param_a) { |item|
+ #{conditional} condition
+ do_something
+ end
+ }
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a comment" do
+ source = <<~RUBY
+ # a short comment
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an assignment" do
+ source = <<~RUBY
+ foo =
+ #{conditional} condition
+ do_something
+ else
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a multiline comment" do
+ source = <<~RUBY
+ =begin
+ a multiline comment
+ =end
+ #{conditional} condition
+ do_something
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by another conditional" do
+ source = <<~RUBY
+ #{conditional} condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an else" do
+ source = <<~RUBY
+ if condition_a
+ do_something
+ else
+ #{conditional} condition_b
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an elsif" do
+ source = <<~RUBY
+ if condition_a
+ do_something
+ elsif condition_b
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by an ensure" do
+ source = <<~RUBY
+ def a_method
+ ensure
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} preceded by a when" do
+ source = <<~RUBY
+ case field
+ when value
+ #{conditional} condition_c
+ do_something_extra
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an end" do
+ source = <<~RUBY
+ class Foo
+
+ #{conditional} condition
+ do_something
+ end
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an else" do
+ source = <<~RUBY
+ #{conditional} condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ else
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by a when" do
+ source = <<~RUBY
+ case
+ when condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ when condition_c
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by an elsif" do
+ source = <<~RUBY
+ if condition_a
+ #{conditional} condition_b
+ do_something
+ end
+ elsif condition_c
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "doesn't flag violation for #{conditional} followed by a rescue" do
+ source = <<~RUBY
+ def a_method
+ #{conditional} condition
+ do_something
+ end
+ rescue
+ do_something_extra
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+
+ it "autocorrects #{conditional} without line break before" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ do_something
+
+ #{conditional} condition
+ do_something_more
+ end
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+
+ it "autocorrects #{conditional} without line break after" do
+ source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+ do_something_more
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ #{conditional} condition
+ do_something
+ end
+
+ do_something_more
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+
+ it "autocorrects #{conditional} without line break before and after" do
+ source = <<~RUBY
+ do_something
+ #{conditional} condition
+ do_something_more
+ end
+ do_something_extra
+ RUBY
+ autocorrected = autocorrect_source(source)
+
+ expected_source = <<~RUBY
+ do_something
+
+ #{conditional} condition
+ do_something_more
+ end
+
+ do_something_extra
+ RUBY
+ expect(autocorrected).to eql(expected_source)
+ end
+ end
+
+ %w[if unless].each do |example|
+ it_behaves_like 'examples with conditional', example
+ end
+
+ it "doesn't flag violation for if with elsif" do
+ source = <<~RUBY
+ if condition
+ do_something
+ elsif another_condition
+ do_something_more
+ end
+ RUBY
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+end
diff --git a/spec/services/check_gcp_project_billing_service_spec.rb b/spec/services/check_gcp_project_billing_service_spec.rb
index f0e39ba6f49..3e68d906e71 100644
--- a/spec/services/check_gcp_project_billing_service_spec.rb
+++ b/spec/services/check_gcp_project_billing_service_spec.rb
@@ -1,29 +1,30 @@
require 'spec_helper'
describe CheckGcpProjectBillingService do
+ include GoogleApi::CloudPlatformHelpers
+
let(:service) { described_class.new }
- let(:projects) { [double(name: 'first_project'), double(name: 'second_project')] }
+ let(:project_id) { 'test-project-1234' }
describe '#execute' do
before do
- expect_any_instance_of(GoogleApi::CloudPlatform::Client)
- .to receive(:projects_list).and_return(projects)
-
- allow_any_instance_of(GoogleApi::CloudPlatform::Client)
- .to receive_message_chain(:projects_get_billing_info, :billingEnabled)
- .and_return(project_billing_enabled)
+ stub_cloud_platform_projects_list(project_id: project_id)
end
subject { service.execute('bogustoken') }
context 'google account has a billing enabled gcp project' do
- let(:project_billing_enabled) { true }
+ before do
+ stub_cloud_platform_projects_get_billing_info(project_id, true)
+ end
- it { is_expected.to eq(projects) }
+ it { is_expected.to all(satisfy { |project| project.project_id == project_id }) }
end
context 'google account does not have a billing enabled gcp project' do
- let(:project_billing_enabled) { false }
+ before do
+ stub_cloud_platform_projects_get_billing_info(project_id, false)
+ end
it { is_expected.to eq([]) }
end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 53ea88332fb..f3c98fa5416 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -179,13 +179,15 @@ describe Issues::MoveService do
{ system: true, note: 'Some system note' },
{ system: false, note: 'Some comment 2' }]
end
-
+ let(:award_names) { %w(thumbsup thumbsdown facepalm) }
let(:notes_contents) { notes_params.map { |n| n[:note] } }
before do
note_params = { noteable: old_issue, project: old_project, author: author }
- notes_params.each do |note|
- create(:note, note_params.merge(note))
+ notes_params.each_with_index do |note, index|
+ new_note = create(:note, note_params.merge(note))
+ award_emoji_params = { awardable: new_note, name: award_names[index] }
+ create(:award_emoji, award_emoji_params)
end
end
@@ -199,6 +201,10 @@ describe Issues::MoveService do
expect(all_notes.pluck(:note).first(3)).to eq notes_contents
end
+ it 'creates new emojis for the new notes' do
+ expect(all_notes.map(&:award_emoji).to_a.flatten.map(&:name)).to eq award_names
+ end
+
it 'adds a system note about move after rewritten notes' do
expect(system_notes.last.note).to match /^moved from/
end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index a9605c6e4c6..cb4c3e72aa0 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -171,6 +171,24 @@ describe MergeRequests::BuildService do
end
end
end
+
+ context 'branch starts with external issue IID followed by a hyphen' do
+ let(:source_branch) { '12345-fix-issue' }
+
+ before do
+ allow(project).to receive(:external_issue_tracker).and_return(true)
+ end
+
+ it 'uses the title of the commit as the title of the merge request' do
+ expect(merge_request.title).to eq(commit_1.safe_message.split("\n").first)
+ end
+
+ it 'uses the description of the commit as the description of the merge request and appends the closes text' do
+ commit_description = commit_1.safe_message.split(/\n+/, 2).last
+
+ expect(merge_request.description).to eq("#{commit_description}\n\nCloses #12345")
+ end
+ end
end
context 'more than one commit in the diff' do
@@ -241,8 +259,12 @@ describe MergeRequests::BuildService do
allow(project).to receive(:external_issue_tracker).and_return(true)
end
- it 'sets the title to: Resolves External Issue $issue-iid' do
- expect(merge_request.title).to eq('Resolve External Issue 12345')
+ it 'sets the title to the humanized branch title' do
+ expect(merge_request.title).to eq('12345 fix issue')
+ end
+
+ it 'appends the closes text' do
+ expect(merge_request.description).to eq('Closes #12345')
end
end
end
diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb
index d1b37cdd073..fc1c3d67203 100644
--- a/spec/services/merge_requests/rebase_service_spec.rb
+++ b/spec/services/merge_requests/rebase_service_spec.rb
@@ -32,70 +32,80 @@ describe MergeRequests::RebaseService do
it 'returns an error' do
expect(service.execute(merge_request)).to match(status: :error,
- message: 'Failed to rebase. Should be done manually')
+ message: described_class::REBASE_ERROR)
end
end
- context 'when unexpected error occurs' do
+ context 'when unexpected error occurs', :disable_gitaly do
before do
allow(repository).to receive(:run_git!).and_raise('Something went wrong')
end
- it 'saves the error message' do
+ it 'saves a generic error message' do
subject.execute(merge_request)
- expect(merge_request.reload.merge_error).to eq 'Something went wrong'
+ expect(merge_request.reload.merge_error).to eq described_class::REBASE_ERROR
end
it 'returns an error' do
expect(service.execute(merge_request)).to match(status: :error,
- message: 'Failed to rebase. Should be done manually')
+ message: described_class::REBASE_ERROR)
end
end
- context 'with git command failure' do
+ context 'with git command failure', :disable_gitaly do
before do
allow(repository).to receive(:run_git!).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong')
end
- it 'saves the error message' do
+ it 'saves a generic error message' do
subject.execute(merge_request)
- expect(merge_request.reload.merge_error).to eq 'Something went wrong'
+ expect(merge_request.reload.merge_error).to eq described_class::REBASE_ERROR
end
it 'returns an error' do
expect(service.execute(merge_request)).to match(status: :error,
- message: 'Failed to rebase. Should be done manually')
+ message: described_class::REBASE_ERROR)
end
end
context 'valid params' do
- before do
- service.execute(merge_request)
- end
+ shared_examples 'successful rebase' do
+ before do
+ service.execute(merge_request)
+ end
- it 'rebases source branch' do
- parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
- target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
- expect(parent_sha).to eq(target_branch_sha)
- end
+ it 'rebases source branch' do
+ parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha
+ target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
+ expect(parent_sha).to eq(target_branch_sha)
+ end
+
+ it 'records the new SHA on the merge request' do
+ head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
+ expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
+ end
+
+ it 'logs correct author and commiter' do
+ head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
- it 'records the new SHA on the merge request' do
- head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
- expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
+ expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
+ expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
+ expect(head_commit.committer_email).to eq(user.email)
+ expect(head_commit.committer_name).to eq(user.name)
+ end
end
- it 'logs correct author and commiter' do
- head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
+ context 'when Gitaly rebase feature is enabled' do
+ it_behaves_like 'successful rebase'
+ end
- expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
- expect(head_commit.author_name).to eq('Dmitriy Zaporozhets')
- expect(head_commit.committer_email).to eq(user.email)
- expect(head_commit.committer_name).to eq(user.name)
+ context 'when Gitaly rebase feature is disabled', :disable_gitaly do
+ it_behaves_like 'successful rebase'
end
- context 'git commands' do
+ context 'git commands', :disable_gitaly do
it 'sets GL_REPOSITORY env variable when calling git commands' do
expect(repository).to receive(:popen).exactly(3)
.with(anything, anything, hash_including('GL_REPOSITORY'))
@@ -106,27 +116,37 @@ describe MergeRequests::RebaseService do
end
context 'fork' do
- let(:forked_project) do
- fork_project(project, user, repository: true)
+ shared_examples 'successful fork rebase' do
+ let(:forked_project) do
+ fork_project(project, user, repository: true)
+ end
+
+ let(:merge_request_from_fork) do
+ forked_project.repository.create_file(
+ user,
+ 'new-file-to-target',
+ '',
+ message: 'Add new file to target',
+ branch_name: 'master')
+
+ create(:merge_request,
+ source_branch: 'master', source_project: forked_project,
+ target_branch: 'master', target_project: project)
+ end
+
+ it 'rebases source branch' do
+ parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
+ target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
+ expect(parent_sha).to eq(target_branch_sha)
+ end
end
- let(:merge_request_from_fork) do
- forked_project.repository.create_file(
- user,
- 'new-file-to-target',
- '',
- message: 'Add new file to target',
- branch_name: 'master')
-
- create(:merge_request,
- source_branch: 'master', source_project: forked_project,
- target_branch: 'master', target_project: project)
+ context 'when Gitaly rebase feature is enabled' do
+ it_behaves_like 'successful fork rebase'
end
- it 'rebases source branch' do
- parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha
- target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha
- expect(parent_sha).to eq(target_branch_sha)
+ context 'when Gitaly rebase feature is disabled', :disable_gitaly do
+ it_behaves_like 'successful fork rebase'
end
end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 39f6388c25e..ef68742a463 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -150,6 +150,7 @@ describe Projects::TransferService do
before do
group.add_owner(user)
+
unless gitlab_shell.add_repository(repository_storage, "#{group.full_path}/#{project.path}")
raise 'failed to add repository'
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 4e640a82dfc..965fd39c967 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -727,6 +727,7 @@ describe SystemNoteService do
else
"#{Settings.gitlab.base_url}/#{project.namespace.path}/#{project.path}/merge_requests/#{merge_request.iid}"
end
+
link = double(object: { 'url' => url })
links << link
expect(link).to receive(:save!)
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index aeba9cd60bc..bb3d73edf8e 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -15,7 +15,7 @@ describe Users::DestroyService do
expect { user_data['email'].to eq(user.email) }
expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- expect { Namespace.with_deleted.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
+ expect { Namespace.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
it 'will delete the project' do
diff --git a/spec/support/features/discussion_comments_shared_example.rb b/spec/support/features/discussion_comments_shared_example.rb
index c24940393f9..fa94aa2ae3d 100644
--- a/spec/support/features/discussion_comments_shared_example.rb
+++ b/spec/support/features/discussion_comments_shared_example.rb
@@ -113,6 +113,7 @@ shared_examples 'discussion comments' do |resource_name|
else
expect(find(submit_selector).value).to eq 'Start discussion'
end
+
expect(page).not_to have_selector menu_selector
end
@@ -200,6 +201,7 @@ shared_examples 'discussion comments' do |resource_name|
else
expect(find(submit_selector).value).to eq 'Comment'
end
+
expect(page).not_to have_selector menu_selector
end
diff --git a/spec/support/filtered_search_helpers.rb b/spec/support/filtered_search_helpers.rb
index 05021ea9054..f3f96bd1f0a 100644
--- a/spec/support/filtered_search_helpers.rb
+++ b/spec/support/filtered_search_helpers.rb
@@ -61,9 +61,11 @@ module FilteredSearchHelpers
token_emoji = tokens[index][:emoji_name]
expect(el.find('.name')).to have_content(token_name)
+
if token_value
expect(el.find('.value')).to have_content(token_value)
end
+
# gl-emoji content is blank when the emoji unicode is not supported
if token_emoji
selector = %(gl-emoji[data-name="#{token_emoji}"])
diff --git a/spec/support/generate-seed-repo-rb b/spec/support/generate-seed-repo-rb
index 4ee33f9725b..876b3b8242d 100755
--- a/spec/support/generate-seed-repo-rb
+++ b/spec/support/generate-seed-repo-rb
@@ -24,6 +24,7 @@ def main
unless system(*%W[git clone --bare #{SOURCE} #{REPO_NAME}], chdir: dir)
abort "git clone failed"
end
+
repo = File.join(dir, REPO_NAME)
erb = ERB.new(DATA.read)
erb.run(binding)
diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb
index 99752ed396e..2fdbddd40c2 100644
--- a/spec/support/google_api/cloud_platform_helpers.rb
+++ b/spec/support/google_api/cloud_platform_helpers.rb
@@ -10,10 +10,14 @@ module GoogleApi
request.session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] = 1.hour.ago.to_i.to_s
end
- def stub_google_project_billing_status
- redis_double = double
- allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double)
- allow(redis_double).to receive(:get).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for('token')).and_return('true')
+ def stub_cloud_platform_projects_list(options)
+ WebMock.stub_request(:get, cloud_platform_projects_list_url)
+ .to_return(cloud_platform_response(cloud_platform_projects_body(options)))
+ end
+
+ def stub_cloud_platform_projects_get_billing_info(project_id, billing_enabled)
+ WebMock.stub_request(:get, cloud_platform_projects_get_billing_info_url(project_id))
+ .to_return(cloud_platform_response(cloud_platform_projects_billing_info_body(project_id, billing_enabled)))
end
def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, **options)
@@ -46,6 +50,14 @@ module GoogleApi
.to_return(status: [500, "Internal Server Error"])
end
+ def cloud_platform_projects_list_url
+ "https://cloudresourcemanager.googleapis.com/v1/projects"
+ end
+
+ def cloud_platform_projects_get_billing_info_url(project_id)
+ "https://cloudbilling.googleapis.com/v1/projects/#{project_id}/billingInfo"
+ end
+
def cloud_platform_get_zone_cluster_url(project_id, zone, cluster_id)
"https://container.googleapis.com/v1/projects/#{project_id}/zones/#{zone}/clusters/#{cluster_id}"
end
@@ -121,5 +133,32 @@ module GoogleApi
"endTime": options[:endTime] || ''
}
end
+
+ def cloud_platform_projects_body(**options)
+ {
+ "projects": [
+ {
+ "projectNumber": options[:project_number] || "1234",
+ "projectId": options[:project_id] || "test-project-1234",
+ "lifecycleState": "ACTIVE",
+ "name": options[:name] || "test-project",
+ "createTime": "2017-12-16T01:48:29.129Z",
+ "parent": {
+ "type": "organization",
+ "id": "12345"
+ }
+ }
+ ]
+ }
+ end
+
+ def cloud_platform_projects_billing_info_body(project_id, billing_enabled)
+ {
+ "name": "projects/#{project_id}/billingInfo",
+ "projectId": "#{project_id}",
+ "billingAccountName": "account-name",
+ "billingEnabled": billing_enabled
+ }
+ end
end
end
diff --git a/spec/support/matchers/access_matchers_for_controller.rb b/spec/support/matchers/access_matchers_for_controller.rb
index cdb62a5deee..42a9ed9ff34 100644
--- a/spec/support/matchers/access_matchers_for_controller.rb
+++ b/spec/support/matchers/access_matchers_for_controller.rb
@@ -43,6 +43,7 @@ module AccessMatchersForController
user = create(:user)
membership.public_send(:"add_#{role}", user)
end
+
user
end
diff --git a/spec/support/select2_helper.rb b/spec/support/select2_helper.rb
index 55da961e173..90618ba5b19 100644
--- a/spec/support/select2_helper.rb
+++ b/spec/support/select2_helper.rb
@@ -17,6 +17,7 @@ module Select2Helper
selector = options.fetch(:from)
first(selector, visible: false)
+
if options[:multiple]
execute_script("$('#{selector}').select2('val', ['#{value}']).trigger('change');")
else
diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb
index f621463e621..695152e2d4e 100644
--- a/spec/support/stub_env.rb
+++ b/spec/support/stub_env.rb
@@ -4,6 +4,7 @@ module StubENV
def stub_env(key_or_hash, value = nil)
init_stub unless env_stubbed?
+
if key_or_hash.is_a? Hash
key_or_hash.each { |k, v| add_stubbed_value(k, v) }
else
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 664698fcbaf..25ff6094408 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -325,6 +325,7 @@ module TestEnv
if component_needs_update?(install_dir, version)
# Cleanup the component entirely to ensure we start fresh
FileUtils.rm_rf(install_dir)
+
unless system('rake', task)
raise ComponentFailedToInstallError
end
diff --git a/spec/support/wait_for_requests.rb b/spec/support/wait_for_requests.rb
index f4130d68271..fda0e29f983 100644
--- a/spec/support/wait_for_requests.rb
+++ b/spec/support/wait_for_requests.rb
@@ -53,6 +53,7 @@ module WaitForRequests
wait_until = Time.now + max_wait_time.seconds
loop do
break if yield
+
if Time.now > wait_until
raise "Condition not met: #{condition_name}"
else
diff --git a/spec/views/projects/buttons/_dropdown.html.haml_spec.rb b/spec/views/projects/buttons/_dropdown.html.haml_spec.rb
new file mode 100644
index 00000000000..d0e692635b9
--- /dev/null
+++ b/spec/views/projects/buttons/_dropdown.html.haml_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'projects/buttons/_dropdown' do
+ let(:user) { create(:user) }
+
+ context 'user with all abilities' do
+ before do
+ assign(:project, project)
+
+ allow(view).to receive(:current_user).and_return(user)
+ allow(view).to receive(:can?).and_return(true)
+ end
+
+ context 'empty repository' do
+ let(:project) { create(:project, :empty_repo) }
+
+ it 'has a link to create a new file' do
+ render
+
+ expect(view).to render_template('projects/buttons/_dropdown')
+ expect(rendered).to have_link('New file')
+ end
+
+ it 'does not have a link to create a new branch' do
+ render
+
+ expect(view).to render_template('projects/buttons/_dropdown')
+ expect(rendered).not_to have_link('New branch')
+ end
+
+ it 'does not have a link to create a new tag' do
+ render
+
+ expect(view).to render_template('projects/buttons/_dropdown')
+ expect(rendered).not_to have_link('New tag')
+ end
+ end
+ end
+end
diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb
index f52a903327c..7b7a7c1bc44 100644
--- a/spec/workers/check_gcp_project_billing_worker_spec.rb
+++ b/spec/workers/check_gcp_project_billing_worker_spec.rb
@@ -8,7 +8,7 @@ describe CheckGcpProjectBillingWorker do
context 'when there is a token in redis' do
before do
- allow_any_instance_of(described_class).to receive(:get_session_token).and_return(token)
+ allow(described_class).to receive(:get_session_token).and_return(token)
end
context 'when there is no lease' do