summaryrefslogtreecommitdiff
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/access_token_validation_service_spec.rb45
-rw-r--r--spec/services/after_branch_delete_service_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb90
-rw-r--r--spec/services/boards/create_service_spec.rb11
-rw-r--r--spec/services/boards/issues/create_service_spec.rb4
-rw-r--r--spec/services/boards/issues/list_service_spec.rb15
-rw-r--r--spec/services/boards/issues/move_service_spec.rb6
-rw-r--r--spec/services/boards/list_service_spec.rb4
-rw-r--r--spec/services/boards/lists/create_service_spec.rb4
-rw-r--r--spec/services/boards/lists/destroy_service_spec.rb4
-rw-r--r--spec/services/boards/lists/generate_service_spec.rb4
-rw-r--r--spec/services/boards/lists/list_service_spec.rb33
-rw-r--r--spec/services/boards/lists/move_service_spec.rb4
-rw-r--r--spec/services/chat_names/authorize_user_service_spec.rb2
-rw-r--r--spec/services/chat_names/find_user_service_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb242
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb26
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb83
-rw-r--r--spec/services/ci/play_build_service_spec.rb8
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb39
-rw-r--r--spec/services/ci/register_job_service_spec.rb8
-rw-r--r--spec/services/ci/retry_build_service_spec.rb26
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb24
-rw-r--r--spec/services/ci/stop_environments_service_spec.rb2
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb10
-rw-r--r--spec/services/ci/update_runner_service_spec.rb2
-rw-r--r--spec/services/compare_service_spec.rb2
-rw-r--r--spec/services/create_branch_service_spec.rb2
-rw-r--r--spec/services/create_deployment_service_spec.rb63
-rw-r--r--spec/services/create_release_service_spec.rb4
-rw-r--r--spec/services/create_snippet_service_spec.rb2
-rw-r--r--spec/services/delete_branch_service_spec.rb2
-rw-r--r--spec/services/delete_merged_branches_service_spec.rb20
-rw-r--r--spec/services/discussions/update_diff_position_service_spec.rb2
-rw-r--r--spec/services/emails/create_service_spec.rb21
-rw-r--r--spec/services/emails/destroy_service_spec.rb14
-rw-r--r--spec/services/event_create_service_spec.rb10
-rw-r--r--spec/services/files/update_service_spec.rb4
-rw-r--r--spec/services/git_hooks_service_spec.rb11
-rw-r--r--spec/services/git_push_service_spec.rb315
-rw-r--r--spec/services/git_tag_push_service_spec.rb6
-rw-r--r--spec/services/gravatar_service_spec.rb2
-rw-r--r--spec/services/groups/create_service_spec.rb10
-rw-r--r--spec/services/groups/destroy_service_spec.rb68
-rw-r--r--spec/services/groups/update_service_spec.rb8
-rw-r--r--spec/services/import_export_clean_up_service_spec.rb2
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb6
-rw-r--r--spec/services/issues/build_service_spec.rb2
-rw-r--r--spec/services/issues/close_service_spec.rb26
-rw-r--r--spec/services/issues/create_service_spec.rb12
-rw-r--r--spec/services/issues/duplicate_service_spec.rb80
-rw-r--r--spec/services/issues/move_service_spec.rb81
-rw-r--r--spec/services/issues/reopen_service_spec.rb4
-rw-r--r--spec/services/issues/resolve_discussions_spec.rb2
-rw-r--r--spec/services/issues/update_service_spec.rb76
-rw-r--r--spec/services/labels/create_service_spec.rb40
-rw-r--r--spec/services/labels/find_or_create_service_spec.rb4
-rw-r--r--spec/services/labels/promote_service_spec.rb18
-rw-r--r--spec/services/labels/transfer_service_spec.rb6
-rw-r--r--spec/services/labels/update_service_spec.rb14
-rw-r--r--spec/services/members/approve_access_request_service_spec.rb4
-rw-r--r--spec/services/members/authorized_destroy_service_spec.rb6
-rw-r--r--spec/services/members/create_service_spec.rb8
-rw-r--r--spec/services/members/destroy_service_spec.rb8
-rw-r--r--spec/services/members/request_access_service_spec.rb8
-rw-r--r--spec/services/merge_requests/assign_issues_service_spec.rb2
-rw-r--r--spec/services/merge_requests/build_service_spec.rb12
-rw-r--r--spec/services/merge_requests/close_service_spec.rb6
-rw-r--r--spec/services/merge_requests/conflicts/resolve_service_spec.rb29
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb2
-rw-r--r--spec/services/merge_requests/create_service_spec.rb16
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb2
-rw-r--r--spec/services/merge_requests/merge_request_diff_cache_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb81
-rw-r--r--spec/services/merge_requests/post_merge_service_spec.rb2
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb74
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb8
-rw-r--r--spec/services/merge_requests/resolved_discussion_notification_service_spec.rb2
-rw-r--r--spec/services/merge_requests/update_service_spec.rb55
-rw-r--r--spec/services/milestones/close_service_spec.rb6
-rw-r--r--spec/services/milestones/create_service_spec.rb6
-rw-r--r--spec/services/milestones/destroy_service_spec.rb51
-rw-r--r--spec/services/note_summary_spec.rb4
-rw-r--r--spec/services/notes/build_service_spec.rb2
-rw-r--r--spec/services/notes/create_service_spec.rb4
-rw-r--r--spec/services/notes/destroy_service_spec.rb4
-rw-r--r--spec/services/notes/post_process_service_spec.rb6
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb (renamed from spec/services/notes/slash_commands_service_spec.rb)20
-rw-r--r--spec/services/notes/update_service_spec.rb4
-rw-r--r--spec/services/notification_recipient_service_spec.rb34
-rw-r--r--spec/services/notification_service_spec.rb88
-rw-r--r--spec/services/pages_service_spec.rb16
-rw-r--r--spec/services/preview_markdown_service_spec.rb20
-rw-r--r--spec/services/projects/autocomplete_service_spec.rb4
-rw-r--r--spec/services/projects/create_service_spec.rb4
-rw-r--r--spec/services/projects/destroy_service_spec.rb85
-rw-r--r--spec/services/projects/download_service_spec.rb4
-rw-r--r--spec/services/projects/enable_deploy_key_service_spec.rb4
-rw-r--r--spec/services/projects/fork_service_spec.rb10
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb12
-rw-r--r--spec/services/projects/import_service_spec.rb22
-rw-r--r--spec/services/projects/participants_service_spec.rb8
-rw-r--r--spec/services/projects/propagate_service_template_spec.rb18
-rw-r--r--spec/services/projects/transfer_service_spec.rb101
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb10
-rw-r--r--spec/services/projects/update_pages_configuration_service_spec.rb4
-rw-r--r--spec/services/projects/update_pages_service_spec.rb72
-rw-r--r--spec/services/projects/update_service_spec.rb59
-rw-r--r--spec/services/protected_branches/create_service_spec.rb4
-rw-r--r--spec/services/protected_branches/update_service_spec.rb2
-rw-r--r--spec/services/protected_tags/create_service_spec.rb4
-rw-r--r--spec/services/protected_tags/update_service_spec.rb2
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb (renamed from spec/services/slash_commands/interpret_service_spec.rb)127
-rw-r--r--spec/services/repair_ldap_blocked_user_service_spec.rb4
-rw-r--r--spec/services/repository_archive_clean_up_service_spec.rb2
-rw-r--r--spec/services/search/global_service_spec.rb18
-rw-r--r--spec/services/search/group_service_spec.rb16
-rw-r--r--spec/services/search/snippet_service_spec.rb4
-rw-r--r--spec/services/search_service_spec.rb68
-rw-r--r--spec/services/spam_service_spec.rb8
-rw-r--r--spec/services/submit_usage_ping_service_spec.rb4
-rw-r--r--spec/services/system_hooks_service_spec.rb4
-rw-r--r--spec/services/system_note_service_spec.rb126
-rw-r--r--spec/services/tags/create_service_spec.rb14
-rw-r--r--spec/services/tags/destroy_service_spec.rb2
-rw-r--r--spec/services/test_hook_service_spec.rb14
-rw-r--r--spec/services/test_hooks/project_service_spec.rb188
-rw-r--r--spec/services/test_hooks/system_service_spec.rb82
-rw-r--r--spec/services/todo_service_spec.rb26
-rw-r--r--spec/services/update_release_service_spec.rb4
-rw-r--r--spec/services/update_snippet_service_spec.rb2
-rw-r--r--spec/services/upload_service_spec.rb4
-rw-r--r--spec/services/user_project_access_changed_service_spec.rb4
-rw-r--r--spec/services/users/activity_service_spec.rb10
-rw-r--r--spec/services/users/build_service_spec.rb2
-rw-r--r--spec/services/users/create_service_spec.rb2
-rw-r--r--spec/services/users/destroy_service_spec.rb6
-rw-r--r--spec/services/users/migrate_to_ghost_user_service_spec.rb35
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb40
-rw-r--r--spec/services/users/update_service_spec.rb43
-rw-r--r--spec/services/web_hook_service_spec.rb35
-rw-r--r--spec/services/wiki_pages/create_service_spec.rb4
-rw-r--r--spec/services/wiki_pages/destroy_service_spec.rb4
-rw-r--r--spec/services/wiki_pages/update_service_spec.rb4
144 files changed, 2638 insertions, 930 deletions
diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb
index 87f093ee8ce..38a3f522504 100644
--- a/spec/services/access_token_validation_service_spec.rb
+++ b/spec/services/access_token_validation_service_spec.rb
@@ -1,41 +1,72 @@
require 'spec_helper'
-describe AccessTokenValidationService, services: true do
+describe AccessTokenValidationService do
describe ".include_any_scope?" do
+ let(:request) { double("request") }
+
it "returns true if the required scope is present in the token's scopes" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:api]
- expect(described_class.new(token).include_any_scope?([:api])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if more than one of the required scopes is present in the token's scopes" do
token = double("token", scopes: [:api, :read_user, :other_scope])
+ scopes = [:api, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if the list of required scopes is an exact match for the token's scopes" do
token = double("token", scopes: [:api, :read_user, :other_scope])
+ scopes = [:api, :read_user, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :read_user, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns true if the list of required scopes contains all of the token's scopes, in addition to others" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:api, :read_user, :other_scope]
- expect(described_class.new(token).include_any_scope?([:api, :read_user, :other_scope])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it 'returns true if the list of required scopes is blank' do
token = double("token", scopes: [])
+ scopes = []
- expect(described_class.new(token).include_any_scope?([])).to be(true)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
end
it "returns false if there are no scopes in common between the required scopes and the token scopes" do
token = double("token", scopes: [:api, :read_user])
+ scopes = [:other_scope]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(false)
+ end
+
+ context "conditions" do
+ it "ignores any scopes whose `if` condition returns false" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { false })]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(false)
+ end
+
+ it "does not ignore scopes whose `if` condition is not set" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { false }), :read_user]
+
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
+ end
+
+ it "does not ignore scopes whose `if` condition returns true" do
+ token = double("token", scopes: [:api, :read_user])
+ scopes = [API::Scope.new(:api, if: ->(_) { true }), API::Scope.new(:read_user, if: ->(_) { false })]
- expect(described_class.new(token).include_any_scope?([:other_scope])).to be(false)
+ expect(described_class.new(token, request: request).include_any_scope?(scopes)).to be(true)
+ end
end
end
end
diff --git a/spec/services/after_branch_delete_service_spec.rb b/spec/services/after_branch_delete_service_spec.rb
index 77ca17bc82c..bc9747d1413 100644
--- a/spec/services/after_branch_delete_service_spec.rb
+++ b/spec/services/after_branch_delete_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe AfterBranchDeleteService, services: true do
+describe AfterBranchDeleteService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index e273dfe1552..d23c09d6d1d 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Auth::ContainerRegistryAuthenticationService, services: true do
+describe Auth::ContainerRegistryAuthenticationService do
let(:current_project) { nil }
let(:current_user) { nil }
let(:current_params) { {} }
@@ -34,7 +34,9 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for changed configuration' do
- before { stub_application_setting(container_registry_token_expire_delay: expire_delay) }
+ before do
+ stub_application_setting(container_registry_token_expire_delay: expire_delay)
+ end
it { expect(expires_at).to be_within(2.seconds).of(Time.now + expire_delay.minutes) }
end
@@ -44,7 +46,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
shared_examples 'an accessible' do
let(:access) do
[{ 'type' => 'repository',
- 'name' => project.path_with_namespace,
+ 'name' => project.full_path,
'actions' => actions }]
end
@@ -94,8 +96,8 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
describe '#full_access_token' do
- let(:project) { create(:empty_project) }
- let(:token) { described_class.full_access_token(project.path_with_namespace) }
+ let(:project) { create(:project) }
+ let(:token) { described_class.full_access_token(project.full_path) }
subject { { token: token } }
@@ -110,17 +112,19 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
let(:current_user) { create(:user) }
context 'for private project' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
context 'allow to use scope-less authentication' do
it_behaves_like 'a valid token'
end
context 'allow developer to push images' do
- before { project.team << [current_user, :developer] }
+ before do
+ project.team << [current_user, :developer]
+ end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'a pushable'
@@ -128,11 +132,13 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'allow reporter to pull images' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
context 'when pulling from root level repository' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -141,10 +147,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'return a least of privileges' do
- before { project.team << [current_user, :reporter] }
+ before do
+ project.team << [current_user, :reporter]
+ end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push,pull" }
+ { scope: "repository:#{project.full_path}:push,pull" }
end
it_behaves_like 'a pullable'
@@ -152,10 +160,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'disallow guest to pull or push images' do
- before { project.team << [current_user, :guest] }
+ before do
+ project.team << [current_user, :guest]
+ end
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'an inaccessible'
@@ -164,11 +174,11 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for public project' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
context 'allow anyone to pull images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -177,7 +187,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'disallow anyone to push images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'an inaccessible'
@@ -195,12 +205,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for internal project' do
- let(:project) { create(:empty_project, :internal) }
+ let(:project) { create(:project, :internal) }
context 'for internal user' do
context 'allow anyone to pull images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a pullable'
@@ -209,7 +219,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'disallow anyone to push images' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'an inaccessible'
@@ -220,7 +230,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'for external user' do
let(:current_user) { create(:user, external: true) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'an inaccessible'
@@ -230,7 +240,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'build authorized as user' do
- let(:current_project) { create(:empty_project) }
+ let(:current_project) { create(:project) }
let(:current_user) { create(:user) }
let(:authentication_abilities) do
@@ -245,7 +255,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'allow to pull and push images' do
let(:current_params) do
- { scope: "repository:#{current_project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{current_project.full_path}:pull,push" }
end
it_behaves_like 'a pullable and pushable' do
@@ -260,11 +270,11 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'for other projects' do
context 'when pulling' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
context 'allow for public' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
@@ -286,7 +296,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'when you are owner' do
- let(:project) { create(:empty_project, namespace: current_user.namespace) }
+ let(:project) { create(:project, namespace: current_user.namespace) }
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
@@ -294,7 +304,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for private' do
- let(:project) { create(:empty_project, :private) }
+ let(:project) { create(:project, :private) }
it_behaves_like 'pullable for being team member'
@@ -316,7 +326,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'when you are owner' do
- let(:project) { create(:empty_project, namespace: current_user.namespace) }
+ let(:project) { create(:project, namespace: current_user.namespace) }
it_behaves_like 'a pullable'
it_behaves_like 'not a container repository factory'
@@ -327,12 +337,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'when pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
context 'disallow for all' do
context 'when you are member' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
before do
project.team << [current_user, :developer]
@@ -343,7 +353,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'when you are owner' do
- let(:project) { create(:empty_project, :public, namespace: current_user.namespace) }
+ let(:project) { create(:project, :public, namespace: current_user.namespace) }
it_behaves_like 'an inaccessible'
it_behaves_like 'not a container repository factory'
@@ -353,13 +363,15 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for project without container registry' do
- let(:project) { create(:empty_project, :public, container_registry_enabled: false) }
+ let(:project) { create(:project, :public, container_registry_enabled: false) }
- before { project.update(container_registry_enabled: false) }
+ before do
+ project.update(container_registry_enabled: false)
+ end
context 'disallow when pulling' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'an inaccessible'
@@ -384,21 +396,21 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
context 'for private project' do
- let(:project) { create(:empty_project, :private) }
+ let(:project) { create(:project, :private) }
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull" }
+ { scope: "repository:#{project.full_path}:pull" }
end
it_behaves_like 'a forbidden'
end
context 'for public project' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
context 'when pulling and pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:pull,push" }
+ { scope: "repository:#{project.full_path}:pull,push" }
end
it_behaves_like 'a pullable'
@@ -407,7 +419,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'when pushing' do
let(:current_params) do
- { scope: "repository:#{project.path_with_namespace}:push" }
+ { scope: "repository:#{project.full_path}:push" }
end
it_behaves_like 'a forbidden'
diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb
index a8555f5b4a0..db51a524e79 100644
--- a/spec/services/boards/create_service_spec.rb
+++ b/spec/services/boards/create_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::CreateService, services: true do
+describe Boards::CreateService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
subject(:service) { described_class.new(project, double) }
@@ -14,8 +14,9 @@ describe Boards::CreateService, services: true do
it 'creates the default lists' do
board = service.execute
- expect(board.lists.size).to eq 1
- expect(board.lists.first).to be_closed
+ expect(board.lists.size).to eq 2
+ expect(board.lists.first).to be_backlog
+ expect(board.lists.last).to be_closed
end
end
@@ -25,6 +26,8 @@ describe Boards::CreateService, services: true do
end
it 'does not create a new board' do
+ expect(service).to receive(:can_create_board?) { false }
+
expect { service.execute }.not_to change(project.boards, :count)
end
end
diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb
index 360ee398f77..f2ddaa903da 100644
--- a/spec/services/boards/issues/create_service_spec.rb
+++ b/spec/services/boards/issues/create_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::Issues::CreateService, services: true do
+describe Boards::Issues::CreateService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
let(:label) { create(:label, project: project, name: 'in-progress') }
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index c982031c791..01ee3856c99 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Boards::Issues::ListService, services: true do
+describe Boards::Issues::ListService do
describe '#execute' do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:bug) { create(:label, project: project, name: 'Bug') }
@@ -13,13 +13,14 @@ describe Boards::Issues::ListService, services: true do
let(:p2) { create(:label, title: 'P2', project: project, priority: 2) }
let(:p3) { create(:label, title: 'P3', project: project, priority: 3) }
+ let!(:backlog) { create(:backlog_list, board: board) }
let!(:list1) { create(:list, board: board, label: development, position: 0) }
let!(:list2) { create(:list, board: board, label: testing, position: 1) }
let!(:closed) { create(:closed_list, board: board) }
let!(:opened_issue1) { create(:labeled_issue, project: project, labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, labels: [p2]) }
- let!(:reopened_issue1) { create(:issue, :reopened, project: project) }
+ let!(:reopened_issue1) { create(:issue, :opened, project: project) }
let!(:list1_issue1) { create(:labeled_issue, project: project, labels: [p2, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, labels: [development]) }
@@ -53,6 +54,14 @@ describe Boards::Issues::ListService, services: true do
expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
end
+ it 'returns opened issues when listing issues from Backlog' do
+ params = { board_id: board.id, id: backlog.id }
+
+ issues = described_class.new(project, user, params).execute
+
+ expect(issues).to eq [opened_issue2, reopened_issue1, opened_issue1]
+ end
+
it 'returns closed issues when listing issues from Closed' do
params = { board_id: board.id, id: closed.id }
diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb
index 4ff7ac6bb2f..63dfe80d672 100644
--- a/spec/services/boards/issues/move_service_spec.rb
+++ b/spec/services/boards/issues/move_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Boards::Issues::MoveService, services: true do
+describe Boards::Issues::MoveService do
describe '#execute' do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board1) { create(:board, project: project) }
let(:bug) { create(:label, project: project, name: 'Bug') }
@@ -73,7 +73,7 @@ describe Boards::Issues::MoveService, services: true do
issue.reload
expect(issue.labels).to contain_exactly(bug, testing)
- expect(issue).to be_reopened
+ expect(issue).to be_opened
end
end
diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb
index dff33e4bcbb..1d0be99fb35 100644
--- a/spec/services/boards/list_service_spec.rb
+++ b/spec/services/boards/list_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::ListService, services: true do
+describe Boards::ListService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
subject(:service) { described_class.new(project, double) }
diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb
index ebac38e68f1..7d0b396cd06 100644
--- a/spec/services/boards/lists/create_service_spec.rb
+++ b/spec/services/boards/lists/create_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::Lists::CreateService, services: true do
+describe Boards::Lists::CreateService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
let(:label) { create(:label, project: project, name: 'in-progress') }
diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb
index af2d7c784bb..bd98625b44f 100644
--- a/spec/services/boards/lists/destroy_service_spec.rb
+++ b/spec/services/boards/lists/destroy_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::Lists::DestroyService, services: true do
+describe Boards::Lists::DestroyService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb
index ed0337662af..592f25059ac 100644
--- a/spec/services/boards/lists/generate_service_spec.rb
+++ b/spec/services/boards/lists/generate_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::Lists::GenerateService, services: true do
+describe Boards::Lists::GenerateService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb
index ab9fb1bc914..b189857e4f4 100644
--- a/spec/services/boards/lists/list_service_spec.rb
+++ b/spec/services/boards/lists/list_service_spec.rb
@@ -1,16 +1,33 @@
require 'spec_helper'
-describe Boards::Lists::ListService, services: true do
+describe Boards::Lists::ListService do
+ let(:project) { create(:project) }
+ let(:board) { create(:board, project: project) }
+ let(:label) { create(:label, project: project) }
+ let!(:list) { create(:list, board: board, label: label) }
+ let(:service) { described_class.new(project, double) }
+
describe '#execute' do
- it "returns board's lists" do
- project = create(:empty_project)
- board = create(:board, project: project)
- label = create(:label, project: project)
- list = create(:list, board: board, label: label)
+ context 'when the board has a backlog list' do
+ let!(:backlog_list) { create(:backlog_list, board: board) }
+
+ it 'does not create a backlog list' do
+ expect { service.execute(board) }.not_to change(board.lists, :count)
+ end
+
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [backlog_list, list, board.closed_list]
+ end
+ end
- service = described_class.new(project, double)
+ context 'when the board does not have a backlog list' do
+ it 'creates a backlog list' do
+ expect { service.execute(board) }.to change(board.lists, :count).by(1)
+ end
- expect(service.execute(board)).to eq [list, board.closed_list]
+ it "returns board's lists" do
+ expect(service.execute(board)).to eq [board.backlog_list, list, board.closed_list]
+ end
end
end
end
diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb
index 4b3bdd133f2..a9d218bad49 100644
--- a/spec/services/boards/lists/move_service_spec.rb
+++ b/spec/services/boards/lists/move_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Boards::Lists::MoveService, services: true do
+describe Boards::Lists::MoveService do
describe '#execute' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:board) { create(:board, project: project) }
let(:user) { create(:user) }
diff --git a/spec/services/chat_names/authorize_user_service_spec.rb b/spec/services/chat_names/authorize_user_service_spec.rb
index d50bfb0492c..d88b2504133 100644
--- a/spec/services/chat_names/authorize_user_service_spec.rb
+++ b/spec/services/chat_names/authorize_user_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatNames::AuthorizeUserService, services: true do
+describe ChatNames::AuthorizeUserService do
describe '#execute' do
let(:service) { create(:service) }
diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb
index 0dc96521fa8..79aaac3aeb6 100644
--- a/spec/services/chat_names/find_user_service_spec.rb
+++ b/spec/services/chat_names/find_user_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ChatNames::FindUserService, services: true do
+describe ChatNames::FindUserService do
describe '#execute' do
let(:service) { create(:service) }
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 597c3947e71..730df4e0336 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -1,21 +1,28 @@
require 'spec_helper'
-describe Ci::CreatePipelineService, services: true do
+describe Ci::CreatePipelineService do
let(:project) { create(:project, :repository) }
let(:user) { create(:admin) }
+ let(:ref_name) { 'refs/heads/master' }
before do
stub_ci_pipeline_to_return_yaml_file
end
describe '#execute' do
- def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: 'refs/heads/master')
+ def execute_service(
+ source: :push,
+ after: project.commit.id,
+ message: 'Message',
+ ref: ref_name,
+ trigger_request: nil)
params = { ref: ref,
before: '00000000',
after: after,
commits: [{ message: message }] }
- described_class.new(project, user, params).execute(source)
+ described_class.new(project, user, params).execute(
+ source, trigger_request: trigger_request)
end
context 'valid params' do
@@ -30,6 +37,7 @@ describe Ci::CreatePipelineService, services: true do
it 'creates a pipeline' do
expect(pipeline).to be_kind_of(Ci::Pipeline)
expect(pipeline).to be_valid
+ expect(pipeline).to be_persisted
expect(pipeline).to be_push
expect(pipeline).to eq(project.pipelines.last)
expect(pipeline).to have_attributes(user: user)
@@ -37,6 +45,14 @@ describe Ci::CreatePipelineService, services: true do
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
end
+ it 'increments the prometheus counter' do
+ expect(Gitlab::Metrics).to receive(:counter)
+ .with(:pipelines_created_total, "Counter of pipelines created")
+ .and_call_original
+
+ pipeline
+ end
+
context 'when merge requests already exist for this source branch' do
it 'updates head pipeline of each merge request' do
merge_request_1 = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project)
@@ -59,7 +75,7 @@ describe Ci::CreatePipelineService, services: true do
end
context 'when merge request target project is different from source project' do
- let!(:target_project) { create(:project) }
+ let!(:target_project) { create(:project, :repository) }
let!(:forked_project_link) { create(:forked_project_link, forked_to_project: project, forked_from_project: target_project) }
it 'updates head pipeline for merge request' do
@@ -311,5 +327,223 @@ describe Ci::CreatePipelineService, services: true do
end.not_to change { Environment.count }
end
end
+
+ context 'when builds with auto-retries are configured' do
+ before do
+ config = YAML.dump(rspec: { script: 'rspec', retry: 2 })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'correctly creates builds with auto-retry value configured' do
+ pipeline = execute_service
+
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.find_by(name: 'rspec').retries_max).to eq 2
+ end
+ end
+
+ shared_examples 'when ref is protected' do
+ let(:user) { create(:user) }
+
+ context 'when user is developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service).not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when user is master' do
+ before do
+ project.add_master(user)
+ end
+
+ it 'creates a pipeline' do
+ expect(execute_service).to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+
+ context 'when trigger belongs to no one' do
+ let(:user) {}
+ let(:trigger_request) { create(:ci_trigger_request) }
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when trigger belongs to a developer' do
+ let(:user) {}
+
+ let(:trigger_request) do
+ create(:ci_trigger_request).tap do |request|
+ user = create(:user)
+ project.add_developer(user)
+ request.trigger.update(owner: user)
+ end
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .not_to be_persisted
+ expect(Ci::Pipeline.count).to eq(0)
+ end
+ end
+
+ context 'when trigger belongs to a master' do
+ let(:user) {}
+
+ let(:trigger_request) do
+ create(:ci_trigger_request).tap do |request|
+ user = create(:user)
+ project.add_master(user)
+ request.trigger.update(owner: user)
+ end
+ end
+
+ it 'does not create a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+ end
+
+ context 'when ref is a protected branch' do
+ before do
+ create(:protected_branch, project: project, name: 'master')
+ end
+
+ it_behaves_like 'when ref is protected'
+ end
+
+ context 'when ref is a protected tag' do
+ let(:ref_name) { 'refs/tags/v1.0.0' }
+
+ before do
+ create(:protected_tag, project: project, name: '*')
+ end
+
+ it_behaves_like 'when ref is protected'
+ end
+
+ context 'when ref is not protected' do
+ context 'when trigger belongs to no one' do
+ let(:user) {}
+ let(:trigger_request) { create(:ci_trigger_request) }
+
+ it 'creates a pipeline' do
+ expect(execute_service(trigger_request: trigger_request))
+ .to be_persisted
+ expect(Ci::Pipeline.count).to eq(1)
+ end
+ end
+ end
+ end
+
+ describe '#allowed_to_create?' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:ref) { 'master' }
+
+ subject do
+ described_class.new(project, user, ref: ref)
+ .send(:allowed_to_create?, user)
+ end
+
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when the branch is protected' do
+ let!(:protected_branch) do
+ create(:protected_branch, project: project, name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+
+ context 'when developers are allowed to merge' do
+ let!(:protected_branch) do
+ create(:protected_branch,
+ :developers_can_merge,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when the tag is protected' do
+ let(:ref) { 'v1.0.0' }
+
+ let!(:protected_tag) do
+ create(:protected_tag, project: project, name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+
+ context 'when developers are allowed to create the tag' do
+ let!(:protected_tag) do
+ create(:protected_tag,
+ :developers_can_create,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
+ context 'when user is a master' do
+ before do
+ project.add_master(user)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when the branch is protected' do
+ let!(:protected_branch) do
+ create(:protected_branch, project: project, name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the tag is protected' do
+ let(:ref) { 'v1.0.0' }
+
+ let!(:protected_tag) do
+ create(:protected_tag, project: project, name: ref)
+ end
+
+ it { is_expected.to be_truthy }
+
+ context 'when no one can create the tag' do
+ let!(:protected_tag) do
+ create(:protected_tag,
+ :no_one_can_create,
+ project: project,
+ name: ref)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ context 'when owner cannot create pipeline' do
+ it { is_expected.to be_falsey }
+ end
end
end
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index f2956262f4b..8295813a1ca 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -1,12 +1,15 @@
require 'spec_helper'
-describe Ci::CreateTriggerRequestService, services: true do
- let(:service) { described_class.new }
+describe Ci::CreateTriggerRequestService do
+ let(:service) { described_class }
let(:project) { create(:project, :repository) }
- let(:trigger) { create(:ci_trigger, project: project) }
+ let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
+ let(:owner) { create(:user) }
before do
stub_ci_pipeline_to_return_yaml_file
+
+ project.add_developer(owner)
end
describe '#execute' do
@@ -14,29 +17,26 @@ describe Ci::CreateTriggerRequestService, services: true do
subject { service.execute(project, trigger, 'master') }
context 'without owner' do
- it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) }
it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) }
it { expect(subject.pipeline).to be_trigger }
- it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
end
context 'with owner' do
- let(:owner) { create(:user) }
- let(:trigger) { create(:ci_trigger, project: project, owner: owner) }
-
- it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) }
+ it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) }
+ it { expect(subject.trigger_request.builds.first.user).to eq(owner) }
it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) }
it { expect(subject.pipeline).to be_trigger }
it { expect(subject.pipeline.user).to eq(owner) }
- it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
- it { expect(subject.builds.first.user).to eq(owner) }
end
end
context 'no commit for ref' do
subject { service.execute(project, trigger, 'other-branch') }
- it { expect(subject).to be_nil }
+ it { expect(subject.pipeline).not_to be_persisted }
end
context 'no builds created' do
@@ -46,7 +46,7 @@ describe Ci::CreateTriggerRequestService, services: true do
stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }')
end
- it { expect(subject).to be_nil }
+ it { expect(subject.pipeline).not_to be_persisted }
end
end
end
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
new file mode 100644
index 00000000000..9a6875e448c
--- /dev/null
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe Ci::PipelineTriggerService do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
+
+ describe '#execute' do
+ let(:user) { create(:user) }
+ let(:trigger) { create(:ci_trigger, project: project, owner: user) }
+ let(:result) { described_class.new(project, user, params).execute }
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when trigger belongs to a different project' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
+ let(:trigger) { create(:ci_trigger, project: create(:project), owner: user) }
+
+ it 'does nothing' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ end
+ end
+
+ context 'when params have an existsed trigger token' do
+ context 'when params have an existsed ref' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: nil } }
+
+ it 'triggers a pipeline' do
+ expect { result }.to change { Ci::Pipeline.count }.by(1)
+ expect(result[:pipeline].ref).to eq('master')
+ expect(result[:pipeline].project).to eq(project)
+ expect(result[:pipeline].user).to eq(trigger.owner)
+ expect(result[:status]).to eq(:success)
+ end
+
+ context 'when commit message has [ci skip]' do
+ before do
+ allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' }
+ end
+
+ it 'ignores [ci skip] and create as general' do
+ expect { result }.to change { Ci::Pipeline.count }.by(1)
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'when params have a variable' do
+ let(:params) { { token: trigger.token, ref: 'master', variables: variables } }
+ let(:variables) { { 'AAA' => 'AAA123' } }
+
+ it 'has a variable' do
+ expect { result }.to change { Ci::PipelineVariable.count }.by(1)
+ .and change { Ci::TriggerRequest.count }.by(1)
+ expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables)
+ expect(result[:pipeline].trigger_requests.last.variables).to be_nil
+ end
+ end
+ end
+
+ context 'when params have a non-existsed ref' do
+ let(:params) { { token: trigger.token, ref: 'invalid-ref', variables: nil } }
+
+ it 'does not trigger a pipeline' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ expect(result[:http_status]).to eq(400)
+ end
+ end
+ end
+
+ context 'when params have a non-existsed trigger token' do
+ let(:params) { { token: 'invalid-token', ref: nil, variables: nil } }
+
+ it 'does not trigger a pipeline' do
+ expect { result }.not_to change { Ci::Pipeline.count }
+ expect(result).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index ea211de1f82..330ec81e87d 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Ci::PlayBuildService, '#execute', :services do
+describe Ci::PlayBuildService, '#execute' do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
@@ -11,7 +11,7 @@ describe Ci::PlayBuildService, '#execute', :services do
end
context 'when project does not have repository yet' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
it 'allows user to play build if protected branch rules are met' do
project.add_developer(user)
@@ -33,7 +33,7 @@ describe Ci::PlayBuildService, '#execute', :services do
end
context 'when project has repository' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
it 'allows user with developer role to play a build' do
project.add_developer(user)
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index 1557cb3c938..214adc9960f 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -1,14 +1,16 @@
require 'spec_helper'
-describe Ci::ProcessPipelineService, '#execute', :services do
+describe Ci::ProcessPipelineService, '#execute' do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:pipeline) do
create(:ci_empty_pipeline, ref: 'master', project: project)
end
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
@@ -62,6 +64,10 @@ describe Ci::ProcessPipelineService, '#execute', :services do
fail_running_or_pending
expect(builds_statuses).to eq %w(failed pending)
+
+ fail_running_or_pending
+
+ expect(pipeline.reload).to be_success
end
end
@@ -459,6 +465,35 @@ describe Ci::ProcessPipelineService, '#execute', :services do
end
end
+ context 'when builds with auto-retries are configured' do
+ before do
+ create_build('build:1', stage_idx: 0, user: user, options: { retry: 2 })
+ create_build('test:1', stage_idx: 1, user: user, when: :on_failure)
+ create_build('test:2', stage_idx: 1, user: user, options: { retry: 1 })
+ end
+
+ it 'automatically retries builds in a valid order' do
+ expect(process_pipeline).to be_truthy
+
+ fail_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1]
+ expect(builds_statuses).to eq %w[failed pending]
+
+ succeed_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1 test:2]
+ expect(builds_statuses).to eq %w[failed success pending]
+
+ succeed_running_or_pending
+
+ expect(builds_names).to eq %w[build:1 build:1 test:2]
+ expect(builds_statuses).to eq %w[failed success success]
+
+ expect(pipeline.reload).to be_success
+ end
+ end
+
def process_pipeline
described_class.new(pipeline.project, user).execute(pipeline)
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 62ba0b01339..8eb0d2d10a4 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
module Ci
- describe RegisterJobService, services: true do
- let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
+ describe RegisterJobService do
+ let!(:project) { FactoryGirl.create :project, shared_runners_enabled: false }
let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline }
let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) }
@@ -72,9 +72,9 @@ module Ci
end
context 'for multiple builds' do
- let!(:project2) { create :empty_project, shared_runners_enabled: true }
+ let!(:project2) { create :project, shared_runners_enabled: true }
let!(:pipeline2) { create :ci_pipeline, project: project2 }
- let!(:project3) { create :empty_project, shared_runners_enabled: true }
+ let!(:project3) { create :project, shared_runners_enabled: true }
let!(:pipeline3) { create :ci_pipeline, project: project3 }
let!(:build1_project1) { pending_build }
let!(:build2_project1) { FactoryGirl.create :ci_build, pipeline: pipeline }
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 7254e6b357a..cec667071cc 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Ci::RetryBuildService, :services do
+describe Ci::RetryBuildService do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
@@ -25,12 +25,24 @@ describe Ci::RetryBuildService, :services do
user_id auto_canceled_by_id retried].freeze
shared_examples 'build duplication' do
+ let(:stage) do
+ # TODO, we still do not have factory for new stages, we will need to
+ # switch existing factory to persist stages, instead of using LegacyStage
+ #
+ Ci::Stage.create!(project: project, pipeline: pipeline, name: 'test')
+ end
+
let(:build) do
create(:ci_build, :failed, :artifacts_expired, :erased,
:queued, :coverage, :tags, :allowed_to_fail, :on_tag,
- :teardown_environment, :triggered, :trace,
- description: 'some build', pipeline: pipeline,
- auto_canceled_by: create(:ci_empty_pipeline))
+ :triggered, :trace, :teardown_environment,
+ description: 'my-job', stage: 'test', pipeline: pipeline,
+ auto_canceled_by: create(:ci_empty_pipeline)) do |build|
+ ##
+ # TODO, workaround for FactoryGirl limitation when having both
+ # stage (text) and stage_id (integer) columns in the table.
+ build.stage_id = stage.id
+ end
end
describe 'clone accessors' do
@@ -73,6 +85,8 @@ describe Ci::RetryBuildService, :services do
context 'when user has ability to execute build' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
@@ -119,6 +133,8 @@ describe Ci::RetryBuildService, :services do
context 'when user has ability to execute build' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 3e860203063..6ce75c65c8c 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Ci::RetryPipelineService, '#execute', :services do
+describe Ci::RetryPipelineService, '#execute' do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:service) { described_class.new(project, user) }
@@ -244,13 +244,9 @@ describe Ci::RetryPipelineService, '#execute', :services do
create_build('verify', :canceled, 1)
end
- it 'does not reprocess manual action' do
- service.execute(pipeline)
-
- expect(build('test')).to be_pending
- expect(build('deploy')).to be_failed
- expect(build('verify')).to be_created
- expect(pipeline.reload).to be_running
+ it 'raises an error' do
+ expect { service.execute(pipeline) }
+ .to raise_error Gitlab::Access::AccessDeniedError
end
end
@@ -261,13 +257,9 @@ describe Ci::RetryPipelineService, '#execute', :services do
create_build('verify', :canceled, 2)
end
- it 'does not reprocess manual action' do
- service.execute(pipeline)
-
- expect(build('test')).to be_pending
- expect(build('deploy')).to be_failed
- expect(build('verify')).to be_created
- expect(pipeline.reload).to be_running
+ it 'raises an error' do
+ expect { service.execute(pipeline) }
+ .to raise_error Gitlab::Access::AccessDeniedError
end
end
end
diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb
index 98044ad232e..e2a9ed27e87 100644
--- a/spec/services/ci/stop_environments_service_spec.rb
+++ b/spec/services/ci/stop_environments_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::StopEnvironmentsService, services: true do
+describe Ci::StopEnvironmentsService do
let(:project) { create(:project, :private, :repository) }
let(:user) { create(:user) }
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index c44e6b2a48b..0da0e57dbcd 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::UpdateBuildQueueService, :services do
+describe Ci::UpdateBuildQueueService do
let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:pipeline) { create(:ci_pipeline, project: project) }
@@ -9,7 +9,9 @@ describe Ci::UpdateBuildQueueService, :services do
let(:runner) { create(:ci_runner) }
context 'when there are runner that can pick build' do
- before { build.project.runners << runner }
+ before do
+ build.project.runners << runner
+ end
it 'ticks runner queue value' do
expect { subject.execute(build) }
@@ -36,7 +38,9 @@ describe Ci::UpdateBuildQueueService, :services do
end
context 'when there are no runners that can pick build' do
- before { build.tag_list = [:docker] }
+ before do
+ build.tag_list = [:docker]
+ end
it 'does not tick runner queue value' do
expect { subject.execute(build) }
diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb
index e429fcfc72f..7cc04c92d27 100644
--- a/spec/services/ci/update_runner_service_spec.rb
+++ b/spec/services/ci/update_runner_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Ci::UpdateRunnerService, :services do
+describe Ci::UpdateRunnerService do
let(:runner) { create(:ci_runner) }
describe '#update' do
diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb
index bea7c965233..9e15eae8c13 100644
--- a/spec/services/compare_service_spec.rb
+++ b/spec/services/compare_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CompareService, services: true do
+describe CompareService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { described_class.new(project, 'feature') }
diff --git a/spec/services/create_branch_service_spec.rb b/spec/services/create_branch_service_spec.rb
index 3f548688c20..38096a080a7 100644
--- a/spec/services/create_branch_service_spec.rb
+++ b/spec/services/create_branch_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateBranchService, services: true do
+describe CreateBranchService do
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index 5398b5c3f7e..049b082277a 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateDeploymentService, services: true do
+describe CreateDeploymentService do
let(:user) { create(:user) }
let(:options) { nil }
@@ -122,6 +122,61 @@ describe CreateDeploymentService, services: true do
end
end
+ describe '#expanded_environment_url' do
+ subject { service.send(:expanded_environment_url) }
+
+ context 'when yaml environment uses $CI_COMMIT_REF_NAME' do
+ let(:job) do
+ create(:ci_build,
+ ref: 'master',
+ options: { environment: { url: 'http://review/$CI_COMMIT_REF_NAME' } })
+ end
+
+ it { is_expected.to eq('http://review/master') }
+ end
+
+ context 'when yaml environment uses $CI_ENVIRONMENT_SLUG' do
+ let(:job) do
+ create(:ci_build,
+ ref: 'master',
+ environment: 'production',
+ options: { environment: { url: 'http://review/$CI_ENVIRONMENT_SLUG' } })
+ end
+
+ let!(:environment) do
+ create(:environment,
+ project: job.project,
+ name: 'production',
+ slug: 'prod-slug',
+ external_url: 'http://review/old')
+ end
+
+ it { is_expected.to eq('http://review/prod-slug') }
+ end
+
+ context 'when yaml environment uses yaml_variables containing symbol keys' do
+ let(:job) do
+ create(:ci_build,
+ yaml_variables: [{ key: :APP_HOST, value: 'host' }],
+ options: { environment: { url: 'http://review/$APP_HOST' } })
+ end
+
+ it { is_expected.to eq('http://review/host') }
+ end
+
+ context 'when yaml environment does not have url' do
+ let(:job) { create(:ci_build, environment: 'staging') }
+
+ let!(:environment) do
+ create(:environment, project: job.project, name: job.environment)
+ end
+
+ it 'returns the external_url from persisted environment' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
describe 'processing of builds' do
shared_examples 'does not create deployment' do
it 'does not create a new deployment' do
@@ -189,6 +244,8 @@ describe CreateDeploymentService, services: true do
context 'when job is retried' do
it_behaves_like 'creates deployment' do
before do
+ stub_not_protect_default_branch
+
project.add_developer(user)
end
@@ -204,7 +261,9 @@ describe CreateDeploymentService, services: true do
let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
context "while updating the 'first_deployed_to_production_at' time" do
- before { merge_request.mark_as_merged }
+ before do
+ merge_request.mark_as_merged
+ end
context "for merge requests merged before the current deploy" do
it "sets the time if the deploy's environment is 'production'" do
diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb
index 271ccfe7968..ac0a0458f56 100644
--- a/spec/services/create_release_service_spec.rb
+++ b/spec/services/create_release_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe CreateReleaseService, services: true do
+describe CreateReleaseService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:tag_name) { project.repository.tag_names.first }
let(:description) { 'Awesome release!' }
- let(:service) { CreateReleaseService.new(project, user) }
+ let(:service) { described_class.new(project, user) }
it 'creates a new release' do
result = service.execute(tag_name, description)
diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb
index d81d0fd76c9..b6ab6b8271c 100644
--- a/spec/services/create_snippet_service_spec.rb
+++ b/spec/services/create_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe CreateSnippetService, services: true do
+describe CreateSnippetService do
before do
@user = create :user
@admin = create :user, admin: true
diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/delete_branch_service_spec.rb
index c4685c9aa31..19855c9bee2 100644
--- a/spec/services/delete_branch_service_spec.rb
+++ b/spec/services/delete_branch_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeleteBranchService, services: true do
+describe DeleteBranchService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb
index cae74df9c90..03c682ae0d7 100644
--- a/spec/services/delete_merged_branches_service_spec.rb
+++ b/spec/services/delete_merged_branches_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DeleteMergedBranchesService, services: true do
+describe DeleteMergedBranchesService do
subject(:service) { described_class.new(project, project.owner) }
let(:project) { create(:project, :repository) }
@@ -24,6 +24,22 @@ describe DeleteMergedBranchesService, services: true do
expect(project.repository.branch_names).to include('master')
end
+ it 'keeps protected branches' do
+ create(:protected_branch, project: project, name: 'improve/awesome')
+
+ service.execute
+
+ expect(project.repository.branch_names).to include('improve/awesome')
+ end
+
+ it 'keeps wildcard protected branches' do
+ create(:protected_branch, project: project, name: 'improve/*')
+
+ service.execute
+
+ expect(project.repository.branch_names).to include('improve/awesome')
+ end
+
context 'user without rights' do
let(:user) { create(:user) }
@@ -35,7 +51,7 @@ describe DeleteMergedBranchesService, services: true do
context 'open merge requests' do
it 'does not delete branches from open merge requests' do
fork_link = create(:forked_project_link, forked_from_project: project)
- create(:merge_request, :reopened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master')
+ create(:merge_request, :opened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master')
create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master')
service.execute
diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb
index 177e32e13bd..c239494298b 100644
--- a/spec/services/discussions/update_diff_position_service_spec.rb
+++ b/spec/services/discussions/update_diff_position_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Discussions::UpdateDiffPositionService, services: true do
+describe Discussions::UpdateDiffPositionService do
let(:project) { create(:project, :repository) }
let(:current_user) { project.owner }
let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") }
diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb
new file mode 100644
index 00000000000..641d5538de8
--- /dev/null
+++ b/spec/services/emails/create_service_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Emails::CreateService do
+ let(:user) { create(:user) }
+ let(:opts) { { email: 'new@email.com' } }
+
+ subject(:service) { described_class.new(user, opts) }
+
+ describe '#execute' do
+ it 'creates an email with valid attributes' do
+ expect { service.execute }.to change { Email.count }.by(1)
+ expect(Email.where(opts)).not_to be_empty
+ end
+
+ it 'has the right user association' do
+ service.execute
+
+ expect(user.emails).to eq(Email.where(opts))
+ end
+ end
+end
diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb
new file mode 100644
index 00000000000..1f4294dd905
--- /dev/null
+++ b/spec/services/emails/destroy_service_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe Emails::DestroyService do
+ let!(:user) { create(:user) }
+ let!(:email) { create(:email, user: user) }
+
+ subject(:service) { described_class.new(user, email: email.email) }
+
+ describe '#execute' do
+ it 'removes an email' do
+ expect { service.execute }.to change { user.emails.count }.by(-1)
+ end
+ end
+end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index b06cefe071d..42adb044190 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe EventCreateService, services: true do
+describe EventCreateService do
include UserActivitiesHelpers
- let(:service) { EventCreateService.new }
+ let(:service) { described_class.new }
describe 'Issues' do
describe '#open_issue' do
@@ -113,8 +113,8 @@ describe EventCreateService, services: true do
end
end
- describe '#push', :redis do
- let(:project) { create(:empty_project) }
+ describe '#push', :clean_gitlab_redis_shared_state do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
it 'creates a new event' do
@@ -128,7 +128,7 @@ describe EventCreateService, services: true do
describe 'Project' do
let(:user) { create :user }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
describe '#join_project' do
subject { service.join_project(project, user) }
diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb
index 16bca66766a..cc950ae6bb3 100644
--- a/spec/services/files/update_service_spec.rb
+++ b/spec/services/files/update_service_spec.rb
@@ -32,8 +32,8 @@ describe Files::UpdateService do
let(:last_commit_sha) { "foo" }
it "returns a hash with the correct error message and a :error status " do
- expect { subject.execute }.
- to raise_error(Files::UpdateService::FileChangedError,
+ expect { subject.execute }
+ .to raise_error(Files::UpdateService::FileChangedError,
"You are attempting to update a file that has changed since you started editing it.")
end
end
diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb
index ac7ccfbaab0..3ce01a995b4 100644
--- a/spec/services/git_hooks_service_spec.rb
+++ b/spec/services/git_hooks_service_spec.rb
@@ -1,18 +1,17 @@
require 'spec_helper'
-describe GitHooksService, services: true do
+describe GitHooksService do
include RepoHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
- let(:service) { GitHooksService.new }
+ let(:service) { described_class.new }
before do
@blankrev = Gitlab::Git::BLANK_SHA
@oldrev = sample_commit.parent_id
@newrev = sample_commit.id
@ref = 'refs/heads/feature'
- @repo_path = project.repository.path_to_repo
end
describe '#execute' do
@@ -21,7 +20,7 @@ describe GitHooksService, services: true do
hook = double(trigger: [true, nil])
expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
- service.execute(user, @repo_path, @blankrev, @newrev, @ref) { }
+ service.execute(user, project, @blankrev, @newrev, @ref) { }
end
end
@@ -31,7 +30,7 @@ describe GitHooksService, services: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
- service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ service.execute(user, project, @blankrev, @newrev, @ref)
end.to raise_error(GitHooksService::PreReceiveError)
end
end
@@ -43,7 +42,7 @@ describe GitHooksService, services: true do
expect(service).not_to receive(:run_hook).with('post-receive')
expect do
- service.execute(user, @repo_path, @blankrev, @newrev, @ref)
+ service.execute(user, project, @blankrev, @newrev, @ref)
end.to raise_error(GitHooksService::PreReceiveError)
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index bcd1fb64ab9..82724ccd281 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -3,27 +3,24 @@ require 'spec_helper'
describe GitPushService, services: true do
include RepoHelpers
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:blankrev) { Gitlab::Git::BLANK_SHA }
+ let(:oldrev) { sample_commit.parent_id }
+ let(:newrev) { sample_commit.id }
+ let(:ref) { 'refs/heads/master' }
before do
project.team << [user, :master]
- @blankrev = Gitlab::Git::BLANK_SHA
- @oldrev = sample_commit.parent_id
- @newrev = sample_commit.id
- @ref = 'refs/heads/master'
end
describe 'Push branches' do
- let(:oldrev) { @oldrev }
- let(:newrev) { @newrev }
-
subject do
- execute_service(project, user, oldrev, newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
context 'new branch' do
- let(:oldrev) { @blankrev }
+ let(:oldrev) { blankrev }
it { is_expected.to be_truthy }
@@ -51,7 +48,7 @@ describe GitPushService, services: true do
end
context 'rm branch' do
- let(:newrev) { @blankrev }
+ let(:newrev) { blankrev }
it { is_expected.to be_truthy }
@@ -70,24 +67,20 @@ describe GitPushService, services: true do
end
describe "Git Push Data" do
- before do
- service = execute_service(project, user, @oldrev, @newrev, @ref )
- @push_data = service.push_data
- @commit = project.commit(@newrev)
- end
+ let(:commit) { project.commit(newrev) }
- subject { @push_data }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref) }
it { is_expected.to include(object_kind: 'push') }
- it { is_expected.to include(before: @oldrev) }
- it { is_expected.to include(after: @newrev) }
- it { is_expected.to include(ref: @ref) }
+ it { is_expected.to include(before: oldrev) }
+ it { is_expected.to include(after: newrev) }
+ it { is_expected.to include(ref: ref) }
it { is_expected.to include(user_id: user.id) }
it { is_expected.to include(user_name: user.name) }
it { is_expected.to include(project_id: project.id) }
context "with repository data" do
- subject { @push_data[:repository] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:repository] }
it { is_expected.to include(name: project.name) }
it { is_expected.to include(url: project.url_to_repo) }
@@ -96,7 +89,7 @@ describe GitPushService, services: true do
end
context "with commits" do
- subject { @push_data[:commits] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits] }
it { is_expected.to be_an(Array) }
it 'has 1 element' do
@@ -104,11 +97,11 @@ describe GitPushService, services: true do
end
context "the commit" do
- subject { @push_data[:commits].first }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first }
- it { is_expected.to include(id: @commit.id) }
- it { is_expected.to include(message: @commit.safe_message) }
- it { is_expected.to include(timestamp: @commit.date.xmlschema) }
+ it { is_expected.to include(id: commit.id) }
+ it { is_expected.to include(message: commit.safe_message) }
+ it { expect(subject[:timestamp].in_time_zone).to eq(commit.date.in_time_zone) }
it do
is_expected.to include(
url: [
@@ -116,23 +109,23 @@ describe GitPushService, services: true do
project.namespace.to_param,
project.to_param,
'commit',
- @commit.id
+ commit.id
].join('/')
)
end
context "with a author" do
- subject { @push_data[:commits].first[:author] }
+ subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first[:author] }
- it { is_expected.to include(name: @commit.author_name) }
- it { is_expected.to include(email: @commit.author_email) }
+ it { is_expected.to include(name: commit.author_name) }
+ it { is_expected.to include(email: commit.author_email) }
end
end
end
end
describe "Pipelines" do
- subject { execute_service(project, user, @oldrev, @newrev, @ref) }
+ subject { execute_service(project, user, oldrev, newrev, ref) }
before do
stub_ci_pipeline_to_return_yaml_file
@@ -145,29 +138,26 @@ describe GitPushService, services: true do
end
describe "Push Event" do
- before do
- service = execute_service(project, user, @oldrev, @newrev, @ref )
- @event = Event.find_by_action(Event::PUSHED)
- @push_data = service.push_data
- end
+ let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
+ let(:event) { Event.find_by_action(Event::PUSHED) }
- it { expect(@event).not_to be_nil }
- it { expect(@event.project).to eq(project) }
- it { expect(@event.action).to eq(Event::PUSHED) }
- it { expect(@event.data).to eq(@push_data) }
+ it { expect(event).not_to be_nil }
+ it { expect(event.project).to eq(project) }
+ it { expect(event.action).to eq(Event::PUSHED) }
+ it { expect(event.data).to eq(push_data) }
context "Updates merge requests" do
it "when pushing a new branch for the first time" do
- expect(UpdateMergeRequestsWorker).to receive(:perform_async).
- with(project.id, user.id, @blankrev, 'newrev', 'refs/heads/master')
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ expect(UpdateMergeRequestsWorker).to receive(:perform_async)
+ .with(project.id, user.id, blankrev, 'newrev', ref)
+ execute_service(project, user, blankrev, 'newrev', ref )
end
end
-
+
context "Sends System Push data" do
it "when pushing on a branch" do
- expect(SystemHookPushWorker).to receive(:perform_async).with(@push_data, :push_hooks)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ expect(SystemHookPushWorker).to receive(:perform_async).with(push_data, :push_hooks)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
end
@@ -177,13 +167,13 @@ describe GitPushService, services: true do
it "calls the copy attributes method for the first push to the default branch" do
expect(project.repository).to receive(:copy_gitattributes).with('master')
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master')
+ execute_service(project, user, blankrev, 'newrev', ref)
end
it "calls the copy attributes method for changes to the default branch" do
- expect(project.repository).to receive(:copy_gitattributes).with('refs/heads/master')
+ expect(project.repository).to receive(:copy_gitattributes).with(ref)
- execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master')
+ execute_service(project, user, 'oldrev', 'newrev', ref)
end
end
@@ -196,7 +186,7 @@ describe GitPushService, services: true do
it "does not call copy attributes method" do
expect(project.repository).not_to receive(:copy_gitattributes)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
end
@@ -206,7 +196,7 @@ describe GitPushService, services: true do
it "when pushing a branch for the first time" do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
@@ -217,7 +207,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).to be_empty
end
@@ -227,7 +217,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
@@ -242,7 +232,7 @@ describe GitPushService, services: true do
expect(project.default_branch).to eq("master")
expect_any_instance_of(ProtectedBranches::CreateService).not_to receive(:execute)
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::NO_ACCESS])
@@ -254,7 +244,7 @@ describe GitPushService, services: true do
expect(project).to receive(:execute_hooks)
expect(project.default_branch).to eq("master")
- execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' )
+ execute_service(project, user, blankrev, 'newrev', ref)
expect(project.protected_branches).not_to be_empty
expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER])
expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER])
@@ -262,7 +252,7 @@ describe GitPushService, services: true do
it "when pushing new commits to existing branch" do
expect(project).to receive(:execute_hooks)
- execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master' )
+ execute_service(project, user, 'oldrev', 'newrev', ref)
end
end
end
@@ -283,8 +273,8 @@ describe GitPushService, services: true do
author_email: commit_author.email
)
- allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit).
- and_return(commit)
+ allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit)
+ .and_return(commit)
allow(project.repository).to receive(:commits_between).and_return([commit])
end
@@ -292,7 +282,7 @@ describe GitPushService, services: true do
it "creates a note if a pushed commit mentions an issue" do
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "only creates a cross-reference note if one doesn't already exist" do
@@ -300,7 +290,7 @@ describe GitPushService, services: true do
expect(SystemNoteService).not_to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "defaults to the pushing user if the commit's author is not known" do
@@ -310,16 +300,16 @@ describe GitPushService, services: true do
)
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, user)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "finds references in the first push to a non-default branch" do
- allow(project.repository).to receive(:commits_between).with(@blankrev, @newrev).and_return([])
- allow(project.repository).to receive(:commits_between).with("master", @newrev).and_return([commit])
+ allow(project.repository).to receive(:commits_between).with(blankrev, newrev).and_return([])
+ allow(project.repository).to receive(:commits_between).with("master", newrev).and_return([commit])
expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author)
- execute_service(project, user, @blankrev, @newrev, 'refs/heads/other' )
+ execute_service(project, user, blankrev, newrev, 'refs/heads/other')
end
end
@@ -341,22 +331,22 @@ describe GitPushService, services: true do
committed_date: commit_time
)
- allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit).
- and_return(commit)
+ allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit)
+ .and_return(commit)
allow(project.repository).to receive(:commits_between).and_return([commit])
end
context "while saving the 'first_mentioned_in_commit_at' metric for an issue" do
it 'sets the metric for referenced issues' do
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(issue.reload.metrics.first_mentioned_in_commit_at).to be_like_time(commit_time)
end
it 'does not set the metric for non-referenced issues' do
non_referenced_issue = create(:issue, project: project)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(non_referenced_issue.reload.metrics.first_mentioned_in_commit_at).to be_nil
end
@@ -377,41 +367,29 @@ describe GitPushService, services: true do
author_email: commit_author.email
)
- allow(project.repository).to receive(:commits_between).
- and_return([closing_commit])
+ allow(project.repository).to receive(:commits_between)
+ .and_return([closing_commit])
- allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit).
- and_return(closing_commit)
+ allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit)
+ .and_return(closing_commit)
project.team << [commit_author, :master]
end
context "to default branches" do
it "closes issues" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(Issue.find(issue.id)).to be_closed
end
it "adds a note indicating that the issue is now closed" do
expect(SystemNoteService).to receive(:change_status).with(issue, project, commit_author, "closed", closing_commit)
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
end
it "doesn't create additional cross-reference notes" do
expect(SystemNoteService).not_to receive(:cross_reference)
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
- end
-
- it "doesn't close issues when external issue tracker is in use" do
- allow_any_instance_of(Project).to receive(:default_issues_tracker?).
- and_return(false)
- external_issue_tracker = double(title: 'My Tracker', issue_path: issue.iid, reference_pattern: project.issue_reference_pattern)
- allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(external_issue_tracker)
-
- # The push still shouldn't create cross-reference notes.
- expect do
- execute_service(project, commit_author, @oldrev, @newrev, 'refs/heads/hurf' )
- end.not_to change { Note.where(project_id: project.id, system: true).count }
+ execute_service(project, commit_author, oldrev, newrev, ref)
end
end
@@ -423,11 +401,11 @@ describe GitPushService, services: true do
it "creates cross-reference notes" do
expect(SystemNoteService).to receive(:cross_reference).with(issue, closing_commit, commit_author)
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
end
it "doesn't close issues" do
- execute_service(project, user, @oldrev, @newrev, @ref )
+ execute_service(project, user, oldrev, newrev, ref)
expect(Issue.find(issue.id)).to be_opened
end
end
@@ -444,11 +422,12 @@ describe GitPushService, services: true do
stub_jira_urls("JIRA-1")
allow(closing_commit).to receive_messages({
- issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
- safe_message: message,
- author_name: commit_author.name,
- author_email: commit_author.email
- })
+ issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
+ safe_message: message,
+ author_name: commit_author.name,
+ author_email: commit_author.email
+ })
+
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
allow(project.repository).to receive_messages(commits_between: [closing_commit])
@@ -462,7 +441,7 @@ describe GitPushService, services: true do
let(:message) { "this is some work.\n\nrelated to JIRA-1" }
it "initiates one api call to jira server to mention the issue" do
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
body: /mentioned this issue in/
@@ -472,7 +451,11 @@ describe GitPushService, services: true do
context "closing an issue" do
let(:message) { "this is some work.\n\ncloses JIRA-1" }
- let(:comment_body) { { body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." }.to_json }
+ let(:comment_body) do
+ {
+ body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.full_path}/commit/#{closing_commit.id}]."
+ }.to_json
+ end
before do
open_issue = JIRA::Resource::Issue.new(jira_tracker.client, attrs: { "id" => "JIRA-1" })
@@ -486,13 +469,13 @@ describe GitPushService, services: true do
context "using right markdown" do
it "initiates one api call to jira server to close the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once
end
it "initiates one api call to jira server to comment on the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ execute_service(project, commit_author, oldrev, newrev, ref)
expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
body: comment_body
@@ -500,21 +483,57 @@ describe GitPushService, services: true do
end
end
- context "using wrong markdown" do
- let(:message) { "this is some work.\n\ncloses #1" }
+ context "using internal issue reference" do
+ context 'when internal issues are disabled' do
+ before do
+ project.issues_enabled = false
+ project.save!
+ end
+ let(:message) { "this is some work.\n\ncloses #1" }
+
+ it "does not initiates one api call to jira server to close the issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
- it "does not initiates one api call to jira server to close the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1'))
+ end
- expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1'))
+ it "does not initiates one api call to jira server to comment on the issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
+ body: comment_body
+ ).once
+ end
end
- it "does not initiates one api call to jira server to comment on the issue" do
- execute_service(project, commit_author, @oldrev, @newrev, @ref )
+ context 'when internal issues are enabled' do
+ let(:issue) { create(:issue, project: project) }
+ let(:message) { "this is some work.\n\ncloses JIRA-1 \n\n closes #{issue.to_reference}" }
- expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
- body: comment_body
- ).once
+ it "initiates one api call to jira server to close the jira issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once
+ end
+
+ it "initiates one api call to jira server to comment on the jira issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+
+ expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with(
+ body: comment_body
+ ).once
+ end
+
+ it "closes the internal issue" do
+ execute_service(project, commit_author, oldrev, newrev, ref)
+ expect(issue.reload).to be_closed
+ end
+
+ it "adds a note indicating that the issue is now closed" do
+ expect(SystemNoteService).to receive(:change_status)
+ .with(issue, project, commit_author, "closed", closing_commit)
+ execute_service(project, commit_author, oldrev, newrev, ref)
+ end
end
end
end
@@ -523,7 +542,7 @@ describe GitPushService, services: true do
describe "empty project" do
let(:project) { create(:project_empty_repo) }
- let(:new_ref) { 'refs/heads/feature'}
+ let(:new_ref) { 'refs/heads/feature' }
before do
allow(project).to receive(:default_branch).and_return('feature')
@@ -531,7 +550,7 @@ describe GitPushService, services: true do
end
it 'push to first branch updates HEAD' do
- execute_service(project, user, @blankrev, @newrev, new_ref )
+ execute_service(project, user, blankrev, newrev, new_ref)
end
end
@@ -539,20 +558,24 @@ describe GitPushService, services: true do
let(:housekeeping) { Projects::HousekeepingService.new(project) }
before do
- # Flush any raw Redis data stored by the housekeeping code.
- Gitlab::Redis.with { |conn| conn.flushall }
+ # Flush any raw key-value data stored by the housekeeping code.
+ Gitlab::Redis::Cache.with { |conn| conn.flushall }
+ Gitlab::Redis::Queues.with { |conn| conn.flushall }
+ Gitlab::Redis::SharedState.with { |conn| conn.flushall }
allow(Projects::HousekeepingService).to receive(:new).and_return(housekeeping)
end
after do
- Gitlab::Redis.with { |conn| conn.flushall }
+ Gitlab::Redis::Cache.with { |conn| conn.flushall }
+ Gitlab::Redis::Queues.with { |conn| conn.flushall }
+ Gitlab::Redis::SharedState.with { |conn| conn.flushall }
end
it 'does not perform housekeeping when not needed' do
expect(housekeeping).not_to receive(:execute)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
context 'when housekeeping is needed' do
@@ -563,20 +586,20 @@ describe GitPushService, services: true do
it 'performs housekeeping' do
expect(housekeeping).to receive(:execute)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
it 'does not raise an exception' do
allow(housekeeping).to receive(:try_obtain_lease).and_return(false)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
it 'increments the push counter' do
expect(housekeeping).to receive(:increment!)
- execute_service(project, user, @oldrev, @newrev, @ref)
+ execute_service(project, user, oldrev, newrev, ref)
end
end
@@ -584,9 +607,9 @@ describe GitPushService, services: true do
let(:service) do
described_class.new(project,
user,
- oldrev: sample_commit.parent_id,
- newrev: sample_commit.id,
- ref: 'refs/heads/master')
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref)
end
context 'on the default branch' do
@@ -598,13 +621,13 @@ describe GitPushService, services: true do
commit = double(:commit)
diff = double(:diff, new_path: 'README.md')
- expect(commit).to receive(:raw_deltas).
- and_return([diff])
+ expect(commit).to receive(:raw_deltas)
+ .and_return([diff])
service.push_commits = [commit]
- expect(ProjectCacheWorker).to receive(:perform_async).
- with(project.id, %i(readme), %i(commit_count repository_size))
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(project.id, %i(readme), %i(commit_count repository_size))
service.update_caches
end
@@ -616,9 +639,9 @@ describe GitPushService, services: true do
end
it 'does not flush any conditional caches' do
- expect(ProjectCacheWorker).to receive(:perform_async).
- with(project.id, [], %i(commit_count repository_size)).
- and_call_original
+ expect(ProjectCacheWorker).to receive(:perform_async)
+ .with(project.id, [], %i(commit_count repository_size))
+ .and_call_original
service.update_caches
end
@@ -629,14 +652,13 @@ describe GitPushService, services: true do
let(:service) do
described_class.new(project,
user,
- oldrev: sample_commit.parent_id,
- newrev: sample_commit.id,
- ref: 'refs/heads/master')
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref)
end
it 'only schedules a limited number of commits' do
- allow(service).to receive(:push_commits).
- and_return(Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true)))
+ service.push_commits = Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true))
expect(ProcessCommitWorker).to receive(:perform_async).exactly(100).times
@@ -644,8 +666,7 @@ describe GitPushService, services: true do
end
it "skips commits which don't include cross-references" do
- allow(service).to receive(:push_commits).
- and_return([double(:commit, to_hash: {}, matches_cross_reference_regex?: false)])
+ service.push_commits = [double(:commit, to_hash: {}, matches_cross_reference_regex?: false)]
expect(ProcessCommitWorker).not_to receive(:perform_async)
@@ -653,9 +674,31 @@ describe GitPushService, services: true do
end
end
+ describe '#update_signatures' do
+ let(:service) do
+ described_class.new(
+ project,
+ user,
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: 'refs/heads/master'
+ )
+ end
+
+ it 'calls CreateGpgSignatureWorker.perform_async for each commit' do
+ expect(CreateGpgSignatureWorker).to receive(:perform_async).with(sample_commit.id, project.id)
+
+ execute_service(project, user, oldrev, newrev, ref)
+ end
+ end
+
def execute_service(project, user, oldrev, newrev, ref)
- service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref )
+ service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
service.execute
service
end
+
+ def push_data_from_service(project, user, oldrev, newrev, ref)
+ execute_service(project, user, oldrev, newrev, ref).push_data
+ end
end
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index 1fdcb420a8b..f877c145390 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe GitTagPushService, services: true do
+describe GitTagPushService do
include RepoHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
- let(:service) { GitTagPushService.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) }
+ let(:service) { described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) }
let(:oldrev) { Gitlab::Git::BLANK_SHA }
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
@@ -184,7 +184,7 @@ describe GitTagPushService, services: true do
describe "Webhooks" do
context "execute webhooks" do
- let(:service) { GitTagPushService.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') }
+ let(:service) { described_class.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') }
it "when pushing tags" do
expect(project).to receive(:execute_hooks)
diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb
index 8c4ad8c7a3e..d2cc53fe0ee 100644
--- a/spec/services/gravatar_service_spec.rb
+++ b/spec/services/gravatar_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe GravatarService, service: true do
+describe GravatarService do
describe '#execute' do
let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' }
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index bcb62429275..b2175717a70 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Groups::CreateService, '#execute', services: true do
+describe Groups::CreateService, '#execute' do
let!(:user) { create(:user) }
let!(:group_params) { { path: "group_path", visibility_level: Gitlab::VisibilityLevel::PUBLIC } }
@@ -14,7 +14,9 @@ describe Groups::CreateService, '#execute', services: true do
end
context "cannot create group with restricted visibility level" do
- before { allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
+ before do
+ allow_any_instance_of(ApplicationSetting).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC])
+ end
it { is_expected.not_to be_persisted }
end
@@ -25,7 +27,9 @@ describe Groups::CreateService, '#execute', services: true do
let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
context 'as group owner' do
- before { group.add_owner(user) }
+ before do
+ group.add_owner(user)
+ end
it { is_expected.to be_persisted }
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index a37257d1bf4..1b2ce3cd03e 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Groups::DestroyService, services: true do
+describe Groups::DestroyService do
include DatabaseConnectionHelpers
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, parent: group) }
- let!(:project) { create(:empty_project, namespace: group) }
+ let!(:project) { create(:project, namespace: group) }
let!(:notification_setting) { create(:notification_setting, source: group)}
let!(:gitlab_shell) { Gitlab::Shell.new }
let!(:remove_path) { group.path + "+#{group.id}+deleted" }
@@ -15,6 +15,14 @@ describe Groups::DestroyService, services: true do
group.add_user(user, Gitlab::Access::OWNER)
end
+ def destroy_group(group, user, async)
+ if async
+ Groups::DestroyService.new(group, user).async_execute
+ else
+ Groups::DestroyService.new(group, user).execute
+ end
+ end
+
shared_examples 'group destruction' do |async|
context 'database records' do
before do
@@ -27,33 +35,27 @@ describe Groups::DestroyService, services: true do
it { expect(NotificationSetting.unscoped.all).not_to include(notification_setting) }
end
+ context 'mattermost team' do
+ let!(:chat_team) { create(:chat_team, namespace: group) }
+
+ it 'destroys the team too' do
+ expect_any_instance_of(Mattermost::Team).to receive(:destroy)
+
+ destroy_group(group, user, async)
+ end
+ end
+
context 'file system' do
context 'Sidekiq inline' do
before do
- # Run sidekiq immediatly to check that renamed dir will be removed
+ # Run sidekiq immediately to check that renamed dir will be removed
Sidekiq::Testing.inline! { destroy_group(group, user, async) }
end
- it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
- it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey }
- end
-
- context 'Sidekiq fake' do
- before do
- # Don't run sidekiq to check if renamed repository exists
- Sidekiq::Testing.fake! { destroy_group(group, user, async) }
+ it 'verifies that paths have been deleted' do
+ expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey
+ expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey
end
-
- it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey }
- it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy }
- end
- end
-
- def destroy_group(group, user, async)
- if async
- Groups::DestroyService.new(group, user).async_execute
- else
- Groups::DestroyService.new(group, user).execute
end
end
end
@@ -61,6 +63,26 @@ describe Groups::DestroyService, services: true do
describe 'asynchronous delete' do
it_behaves_like 'group destruction', true
+ context 'Sidekiq fake' do
+ before do
+ # Don't run Sidekiq to verify that group and projects are not actually destroyed
+ Sidekiq::Testing.fake! { destroy_group(group, user, true) }
+ end
+
+ after do
+ # Clean up stale directories
+ gitlab_shell.rm_namespace(project.repository_storage_path, group.path)
+ gitlab_shell.rm_namespace(project.repository_storage_path, remove_path)
+ end
+
+ it 'verifies original paths and projects still exist' do
+ expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_truthy
+ expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey
+ expect(Project.unscoped.count).to eq(1)
+ expect(Group.unscoped.count).to eq(2)
+ end
+ end
+
context 'potential race conditions' do
context "when the `GroupDestroyWorker` task runs immediately" do
it "deletes the group" do
@@ -88,7 +110,7 @@ describe Groups::DestroyService, services: true do
# Kick off the initial group destroy in a new thread, so that
# it doesn't share this spec's database transaction.
- Thread.new { Groups::DestroyService.new(group, user).async_execute }.join(5)
+ Thread.new { described_class.new(group, user).async_execute }.join(5)
group_record = run_with_new_database_connection do |conn|
conn.execute("SELECT * FROM namespaces WHERE id = #{group.id}").first
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index f6ad5cebd2c..44f22a3b37b 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Groups::UpdateService, services: true do
+describe Groups::UpdateService do
let!(:user) { create(:user) }
let!(:private_group) { create(:group, :private) }
let!(:internal_group) { create(:group, :internal) }
@@ -13,7 +13,7 @@ describe Groups::UpdateService, services: true do
before do
public_group.add_user(user, Gitlab::Access::MASTER)
- create(:empty_project, :public, group: public_group)
+ create(:project, :public, group: public_group)
end
it "does not change permission level" do
@@ -27,7 +27,7 @@ describe Groups::UpdateService, services: true do
before do
internal_group.add_user(user, Gitlab::Access::MASTER)
- create(:empty_project, :internal, group: internal_group)
+ create(:project, :internal, group: internal_group)
end
it "does not change permission level" do
@@ -69,7 +69,7 @@ describe Groups::UpdateService, services: true do
before do
internal_group.add_user(user, Gitlab::Access::MASTER)
- create(:empty_project, :internal, group: internal_group)
+ create(:project, :internal, group: internal_group)
end
it 'returns true' do
diff --git a/spec/services/import_export_clean_up_service_spec.rb b/spec/services/import_export_clean_up_service_spec.rb
index 81b1d327696..1875d0448cd 100644
--- a/spec/services/import_export_clean_up_service_spec.rb
+++ b/spec/services/import_export_clean_up_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ImportExportCleanUpService, services: true do
+describe ImportExportCleanUpService do
describe '#execute' do
let(:service) { described_class.new }
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index 6437d00e451..befa65ec0f8 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Issuable::BulkUpdateService, services: true do
+describe Issuable::BulkUpdateService do
let(:user) { create(:user) }
- let(:project) { create(:empty_project, namespace: user.namespace) }
+ let(:project) { create(:project, namespace: user.namespace) }
def bulk_update(issuables, extra_params = {})
bulk_update_params = extra_params
@@ -72,7 +72,7 @@ describe Issuable::BulkUpdateService, services: true do
end
context "when the new assignee ID is #{IssuableFinder::NONE}" do
- it "unassigns the issues" do
+ it 'unassigns the issues' do
expect { bulk_update(merge_request, assignee_id: IssuableFinder::NONE) }
.to change { merge_request.reload.assignee }.to(nil)
end
diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb
index bed25fe7ccf..03f76bd428d 100644
--- a/spec/services/issues/build_service_spec.rb
+++ b/spec/services/issues/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper.rb'
-describe Issues::BuildService, services: true do
+describe Issues::BuildService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index be0e829880e..a03f68434de 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issues::CloseService, services: true do
+describe Issues::CloseService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -18,26 +18,26 @@ describe Issues::CloseService, services: true do
let(:service) { described_class.new(project, user) }
it 'checks if the user is authorized to update the issue' do
- expect(service).to receive(:can?).with(user, :update_issue, issue).
- and_call_original
+ expect(service).to receive(:can?).with(user, :update_issue, issue)
+ .and_call_original
service.execute(issue)
end
it 'does not close the issue when the user is not authorized to do so' do
- allow(service).to receive(:can?).with(user, :update_issue, issue).
- and_return(false)
+ allow(service).to receive(:can?).with(user, :update_issue, issue)
+ .and_return(false)
expect(service).not_to receive(:close_issue)
expect(service.execute(issue)).to eq(issue)
end
it 'closes the issue when the user is authorized to do so' do
- allow(service).to receive(:can?).with(user, :update_issue, issue).
- and_return(true)
+ allow(service).to receive(:can?).with(user, :update_issue, issue)
+ .and_return(true)
- expect(service).to receive(:close_issue).
- with(issue, commit: nil, notifications: true, system_note: true)
+ expect(service).to receive(:close_issue)
+ .with(issue, commit: nil, notifications: true, system_note: true)
service.execute(issue)
end
@@ -98,13 +98,13 @@ describe Issues::CloseService, services: true do
end
end
- context 'external issue tracker' do
+ context 'internal issues disabled' do
before do
- allow(project).to receive(:default_issues_tracker?).and_return(false)
- described_class.new(project, user).close_issue(issue)
+ project.issues_enabled = false
+ project.save!
end
- it 'closes the issue' do
+ it 'does not close the issue' do
expect(issue).to be_valid
expect(issue).to be_opened
expect(todo.reload).to be_pending
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index dab1a3469f7..fcbd69fd58b 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Issues::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe Issues::CreateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
describe '#execute' do
@@ -155,7 +155,9 @@ describe Issues::CreateService, services: true do
context 'issue create service' do
context 'assignees' do
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_ids: [-1] }
@@ -204,9 +206,9 @@ describe Issues::CreateService, services: true do
end
end
- it_behaves_like 'new issuable record that supports slash commands'
+ it_behaves_like 'new issuable record that supports quick actions'
- context 'Slash commands' do
+ context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:opts) do
{
diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb
new file mode 100644
index 00000000000..089e77cc88b
--- /dev/null
+++ b/spec/services/issues/duplicate_service_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe Issues::DuplicateService do
+ let(:user) { create(:user) }
+ let(:canonical_project) { create(:project) }
+ let(:duplicate_project) { create(:project) }
+
+ let(:canonical_issue) { create(:issue, project: canonical_project) }
+ let(:duplicate_issue) { create(:issue, project: duplicate_project) }
+
+ subject { described_class.new(duplicate_project, user, {}) }
+
+ describe '#execute' do
+ context 'when the issues passed are the same' do
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, duplicate_issue)
+ end
+ end
+
+ context 'when the user cannot update the duplicate issue' do
+ before do
+ canonical_project.add_reporter(user)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+
+ context 'when the user cannot comment on the canonical issue' do
+ before do
+ duplicate_project.add_reporter(user)
+ end
+
+ it 'does nothing' do
+ expect(subject).not_to receive(:close_service)
+ expect(SystemNoteService).not_to receive(:mark_duplicate_issue)
+ expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+
+ context 'when the user can mark the issue as a duplicate' do
+ before do
+ canonical_project.add_reporter(user)
+ duplicate_project.add_reporter(user)
+ end
+
+ it 'closes the duplicate issue' do
+ subject.execute(duplicate_issue, canonical_issue)
+
+ expect(duplicate_issue.reload).to be_closed
+ expect(canonical_issue.reload).to be_open
+ end
+
+ it 'adds a system note to the duplicate issue' do
+ expect(SystemNoteService)
+ .to receive(:mark_duplicate_issue).with(duplicate_issue, duplicate_project, user, canonical_issue)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+
+ it 'adds a system note to the canonical issue' do
+ expect(SystemNoteService)
+ .to receive(:mark_canonical_issue_of_duplicate).with(canonical_issue, canonical_project, user, duplicate_issue)
+
+ subject.execute(duplicate_issue, canonical_issue)
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 9f8346d52bb..f2b35a8fadf 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe Issues::MoveService, services: true do
+describe Issues::MoveService do
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:title) { 'Some issue' }
let(:description) { 'Some issue description' }
- let(:old_project) { create(:empty_project) }
- let(:new_project) { create(:empty_project) }
+ let(:old_project) { create(:project) }
+ let(:new_project) { create(:project) }
let(:milestone1) { create(:milestone, project_id: old_project.id, title: 'v9.0') }
let(:old_issue) do
@@ -37,9 +37,6 @@ describe Issues::MoveService, services: true do
describe '#execute' do
shared_context 'issue move executed' do
- let!(:milestone2) do
- create(:milestone, project_id: new_project.id, title: 'v9.0')
- end
let!(:award_emoji) { create(:award_emoji, awardable: old_issue) }
let!(:new_issue) { move_service.execute(old_issue, new_project) }
@@ -48,6 +45,63 @@ describe Issues::MoveService, services: true do
context 'issue movable' do
include_context 'user can move issue'
+ context 'move to new milestone' do
+ let(:new_issue) { move_service.execute(old_issue, new_project) }
+
+ context 'project milestone' do
+ let!(:milestone2) do
+ create(:milestone, project_id: new_project.id, title: 'v9.0')
+ end
+
+ it 'assigns milestone to new issue' do
+ expect(new_issue.reload.milestone.title).to eq 'v9.0'
+ expect(new_issue.reload.milestone).to eq(milestone2)
+ end
+ end
+
+ context 'group milestones' do
+ let!(:group) { create(:group, :private) }
+ let!(:group_milestone_1) do
+ create(:milestone, group_id: group.id, title: 'v9.0_group')
+ end
+
+ before do
+ old_issue.update(milestone: group_milestone_1)
+ old_project.update(namespace: group)
+ new_project.update(namespace: group)
+
+ group.add_users([user], GroupMember::DEVELOPER)
+ end
+
+ context 'when moving to a project of the same group' do
+ it 'keeps the same group milestone' do
+ expect(new_issue.reload.project).to eq(new_project)
+ expect(new_issue.reload.milestone).to eq(group_milestone_1)
+ end
+ end
+
+ context 'when moving to a project of a different group' do
+ let!(:group_2) { create(:group, :private) }
+
+ let!(:group_milestone_2) do
+ create(:milestone, group_id: group_2.id, title: 'v9.0_group')
+ end
+
+ before do
+ old_issue.update(milestone: group_milestone_1)
+ new_project.update(namespace: group_2)
+
+ group_2.add_users([user], GroupMember::DEVELOPER)
+ end
+
+ it 'assigns to new group milestone of same title' do
+ expect(new_issue.reload.project).to eq(new_project)
+ expect(new_issue.reload.milestone).to eq(group_milestone_2)
+ end
+ end
+ end
+ end
+
context 'generic issue' do
include_context 'issue move executed'
@@ -55,11 +109,6 @@ describe Issues::MoveService, services: true do
expect(new_issue.project).to eq new_project
end
- it 'assigns milestone to new issue' do
- expect(new_issue.reload.milestone.title).to eq 'v9.0'
- expect(new_issue.reload.milestone).to eq(milestone2)
- end
-
it 'assign labels to new issue' do
expected_label_titles = new_issue.reload.labels.map(&:title)
expect(expected_label_titles).to include 'label1'
@@ -251,12 +300,18 @@ describe Issues::MoveService, services: true do
end
context 'user is reporter only in new project' do
- before { new_project.team << [user, :reporter] }
+ before do
+ new_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
context 'user is reporter only in old project' do
- before { old_project.team << [user, :reporter] }
+ before do
+ old_project.team << [user, :reporter]
+ end
+
it { expect { move }.to raise_error(StandardError, /permissions/) }
end
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 391ecad303a..205e9ebd237 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Issues::ReopenService, services: true do
- let(:project) { create(:empty_project) }
+describe Issues::ReopenService do
+ let(:project) { create(:project) }
let(:issue) { create(:issue, :closed, project: project) }
describe '#execute' do
diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb
index 86f218dec12..fac66791ffb 100644
--- a/spec/services/issues/resolve_discussions_spec.rb
+++ b/spec/services/issues/resolve_discussions_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper.rb'
-describe Issues::ResolveDiscussions, services: true do
+describe Issues::ResolveDiscussions do
class DummyService < Issues::BaseService
include ::Issues::ResolveDiscussions
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 5184c1d5f19..ff0d876e6da 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -1,13 +1,13 @@
# coding: utf-8
require 'spec_helper'
-describe Issues::UpdateService, services: true do
+describe Issues::UpdateService do
include EmailHelpers
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:label) { create(:label, project: project) }
let(:label2) { create(:label) }
@@ -31,6 +31,13 @@ describe Issues::UpdateService, services: true do
end
end
+ def find_notes(action)
+ issue
+ .notes
+ .joins(:system_note_metadata)
+ .where(system_note_metadata: { action: action })
+ end
+
def update_issue(opts)
described_class.new(project, user, opts).execute(issue)
end
@@ -246,13 +253,13 @@ describe Issues::UpdateService, services: true do
end
context 'when the milestone change' do
- before do
+ it 'marks todos as done' do
update_issue(milestone: create(:milestone))
- end
- it 'marks todos as done' do
expect(todo.reload.done?).to eq true
end
+
+ it_behaves_like 'system notes for milestones'
end
context 'when the labels change' do
@@ -288,7 +295,9 @@ describe Issues::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { issue.labels << label }
+ before do
+ issue.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
@@ -322,7 +331,9 @@ describe Issues::UpdateService, services: true do
it { expect(issue.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_issue(description: "- [x] Task 1\n- [X] Task 2") }
+ before do
+ update_issue(description: "- [x] Task 1\n- [X] Task 2")
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
@@ -330,6 +341,9 @@ describe Issues::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -345,6 +359,9 @@ describe Issues::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -354,10 +371,12 @@ describe Issues::UpdateService, services: true do
update_issue(description: "- [x] Task 1\n- [ ] Task 3\n- [ ] Task 2")
end
- it 'does not create a system note' do
- note = find_note('marked the task **Task 2** as incomplete')
+ it 'does not create a system note for the task' do
+ task_note = find_note('marked the task **Task 2** as incomplete')
+ description_notes = find_notes('description')
- expect(note).to be_nil
+ expect(task_note).to be_nil
+ expect(description_notes.length).to eq(2)
end
end
@@ -368,9 +387,11 @@ describe Issues::UpdateService, services: true do
end
it 'does not create a system note referencing the position the old item' do
- note = find_note('marked the task **Two** as incomplete')
+ task_note = find_note('marked the task **Two** as incomplete')
+ description_notes = find_notes('description')
- expect(note).to be_nil
+ expect(task_note).to be_nil
+ expect(description_notes.length).to eq(2)
end
it 'does not generate a new note at all' do
@@ -400,7 +421,9 @@ describe Issues::UpdateService, services: true do
context 'when remove_label_ids and label_ids are passed' do
let(:params) { { label_ids: [], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label, label3]) }
+ before do
+ issue.update_attributes(labels: [label, label3])
+ end
it 'ignores the label_ids parameter' do
expect(result.label_ids).not_to be_empty
@@ -414,7 +437,9 @@ describe Issues::UpdateService, services: true do
context 'when add_label_ids and remove_label_ids are passed' do
let(:params) { { add_label_ids: [label3.id], remove_label_ids: [label.id] } }
- before { issue.update_attributes(labels: [label]) }
+ before do
+ issue.update_attributes(labels: [label])
+ end
it 'adds the passed labels' do
expect(result.label_ids).to include(label3.id)
@@ -463,7 +488,28 @@ describe Issues::UpdateService, services: true do
context 'updating mentions' do
let(:mentionable) { issue }
- include_examples 'updating mentions', Issues::UpdateService
+ include_examples 'updating mentions', described_class
+ end
+
+ context 'duplicate issue' do
+ let(:canonical_issue) { create(:issue, project: project) }
+
+ context 'invalid canonical_issue_id' do
+ it 'does not call the duplicate service' do
+ expect(Issues::DuplicateService).not_to receive(:new)
+
+ update_issue(canonical_issue_id: 123456789)
+ end
+ end
+
+ context 'valid canonical_issue_id' do
+ it 'calls the duplicate service with both issues' do
+ expect_any_instance_of(Issues::DuplicateService)
+ .to receive(:execute).with(issue, canonical_issue)
+
+ update_issue(canonical_issue_id: canonical_issue.id)
+ end
+ end
end
include_examples 'issuable update service' do
diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb
index 0ecab0c3475..438e6dbc628 100644
--- a/spec/services/labels/create_service_spec.rb
+++ b/spec/services/labels/create_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe Labels::CreateService, services: true do
+describe Labels::CreateService do
describe '#execute' do
let(:project) { create(:project) }
let(:group) { create(:group) }
-
+
let(:hex_color) { '#FF0000' }
let(:named_color) { 'red' }
let(:upcase_color) { 'RED' }
@@ -17,7 +17,7 @@ describe Labels::CreateService, services: true do
context 'in a project' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(project: project)
+ label = described_class.new(params_with(hex_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -26,7 +26,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(project: project)
+ label = described_class.new(params_with(named_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -35,7 +35,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(project: project)
+ label = described_class.new(params_with(upcase_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -44,7 +44,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(project: project)
+ label = described_class.new(params_with(spaced_color)).execute(project: project)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -53,7 +53,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(project: project)
+ label = described_class.new(params_with(unknown_color)).execute(project: project)
expect(label).not_to be_persisted
end
@@ -61,7 +61,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(project: project)
+ label = described_class.new(params_with(no_color)).execute(project: project)
expect(label).not_to be_persisted
end
@@ -71,7 +71,7 @@ describe Labels::CreateService, services: true do
context 'in a group' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(group: group)
+ label = described_class.new(params_with(hex_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -80,7 +80,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(group: group)
+ label = described_class.new(params_with(named_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -89,7 +89,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(group: group)
+ label = described_class.new(params_with(upcase_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -98,7 +98,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(group: group)
+ label = described_class.new(params_with(spaced_color)).execute(group: group)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -107,7 +107,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(group: group)
+ label = described_class.new(params_with(unknown_color)).execute(group: group)
expect(label).not_to be_persisted
end
@@ -115,7 +115,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(group: group)
+ label = described_class.new(params_with(no_color)).execute(group: group)
expect(label).not_to be_persisted
end
@@ -125,7 +125,7 @@ describe Labels::CreateService, services: true do
context 'in admin area' do
context 'with color in hex-code' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(hex_color)).execute(template: true)
+ label = described_class.new(params_with(hex_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -134,7 +134,7 @@ describe Labels::CreateService, services: true do
context 'with color in allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(named_color)).execute(template: true)
+ label = described_class.new(params_with(named_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -143,7 +143,7 @@ describe Labels::CreateService, services: true do
context 'with color in up-case allowed name' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(upcase_color)).execute(template: true)
+ label = described_class.new(params_with(upcase_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -152,7 +152,7 @@ describe Labels::CreateService, services: true do
context 'with color surrounded by spaces' do
it 'creates a label' do
- label = Labels::CreateService.new(params_with(spaced_color)).execute(template: true)
+ label = described_class.new(params_with(spaced_color)).execute(template: true)
expect(label).to be_persisted
expect(label.color).to eq expected_saved_color
@@ -161,7 +161,7 @@ describe Labels::CreateService, services: true do
context 'with unknown color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(unknown_color)).execute(template: true)
+ label = described_class.new(params_with(unknown_color)).execute(template: true)
expect(label).not_to be_persisted
end
@@ -169,7 +169,7 @@ describe Labels::CreateService, services: true do
context 'with no color' do
it 'doesn\'t create a label' do
- label = Labels::CreateService.new(params_with(no_color)).execute(template: true)
+ label = described_class.new(params_with(no_color)).execute(template: true)
expect(label).not_to be_persisted
end
diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb
index de8f1827cce..a781fbc7f7d 100644
--- a/spec/services/labels/find_or_create_service_spec.rb
+++ b/spec/services/labels/find_or_create_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Labels::FindOrCreateService, services: true do
+describe Labels::FindOrCreateService do
describe '#execute' do
let(:group) { create(:group) }
- let(:project) { create(:empty_project, namespace: group) }
+ let(:project) { create(:project, namespace: group) }
let(:params) do
{
diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb
index 4b90ad19640..8809b282127 100644
--- a/spec/services/labels/promote_service_spec.rb
+++ b/spec/services/labels/promote_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe Labels::PromoteService, services: true do
+describe Labels::PromoteService do
describe '#execute' do
let!(:user) { create(:user) }
context 'project without group' do
- let!(:project_1) { create(:empty_project) }
+ let!(:project_1) { create(:project) }
let!(:project_label_1_1) { create(:label, project: project_1) }
@@ -27,10 +27,10 @@ describe Labels::PromoteService, services: true do
let!(:group_1) { create(:group) }
let!(:group_2) { create(:group) }
- let!(:project_1) { create(:empty_project, namespace: group_1) }
- let!(:project_2) { create(:empty_project, namespace: group_1) }
- let!(:project_3) { create(:empty_project, namespace: group_1) }
- let!(:project_4) { create(:empty_project, namespace: group_2) }
+ let!(:project_1) { create(:project, namespace: group_1) }
+ let!(:project_2) { create(:project, namespace: group_1) }
+ let!(:project_3) { create(:project, namespace: group_1) }
+ let!(:project_4) { create(:project, namespace: group_2) }
# Labels/issues can't be lazily created so we might as well eager initialize
# all other objects too since we use them inside
@@ -66,9 +66,9 @@ describe Labels::PromoteService, services: true do
end
it 'recreates the label as a group label' do
- expect { service.execute(project_label_1_1) }.
- to change(project_1.labels, :count).by(-1).
- and change(group_1.labels, :count).by(1)
+ expect { service.execute(project_label_1_1) }
+ .to change(project_1.labels, :count).by(-1)
+ .and change(group_1.labels, :count).by(1)
expect(new_label).not_to be_nil
end
diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb
index 11d5f1cad5e..ae819c011de 100644
--- a/spec/services/labels/transfer_service_spec.rb
+++ b/spec/services/labels/transfer_service_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Labels::TransferService, services: true do
+describe Labels::TransferService do
describe '#execute' do
let(:user) { create(:admin) }
let(:group_1) { create(:group) }
let(:group_2) { create(:group) }
let(:group_3) { create(:group) }
- let(:project_1) { create(:empty_project, namespace: group_2) }
- let(:project_2) { create(:empty_project, namespace: group_3) }
+ let(:project_1) { create(:project, namespace: group_2) }
+ let(:project_2) { create(:project, namespace: group_3) }
let(:group_label_1) { create(:group_label, group: group_1, name: 'Group Label 1') }
let(:group_label_2) { create(:group_label, group: group_1, name: 'Group Label 2') }
diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb
index f2498ea6990..bb95fe20fbf 100644
--- a/spec/services/labels/update_service_spec.rb
+++ b/spec/services/labels/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Labels::UpdateService, services: true do
+describe Labels::UpdateService do
describe '#execute' do
let(:project) { create(:project) }
@@ -20,7 +20,7 @@ describe Labels::UpdateService, services: true do
context 'with color in hex-code' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(hex_color)).execute(@label)
+ label = described_class.new(params_with(hex_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -29,7 +29,7 @@ describe Labels::UpdateService, services: true do
context 'with color in allowed name' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(named_color)).execute(@label)
+ label = described_class.new(params_with(named_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -38,7 +38,7 @@ describe Labels::UpdateService, services: true do
context 'with color in up-case allowed name' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(upcase_color)).execute(@label)
+ label = described_class.new(params_with(upcase_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -47,7 +47,7 @@ describe Labels::UpdateService, services: true do
context 'with color surrounded by spaces' do
it 'updates the label' do
- label = Labels::UpdateService.new(params_with(spaced_color)).execute(@label)
+ label = described_class.new(params_with(spaced_color)).execute(@label)
expect(label).to be_valid
expect(label.reload.color).to eq expected_saved_color
@@ -56,7 +56,7 @@ describe Labels::UpdateService, services: true do
context 'with unknown color' do
it 'doesn\'t update the label' do
- label = Labels::UpdateService.new(params_with(unknown_color)).execute(@label)
+ label = described_class.new(params_with(unknown_color)).execute(@label)
expect(label).not_to be_valid
end
@@ -64,7 +64,7 @@ describe Labels::UpdateService, services: true do
context 'with no color' do
it 'doesn\'t update the label' do
- label = Labels::UpdateService.new(params_with(no_color)).execute(@label)
+ label = described_class.new(params_with(no_color)).execute(@label)
expect(label).not_to be_valid
end
diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb
index 7d5a66801db..302c488d6c6 100644
--- a/spec/services/members/approve_access_request_service_spec.rb
+++ b/spec/services/members/approve_access_request_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Members::ApproveAccessRequestService, services: true do
+describe Members::ApproveAccessRequestService do
let(:user) { create(:user) }
let(:access_requester) { create(:user) }
- let(:project) { create(:empty_project, :public, :access_requestable) }
+ let(:project) { create(:project, :public, :access_requestable) }
let(:group) { create(:group, :public, :access_requestable) }
let(:opts) { {} }
diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb
index f99b11f208c..2d04d824180 100644
--- a/spec/services/members/authorized_destroy_service_spec.rb
+++ b/spec/services/members/authorized_destroy_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe Members::AuthorizedDestroyService, services: true do
+describe Members::AuthorizedDestroyService do
let(:member_user) { create(:user) }
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:group) { create(:group, :public) }
- let(:group_project) { create(:empty_project, :public, group: group) }
+ let(:group_project) { create(:project, :public, group: group) }
def number_of_assigned_issuables(user)
Issue.assigned_to(user).count + MergeRequest.assigned_to(user).count
diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb
index 5ce8e17976b..2a793e0eb4d 100644
--- a/spec/services/members/create_service_spec.rb
+++ b/spec/services/members/create_service_spec.rb
@@ -1,11 +1,13 @@
require 'spec_helper'
-describe Members::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe Members::CreateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:project_user) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'adds user to members' do
params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST }
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 41450c67d7e..72f5e27180d 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Members::DestroyService, services: true do
+describe Members::DestroyService do
let(:user) { create(:user) }
let(:member_user) { create(:user) }
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:group) { create(:group, :public) }
shared_examples 'a service raising ActiveRecord::RecordNotFound' do
@@ -104,8 +104,8 @@ describe Members::DestroyService, services: true do
let(:params) { { id: project.members.find_by!(user_id: user.id).id } }
it 'destroys the member' do
- expect { described_class.new(project, user, params).execute }.
- to change { project.members.count }.by(-1)
+ expect { described_class.new(project, user, params).execute }
+ .to change { project.members.count }.by(-1)
end
end
end
diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb
index 814c17b9ad0..0a704bba521 100644
--- a/spec/services/members/request_access_service_spec.rb
+++ b/spec/services/members/request_access_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Members::RequestAccessService, services: true do
+describe Members::RequestAccessService do
let(:user) { create(:user) }
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
@@ -29,7 +29,7 @@ describe Members::RequestAccessService, services: true do
end
context 'when current user cannot request access to the project' do
- %i[empty_project group].each do |source_type|
+ %i[project group].each do |source_type|
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { create(source_type, :private) }
end
@@ -37,7 +37,7 @@ describe Members::RequestAccessService, services: true do
end
context 'when access requests are disabled' do
- %i[empty_project group].each do |source_type|
+ %i[project group].each do |source_type|
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
let(:source) { create(source_type, :public) }
end
@@ -45,7 +45,7 @@ describe Members::RequestAccessService, services: true do
end
context 'when current user can request access to the project' do
- %i[empty_project group].each do |source_type|
+ %i[project group].each do |source_type|
it_behaves_like 'a service creating a access request' do
let(:source) { create(source_type, :public, :access_requestable) }
end
diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb
index d3556020d4d..fcbe0e5985f 100644
--- a/spec/services/merge_requests/assign_issues_service_spec.rb
+++ b/spec/services/merge_requests/assign_issues_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::AssignIssuesService, services: true do
+describe MergeRequests::AssignIssuesService do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 6f9d1208b1d..b46c419de14 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::BuildService, services: true do
+describe MergeRequests::BuildService do
include RepoHelpers
let(:project) { create(:project, :repository) }
@@ -19,7 +19,7 @@ describe MergeRequests::BuildService, services: true do
let(:commits) { nil }
let(:service) do
- MergeRequests::BuildService.new(project, user,
+ described_class.new(project, user,
description: description,
source_branch: source_branch,
target_branch: target_branch,
@@ -206,7 +206,9 @@ describe MergeRequests::BuildService, services: true do
context 'branch starts with external issue IID followed by a hyphen' do
let(:source_branch) { '12345-fix-issue' }
- before { allow(project).to receive(:default_issues_tracker?).and_return(false) }
+ before 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')
@@ -262,8 +264,8 @@ describe MergeRequests::BuildService, services: true do
end
context 'upstream project has disabled merge requests' do
- let(:upstream_project) { create(:empty_project, :merge_requests_disabled) }
- let(:project) { create(:empty_project, forked_from_project: upstream_project) }
+ let(:upstream_project) { create(:project, :merge_requests_disabled) }
+ let(:project) { create(:project, forked_from_project: upstream_project) }
let(:commits) { Commit.decorate([commit_1], project) }
it 'sets target project correctly' do
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index 154f30aac3b..04bf267d167 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CloseService, services: true do
+describe MergeRequests::CloseService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -32,8 +32,8 @@ describe MergeRequests::CloseService, services: true do
it { expect(@merge_request).to be_closed }
it 'executes hooks with close action' do
- expect(service).to have_received(:execute_hooks).
- with(@merge_request, 'close')
+ expect(service).to have_received(:execute_hooks)
+ .with(@merge_request, 'close')
end
it 'sends email to user2 about assign of new merge_request' do
diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
index c77e6e9cd50..6f49a65d795 100644
--- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
@@ -64,9 +64,9 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'creates a commit with the correct parents' do
- expect(merge_request.source_branch_head.parents.map(&:id)).
- to eq(%w(1450cd639e0bc6721eb02800169e464f212cde06
- 824be604a34828eb682305f0d963056cfac87b2d))
+ expect(merge_request.source_branch_head.parents.map(&:id))
+ .to eq(%w(1450cd639e0bc6721eb02800169e464f212cde06
+ 824be604a34828eb682305f0d963056cfac87b2d))
end
end
@@ -129,9 +129,8 @@ describe MergeRequests::Conflicts::ResolveService do
it 'creates a commit with the correct parents' do
resolve_conflicts
- expect(merge_request_from_fork.source_branch_head.parents.map(&:id)).
- to eq(['404fa3fc7c2c9b5dacff102f353bdf55b1be2813',
- target_head])
+ expect(merge_request_from_fork.source_branch_head.parents.map(&:id))
+ .to eq(['404fa3fc7c2c9b5dacff102f353bdf55b1be2813', target_head])
end
end
end
@@ -169,9 +168,9 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'creates a commit with the correct parents' do
- expect(merge_request.source_branch_head.parents.map(&:id)).
- to eq(%w(1450cd639e0bc6721eb02800169e464f212cde06
- 824be604a34828eb682305f0d963056cfac87b2d))
+ expect(merge_request.source_branch_head.parents.map(&:id))
+ .to eq(%w(1450cd639e0bc6721eb02800169e464f212cde06
+ 824be604a34828eb682305f0d963056cfac87b2d))
end
it 'sets the content to the content given' do
@@ -204,8 +203,8 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'raises a MissingResolution error' do
- expect { service.execute(user, invalid_params) }.
- to raise_error(Gitlab::Conflict::File::MissingResolution)
+ expect { service.execute(user, invalid_params) }
+ .to raise_error(Gitlab::Conflict::File::MissingResolution)
end
end
@@ -230,8 +229,8 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'raises a MissingResolution error' do
- expect { service.execute(user, invalid_params) }.
- to raise_error(Gitlab::Conflict::File::MissingResolution)
+ expect { service.execute(user, invalid_params) }
+ .to raise_error(Gitlab::Conflict::File::MissingResolution)
end
end
@@ -250,8 +249,8 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'raises a MissingFiles error' do
- expect { service.execute(user, invalid_params) }.
- to raise_error(described_class::MissingFiles)
+ expect { service.execute(user, invalid_params) }
+ .to raise_error(described_class::MissingFiles)
end
end
end
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index 1588d30c394..492b55cdece 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CreateFromIssueService, services: true do
+describe MergeRequests::CreateFromIssueService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 2963f62cc7d..8fef480274d 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::CreateService, services: true do
+describe MergeRequests::CreateService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:assignee) { create(:user) }
@@ -83,9 +83,9 @@ describe MergeRequests::CreateService, services: true do
let!(:pipeline_3) { create(:ci_pipeline, project: project, ref: "other_branch", project_id: project.id) }
before do
- project.merge_requests.
- where(source_branch: opts[:source_branch], target_branch: opts[:target_branch]).
- destroy_all
+ project.merge_requests
+ .where(source_branch: opts[:source_branch], target_branch: opts[:target_branch])
+ .destroy_all
end
it 'sets head pipeline' do
@@ -108,7 +108,7 @@ describe MergeRequests::CreateService, services: true do
end
end
- it_behaves_like 'new issuable record that supports slash commands' do
+ it_behaves_like 'new issuable record that supports quick actions' do
let(:default_params) do
{
source_branch: 'feature',
@@ -117,7 +117,7 @@ describe MergeRequests::CreateService, services: true do
end
end
- context 'Slash commands' do
+ context 'Quick actions' do
context 'with assignee and milestone in params and command' do
let(:merge_request) { described_class.new(project, user, opts).execute }
let(:milestone) { create(:milestone, project: project) }
@@ -150,7 +150,9 @@ describe MergeRequests::CreateService, services: true do
context 'asssignee_id' do
let(:assignee) { create(:user) }
- before { project.team << [user, :master] }
+ before do
+ project.team << [user, :master]
+ end
it 'removes assignee_id when user id is invalid' do
opts = { title: 'Title', description: 'Description', assignee_id: -1 }
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 4a7d8ab4c6c..672d86e4028 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -78,7 +78,7 @@ describe MergeRequests::GetUrlsService do
end
context 'pushing to existing branch and merge request is reopened' do
- let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) }
+ let!(:merge_request) { create(:merge_request, :opened, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'show_merge_request_url'
end
diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
index 935f4710851..bb46e1dd9ab 100644
--- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
+++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
@@ -10,8 +10,8 @@ describe MergeRequests::MergeRequestDiffCacheService do
expect(Rails.cache).to receive(:read).with(cache_key).and_return({})
expect(Rails.cache).to receive(:write).with(cache_key, anything)
- allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(double("text?" => true))
- allow_any_instance_of(Repository).to receive(:diffable?).and_return(true)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:text?).and_return(true)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:diffable?).and_return(true)
subject.execute(merge_request)
end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index d96f819e66a..e593bfeeaf7 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe MergeRequests::MergeService, services: true do
+describe MergeRequests::MergeService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
- let(:merge_request) { create(:merge_request, assignee: user2) }
+ let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) }
let(:project) { merge_request.project }
before do
@@ -13,7 +13,7 @@ describe MergeRequests::MergeService, services: true do
describe '#execute' do
context 'valid params' do
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
before do
allow(service).to receive(:execute_hooks)
@@ -81,7 +81,9 @@ describe MergeRequests::MergeService, services: true do
end
context "when jira_issue_transition_id is not present" do
- before { allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil) }
+ before do
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(nil)
+ end
it "does not close issue" do
allow(jira_tracker).to receive_messages(jira_issue_transition_id: nil)
@@ -110,7 +112,7 @@ describe MergeRequests::MergeService, services: true do
context 'closes related todos' do
let(:merge_request) { create(:merge_request, assignee: user, author: user) }
let(:project) { merge_request.project }
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
let!(:todo) do
create(:todo, :assigned,
project: project,
@@ -131,23 +133,70 @@ describe MergeRequests::MergeService, services: true do
it { expect(todo).to be_done }
end
- context 'remove source branch by author' do
- let(:service) do
- merge_request.merge_params['force_remove_source_branch'] = '1'
- merge_request.save!
- MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message')
+ context 'source branch removal' do
+ context 'when the source branch is protected' do
+ let(:service) do
+ described_class.new(project, user, should_remove_source_branch: '1')
+ end
+
+ before do
+ create(:protected_branch, project: project, name: merge_request.source_branch)
+ end
+
+ it 'does not delete the source branch' do
+ expect(DeleteBranchService).not_to receive(:new)
+ service.execute(merge_request)
+ end
end
- it 'removes the source branch' do
- expect(DeleteBranchService).to receive(:new).
- with(merge_request.source_project, merge_request.author).
- and_call_original
- service.execute(merge_request)
+ context 'when the source branch is the default branch' do
+ let(:service) do
+ described_class.new(project, user, should_remove_source_branch: '1')
+ end
+
+ before do
+ allow(project).to receive(:root_ref?).with(merge_request.source_branch).and_return(true)
+ end
+
+ it 'does not delete the source branch' do
+ expect(DeleteBranchService).not_to receive(:new)
+ service.execute(merge_request)
+ end
+ end
+
+ context 'when the source branch can be removed' do
+ context 'when MR author set the source branch to be removed' do
+ let(:service) do
+ merge_request.merge_params['force_remove_source_branch'] = '1'
+ merge_request.save!
+ described_class.new(project, user, commit_message: 'Awesome message')
+ end
+
+ it 'removes the source branch using the author user' do
+ expect(DeleteBranchService).to receive(:new)
+ .with(merge_request.source_project, merge_request.author)
+ .and_call_original
+ service.execute(merge_request)
+ end
+ end
+
+ context 'when MR merger set the source branch to be removed' do
+ let(:service) do
+ described_class.new(project, user, commit_message: 'Awesome message', should_remove_source_branch: '1')
+ end
+
+ it 'removes the source branch using the current user' do
+ expect(DeleteBranchService).to receive(:new)
+ .with(merge_request.source_project, user)
+ .and_call_original
+ service.execute(merge_request)
+ end
+ end
end
end
context "error handling" do
- let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
+ let(:service) { described_class.new(project, user, commit_message: 'Awesome message') }
before do
allow(Rails.logger).to receive(:error)
diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb
index a20b32eda5f..a37cdab8928 100644
--- a/spec/services/merge_requests/post_merge_service_spec.rb
+++ b/spec/services/merge_requests/post_merge_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::PostMergeService, services: true do
+describe MergeRequests::PostMergeService do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request, assignee: user) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 1f109eab268..2af2485eeed 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe MergeRequests::RefreshService, services: true do
+describe MergeRequests::RefreshService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
- let(:service) { MergeRequests::RefreshService }
+ let(:service) { described_class }
describe '#execute' do
before do
@@ -57,8 +57,8 @@ describe MergeRequests::RefreshService, services: true do
end
it 'executes hooks with update action' do
- expect(refresh_service).to have_received(:execute_hooks).
- with(@merge_request, 'update', @oldrev)
+ expect(refresh_service).to have_received(:execute_hooks)
+ .with(@merge_request, 'update', @oldrev)
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
@@ -83,8 +83,8 @@ describe MergeRequests::RefreshService, services: true do
end
it 'executes hooks with update action' do
- expect(refresh_service).to have_received(:execute_hooks).
- with(@merge_request, 'update', @oldrev)
+ expect(refresh_service).to have_received(:execute_hooks)
+ .with(@merge_request, 'update', @oldrev)
expect(@merge_request.notes).not_to be_empty
expect(@merge_request).to be_open
@@ -98,18 +98,52 @@ describe MergeRequests::RefreshService, services: true do
end
context 'push to origin repo target branch' do
- before do
- service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
- reload_mrs
+ context 'when all MRs to the target branch had diffs' do
+ before do
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ end
+
+ it 'updates the merge state' do
+ expect(@merge_request.notes.last.note).to include('merged')
+ expect(@merge_request).to be_merged
+ expect(@fork_merge_request).to be_merged
+ expect(@fork_merge_request.notes.last.note).to include('merged')
+ expect(@build_failed_todo).to be_done
+ expect(@fork_build_failed_todo).to be_done
+ end
end
- it 'updates the merge state' do
- expect(@merge_request.notes.last.note).to include('merged')
- expect(@merge_request).to be_merged
- expect(@fork_merge_request).to be_merged
- expect(@fork_merge_request.notes.last.note).to include('merged')
- expect(@build_failed_todo).to be_done
- expect(@fork_build_failed_todo).to be_done
+ context 'when an MR to be closed was empty already' do
+ let!(:empty_fork_merge_request) do
+ create(:merge_request,
+ source_project: @fork_project,
+ source_branch: 'master',
+ target_branch: 'master',
+ target_project: @project)
+ end
+
+ before do
+ # This spec already has a fake push, so pretend that we were targeting
+ # feature all along.
+ empty_fork_merge_request.update_columns(target_branch: 'feature')
+
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ empty_fork_merge_request.reload
+ end
+
+ it 'only updates the non-empty MRs' do
+ expect(@merge_request).to be_merged
+ expect(@merge_request.notes.last.note).to include('merged')
+
+ expect(@fork_merge_request).to be_merged
+ expect(@fork_merge_request.notes.last.note).to include('merged')
+
+ expect(empty_fork_merge_request).to be_open
+ expect(empty_fork_merge_request.merge_request_diff.state).to eq('empty')
+ expect(empty_fork_merge_request.notes).to be_empty
+ end
end
end
@@ -146,8 +180,8 @@ describe MergeRequests::RefreshService, services: true do
end
it 'executes hooks with update action' do
- expect(refresh_service).to have_received(:execute_hooks).
- with(@fork_merge_request, 'update', @oldrev)
+ expect(refresh_service).to have_received(:execute_hooks)
+ .with(@fork_merge_request, 'update', @oldrev)
expect(@merge_request.notes).to be_empty
expect(@merge_request).to be_open
@@ -228,8 +262,8 @@ describe MergeRequests::RefreshService, services: true do
let(:refresh_service) { service.new(@fork_project, @user) }
it 'refreshes the merge request' do
- expect(refresh_service).to receive(:execute_hooks).
- with(@fork_merge_request, 'update', Gitlab::Git::BLANK_SHA)
+ expect(refresh_service).to receive(:execute_hooks)
+ .with(@fork_merge_request, 'update', Gitlab::Git::BLANK_SHA)
allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev)
refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index b6d4db2f922..f02af0c582e 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::ReopenService, services: true do
+describe MergeRequests::ReopenService do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:guest) { create(:user) }
@@ -28,11 +28,11 @@ describe MergeRequests::ReopenService, services: true do
end
it { expect(merge_request).to be_valid }
- it { expect(merge_request).to be_reopened }
+ it { expect(merge_request).to be_opened }
it 'executes hooks with reopen action' do
- expect(service).to have_received(:execute_hooks).
- with(merge_request, 'reopen')
+ expect(service).to have_received(:execute_hooks)
+ .with(merge_request, 'reopen')
end
it 'sends email to user2 about reopen of merge_request' do
diff --git a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
index 7ddd812e513..e3fd906fe7b 100644
--- a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
+++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::ResolvedDiscussionNotificationService, services: true do
+describe MergeRequests::ResolvedDiscussionNotificationService do
let(:merge_request) { create(:merge_request) }
let(:user) { create(:user) }
let(:project) { merge_request.project }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index d371fc68312..dd3ac9c4ac6 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::UpdateService, services: true do
+describe MergeRequests::UpdateService do
include EmailHelpers
let(:project) { create(:project, :repository) }
@@ -30,6 +30,13 @@ describe MergeRequests::UpdateService, services: true do
end
end
+ def find_notes(action)
+ @merge_request
+ .notes
+ .joins(:system_note_metadata)
+ .where(system_note_metadata: { action: action })
+ end
+
def update_merge_request(opts)
@merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
@merge_request.reload
@@ -48,7 +55,7 @@ describe MergeRequests::UpdateService, services: true do
}
end
- let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
+ let(:service) { described_class.new(project, user, opts) }
before do
allow(service).to receive(:execute_hooks)
@@ -71,8 +78,8 @@ describe MergeRequests::UpdateService, services: true do
end
it 'executes hooks with update action' do
- expect(service).to have_received(:execute_hooks).
- with(@merge_request, 'update')
+ expect(service).to have_received(:execute_hooks)
+ .with(@merge_request, 'update')
end
it 'sends email to user2 about assign of new merge request and email to user3 about merge request unassignment' do
@@ -138,7 +145,7 @@ describe MergeRequests::UpdateService, services: true do
}
end
- let(:service) { MergeRequests::UpdateService.new(project, user, opts) }
+ let(:service) { described_class.new(project, user, opts) }
context 'without pipeline' do
before do
@@ -188,8 +195,8 @@ describe MergeRequests::UpdateService, services: true do
head_pipeline_of: merge_request
)
- expect(MergeRequests::MergeWhenPipelineSucceedsService).to receive(:new).with(project, user).
- and_return(service_mock)
+ expect(MergeRequests::MergeWhenPipelineSucceedsService).to receive(:new).with(project, user)
+ .and_return(service_mock)
expect(service_mock).to receive(:execute).with(merge_request)
end
@@ -198,7 +205,7 @@ describe MergeRequests::UpdateService, services: true do
context 'with a non-authorised user' do
let(:visitor) { create(:user) }
- let(:service) { MergeRequests::UpdateService.new(project, visitor, opts) }
+ let(:service) { described_class.new(project, visitor, opts) }
before do
merge_request.update_attribute(:merge_error, 'Error')
@@ -289,13 +296,13 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when the milestone change' do
- before do
+ it 'marks pending todos as done' do
update_merge_request({ milestone: create(:milestone) })
- end
- it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
end
+
+ it_behaves_like 'system notes for milestones'
end
context 'when the labels change' do
@@ -341,7 +348,7 @@ describe MergeRequests::UpdateService, services: true do
opts = { label_ids: [label.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_email(subscriber)
@@ -349,13 +356,15 @@ describe MergeRequests::UpdateService, services: true do
end
context 'when issue has the `label` label' do
- before { merge_request.labels << label }
+ before do
+ merge_request.labels << label
+ end
it 'does not send notifications for existing labels' do
opts = { label_ids: [label.id, label2.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_not_email(subscriber)
@@ -366,7 +375,7 @@ describe MergeRequests::UpdateService, services: true do
opts = { label_ids: [label2.id] }
perform_enqueued_jobs do
- @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request)
+ @merge_request = described_class.new(project, user, opts).execute(merge_request)
end
should_not_email(subscriber)
@@ -377,16 +386,20 @@ describe MergeRequests::UpdateService, services: true do
context 'updating mentions' do
let(:mentionable) { merge_request }
- include_examples 'updating mentions', MergeRequests::UpdateService
+ include_examples 'updating mentions', described_class
end
context 'when MergeRequest has tasks' do
- before { update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [ ] Task 1\n- [ ] Task 2" })
+ end
it { expect(@merge_request.tasks?).to eq(true) }
context 'when tasks are marked as completed' do
- before { update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" }) }
+ before do
+ update_merge_request({ description: "- [x] Task 1\n- [X] Task 2" })
+ end
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
@@ -394,6 +407,9 @@ describe MergeRequests::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
@@ -409,6 +425,9 @@ describe MergeRequests::UpdateService, services: true do
expect(note1).not_to be_nil
expect(note2).not_to be_nil
+
+ description_notes = find_notes('description')
+ expect(description_notes.length).to eq(1)
end
end
end
diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb
index d581b94ff43..2bdf224804d 100644
--- a/spec/services/milestones/close_service_spec.rb
+++ b/spec/services/milestones/close_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Milestones::CloseService, services: true do
+describe Milestones::CloseService do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) }
before do
@@ -11,7 +11,7 @@ describe Milestones::CloseService, services: true do
describe '#execute' do
before do
- Milestones::CloseService.new(project, user, {}).execute(milestone)
+ described_class.new(project, user, {}).execute(milestone)
end
it { expect(milestone).to be_valid }
diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb
index 6d29edb449a..8837b91051d 100644
--- a/spec/services/milestones/create_service_spec.rb
+++ b/spec/services/milestones/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Milestones::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe Milestones::CreateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
describe '#execute' do
@@ -14,7 +14,7 @@ describe Milestones::CreateService, services: true do
description: 'Patch release to fix security issue'
}
- @milestone = Milestones::CreateService.new(project, user, opts).execute
+ @milestone = described_class.new(project, user, opts).execute
end
it { expect(@milestone).to be_valid }
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
new file mode 100644
index 00000000000..5739386dd0d
--- /dev/null
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+describe Milestones::DestroyService do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) }
+ let(:issue) { create(:issue, project: project, milestone: milestone) }
+ let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ def service
+ described_class.new(project, user, {})
+ end
+
+ describe '#execute' do
+ it 'deletes milestone' do
+ service.execute(milestone)
+
+ expect { milestone.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
+
+ it 'deletes milestone id from issuables' do
+ service.execute(milestone)
+
+ expect(issue.reload.milestone).to be_nil
+ expect(merge_request.reload.milestone).to be_nil
+ end
+
+ context 'group milestones' do
+ let(:group) { create(:group) }
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ before do
+ project.update(namespace: group)
+ group.add_developer(user)
+ end
+
+ it { expect(service.execute(group_milestone)).to be_nil }
+
+ it 'does not update milestone issuables' do
+ expect(MergeRequests::UpdateService).not_to receive(:new)
+ expect(Issues::UpdateService).not_to receive(:new)
+
+ service.execute(group_milestone)
+ end
+ end
+ end
+end
diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb
index 39f06f8f8e7..a6cc2251e48 100644
--- a/spec/services/note_summary_spec.rb
+++ b/spec/services/note_summary_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe NoteSummary, services: true do
- let(:project) { build(:empty_project) }
+describe NoteSummary do
+ let(:project) { build(:project) }
let(:noteable) { build(:issue) }
let(:user) { build(:user) }
diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb
index 133175769ca..6e1c1fe6c02 100644
--- a/spec/services/notes/build_service_spec.rb
+++ b/spec/services/notes/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Notes::BuildService, services: true do
+describe Notes::BuildService do
let(:note) { create(:discussion_note_on_issue) }
let(:project) { note.project }
let(:author) { note.author }
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 152c6d20daa..661d26946e7 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Notes::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe Notes::CreateService do
+ let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
let(:opts) do
diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb
index f53f96e0c2b..c9a99a43edb 100644
--- a/spec/services/notes/destroy_service_spec.rb
+++ b/spec/services/notes/destroy_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Notes::DestroyService, services: true do
+describe Notes::DestroyService do
describe '#execute' do
it 'deletes a note' do
- project = create(:empty_project)
+ project = create(:project)
issue = create(:issue, project: project)
note = create(:note, project: project, noteable: issue)
diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb
index e33a611929b..a2b3638059f 100644
--- a/spec/services/notes/post_process_service_spec.rb
+++ b/spec/services/notes/post_process_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Notes::PostProcessService, services: true do
- let(:project) { create(:empty_project) }
+describe Notes::PostProcessService do
+ let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
@@ -21,7 +21,7 @@ describe Notes::PostProcessService, services: true do
expect(project).to receive(:execute_hooks)
expect(project).to receive(:execute_services)
- Notes::PostProcessService.new(@note).execute
+ described_class.new(@note).execute
end
end
end
diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index c9954dc3603..0280a19098b 100644
--- a/spec/services/notes/slash_commands_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -1,15 +1,17 @@
require 'spec_helper'
-describe Notes::SlashCommandsService, services: true do
+describe Notes::QuickActionsService do
shared_context 'note on noteable' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
- before { project.team << [assignee, :master] }
+ before do
+ project.team << [assignee, :master]
+ end
end
- shared_examples 'note on noteable that does not support slash commands' do
+ shared_examples 'note on noteable that does not support quick actions' do
include_context 'note on noteable'
before do
@@ -43,7 +45,7 @@ describe Notes::SlashCommandsService, services: true do
end
end
- shared_examples 'note on noteable that supports slash commands' do
+ shared_examples 'note on noteable that supports quick actions' do
include_context 'note on noteable'
before do
@@ -208,22 +210,22 @@ describe Notes::SlashCommandsService, services: true do
describe '#execute' do
let(:service) { described_class.new(project, master) }
- it_behaves_like 'note on noteable that supports slash commands' do
+ it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_issue, project: project) }
end
- it_behaves_like 'note on noteable that supports slash commands' do
+ it_behaves_like 'note on noteable that supports quick actions' do
let(:note) { build(:note_on_merge_request, project: project) }
end
- it_behaves_like 'note on noteable that does not support slash commands' do
+ it_behaves_like 'note on noteable that does not support quick actions' do
let(:note) { build(:note_on_commit, project: project) }
end
end
context 'CE restriction for issue assignees' do
describe '/assign' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:assignee) { create(:user) }
let(:master) { create(:user) }
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 905e2f46bde..3210539f3ee 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Notes::UpdateService, services: true do
- let(:project) { create(:empty_project) }
+describe Notes::UpdateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb
new file mode 100644
index 00000000000..0eb0771fd29
--- /dev/null
+++ b/spec/services/notification_recipient_service_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe NotificationRecipientService do
+ set(:user) { create(:user) }
+ set(:project) { create(:project, :public) }
+ set(:issue) { create(:issue, project: project) }
+
+ set(:watcher) do
+ watcher = create(:user)
+ setting = watcher.notification_settings_for(project)
+ setting.level = :watch
+ setting.save
+
+ watcher
+ end
+
+ subject { described_class.new(project) }
+
+ describe '#build_recipients' do
+ it 'does not modify the participants of the target' do
+ expect { subject.build_recipients(issue, user, action: :new_issue) }
+ .not_to change { issue.participants(user) }
+ end
+ end
+
+ describe '#build_new_note_recipients' do
+ set(:note) { create(:note_on_issue, noteable: issue, project: project) }
+
+ it 'does not modify the participants of the target' do
+ expect { subject.build_new_note_recipients(note) }
+ .not_to change { note.noteable.participants(note.author) }
+ end
+ end
+end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index de3bbc6b6a1..882ee7751b5 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe NotificationService, services: true do
+describe NotificationService do
include EmailHelpers
- let(:notification) { NotificationService.new }
+ let(:notification) { described_class.new }
let(:assignee) { create(:user) }
around(:each) do |example|
@@ -93,6 +93,18 @@ describe NotificationService, services: true do
end
end
+ describe 'GpgKeys' do
+ describe '#new_gpg_key' do
+ let!(:key) { create(:gpg_key) }
+
+ it { expect(notification.new_gpg_key(key)).to be_truthy }
+
+ it 'sends email to key owner' do
+ expect{ notification.new_gpg_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
+ end
+ end
+ end
+
describe 'Email' do
describe '#new_email' do
let!(:email) { create(:email) }
@@ -107,7 +119,7 @@ describe NotificationService, services: true do
describe 'Notes' do
context 'issue note' do
- let(:project) { create(:empty_project, :private) }
+ let(:project) { create(:project, :private) }
let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') }
@@ -216,7 +228,7 @@ describe NotificationService, services: true do
end
context 'confidential issue note' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:non_member) { create(:user) }
@@ -248,7 +260,7 @@ describe NotificationService, services: true do
end
context 'issue note mention' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project, assignees: [assignee]) }
let(:mentioned_issue) { create(:issue, assignees: issue.assignees) }
let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
@@ -291,7 +303,7 @@ describe NotificationService, services: true do
end
context 'project snippet note' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:snippet) { create(:project_snippet, project: project, author: create(:user)) }
let(:note) { create(:note_on_project_snippet, noteable: snippet, project_id: snippet.project.id, note: '@all mentioned') }
@@ -383,7 +395,7 @@ describe NotificationService, services: true do
before do
build_team(note.project)
reset_delivered_emails!
- allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer)
+ allow(note.noteable).to receive(:author).and_return(@u_committer)
update_custom_notification(:new_note, @u_guest_custom, resource: project)
update_custom_notification(:new_note, @u_custom_global)
end
@@ -452,8 +464,8 @@ describe NotificationService, services: true do
describe 'Issues' do
let(:group) { create(:group) }
- let(:project) { create(:empty_project, :public, namespace: group) }
- let(:another_project) { create(:empty_project, :public, namespace: group) }
+ let(:project) { create(:project, :public, namespace: group) }
+ let(:another_project) { create(:project, :public, namespace: group) }
let(:issue) { create :issue, project: project, assignees: [assignee], description: 'cc @participant' }
before do
@@ -682,17 +694,6 @@ describe NotificationService, services: true do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the issue's added labels only" do
- notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
-
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
- end
-
it "emails the current user if they've opted into notifications about their activity" do
subscriber_to_label_2.notified_of_own_activity = true
notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2)
@@ -709,6 +710,12 @@ describe NotificationService, services: true do
it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled)
+ should_not_email(subscriber_to_label_1)
+ should_not_email(subscriber_to_group_label_1)
+ should_not_email(subscriber_to_group_label_2_on_another_project)
+ should_email(subscriber_1_to_group_label_2)
+ should_email(subscriber_2_to_group_label_2)
+ should_email(subscriber_to_label_2)
should_not_email(issue.assignees.first)
should_not_email(issue.author)
should_not_email(@u_watcher)
@@ -718,12 +725,6 @@ describe NotificationService, services: true do
should_not_email(@watcher_and_subscriber)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
context 'confidential issues' do
@@ -854,7 +855,7 @@ describe NotificationService, services: true do
describe 'Merge Requests' do
let(:group) { create(:group) }
let(:project) { create(:project, :public, :repository, namespace: group) }
- let(:another_project) { create(:empty_project, :public, namespace: group) }
+ let(:another_project) { create(:project, :public, namespace: group) }
let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user), description: 'cc @participant' }
before do
@@ -866,11 +867,6 @@ describe NotificationService, services: true do
end
describe '#new_merge_request' do
- before do
- update_custom_notification(:new_merge_request, @u_guest_custom, resource: project)
- update_custom_notification(:new_merge_request, @u_custom_global)
- end
-
it do
notification.new_merge_request(merge_request, @u_disabled)
@@ -996,7 +992,7 @@ describe NotificationService, services: true do
let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } }
let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } }
- it "emails subscribers of the merge request's added labels only" do
+ it "doesn't send email to anyone but subscribers of the given labels" do
notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
should_not_email(subscriber_to_label_1)
@@ -1005,11 +1001,6 @@ describe NotificationService, services: true do
should_email(subscriber_1_to_group_label_2)
should_email(subscriber_2_to_group_label_2)
should_email(subscriber_to_label_2)
- end
-
- it "doesn't send email to anyone but subscribers of the given labels" do
- notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled)
-
should_not_email(merge_request.assignee)
should_not_email(merge_request.author)
should_not_email(@u_watcher)
@@ -1019,12 +1010,6 @@ describe NotificationService, services: true do
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_lazy_participant)
- should_not_email(subscriber_to_label_1)
- should_not_email(subscriber_to_group_label_1)
- should_not_email(subscriber_to_group_label_2_on_another_project)
- should_email(subscriber_1_to_group_label_2)
- should_email(subscriber_2_to_group_label_2)
- should_email(subscriber_to_label_2)
end
end
@@ -1069,12 +1054,12 @@ describe NotificationService, services: true do
should_email(merge_request.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
+ should_email(@u_guest_custom)
+ should_email(@u_custom_global)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
- should_email(@u_guest_watcher)
- should_email(@u_custom_global)
- should_email(@u_guest_custom)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
@@ -1165,7 +1150,7 @@ describe NotificationService, services: true do
end
describe 'Projects' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
before do
build_team(project)
@@ -1226,7 +1211,7 @@ describe NotificationService, services: true do
describe 'ProjectMember' do
describe '#decline_group_invite' do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:member) { create(:user) }
before(:each) do
@@ -1244,7 +1229,7 @@ describe NotificationService, services: true do
end
context 'guest user in private project' do
- let(:private_project) { create(:empty_project, :private) }
+ let(:private_project) { create(:project, :private) }
let(:guest) { create(:user) }
let(:developer) { create(:user) }
let(:assignee) { create(:user) }
@@ -1539,8 +1524,7 @@ describe NotificationService, services: true do
# When resource is nil it means global notification
def update_custom_notification(event, user, resource: nil, value: true)
setting = user.notification_settings_for(resource)
- setting.events[event] = value
- setting.save
+ setting.update!(event => value)
end
def add_users_with_subscription(project, issuable)
diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb
index aa63fe3a5c1..f8db6900a0a 100644
--- a/spec/services/pages_service_spec.rb
+++ b/spec/services/pages_service_spec.rb
@@ -1,19 +1,23 @@
require 'spec_helper'
-describe PagesService, services: true do
+describe PagesService do
let(:build) { create(:ci_build) }
let(:data) { Gitlab::DataBuilder::Build.build(build) }
- let(:service) { PagesService.new(data) }
+ let(:service) { described_class.new(data) }
before do
allow(Gitlab.config.pages).to receive(:enabled).and_return(true)
end
context 'execute asynchronously for pages job' do
- before { build.name = 'pages' }
+ before do
+ build.name = 'pages'
+ end
context 'on success' do
- before { build.success }
+ before do
+ build.success
+ end
it 'executes worker' do
expect(PagesWorker).to receive(:perform_async)
@@ -23,7 +27,9 @@ describe PagesService, services: true do
%w(pending running failed canceled).each do |status|
context "on #{status}" do
- before { build.status = status }
+ before do
+ build.status = status
+ end
it 'does not execute worker' do
expect(PagesWorker).not_to receive(:perform_async)
diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb
index b2fb5c91313..64a9559791f 100644
--- a/spec/services/preview_markdown_service_spec.rb
+++ b/spec/services/preview_markdown_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe PreviewMarkdownService do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
before do
project.add_developer(user)
@@ -19,24 +19,24 @@ describe PreviewMarkdownService do
end
end
- context 'new note with slash commands' do
+ context 'new note with quick actions' do
let(:issue) { create(:issue, project: project) }
let(:params) do
{
text: "Please do it\n/assign #{user.to_reference}",
- slash_commands_target_type: 'Issue',
- slash_commands_target_id: issue.id
+ quick_actions_target_type: 'Issue',
+ quick_actions_target_id: issue.id
}
end
let(:service) { described_class.new(project, user, params) }
- it 'removes slash commands from text' do
+ it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'Please do it'
end
- it 'explains slash commands effect' do
+ it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq "Assigns #{user.to_reference}."
@@ -47,21 +47,21 @@ describe PreviewMarkdownService do
let(:params) do
{
text: "My work\n/estimate 2y",
- slash_commands_target_type: 'MergeRequest'
+ quick_actions_target_type: 'MergeRequest'
}
end
let(:service) { described_class.new(project, user, params) }
- it 'removes slash commands from text' do
+ it 'removes quick actions from text' do
result = service.execute
expect(result[:text]).to eq 'My work'
end
- it 'explains slash commands effect' do
+ it 'explains quick actions effect' do
result = service.execute
expect(result[:commands]).to eq 'Sets time estimate to 2y.'
- end
+ end
end
end
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
index c198c3eedfc..c1f098530bf 100644
--- a/spec/services/projects/autocomplete_service_spec.rb
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::AutocompleteService, services: true do
+describe Projects::AutocompleteService do
describe '#issues' do
describe 'confidential issues' do
let(:author) { create(:user) }
@@ -8,7 +8,7 @@ describe Projects::AutocompleteService, services: true do
let(:non_member) { create(:user) }
let(:member) { create(:user) }
let(:admin) { create(:admin) }
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let!(:issue) { create(:issue, project: project, title: 'Issue 1') }
let!(:security_issue_1) { create(:issue, :confidential, project: project, title: 'Security issue 1', author: author) }
let!(:security_issue_2) { create(:issue, :confidential, title: 'Security issue 2', project: project, assignees: [assignee]) }
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 3c566c04d6b..b0dc7488b5f 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::CreateService, '#execute', services: true do
+describe Projects::CreateService, '#execute' do
let(:user) { create :user }
let(:opts) do
{
@@ -115,7 +115,7 @@ describe Projects::CreateService, '#execute', services: true do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
opts.merge!(
- visibility_level: Gitlab::VisibilityLevel.options['Public']
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC
)
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index 0d6dd28e332..85b05ef6d05 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::DestroyService, services: true do
+describe Projects::DestroyService do
let!(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace) }
let!(:path) { project.repository.path_to_repo }
@@ -15,8 +15,9 @@ describe Projects::DestroyService, services: true do
shared_examples 'deleting the project' do
it 'deletes the project' do
expect(Project.unscoped.all).not_to include(project)
- expect(Dir.exist?(path)).to be_falsey
- expect(Dir.exist?(remove_path)).to be_falsey
+
+ expect(project.gitlab_shell.exists?(project.repository_storage_path, path + '.git')).to be_falsey
+ expect(project.gitlab_shell.exists?(project.repository_storage_path, remove_path + '.git')).to be_falsey
end
end
@@ -35,6 +36,27 @@ describe Projects::DestroyService, services: true do
end
end
+ shared_examples 'handles errors thrown during async destroy' do |error_message|
+ it 'does not allow the error to bubble up' do
+ expect do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+ end.not_to raise_error
+ end
+
+ it 'unmarks the project as "pending deletion"' do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+
+ expect(project.reload.pending_delete).to be(false)
+ end
+
+ it 'stores an error message in `projects.delete_error`' do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+
+ expect(project.reload.delete_error).to be_present
+ expect(project.delete_error).to include(error_message)
+ end
+ end
+
context 'Sidekiq inline' do
before do
# Run sidekiq immediatly to check that renamed repository will be removed
@@ -59,14 +81,14 @@ describe Projects::DestroyService, services: true do
before do
new_user = create(:user)
project.team.add_user(new_user, Gitlab::Access::DEVELOPER)
- allow_any_instance_of(Projects::DestroyService).to receive(:flush_caches).and_raise(Redis::CannotConnectError)
+ allow_any_instance_of(described_class).to receive(:flush_caches).and_raise(::Redis::CannotConnectError)
end
it 'keeps project team intact upon an error' do
Sidekiq::Testing.inline! do
begin
destroy_project(project, user, {})
- rescue Redis::CannotConnectError
+ rescue ::Redis::CannotConnectError
end
end
@@ -88,10 +110,51 @@ describe Projects::DestroyService, services: true do
end
it_behaves_like 'deleting the project with pipeline and build'
- end
- context 'with execute' do
- it_behaves_like 'deleting the project with pipeline and build'
+ context 'errors' do
+ context 'when `remove_legacy_registry_tags` fails' do
+ before do
+ expect_any_instance_of(described_class)
+ .to receive(:remove_legacy_registry_tags).and_return(false)
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Failed to remove some tags"
+ end
+
+ context 'when `remove_repository` fails' do
+ before do
+ expect_any_instance_of(described_class)
+ .to receive(:remove_repository).and_return(false)
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Failed to remove project repository"
+ end
+
+ context 'when `execute` raises expected error' do
+ before do
+ expect_any_instance_of(Project)
+ .to receive(:destroy!).and_raise(StandardError.new("Other error message"))
+ end
+
+ it_behaves_like 'handles errors thrown during async destroy', "Other error message"
+ end
+
+ context 'when `execute` raises unexpected error' do
+ before do
+ expect_any_instance_of(Project)
+ .to receive(:destroy!).and_raise(Exception.new("Other error message"))
+ end
+
+ it 'allows error to bubble up and rolls back project deletion' do
+ expect do
+ Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
+ end.to raise_error
+
+ expect(project.reload.pending_delete).to be(false)
+ expect(project.delete_error).to include("Other error message")
+ end
+ end
+ end
end
describe 'container registry' do
@@ -118,8 +181,7 @@ describe Projects::DestroyService, services: true do
expect_any_instance_of(ContainerRepository)
.to receive(:delete_tags!).and_return(false)
- expect{ destroy_project(project, user) }
- .to raise_error(ActiveRecord::RecordNotDestroyed)
+ expect(destroy_project(project, user)).to be false
end
end
end
@@ -144,8 +206,7 @@ describe Projects::DestroyService, services: true do
expect_any_instance_of(ContainerRepository)
.to receive(:delete_tags!).and_return(false)
- expect { destroy_project(project, user) }
- .to raise_error(Projects::DestroyService::DestroyError)
+ expect(destroy_project(project, user)).to be false
end
end
end
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index 33b267c069c..da236052ebf 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe Projects::DownloadService, services: true do
+describe Projects::DownloadService do
describe 'File service' do
before do
@user = create(:user)
- @project = create(:empty_project, creator_id: @user.id, namespace: @user.namespace)
+ @project = create(:project, creator_id: @user.id, namespace: @user.namespace)
end
context 'for a URL that is not on whitelist' do
diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb
index 78626fbad4b..835dae68fcd 100644
--- a/spec/services/projects/enable_deploy_key_service_spec.rb
+++ b/spec/services/projects/enable_deploy_key_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Projects::EnableDeployKeyService, services: true do
+describe Projects::EnableDeployKeyService do
let(:deploy_key) { create(:deploy_key, public: true) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:user) { project.creator}
let!(:params) { { key_id: deploy_key.id } }
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index f8eb34f2ef4..c90536ba346 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe Projects::ForkService, services: true do
+describe Projects::ForkService do
describe 'fork by user' do
before do
- @from_namespace = create(:namespace)
- @from_user = create(:user, namespace: @from_namespace )
+ @from_user = create(:user)
+ @from_namespace = @from_user.namespace
avatar = fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
@from_project = create(:project,
:repository,
@@ -13,8 +13,8 @@ describe Projects::ForkService, services: true do
star_count: 107,
avatar: avatar,
description: 'wow such project')
- @to_namespace = create(:namespace)
- @to_user = create(:user, namespace: @to_namespace)
+ @to_user = create(:user)
+ @to_namespace = @to_user.namespace
@from_project.add_user(@to_user, :developer)
end
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index fff12beed71..ebed802708d 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -66,14 +66,14 @@ describe Projects::HousekeepingService do
allow(subject).to receive(:lease_key).and_return(:the_lease_key)
# At push 200
- expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :the_lease_key, :the_uuid).
- exactly(1).times
+ expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :the_lease_key, :the_uuid)
+ .exactly(1).times
# At push 50, 100, 150
- expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :full_repack, :the_lease_key, :the_uuid).
- exactly(3).times
+ expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :full_repack, :the_lease_key, :the_uuid)
+ .exactly(3).times
# At push 10, 20, ... (except those above)
- expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :incremental_repack, :the_lease_key, :the_uuid).
- exactly(16).times
+ expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :incremental_repack, :the_lease_key, :the_uuid)
+ .exactly(16).times
201.times do
subject.increment!
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index 44db299812f..c0ab1ea704d 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Projects::ImportService, services: true do
- let!(:project) { create(:empty_project) }
+describe Projects::ImportService do
+ let!(:project) { create(:project) }
let(:user) { project.creator }
subject { described_class.new(project, user) }
@@ -26,7 +26,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The repository could not be created."
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The repository could not be created."
end
end
@@ -52,7 +52,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository"
end
it 'does not remove the GitHub remote' do
@@ -86,7 +86,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository"
end
end
end
@@ -111,11 +111,11 @@ describe Projects::ImportService, services: true do
end
it 'flushes various caches' do
- allow_any_instance_of(Repository).to receive(:fetch_remote).
- and_return(true)
+ allow_any_instance_of(Repository).to receive(:fetch_remote)
+ .and_return(true)
- allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).
- and_return(true)
+ allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute)
+ .and_return(true)
expect_any_instance_of(Repository).to receive(:expire_content_cache)
@@ -129,7 +129,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The remote data could not be imported."
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The remote data could not be imported."
end
it 'fails if importer raise an error' do
@@ -139,7 +139,7 @@ describe Projects::ImportService, services: true do
result = subject.execute
expect(result[:status]).to eq :error
- expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Github: failed to connect API"
+ expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Github: failed to connect API"
end
it 'expires content cache after error' do
diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb
index 0657b7e93fe..0d18ceb8ff8 100644
--- a/spec/services/projects/participants_service_spec.rb
+++ b/spec/services/projects/participants_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe Projects::ParticipantsService, services: true do
+describe Projects::ParticipantsService do
describe '#groups' do
describe 'avatar_url' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:group) { create(:group, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/dk.png')) }
let(:user) { create(:user) }
let!(:group_member) { create(:group_member, group: group, user: user) }
@@ -13,7 +13,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/uploads/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
it 'should return an url for the avatar with relative url' do
@@ -24,7 +24,7 @@ describe Projects::ParticipantsService, services: true do
groups = participants.groups
expect(groups.size).to eq 1
- expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/group/avatar/#{group.id}/dk.png")
+ expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/-/system/group/avatar/#{group.id}/dk.png")
end
end
end
diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb
index 8a6a9f09f74..f4c59735c43 100644
--- a/spec/services/projects/propagate_service_template_spec.rb
+++ b/spec/services/projects/propagate_service_template_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::PropagateServiceTemplate, services: true do
+describe Projects::PropagateServiceTemplate do
describe '.propagate' do
let!(:service_template) do
PushoverService.create(
@@ -15,7 +15,7 @@ describe Projects::PropagateServiceTemplate, services: true do
})
end
- let!(:project) { create(:empty_project) }
+ let!(:project) { create(:project) }
it 'creates services for projects' do
expect(project.pushover_service).to be_nil
@@ -60,8 +60,8 @@ describe Projects::PropagateServiceTemplate, services: true do
Service.build_from_template(project.id, service_template).save!
Service.build_from_template(project.id, other_service).save!
- expect { described_class.propagate(service_template) }.
- not_to change { Service.count }
+ expect { described_class.propagate(service_template) }
+ .not_to change { Service.count }
end
it 'creates the service containing the template attributes' do
@@ -76,7 +76,7 @@ describe Projects::PropagateServiceTemplate, services: true do
before do
stub_const 'Projects::PropagateServiceTemplate::BATCH_SIZE', 3
- project_total.times { create(:empty_project) }
+ project_total.times { create(:project) }
described_class.propagate(service_template)
end
@@ -90,8 +90,8 @@ describe Projects::PropagateServiceTemplate, services: true do
it 'updates the project external tracker' do
service_template.update!(category: 'issue_tracker', default: false)
- expect { described_class.propagate(service_template) }.
- to change { project.reload.has_external_issue_tracker }.to(true)
+ expect { described_class.propagate(service_template) }
+ .to change { project.reload.has_external_issue_tracker }.to(true)
end
end
@@ -99,8 +99,8 @@ describe Projects::PropagateServiceTemplate, services: true do
it 'updates the project external tracker' do
service_template.update!(type: 'ExternalWikiService')
- expect { described_class.propagate(service_template) }.
- to change { project.reload.has_external_wiki }.to(true)
+ expect { described_class.propagate(service_template) }
+ .to change { project.reload.has_external_wiki }.to(true)
end
end
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index b957517c715..2cb60cbcfc4 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -1,16 +1,16 @@
require 'spec_helper'
-describe Projects::TransferService, services: true do
+describe Projects::TransferService do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: user.namespace) }
context 'namespace -> namespace' do
before do
- allow_any_instance_of(Gitlab::UploadsTransfer).
- to receive(:move_project).and_return(true)
- allow_any_instance_of(Gitlab::PagesTransfer).
- to receive(:move_project).and_return(true)
+ allow_any_instance_of(Gitlab::UploadsTransfer)
+ .to receive(:move_project).and_return(true)
+ allow_any_instance_of(Gitlab::PagesTransfer)
+ .to receive(:move_project).and_return(true)
group.add_owner(user)
@result = transfer_project(project, user, group)
end
@@ -19,6 +19,73 @@ describe Projects::TransferService, services: true do
it { expect(project.namespace).to eq(group) }
end
+ context 'when transfer succeeds' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'sends notifications' do
+ expect_any_instance_of(NotificationService).to receive(:project_was_moved)
+
+ transfer_project(project, user, group)
+ end
+
+ it 'expires full_path cache' do
+ expect(project).to receive(:expires_full_path_cache)
+
+ transfer_project(project, user, group)
+ end
+
+ it 'executes system hooks' do
+ transfer_project(project, user, group) do |service|
+ expect(service).to receive(:execute_system_hooks)
+ end
+ end
+ end
+
+ context 'when transfer fails' do
+ let!(:original_path) { project_path(project) }
+
+ def attempt_project_transfer(&block)
+ expect do
+ transfer_project(project, user, group, &block)
+ end.to raise_error(ActiveRecord::ActiveRecordError)
+ end
+
+ before do
+ group.add_owner(user)
+
+ expect_any_instance_of(Labels::TransferService).to receive(:execute).and_raise(ActiveRecord::StatementInvalid, "PG ERROR")
+ end
+
+ def project_path(project)
+ File.join(project.repository_storage_path, "#{project.disk_path}.git")
+ end
+
+ def current_path
+ project_path(project)
+ end
+
+ it 'rolls back repo location' do
+ attempt_project_transfer
+
+ expect(Dir.exist?(original_path)).to be_truthy
+ expect(original_path).to eq current_path
+ end
+
+ it "doesn't send move notifications" do
+ expect_any_instance_of(NotificationService).not_to receive(:project_was_moved)
+
+ attempt_project_transfer
+ end
+
+ it "doesn't run system hooks" do
+ attempt_project_transfer do |service|
+ expect(service).not_to receive(:execute_system_hooks)
+ end
+ end
+ end
+
context 'namespace -> no namespace' do
before do
@result = transfer_project(project, user, nil)
@@ -53,18 +120,26 @@ describe Projects::TransferService, services: true do
end
def transfer_project(project, user, new_namespace)
- Projects::TransferService.new(project, user).execute(new_namespace)
+ service = Projects::TransferService.new(project, user)
+
+ yield(service) if block_given?
+
+ service.execute(new_namespace)
end
context 'visibility level' do
let(:internal_group) { create(:group, :internal) }
- before { internal_group.add_owner(user) }
+ before do
+ internal_group.add_owner(user)
+ end
context 'when namespace visibility level < project visibility level' do
let(:public_project) { create(:project, :public, :repository, namespace: user.namespace) }
- before { transfer_project(public_project, user, internal_group) }
+ before do
+ transfer_project(public_project, user, internal_group)
+ end
it { expect(public_project.visibility_level).to eq(internal_group.visibility_level) }
end
@@ -72,7 +147,9 @@ describe Projects::TransferService, services: true do
context 'when namespace visibility level > project visibility level' do
let(:private_project) { create(:project, :private, :repository, namespace: user.namespace) }
- before { transfer_project(private_project, user, internal_group) }
+ before do
+ transfer_project(private_project, user, internal_group)
+ end
it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) }
end
@@ -106,9 +183,9 @@ describe Projects::TransferService, services: true do
end
it 'only schedules a single job for every user' do
- expect(UserProjectAccessChangedService).to receive(:new).
- with([owner.id, group_member.id]).
- and_call_original
+ expect(UserProjectAccessChangedService).to receive(:new)
+ .with([owner.id, group_member.id])
+ .and_call_original
transfer_project(project, owner, group)
end
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index 23f5555d3e0..2ae8d5f7c54 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Projects::UnlinkForkService, services: true do
- subject { Projects::UnlinkForkService.new(fork_project, user) }
+describe Projects::UnlinkForkService do
+ subject { described_class.new(fork_project, user) }
let(:fork_link) { create(:forked_project_link) }
let(:fork_project) { fork_link.forked_to_project }
@@ -12,9 +12,9 @@ describe Projects::UnlinkForkService, services: true do
let(:mr_close_service) { MergeRequests::CloseService.new(fork_project, user) }
before do
- allow(MergeRequests::CloseService).to receive(:new).
- with(fork_project, user).
- and_return(mr_close_service)
+ allow(MergeRequests::CloseService).to receive(:new)
+ .with(fork_project, user)
+ .and_return(mr_close_service)
end
it 'close all pending merge requests' do
diff --git a/spec/services/projects/update_pages_configuration_service_spec.rb b/spec/services/projects/update_pages_configuration_service_spec.rb
index 8b329bc21c3..e4d4e6ff3dd 100644
--- a/spec/services/projects/update_pages_configuration_service_spec.rb
+++ b/spec/services/projects/update_pages_configuration_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe Projects::UpdatePagesConfigurationService, services: true do
- let(:project) { create(:empty_project) }
+describe Projects::UpdatePagesConfigurationService do
+ let(:project) { create(:project) }
subject { described_class.new(project) }
describe "#update" do
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index fc0a17296f3..aa6ad6340f5 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -96,6 +96,78 @@ describe Projects::UpdatePagesService do
expect(execute).not_to eq(:success)
end
+ describe 'maximum pages artifacts size' do
+ let(:metadata) { spy('metadata') }
+
+ before do
+ file = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip')
+ metafile = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip.meta')
+
+ build.update_attributes(artifacts_file: file)
+ build.update_attributes(artifacts_metadata: metafile)
+
+ allow(build).to receive(:artifacts_metadata_entry)
+ .and_return(metadata)
+ end
+
+ shared_examples 'pages size limit exceeded' do
+ it 'limits the maximum size of gitlab pages' do
+ subject.execute
+
+ expect(deploy_status.description)
+ .to match(/artifacts for pages are too large/)
+ end
+ end
+
+ context 'when maximum pages size is set to zero' do
+ before do
+ stub_application_setting(max_pages_size: 0)
+ end
+
+ context 'when page size does not exceed internal maximum' do
+ before do
+ allow(metadata).to receive(:total_size).and_return(200.megabytes)
+ end
+
+ it 'updates pages correctly' do
+ subject.execute
+
+ expect(deploy_status.description).not_to be_present
+ end
+ end
+
+ context 'when pages size does exceed internal maximum' do
+ before do
+ allow(metadata).to receive(:total_size).and_return(2.terabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+ end
+
+ context 'when pages size is greater than max size setting' do
+ before do
+ stub_application_setting(max_pages_size: 200)
+ allow(metadata).to receive(:total_size).and_return(201.megabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+
+ context 'when max size setting is greater than internal max size' do
+ before do
+ stub_application_setting(max_pages_size: 3.terabytes / 1.megabyte)
+ allow(metadata).to receive(:total_size).and_return(2.terabytes)
+ end
+
+ it_behaves_like 'pages size limit exceeded'
+ end
+ end
+
+ def deploy_status
+ GenericCommitStatus.find_by(name: 'pages:deploy')
+ end
+
def execute
subject.execute[:status]
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 05b18fef061..d945e0aa1f0 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -1,11 +1,14 @@
require 'spec_helper'
-describe Projects::UpdateService, services: true do
+describe Projects::UpdateService, '#execute' do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
- let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
- describe 'update_by_user' do
+ let(:project) do
+ create(:project, creator: user, namespace: user.namespace)
+ end
+
+ context 'when changing visibility level' do
context 'when visibility_level is INTERNAL' do
it 'updates the project to internal' do
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::INTERNAL)
@@ -40,7 +43,7 @@ describe Projects::UpdateService, services: true do
it 'does not update the project to public' do
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- expect(result).to eq({ status: :error, message: 'Visibility level unallowed' })
+ expect(result).to eq({ status: :error, message: 'New visibility level not allowed!' })
expect(project).to be_private
end
@@ -55,12 +58,13 @@ describe Projects::UpdateService, services: true do
end
end
- describe 'visibility_level' do
- let(:project) { create(:empty_project, :internal) }
+ describe 'when updating project that has forks' do
+ let(:project) { create(:project, :internal) }
let(:forked_project) { create(:forked_project_with_submodules, :internal) }
before do
- forked_project.build_forked_project_link(forked_to_project_id: forked_project.id, forked_from_project_id: project.id)
+ forked_project.build_forked_project_link(forked_to_project_id: forked_project.id,
+ forked_from_project_id: project.id)
forked_project.save
end
@@ -89,10 +93,45 @@ describe Projects::UpdateService, services: true do
end
end
- it 'returns an error result when record cannot be updated' do
- result = update_project(project, admin, { name: 'foo&bar' })
+ context 'when updating a default branch' do
+ let(:project) { create(:project, :repository) }
+
+ it 'changes a default branch' do
+ update_project(project, admin, default_branch: 'feature')
+
+ expect(Project.find(project.id).default_branch).to eq 'feature'
+ end
+ end
+
+ context 'when updating a project that contains container images' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags(repository: /image/, tags: %w[rc1])
+ create(:container_repository, project: project, name: :image)
+ end
+
+ it 'does not allow to rename the project' do
+ result = update_project(project, admin, path: 'renamed')
+
+ expect(result).to include(status: :error)
+ expect(result[:message]).to match(/contains container registry tags/)
+ end
+
+ it 'allows to update other settings' do
+ result = update_project(project, admin, public_builds: true)
+
+ expect(result[:status]).to eq :success
+ expect(project.reload.public_builds).to be true
+ end
+ end
+
+ context 'when passing invalid parameters' do
+ it 'returns an error result when record cannot be updated' do
+ result = update_project(project, admin, { name: 'foo&bar' })
- expect(result).to eq({ status: :error, message: 'Project could not be updated' })
+ expect(result).to eq({ status: :error,
+ message: 'Project could not be updated!' })
+ end
end
def update_project(project, user, opts)
diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb
index 6ea8f309981..835e83d6dba 100644
--- a/spec/services/protected_branches/create_service_spec.rb
+++ b/spec/services/protected_branches/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe ProtectedBranches::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe ProtectedBranches::CreateService do
+ let(:project) { create(:project) }
let(:user) { project.owner }
let(:params) do
{
diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb
index 62bdd49a4d7..5698101af54 100644
--- a/spec/services/protected_branches/update_service_spec.rb
+++ b/spec/services/protected_branches/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedBranches::UpdateService, services: true do
+describe ProtectedBranches::UpdateService do
let(:protected_branch) { create(:protected_branch) }
let(:project) { protected_branch.project }
let(:user) { project.owner }
diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb
index d91a58e8de5..c3ed95aaebf 100644
--- a/spec/services/protected_tags/create_service_spec.rb
+++ b/spec/services/protected_tags/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe ProtectedTags::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe ProtectedTags::CreateService do
+ let(:project) { create(:project) }
let(:user) { project.owner }
let(:params) do
{
diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb
index e78fde4c48d..d333430088d 100644
--- a/spec/services/protected_tags/update_service_spec.rb
+++ b/spec/services/protected_tags/update_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe ProtectedTags::UpdateService, services: true do
+describe ProtectedTags::UpdateService do
let(:protected_tag) { create(:protected_tag) }
let(:project) { protected_tag.project }
let(:user) { project.owner }
diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index e5e400ee281..b78ecfb61c4 100644
--- a/spec/services/slash_commands/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe SlashCommands::InterpretService, services: true do
- let(:project) { create(:empty_project, :public) }
+describe QuickActions::InterpretService do
+ let(:project) { create(:project, :public) }
let(:developer) { create(:user) }
let(:developer2) { create(:user) }
let(:issue) { create(:issue, project: project) }
@@ -9,13 +9,13 @@ describe SlashCommands::InterpretService, services: true do
let(:inprogress) { create(:label, project: project, title: 'In Progress') }
let(:bug) { create(:label, project: project, title: 'Bug') }
let(:note) { build(:note, commit_id: merge_request.diff_head_sha) }
+ let(:service) { described_class.new(project, developer) }
before do
project.team << [developer, :developer]
end
describe '#execute' do
- let(:service) { described_class.new(project, developer) }
let(:merge_request) { create(:merge_request, source_project: project) }
shared_examples 'reopen command' do
@@ -261,6 +261,31 @@ describe SlashCommands::InterpretService, services: true do
end
end
+ shared_examples 'duplicate command' do
+ it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do
+ issue_duplicate # populate the issue
+ _, updates = service.execute(content, issuable)
+
+ expect(updates).to eq(canonical_issue_id: issue_duplicate.id)
+ end
+ end
+
+ shared_examples 'shrug command' do
+ it 'appends ¯\_(ツ)_/¯ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::SHRUG)
+ end
+ end
+
+ shared_examples 'tableflip command' do
+ it 'appends (╯°□°)╯︵ ┻━┻ to the comment' do
+ new_content, _ = service.execute(content, issuable)
+
+ expect(new_content).to end_with(described_class::TABLEFLIP)
+ end
+ end
+
it_behaves_like 'reopen command' do
let(:content) { '/reopen' }
let(:issuable) { issue }
@@ -359,18 +384,18 @@ describe SlashCommands::InterpretService, services: true do
let(:content) { "/assign @#{developer.username}" }
context 'Issue' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, issue)
- expect(updates).to eq(assignee_ids: [developer.id])
+ expect(updates[:assignee_ids]).to match_array([developer.id])
end
end
context 'Merge Request' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: developer.id)
+ expect(updates).to eq(assignee_ids: [developer.id])
end
end
end
@@ -378,21 +403,23 @@ describe SlashCommands::InterpretService, services: true do
context 'assign command with multiple assignees' do
let(:content) { "/assign @#{developer.username} @#{developer2.username}" }
- before{ project.team << [developer2, :developer] }
+ before do
+ project.team << [developer2, :developer]
+ end
context 'Issue' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, issue)
- expect(updates[:assignee_ids]).to match_array([developer.id, developer2.id])
+ expect(updates[:assignee_ids]).to match_array([developer.id])
end
end
context 'Merge Request' do
- it 'fetches assignee and populates assignee_id if content contains /assign' do
+ it 'fetches assignee and populates assignee_ids if content contains /assign' do
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: developer.id)
+ expect(updates).to eq(assignee_ids: [developer.id])
end
end
end
@@ -420,11 +447,11 @@ describe SlashCommands::InterpretService, services: true do
end
context 'Merge Request' do
- it 'populates assignee_id: nil if content contains /unassign' do
- merge_request.update(assignee_id: developer.id)
+ it 'populates assignee_ids: [] if content contains /unassign' do
+ merge_request.update(assignee_ids: [developer.id])
_, updates = service.execute(content, merge_request)
- expect(updates).to eq(assignee_id: nil)
+ expect(updates).to eq(assignee_ids: [])
end
end
end
@@ -642,6 +669,41 @@ describe SlashCommands::InterpretService, services: true do
let(:issuable) { issue }
end
+ context '/duplicate command' do
+ it_behaves_like 'duplicate command' do
+ let(:issue_duplicate) { create(:issue, project: project) }
+ let(:content) { "/duplicate #{issue_duplicate.to_reference}" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:content) { '/duplicate' }
+ let(:issuable) { issue }
+ end
+
+ context 'cross project references' do
+ it_behaves_like 'duplicate command' do
+ let(:other_project) { create(:project, :public) }
+ let(:issue_duplicate) { create(:issue, project: other_project) }
+ let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:content) { "/duplicate imaginary#1234" }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'empty command' do
+ let(:other_project) { create(:project, :private) }
+ let(:issue_duplicate) { create(:issue, project: other_project) }
+
+ let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" }
+ let(:issuable) { issue }
+ end
+ end
+ end
+
context 'when current_user cannot :admin_issue' do
let(:visitor) { create(:user) }
let(:issue) { create(:issue, project: project, author: visitor) }
@@ -691,6 +753,11 @@ describe SlashCommands::InterpretService, services: true do
let(:content) { '/remove_due_date' }
let(:issuable) { issue }
end
+
+ it_behaves_like 'empty command' do
+ let(:content) { '/duplicate #{issue.to_reference}' }
+ let(:issuable) { issue }
+ end
end
context '/award command' do
@@ -724,6 +791,30 @@ describe SlashCommands::InterpretService, services: true do
end
end
+ context '/shrug command' do
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug people are people' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'shrug command' do
+ let(:content) { '/shrug' }
+ let(:issuable) { issue }
+ end
+ end
+
+ context '/tableflip command' do
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip curse your sudden but enviable betrayal' }
+ let(:issuable) { issue }
+ end
+
+ it_behaves_like 'tableflip command' do
+ let(:content) { '/tableflip' }
+ let(:issuable) { issue }
+ end
+ end
+
context '/target_branch command' do
let(:non_empty_project) { create(:project, :repository) }
let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) }
@@ -798,7 +889,11 @@ describe SlashCommands::InterpretService, services: true do
context 'if the project has multiple boards' do
let(:issuable) { issue }
- before { create(:board, project: project) }
+
+ before do
+ create(:board, project: project)
+ end
+
it_behaves_like 'empty command'
end
diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb
index 87192457298..bf79cfe74b7 100644
--- a/spec/services/repair_ldap_blocked_user_service_spec.rb
+++ b/spec/services/repair_ldap_blocked_user_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe RepairLdapBlockedUserService, services: true do
+describe RepairLdapBlockedUserService do
let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') }
let(:identity) { user.ldap_identity }
- subject(:service) { RepairLdapBlockedUserService.new(user) }
+ subject(:service) { described_class.new(user) }
describe '#execute' do
it 'changes to normal block after destroying last ldap identity' do
diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb
index 842585f9e54..2d7fa3f80f7 100644
--- a/spec/services/repository_archive_clean_up_service_spec.rb
+++ b/spec/services/repository_archive_clean_up_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe RepositoryArchiveCleanUpService, services: true do
+describe RepositoryArchiveCleanUpService do
describe '#execute' do
subject(:service) { described_class.new }
diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb
index cbf4f56213d..1309240b430 100644
--- a/spec/services/search/global_service_spec.rb
+++ b/spec/services/search/global_service_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Search::GlobalService, services: true do
+describe Search::GlobalService do
let(:user) { create(:user) }
let(:internal_user) { create(:user) }
- let!(:found_project) { create(:empty_project, :private, name: 'searchable_project') }
- let!(:unfound_project) { create(:empty_project, :private, name: 'unfound_project') }
- let!(:internal_project) { create(:empty_project, :internal, name: 'searchable_internal_project') }
- let!(:public_project) { create(:empty_project, :public, name: 'searchable_public_project') }
+ let!(:found_project) { create(:project, :private, name: 'searchable_project') }
+ let!(:unfound_project) { create(:project, :private, name: 'unfound_project') }
+ let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project') }
+ let!(:public_project) { create(:project, :public, name: 'searchable_public_project') }
before do
found_project.add_master(user)
@@ -16,7 +16,7 @@ describe Search::GlobalService, services: true do
describe '#execute' do
context 'unauthenticated' do
it 'returns public projects only' do
- results = Search::GlobalService.new(nil, search: "searchable").execute
+ results = described_class.new(nil, search: "searchable").execute
expect(results.objects('projects')).to match_array [public_project]
end
@@ -24,19 +24,19 @@ describe Search::GlobalService, services: true do
context 'authenticated' do
it 'returns public, internal and private projects' do
- results = Search::GlobalService.new(user, search: "searchable").execute
+ results = described_class.new(user, search: "searchable").execute
expect(results.objects('projects')).to match_array [public_project, found_project, internal_project]
end
it 'returns only public & internal projects' do
- results = Search::GlobalService.new(internal_user, search: "searchable").execute
+ results = described_class.new(internal_user, search: "searchable").execute
expect(results.objects('projects')).to match_array [internal_project, public_project]
end
it 'namespace name is searchable' do
- results = Search::GlobalService.new(user, search: found_project.namespace.path).execute
+ results = described_class.new(user, search: found_project.namespace.path).execute
expect(results.objects('projects')).to match_array [found_project]
end
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
index 38f264f6e7b..cbc553a60cf 100644
--- a/spec/services/search/group_service_spec.rb
+++ b/spec/services/search/group_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Search::GroupService, services: true do
+describe Search::GroupService do
shared_examples_for 'group search' do
context 'finding projects by name' do
let(:user) { create(:user) }
@@ -8,16 +8,16 @@ describe Search::GroupService, services: true do
let(:nested_group) { create(:group, :nested) }
# These projects shouldn't be found
- let!(:outside_project) { create(:empty_project, :public, name: "Outside #{term}") }
- let!(:private_project) { create(:empty_project, :private, namespace: nested_group, name: "Private #{term}" )}
- let!(:other_project) { create(:empty_project, :public, namespace: nested_group, name: term.reverse) }
+ let!(:outside_project) { create(:project, :public, name: "Outside #{term}") }
+ let!(:private_project) { create(:project, :private, namespace: nested_group, name: "Private #{term}" )}
+ let!(:other_project) { create(:project, :public, namespace: nested_group, name: term.reverse) }
# These projects should be found
- let!(:project1) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 1") }
- let!(:project2) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 2") }
- let!(:project3) { create(:empty_project, :internal, namespace: nested_group.parent, name: "Outer #{term}") }
+ let!(:project1) { create(:project, :internal, namespace: nested_group, name: "Inner #{term} 1") }
+ let!(:project2) { create(:project, :internal, namespace: nested_group, name: "Inner #{term} 2") }
+ let!(:project3) { create(:project, :internal, namespace: nested_group.parent, name: "Outer #{term}") }
- let(:results) { Search::GroupService.new(user, search_group, search: term).execute }
+ let(:results) { described_class.new(user, search_group, search: term).execute }
subject { results.objects('projects') }
context 'in parent group' do
diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb
index 14f3301d9f4..eae9bd4f5cf 100644
--- a/spec/services/search/snippet_service_spec.rb
+++ b/spec/services/search/snippet_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe Search::SnippetService, services: true do
+describe Search::SnippetService do
let(:author) { create(:author) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let!(:public_snippet) { create(:snippet, :public, content: 'password: XXX') }
let!(:internal_snippet) { create(:snippet, :internal, content: 'password: XXX') }
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 5cf989105d0..02de83a2df8 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -1,19 +1,19 @@
require 'spec_helper'
-describe SearchService, services: true do
+describe SearchService do
let(:user) { create(:user) }
let(:accessible_group) { create(:group, :private) }
let(:inaccessible_group) { create(:group, :private) }
let!(:group_member) { create(:group_member, group: accessible_group, user: user) }
- let!(:accessible_project) { create(:empty_project, :private, name: 'accessible_project') }
- let!(:inaccessible_project) { create(:empty_project, :private, name: 'inaccessible_project') }
+ let!(:accessible_project) { create(:project, :private, name: 'accessible_project') }
+ let!(:inaccessible_project) { create(:project, :private, name: 'inaccessible_project') }
let(:note) { create(:note_on_issue, project: accessible_project) }
let(:snippet) { create(:snippet, author: user) }
- let(:group_project) { create(:empty_project, group: accessible_group, name: 'group_project') }
- let(:public_project) { create(:empty_project, :public, name: 'public_project') }
+ let(:group_project) { create(:project, group: accessible_group, name: 'group_project') }
+ let(:public_project) { create(:project, :public, name: 'public_project') }
before do
accessible_project.add_master(user)
@@ -22,16 +22,16 @@ describe SearchService, services: true do
describe '#project' do
context 'when the project is accessible' do
it 'returns the project' do
- project = SearchService.new(user, project_id: accessible_project.id).project
+ project = described_class.new(user, project_id: accessible_project.id).project
expect(project).to eq accessible_project
end
it 'returns the project for guests' do
- search_project = create :empty_project
+ search_project = create :project
search_project.add_guest(user)
- project = SearchService.new(user, project_id: search_project.id).project
+ project = described_class.new(user, project_id: search_project.id).project
expect(project).to eq search_project
end
@@ -39,7 +39,7 @@ describe SearchService, services: true do
context 'when the project is not accessible' do
it 'returns nil' do
- project = SearchService.new(user, project_id: inaccessible_project.id).project
+ project = described_class.new(user, project_id: inaccessible_project.id).project
expect(project).to be_nil
end
@@ -47,7 +47,7 @@ describe SearchService, services: true do
context 'when there is no project_id' do
it 'returns nil' do
- project = SearchService.new(user).project
+ project = described_class.new(user).project
expect(project).to be_nil
end
@@ -57,7 +57,7 @@ describe SearchService, services: true do
describe '#group' do
context 'when the group is accessible' do
it 'returns the group' do
- group = SearchService.new(user, group_id: accessible_group.id).group
+ group = described_class.new(user, group_id: accessible_group.id).group
expect(group).to eq accessible_group
end
@@ -65,7 +65,7 @@ describe SearchService, services: true do
context 'when the group is not accessible' do
it 'returns nil' do
- group = SearchService.new(user, group_id: inaccessible_group.id).group
+ group = described_class.new(user, group_id: inaccessible_group.id).group
expect(group).to be_nil
end
@@ -73,7 +73,7 @@ describe SearchService, services: true do
context 'when there is no group_id' do
it 'returns nil' do
- group = SearchService.new(user).group
+ group = described_class.new(user).group
expect(group).to be_nil
end
@@ -83,7 +83,7 @@ describe SearchService, services: true do
describe '#show_snippets?' do
context 'when :snippets is \'true\'' do
it 'returns true' do
- show_snippets = SearchService.new(user, snippets: 'true').show_snippets?
+ show_snippets = described_class.new(user, snippets: 'true').show_snippets?
expect(show_snippets).to be_truthy
end
@@ -91,7 +91,7 @@ describe SearchService, services: true do
context 'when :snippets is not \'true\'' do
it 'returns false' do
- show_snippets = SearchService.new(user, snippets: 'tru').show_snippets?
+ show_snippets = described_class.new(user, snippets: 'tru').show_snippets?
expect(show_snippets).to be_falsey
end
@@ -99,7 +99,7 @@ describe SearchService, services: true do
context 'when :snippets is missing' do
it 'returns false' do
- show_snippets = SearchService.new(user).show_snippets?
+ show_snippets = described_class.new(user).show_snippets?
expect(show_snippets).to be_falsey
end
@@ -110,7 +110,7 @@ describe SearchService, services: true do
context 'with accessible project_id' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, project_id: accessible_project.id, scope: 'notes').scope
+ scope = described_class.new(user, project_id: accessible_project.id, scope: 'notes').scope
expect(scope).to eq 'notes'
end
@@ -118,7 +118,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, project_id: accessible_project.id, scope: 'projects').scope
+ scope = described_class.new(user, project_id: accessible_project.id, scope: 'projects').scope
expect(scope).to eq 'blobs'
end
@@ -126,7 +126,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, project_id: accessible_project.id).scope
+ scope = described_class.new(user, project_id: accessible_project.id).scope
expect(scope).to eq 'blobs'
end
@@ -136,7 +136,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, snippets: 'true', scope: 'snippet_titles').scope
+ scope = described_class.new(user, snippets: 'true', scope: 'snippet_titles').scope
expect(scope).to eq 'snippet_titles'
end
@@ -144,7 +144,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, snippets: 'true', scope: 'projects').scope
+ scope = described_class.new(user, snippets: 'true', scope: 'projects').scope
expect(scope).to eq 'snippet_blobs'
end
@@ -152,7 +152,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, snippets: 'true').scope
+ scope = described_class.new(user, snippets: 'true').scope
expect(scope).to eq 'snippet_blobs'
end
@@ -162,7 +162,7 @@ describe SearchService, services: true do
context 'with no project_id, no snippets' do
context 'and allowed scope' do
it 'returns the specified scope' do
- scope = SearchService.new(user, scope: 'issues').scope
+ scope = described_class.new(user, scope: 'issues').scope
expect(scope).to eq 'issues'
end
@@ -170,7 +170,7 @@ describe SearchService, services: true do
context 'and disallowed scope' do
it 'returns the default scope' do
- scope = SearchService.new(user, scope: 'blobs').scope
+ scope = described_class.new(user, scope: 'blobs').scope
expect(scope).to eq 'projects'
end
@@ -178,7 +178,7 @@ describe SearchService, services: true do
context 'and no scope' do
it 'returns the default scope' do
- scope = SearchService.new(user).scope
+ scope = described_class.new(user).scope
expect(scope).to eq 'projects'
end
@@ -189,7 +189,7 @@ describe SearchService, services: true do
describe '#search_results' do
context 'with accessible project_id' do
it 'returns an instance of Gitlab::ProjectSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
project_id: accessible_project.id,
scope: 'notes',
@@ -201,7 +201,7 @@ describe SearchService, services: true do
context 'with accessible project_id and \'true\' snippets' do
it 'returns an instance of Gitlab::ProjectSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
project_id: accessible_project.id,
snippets: 'true',
@@ -214,7 +214,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
it 'returns an instance of Gitlab::SnippetSearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
snippets: 'true',
search: snippet.content).search_results
@@ -225,7 +225,7 @@ describe SearchService, services: true do
context 'with no project_id and no snippets' do
it 'returns an instance of Gitlab::SearchResults' do
- search_results = SearchService.new(
+ search_results = described_class.new(
user,
search: public_project.name).search_results
@@ -237,7 +237,7 @@ describe SearchService, services: true do
describe '#search_objects' do
context 'with accessible project_id' do
it 'returns objects in the project' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
project_id: accessible_project.id,
scope: 'notes',
@@ -249,7 +249,7 @@ describe SearchService, services: true do
context 'with accessible project_id and \'true\' snippets' do
it 'returns objects in the project' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
project_id: accessible_project.id,
snippets: 'true',
@@ -262,7 +262,7 @@ describe SearchService, services: true do
context 'with \'true\' snippets' do
it 'returns objects in snippets' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
snippets: 'true',
search: snippet.content).search_objects
@@ -273,7 +273,7 @@ describe SearchService, services: true do
context 'with accessible group_id' do
it 'returns objects in the group' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
group_id: accessible_group.id,
search: group_project.name).search_objects
@@ -284,7 +284,7 @@ describe SearchService, services: true do
context 'with no project_id, group_id or snippets' do
it 'returns objects in global' do
- search_objects = SearchService.new(
+ search_objects = described_class.new(
user,
search: public_project.name).search_objects
diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb
index 74cba8c014b..a14dfa3f01f 100644
--- a/spec/services/spam_service_spec.rb
+++ b/spec/services/spam_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe SpamService, services: true do
+describe SpamService do
describe '#when_recaptcha_verified' do
def check_spam(issue, request, recaptcha_verified)
described_class.new(issue, request).when_recaptcha_verified(recaptcha_verified) do
@@ -15,7 +15,7 @@ describe SpamService, services: true do
end
context 'when recaptcha was not verified' do
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) }
let(:request) { double(:request, env: {}) }
@@ -70,7 +70,9 @@ describe SpamService, services: true do
end
context 'when not indicated as spam by akismet' do
- before { allow(AkismetService).to receive(:new).and_return(double(is_spam?: false)) }
+ before do
+ allow(AkismetService).to receive(:new).and_return(double(is_spam?: false))
+ end
it 'returns false' do
expect(check_spam(issue, request, false)).to be_falsey
diff --git a/spec/services/submit_usage_ping_service_spec.rb b/spec/services/submit_usage_ping_service_spec.rb
index 63a1e78f274..817fa4262d5 100644
--- a/spec/services/submit_usage_ping_service_spec.rb
+++ b/spec/services/submit_usage_ping_service_spec.rb
@@ -92,8 +92,8 @@ describe SubmitUsagePingService do
end
def stub_response(body)
- stub_request(:post, 'https://version.gitlab.com/usage_data').
- to_return(
+ stub_request(:post, 'https://version.gitlab.com/usage_data')
+ .to_return(
headers: { 'Content-Type' => 'application/json' },
body: body.to_json
)
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 667059f230c..8b5d9187785 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
-describe SystemHooksService, services: true do
+describe SystemHooksService do
let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:project_member) { create(:project_member) }
let(:key) { create(:key, user: user) }
let(:deploy_key) { create(:key) }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index c499b1bb343..e3805160b04 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
-describe SystemNoteService, services: true do
- include Gitlab::Routing.url_helpers
+describe SystemNoteService do
+ include Gitlab::Routing
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:author) { create(:user) }
let(:noteable) { create(:issue, project: project) }
let(:issue) { noteable }
@@ -333,8 +333,8 @@ describe SystemNoteService, services: true do
end
it 'sets the note text' do
- expect(subject.note).
- to eq "changed title from **{-Old title-}** to **{+Lorem ipsum+}**"
+ expect(subject.note)
+ .to eq "changed title from **{-Old title-}** to **{+Lorem ipsum+}**"
end
end
end
@@ -521,8 +521,8 @@ describe SystemNoteService, services: true do
context 'when mentioner is not a MergeRequest' do
it 'is falsey' do
mentioner = noteable.dup
- expect(described_class.cross_reference_disallowed?(noteable, mentioner)).
- to be_falsey
+ expect(described_class.cross_reference_disallowed?(noteable, mentioner))
+ .to be_falsey
end
end
@@ -533,14 +533,14 @@ describe SystemNoteService, services: true do
it 'is truthy when noteable is in commits' do
expect(mentioner).to receive(:commits).and_return([noteable])
- expect(described_class.cross_reference_disallowed?(noteable, mentioner)).
- to be_truthy
+ expect(described_class.cross_reference_disallowed?(noteable, mentioner))
+ .to be_truthy
end
it 'is falsey when noteable is not in commits' do
expect(mentioner).to receive(:commits).and_return([])
- expect(described_class.cross_reference_disallowed?(noteable, mentioner)).
- to be_falsey
+ expect(described_class.cross_reference_disallowed?(noteable, mentioner))
+ .to be_falsey
end
end
@@ -548,8 +548,8 @@ describe SystemNoteService, services: true do
let(:noteable) { ExternalIssue.new('EXT-1234', project) }
it 'is truthy' do
mentioner = noteable.dup
- expect(described_class.cross_reference_disallowed?(noteable, mentioner)).
- to be_truthy
+ expect(described_class.cross_reference_disallowed?(noteable, mentioner))
+ .to be_truthy
end
end
end
@@ -566,13 +566,13 @@ describe SystemNoteService, services: true do
end
it 'is truthy when already mentioned' do
- expect(described_class.cross_reference_exists?(noteable, commit0)).
- to be_truthy
+ expect(described_class.cross_reference_exists?(noteable, commit0))
+ .to be_truthy
end
it 'is falsey when not already mentioned' do
- expect(described_class.cross_reference_exists?(noteable, commit1)).
- to be_falsey
+ expect(described_class.cross_reference_exists?(noteable, commit1))
+ .to be_falsey
end
context 'legacy capitalized cross reference' do
@@ -583,8 +583,8 @@ describe SystemNoteService, services: true do
end
it 'is truthy when already mentioned' do
- expect(described_class.cross_reference_exists?(noteable, commit0)).
- to be_truthy
+ expect(described_class.cross_reference_exists?(noteable, commit0))
+ .to be_truthy
end
end
end
@@ -596,13 +596,13 @@ describe SystemNoteService, services: true do
end
it 'is truthy when already mentioned' do
- expect(described_class.cross_reference_exists?(commit0, commit1)).
- to be_truthy
+ expect(described_class.cross_reference_exists?(commit0, commit1))
+ .to be_truthy
end
it 'is falsey when not already mentioned' do
- expect(described_class.cross_reference_exists?(commit1, commit0)).
- to be_falsey
+ expect(described_class.cross_reference_exists?(commit1, commit0))
+ .to be_falsey
end
context 'legacy capitalized cross reference' do
@@ -613,8 +613,8 @@ describe SystemNoteService, services: true do
end
it 'is truthy when already mentioned' do
- expect(described_class.cross_reference_exists?(commit0, commit1)).
- to be_truthy
+ expect(described_class.cross_reference_exists?(commit0, commit1))
+ .to be_truthy
end
end
end
@@ -629,8 +629,8 @@ describe SystemNoteService, services: true do
end
it 'is true when a fork mentions an external issue' do
- expect(described_class.cross_reference_exists?(noteable, commit2)).
- to be true
+ expect(described_class.cross_reference_exists?(noteable, commit2))
+ .to be true
end
context 'legacy capitalized cross reference' do
@@ -640,15 +640,15 @@ describe SystemNoteService, services: true do
end
it 'is true when a fork mentions an external issue' do
- expect(described_class.cross_reference_exists?(noteable, commit2)).
- to be true
+ expect(described_class.cross_reference_exists?(noteable, commit2))
+ .to be true
end
end
end
end
describe '.noteable_moved' do
- let(:new_project) { create(:empty_project) }
+ let(:new_project) { create(:project) }
let(:new_noteable) { create(:issue, project: new_project) }
subject do
@@ -667,7 +667,7 @@ describe SystemNoteService, services: true do
end
it 'mentions referenced project' do
- expect(subject.note).to include new_project.path_with_namespace
+ expect(subject.note).to include new_project.full_path
end
end
@@ -718,7 +718,7 @@ describe SystemNoteService, services: true do
describe 'JIRA integration' do
include JiraServiceHelper
- let(:project) { create(:jira_project) }
+ let(:project) { create(:jira_project, :repository) }
let(:author) { create(:user) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, :simple, target_project: project, source_project: project) }
@@ -807,7 +807,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_commit_url(project.namespace, project, commit),
+ url: project_commit_url(project, commit),
title: "GitLab: Mentioned on commit - #{commit.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -833,7 +833,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_issue_url(project.namespace, project, issue),
+ url: project_issue_url(project, issue),
title: "GitLab: Mentioned on issue - #{issue.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -859,7 +859,7 @@ describe SystemNoteService, services: true do
body: hash_including(
GlobalID: "GitLab",
object: {
- url: namespace_project_snippet_url(project.namespace, project, snippet),
+ url: project_snippet_url(project, snippet),
title: "GitLab: Mentioned on snippet - #{snippet.title}",
icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
status: { resolved: false }
@@ -873,7 +873,7 @@ describe SystemNoteService, services: true do
describe "existing reference" do
before do
allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
- message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
+ message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.full_path}/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)])
end
@@ -1052,7 +1052,7 @@ describe SystemNoteService, services: true do
let(:action) { 'task' }
end
- it "posts the 'marked as a Work In Progress from commit' system note" do
+ it "posts the 'marked the task as complete' system note" do
expect(subject.note).to eq("marked the task **task** as completed")
end
end
@@ -1098,7 +1098,57 @@ describe SystemNoteService, services: true do
diff_id = merge_request.merge_request_diff.id
line_code = change_position.line_code(project.repository)
- expect(subject.note).to include(diffs_namespace_project_merge_request_url(project.namespace, project, merge_request, diff_id: diff_id, anchor: line_code))
+ expect(subject.note).to include(diffs_project_merge_request_url(project, merge_request, diff_id: diff_id, anchor: line_code))
+ end
+ end
+
+ describe '.mark_duplicate_issue' do
+ subject { described_class.mark_duplicate_issue(noteable, project, author, canonical_issue) }
+
+ context 'within the same project' do
+ let(:canonical_issue) { create(:issue, project: project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference}" }
+ end
+
+ context 'across different projects' do
+ let(:other_project) { create(:project) }
+ let(:canonical_issue) { create(:issue, project: other_project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}" }
+ end
+ end
+
+ describe '.mark_canonical_issue_of_duplicate' do
+ subject { described_class.mark_canonical_issue_of_duplicate(noteable, project, author, duplicate_issue) }
+
+ context 'within the same project' do
+ let(:duplicate_issue) { create(:issue, project: project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference} as a duplicate of this issue" }
+ end
+
+ context 'across different projects' do
+ let(:other_project) { create(:project) }
+ let(:duplicate_issue) { create(:issue, project: other_project) }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'duplicate' }
+ end
+
+ it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference(project)} as a duplicate of this issue" }
end
end
end
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index b9121b1de49..1b31ce29f7a 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Tags::CreateService, services: true do
+describe Tags::CreateService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
@@ -26,9 +26,9 @@ describe Tags::CreateService, services: true do
context 'when tag already exists' do
it 'returns an error' do
- expect(repository).to receive(:add_tag).
- with(user, 'v1.1.0', 'master', 'Foo').
- and_raise(Rugged::TagError)
+ expect(repository).to receive(:add_tag)
+ .with(user, 'v1.1.0', 'master', 'Foo')
+ .and_raise(Rugged::TagError)
response = service.execute('v1.1.0', 'master', 'Foo')
@@ -39,9 +39,9 @@ describe Tags::CreateService, services: true do
context 'when pre-receive hook fails' do
it 'returns an error' do
- expect(repository).to receive(:add_tag).
- with(user, 'v1.1.0', 'master', 'Foo').
- and_raise(GitHooksService::PreReceiveError, 'something went wrong')
+ expect(repository).to receive(:add_tag)
+ .with(user, 'v1.1.0', 'master', 'Foo')
+ .and_raise(GitHooksService::PreReceiveError, 'something went wrong')
response = service.execute('v1.1.0', 'master', 'Foo')
diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb
index 28396fc3658..7c8c1dd0d3a 100644
--- a/spec/services/tags/destroy_service_spec.rb
+++ b/spec/services/tags/destroy_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Tags::DestroyService, services: true do
+describe Tags::DestroyService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb
deleted file mode 100644
index f99fd8434c2..00000000000
--- a/spec/services/test_hook_service_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require 'spec_helper'
-
-describe TestHookService, services: true do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:hook) { create(:project_hook, project: project) }
-
- describe '#execute' do
- it "executes successfully" do
- stub_request(:post, hook.url).to_return(status: 200)
- expect(TestHookService.new.execute(hook, user)).to be_truthy
- end
- end
-end
diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb
new file mode 100644
index 00000000000..4218c15a3ce
--- /dev/null
+++ b/spec/services/test_hooks/project_service_spec.rb
@@ -0,0 +1,188 @@
+require 'spec_helper'
+
+describe TestHooks::ProjectService do
+ let(:current_user) { create(:user) }
+
+ describe '#execute' do
+ let(:project) { create(:project, :repository) }
+ let(:hook) { create(:project_hook, project: project) }
+ let(:service) { described_class.new(hook, current_user, trigger) }
+ let(:sample_data) { { data: 'sample' } }
+ let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }
+
+ context 'hook with not implemented test' do
+ let(:trigger) { 'not_implemented_events' }
+
+ it 'returns error message' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' })
+ end
+ end
+
+ context 'push_events' do
+ let(:trigger) { 'push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has at least one commit.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'tag_push_events' do
+ let(:trigger) { 'tag_push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has at least one commit.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'note_events' do
+ let(:trigger) { 'note_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has notes.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:notes).and_return([Note.new])
+ allow(Gitlab::DataBuilder::Note).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'issues_events' do
+ let(:trigger) { 'issues_events' }
+ let(:issue) { build(:issue) }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has issues.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:issues).and_return([issue])
+ allow(issue).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'confidential_issues_events' do
+ let(:trigger) { 'confidential_issues_events' }
+ let(:issue) { build(:issue) }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has issues.' })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:issues).and_return([issue])
+ allow(issue).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'merge_requests_events' do
+ let(:trigger) { 'merge_requests_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has merge requests.' })
+ end
+
+ it 'executes hook' do
+ create(:merge_request, source_project: project)
+ allow_any_instance_of(MergeRequest).to receive(:to_hook_data).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'job_events' do
+ let(:trigger) { 'job_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has CI jobs.' })
+ end
+
+ it 'executes hook' do
+ create(:ci_build, project: project)
+ allow(Gitlab::DataBuilder::Build).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'pipeline_events' do
+ let(:trigger) { 'pipeline_events' }
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the project has CI pipelines.' })
+ end
+
+ it 'executes hook' do
+ create(:ci_empty_pipeline, project: project)
+ allow(Gitlab::DataBuilder::Pipeline).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'wiki_page_events' do
+ let(:trigger) { 'wiki_page_events' }
+
+ it 'returns error message if wiki disabled' do
+ allow(project).to receive(:wiki_enabled?).and_return(false)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
+ end
+
+ it 'returns error message if not enough data' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Ensure the wiki is enabled and has pages.' })
+ end
+
+ it 'executes hook' do
+ create(:wiki_page, wiki: project.wiki)
+ allow(Gitlab::DataBuilder::WikiPage).to receive(:build).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+ end
+end
diff --git a/spec/services/test_hooks/system_service_spec.rb b/spec/services/test_hooks/system_service_spec.rb
new file mode 100644
index 00000000000..00d89924766
--- /dev/null
+++ b/spec/services/test_hooks/system_service_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe TestHooks::SystemService do
+ let(:current_user) { create(:user) }
+
+ describe '#execute' do
+ let(:project) { create(:project, :repository) }
+ let(:hook) { create(:system_hook) }
+ let(:service) { described_class.new(hook, current_user, trigger) }
+ let(:sample_data) { { data: 'sample' }}
+ let(:success_result) { { status: :success, http_status: 200, message: 'ok' } }
+
+ before do
+ allow(Project).to receive(:first).and_return(project)
+ end
+
+ context 'hook with not implemented test' do
+ let(:trigger) { 'not_implemented_events' }
+
+ it 'returns error message' do
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' })
+ end
+ end
+
+ context 'push_events' do
+ let(:trigger) { 'push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:empty_repo?).and_return(true)
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has commits." })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'tag_push_events' do
+ let(:trigger) { 'tag_push_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project.repository).to receive(:tags).and_return([])
+
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has tags." })
+ end
+
+ it 'executes hook' do
+ allow(project.repository).to receive(:tags).and_return(['tag'])
+ allow(Gitlab::DataBuilder::Push).to receive(:build_sample).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+
+ context 'repository_update_events' do
+ let(:trigger) { 'repository_update_events' }
+
+ it 'returns error message if not enough data' do
+ allow(project).to receive(:commit).and_return(nil)
+ expect(hook).not_to receive(:execute)
+ expect(service.execute).to include({ status: :error, message: "Ensure project \"#{project.human_name}\" has commits." })
+ end
+
+ it 'executes hook' do
+ allow(project).to receive(:empty_repo?).and_return(false)
+ allow(Gitlab::DataBuilder::Repository).to receive(:update).and_return(sample_data)
+
+ expect(hook).to receive(:execute).with(sample_data, trigger).and_return(success_result)
+ expect(service.execute).to include(success_result)
+ end
+ end
+ end
+end
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 175a42a32d9..534d3e65be2 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe TodoService, services: true do
+describe TodoService do
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:non_member) { create(:user) }
@@ -10,7 +10,7 @@ describe TodoService, services: true do
let(:john_doe) { create(:user) }
let(:skipped) { create(:user) }
let(:skip_users) { [skipped] }
- let(:project) { create(:empty_project) }
+ let(:project) { create(:project) }
let(:mentions) { 'FYI: ' + [author, assignee, john_doe, member, guest, non_member, admin, skipped].map(&:to_reference).join(' ') }
let(:directly_addressed) { [author, assignee, john_doe, member, guest, non_member, admin, skipped].map(&:to_reference).join(' ') }
let(:directly_addressed_and_mentioned) { member.to_reference + ", what do you think? cc: " + [guest, admin, skipped].map(&:to_reference).join(' ') }
@@ -103,7 +103,7 @@ describe TodoService, services: true do
context 'when a private group is mentioned' do
let(:group) { create(:group, :private) }
- let(:project) { create(:empty_project, :private, group: group) }
+ let(:project) { create(:project, :private, group: group) }
let(:issue) { create(:issue, author: author, project: project, description: group.to_reference) }
before do
@@ -873,21 +873,21 @@ describe TodoService, services: true do
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
todos = TodosFinder.new(john_doe, {}).execute
- expect { TodoService.new.mark_todos_as_done(todos, john_doe) }
+ expect { described_class.new.mark_todos_as_done(todos, john_doe) }
.to change { john_doe.todos.done.count }.from(0).to(1)
end
it 'marks an array of todos as done' do
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- expect { TodoService.new.mark_todos_as_done([todo], john_doe) }
+ expect { described_class.new.mark_todos_as_done([todo], john_doe) }
.to change { todo.reload.state }.from('pending').to('done')
end
it 'returns the ids of updated todos' do # Needed on API
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id])
+ expect(described_class.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id])
end
context 'when some of the todos are done already' do
@@ -895,23 +895,23 @@ describe TodoService, services: true do
let!(:second_todo) { create(:todo, :mentioned, user: john_doe, target: another_issue, project: project) }
it 'returns the ids of those still pending' do
- TodoService.new.mark_pending_todos_as_done(issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(issue, john_doe)
- expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id])
+ expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id])
end
it 'returns an empty array if all are done' do
- TodoService.new.mark_pending_todos_as_done(issue, john_doe)
- TodoService.new.mark_pending_todos_as_done(another_issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(issue, john_doe)
+ described_class.new.mark_pending_todos_as_done(another_issue, john_doe)
- expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([])
+ expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([])
end
end
- it 'caches the number of todos of a user', :caching do
+ it 'caches the number of todos of a user', :use_clean_rails_memory_store_caching do
create(:todo, :mentioned, user: john_doe, target: issue, project: project)
todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project)
- TodoService.new.mark_todos_as_done([todo], john_doe)
+ described_class.new.mark_todos_as_done([todo], john_doe)
expect_any_instance_of(TodosFinder).not_to receive(:execute)
diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb
index 69ed8de9c31..dc2d0e2d47a 100644
--- a/spec/services/update_release_service_spec.rb
+++ b/spec/services/update_release_service_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-describe UpdateReleaseService, services: true do
+describe UpdateReleaseService do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:tag_name) { project.repository.tag_names.first }
let(:description) { 'Awesome release!' }
let(:new_description) { 'The best release!' }
- let(:service) { UpdateReleaseService.new(project, user) }
+ let(:service) { described_class.new(project, user) }
context 'with an existing release' do
let(:create_service) { CreateReleaseService.new(project, user) }
diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb
index 37c2e861362..ef535c5cf1f 100644
--- a/spec/services/update_snippet_service_spec.rb
+++ b/spec/services/update_snippet_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe UpdateSnippetService, services: true do
+describe UpdateSnippetService do
before do
@user = create :user
@admin = create :user, admin: true
diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb
index 95ba28dbecd..24f3a5c5ff0 100644
--- a/spec/services/upload_service_spec.rb
+++ b/spec/services/upload_service_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
-describe UploadService, services: true do
+describe UploadService do
describe 'File service' do
before do
@user = create(:user)
- @project = create(:empty_project, creator_id: @user.id, namespace: @user.namespace)
+ @project = create(:project, creator_id: @user.id, namespace: @user.namespace)
end
context 'for valid gif file' do
diff --git a/spec/services/user_project_access_changed_service_spec.rb b/spec/services/user_project_access_changed_service_spec.rb
index b4efe7de431..14a5e40350a 100644
--- a/spec/services/user_project_access_changed_service_spec.rb
+++ b/spec/services/user_project_access_changed_service_spec.rb
@@ -3,8 +3,8 @@ require 'spec_helper'
describe UserProjectAccessChangedService do
describe '#execute' do
it 'schedules the user IDs' do
- expect(AuthorizedProjectsWorker).to receive(:bulk_perform_and_wait).
- with([[1], [2]])
+ expect(AuthorizedProjectsWorker).to receive(:bulk_perform_and_wait)
+ .with([[1], [2]])
described_class.new([1, 2]).execute
end
diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb
index 8d67ebe3231..fef4da0c76e 100644
--- a/spec/services/users/activity_service_spec.rb
+++ b/spec/services/users/activity_service_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
-describe Users::ActivityService, services: true do
+describe Users::ActivityService do
include UserActivitiesHelpers
let(:user) { create(:user) }
subject(:service) { described_class.new(user, 'type') }
- describe '#execute', :redis do
+ describe '#execute', :clean_gitlab_redis_shared_state do
context 'when last activity is nil' do
before do
service.execute
@@ -41,8 +41,8 @@ describe Users::ActivityService, services: true do
end
def last_hour_user_ids
- Gitlab::UserActivities.new.
- select { |k, v| v >= 1.hour.ago.to_i.to_s }.
- map { |k, _| k.to_i }
+ Gitlab::UserActivities.new
+ .select { |k, v| v >= 1.hour.ago.to_i.to_s }
+ .map { |k, _| k.to_i }
end
end
diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb
index 2a6bfc1b3a0..677d4a622e1 100644
--- a/spec/services/users/build_service_spec.rb
+++ b/spec/services/users/build_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Users::BuildService, services: true do
+describe Users::BuildService do
describe '#execute' do
let(:params) do
{ name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' }
diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb
index 75746278573..24dac569678 100644
--- a/spec/services/users/create_service_spec.rb
+++ b/spec/services/users/create_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Users::CreateService, services: true do
+describe Users::CreateService do
describe '#execute' do
let(:admin_user) { create(:admin) }
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index 5409f67c091..a82567f6f43 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
-describe Users::DestroyService, services: true do
+describe Users::DestroyService do
describe "Deletes a user and all their personal projects" do
let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
let!(:namespace) { create(:namespace, owner: user) }
- let!(:project) { create(:empty_project, namespace: namespace) }
+ let!(:project) { create(:project, namespace: namespace) }
let(:service) { described_class.new(admin) }
context 'no options are given' do
@@ -66,7 +66,7 @@ describe Users::DestroyService, services: true do
end
context "a deleted user's merge_requests" do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
project.add_developer(user)
diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb
index 9e1edf1ac30..ac3a8738cac 100644
--- a/spec/services/users/migrate_to_ghost_user_service_spec.rb
+++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb
@@ -1,22 +1,38 @@
require 'spec_helper'
-describe Users::MigrateToGhostUserService, services: true do
+describe Users::MigrateToGhostUserService do
let!(:user) { create(:user) }
- let!(:project) { create(:project) }
+ let!(:project) { create(:project, :repository) }
let(:service) { described_class.new(user) }
context "migrating a user's associated records to the ghost user" do
context 'issues' do
- include_examples "migrating a deleted user's associated records to the ghost user", Issue do
- let(:created_record) { create(:issue, project: project, author: user) }
- let(:assigned_record) { create(:issue, project: project, assignee: user) }
+ context 'deleted user is present as both author and edited_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:author, :last_edited_by] do
+ let(:created_record) do
+ create(:issue, project: project, author: user, last_edited_by: user)
+ end
+ end
+ end
+
+ context 'deleted user is present only as edited_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:last_edited_by] do
+ let(:created_record) { create(:issue, project: project, author: create(:user), last_edited_by: user) }
+ end
end
end
context 'merge requests' do
- include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest do
- let(:created_record) { create(:merge_request, source_project: project, author: user, target_branch: "first") }
- let(:assigned_record) { create(:merge_request, source_project: project, assignee: user, target_branch: 'second') }
+ context 'deleted user is present as both author and merge_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:author, :merge_user] do
+ let(:created_record) { create(:merge_request, source_project: project, author: user, merge_user: user, target_branch: "first") }
+ end
+ end
+
+ context 'deleted user is present only as both merge_user' do
+ include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:merge_user] do
+ let(:created_record) { create(:merge_request, source_project: project, merge_user: user, target_branch: "first") }
+ end
end
end
@@ -33,9 +49,8 @@ describe Users::MigrateToGhostUserService, services: true do
end
context 'award emoji' do
- include_examples "migrating a deleted user's associated records to the ghost user", AwardEmoji do
+ include_examples "migrating a deleted user's associated records to the ghost user", AwardEmoji, [:user] do
let(:created_record) { create(:award_emoji, user: user) }
- let(:author_alias) { :user }
context "when the awardable already has an award emoji of the same name assigned to the ghost user" do
let(:awardable) { create(:issue) }
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index 8c40d25e00c..08fd26d67fd 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -3,18 +3,18 @@ require 'spec_helper'
describe Users::RefreshAuthorizedProjectsService do
# We're using let! here so that any expectations for the service class are not
# triggered twice.
- let!(:project) { create(:empty_project) }
+ let!(:project) { create(:project) }
let(:user) { project.namespace.owner }
let(:service) { described_class.new(user) }
- describe '#execute', :redis do
+ describe '#execute', :clean_gitlab_redis_shared_state do
it 'refreshes the authorizations using a lease' do
- expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).
- and_return('foo')
+ expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain)
+ .and_return('foo')
- expect(Gitlab::ExclusiveLease).to receive(:cancel).
- with(an_instance_of(String), 'foo')
+ expect(Gitlab::ExclusiveLease).to receive(:cancel)
+ .with(an_instance_of(String), 'foo')
expect(service).to receive(:execute_without_lease)
@@ -28,12 +28,12 @@ describe Users::RefreshAuthorizedProjectsService do
end
it 'updates the authorized projects of the user' do
- project2 = create(:empty_project)
- to_remove = user.project_authorizations.
- create!(project: project2, access_level: Gitlab::Access::MASTER)
+ project2 = create(:project)
+ to_remove = user.project_authorizations
+ .create!(project: project2, access_level: Gitlab::Access::MASTER)
- expect(service).to receive(:update_authorizations).
- with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]])
+ expect(service).to receive(:update_authorizations)
+ .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]])
service.execute_without_lease
end
@@ -41,11 +41,11 @@ describe Users::RefreshAuthorizedProjectsService do
it 'sets the access level of a project to the highest available level' do
user.project_authorizations.delete_all
- to_remove = user.project_authorizations.
- create!(project: project, access_level: Gitlab::Access::DEVELOPER)
+ to_remove = user.project_authorizations
+ .create!(project: project, access_level: Gitlab::Access::DEVELOPER)
- expect(service).to receive(:update_authorizations).
- with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]])
+ expect(service).to receive(:update_authorizations)
+ .with([to_remove.project_id], [[user.id, project.id, Gitlab::Access::MASTER]])
service.execute_without_lease
end
@@ -109,7 +109,7 @@ describe Users::RefreshAuthorizedProjectsService do
end
context 'projects the user is a member of' do
- let!(:other_project) { create(:empty_project) }
+ let!(:other_project) { create(:project) }
before do
other_project.team.add_reporter(user)
@@ -122,7 +122,7 @@ describe Users::RefreshAuthorizedProjectsService do
context 'projects of groups the user is a member of' do
let(:group) { create(:group) }
- let!(:other_project) { create(:empty_project, group: group) }
+ let!(:other_project) { create(:project, group: group) }
before do
group.add_owner(user)
@@ -136,7 +136,7 @@ describe Users::RefreshAuthorizedProjectsService do
context 'projects of subgroups of groups the user is a member of', :nested_groups do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
- let!(:other_project) { create(:empty_project, group: nested_group) }
+ let!(:other_project) { create(:project, group: nested_group) }
before do
group.add_master(user)
@@ -149,7 +149,7 @@ describe Users::RefreshAuthorizedProjectsService do
context 'projects shared with groups the user is a member of' do
let(:group) { create(:group) }
- let(:other_project) { create(:empty_project) }
+ let(:other_project) { create(:project) }
let!(:project_group_link) { create(:project_group_link, project: other_project, group: group, group_access: Gitlab::Access::GUEST) }
before do
@@ -164,7 +164,7 @@ describe Users::RefreshAuthorizedProjectsService do
context 'projects shared with subgroups of groups the user is a member of', :nested_groups do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
- let(:other_project) { create(:empty_project) }
+ let(:other_project) { create(:project) }
let!(:project_group_link) { create(:project_group_link, project: other_project, group: nested_group, group_access: Gitlab::Access::DEVELOPER) }
before do
diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb
new file mode 100644
index 00000000000..343804e3de0
--- /dev/null
+++ b/spec/services/users/update_service_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Users::UpdateService do
+ let(:user) { create(:user) }
+
+ describe '#execute' do
+ it 'updates the name' do
+ result = update_user(user, name: 'New Name')
+
+ expect(result).to eq(status: :success)
+ expect(user.name).to eq('New Name')
+ end
+
+ it 'returns an error result when record cannot be updated' do
+ expect do
+ update_user(user, { email: 'invalid' })
+ end.not_to change { user.reload.email }
+ end
+
+ def update_user(user, opts)
+ described_class.new(user, opts).execute
+ end
+ end
+
+ describe '#execute!' do
+ it 'updates the name' do
+ result = update_user(user, name: 'New Name')
+
+ expect(result).to be true
+ expect(user.name).to eq('New Name')
+ end
+
+ it 'raises an error when record cannot be updated' do
+ expect do
+ update_user(user, email: 'invalid')
+ end.to raise_error(ActiveRecord::RecordInvalid)
+ end
+
+ def update_user(user, opts)
+ described_class.new(user, opts).execute!
+ end
+ end
+end
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
index b5abc46e80c..79d90defd78 100644
--- a/spec/services/web_hook_service_spec.rb
+++ b/spec/services/web_hook_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe WebHookService, services: true do
- let(:project) { create(:empty_project) }
+describe WebHookService do
+ let(:project) { create(:project) }
let(:project_hook) { create(:project_hook) }
let(:headers) do
{
@@ -12,7 +12,7 @@ describe WebHookService, services: true do
let(:data) do
{ before: 'oldrev', after: 'newrev', ref: 'ref' }
end
- let(:service_instance) { WebHookService.new(project_hook, data, 'push_hooks') }
+ let(:service_instance) { described_class.new(project_hook, data, 'push_hooks') }
describe '#execute' do
before(:each) do
@@ -53,12 +53,12 @@ describe WebHookService, services: true do
end
it 'handles exceptions' do
- exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout]
+ exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout]
exceptions.each do |exception_class|
exception = exception_class.new('Exception message')
WebMock.stub_request(:post, project_hook.url).to_raise(exception)
- expect(service_instance.execute).to eq([nil, exception.message])
+ expect(service_instance.execute).to eq({ status: :error, message: exception.message })
expect { service_instance.execute }.not_to raise_error
end
end
@@ -66,13 +66,13 @@ describe WebHookService, services: true do
it 'handles 200 status code' do
WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: 'Success')
- expect(service_instance.execute).to eq([200, 'Success'])
+ expect(service_instance.execute).to include({ status: :success, http_status: 200, message: 'Success' })
end
it 'handles 2xx status codes' do
WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: 'Success')
- expect(service_instance.execute).to eq([201, 'Success'])
+ expect(service_instance.execute).to include({ status: :success, http_status: 201, message: 'Success' })
end
context 'execution logging' do
@@ -112,9 +112,26 @@ describe WebHookService, services: true do
end
end
+ context 'with unsafe response body' do
+ before do
+ WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "\xBB")
+ service_instance.execute
+ end
+
+ it 'log successful execution' do
+ expect(hook_log.trigger).to eq('push_hooks')
+ expect(hook_log.url).to eq(project_hook.url)
+ expect(hook_log.request_headers).to eq(headers)
+ expect(hook_log.response_body).to eq('')
+ expect(hook_log.response_status).to eq('200')
+ expect(hook_log.execution_duration).to be > 0
+ expect(hook_log.internal_error_message).to be_nil
+ end
+ end
+
context 'should not log ServiceHooks' do
let(:service_hook) { create(:service_hook) }
- let(:service_instance) { WebHookService.new(service_hook, data, 'service_hook') }
+ let(:service_instance) { described_class.new(service_hook, data, 'service_hook') }
before do
WebMock.stub_request(:post, service_hook.url).to_return(status: 200, body: 'Success')
@@ -131,7 +148,7 @@ describe WebHookService, services: true do
it 'enqueue WebHookWorker' do
expect(Sidekiq::Client).to receive(:enqueue).with(WebHookWorker, project_hook.id, data, 'push_hooks')
- WebHookService.new(project_hook, data, 'push_hooks').async_execute
+ described_class.new(project_hook, data, 'push_hooks').async_execute
end
end
end
diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb
index 054e28ae7b0..b270194d9b8 100644
--- a/spec/services/wiki_pages/create_service_spec.rb
+++ b/spec/services/wiki_pages/create_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe WikiPages::CreateService, services: true do
- let(:project) { create(:empty_project) }
+describe WikiPages::CreateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:opts) do
diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb
index 920be4d4c8a..2938126914b 100644
--- a/spec/services/wiki_pages/destroy_service_spec.rb
+++ b/spec/services/wiki_pages/destroy_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe WikiPages::DestroyService, services: true do
- let(:project) { create(:empty_project) }
+describe WikiPages::DestroyService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:page) { create(:wiki_page) }
diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb
index 5e36ea4cf94..a242bf5a5cc 100644
--- a/spec/services/wiki_pages/update_service_spec.rb
+++ b/spec/services/wiki_pages/update_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
-describe WikiPages::UpdateService, services: true do
- let(:project) { create(:empty_project) }
+describe WikiPages::UpdateService do
+ let(:project) { create(:project) }
let(:user) { create(:user) }
let(:page) { create(:wiki_page) }