Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/copy_cross_database_associations_service_spec.rb18
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb101
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb16
-rw-r--r--spec/services/ci/pipeline_schedule_service_spec.rb17
-rw-r--r--spec/services/ci/process_sync_events_service_spec.rb76
-rw-r--r--spec/services/ci/register_job_service_spec.rb4
-rw-r--r--spec/services/ci/register_runner_service_spec.rb330
-rw-r--r--spec/services/ci/retry_build_service_spec.rb20
-rw-r--r--spec/services/ci/unregister_runner_service_spec.rb15
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb32
-rw-r--r--spec/services/ci/update_runner_service_spec.rb14
11 files changed, 370 insertions, 273 deletions
diff --git a/spec/services/ci/copy_cross_database_associations_service_spec.rb b/spec/services/ci/copy_cross_database_associations_service_spec.rb
new file mode 100644
index 00000000000..5938ac258d0
--- /dev/null
+++ b/spec/services/ci/copy_cross_database_associations_service_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CopyCrossDatabaseAssociationsService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:old_build) { create(:ci_build, pipeline: pipeline) }
+ let_it_be(:new_build) { create(:ci_build, pipeline: pipeline) }
+
+ subject(:execute) { described_class.new.execute(old_build, new_build) }
+
+ describe '#execute' do
+ it 'returns a success response' do
+ expect(execute).to be_success
+ end
+ end
+end
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb
index d61abf6a6ee..43eb57df66c 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -441,44 +441,99 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
end
- context 'when relationship between pipelines is cyclical' do
- before do
- pipeline_a = create(:ci_pipeline, project: upstream_project)
- pipeline_b = create(:ci_pipeline, project: downstream_project)
- pipeline_c = create(:ci_pipeline, project: upstream_project)
+ describe 'cyclical dependency detection' do
+ shared_examples 'detects cyclical pipelines' do
+ it 'does not create a new pipeline' do
+ expect { service.execute(bridge) }
+ .not_to change { Ci::Pipeline.count }
+ end
+
+ it 'changes status of the bridge build' do
+ service.execute(bridge)
- create_source_pipeline(pipeline_a, pipeline_b)
- create_source_pipeline(pipeline_b, pipeline_c)
- create_source_pipeline(pipeline_c, upstream_pipeline)
+ expect(bridge.reload).to be_failed
+ expect(bridge.failure_reason).to eq 'pipeline_loop_detected'
+ end
end
- it 'does not create a new pipeline' do
- expect { service.execute(bridge) }
- .not_to change { Ci::Pipeline.count }
+ shared_examples 'passes cyclical pipeline precondition' do
+ it 'creates a new pipeline' do
+ expect { service.execute(bridge) }
+ .to change { Ci::Pipeline.count }
+ end
+
+ it 'expect bridge build not to be failed' do
+ service.execute(bridge)
+
+ expect(bridge.reload).not_to be_failed
+ end
end
- it 'changes status of the bridge build' do
- service.execute(bridge)
+ context 'when pipeline ancestry contains 2 cycles of dependencies' do
+ before do
+ # A(push on master) -> B(pipeline on master) -> A(push on master) ->
+ # B(pipeline on master) -> A(push on master)
+ pipeline_1 = create(:ci_pipeline, project: upstream_project, source: :push)
+ pipeline_2 = create(:ci_pipeline, project: downstream_project, source: :pipeline)
+ pipeline_3 = create(:ci_pipeline, project: upstream_project, source: :push)
+ pipeline_4 = create(:ci_pipeline, project: downstream_project, source: :pipeline)
+
+ create_source_pipeline(pipeline_1, pipeline_2)
+ create_source_pipeline(pipeline_2, pipeline_3)
+ create_source_pipeline(pipeline_3, pipeline_4)
+ create_source_pipeline(pipeline_4, upstream_pipeline)
+ end
- expect(bridge.reload).to be_failed
- expect(bridge.failure_reason).to eq 'pipeline_loop_detected'
+ it_behaves_like 'detects cyclical pipelines'
+
+ context 'when ci_drop_cyclical_triggered_pipelines is not enabled' do
+ before do
+ stub_feature_flags(ci_drop_cyclical_triggered_pipelines: false)
+ end
+
+ it_behaves_like 'passes cyclical pipeline precondition'
+ end
end
- context 'when ci_drop_cyclical_triggered_pipelines is not enabled' do
+ context 'when source in the ancestry differ' do
before do
- stub_feature_flags(ci_drop_cyclical_triggered_pipelines: false)
+ # A(push on master) -> B(pipeline on master) -> A(pipeline on master)
+ pipeline_1 = create(:ci_pipeline, project: upstream_project, source: :push)
+ pipeline_2 = create(:ci_pipeline, project: downstream_project, source: :pipeline)
+ upstream_pipeline.update!(source: :pipeline)
+
+ create_source_pipeline(pipeline_1, pipeline_2)
+ create_source_pipeline(pipeline_2, upstream_pipeline)
end
- it 'creates a new pipeline' do
- expect { service.execute(bridge) }
- .to change { Ci::Pipeline.count }
+ it_behaves_like 'passes cyclical pipeline precondition'
+ end
+
+ context 'when ref in the ancestry differ' do
+ before do
+ # A(push on master) -> B(pipeline on master) -> A(push on feature-1)
+ pipeline_1 = create(:ci_pipeline, ref: 'master', project: upstream_project, source: :push)
+ pipeline_2 = create(:ci_pipeline, ref: 'master', project: downstream_project, source: :pipeline)
+ upstream_pipeline.update!(ref: 'feature-1')
+
+ create_source_pipeline(pipeline_1, pipeline_2)
+ create_source_pipeline(pipeline_2, upstream_pipeline)
end
- it 'expect bridge build not to be failed' do
- service.execute(bridge)
+ it_behaves_like 'passes cyclical pipeline precondition'
+ end
- expect(bridge.reload).not_to be_failed
+ context 'when only 1 cycle is detected' do
+ before do
+ # A(push on master) -> B(pipeline on master) -> A(push on master)
+ pipeline_1 = create(:ci_pipeline, ref: 'master', project: upstream_project, source: :push)
+ pipeline_2 = create(:ci_pipeline, ref: 'master', project: downstream_project, source: :pipeline)
+
+ create_source_pipeline(pipeline_1, pipeline_2)
+ create_source_pipeline(pipeline_2, upstream_pipeline)
end
+
+ it_behaves_like 'passes cyclical pipeline precondition'
end
end
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
index 26bc6f747e1..7365ad162d2 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -1043,22 +1043,6 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
expect(all_builds_names).to eq(%w[A1 A2 B])
expect(all_builds_statuses).to eq(%w[pending created created])
end
-
- context 'when the FF ci_order_subsequent_jobs_by_stage is disabled' do
- before do
- stub_feature_flags(ci_order_subsequent_jobs_by_stage: false)
- end
-
- it 'processes subsequent jobs in an incorrect order when playing first job' do
- expect(all_builds_names).to eq(%w[A1 A2 B])
- expect(all_builds_statuses).to eq(%w[manual skipped skipped])
-
- play_manual_action('A1')
-
- expect(all_builds_names).to eq(%w[A1 A2 B])
- expect(all_builds_statuses).to eq(%w[pending created skipped])
- end
- end
end
private
diff --git a/spec/services/ci/pipeline_schedule_service_spec.rb b/spec/services/ci/pipeline_schedule_service_spec.rb
index 65bbd13c5e7..b8e4fb19f5d 100644
--- a/spec/services/ci/pipeline_schedule_service_spec.rb
+++ b/spec/services/ci/pipeline_schedule_service_spec.rb
@@ -32,5 +32,22 @@ RSpec.describe Ci::PipelineScheduleService do
expect { subject }.not_to raise_error
end
end
+
+ context 'when the project is missing' do
+ before do
+ project.delete
+ end
+
+ it 'does not raise an exception' do
+ expect { subject }.not_to raise_error
+ end
+
+ it 'does not run RunPipelineScheduleWorker' do
+ expect(RunPipelineScheduleWorker)
+ .not_to receive(:perform_async).with(schedule.id, schedule.owner.id)
+
+ subject
+ end
+ end
end
end
diff --git a/spec/services/ci/process_sync_events_service_spec.rb b/spec/services/ci/process_sync_events_service_spec.rb
index 8b7717fe4bf..6b9717fe57d 100644
--- a/spec/services/ci/process_sync_events_service_spec.rb
+++ b/spec/services/ci/process_sync_events_service_spec.rb
@@ -25,6 +25,8 @@ RSpec.describe Ci::ProcessSyncEventsService do
project2.update!(group: parent_group_2)
end
+ it { is_expected.to eq(service_results(2, 2, 2)) }
+
it 'consumes events' do
expect { execute }.to change(Projects::SyncEvent, :count).from(2).to(0)
@@ -36,20 +38,32 @@ RSpec.describe Ci::ProcessSyncEventsService do
)
end
- it 'enqueues Projects::ProcessSyncEventsWorker if any left' do
- stub_const("#{described_class}::BATCH_SIZE", 1)
+ context 'when any event left after processing' do
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ end
- expect(Projects::ProcessSyncEventsWorker).to receive(:perform_async)
+ it { is_expected.to eq(service_results(2, 1, 1)) }
- execute
+ it 'enqueues Projects::ProcessSyncEventsWorker' do
+ expect(Projects::ProcessSyncEventsWorker).to receive(:perform_async)
+
+ execute
+ end
end
- it 'does not enqueue Projects::ProcessSyncEventsWorker if no left' do
- stub_const("#{described_class}::BATCH_SIZE", 2)
+ context 'when no event left after processing' do
+ before do
+ stub_const("#{described_class}::BATCH_SIZE", 2)
+ end
- expect(Projects::ProcessSyncEventsWorker).not_to receive(:perform_async)
+ it { is_expected.to eq(service_results(2, 2, 2)) }
- execute
+ it 'does not enqueue Projects::ProcessSyncEventsWorker' do
+ expect(Projects::ProcessSyncEventsWorker).not_to receive(:perform_async)
+
+ execute
+ end
end
context 'when there is no event' do
@@ -57,37 +71,45 @@ RSpec.describe Ci::ProcessSyncEventsService do
Projects::SyncEvent.delete_all
end
+ it { is_expected.to eq(service_results(0, 0, nil)) }
+
it 'does nothing' do
expect { execute }.not_to change(Projects::SyncEvent, :count)
end
end
- context 'when the FF ci_namespace_project_mirrors is disabled' do
+ context 'when there is non-executed events' do
before do
- stub_feature_flags(ci_namespace_project_mirrors: false)
- end
+ new_project = create(:project)
+ sync_event_class.delete_all
- it 'does nothing' do
- expect { execute }.not_to change(Projects::SyncEvent, :count)
- end
- end
+ project1.update!(group: parent_group_2)
+ new_project.update!(group: parent_group_1)
+ project2.update!(group: parent_group_1)
- it 'does not delete non-executed events' do
- new_project = create(:project)
- sync_event_class.delete_all
+ @new_project_sync_event = new_project.sync_events.last
- project1.update!(group: parent_group_2)
- new_project.update!(group: parent_group_1)
- project2.update!(group: parent_group_1)
+ allow(sync_event_class).to receive(:preload_synced_relation).and_return(
+ sync_event_class.where.not(id: @new_project_sync_event)
+ )
+ end
- new_project_sync_event = new_project.sync_events.last
+ it { is_expected.to eq(service_results(3, 2, 2)) }
- allow(sync_event_class).to receive(:preload_synced_relation).and_return(
- sync_event_class.where.not(id: new_project_sync_event)
- )
+ it 'does not delete non-executed events' do
+ expect { execute }.to change(Projects::SyncEvent, :count).from(3).to(1)
+ expect(@new_project_sync_event.reload).to be_persisted
+ end
+ end
+
+ private
- expect { execute }.to change(Projects::SyncEvent, :count).from(3).to(1)
- expect(new_project_sync_event.reload).to be_persisted
+ def service_results(total, consumable, processed)
+ {
+ estimated_total_events: total,
+ consumable_events: consumable,
+ processed_events: processed
+ }.compact
end
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 251159864f5..2127a4fa0fc 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -750,6 +750,8 @@ module Ci
context 'with ci_queuing_use_denormalized_data_strategy disabled' do
before do
+ skip_if_multiple_databases_are_setup
+
stub_feature_flags(ci_queuing_use_denormalized_data_strategy: false)
end
@@ -773,6 +775,8 @@ module Ci
context 'when not using pending builds table' do
before do
+ skip_if_multiple_databases_are_setup
+
stub_feature_flags(ci_pending_builds_queue_source: false)
end
diff --git a/spec/services/ci/register_runner_service_spec.rb b/spec/services/ci/register_runner_service_spec.rb
index e813a1d8b31..491582bbd13 100644
--- a/spec/services/ci/register_runner_service_spec.rb
+++ b/spec/services/ci/register_runner_service_spec.rb
@@ -2,8 +2,10 @@
require 'spec_helper'
-RSpec.describe ::Ci::RegisterRunnerService do
+RSpec.describe ::Ci::RegisterRunnerService, '#execute' do
let(:registration_token) { 'abcdefg123456' }
+ let(:token) { }
+ let(:args) { {} }
before do
stub_feature_flags(runner_registration_control: false)
@@ -11,213 +13,219 @@ RSpec.describe ::Ci::RegisterRunnerService do
stub_application_setting(valid_runner_registrars: ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES)
end
- describe '#execute' do
- let(:token) { }
- let(:args) { {} }
+ subject { described_class.new.execute(token, args) }
- subject { described_class.new.execute(token, args) }
+ context 'when no token is provided' do
+ let(:token) { '' }
- context 'when no token is provided' do
- let(:token) { '' }
-
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it 'returns nil' do
+ is_expected.to be_nil
end
+ end
- context 'when invalid token is provided' do
- let(:token) { 'invalid' }
+ context 'when invalid token is provided' do
+ let(:token) { 'invalid' }
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it 'returns nil' do
+ is_expected.to be_nil
end
+ end
- context 'when valid token is provided' do
- context 'with a registration token' do
- let(:token) { registration_token }
+ context 'when valid token is provided' do
+ context 'with a registration token' do
+ let(:token) { registration_token }
+
+ it 'creates runner with default values' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.persisted?).to be_truthy
+ expect(subject.run_untagged).to be true
+ expect(subject.active).to be true
+ expect(subject.token).not_to eq(registration_token)
+ expect(subject).to be_instance_type
+ end
- it 'creates runner with default values' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.persisted?).to be_truthy
- expect(subject.run_untagged).to be true
- expect(subject.active).to be true
- expect(subject.token).not_to eq(registration_token)
- expect(subject).to be_instance_type
- end
-
- context 'with non-default arguments' do
- let(:args) do
- {
- description: 'some description',
- active: false,
- locked: true,
- run_untagged: false,
- tag_list: %w(tag1 tag2),
- access_level: 'ref_protected',
- maximum_timeout: 600,
- name: 'some name',
- version: 'some version',
- revision: 'some revision',
- platform: 'some platform',
- architecture: 'some architecture',
- ip_address: '10.0.0.1',
- config: {
- gpus: 'some gpu config'
- }
+ context 'with non-default arguments' do
+ let(:args) do
+ {
+ description: 'some description',
+ active: false,
+ locked: true,
+ run_untagged: false,
+ tag_list: %w(tag1 tag2),
+ access_level: 'ref_protected',
+ maximum_timeout: 600,
+ name: 'some name',
+ version: 'some version',
+ revision: 'some revision',
+ platform: 'some platform',
+ architecture: 'some architecture',
+ ip_address: '10.0.0.1',
+ config: {
+ gpus: 'some gpu config'
}
- end
+ }
+ end
- it 'creates runner with specified values', :aggregate_failures do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.active).to eq args[:active]
- expect(subject.locked).to eq args[:locked]
- expect(subject.run_untagged).to eq args[:run_untagged]
- expect(subject.tags).to contain_exactly(
- an_object_having_attributes(name: 'tag1'),
- an_object_having_attributes(name: 'tag2')
- )
- expect(subject.access_level).to eq args[:access_level]
- expect(subject.maximum_timeout).to eq args[:maximum_timeout]
- expect(subject.name).to eq args[:name]
- expect(subject.version).to eq args[:version]
- expect(subject.revision).to eq args[:revision]
- expect(subject.platform).to eq args[:platform]
- expect(subject.architecture).to eq args[:architecture]
- expect(subject.ip_address).to eq args[:ip_address]
- end
+ it 'creates runner with specified values', :aggregate_failures do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.active).to eq args[:active]
+ expect(subject.locked).to eq args[:locked]
+ expect(subject.run_untagged).to eq args[:run_untagged]
+ expect(subject.tags).to contain_exactly(
+ an_object_having_attributes(name: 'tag1'),
+ an_object_having_attributes(name: 'tag2')
+ )
+ expect(subject.access_level).to eq args[:access_level]
+ expect(subject.maximum_timeout).to eq args[:maximum_timeout]
+ expect(subject.name).to eq args[:name]
+ expect(subject.version).to eq args[:version]
+ expect(subject.revision).to eq args[:revision]
+ expect(subject.platform).to eq args[:platform]
+ expect(subject.architecture).to eq args[:architecture]
+ expect(subject.ip_address).to eq args[:ip_address]
end
end
- context 'when project token is used' do
- let(:project) { create(:project) }
- let(:token) { project.runners_token }
+ context 'with runner token expiration interval', :freeze_time do
+ before do
+ stub_application_setting(runner_token_expiration_interval: 5.days)
+ end
- it 'creates project runner' do
+ it 'creates runner with token expiration' do
is_expected.to be_an_instance_of(::Ci::Runner)
- expect(project.runners.size).to eq(1)
- is_expected.to eq(project.runners.first)
- expect(subject.token).not_to eq(registration_token)
- expect(subject.token).not_to eq(project.runners_token)
- expect(subject).to be_project_type
+ expect(subject.token_expires_at).to eq(5.days.from_now)
end
+ end
+ end
- context 'when it exceeds the application limits' do
- before do
- create(:ci_runner, runner_type: :project_type, projects: [project], contacted_at: 1.second.ago)
- create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
- end
+ context 'when project token is used' do
+ let(:project) { create(:project) }
+ let(:token) { project.runners_token }
+
+ it 'creates project runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(project.runners.size).to eq(1)
+ is_expected.to eq(project.runners.first)
+ expect(subject.token).not_to eq(registration_token)
+ expect(subject.token).not_to eq(project.runners_token)
+ expect(subject).to be_project_type
+ end
- it 'does not create runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.persisted?).to be_falsey
- expect(subject.errors.messages).to eq('runner_projects.base': ['Maximum number of ci registered project runners (1) exceeded'])
- expect(project.runners.reload.size).to eq(1)
- end
+ context 'when it exceeds the application limits' do
+ before do
+ create(:ci_runner, runner_type: :project_type, projects: [project], contacted_at: 1.second.ago)
+ create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
end
- context 'when abandoned runners cause application limits to not be exceeded' do
- before do
- create(:ci_runner, runner_type: :project_type, projects: [project], created_at: 14.months.ago, contacted_at: 13.months.ago)
- create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
- end
+ it 'does not create runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.persisted?).to be_falsey
+ expect(subject.errors.messages).to eq('runner_projects.base': ['Maximum number of ci registered project runners (1) exceeded'])
+ expect(project.runners.reload.size).to eq(1)
+ end
+ end
- it 'creates runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.errors).to be_empty
- expect(project.runners.reload.size).to eq(2)
- expect(project.runners.recent.size).to eq(1)
- end
+ context 'when abandoned runners cause application limits to not be exceeded' do
+ before do
+ create(:ci_runner, runner_type: :project_type, projects: [project], created_at: 14.months.ago, contacted_at: 13.months.ago)
+ create(:plan_limits, :default_plan, ci_registered_project_runners: 1)
end
- context 'when valid runner registrars do not include project' do
+ it 'creates runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.errors).to be_empty
+ expect(project.runners.reload.size).to eq(2)
+ expect(project.runners.recent.size).to eq(1)
+ end
+ end
+
+ context 'when valid runner registrars do not include project' do
+ before do
+ stub_application_setting(valid_runner_registrars: ['group'])
+ end
+
+ context 'when feature flag is enabled' do
before do
- stub_application_setting(valid_runner_registrars: ['group'])
+ stub_feature_flags(runner_registration_control: true)
end
- context 'when feature flag is enabled' do
- before do
- stub_feature_flags(runner_registration_control: true)
- end
-
- it 'returns 403 error' do
- is_expected.to be_nil
- end
+ it 'returns 403 error' do
+ is_expected.to be_nil
end
+ end
- context 'when feature flag is disabled' do
- it 'registers the runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.errors).to be_empty
- expect(subject.active).to be true
- end
+ context 'when feature flag is disabled' do
+ it 'registers the runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.errors).to be_empty
+ expect(subject.active).to be true
end
end
end
+ end
+
+ context 'when group token is used' do
+ let(:group) { create(:group) }
+ let(:token) { group.runners_token }
+
+ it 'creates a group runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.errors).to be_empty
+ expect(group.runners.reload.size).to eq(1)
+ expect(subject.token).not_to eq(registration_token)
+ expect(subject.token).not_to eq(group.runners_token)
+ expect(subject).to be_group_type
+ end
- context 'when group token is used' do
- let(:group) { create(:group) }
- let(:token) { group.runners_token }
+ context 'when it exceeds the application limits' do
+ before do
+ create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 1.month.ago)
+ create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
+ end
- it 'creates a group runner' do
+ it 'does not create runner' do
is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.errors).to be_empty
+ expect(subject.persisted?).to be_falsey
+ expect(subject.errors.messages).to eq('runner_namespaces.base': ['Maximum number of ci registered group runners (1) exceeded'])
expect(group.runners.reload.size).to eq(1)
- expect(subject.token).not_to eq(registration_token)
- expect(subject.token).not_to eq(group.runners_token)
- expect(subject).to be_group_type
end
+ end
- context 'when it exceeds the application limits' do
- before do
- create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 1.month.ago)
- create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
- end
-
- it 'does not create runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.persisted?).to be_falsey
- expect(subject.errors.messages).to eq('runner_namespaces.base': ['Maximum number of ci registered group runners (1) exceeded'])
- expect(group.runners.reload.size).to eq(1)
- end
+ context 'when abandoned runners cause application limits to not be exceeded' do
+ before do
+ create(:ci_runner, runner_type: :group_type, groups: [group], created_at: 4.months.ago, contacted_at: 3.months.ago)
+ create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 4.months.ago)
+ create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
end
- context 'when abandoned runners cause application limits to not be exceeded' do
- before do
- create(:ci_runner, runner_type: :group_type, groups: [group], created_at: 4.months.ago, contacted_at: 3.months.ago)
- create(:ci_runner, runner_type: :group_type, groups: [group], contacted_at: nil, created_at: 4.months.ago)
- create(:plan_limits, :default_plan, ci_registered_group_runners: 1)
- end
+ it 'creates runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.errors).to be_empty
+ expect(group.runners.reload.size).to eq(3)
+ expect(group.runners.recent.size).to eq(1)
+ end
+ end
- it 'creates runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.errors).to be_empty
- expect(group.runners.reload.size).to eq(3)
- expect(group.runners.recent.size).to eq(1)
- end
+ context 'when valid runner registrars do not include group' do
+ before do
+ stub_application_setting(valid_runner_registrars: ['project'])
end
- context 'when valid runner registrars do not include group' do
+ context 'when feature flag is enabled' do
before do
- stub_application_setting(valid_runner_registrars: ['project'])
+ stub_feature_flags(runner_registration_control: true)
end
- context 'when feature flag is enabled' do
- before do
- stub_feature_flags(runner_registration_control: true)
- end
-
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it 'returns nil' do
+ is_expected.to be_nil
end
+ end
- context 'when feature flag is disabled' do
- it 'registers the runner' do
- is_expected.to be_an_instance_of(::Ci::Runner)
- expect(subject.errors).to be_empty
- expect(subject.active).to be true
- end
+ context 'when feature flag is disabled' do
+ it 'registers the runner' do
+ is_expected.to be_an_instance_of(::Ci::Runner)
+ expect(subject.errors).to be_empty
+ expect(subject.active).to be true
end
end
end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 4e8e41ca6e6..2421fd56c47 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -60,7 +60,8 @@ RSpec.describe Ci::RetryBuildService do
artifacts_file artifacts_metadata artifacts_size commands
resource resource_group_id processed security_scans author
pipeline_id report_results pending_state pages_deployments
- queuing_entry runtime_metadata trace_metadata].freeze
+ queuing_entry runtime_metadata trace_metadata
+ dast_site_profile dast_scanner_profile].freeze
shared_examples 'build duplication' do
let_it_be(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
@@ -370,23 +371,6 @@ RSpec.describe Ci::RetryBuildService do
it_behaves_like 'when build with deployment is retried'
it_behaves_like 'when build with dynamic environment is retried'
- context 'when create_deployment_in_separate_transaction feature flag is disabled' do
- let(:new_build) do
- travel_to(1.second.from_now) do
- ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.allow_cross_database_modification_within_transaction(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/345668') do
- service.clone!(build)
- end
- end
- end
-
- before do
- stub_feature_flags(create_deployment_in_separate_transaction: false)
- end
-
- it_behaves_like 'when build with deployment is retried'
- it_behaves_like 'when build with dynamic environment is retried'
- end
-
context 'when build has needs' do
before do
create(:ci_build_need, build: build, name: 'build1')
diff --git a/spec/services/ci/unregister_runner_service_spec.rb b/spec/services/ci/unregister_runner_service_spec.rb
new file mode 100644
index 00000000000..f427e04f228
--- /dev/null
+++ b/spec/services/ci/unregister_runner_service_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Ci::UnregisterRunnerService, '#execute' do
+ subject { described_class.new(runner).execute }
+
+ let(:runner) { create(:ci_runner) }
+
+ it 'destroys runner' do
+ expect(runner).to receive(:destroy).once.and_call_original
+ expect { subject }.to change { Ci::Runner.count }.by(-1)
+ expect(runner[:errors]).to be_nil
+ end
+end
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index 2e2ef120f1b..ef43866d8d4 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -308,36 +308,12 @@ RSpec.describe Ci::UpdateBuildQueueService do
let!(:build) { create(:ci_build, pipeline: pipeline, tag_list: %w[a b]) }
let!(:project_runner) { create(:ci_runner, :project, :online, projects: [project], tag_list: %w[a b c]) }
- context 'when ci_preload_runner_tags is enabled' do
- before do
- stub_feature_flags(
- ci_preload_runner_tags: true
- )
- end
-
- it 'does execute the same amount of queries regardless of number of runners' do
- control_count = ActiveRecord::QueryRecorder.new { subject.tick(build) }.count
-
- create_list(:ci_runner, 10, :project, :online, projects: [project], tag_list: %w[b c d])
-
- expect { subject.tick(build) }.not_to exceed_all_query_limit(control_count)
- end
- end
-
- context 'when ci_preload_runner_tags are disabled' do
- before do
- stub_feature_flags(
- ci_preload_runner_tags: false
- )
- end
-
- it 'does execute more queries for more runners' do
- control_count = ActiveRecord::QueryRecorder.new { subject.tick(build) }.count
+ it 'does execute the same amount of queries regardless of number of runners' do
+ control_count = ActiveRecord::QueryRecorder.new { subject.tick(build) }.count
- create_list(:ci_runner, 10, :project, :online, projects: [project], tag_list: %w[b c d])
+ create_list(:ci_runner, 10, :project, :online, projects: [project], tag_list: %w[b c d])
- expect { subject.tick(build) }.to exceed_all_query_limit(control_count)
- end
+ expect { subject.tick(build) }.not_to exceed_all_query_limit(control_count)
end
end
end
diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb
index 1c875b2f54a..eee80bfef47 100644
--- a/spec/services/ci/update_runner_service_spec.rb
+++ b/spec/services/ci/update_runner_service_spec.rb
@@ -23,6 +23,20 @@ RSpec.describe Ci::UpdateRunnerService do
end
end
+ context 'with paused param' do
+ let(:params) { { paused: true } }
+
+ it 'updates the runner and ticking the queue' do
+ expect(runner.active).to be_truthy
+ expect(update).to be_truthy
+
+ runner.reload
+
+ expect(runner).to have_received(:tick_runner_queue)
+ expect(runner.active).to be_falsey
+ end
+ end
+
context 'with cost factor params' do
let(:params) { { public_projects_minutes_cost_factor: 1.1, private_projects_minutes_cost_factor: 2.2 }}