summaryrefslogtreecommitdiff
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb36
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb2
-rw-r--r--spec/services/ci/play_build_service_spec.rb17
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb7
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb7
-rw-r--r--spec/services/create_deployment_service_spec.rb246
-rw-r--r--spec/services/discussions/update_diff_position_service_spec.rb (renamed from spec/services/notes/diff_position_update_service_spec.rb)38
-rw-r--r--spec/services/git_push_service_spec.rb14
-rw-r--r--spec/services/git_tag_push_service_spec.rb14
-rw-r--r--spec/services/gravatar_service_spec.rb20
-rw-r--r--spec/services/issues/close_service_spec.rb6
-rw-r--r--spec/services/issues/reopen_service_spec.rb7
-rw-r--r--spec/services/members/authorized_destroy_service_spec.rb2
-rw-r--r--spec/services/merge_requests/close_service_spec.rb2
-rw-r--r--spec/services/merge_requests/conflicts/resolve_service_spec.rb42
-rw-r--r--spec/services/merge_requests/create_service_spec.rb31
-rw-r--r--spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb12
-rw-r--r--spec/services/merge_requests/post_merge_service_spec.rb15
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb2
-rw-r--r--spec/services/merge_requests/update_service_spec.rb11
-rw-r--r--spec/services/projects/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/import_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb9
-rw-r--r--spec/services/submit_usage_ping_service_spec.rb101
-rw-r--r--spec/services/system_note_service_spec.rb81
-rw-r--r--spec/services/users/destroy_service_spec.rb8
-rw-r--r--spec/services/users/refresh_authorized_projects_service_spec.rb66
-rw-r--r--spec/services/web_hook_service_spec.rb137
-rw-r--r--spec/services/wiki_pages/create_service_spec.rb40
-rw-r--r--spec/services/wiki_pages/destroy_service_spec.rb19
-rw-r--r--spec/services/wiki_pages/update_service_spec.rb42
31 files changed, 739 insertions, 299 deletions
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index b536103ed65..597c3947e71 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -9,13 +9,13 @@ describe Ci::CreatePipelineService, services: true do
end
describe '#execute' do
- def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master')
+ def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: 'refs/heads/master')
params = { ref: ref,
before: '00000000',
after: after,
commits: [{ message: message }] }
- described_class.new(project, user, params).execute
+ described_class.new(project, user, params).execute(source)
end
context 'valid params' do
@@ -30,13 +30,14 @@ 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_push
expect(pipeline).to eq(project.pipelines.last)
expect(pipeline).to have_attributes(user: user)
expect(pipeline).to have_attributes(status: 'pending')
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
end
- context '#update_merge_requests_head_pipeline' do
+ 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)
merge_request_2 = create(:merge_request, source_branch: 'master', target_branch: "branch_2", source_project: project)
@@ -58,7 +59,7 @@ describe Ci::CreatePipelineService, services: true do
end
context 'when merge request target project is different from source project' do
- let!(:target_project) { create(:empty_project) }
+ let!(:target_project) { create(:project) }
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
@@ -70,6 +71,18 @@ describe Ci::CreatePipelineService, services: true do
expect(merge_request.reload.head_pipeline).to eq(head_pipeline)
end
end
+
+ context 'when the pipeline is not the latest for the branch' do
+ it 'does not update merge request head pipeline' do
+ merge_request = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project)
+
+ allow_any_instance_of(Ci::Pipeline).to receive(:latest?).and_return(false)
+
+ pipeline
+
+ expect(merge_request.reload.head_pipeline).to be_nil
+ end
+ end
end
context 'auto-cancel enabled' do
@@ -283,5 +296,20 @@ describe Ci::CreatePipelineService, services: true do
expect(Environment.find_by(name: "review/master")).not_to be_nil
end
end
+
+ context 'when environment with invalid name' do
+ before do
+ config = YAML.dump(deploy: { environment: { name: 'name,with,commas' }, script: 'ls' })
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'does not create an environment' do
+ expect do
+ result = execute_service
+
+ expect(result).to be_persisted
+ end.not_to change { Environment.count }
+ end
+ 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 5a20102872a..f2956262f4b 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -16,6 +16,7 @@ describe Ci::CreateTriggerRequestService, services: true do
context 'without owner' do
it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
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
@@ -25,6 +26,7 @@ describe Ci::CreateTriggerRequestService, services: true do
it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
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) }
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index d6f9fa42045..ea211de1f82 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -13,8 +13,11 @@ describe Ci::PlayBuildService, '#execute', :services do
context 'when project does not have repository yet' do
let(:project) { create(:empty_project) }
- it 'allows user with master role to play build' do
- project.add_master(user)
+ it 'allows user to play build if protected branch rules are met' do
+ project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: build.ref, project: project)
service.execute(build)
@@ -45,7 +48,10 @@ describe Ci::PlayBuildService, '#execute', :services do
let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
before do
- project.add_master(user)
+ project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: build.ref, project: project)
end
it 'enqueues the build' do
@@ -64,7 +70,10 @@ describe Ci::PlayBuildService, '#execute', :services do
let(:build) { create(:ci_build, when: :manual, pipeline: pipeline) }
before do
- project.add_master(user)
+ project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: build.ref, project: project)
end
it 'duplicates the build' do
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index fc5de5d069a..1557cb3c938 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -333,10 +333,11 @@ describe Ci::ProcessPipelineService, '#execute', :services do
context 'when pipeline is promoted sequentially up to the end' do
before do
- # We are using create(:empty_project), and users has to be master in
- # order to execute manual action when repository does not exist.
+ # Users need ability to merge into a branch in order to trigger
+ # protected manual actions.
#
- project.add_master(user)
+ create(:protected_branch, :developers_can_merge,
+ name: 'master', project: project)
end
it 'properly processes entire pipeline' do
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index d941d56c0d8..3e860203063 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -6,9 +6,12 @@ describe Ci::RetryPipelineService, '#execute', :services do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:service) { described_class.new(project, user) }
- context 'when user has ability to modify pipeline' do
+ context 'when user has full ability to modify pipeline' do
before do
- project.add_master(user)
+ project.add_developer(user)
+
+ create(:protected_branch, :developers_can_merge,
+ name: pipeline.ref, project: project)
end
context 'when there are already retried jobs present' do
diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb
index f35d7a33548..5398b5c3f7e 100644
--- a/spec/services/create_deployment_service_spec.rb
+++ b/spec/services/create_deployment_service_spec.rb
@@ -1,156 +1,117 @@
require 'spec_helper'
describe CreateDeploymentService, services: true do
- let(:project) { create(:empty_project) }
let(:user) { create(:user) }
+ let(:options) { nil }
+
+ let(:job) do
+ create(:ci_build,
+ ref: 'master',
+ tag: false,
+ environment: 'production',
+ options: { environment: options })
+ end
- let(:service) { described_class.new(project, user, params) }
+ let(:project) { job.project }
- describe '#execute' do
- let(:options) { nil }
- let(:params) do
- {
- environment: 'production',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142',
- options: options
- }
- end
+ let!(:environment) do
+ create(:environment, project: project, name: 'production')
+ end
- subject { service.execute }
+ let(:service) { described_class.new(job) }
- context 'when no environments exist' do
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
- end
+ describe '#execute' do
+ subject { service.execute }
- it 'does create a deployment' do
+ context 'when environment exists' do
+ it 'creates a deployment' do
expect(subject).to be_persisted
end
end
- context 'when environment exist' do
- let!(:environment) { create(:environment, project: project, name: 'production') }
-
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
+ context 'when environment does not exist' do
+ let(:environment) {}
- it 'does create a deployment' do
- expect(subject).to be_persisted
+ it 'does not create a deployment' do
+ expect do
+ expect(subject).to be_nil
+ end.not_to change { Deployment.count }
end
+ end
- context 'and start action is defined' do
- let(:options) { { action: 'start' } }
+ context 'when start action is defined' do
+ let(:options) { { action: 'start' } }
- context 'and environment is stopped' do
- before do
- environment.stop
- end
+ context 'and environment is stopped' do
+ before do
+ environment.stop
+ end
- it 'makes environment available' do
- subject
+ it 'makes environment available' do
+ subject
- expect(environment.reload).to be_available
- end
+ expect(environment.reload).to be_available
+ end
- it 'does create a deployment' do
- expect(subject).to be_persisted
- end
+ it 'creates a deployment' do
+ expect(subject).to be_persisted
end
end
+ end
- context 'and stop action is defined' do
- let(:options) { { action: 'stop' } }
-
- context 'and environment is available' do
- before do
- environment.start
- end
-
- it 'makes environment stopped' do
- subject
-
- expect(environment.reload).to be_stopped
- end
+ context 'when stop action is defined' do
+ let(:options) { { action: 'stop' } }
- it 'does not create a deployment' do
- expect(subject).to be_nil
- end
+ context 'and environment is available' do
+ before do
+ environment.start
end
- end
- end
- context 'for environment with invalid name' do
- let(:params) do
- {
- environment: 'name,with,commas',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142'
- }
- end
+ it 'makes environment stopped' do
+ subject
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
+ expect(environment.reload).to be_stopped
+ end
- it 'does not create a deployment' do
- expect(subject).to be_nil
+ it 'does not create a deployment' do
+ expect(subject).to be_nil
+ end
end
end
context 'when variables are used' do
- let(:params) do
- {
- environment: 'review-apps/$CI_COMMIT_REF_NAME',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142',
- options: {
- name: 'review-apps/$CI_COMMIT_REF_NAME',
- url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com'
- },
- variables: [
- { key: 'CI_COMMIT_REF_NAME', value: 'feature-review-apps' }
- ]
- }
+ let(:options) do
+ { name: 'review-apps/$CI_COMMIT_REF_NAME',
+ url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com' }
end
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject.environment.name).to eq('review-apps/feature-review-apps')
- expect(subject.environment.external_url).to eq('http://feature-review-apps.review-apps.gitlab.com')
+ before do
+ environment.update(name: 'review-apps/master')
+ job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME')
end
- it 'does create a new deployment' do
+ it 'creates a new deployment' do
expect(subject).to be_persisted
end
- context 'and environment exist' do
- let!(:environment) { create(:environment, project: project, name: 'review-apps/feature-review-apps') }
-
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
-
- it 'updates external url' do
- subject
+ it 'does not create a new environment' do
+ expect { subject }.not_to change { Environment.count }
+ end
- expect(subject.environment.name).to eq('review-apps/feature-review-apps')
- expect(subject.environment.external_url).to eq('http://feature-review-apps.review-apps.gitlab.com')
- end
+ it 'updates external url' do
+ subject
- it 'does create a new deployment' do
- expect(subject).to be_persisted
- end
+ expect(subject.environment.name).to eq('review-apps/master')
+ expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
end
end
context 'when project was removed' do
- let(:project) { nil }
+ let(:environment) {}
+
+ before do
+ job.update(project: nil)
+ end
it 'does not create deployment or environment' do
expect { subject }.not_to raise_error
@@ -162,34 +123,26 @@ describe CreateDeploymentService, services: true do
end
describe 'processing of builds' do
- let(:environment) { nil }
-
- shared_examples 'does not create environment and deployment' do
- it 'does not create a new environment' do
- expect { subject }.not_to change { Environment.count }
- end
-
+ shared_examples 'does not create deployment' do
it 'does not create a new deployment' do
expect { subject }.not_to change { Deployment.count }
end
it 'does not call a service' do
expect_any_instance_of(described_class).not_to receive(:execute)
+
subject
end
end
- shared_examples 'does create environment and deployment' do
- it 'does create a new environment' do
- expect { subject }.to change { Environment.count }.by(1)
- end
-
- it 'does create a new deployment' do
+ shared_examples 'creates deployment' do
+ it 'creates a new deployment' do
expect { subject }.to change { Deployment.count }.by(1)
end
- it 'does call a service' do
+ it 'calls a service' do
expect_any_instance_of(described_class).to receive(:execute)
+
subject
end
@@ -199,7 +152,7 @@ describe CreateDeploymentService, services: true do
expect(Deployment.last.deployable).to eq(deployable)
end
- it 'create environment has URL set' do
+ it 'updates environment URL' do
subject
expect(Deployment.last.environment.external_url).not_to be_nil
@@ -207,41 +160,39 @@ describe CreateDeploymentService, services: true do
end
context 'without environment specified' do
- let(:build) { create(:ci_build, project: project) }
+ let(:job) { create(:ci_build) }
- it_behaves_like 'does not create environment and deployment' do
- subject { build.success }
+ it_behaves_like 'does not create deployment' do
+ subject { job.success }
end
end
context 'when environment is specified' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline, environment: 'production', options: options) }
+ let(:deployable) { job }
+
let(:options) do
{ environment: { name: 'production', url: 'http://gitlab.com' } }
end
- context 'when build succeeds' do
- it_behaves_like 'does create environment and deployment' do
- let(:deployable) { build }
-
- subject { build.success }
+ context 'when job succeeds' do
+ it_behaves_like 'creates deployment' do
+ subject { job.success }
end
end
- context 'when build fails' do
- it_behaves_like 'does not create environment and deployment' do
- subject { build.drop }
+ context 'when job fails' do
+ it_behaves_like 'does not create deployment' do
+ subject { job.drop }
end
end
- context 'when build is retried' do
- it_behaves_like 'does create environment and deployment' do
+ context 'when job is retried' do
+ it_behaves_like 'creates deployment' do
before do
project.add_developer(user)
end
- let(:deployable) { Ci::Build.retry(build, user) }
+ let(:deployable) { Ci::Build.retry(job, user) }
subject { deployable.success }
end
@@ -250,15 +201,6 @@ describe CreateDeploymentService, services: true do
end
describe "merge request metrics" do
- let(:params) do
- {
- environment: 'production',
- ref: 'master',
- tag: false,
- sha: '97de212e80737a608d939f648d959671fb0a0142b'
- }
- end
-
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
@@ -273,8 +215,8 @@ describe CreateDeploymentService, services: true do
end
it "doesn't set the time if the deploy's environment is not 'production'" do
- staging_params = params.merge(environment: 'staging')
- service = described_class.new(project, user, staging_params)
+ job.update(environment: 'staging')
+ service = described_class.new(job)
service.execute
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
@@ -298,7 +240,7 @@ describe CreateDeploymentService, services: true do
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
# Current deploy
- service = described_class.new(project, user, params)
+ service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(time)
@@ -318,7 +260,7 @@ describe CreateDeploymentService, services: true do
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
# Current deploy
- service = described_class.new(project, user, params)
+ service = described_class.new(job)
Timecop.freeze(time + 12.hours) { service.execute }
expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
diff --git a/spec/services/notes/diff_position_update_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb
index d73ae51fbc3..177e32e13bd 100644
--- a/spec/services/notes/diff_position_update_service_spec.rb
+++ b/spec/services/discussions/update_diff_position_service_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
-describe Notes::DiffPositionUpdateService, services: true do
+describe Discussions::UpdateDiffPositionService, services: true do
let(:project) { create(:project, :repository) }
+ let(:current_user) { project.owner }
let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") }
let(:modify_commit) { project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e") }
let(:edit_commit) { project.commit("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") }
@@ -25,7 +26,7 @@ describe Notes::DiffPositionUpdateService, services: true do
subject do
described_class.new(
project,
- nil,
+ current_user,
old_diff_refs: old_diff_refs,
new_diff_refs: new_diff_refs,
paths: [path]
@@ -137,7 +138,7 @@ describe Notes::DiffPositionUpdateService, services: true do
# .. ..
describe "#execute" do
- let(:note) { create(:diff_note_on_merge_request, project: project, position: old_position) }
+ let(:discussion) { create(:diff_note_on_merge_request, project: project, position: old_position).to_discussion }
let(:old_position) do
Gitlab::Diff::Position.new(
@@ -153,11 +154,11 @@ describe Notes::DiffPositionUpdateService, services: true do
let(:line) { 16 }
it "updates the position" do
- subject.execute(note)
+ subject.execute(discussion)
- expect(note.original_position).to eq(old_position)
- expect(note.position).not_to eq(old_position)
- expect(note.position.new_line).to eq(22)
+ expect(discussion.original_position).to eq(old_position)
+ expect(discussion.position).not_to eq(old_position)
+ expect(discussion.position.new_line).to eq(22)
end
end
@@ -165,10 +166,27 @@ describe Notes::DiffPositionUpdateService, services: true do
let(:line) { 9 }
it "doesn't update the position" do
- subject.execute(note)
+ subject.execute(discussion)
- expect(note.original_position).to eq(old_position)
- expect(note.position).to eq(old_position)
+ expect(discussion.original_position).to eq(old_position)
+ expect(discussion.position).to eq(old_position)
+ end
+
+ it 'sets the change position' do
+ subject.execute(discussion)
+
+ change_position = discussion.change_position
+ expect(change_position.start_sha).to eq(old_diff_refs.head_sha)
+ expect(change_position.head_sha).to eq(new_diff_refs.head_sha)
+ expect(change_position.old_line).to eq(9)
+ expect(change_position.new_line).to be_nil
+ end
+
+ it 'creates a system discussion' do
+ expect(SystemNoteService).to receive(:diff_discussion_outdated).with(
+ discussion, project, current_user, instance_of(Gitlab::Diff::Position))
+
+ subject.execute(discussion)
end
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index ab06f45dbb9..bcd1fb64ab9 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -131,6 +131,19 @@ describe GitPushService, services: true do
end
end
+ describe "Pipelines" do
+ subject { execute_service(project, user, @oldrev, @newrev, @ref) }
+
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ end
+
+ it "creates a new pipeline" do
+ expect{ subject }.to change{ Ci::Pipeline.count }
+ expect(Ci::Pipeline.last).to be_push
+ end
+ end
+
describe "Push Event" do
before do
service = execute_service(project, user, @oldrev, @newrev, @ref )
@@ -436,6 +449,7 @@ describe GitPushService, services: true do
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])
end
diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb
index b73beb3f6fc..1fdcb420a8b 100644
--- a/spec/services/git_tag_push_service_spec.rb
+++ b/spec/services/git_tag_push_service_spec.rb
@@ -30,6 +30,20 @@ describe GitTagPushService, services: true do
end
end
+ describe "Pipelines" do
+ subject { service.execute }
+
+ before do
+ stub_ci_pipeline_to_return_yaml_file
+ project.team << [user, :developer]
+ end
+
+ it "creates a new pipeline" do
+ expect{ subject }.to change{ Ci::Pipeline.count }
+ expect(Ci::Pipeline.last).to be_push
+ end
+ end
+
describe "Git Tag Push Data" do
subject { @push_data }
let(:tag) { project.repository.find_tag(tag_name) }
diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb
new file mode 100644
index 00000000000..8c4ad8c7a3e
--- /dev/null
+++ b/spec/services/gravatar_service_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe GravatarService, service: true do
+ describe '#execute' do
+ let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' }
+
+ before do
+ allow(Gitlab.config.gravatar).to receive(:plain_url).and_return(url)
+ end
+
+ it 'replaces the placeholders' do
+ avatar_url = described_class.new.execute('user@example.com', 100, 2, username: 'user')
+
+ expect(avatar_url).to include("hash=#{Digest::MD5.hexdigest('user@example.com')}")
+ expect(avatar_url).to include("size=200")
+ expect(avatar_url).to include("email=user%40example.com")
+ expect(avatar_url).to include("username=user")
+ end
+ end
+end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index 0a1f41719f7..be0e829880e 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -41,6 +41,12 @@ describe Issues::CloseService, services: true do
service.execute(issue)
end
+
+ it 'invalidates counter cache for assignees' do
+ expect_any_instance_of(User).to receive(:invalidate_issue_cache_counts)
+
+ service.execute(issue)
+ end
end
describe '#close_issue' do
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 93a8270fd16..391ecad303a 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -27,6 +27,13 @@ describe Issues::ReopenService, services: true do
project.team << [user, :master]
end
+ it 'invalidates counter cache for assignees' do
+ issue.assignees << user
+ expect_any_instance_of(User).to receive(:invalidate_issue_cache_counts)
+
+ described_class.new(project, user).execute(issue)
+ end
+
context 'when issue is not confidential' do
it 'executes issue hooks' do
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb
index 8a6732faa19..f99b11f208c 100644
--- a/spec/services/members/authorized_destroy_service_spec.rb
+++ b/spec/services/members/authorized_destroy_service_spec.rb
@@ -18,7 +18,7 @@ describe Members::AuthorizedDestroyService, services: true do
member = create :project_member, :invited, project: project
expect { described_class.new(member, member_user).execute }
- .to change { Member.count }.from(2).to(1)
+ .to change { Member.count }.from(3).to(2)
end
it 'destroys invited group member' do
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index d55a7657c0e..154f30aac3b 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -15,6 +15,8 @@ describe MergeRequests::CloseService, services: true do
end
describe '#execute' do
+ it_behaves_like 'cache counters invalidator'
+
context 'valid params' do
let(:service) { described_class.new(project, user, {}) }
diff --git a/spec/services/merge_requests/conflicts/resolve_service_spec.rb b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
index 19e8d5cc5f1..c77e6e9cd50 100644
--- a/spec/services/merge_requests/conflicts/resolve_service_spec.rb
+++ b/spec/services/merge_requests/conflicts/resolve_service_spec.rb
@@ -26,6 +26,10 @@ describe MergeRequests::Conflicts::ResolveService do
describe '#execute' do
let(:service) { described_class.new(merge_request) }
+ def blob_content(project, ref, path)
+ project.repository.blob_at(ref, path).data
+ end
+
context 'with section params' do
let(:params) do
{
@@ -66,6 +70,35 @@ describe MergeRequests::Conflicts::ResolveService do
end
end
+ context 'when some files have trailing newlines' do
+ let!(:source_head) do
+ branch = 'conflict-resolvable'
+ path = 'files/ruby/popen.rb'
+ popen_content = blob_content(project, branch, path)
+
+ project.repository.update_file(
+ user,
+ path,
+ popen_content.chomp("\n"),
+ message: 'Remove trailing newline from popen.rb',
+ branch_name: branch
+ )
+ end
+
+ before do
+ service.execute(user, params)
+ end
+
+ it 'preserves trailing newlines from our side of the conflicts' do
+ head_sha = merge_request.source_branch_head.sha
+ popen_content = blob_content(project, head_sha, 'files/ruby/popen.rb')
+ regex_content = blob_content(project, head_sha, 'files/ruby/regex.rb')
+
+ expect(popen_content).not_to end_with("\n")
+ expect(regex_content).to end_with("\n")
+ end
+ end
+
context 'when the source project is a fork and does not contain the HEAD of the target branch' do
let!(:target_head) do
project.repository.create_file(
@@ -142,10 +175,13 @@ describe MergeRequests::Conflicts::ResolveService do
end
it 'sets the content to the content given' do
- blob = merge_request.source_project.repository.blob_at(merge_request.source_branch_head.sha,
- 'files/ruby/popen.rb')
+ blob = blob_content(
+ merge_request.source_project,
+ merge_request.source_branch_head.sha,
+ 'files/ruby/popen.rb'
+ )
- expect(blob.data).to eq(popen_content)
+ expect(blob).to eq(popen_content)
end
end
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index b70e9d534a4..2963f62cc7d 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -75,6 +75,37 @@ describe MergeRequests::CreateService, services: true do
expect(Todo.where(attributes).count).to eq 1
end
end
+
+ context 'when head pipelines already exist for merge request source branch' do
+ let(:sha) { project.commit(opts[:source_branch]).id }
+ let!(:pipeline_1) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: sha) }
+ let!(:pipeline_2) { create(:ci_pipeline, project: project, ref: opts[:source_branch], project_id: project.id, sha: sha) }
+ 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
+ end
+
+ it 'sets head pipeline' do
+ merge_request = service.execute
+
+ expect(merge_request.head_pipeline).to eq(pipeline_2)
+ expect(merge_request).to be_persisted
+ end
+
+ context 'when merge request head commit sha does not match pipeline sha' do
+ it 'sets the head pipeline correctly' do
+ pipeline_2.update(sha: 1234)
+
+ merge_request = service.execute
+
+ expect(merge_request.head_pipeline).to eq(pipeline_1)
+ expect(merge_request).to be_persisted
+ end
+ end
+ end
end
it_behaves_like 'new issuable record that supports slash commands' do
diff --git a/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb
index 3ef5135e6a3..f17db70faf6 100644
--- a/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb
@@ -79,11 +79,8 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do
context 'when triggered by pipeline with valid ref and sha' do
let(:triggering_pipeline) do
create(:ci_pipeline, project: project, ref: merge_request_ref,
- sha: merge_request_head, status: 'success')
- end
-
- before do
- mr_merge_if_green_enabled.update(head_pipeline: triggering_pipeline)
+ sha: merge_request_head, status: 'success',
+ head_pipeline_of: mr_merge_if_green_enabled)
end
it "merges all merge requests with merge when the pipeline succeeds enabled" do
@@ -125,11 +122,10 @@ describe MergeRequests::MergeWhenPipelineSucceedsService do
let(:conflict_pipeline) do
create(:ci_pipeline, project: project, ref: mr_conflict.source_branch,
- sha: mr_conflict.diff_head_sha, status: 'success')
+ sha: mr_conflict.diff_head_sha, status: 'success',
+ head_pipeline_of: mr_conflict)
end
- before { mr_conflict.update(head_pipeline: conflict_pipeline) }
-
it 'does not merge the merge request' do
expect(MergeWorker).not_to receive(:perform_async)
diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb
new file mode 100644
index 00000000000..a20b32eda5f
--- /dev/null
+++ b/spec/services/merge_requests/post_merge_service_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe MergeRequests::PostMergeService, services: true do
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request, assignee: user) }
+ let(:project) { merge_request.project }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ describe '#execute' do
+ it_behaves_like 'cache counters invalidator'
+ end
+end
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index a99d4eac9bd..b6d4db2f922 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -14,6 +14,8 @@ describe MergeRequests::ReopenService, services: true do
end
describe '#execute' do
+ it_behaves_like 'cache counters invalidator'
+
context 'valid params' do
let(:service) { described_class.new(project, user, {}) }
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 860a7798857..d371fc68312 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -180,12 +180,13 @@ describe MergeRequests::UpdateService, services: true do
context 'with active pipeline' do
before do
service_mock = double
- pipeline = create(:ci_pipeline_with_one_job,
+ create(
+ :ci_pipeline_with_one_job,
project: project,
- ref: merge_request.source_branch,
- sha: merge_request.diff_head_sha)
-
- merge_request.update(head_pipeline: pipeline)
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha,
+ head_pipeline_of: merge_request
+ )
expect(MergeRequests::MergeWhenPipelineSucceedsService).to receive(:new).with(project, user).
and_return(service_mock)
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index 4b8589b2736..0d6dd28e332 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -70,7 +70,7 @@ describe Projects::DestroyService, services: true do
end
end
- expect(project.team.members.count).to eq 1
+ expect(project.team.members.count).to eq 2
end
end
diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb
index 852a4ac852f..44db299812f 100644
--- a/spec/services/projects/import_service_spec.rb
+++ b/spec/services/projects/import_service_spec.rb
@@ -186,7 +186,7 @@ describe Projects::ImportService, services: true do
}
)
- allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
+ stub_omniauth_setting(providers: [provider])
end
end
end
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 2112f1cf9ea..5cf989105d0 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -26,6 +26,15 @@ describe SearchService, services: true do
expect(project).to eq accessible_project
end
+
+ it 'returns the project for guests' do
+ search_project = create :empty_project
+ search_project.add_guest(user)
+
+ project = SearchService.new(user, project_id: search_project.id).project
+
+ expect(project).to eq search_project
+ end
end
context 'when the project is not accessible' do
diff --git a/spec/services/submit_usage_ping_service_spec.rb b/spec/services/submit_usage_ping_service_spec.rb
new file mode 100644
index 00000000000..63a1e78f274
--- /dev/null
+++ b/spec/services/submit_usage_ping_service_spec.rb
@@ -0,0 +1,101 @@
+require 'spec_helper'
+
+describe SubmitUsagePingService do
+ context 'when usage ping is disabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: false)
+ end
+
+ it 'does not run' do
+ expect(HTTParty).not_to receive(:post)
+
+ result = subject.execute
+
+ expect(result).to eq false
+ end
+ end
+
+ context 'when usage ping is enabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: true)
+ end
+
+ it 'sends a POST request' do
+ response = stub_response(without_conv_index_params)
+
+ subject.execute
+
+ expect(response).to have_been_requested
+ end
+
+ it 'refreshes usage data statistics before submitting' do
+ stub_response(without_conv_index_params)
+
+ expect(Gitlab::UsageData).to receive(:to_json)
+ .with(force_refresh: true)
+ .and_call_original
+
+ subject.execute
+ end
+
+ it 'saves conversational development index data from the response' do
+ stub_response(with_conv_index_params)
+
+ expect { subject.execute }
+ .to change { ConversationalDevelopmentIndex::Metric.count }
+ .by(1)
+
+ expect(ConversationalDevelopmentIndex::Metric.last.leader_issues).to eq 10.2
+ end
+ end
+
+ def without_conv_index_params
+ {
+ conv_index: {}
+ }
+ end
+
+ def with_conv_index_params
+ {
+ conv_index: {
+ leader_issues: 10.2,
+ instance_issues: 3.2,
+
+ leader_notes: 25.3,
+ instance_notes: 23.2,
+
+ leader_milestones: 16.2,
+ instance_milestones: 5.5,
+
+ leader_boards: 5.2,
+ instance_boards: 3.2,
+
+ leader_merge_requests: 5.2,
+ instance_merge_requests: 3.2,
+
+ leader_ci_pipelines: 25.1,
+ instance_ci_pipelines: 21.3,
+
+ leader_environments: 3.3,
+ instance_environments: 2.2,
+
+ leader_deployments: 41.3,
+ instance_deployments: 15.2,
+
+ leader_projects_prometheus_active: 0.31,
+ instance_projects_prometheus_active: 0.30,
+
+ leader_service_desk_issues: 15.8,
+ instance_service_desk_issues: 15.1
+ }
+ }
+ end
+
+ def stub_response(body)
+ stub_request(:post, 'https://version.gitlab.com/usage_data').
+ to_return(
+ headers: { 'Content-Type' => 'application/json' },
+ body: body.to_json
+ )
+ end
+end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 7a9cd7553b1..c499b1bb343 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -733,6 +733,26 @@ describe SystemNoteService, services: true do
jira_service_settings
end
+ def cross_reference(type, link_exists = false)
+ noteable = type == 'commit' ? commit : merge_request
+
+ links = []
+ if link_exists
+ url = if type == 'commit'
+ "#{Settings.gitlab.base_url}/#{project.namespace.path}/#{project.path}/commit/#{commit.id}"
+ else
+ "#{Settings.gitlab.base_url}/#{project.namespace.path}/#{project.path}/merge_requests/#{merge_request.iid}"
+ end
+ link = double(object: { 'url' => url })
+ links << link
+ expect(link).to receive(:save!)
+ end
+
+ allow(JIRA::Resource::Remotelink).to receive(:all).and_return(links)
+
+ described_class.cross_reference(jira_issue, noteable, author)
+ end
+
noteable_types = %w(merge_requests commit)
noteable_types.each do |type|
@@ -740,24 +760,39 @@ describe SystemNoteService, services: true do
it "blocks cross reference when #{type.underscore}_events is false" do
jira_tracker.update("#{type}_events" => false)
- noteable = type == "commit" ? commit : merge_request
- result = described_class.cross_reference(jira_issue, noteable, author)
-
- expect(result).to eq("Events for #{noteable.class.to_s.underscore.humanize.pluralize.downcase} are disabled.")
+ expect(cross_reference(type)).to eq("Events for #{type.pluralize.humanize.downcase} are disabled.")
end
it "blocks cross reference when #{type.underscore}_events is true" do
jira_tracker.update("#{type}_events" => true)
- noteable = type == "commit" ? commit : merge_request
- result = described_class.cross_reference(jira_issue, noteable, author)
+ expect(cross_reference(type)).to eq(success_message)
+ end
+ end
- expect(result).to eq(success_message)
+ context 'when a new cross reference is created' do
+ it 'creates a new comment and remote link' do
+ cross_reference(type)
+
+ expect(WebMock).to have_requested(:post, jira_api_comment_url(jira_issue))
+ expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue))
+ end
+ end
+
+ context 'when a link exists' do
+ it 'updates a link but does not create a new comment' do
+ expect(WebMock).not_to have_requested(:post, jira_api_comment_url(jira_issue))
+
+ cross_reference(type, true)
end
end
end
describe "new reference" do
+ before do
+ allow(JIRA::Resource::Remotelink).to receive(:all).and_return([])
+ end
+
context 'for commits' do
it "creates comment" do
result = described_class.cross_reference(jira_issue, commit, author)
@@ -837,6 +872,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}'"
allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)])
end
@@ -1034,4 +1070,35 @@ describe SystemNoteService, services: true do
expect(subject.note).to eq 'resolved all discussions'
end
end
+
+ describe '.diff_discussion_outdated' do
+ let(:discussion) { create(:diff_note_on_merge_request).to_discussion }
+ let(:merge_request) { discussion.noteable }
+ let(:project) { merge_request.source_project }
+ let(:change_position) { discussion.position }
+
+ def reloaded_merge_request
+ MergeRequest.find(merge_request.id)
+ end
+
+ subject { described_class.diff_discussion_outdated(discussion, project, author, change_position) }
+
+ it_behaves_like 'a system note' do
+ let(:expected_noteable) { discussion.first_note.noteable }
+ let(:action) { 'outdated' }
+ end
+
+ it 'creates a new note in the discussion' do
+ # we need to completely rebuild the merge request object, or the `@discussions` on the merge request are not reloaded.
+ expect { subject }.to change { reloaded_merge_request.discussions.first.notes.size }.by(1)
+ end
+
+ it 'links to the diff in the system note' do
+ expect(subject.note).to include('version 1')
+
+ 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))
+ end
+ end
end
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index de37a61e388..5409f67c091 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -147,16 +147,22 @@ describe Users::DestroyService, services: true do
end
context "migrating associated records" do
+ let!(:issue) { create(:issue, author: user) }
+
it 'delegates to the `MigrateToGhostUser` service to move associated records to the ghost user' do
- expect_any_instance_of(Users::MigrateToGhostUserService).to receive(:execute).once
+ expect_any_instance_of(Users::MigrateToGhostUserService).to receive(:execute).once.and_call_original
service.execute(user)
+
+ expect(issue.reload.author).to be_ghost
end
it 'does not run `MigrateToGhostUser` if hard_delete option is given' do
expect_any_instance_of(Users::MigrateToGhostUserService).not_to receive(:execute)
service.execute(user, hard_delete: true)
+
+ expect(Issue.exists?(issue.id)).to be_falsy
end
end
end
diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb
index b19374ef1a2..8c40d25e00c 100644
--- a/spec/services/users/refresh_authorized_projects_service_spec.rb
+++ b/spec/services/users/refresh_authorized_projects_service_spec.rb
@@ -1,15 +1,13 @@
require 'spec_helper'
describe Users::RefreshAuthorizedProjectsService do
- let(:project) { create(:empty_project) }
+ # We're using let! here so that any expectations for the service class are not
+ # triggered twice.
+ let!(:project) { create(:empty_project) }
+
let(:user) { project.namespace.owner }
let(:service) { described_class.new(user) }
- def create_authorization(project, user, access_level = Gitlab::Access::MASTER)
- ProjectAuthorization.
- create!(project: project, user: user, access_level: access_level)
- end
-
describe '#execute', :redis do
it 'refreshes the authorizations using a lease' do
expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).
@@ -31,7 +29,8 @@ describe Users::RefreshAuthorizedProjectsService do
it 'updates the authorized projects of the user' do
project2 = create(:empty_project)
- to_remove = create_authorization(project2, user)
+ 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]])
@@ -40,7 +39,10 @@ describe Users::RefreshAuthorizedProjectsService do
end
it 'sets the access level of a project to the highest available level' do
- to_remove = create_authorization(project, user, Gitlab::Access::DEVELOPER)
+ user.project_authorizations.delete_all
+
+ 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]])
@@ -61,34 +63,10 @@ describe Users::RefreshAuthorizedProjectsService do
service.update_authorizations([], [])
end
-
- context 'when the authorized projects column is not set' do
- before do
- user.update!(authorized_projects_populated: nil)
- end
-
- it 'populates the authorized projects column' do
- service.update_authorizations([], [])
-
- expect(user.authorized_projects_populated).to eq true
- end
- end
-
- context 'when the authorized projects column is set' do
- before do
- user.update!(authorized_projects_populated: true)
- end
-
- it 'does nothing' do
- expect(user).not_to receive(:set_authorized_projects_column)
-
- service.update_authorizations([], [])
- end
- end
end
it 'removes authorizations that should be removed' do
- authorization = create_authorization(project, user)
+ authorization = user.project_authorizations.find_by(project_id: project.id)
service.update_authorizations([authorization.project_id])
@@ -96,6 +74,8 @@ describe Users::RefreshAuthorizedProjectsService do
end
it 'inserts authorizations that should be added' do
+ user.project_authorizations.delete_all
+
service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]])
authorizations = user.project_authorizations
@@ -105,16 +85,6 @@ describe Users::RefreshAuthorizedProjectsService do
expect(authorizations[0].project_id).to eq(project.id)
expect(authorizations[0].access_level).to eq(Gitlab::Access::MASTER)
end
-
- it 'populates the authorized projects column' do
- # make sure we start with a nil value no matter what the default in the
- # factory may be.
- user.update!(authorized_projects_populated: nil)
-
- service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]])
-
- expect(user.authorized_projects_populated).to eq(true)
- end
end
describe '#fresh_access_levels_per_project' do
@@ -163,7 +133,7 @@ describe Users::RefreshAuthorizedProjectsService do
end
end
- context 'projects of subgroups of groups the user is a member of' 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) }
@@ -191,7 +161,7 @@ describe Users::RefreshAuthorizedProjectsService do
end
end
- context 'projects shared with subgroups of groups the user is a member of' 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) }
@@ -208,8 +178,6 @@ describe Users::RefreshAuthorizedProjectsService do
end
describe '#current_authorizations_per_project' do
- before { create_authorization(project, user) }
-
let(:hash) { service.current_authorizations_per_project }
it 'returns a Hash' do
@@ -233,13 +201,13 @@ describe Users::RefreshAuthorizedProjectsService do
describe '#current_authorizations' do
context 'without authorizations' do
it 'returns an empty list' do
+ user.project_authorizations.delete_all
+
expect(service.current_authorizations.empty?).to eq(true)
end
end
context 'with an authorization' do
- before { create_authorization(project, user) }
-
let(:row) { service.current_authorizations.take }
it 'returns the currently authorized projects' do
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
new file mode 100644
index 00000000000..b5abc46e80c
--- /dev/null
+++ b/spec/services/web_hook_service_spec.rb
@@ -0,0 +1,137 @@
+require 'spec_helper'
+
+describe WebHookService, services: true do
+ let(:project) { create(:empty_project) }
+ let(:project_hook) { create(:project_hook) }
+ let(:headers) do
+ {
+ 'Content-Type' => 'application/json',
+ 'X-Gitlab-Event' => 'Push Hook'
+ }
+ end
+ let(:data) do
+ { before: 'oldrev', after: 'newrev', ref: 'ref' }
+ end
+ let(:service_instance) { WebHookService.new(project_hook, data, 'push_hooks') }
+
+ describe '#execute' do
+ before(:each) do
+ project.hooks << [project_hook]
+
+ WebMock.stub_request(:post, project_hook.url)
+ end
+
+ context 'when token is defined' do
+ let(:project_hook) { create(:project_hook, :token) }
+
+ it 'POSTs to the webhook URL' do
+ service_instance.execute
+ expect(WebMock).to have_requested(:post, project_hook.url).with(
+ headers: headers.merge({ 'X-Gitlab-Token' => project_hook.token })
+ ).once
+ end
+ end
+
+ it 'POSTs to the webhook URL' do
+ service_instance.execute
+ expect(WebMock).to have_requested(:post, project_hook.url).with(
+ headers: headers
+ ).once
+ end
+
+ it 'POSTs the data as JSON' do
+ service_instance.execute
+ expect(WebMock).to have_requested(:post, project_hook.url).with(
+ headers: headers
+ ).once
+ end
+
+ it 'catches exceptions' do
+ WebMock.stub_request(:post, project_hook.url).to_raise(StandardError.new('Some error'))
+
+ expect { service_instance.execute }.to raise_error(StandardError)
+ end
+
+ it 'handles exceptions' do
+ exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout]
+ 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 }.not_to raise_error
+ end
+ end
+
+ 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'])
+ 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'])
+ end
+
+ context 'execution logging' do
+ let(:hook_log) { project_hook.web_hook_logs.last }
+
+ context 'with success' do
+ before do
+ WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: 'Success')
+ 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('Success')
+ 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 'with exception' do
+ before do
+ WebMock.stub_request(:post, project_hook.url).to_raise(SocketError.new('Some HTTP Post error'))
+ service_instance.execute
+ end
+
+ it 'log failed 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('internal error')
+ expect(hook_log.execution_duration).to be > 0
+ expect(hook_log.internal_error_message).to eq('Some HTTP Post error')
+ end
+ end
+
+ context 'should not log ServiceHooks' do
+ let(:service_hook) { create(:service_hook) }
+ let(:service_instance) { WebHookService.new(service_hook, data, 'service_hook') }
+
+ before do
+ WebMock.stub_request(:post, service_hook.url).to_return(status: 200, body: 'Success')
+ end
+
+ it { expect { service_instance.execute }.not_to change(WebHookLog, :count) }
+ end
+ end
+ end
+
+ describe '#async_execute' do
+ let(:system_hook) { create(:system_hook) }
+
+ 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
+ end
+ end
+end
diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb
index 5341ba3d261..054e28ae7b0 100644
--- a/spec/services/wiki_pages/create_service_spec.rb
+++ b/spec/services/wiki_pages/create_service_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
describe WikiPages::CreateService, services: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
+
let(:opts) do
{
title: 'Title',
@@ -10,27 +11,28 @@ describe WikiPages::CreateService, services: true do
format: 'markdown'
}
end
- let(:service) { described_class.new(project, user, opts) }
+
+ subject(:service) { described_class.new(project, user, opts) }
+
+ before do
+ project.add_developer(user)
+ end
describe '#execute' do
- context "valid params" do
- before do
- allow(service).to receive(:execute_hooks)
- project.add_master(user)
- end
-
- subject { service.execute }
-
- it 'creates a valid wiki page' do
- is_expected.to be_valid
- expect(subject.title).to eq(opts[:title])
- expect(subject.content).to eq(opts[:content])
- expect(subject.format).to eq(opts[:format].to_sym)
- end
-
- it 'executes webhooks' do
- expect(service).to have_received(:execute_hooks).once.with(subject, 'create')
- end
+ it 'creates wiki page with valid attributes' do
+ page = service.execute
+
+ expect(page).to be_valid
+ expect(page.title).to eq(opts[:title])
+ expect(page.content).to eq(opts[:content])
+ expect(page.format).to eq(opts[:format].to_sym)
+ end
+
+ it 'executes webhooks' do
+ expect(service).to receive(:execute_hooks).once
+ .with(instance_of(WikiPage), 'create')
+
+ service.execute
end
end
end
diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb
index a4b9a390fe2..920be4d4c8a 100644
--- a/spec/services/wiki_pages/destroy_service_spec.rb
+++ b/spec/services/wiki_pages/destroy_service_spec.rb
@@ -3,19 +3,20 @@ require 'spec_helper'
describe WikiPages::DestroyService, services: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
- let(:wiki_page) { create(:wiki_page) }
- let(:service) { described_class.new(project, user) }
+ let(:page) { create(:wiki_page) }
- describe '#execute' do
- before do
- allow(service).to receive(:execute_hooks)
- project.add_master(user)
- end
+ subject(:service) { described_class.new(project, user) }
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
it 'executes webhooks' do
- service.execute(wiki_page)
+ expect(service).to receive(:execute_hooks).once
+ .with(instance_of(WikiPage), 'delete')
- expect(service).to have_received(:execute_hooks).once.with(wiki_page, 'delete')
+ service.execute(page)
end
end
end
diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb
index 2bccca764d7..5e36ea4cf94 100644
--- a/spec/services/wiki_pages/update_service_spec.rb
+++ b/spec/services/wiki_pages/update_service_spec.rb
@@ -3,7 +3,8 @@ require 'spec_helper'
describe WikiPages::UpdateService, services: true do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
- let(:wiki_page) { create(:wiki_page) }
+ let(:page) { create(:wiki_page) }
+
let(:opts) do
{
content: 'New content for wiki page',
@@ -11,27 +12,28 @@ describe WikiPages::UpdateService, services: true do
message: 'New wiki message'
}
end
- let(:service) { described_class.new(project, user, opts) }
+
+ subject(:service) { described_class.new(project, user, opts) }
+
+ before do
+ project.add_developer(user)
+ end
describe '#execute' do
- context "valid params" do
- before do
- allow(service).to receive(:execute_hooks)
- project.add_master(user)
- end
-
- subject { service.execute(wiki_page) }
-
- it 'updates the wiki page' do
- is_expected.to be_valid
- expect(subject.content).to eq(opts[:content])
- expect(subject.format).to eq(opts[:format].to_sym)
- expect(subject.message).to eq(opts[:message])
- end
-
- it 'executes webhooks' do
- expect(service).to have_received(:execute_hooks).once.with(subject, 'update')
- end
+ it 'updates the wiki page' do
+ updated_page = service.execute(page)
+
+ expect(updated_page).to be_valid
+ expect(updated_page.message).to eq(opts[:message])
+ expect(updated_page.content).to eq(opts[:content])
+ expect(updated_page.format).to eq(opts[:format].to_sym)
+ end
+
+ it 'executes webhooks' do
+ expect(service).to receive(:execute_hooks).once
+ .with(instance_of(WikiPage), 'update')
+
+ service.execute(page)
end
end
end