summaryrefslogtreecommitdiff
path: root/spec/services
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services')
-rw-r--r--spec/services/application_settings/update_service_spec.rb57
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb20
-rw-r--r--spec/services/ci/register_job_service_spec.rb99
-rw-r--r--spec/services/ci/retry_build_service_spec.rb2
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb62
-rw-r--r--spec/services/git_push_service_spec.rb66
-rw-r--r--spec/services/issuable/common_system_notes_service_spec.rb28
-rw-r--r--spec/services/notification_service_spec.rb31
-rw-r--r--spec/services/projects/create_from_template_service_spec.rb2
-rw-r--r--spec/services/projects/destroy_service_spec.rb13
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb355
-rw-r--r--spec/services/test_hooks/project_service_spec.rb1
-rw-r--r--spec/services/users/respond_to_terms_service_spec.rb37
-rw-r--r--spec/services/web_hook_service_spec.rb2
-rw-r--r--spec/services/wiki_pages/create_service_spec.rb2
15 files changed, 691 insertions, 86 deletions
diff --git a/spec/services/application_settings/update_service_spec.rb b/spec/services/application_settings/update_service_spec.rb
new file mode 100644
index 00000000000..fb07ecc6ae8
--- /dev/null
+++ b/spec/services/application_settings/update_service_spec.rb
@@ -0,0 +1,57 @@
+require 'spec_helper'
+
+describe ApplicationSettings::UpdateService do
+ let(:application_settings) { Gitlab::CurrentSettings.current_application_settings }
+ let(:admin) { create(:user, :admin) }
+ let(:params) { {} }
+
+ subject { described_class.new(application_settings, admin, params) }
+
+ before do
+ # So the caching behaves like it would in production
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ end
+
+ describe 'updating terms' do
+ context 'when the passed terms are blank' do
+ let(:params) { { terms: '' } }
+
+ it 'does not create terms' do
+ expect { subject.execute }.not_to change { ApplicationSetting::Term.count }
+ end
+ end
+
+ context 'when passing terms' do
+ let(:params) { { terms: 'Be nice! ' } }
+
+ it 'creates the terms' do
+ expect { subject.execute }.to change { ApplicationSetting::Term.count }.by(1)
+ end
+
+ it 'does not create terms if they are the same as the existing ones' do
+ create(:term, terms: 'Be nice!')
+
+ expect { subject.execute }.not_to change { ApplicationSetting::Term.count }
+ end
+
+ it 'updates terms if they already existed' do
+ create(:term, terms: 'Other terms')
+
+ subject.execute
+
+ expect(application_settings.terms).to eq('Be nice!')
+ end
+
+ it 'Only queries once when the terms are changed' do
+ create(:term, terms: 'Other terms')
+ expect(application_settings.terms).to eq('Other terms')
+
+ subject.execute
+
+ expect(application_settings.terms).to eq('Be nice!')
+ expect { 2.times { application_settings.terms } }
+ .not_to exceed_query_limit(0)
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 267258b33a8..9a0b6efd8a9 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -17,11 +17,13 @@ describe Ci::CreatePipelineService do
after: project.commit.id,
message: 'Message',
ref: ref_name,
- trigger_request: nil)
+ trigger_request: nil,
+ variables_attributes: nil)
params = { ref: ref,
before: '00000000',
after: after,
- commits: [{ message: message }] }
+ commits: [{ message: message }],
+ variables_attributes: variables_attributes }
described_class.new(project, user, params).execute(
source, trigger_request: trigger_request)
@@ -545,5 +547,19 @@ describe Ci::CreatePipelineService do
expect(pipeline.tag?).to be true
end
end
+
+ context 'when pipeline variables are specified' do
+ let(:variables_attributes) do
+ [{ key: 'first', secret_value: 'world' },
+ { key: 'second', secret_value: 'second_world' }]
+ end
+
+ subject { execute_service(variables_attributes: variables_attributes) }
+
+ it 'creates a pipeline with specified variables' do
+ expect(subject.variables.map { |var| var.slice(:key, :secret_value) })
+ .to eq variables_attributes.map(&:with_indifferent_access)
+ end
+ end
end
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 8a537e83d5f..8063bc7e1ac 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -2,11 +2,13 @@ require 'spec_helper'
module Ci
describe RegisterJobService do
- let!(:project) { FactoryBot.create :project, shared_runners_enabled: false }
- let!(:pipeline) { FactoryBot.create :ci_pipeline, project: project }
- let!(:pending_job) { FactoryBot.create :ci_build, pipeline: pipeline }
- let!(:shared_runner) { FactoryBot.create(:ci_runner, is_shared: true) }
- let!(:specific_runner) { FactoryBot.create(:ci_runner, is_shared: false) }
+ set(:group) { create(:group) }
+ set(:project) { create(:project, group: group, shared_runners_enabled: false, group_runners_enabled: false) }
+ set(:pipeline) { create(:ci_pipeline, project: project) }
+ let!(:shared_runner) { create(:ci_runner, is_shared: true) }
+ let!(:specific_runner) { create(:ci_runner, is_shared: false) }
+ let!(:group_runner) { create(:ci_runner, groups: [group], runner_type: :group_type) }
+ let!(:pending_job) { create(:ci_build, pipeline: pipeline) }
before do
specific_runner.assign_to(project)
@@ -150,7 +152,7 @@ module Ci
context 'disallow when builds are disabled' do
before do
- project.update(shared_runners_enabled: true)
+ project.update(shared_runners_enabled: true, group_runners_enabled: true)
project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
end
@@ -160,13 +162,90 @@ module Ci
it { expect(build).to be_nil }
end
- context 'and uses specific runner' do
+ context 'and uses group runner' do
+ let(:build) { execute(group_runner) }
+
+ it { expect(build).to be_nil }
+ end
+
+ context 'and uses project runner' do
let(:build) { execute(specific_runner) }
it { expect(build).to be_nil }
end
end
+ context 'allow group runners' do
+ before do
+ project.update!(group_runners_enabled: true)
+ end
+
+ context 'for multiple builds' do
+ let!(:project2) { create :project, group_runners_enabled: true, group: group }
+ let!(:pipeline2) { create :ci_pipeline, project: project2 }
+ let!(:project3) { create :project, group_runners_enabled: true, group: group }
+ let!(:pipeline3) { create :ci_pipeline, project: project3 }
+
+ let!(:build1_project1) { pending_job }
+ let!(:build2_project1) { create :ci_build, pipeline: pipeline }
+ let!(:build3_project1) { create :ci_build, pipeline: pipeline }
+ let!(:build1_project2) { create :ci_build, pipeline: pipeline2 }
+ let!(:build2_project2) { create :ci_build, pipeline: pipeline2 }
+ let!(:build1_project3) { create :ci_build, pipeline: pipeline3 }
+
+ # these shouldn't influence the scheduling
+ let!(:unrelated_group) { create :group }
+ let!(:unrelated_project) { create :project, group_runners_enabled: true, group: unrelated_group }
+ let!(:unrelated_pipeline) { create :ci_pipeline, project: unrelated_project }
+ let!(:build1_unrelated_project) { create :ci_build, pipeline: unrelated_pipeline }
+ let!(:unrelated_group_runner) { create :ci_runner, groups: [unrelated_group] }
+
+ it 'does not consider builds from other group runners' do
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 6
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 5
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 4
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 3
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 2
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 1
+ execute(group_runner)
+
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 0
+ expect(execute(group_runner)).to be_nil
+ end
+ end
+
+ context 'group runner' do
+ let(:build) { execute(group_runner) }
+
+ it { expect(build).to be_kind_of(Build) }
+ it { expect(build).to be_valid }
+ it { expect(build).to be_running }
+ it { expect(build.runner).to eq(group_runner) }
+ end
+ end
+
+ context 'disallow group runners' do
+ before do
+ project.update!(group_runners_enabled: false)
+ end
+
+ context 'group runner' do
+ let(:build) { execute(group_runner) }
+
+ it { expect(build).to be_nil }
+ end
+ end
+
context 'when first build is stalled' do
before do
pending_job.update(lock_version: 0)
@@ -178,7 +257,7 @@ module Ci
let!(:other_build) { create :ci_build, pipeline: pipeline }
before do
- allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_specific_runner)
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner)
.and_return(Ci::Build.where(id: [pending_job, other_build]))
end
@@ -190,7 +269,7 @@ module Ci
context 'when single build is in queue' do
before do
- allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_specific_runner)
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner)
.and_return(Ci::Build.where(id: pending_job))
end
@@ -201,7 +280,7 @@ module Ci
context 'when there is no build in queue' do
before do
- allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_specific_runner)
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner)
.and_return(Ci::Build.none)
end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 5bc6031388e..e1cb7ed8110 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -32,7 +32,7 @@ describe Ci::RetryBuildService do
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
artifacts_file_store artifacts_metadata_store
- metadata].freeze
+ metadata trace_chunks].freeze
shared_examples 'build duplication' do
let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index 0da0e57dbcd..74a23ed2a3f 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -8,21 +8,19 @@ describe Ci::UpdateBuildQueueService do
context 'when updating specific runners' do
let(:runner) { create(:ci_runner) }
- context 'when there are runner that can pick build' do
+ context 'when there is a runner that can pick build' do
before do
build.project.runners << runner
end
it 'ticks runner queue value' do
- expect { subject.execute(build) }
- .to change { runner.ensure_runner_queue_value }
+ expect { subject.execute(build) }.to change { runner.ensure_runner_queue_value }
end
end
- context 'when there are no runners that can pick build' do
+ context 'when there is no runner that can pick build' do
it 'does not tick runner queue value' do
- expect { subject.execute(build) }
- .not_to change { runner.ensure_runner_queue_value }
+ expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
end
end
end
@@ -30,21 +28,61 @@ describe Ci::UpdateBuildQueueService do
context 'when updating shared runners' do
let(:runner) { create(:ci_runner, :shared) }
- context 'when there are runner that can pick build' do
+ context 'when there is no runner that can pick build' do
it 'ticks runner queue value' do
- expect { subject.execute(build) }
- .to change { runner.ensure_runner_queue_value }
+ expect { subject.execute(build) }.to change { runner.ensure_runner_queue_value }
end
end
- context 'when there are no runners that can pick build' do
+ context 'when there is no runner that can pick build due to tag mismatch' do
before do
build.tag_list = [:docker]
end
it 'does not tick runner queue value' do
- expect { subject.execute(build) }
- .not_to change { runner.ensure_runner_queue_value }
+ expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
+ end
+ end
+
+ context 'when there is no runner that can pick build due to being disabled on project' do
+ before do
+ build.project.shared_runners_enabled = false
+ end
+
+ it 'does not tick runner queue value' do
+ expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
+ end
+ end
+ end
+
+ context 'when updating group runners' do
+ let(:group) { create :group }
+ let(:project) { create :project, group: group }
+ let(:runner) { create :ci_runner, groups: [group] }
+
+ context 'when there is a runner that can pick build' do
+ it 'ticks runner queue value' do
+ expect { subject.execute(build) }.to change { runner.ensure_runner_queue_value }
+ end
+ end
+
+ context 'when there is no runner that can pick build due to tag mismatch' do
+ before do
+ build.tag_list = [:docker]
+ end
+
+ it 'does not tick runner queue value' do
+ expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
+ end
+ end
+
+ context 'when there is no runner that can pick build due to being disabled on project' do
+ before do
+ build.project.group_runners_enabled = false
+ end
+
+ it 'does not tick runner queue value' do
+ expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
end
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index 26fdf8d4b24..35826de5814 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -14,6 +14,72 @@ describe GitPushService, services: true do
project.add_master(user)
end
+ describe 'with remote mirrors' do
+ let(:project) { create(:project, :repository, :remote_mirror) }
+
+ subject do
+ described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref)
+ end
+
+ context 'when remote mirror feature is enabled' do
+ it 'fails stuck remote mirrors' do
+ allow(project).to receive(:update_remote_mirrors).and_return(project.remote_mirrors)
+ expect(project).to receive(:mark_stuck_remote_mirrors_as_failed!)
+
+ subject.execute
+ end
+
+ it 'updates remote mirrors' do
+ expect(project).to receive(:update_remote_mirrors)
+
+ subject.execute
+ end
+ end
+
+ context 'when remote mirror feature is disabled' do
+ before do
+ stub_application_setting(mirror_available: false)
+ end
+
+ context 'with remote mirrors global setting overridden' do
+ before do
+ project.remote_mirror_available_overridden = true
+ end
+
+ it 'fails stuck remote mirrors' do
+ allow(project).to receive(:update_remote_mirrors).and_return(project.remote_mirrors)
+ expect(project).to receive(:mark_stuck_remote_mirrors_as_failed!)
+
+ subject.execute
+ end
+
+ it 'updates remote mirrors' do
+ expect(project).to receive(:update_remote_mirrors)
+
+ subject.execute
+ end
+ end
+
+ context 'without remote mirrors global setting overridden' do
+ before do
+ project.remote_mirror_available_overridden = false
+ end
+
+ it 'does not fails stuck remote mirrors' do
+ expect(project).not_to receive(:mark_stuck_remote_mirrors_as_failed!)
+
+ subject.execute
+ end
+
+ it 'does not updates remote mirrors' do
+ expect(project).not_to receive(:update_remote_mirrors)
+
+ subject.execute
+ end
+ end
+ end
+ end
+
describe 'Push branches' do
subject do
execute_service(project, user, oldrev, newrev, ref)
diff --git a/spec/services/issuable/common_system_notes_service_spec.rb b/spec/services/issuable/common_system_notes_service_spec.rb
index b8fa3e3d124..dcf4503ef9c 100644
--- a/spec/services/issuable/common_system_notes_service_spec.rb
+++ b/spec/services/issuable/common_system_notes_service_spec.rb
@@ -5,34 +5,6 @@ describe Issuable::CommonSystemNotesService do
let(:project) { create(:project) }
let(:issuable) { create(:issue) }
- shared_examples 'system note creation' do |update_params, note_text|
- subject { described_class.new(project, user).execute(issuable, [])}
-
- before do
- issuable.assign_attributes(update_params)
- issuable.save
- end
-
- it 'creates 1 system note with the correct content' do
- expect { subject }.to change { Note.count }.from(0).to(1)
-
- note = Note.last
- expect(note.note).to match(note_text)
- expect(note.noteable_type).to eq(issuable.class.name)
- end
- end
-
- shared_examples 'WIP notes creation' do |wip_action|
- subject { described_class.new(project, user).execute(issuable, []) }
-
- it 'creates WIP toggle and title change notes' do
- expect { subject }.to change { Note.count }.from(0).to(2)
-
- expect(Note.first.note).to match("#{wip_action} as a **Work In Progress**")
- expect(Note.second.note).to match('changed title')
- end
- end
-
describe '#execute' do
it_behaves_like 'system note creation', { title: 'New title' }, 'changed title'
it_behaves_like 'system note creation', { description: 'New description' }, 'changed the description'
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 48ef5f3c115..5f28bc123f3 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe NotificationService, :mailer do
include EmailSpec::Matchers
+ include NotificationHelpers
let(:notification) { described_class.new }
let(:assignee) { create(:user) }
@@ -13,12 +14,6 @@ describe NotificationService, :mailer do
end
shared_examples 'notifications for new mentions' do
- def send_notifications(*new_mentions)
- mentionable.description = new_mentions.map(&:to_reference).join(' ')
-
- notification.send(notification_method, mentionable, new_mentions, @u_disabled)
- end
-
it 'sends no emails when no new mentions are present' do
send_notifications
should_not_email_anyone
@@ -1914,30 +1909,6 @@ describe NotificationService, :mailer do
group
end
- def create_global_setting_for(user, level)
- setting = user.global_notification_setting
- setting.level = level
- setting.save
-
- user
- end
-
- def create_user_with_notification(level, username, resource = project)
- user = create(:user, username: username)
- setting = user.notification_settings_for(resource)
- setting.level = level
- setting.save
-
- user
- end
-
- # Create custom notifications
- # 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.update!(event => value)
- end
-
def add_users_with_subscription(project, issuable)
@subscriber = create :user
@unsubscriber = create :user
diff --git a/spec/services/projects/create_from_template_service_spec.rb b/spec/services/projects/create_from_template_service_spec.rb
index d40e6f1449d..9aa9237d875 100644
--- a/spec/services/projects/create_from_template_service_spec.rb
+++ b/spec/services/projects/create_from_template_service_spec.rb
@@ -23,7 +23,7 @@ describe Projects::CreateFromTemplateService do
project = subject.execute
expect(project).to be_saved
- expect(project.scheduled?).to be(true)
+ expect(project.import_scheduled?).to be(true)
end
context 'the result project' do
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index b2c52214f48..b63f409579e 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -65,6 +65,19 @@ describe Projects::DestroyService do
Sidekiq::Testing.inline! { destroy_project(project, user, {}) }
end
+ context 'when has remote mirrors' do
+ let!(:project) do
+ create(:project, :repository, namespace: user.namespace).tap do |project|
+ project.remote_mirrors.create(url: 'http://test.com')
+ end
+ end
+ let!(:async) { true }
+
+ it 'destroys them' do
+ expect(RemoteMirror.count).to eq(0)
+ end
+ end
+
it_behaves_like 'deleting the project'
it 'invalidates personal_project_count cache' do
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
new file mode 100644
index 00000000000..be09afd9f36
--- /dev/null
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -0,0 +1,355 @@
+require 'spec_helper'
+
+describe Projects::UpdateRemoteMirrorService do
+ let(:project) { create(:project, :repository) }
+ let(:remote_project) { create(:forked_project_with_submodules) }
+ let(:repository) { project.repository }
+ let(:raw_repository) { repository.raw }
+ let(:remote_mirror) { project.remote_mirrors.create!(url: remote_project.http_url_to_repo, enabled: true, only_protected_branches: false) }
+
+ subject { described_class.new(project, project.creator) }
+
+ describe "#execute", :skip_gitaly_mock do
+ before do
+ create_branch(repository, 'existing-branch')
+ allow(raw_repository).to receive(:remote_tags) do
+ generate_tags(repository, 'v1.0.0', 'v1.1.0')
+ end
+ allow(raw_repository).to receive(:push_remote_branches).and_return(true)
+ end
+
+ it "fetches the remote repository" do
+ expect(repository).to receive(:fetch_remote).with(remote_mirror.remote_name, no_tags: true) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ end
+
+ subject.execute(remote_mirror)
+ end
+
+ it "succeeds" do
+ allow(repository).to receive(:fetch_remote) { sync_remote(repository, remote_mirror.remote_name, local_branch_names) }
+
+ result = subject.execute(remote_mirror)
+
+ expect(result[:status]).to eq(:success)
+ end
+
+ describe 'Syncing branches' do
+ it "push all the branches the first time" do
+ allow(repository).to receive(:fetch_remote)
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, local_branch_names)
+
+ subject.execute(remote_mirror)
+ end
+
+ it "does not push anything is remote is up to date" do
+ allow(repository).to receive(:fetch_remote) { sync_remote(repository, remote_mirror.remote_name, local_branch_names) }
+
+ expect(raw_repository).not_to receive(:push_remote_branches)
+
+ subject.execute(remote_mirror)
+ end
+
+ it "sync new branches" do
+ # call local_branch_names early so it is not called after the new branch has been created
+ current_branches = local_branch_names
+ allow(repository).to receive(:fetch_remote) { sync_remote(repository, remote_mirror.remote_name, current_branches) }
+ create_branch(repository, 'my-new-branch')
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, ['my-new-branch'])
+
+ subject.execute(remote_mirror)
+ end
+
+ it "sync updated branches" do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ update_branch(repository, 'existing-branch')
+ end
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, ['existing-branch'])
+
+ subject.execute(remote_mirror)
+ end
+
+ context 'when push only protected branches option is set' do
+ let(:unprotected_branch_name) { 'existing-branch' }
+ let(:protected_branch_name) do
+ project.repository.branch_names.find { |n| n != unprotected_branch_name }
+ end
+ let!(:protected_branch) do
+ create(:protected_branch, project: project, name: protected_branch_name)
+ end
+
+ before do
+ project.reload
+ remote_mirror.only_protected_branches = true
+ end
+
+ it "sync updated protected branches" do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ update_branch(repository, protected_branch_name)
+ end
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, [protected_branch_name])
+
+ subject.execute(remote_mirror)
+ end
+
+ it 'does not sync unprotected branches' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ update_branch(repository, unprotected_branch_name)
+ end
+
+ expect(raw_repository).not_to receive(:push_remote_branches).with(remote_mirror.remote_name, [unprotected_branch_name])
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when branch exists in local and remote repo' do
+ context 'when it has diverged' do
+ it 'syncs branches' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ update_remote_branch(repository, remote_mirror.remote_name, 'markdown')
+ end
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, ['markdown'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+ end
+
+ describe 'for delete' do
+ context 'when branch exists in local and remote repo' do
+ it 'deletes the branch from remote repo' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ delete_branch(repository, 'existing-branch')
+ end
+
+ expect(raw_repository).to receive(:delete_remote_branches).with(remote_mirror.remote_name, ['existing-branch'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when push only protected branches option is set' do
+ before do
+ remote_mirror.only_protected_branches = true
+ end
+
+ context 'when branch exists in local and remote repo' do
+ let!(:protected_branch_name) { local_branch_names.first }
+
+ before do
+ create(:protected_branch, project: project, name: protected_branch_name)
+ project.reload
+ end
+
+ it 'deletes the protected branch from remote repo' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ delete_branch(repository, protected_branch_name)
+ end
+
+ expect(raw_repository).not_to receive(:delete_remote_branches).with(remote_mirror.remote_name, [protected_branch_name])
+
+ subject.execute(remote_mirror)
+ end
+
+ it 'does not delete the unprotected branch from remote repo' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+ delete_branch(repository, 'existing-branch')
+ end
+
+ expect(raw_repository).not_to receive(:delete_remote_branches).with(remote_mirror.remote_name, ['existing-branch'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when branch only exists on remote repo' do
+ let!(:protected_branch_name) { 'remote-branch' }
+
+ before do
+ create(:protected_branch, project: project, name: protected_branch_name)
+ end
+
+ context 'when it has diverged' do
+ it 'does not delete the remote branch' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+
+ rev = repository.find_branch('markdown').dereferenced_target
+ create_remote_branch(repository, remote_mirror.remote_name, 'remote-branch', rev.id)
+ end
+
+ expect(raw_repository).not_to receive(:delete_remote_branches)
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when it has not diverged' do
+ it 'deletes the remote branch' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+
+ masterrev = repository.find_branch('master').dereferenced_target
+ create_remote_branch(repository, remote_mirror.remote_name, protected_branch_name, masterrev.id)
+ end
+
+ expect(raw_repository).to receive(:delete_remote_branches).with(remote_mirror.remote_name, [protected_branch_name])
+
+ subject.execute(remote_mirror)
+ end
+ end
+ end
+ end
+
+ context 'when branch only exists on remote repo' do
+ context 'when it has diverged' do
+ it 'does not delete the remote branch' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+
+ rev = repository.find_branch('markdown').dereferenced_target
+ create_remote_branch(repository, remote_mirror.remote_name, 'remote-branch', rev.id)
+ end
+
+ expect(raw_repository).not_to receive(:delete_remote_branches)
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when it has not diverged' do
+ it 'deletes the remote branch' do
+ allow(repository).to receive(:fetch_remote) do
+ sync_remote(repository, remote_mirror.remote_name, local_branch_names)
+
+ masterrev = repository.find_branch('master').dereferenced_target
+ create_remote_branch(repository, remote_mirror.remote_name, 'remote-branch', masterrev.id)
+ end
+
+ expect(raw_repository).to receive(:delete_remote_branches).with(remote_mirror.remote_name, ['remote-branch'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+ end
+ end
+ end
+
+ describe 'Syncing tags' do
+ before do
+ allow(repository).to receive(:fetch_remote) { sync_remote(repository, remote_mirror.remote_name, local_branch_names) }
+ end
+
+ context 'when there are not tags to push' do
+ it 'does not try to push tags' do
+ allow(repository).to receive(:remote_tags) { {} }
+ allow(repository).to receive(:tags) { [] }
+
+ expect(repository).not_to receive(:push_tags)
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when there are some tags to push' do
+ it 'pushes tags to remote' do
+ allow(raw_repository).to receive(:remote_tags) { {} }
+
+ expect(raw_repository).to receive(:push_remote_branches).with(remote_mirror.remote_name, ['v1.0.0', 'v1.1.0'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+
+ context 'when there are some tags to delete' do
+ it 'deletes tags from remote' do
+ remote_tags = generate_tags(repository, 'v1.0.0', 'v1.1.0')
+ allow(raw_repository).to receive(:remote_tags) { remote_tags }
+
+ repository.rm_tag(create(:user), 'v1.0.0')
+
+ expect(raw_repository).to receive(:delete_remote_branches).with(remote_mirror.remote_name, ['v1.0.0'])
+
+ subject.execute(remote_mirror)
+ end
+ end
+ end
+ end
+
+ def create_branch(repository, branch_name)
+ rugged = repository.rugged
+ masterrev = repository.find_branch('master').dereferenced_target
+ parentrev = repository.commit(masterrev).parent_id
+
+ rugged.references.create("refs/heads/#{branch_name}", parentrev)
+
+ repository.expire_branches_cache
+ end
+
+ def create_remote_branch(repository, remote_name, branch_name, source_id)
+ rugged = repository.rugged
+
+ rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", source_id)
+ end
+
+ def sync_remote(repository, remote_name, local_branch_names)
+ rugged = repository.rugged
+
+ local_branch_names.each do |branch|
+ target = repository.find_branch(branch).try(:dereferenced_target)
+ rugged.references.create("refs/remotes/#{remote_name}/#{branch}", target.id) if target
+ end
+ end
+
+ def update_remote_branch(repository, remote_name, branch)
+ rugged = repository.rugged
+ masterrev = repository.find_branch('master').dereferenced_target.id
+
+ rugged.references.create("refs/remotes/#{remote_name}/#{branch}", masterrev, force: true)
+ repository.expire_branches_cache
+ end
+
+ def update_branch(repository, branch)
+ rugged = repository.rugged
+ masterrev = repository.find_branch('master').dereferenced_target.id
+
+ # Updated existing branch
+ rugged.references.create("refs/heads/#{branch}", masterrev, force: true)
+ repository.expire_branches_cache
+ end
+
+ def delete_branch(repository, branch)
+ rugged = repository.rugged
+
+ rugged.references.delete("refs/heads/#{branch}")
+ repository.expire_branches_cache
+ end
+
+ def generate_tags(repository, *tag_names)
+ tag_names.each_with_object([]) do |name, tags|
+ tag = repository.find_tag(name)
+ target = tag.try(:target)
+ target_commit = tag.try(:dereferenced_target)
+ tags << Gitlab::Git::Tag.new(repository.raw_repository, name, target, target_commit)
+ end
+ end
+
+ def local_branch_names
+ branch_names = repository.branches.map(&:name)
+ # we want the protected branch to be pushed first
+ branch_names.unshift(branch_names.delete('master'))
+ end
+end
diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb
index 28dfa9cf59c..962b9f40c4f 100644
--- a/spec/services/test_hooks/project_service_spec.rb
+++ b/spec/services/test_hooks/project_service_spec.rb
@@ -170,6 +170,7 @@ describe TestHooks::ProjectService do
end
context 'wiki_page_events' do
+ let(:project) { create(:project, :wiki_repo) }
let(:trigger) { 'wiki_page_events' }
let(:trigger_key) { :wiki_page_hooks }
diff --git a/spec/services/users/respond_to_terms_service_spec.rb b/spec/services/users/respond_to_terms_service_spec.rb
new file mode 100644
index 00000000000..fb08dd10b87
--- /dev/null
+++ b/spec/services/users/respond_to_terms_service_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Users::RespondToTermsService do
+ let(:user) { create(:user) }
+ let(:term) { create(:term) }
+
+ subject(:service) { described_class.new(user, term) }
+
+ describe '#execute' do
+ it 'creates a new agreement if it did not exist' do
+ expect { service.execute(accepted: true) }
+ .to change { user.term_agreements.size }.by(1)
+ end
+
+ it 'updates an agreement if it existed' do
+ agreement = create(:term_agreement, user: user, term: term, accepted: true)
+
+ service.execute(accepted: true)
+
+ expect(agreement.reload.accepted).to be_truthy
+ end
+
+ it 'adds the accepted terms to the user' do
+ service.execute(accepted: true)
+
+ expect(user.reload.accepted_term).to eq(term)
+ end
+
+ it 'removes accepted terms when declining' do
+ user.update!(accepted_term: term)
+
+ service.execute(accepted: false)
+
+ expect(user.reload.accepted_term).to be_nil
+ end
+ end
+end
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
index 2ef2e61babc..7995f2c9ae7 100644
--- a/spec/services/web_hook_service_spec.rb
+++ b/spec/services/web_hook_service_spec.rb
@@ -67,7 +67,7 @@ describe WebHookService do
end
it 'handles exceptions' do
- exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout]
+ exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError]
exceptions.each do |exception_class|
exception = exception_class.new('Exception message')
diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb
index b270194d9b8..259f445247e 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 do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :wiki_repo) }
let(:user) { create(:user) }
let(:opts) do