summaryrefslogtreecommitdiff
path: root/spec/services/ci
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-12-20 14:22:11 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-12-20 14:22:11 +0000
commit0c872e02b2c822e3397515ec324051ff540f0cd5 (patch)
treece2fb6ce7030e4dad0f4118d21ab6453e5938cdd /spec/services/ci
parentf7e05a6853b12f02911494c4b3fe53d9540d74fc (diff)
downloadgitlab-ce-0c872e02b2c822e3397515ec324051ff540f0cd5.tar.gz
Add latest changes from gitlab-org/gitlab@15-7-stable-eev15.7.0-rc42
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/append_build_trace_service_spec.rb32
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb237
-rw-r--r--spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/environment_spec.rb18
-rw-r--r--spec/services/ci/create_pipeline_service/logger_spec.rb43
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/partitioning_spec.rb21
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb8
-rw-r--r--spec/services/ci/create_pipeline_service/scripts_spec.rb112
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb33
-rw-r--r--spec/services/ci/enqueue_job_service_spec.rb81
-rw-r--r--spec/services/ci/generate_kubeconfig_service_spec.rb110
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb2
-rw-r--r--spec/services/ci/pipeline_schedules/calculate_next_run_service_spec.rb107
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb3
-rw-r--r--spec/services/ci/pipelines/add_job_service_spec.rb4
-rw-r--r--spec/services/ci/process_build_service_spec.rb72
-rw-r--r--spec/services/ci/reset_skipped_jobs_service_spec.rb (renamed from spec/services/ci/after_requeue_job_service_spec.rb)18
-rw-r--r--spec/services/ci/retry_job_service_spec.rb45
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb5
-rw-r--r--spec/services/ci/runners/assign_runner_service_spec.rb2
-rw-r--r--spec/services/ci/runners/bulk_delete_runners_service_spec.rb2
-rw-r--r--spec/services/ci/runners/process_runner_version_update_service_spec.rb2
-rw-r--r--spec/services/ci/runners/reconcile_existing_runner_versions_service_spec.rb2
-rw-r--r--spec/services/ci/runners/register_runner_service_spec.rb2
-rw-r--r--spec/services/ci/runners/reset_registration_token_service_spec.rb2
-rw-r--r--spec/services/ci/runners/set_runner_associated_projects_service_spec.rb2
-rw-r--r--spec/services/ci/runners/unassign_runner_service_spec.rb2
-rw-r--r--spec/services/ci/runners/unregister_runner_service_spec.rb2
-rw-r--r--spec/services/ci/runners/update_runner_service_spec.rb2
-rw-r--r--spec/services/ci/test_failure_history_service_spec.rb37
-rw-r--r--spec/services/ci/track_failed_build_service_spec.rb23
-rw-r--r--spec/services/ci/unlock_artifacts_service_spec.rb27
33 files changed, 768 insertions, 294 deletions
diff --git a/spec/services/ci/append_build_trace_service_spec.rb b/spec/services/ci/append_build_trace_service_spec.rb
index 487dbacbe90..20f7967d1f1 100644
--- a/spec/services/ci/append_build_trace_service_spec.rb
+++ b/spec/services/ci/append_build_trace_service_spec.rb
@@ -76,4 +76,36 @@ RSpec.describe Ci::AppendBuildTraceService do
expect(build.failure_reason).to eq 'trace_size_exceeded'
end
end
+
+ context 'when debug_trace param is provided' do
+ let(:metadata) { Ci::BuildMetadata.find_by(build_id: build) }
+ let(:stream_size) { 192.kilobytes }
+ let(:body_data) { 'x' * stream_size }
+ let(:content_range) { "#{body_start}-#{stream_size}" }
+
+ context 'when sending the first trace' do
+ let(:body_start) { 0 }
+
+ it 'updates build metadata debug_trace_enabled' do
+ described_class
+ .new(build, content_range: content_range, debug_trace: true)
+ .execute(body_data)
+
+ expect(metadata.debug_trace_enabled).to be(true)
+ end
+ end
+
+ context 'when sending the second trace' do
+ let(:body_start) { 1 }
+
+ it 'does not update build metadata debug_trace_enabled', :aggregate_failures do
+ query_recorder = ActiveRecord::QueryRecorder.new do
+ described_class.new(build, content_range: content_range, debug_trace: true).execute(body_data)
+ end
+
+ expect(metadata.debug_trace_enabled).to be(false)
+ expect(query_recorder.log).not_to include(/p_ci_builds_metadata/)
+ end
+ 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 9c02c5218f1..bcdb2b4f796 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
+RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category: :continuous_integration do
include Ci::SourcePipelineHelpers
# Using let_it_be on user and projects for these specs can cause
@@ -13,7 +13,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
let(:downstream_project) { create(:project, :repository) }
let!(:upstream_pipeline) do
- create(:ci_pipeline, :running, project: upstream_project)
+ create(:ci_pipeline, :created, project: upstream_project)
end
let(:trigger) do
@@ -33,6 +33,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
let(:service) { described_class.new(upstream_project, user) }
+ let(:pipeline) { subject.payload }
before do
upstream_project.add_developer(user)
@@ -40,6 +41,12 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
subject { service.execute(bridge) }
+ shared_context 'when ci_bridge_remove_sourced_pipelines is disabled' do
+ before do
+ stub_feature_flags(ci_bridge_remove_sourced_pipelines: false)
+ end
+ end
+
context 'when downstream project has not been found' do
let(:trigger) do
{ trigger: { project: 'unknown/project' } }
@@ -48,6 +55,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
end
it 'changes pipeline bridge job status to failed' do
@@ -63,9 +72,11 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a new pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
end
- it 'changes status of the bridge build' do
+ it 'changes status of the bridge build to failed' do
subject
expect(bridge.reload).to be_failed
@@ -82,9 +93,11 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a new pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
end
- it 'changes status of the bridge build' do
+ it 'changes status of the bridge build to failed' do
subject
expect(bridge.reload).to be_failed
@@ -103,35 +116,51 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates only one new pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
end
it 'creates a new pipeline in a downstream project' do
- pipeline = subject
-
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq downstream_project
- expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
end
+ context 'when ci_bridge_remove_sourced_pipelines is disabled' do
+ include_context 'when ci_bridge_remove_sourced_pipelines is disabled'
+
+ it 'creates a new pipeline in a downstream project' do
+ expect(pipeline.user).to eq bridge.user
+ expect(pipeline.project).to eq downstream_project
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
+ expect(pipeline.source_bridge).to eq bridge
+ expect(pipeline.source_bridge).to be_a ::Ci::Bridge
+ end
+ end
+
it_behaves_like 'logs downstream pipeline creation' do
+ let(:downstream_pipeline) { pipeline }
let(:expected_root_pipeline) { upstream_pipeline }
let(:expected_hierarchy_size) { 2 }
let(:expected_downstream_relationship) { :multi_project }
end
it 'updates bridge status when downstream pipeline gets processed' do
- pipeline = subject
-
expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
- context 'when bridge job has already any downstream pipelines' do
+ it 'triggers the upstream pipeline duration calculation', :sidekiq_inline do
+ expect { subject }
+ .to change { upstream_pipeline.reload.duration }.from(nil).to(an_instance_of(Integer))
+ end
+
+ context 'when bridge job has already any downstream pipeline' do
before do
- bridge.sourced_pipelines.create!(
+ bridge.create_sourced_pipeline!(
source_pipeline: bridge.pipeline,
source_project: bridge.project,
project: bridge.project,
@@ -147,7 +176,33 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
bridge_id: bridge.id, project_id: bridge.project.id)
.and_call_original
expect(Ci::CreatePipelineService).not_to receive(:new)
- expect(subject).to eq({ message: "Already has a downstream pipeline", status: :error })
+ expect(subject).to be_error
+ expect(subject.message).to eq("Already has a downstream pipeline")
+ end
+
+ context 'when ci_bridge_remove_sourced_pipelines is disabled' do
+ include_context 'when ci_bridge_remove_sourced_pipelines is disabled'
+
+ before do
+ bridge.sourced_pipelines.create!(
+ source_pipeline: bridge.pipeline,
+ source_project: bridge.project,
+ project: bridge.project,
+ pipeline: create(:ci_pipeline, project: bridge.project)
+ )
+ end
+
+ it 'logs an error and exits' do
+ expect(Gitlab::ErrorTracking)
+ .to receive(:track_exception)
+ .with(
+ instance_of(described_class::DuplicateDownstreamPipelineError),
+ bridge_id: bridge.id, project_id: bridge.project.id)
+ .and_call_original
+ expect(Ci::CreatePipelineService).not_to receive(:new)
+ expect(subject).to be_error
+ expect(subject.message).to eq("Already has a downstream pipeline")
+ end
end
end
@@ -157,8 +212,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
it 'is using default branch name' do
- pipeline = subject
-
expect(pipeline.ref).to eq 'master'
end
end
@@ -171,22 +224,33 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates only one new pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_error
+ expect(subject.message).to match_array(["jobs job config should implement a script: or a trigger: keyword"])
end
it 'creates a new pipeline in a downstream project' do
- pipeline = subject
-
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq downstream_project
- expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
end
- it 'updates the bridge status when downstream pipeline gets processed' do
- pipeline = subject
+ context 'when ci_bridge_remove_sourced_pipelines is disabled' do
+ include_context 'when ci_bridge_remove_sourced_pipelines is disabled'
+
+ it 'creates a new pipeline in a downstream project' do
+ expect(pipeline.user).to eq bridge.user
+ expect(pipeline.project).to eq downstream_project
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
+ expect(pipeline.source_bridge).to eq bridge
+ expect(pipeline.source_bridge).to be_a ::Ci::Bridge
+ end
+ end
+ it 'updates the bridge status when downstream pipeline gets processed' do
expect(pipeline.reload).to be_failed
expect(bridge.reload).to be_failed
end
@@ -201,6 +265,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a new pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
end
it 'changes status of the bridge build' do
@@ -222,32 +288,39 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates only one new pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
end
it 'creates a child pipeline in the same project' do
- pipeline = subject
- pipeline.reload
-
expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo])
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq bridge.project
- expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(bridge.reload.sourced_pipeline.pipeline).to eq pipeline
expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
expect(pipeline.source_bridge).to eq bridge
expect(pipeline.source_bridge).to be_a ::Ci::Bridge
end
- it 'updates bridge status when downstream pipeline gets processed' do
- pipeline = subject
+ context 'when ci_bridge_remove_sourced_pipelines is disabled' do
+ include_context 'when ci_bridge_remove_sourced_pipelines is disabled'
+
+ it 'creates a child pipeline in the same project' do
+ expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo])
+ expect(pipeline.user).to eq bridge.user
+ expect(pipeline.project).to eq bridge.project
+ expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
+ expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline
+ expect(pipeline.source_bridge).to eq bridge
+ expect(pipeline.source_bridge).to be_a ::Ci::Bridge
+ end
+ end
+ it 'updates bridge status when downstream pipeline gets processed' do
expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
it 'propagates parent pipeline settings to the child pipeline' do
- pipeline = subject
- pipeline.reload
-
expect(pipeline.ref).to eq(upstream_pipeline.ref)
expect(pipeline.sha).to eq(upstream_pipeline.sha)
expect(pipeline.source_sha).to eq(upstream_pipeline.source_sha)
@@ -276,6 +349,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it_behaves_like 'creates a child pipeline'
it_behaves_like 'logs downstream pipeline creation' do
+ let(:downstream_pipeline) { pipeline }
let(:expected_root_pipeline) { upstream_pipeline }
let(:expected_hierarchy_size) { 2 }
let(:expected_downstream_relationship) { :parent_child }
@@ -283,6 +357,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'updates the bridge job to success' do
expect { subject }.to change { bridge.status }.to 'success'
+ expect(subject).to be_success
end
context 'when bridge uses "depend" strategy' do
@@ -292,8 +367,9 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
}
end
- it 'does not update the bridge job status' do
- expect { subject }.not_to change { bridge.status }
+ it 'update the bridge job to running status' do
+ expect { subject }.to change { bridge.status }.from('pending').to('running')
+ expect(subject).to be_success
end
end
@@ -323,8 +399,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it_behaves_like 'creates a child pipeline'
it 'propagates the merge request to the child pipeline' do
- pipeline = subject
-
expect(pipeline.merge_request).to eq(merge_request)
expect(pipeline).to be_merge_request
end
@@ -341,11 +415,13 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates the pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
expect(bridge.reload).to be_success
end
it_behaves_like 'logs downstream pipeline creation' do
+ let(:downstream_pipeline) { pipeline }
let(:expected_root_pipeline) { upstream_pipeline.parent_pipeline }
let(:expected_hierarchy_size) { 3 }
let(:expected_downstream_relationship) { :parent_child }
@@ -394,6 +470,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'create the pipeline' do
expect { subject }.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
end
end
@@ -406,11 +483,10 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates a new pipeline allowing variables to be passed downstream' do
expect { subject }.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
end
it 'passes variables downstream from the bridge' do
- pipeline = subject
-
pipeline.variables.map(&:key).tap do |variables|
expect(variables).to include 'BRIDGE'
end
@@ -466,6 +542,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a new pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
end
it 'changes status of the bridge build' do
@@ -480,6 +558,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates a new pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }
+ expect(subject).to be_success
end
it 'expect bridge build not to be failed' do
@@ -559,18 +638,16 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates only one new pipeline' do
expect { subject }
.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_error
+ expect(subject.message).to match_array(["jobs invalid config should implement a script: or a trigger: keyword"])
end
it 'creates a new pipeline in the downstream project' do
- pipeline = subject
-
expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq downstream_project
end
it 'drops the bridge' do
- pipeline = subject
-
expect(pipeline.reload).to be_failed
expect(bridge.reload).to be_failed
expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed')
@@ -585,15 +662,10 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
bridge.drop!
end
- it 'tracks the exception' do
- expect(Gitlab::ErrorTracking)
- .to receive(:track_exception)
- .with(
- instance_of(Ci::Bridge::InvalidTransitionError),
- bridge_id: bridge.id,
- downstream_pipeline_id: kind_of(Numeric))
-
- subject
+ it 'returns the error' do
+ expect { subject }.not_to change(downstream_project.ci_pipelines, :count)
+ expect(subject).to be_error
+ expect(subject.message).to eq('Can not run the bridge')
end
end
@@ -603,8 +675,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
it 'passes bridge variables to downstream pipeline' do
- pipeline = subject
-
expect(pipeline.variables.first)
.to have_attributes(key: 'BRIDGE', value: 'var')
end
@@ -616,8 +686,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
it 'does not pass pipeline variables directly downstream' do
- pipeline = subject
-
pipeline.variables.map(&:key).tap do |variables|
expect(variables).not_to include 'PIPELINE_VARIABLE'
end
@@ -629,8 +697,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
end
it 'makes it possible to pass pipeline variable downstream' do
- pipeline = subject
-
pipeline.variables.find_by(key: 'BRIDGE').tap do |variable|
expect(variable.value).to eq 'my-value-var'
end
@@ -644,11 +710,11 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a new pipeline' do
expect { subject }
.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to match_array(["Insufficient permissions to set pipeline variables"])
end
it 'ignores variables passed downstream from the bridge' do
- pipeline = subject
-
pipeline.variables.map(&:key).tap do |variables|
expect(variables).not_to include 'BRIDGE'
end
@@ -668,7 +734,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
# TODO: Move this context into a feature spec that uses
# multiple pipeline processing services. Location TBD in:
# https://gitlab.com/gitlab-org/gitlab/issues/36216
- context 'when configured with bridge job rules' do
+ context 'when configured with bridge job rules', :sidekiq_inline do
before do
stub_ci_pipeline_yaml_file(config)
downstream_project.add_maintainer(upstream_project.first_owner)
@@ -701,6 +767,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates the downstream pipeline' do
expect { subject }
.to change(downstream_project.ci_pipelines, :count).by(1)
+ expect(subject).to be_error
+ expect(subject.message).to eq("Already has a downstream pipeline")
end
end
end
@@ -731,6 +799,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a pipeline and drops the bridge' do
expect { subject }.not_to change(downstream_project.ci_pipelines, :count)
+ expect(subject).to be_error
+ expect(subject.message).to match_array(["Reference not found"])
expect(bridge.reload).to be_failed
expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed')
@@ -754,6 +824,8 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'does not create a pipeline and drops the bridge' do
expect { subject }.not_to change(downstream_project.ci_pipelines, :count)
+ expect(subject).to be_error
+ expect(subject.message).to match_array(["No stages / jobs for this pipeline."])
expect(bridge.reload).to be_failed
expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed')
@@ -776,6 +848,10 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates the pipeline but drops the bridge' do
expect { subject }.to change(downstream_project.ci_pipelines, :count).by(1)
+ expect(subject).to be_error
+ expect(subject.message).to eq(
+ ["test job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post"]
+ )
expect(bridge.reload).to be_failed
expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed')
@@ -808,6 +884,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates the pipeline' do
expect { subject }.to change(downstream_project.ci_pipelines, :count).by(1)
+ expect(subject).to be_success
expect(bridge.reload).to be_success
end
@@ -822,6 +899,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
context 'when a downstream pipeline has sibling pipelines' do
it_behaves_like 'logs downstream pipeline creation' do
+ let(:downstream_pipeline) { pipeline }
let(:expected_root_pipeline) { upstream_pipeline }
let(:expected_downstream_relationship) { :multi_project }
@@ -839,23 +917,47 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
let_it_be(:child) { create(:ci_pipeline, child_of: parent) }
let_it_be(:sibling) { create(:ci_pipeline, child_of: parent) }
- before do
- stub_const("#{described_class}::MAX_HIERARCHY_SIZE", 3)
- end
-
+ let(:project) { build(:project, :repository) }
let(:bridge) do
- create(:ci_bridge, status: :pending, user: user, options: trigger, pipeline: child)
+ create(:ci_bridge, status: :pending, user: user, options: trigger, pipeline: child, project: project)
end
- it 'does not create a new pipeline' do
- expect { subject }.not_to change { Ci::Pipeline.count }
+ context 'when limit was specified by admin' do
+ before do
+ project.actual_limits.update!(pipeline_hierarchy_size: 3)
+ end
+
+ it 'does not create a new pipeline' do
+ expect { subject }.not_to change { Ci::Pipeline.count }
+ end
+
+ it 'drops the trigger job with an explanatory reason' do
+ subject
+
+ expect(bridge.reload).to be_failed
+ expect(bridge.failure_reason).to eq('reached_max_pipeline_hierarchy_size')
+ end
end
- it 'drops the trigger job with an explanatory reason' do
- subject
+ context 'when there was no limit specified by admin' do
+ before do
+ allow(bridge.pipeline).to receive(:complete_hierarchy_count).and_return(1000)
+ end
- expect(bridge.reload).to be_failed
- expect(bridge.failure_reason).to eq('reached_max_pipeline_hierarchy_size')
+ context 'when pipeline count reaches the default limit of 1000' do
+ it 'does not create a new pipeline' do
+ expect { subject }.not_to change { Ci::Pipeline.count }
+ expect(subject).to be_error
+ expect(subject.message).to eq("Pre-conditions not met")
+ end
+
+ it 'drops the trigger job with an explanatory reason' do
+ subject
+
+ expect(bridge.reload).to be_failed
+ expect(bridge.failure_reason).to eq('reached_max_pipeline_hierarchy_size')
+ end
+ end
end
context 'with :ci_limit_complete_hierarchy_size disabled' do
@@ -865,6 +967,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'creates a new pipeline' do
expect { subject }.to change { Ci::Pipeline.count }.by(1)
+ expect(subject).to be_success
end
it 'marks the bridge job as successful' do
diff --git a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
index 74d3534eb45..0d5017a763f 100644
--- a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
pipeline = create_pipeline!
test = pipeline.statuses.find_by(name: 'instrumentation_test')
- expect(test).to be_pending
+ expect(test).to be_running
expect(pipeline.triggered_pipelines.count).to eq(1)
end
diff --git a/spec/services/ci/create_pipeline_service/environment_spec.rb b/spec/services/ci/create_pipeline_service/environment_spec.rb
index 438cb6ac895..b713cad2cad 100644
--- a/spec/services/ci/create_pipeline_service/environment_spec.rb
+++ b/spec/services/ci/create_pipeline_service/environment_spec.rb
@@ -46,6 +46,24 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
+ context 'when branch pipeline creates a dynamic environment' do
+ before do
+ config = YAML.dump(
+ review_app: {
+ script: 'echo',
+ environment: { name: "review/$CI_COMMIT_REF_NAME" }
+ })
+
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ it 'does not associate merge request with the environment' do
+ is_expected.to be_created_successfully
+
+ expect(Environment.find_by_name('review/master').merge_request).to be_nil
+ end
+ end
+
context 'when variables are dependent on stage name' do
let(:config) do
<<~YAML
diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb
index 3045f8e92b1..ccb15bfa684 100644
--- a/spec/services/ci/create_pipeline_service/logger_spec.rb
+++ b/spec/services/ci/create_pipeline_service/logger_spec.rb
@@ -2,8 +2,10 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
- context 'pipeline logger' do
+RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath
+ :yaml_processor_feature_flag_corectness,
+ feature_category: :continuous_integration do
+ describe 'pipeline logger' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -12,17 +14,11 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
let(:pipeline) { service.execute(:push).payload }
let(:file_location) { 'spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml' }
- before do
- stub_ci_pipeline_yaml_file(gitlab_ci_yaml)
- end
-
let(:counters) do
{
'count' => a_kind_of(Numeric),
- 'avg' => a_kind_of(Numeric),
- 'sum' => a_kind_of(Numeric),
'max' => a_kind_of(Numeric),
- 'min' => a_kind_of(Numeric)
+ 'sum' => a_kind_of(Numeric)
}
end
@@ -34,15 +30,22 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
'pipeline_persisted' => true,
'project_id' => project.id,
'pipeline_creation_service_duration_s' => a_kind_of(Numeric),
- 'pipeline_creation_duration_s' => counters,
- 'pipeline_size_count' => counters,
- 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => counters,
+ 'pipeline_creation_duration_s' => a_kind_of(Numeric),
+ 'pipeline_size_count' => a_kind_of(Numeric),
+ 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => a_kind_of(Numeric),
'pipeline_seed_build_inclusion_duration_s' => counters,
+ 'pipeline_seed_build_errors_duration_s' => counters,
+ 'pipeline_seed_build_to_resource_duration_s' => counters,
+ 'pipeline_seed_stage_seeds_duration_s' => counters,
'pipeline_builds_tags_count' => a_kind_of(Numeric),
'pipeline_builds_distinct_tags_count' => a_kind_of(Numeric)
}
end
+ before do
+ stub_ci_pipeline_yaml_file(gitlab_ci_yaml)
+ end
+
context 'when the duration is under the threshold' do
it 'does not create a log entry but it collects the data' do
expect(Gitlab::AppJsonLogger).not_to receive(:info)
@@ -51,9 +54,9 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
expect(service.logger.observations_hash)
.to match(
a_hash_including(
- 'pipeline_creation_duration_s' => counters,
- 'pipeline_size_count' => counters,
- 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => counters
+ 'pipeline_creation_duration_s' => a_kind_of(Numeric),
+ 'pipeline_size_count' => a_kind_of(Numeric),
+ 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => a_kind_of(Numeric)
)
)
end
@@ -62,7 +65,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when the durations exceeds the threshold' do
let(:timer) do
proc do
- @timer = @timer.to_i + 30
+ @timer = @timer.to_i + 30 # rubocop: disable RSpec/InstanceVariable
end
end
@@ -88,17 +91,15 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
'pipeline_persisted' => false,
'project_id' => project.id,
'pipeline_creation_service_duration_s' => a_kind_of(Numeric),
- 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => counters
+ 'pipeline_step_gitlab_ci_pipeline_chain_seed_duration_s' => a_kind_of(Numeric)
}
end
- before do
+ it 'creates a log entry' do
allow_next_instance_of(Ci::Pipeline) do |pipeline|
expect(pipeline).to receive(:save!).and_raise { RuntimeError }
end
- end
- it 'creates a log entry' do
expect(Gitlab::AppJsonLogger)
.to receive(:info)
.with(a_hash_including(loggable_data))
@@ -125,7 +126,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when the size exceeds the threshold' do
before do
allow_next_instance_of(Ci::Pipeline) do |pipeline|
- allow(pipeline).to receive(:total_size) { 5000 }
+ allow(pipeline).to receive(:total_size).and_return(5000)
end
end
diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
index 513cbbed6cd..eb17935967c 100644
--- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
@@ -108,7 +108,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_fl
pipeline = create_pipeline!
test = pipeline.statuses.find_by(name: 'instrumentation_test')
- expect(test).to be_pending
+ expect(test).to be_running
expect(pipeline.triggered_pipelines.count).to eq(1)
end
diff --git a/spec/services/ci/create_pipeline_service/partitioning_spec.rb b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
index f34d103d965..a87135cefdd 100644
--- a/spec/services/ci/create_pipeline_service/partitioning_spec.rb
+++ b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :aggregate_failures,
-:ci_partitionable do
+:ci_partitionable, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -15,8 +15,13 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
- test
- deploy
+ needs:build:
+ stage: build
+ script: echo "needs..."
+
build:
stage: build
+ needs: ["needs:build"]
script: make build
test:
@@ -95,6 +100,12 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
expect(pipeline.variables.size).to eq(2)
expect(variables_partition_ids).to eq([current_partition_id])
end
+
+ it 'assigns partition_id to needs' do
+ needs = find_need('build')
+
+ expect(needs.partition_id).to eq(current_partition_id)
+ end
end
context 'with parent child pipelines' do
@@ -144,4 +155,12 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
.find { |job| job.name == name }
.metadata
end
+
+ def find_need(name)
+ pipeline
+ .processables
+ .find { |job| job.name == name }
+ .needs
+ .first
+ end
end
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index 5fdefb2b306..b866293393b 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -912,7 +912,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when outside freeze period' do
it 'creates two jobs' do
- Timecop.freeze(2020, 4, 10, 22, 59) do
+ travel_to(Time.utc(2020, 4, 10, 22, 59)) do
expect(pipeline).to be_persisted
expect(build_names).to contain_exactly('test-job', 'deploy-job')
end
@@ -921,7 +921,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when inside freeze period' do
it 'creates one job' do
- Timecop.freeze(2020, 4, 10, 23, 1) do
+ travel_to(Time.utc(2020, 4, 10, 23, 1)) do
expect(pipeline).to be_persisted
expect(build_names).to contain_exactly('test-job')
end
@@ -946,7 +946,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when outside freeze period' do
it 'creates two jobs' do
- Timecop.freeze(2020, 4, 10, 22, 59) do
+ travel_to(Time.utc(2020, 4, 10, 22, 59)) do
expect(pipeline).to be_persisted
expect(build_names).to contain_exactly('deploy-job')
end
@@ -955,7 +955,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
context 'when inside freeze period' do
it 'does not create the pipeline', :aggregate_failures do
- Timecop.freeze(2020, 4, 10, 23, 1) do
+ travel_to(Time.utc(2020, 4, 10, 23, 1)) do
expect(response).to be_error
expect(pipeline).not_to be_persisted
end
diff --git a/spec/services/ci/create_pipeline_service/scripts_spec.rb b/spec/services/ci/create_pipeline_service/scripts_spec.rb
new file mode 100644
index 00000000000..50b558e505a
--- /dev/null
+++ b/spec/services/ci/create_pipeline_service/scripts_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { project.first_owner }
+
+ let(:service) { described_class.new(project, user, { ref: 'master' }) }
+ let(:pipeline) { service.execute(:push).payload }
+
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ context 'when job has script and nested before_script and after_script' do
+ let(:config) do
+ <<-CI_CONFIG
+ default:
+ before_script: echo 'hello default before_script'
+ after_script: echo 'hello default after_script'
+
+ job:
+ before_script: echo 'hello job before_script'
+ after_script: echo 'hello job after_script'
+ script: echo 'hello job script'
+ CI_CONFIG
+ end
+
+ it 'creates a job with script data' do
+ expect(pipeline).to be_created_successfully
+ expect(pipeline.builds.first).to have_attributes(
+ name: 'job',
+ stage: 'test',
+ options: { script: ["echo 'hello job script'"],
+ before_script: ["echo 'hello job before_script'"],
+ after_script: ["echo 'hello job after_script'"] }
+ )
+ end
+ end
+
+ context 'when job has hooks and default hooks' do
+ let(:config) do
+ <<-CI_CONFIG
+ default:
+ hooks:
+ pre_get_sources_script:
+ - echo 'hello default pre_get_sources_script'
+
+ job1:
+ hooks:
+ pre_get_sources_script:
+ - echo 'hello job1 pre_get_sources_script'
+ script: echo 'hello job1 script'
+
+ job2:
+ script: echo 'hello job2 script'
+
+ job3:
+ inherit:
+ default: false
+ script: echo 'hello job3 script'
+ CI_CONFIG
+ end
+
+ it 'creates jobs with hook data' do
+ expect(pipeline).to be_created_successfully
+ expect(pipeline.builds.find_by(name: 'job1')).to have_attributes(
+ name: 'job1',
+ stage: 'test',
+ options: { script: ["echo 'hello job1 script'"],
+ hooks: { pre_get_sources_script: ["echo 'hello job1 pre_get_sources_script'"] } }
+ )
+ expect(pipeline.builds.find_by(name: 'job2')).to have_attributes(
+ name: 'job2',
+ stage: 'test',
+ options: { script: ["echo 'hello job2 script'"],
+ hooks: { pre_get_sources_script: ["echo 'hello default pre_get_sources_script'"] } }
+ )
+ expect(pipeline.builds.find_by(name: 'job3')).to have_attributes(
+ name: 'job3',
+ stage: 'test',
+ options: { script: ["echo 'hello job3 script'"] }
+ )
+ end
+
+ context 'when the FF ci_hooks_pre_get_sources_script is disabled' do
+ before do
+ stub_feature_flags(ci_hooks_pre_get_sources_script: false)
+ end
+
+ it 'creates jobs without hook data' do
+ expect(pipeline).to be_created_successfully
+ expect(pipeline.builds.find_by(name: 'job1')).to have_attributes(
+ name: 'job1',
+ stage: 'test',
+ options: { script: ["echo 'hello job1 script'"] }
+ )
+ expect(pipeline.builds.find_by(name: 'job2')).to have_attributes(
+ name: 'job2',
+ stage: 'test',
+ options: { script: ["echo 'hello job2 script'"] }
+ )
+ expect(pipeline.builds.find_by(name: 'job3')).to have_attributes(
+ name: 'job3',
+ stage: 'test',
+ options: { script: ["echo 'hello job3 script'"] }
+ )
+ 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 67c13649c6f..8628e95ba80 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -79,11 +79,11 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
let(:accepted_n_plus_ones) do
1 + # SELECT "ci_instance_variables"
- 1 + # INSERT INTO "ci_stages"
- 1 + # SELECT "ci_builds".* FROM "ci_builds"
- 1 + # INSERT INTO "ci_builds"
- 1 + # INSERT INTO "ci_builds_metadata"
- 1 # SELECT "taggings".* FROM "taggings"
+ 1 + # INSERT INTO "ci_stages"
+ 1 + # SELECT "ci_builds".* FROM "ci_builds"
+ 1 + # INSERT INTO "ci_builds"
+ 1 + # INSERT INTO "ci_builds_metadata"
+ 1 # SELECT "taggings".* FROM "taggings"
end
end
end
@@ -710,6 +710,29 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
+ context 'when the configuration includes ID tokens' do
+ it 'creates variables for the ID tokens' do
+ config = YAML.dump({
+ job_with_id_tokens: {
+ script: 'ls',
+ id_tokens: {
+ 'TEST_ID_TOKEN' => {
+ aud: 'https://gitlab.com'
+ }
+ }
+ }
+ })
+ stub_ci_pipeline_yaml_file(config)
+
+ result = execute_service.payload
+
+ expect(result).to be_persisted
+ expect(result.builds.first.id_tokens).to eq({
+ 'TEST_ID_TOKEN' => { 'aud' => 'https://gitlab.com' }
+ })
+ end
+ end
+
context 'with manual actions' do
before do
config = YAML.dump({ deploy: { script: 'ls', when: 'manual' } })
diff --git a/spec/services/ci/enqueue_job_service_spec.rb b/spec/services/ci/enqueue_job_service_spec.rb
new file mode 100644
index 00000000000..c2bb0bb2bb5
--- /dev/null
+++ b/spec/services/ci/enqueue_job_service_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::EnqueueJobService, '#execute', feature_category: :continuous_integration do
+ let_it_be(:project) { create(:project) }
+ let(:user) { create(:user, developer_projects: [project]) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, :manual, pipeline: pipeline) }
+
+ let(:service) do
+ described_class.new(build, current_user: user)
+ end
+
+ subject(:execute) { service.execute }
+
+ it 'assigns the user to the job' do
+ expect { execute }.to change { build.reload.user }.to(user)
+ end
+
+ it 'calls enqueue!' do
+ expect(build).to receive(:enqueue!)
+ execute
+ end
+
+ it 'calls Ci::ResetSkippedJobsService' do
+ expect_next_instance_of(Ci::ResetSkippedJobsService) do |service|
+ expect(service).to receive(:execute).with(build)
+ end
+
+ execute
+ end
+
+ it 'returns the job' do
+ expect(execute).to eq(build)
+ end
+
+ context 'when variables are supplied' do
+ let(:job_variables) do
+ [{ key: 'first', secret_value: 'first' },
+ { key: 'second', secret_value: 'second' }]
+ end
+
+ let(:service) do
+ described_class.new(build, current_user: user, variables: job_variables)
+ end
+
+ it 'assigns the variables to the job' do
+ execute
+ expect(build.reload.job_variables.map(&:key)).to contain_exactly('first', 'second')
+ end
+ end
+
+ context 'when the job transition is invalid' do
+ let(:bridge) { create(:ci_bridge, :failed, pipeline: pipeline, project: project) }
+
+ let(:service) do
+ described_class.new(bridge, current_user: user)
+ end
+
+ it 'raises StateMachines::InvalidTransition' do
+ expect { execute }.to raise_error StateMachines::InvalidTransition
+ end
+ end
+
+ context 'when a transition block is supplied' do
+ let(:bridge) { create(:ci_bridge, :playable, pipeline: pipeline) }
+
+ let(:service) do
+ described_class.new(bridge, current_user: user)
+ end
+
+ subject(:execute) { service.execute(&:pending!) }
+
+ it 'calls the transition block instead of enqueue!' do
+ expect(bridge).to receive(:pending!)
+ expect(bridge).not_to receive(:enqueue!)
+ execute
+ end
+ end
+end
diff --git a/spec/services/ci/generate_kubeconfig_service_spec.rb b/spec/services/ci/generate_kubeconfig_service_spec.rb
index bfde39780dd..c0858b0f0c9 100644
--- a/spec/services/ci/generate_kubeconfig_service_spec.rb
+++ b/spec/services/ci/generate_kubeconfig_service_spec.rb
@@ -4,52 +4,98 @@ require 'spec_helper'
RSpec.describe Ci::GenerateKubeconfigService do
describe '#execute' do
- let(:project) { create(:project) }
- let(:build) { create(:ci_build, project: project) }
- let(:pipeline) { build.pipeline }
- let(:agent1) { create(:cluster_agent, project: project) }
- let(:agent2) { create(:cluster_agent) }
- let(:authorization1) { create(:agent_project_authorization, agent: agent1) }
- let(:authorization2) { create(:agent_project_authorization, agent: agent2) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project) }
+ let_it_be(:build) { create(:ci_build, project: project, pipeline: pipeline) }
- let(:template) { instance_double(Gitlab::Kubernetes::Kubeconfig::Template) }
+ let_it_be(:agent_project) { create(:project, group: group, name: 'project-containing-agent-config') }
- subject { described_class.new(pipeline, token: build.token).execute }
+ let_it_be(:project_agent_authorization) do
+ agent = create(:cluster_agent, project: agent_project)
+ create(:agent_project_authorization, agent: agent, project: project)
+ end
+
+ let_it_be(:group_agent_authorization) do
+ agent = create(:cluster_agent, project: agent_project)
+ create(:agent_group_authorization, agent: agent, group: group)
+ end
+
+ let(:template) do
+ instance_double(
+ Gitlab::Kubernetes::Kubeconfig::Template,
+ add_cluster: nil,
+ add_user: nil,
+ add_context: nil
+ )
+ end
+
+ let(:agent_authorizations) { [project_agent_authorization, group_agent_authorization] }
+ let(:filter_service) do
+ instance_double(
+ ::Clusters::Agents::FilterAuthorizationsService,
+ execute: agent_authorizations
+ )
+ end
+
+ subject(:execute) { described_class.new(pipeline, token: build.token, environment: nil).execute }
before do
- expect(Gitlab::Kubernetes::Kubeconfig::Template).to receive(:new).and_return(template)
- expect(pipeline).to receive(:cluster_agent_authorizations).and_return([authorization1, authorization2])
+ allow(Gitlab::Kubernetes::Kubeconfig::Template).to receive(:new).and_return(template)
+ allow(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).and_return(filter_service)
+ end
+
+ it 'returns a Kubeconfig Template' do
+ expect(execute).to eq(template)
end
- it 'adds a cluster, and a user and context for each available agent' do
+ it 'adds a cluster' do
expect(template).to receive(:add_cluster).with(
name: 'gitlab',
url: Gitlab::Kas.tunnel_url
).once
- expect(template).to receive(:add_user).with(
- name: "agent:#{agent1.id}",
- token: "ci:#{agent1.id}:#{build.token}"
- )
- expect(template).to receive(:add_user).with(
- name: "agent:#{agent2.id}",
- token: "ci:#{agent2.id}:#{build.token}"
- )
+ execute
+ end
- expect(template).to receive(:add_context).with(
- name: "#{project.full_path}:#{agent1.name}",
- namespace: 'production',
- cluster: 'gitlab',
- user: "agent:#{agent1.id}"
- )
- expect(template).to receive(:add_context).with(
- name: "#{agent2.project.full_path}:#{agent2.name}",
- namespace: 'production',
- cluster: 'gitlab',
- user: "agent:#{agent2.id}"
+ it "filters the pipeline's agents by `nil` environment" do
+ expect(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).with(
+ pipeline.cluster_agent_authorizations,
+ environment: nil
)
- expect(subject).to eq(template)
+ execute
+ end
+
+ it 'adds user and context for all eligible agents', :aggregate_failures do
+ agent_authorizations.each do |authorization|
+ expect(template).to receive(:add_user).with(
+ name: "agent:#{authorization.agent.id}",
+ token: "ci:#{authorization.agent.id}:#{build.token}"
+ )
+
+ expect(template).to receive(:add_context).with(
+ name: "#{agent_project.full_path}:#{authorization.agent.name}",
+ namespace: 'production',
+ cluster: 'gitlab',
+ user: "agent:#{authorization.agent.id}"
+ )
+ end
+
+ execute
+ end
+
+ context 'when environment is specified' do
+ subject(:execute) { described_class.new(pipeline, token: build.token, environment: 'production').execute }
+
+ it "filters the pipeline's agents by the specified environment" do
+ expect(::Clusters::Agents::FilterAuthorizationsService).to receive(:new).with(
+ pipeline.cluster_agent_authorizations,
+ environment: 'production'
+ )
+
+ execute
+ end
end
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 1fbefc1fa22..2f2af9f6c85 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
+RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category: :continuous_integration do
describe 'Pipeline Processing Service Tests With Yaml' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
diff --git a/spec/services/ci/pipeline_schedules/calculate_next_run_service_spec.rb b/spec/services/ci/pipeline_schedules/calculate_next_run_service_spec.rb
new file mode 100644
index 00000000000..182c5bebbc1
--- /dev/null
+++ b/spec/services/ci/pipeline_schedules/calculate_next_run_service_spec.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+# rubocop:disable Layout/LineLength
+require 'spec_helper'
+
+RSpec.describe Ci::PipelineSchedules::CalculateNextRunService, feature_category: :continuous_integration do
+ let_it_be(:project) { create(:project, :public, :repository) }
+
+ describe '#execute' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:run_service) do
+ described_class.new(project).execute(pipeline_schedule,
+ fallback_method: pipeline_schedule.method(:calculate_next_run_at))
+ end
+
+ let(:pipeline_schedule) { create(:ci_pipeline_schedule, cron: schedule_cron) }
+ let(:daily_limit_of_144_runs) { 1.day / 10.minutes }
+ let(:daily_limit_of_24_runs) { 1.day / 1.hour }
+
+ before do
+ allow(Settings).to receive(:cron_jobs) { { 'pipeline_schedule_worker' => { 'cron' => worker_cron } } }
+ create(:plan_limits, :default_plan, ci_daily_pipeline_schedule_triggers: plan_limit) if plan_limit
+ end
+
+ context "when there is invalid or no plan limits" do
+ where(:worker_cron, :schedule_cron, :plan_limit, :now, :expected_result) do
+ '0 1 2 3 *' | '0 1 * * *' | nil | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0)
+ '*/5 * * * *' | '*/1 * * * *' | nil | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 5)
+ '*/5 * * * *' | '0 * * * *' | nil | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5)
+ # 1.day / 2.hours => 12 times a day and it is invalid because there is a minimum for plan limits.
+ # See: https://docs.gitlab.com/ee/administration/instance_limits.html#limit-the-number-of-pipelines-created-by-a-pipeline-schedule-per-day
+ '*/5 * * * *' | '0 * * * *' | 1.day / 2.hours | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 5)
+ end
+
+ with_them do
+ it 'calls fallback method to get next_run_at' do
+ travel_to(now) do
+ expect(pipeline_schedule).to receive(:calculate_next_run_at).and_call_original
+
+ result = run_service
+
+ expect(result).to eq(expected_result)
+ end
+ end
+ end
+ end
+
+ context "when the workers next run matches schedule's earliest run" do
+ where(:worker_cron, :schedule_cron, :plan_limit, :now, :expected_result) do
+ '*/5 * * * *' | '0 * * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0)
+ '*/5 * * * *' | '*/5 * * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10)
+ '*/5 * * * *' | '0 1 * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 28, 1, 0)
+ '*/5 * * * *' | '0 2 * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 27, 2, 0)
+ '*/5 * * * *' | '0 3 * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 1, 0) | Time.zone.local(2021, 5, 27, 3, 0)
+ '*/5 * * * *' | '0 1 1 * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 1, 1, 0) | Time.zone.local(2021, 6, 1, 1, 0)
+ '*/9 * * * *' | '0 1 1 * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 1, 1, 9) | Time.zone.local(2021, 6, 1, 1, 0)
+ '*/5 * * * *' | '45 21 1 2 *' | daily_limit_of_144_runs | Time.zone.local(2021, 2, 1, 21, 45) | Time.zone.local(2022, 2, 1, 21, 45)
+ end
+
+ with_them do
+ it 'calculates the next_run_at to be earliest point of match' do
+ travel_to(now) do
+ result = run_service
+
+ expect(result).to eq(expected_result)
+ end
+ end
+ end
+ end
+
+ context "when next_run_at is restricted by plan limit" do
+ where(:worker_cron, :schedule_cron, :plan_limit, :now, :expected_result) do
+ '*/5 * * * *' | '59 14 * * *' | daily_limit_of_24_runs | Time.zone.local(2021, 5, 1, 15, 0) | Time.zone.local(2021, 5, 2, 15, 0)
+ '*/5 * * * *' | '*/1 * * * *' | daily_limit_of_24_runs | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 12, 0)
+ '*/5 * * * *' | '*/1 * * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10)
+ '*/5 * * * *' | '*/1 * * * *' | (1.day / 7.minutes).to_i | Time.zone.local(2021, 5, 27, 11, 0) | Time.zone.local(2021, 5, 27, 11, 10)
+ end
+
+ with_them do
+ it 'calculates the next_run_at based on next available limit' do
+ travel_to(now) do
+ result = run_service
+
+ expect(result).to eq(expected_result)
+ end
+ end
+ end
+ end
+
+ context "when next_run_at is restricted by worker's availability" do
+ where(:worker_cron, :schedule_cron, :plan_limit, :now, :expected_result) do
+ '0 1 2 3 *' | '0 1 * * *' | daily_limit_of_144_runs | Time.zone.local(2021, 3, 2, 1, 0) | Time.zone.local(2022, 3, 2, 1, 0)
+ end
+
+ with_them do
+ it 'calculates the next_run_at using worker_cron' do
+ travel_to(now) do
+ result = run_service
+
+ expect(result).to eq(expected_result)
+ end
+ end
+ end
+ end
+ end
+end
+# rubocop:enable Layout/LineLength
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index 4b3e774ff3c..4946367380e 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -197,8 +197,7 @@ RSpec.describe Ci::PipelineTriggerService do
end
it_behaves_like 'logs downstream pipeline creation' do
- subject { result[:pipeline] }
-
+ let(:downstream_pipeline) { result[:pipeline] }
let(:expected_root_pipeline) { pipeline }
let(:expected_hierarchy_size) { 2 }
let(:expected_downstream_relationship) { :multi_project }
diff --git a/spec/services/ci/pipelines/add_job_service_spec.rb b/spec/services/ci/pipelines/add_job_service_spec.rb
index e735b2752d9..c62aa9506bd 100644
--- a/spec/services/ci/pipelines/add_job_service_spec.rb
+++ b/spec/services/ci/pipelines/add_job_service_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Ci::Pipelines::AddJobService do
include ExclusiveLeaseHelpers
- let_it_be(:pipeline) { create(:ci_pipeline) }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline) }
let(:job) { build(:ci_build) }
@@ -35,7 +35,7 @@ RSpec.describe Ci::Pipelines::AddJobService do
end
it 'assigns partition_id to job and metadata' do
- pipeline.partition_id = 123
+ pipeline.partition_id = ci_testing_partition_id
expect { execute }
.to change(job, :partition_id).to(pipeline.partition_id)
diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb
index 9301098b083..de308bb1a87 100644
--- a/spec/services/ci/process_build_service_spec.rb
+++ b/spec/services/ci/process_build_service_spec.rb
@@ -19,31 +19,25 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
end
end
- shared_context 'with ci_retry_job_fix disabled' do
- before do
- stub_feature_flags(ci_retry_job_fix: false)
- end
- end
-
context 'for single build' do
let!(:build) { create(:ci_build, *[trait].compact, :created, **conditions, pipeline: pipeline) }
- where(:trait, :conditions, :current_status, :after_status, :retry_after_status, :retry_disabled_after_status) do
- nil | { when: :on_success } | 'success' | 'pending' | 'pending' | 'pending'
- nil | { when: :on_success } | 'skipped' | 'pending' | 'pending' | 'pending'
- nil | { when: :on_success } | 'failed' | 'skipped' | 'skipped' | 'skipped'
- nil | { when: :on_failure } | 'success' | 'skipped' | 'skipped' | 'skipped'
- nil | { when: :on_failure } | 'skipped' | 'skipped' | 'skipped' | 'skipped'
- nil | { when: :on_failure } | 'failed' | 'pending' | 'pending' | 'pending'
- nil | { when: :always } | 'success' | 'pending' | 'pending' | 'pending'
- nil | { when: :always } | 'skipped' | 'pending' | 'pending' | 'pending'
- nil | { when: :always } | 'failed' | 'pending' | 'pending' | 'pending'
- :actionable | { when: :manual } | 'success' | 'manual' | 'pending' | 'manual'
- :actionable | { when: :manual } | 'skipped' | 'manual' | 'pending' | 'manual'
- :actionable | { when: :manual } | 'failed' | 'skipped' | 'skipped' | 'skipped'
- :schedulable | { when: :delayed } | 'success' | 'scheduled' | 'pending' | 'scheduled'
- :schedulable | { when: :delayed } | 'skipped' | 'scheduled' | 'pending' | 'scheduled'
- :schedulable | { when: :delayed } | 'failed' | 'skipped' | 'skipped' | 'skipped'
+ where(:trait, :conditions, :current_status, :after_status, :retry_after_status) do
+ nil | { when: :on_success } | 'success' | 'pending' | 'pending'
+ nil | { when: :on_success } | 'skipped' | 'pending' | 'pending'
+ nil | { when: :on_success } | 'failed' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'success' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'skipped' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'failed' | 'pending' | 'pending'
+ nil | { when: :always } | 'success' | 'pending' | 'pending'
+ nil | { when: :always } | 'skipped' | 'pending' | 'pending'
+ nil | { when: :always } | 'failed' | 'pending' | 'pending'
+ :actionable | { when: :manual } | 'success' | 'manual' | 'pending'
+ :actionable | { when: :manual } | 'skipped' | 'manual' | 'pending'
+ :actionable | { when: :manual } | 'failed' | 'skipped' | 'skipped'
+ :schedulable | { when: :delayed } | 'success' | 'scheduled' | 'pending'
+ :schedulable | { when: :delayed } | 'skipped' | 'scheduled' | 'pending'
+ :schedulable | { when: :delayed } | 'failed' | 'skipped' | 'skipped'
end
with_them do
@@ -57,14 +51,6 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
it 'updates the job status to retry_after_status' do
expect { subject }.to change { build.status }.to(retry_after_status)
end
-
- context 'when feature flag ci_retry_job_fix is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it "updates the job status to retry_disabled_after_status" do
- expect { subject }.to change { build.status }.to(retry_disabled_after_status)
- end
- end
end
end
end
@@ -84,15 +70,15 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
let!(:other_build) { create(:ci_build, :created, when: :on_success, pipeline: pipeline) }
- where(:trait, :build_when, :current_status, :after_status, :retry_after_status, :retry_disabled_after_status) do
- nil | :on_success | 'success' | 'pending' | 'pending' | 'pending'
- nil | :on_success | 'skipped' | 'skipped' | 'skipped' | 'skipped'
- nil | :manual | 'success' | 'manual' | 'pending' | 'manual'
- nil | :manual | 'skipped' | 'skipped' | 'skipped' | 'skipped'
- nil | :delayed | 'success' | 'manual' | 'pending' | 'manual'
- nil | :delayed | 'skipped' | 'skipped' | 'skipped' | 'skipped'
- :schedulable | :delayed | 'success' | 'scheduled' | 'pending' | 'scheduled'
- :schedulable | :delayed | 'skipped' | 'skipped' | 'skipped' | 'skipped'
+ where(:trait, :build_when, :current_status, :after_status, :retry_after_status) do
+ nil | :on_success | 'success' | 'pending' | 'pending'
+ nil | :on_success | 'skipped' | 'skipped' | 'skipped'
+ nil | :manual | 'success' | 'manual' | 'pending'
+ nil | :manual | 'skipped' | 'skipped' | 'skipped'
+ nil | :delayed | 'success' | 'manual' | 'pending'
+ nil | :delayed | 'skipped' | 'skipped' | 'skipped'
+ :schedulable | :delayed | 'success' | 'scheduled' | 'pending'
+ :schedulable | :delayed | 'skipped' | 'skipped' | 'skipped'
end
with_them do
@@ -106,14 +92,6 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
it 'updates the job status to retry_after_status' do
expect { subject }.to change { build.status }.to(retry_after_status)
end
-
- context 'when feature flag ci_retry_job_fix is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it "updates the job status to retry_disabled_after_status" do
- expect { subject }.to change { build.status }.to(retry_disabled_after_status)
- end
- end
end
end
end
diff --git a/spec/services/ci/after_requeue_job_service_spec.rb b/spec/services/ci/reset_skipped_jobs_service_spec.rb
index e6f46fb9ebe..712a21e665b 100644
--- a/spec/services/ci/after_requeue_job_service_spec.rb
+++ b/spec/services/ci/reset_skipped_jobs_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
+RSpec.describe Ci::ResetSkippedJobsService, :sidekiq_inline, feature_category: :continuous_integration do
let_it_be(:project) { create(:project, :empty_repo) }
let_it_be(:user) { project.first_owner }
@@ -12,9 +12,9 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
subject(:service) { described_class.new(project, user) }
- context 'stage-dag mixed pipeline' do
+ context 'with a stage-dag mixed pipeline' do
let(:config) do
- <<-EOY
+ <<-YAML
stages: [a, b, c]
a1:
@@ -49,7 +49,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c2:
stage: c
script: exit 0
- EOY
+ YAML
end
let(:pipeline) do
@@ -150,9 +150,9 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
end
end
- context 'stage-dag mixed pipeline with some same-stage needs' do
+ context 'with stage-dag mixed pipeline with some same-stage needs' do
let(:config) do
- <<-EOY
+ <<-YAML
stages: [a, b, c]
a1:
@@ -181,7 +181,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c2:
stage: c
script: exit 0
- EOY
+ YAML
end
let(:pipeline) do
@@ -239,7 +239,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
context 'with same-stage needs' do
let(:config) do
- <<-EOY
+ <<-YAML
a:
script: exit $(($RANDOM % 2))
@@ -250,7 +250,7 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c:
script: exit 0
needs: [b]
- EOY
+ YAML
end
let(:pipeline) do
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index 540e700efa6..c3d80f2cb56 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -48,12 +48,6 @@ RSpec.describe Ci::RetryJobService do
end
end
- shared_context 'with ci_retry_job_fix disabled' do
- before do
- stub_feature_flags(ci_retry_job_fix: false)
- end
- end
-
shared_examples_for 'clones the job' do
let(:job) { job_to_clone }
@@ -284,14 +278,6 @@ RSpec.describe Ci::RetryJobService do
with_them do
it_behaves_like 'checks enqueue_immediately?'
-
- context 'when feature flag is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it_behaves_like 'checks enqueue_immediately?' do
- let(:enqueue_immediately) { false }
- end
- end
end
end
end
@@ -384,15 +370,6 @@ RSpec.describe Ci::RetryJobService do
expect(subject).to be_success
expect(new_job.status).to eq after_status
end
-
- context 'when feature flag is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it 'enqueues the new job' do
- expect(subject).to be_success
- expect(new_job).to be_pending
- end
- end
end
end
@@ -435,15 +412,6 @@ RSpec.describe Ci::RetryJobService do
expect(subject).to be_success
expect(new_job.status).to eq after_status
end
-
- context 'when feature flag is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it 'enqueues the new job' do
- expect(subject).to be_success
- expect(new_job).to be_pending
- end
- end
end
end
@@ -487,19 +455,6 @@ RSpec.describe Ci::RetryJobService do
end
it_behaves_like 'checks enqueue_immediately?'
-
- context 'when feature flag is disabled' do
- include_context 'with ci_retry_job_fix disabled'
-
- it 'enqueues the new job' do
- expect(subject).to be_success
- expect(new_job).to be_pending
- end
-
- it_behaves_like 'checks enqueue_immediately?' do
- let(:enqueue_immediately) { false }
- end
- end
end
end
end
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 77345096537..07518c35fab 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -349,7 +349,10 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
it 'marks source bridge as pending' do
expect { service.execute(pipeline) }.to change { bridge.reload.status }.to('pending')
- .and not_change { bridge.reload.user }
+ end
+
+ it 'assigns the current user to the source bridge' do
+ expect { service.execute(pipeline) }.to change { bridge.reload.user }.to(user)
end
end
end
diff --git a/spec/services/ci/runners/assign_runner_service_spec.rb b/spec/services/ci/runners/assign_runner_service_spec.rb
index 08bb99830fb..92f6db2bdfb 100644
--- a/spec/services/ci/runners/assign_runner_service_spec.rb
+++ b/spec/services/ci/runners/assign_runner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::AssignRunnerService, '#execute' do
+RSpec.describe ::Ci::Runners::AssignRunnerService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(runner, project, user).execute }
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
diff --git a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
index fa8af1100df..5e697565972 100644
--- a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
+++ b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do
+RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(**service_args).execute }
let_it_be(:admin_user) { create(:user, :admin) }
diff --git a/spec/services/ci/runners/process_runner_version_update_service_spec.rb b/spec/services/ci/runners/process_runner_version_update_service_spec.rb
index b885138fc7a..d2a7e87b2d5 100644
--- a/spec/services/ci/runners/process_runner_version_update_service_spec.rb
+++ b/spec/services/ci/runners/process_runner_version_update_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateService do
+RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateService, feature_category: :runner_fleet do
subject(:service) { described_class.new(version) }
let(:version) { '1.0.0' }
diff --git a/spec/services/ci/runners/reconcile_existing_runner_versions_service_spec.rb b/spec/services/ci/runners/reconcile_existing_runner_versions_service_spec.rb
index 1690190320a..39082b5c0f4 100644
--- a/spec/services/ci/runners/reconcile_existing_runner_versions_service_spec.rb
+++ b/spec/services/ci/runners/reconcile_existing_runner_versions_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute' do
+RSpec.describe ::Ci::Runners::ReconcileExistingRunnerVersionsService, '#execute', feature_category: :runner_fleet do
include RunnerReleasesHelper
subject(:execute) { described_class.new.execute }
diff --git a/spec/services/ci/runners/register_runner_service_spec.rb b/spec/services/ci/runners/register_runner_service_spec.rb
index 2d1b109072f..47d399cb19a 100644
--- a/spec/services/ci/runners/register_runner_service_spec.rb
+++ b/spec/services/ci/runners/register_runner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::RegisterRunnerService, '#execute' do
+RSpec.describe ::Ci::Runners::RegisterRunnerService, '#execute', feature_category: :runner_fleet do
let(:registration_token) { 'abcdefg123456' }
let(:token) {}
let(:args) { {} }
diff --git a/spec/services/ci/runners/reset_registration_token_service_spec.rb b/spec/services/ci/runners/reset_registration_token_service_spec.rb
index 79059712032..c8115236034 100644
--- a/spec/services/ci/runners/reset_registration_token_service_spec.rb
+++ b/spec/services/ci/runners/reset_registration_token_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::ResetRegistrationTokenService, '#execute' do
+RSpec.describe ::Ci::Runners::ResetRegistrationTokenService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(scope, current_user).execute }
let_it_be(:user) { build(:user) }
diff --git a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
index e5cba80d567..9921f9322bd 100644
--- a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
+++ b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute' do
+RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(runner: runner, current_user: user, project_ids: project_ids).execute }
let_it_be(:owner_project) { create(:project) }
diff --git a/spec/services/ci/runners/unassign_runner_service_spec.rb b/spec/services/ci/runners/unassign_runner_service_spec.rb
index cf710cf6893..e91d4249473 100644
--- a/spec/services/ci/runners/unassign_runner_service_spec.rb
+++ b/spec/services/ci/runners/unassign_runner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::UnassignRunnerService, '#execute' do
+RSpec.describe ::Ci::Runners::UnassignRunnerService, '#execute', feature_category: :runner_fleet do
let_it_be(:project) { create(:project) }
let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) }
diff --git a/spec/services/ci/runners/unregister_runner_service_spec.rb b/spec/services/ci/runners/unregister_runner_service_spec.rb
index 77fc299e4e1..fb779e1a673 100644
--- a/spec/services/ci/runners/unregister_runner_service_spec.rb
+++ b/spec/services/ci/runners/unregister_runner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ::Ci::Runners::UnregisterRunnerService, '#execute' do
+RSpec.describe ::Ci::Runners::UnregisterRunnerService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(runner, 'some_token').execute }
let(:runner) { create(:ci_runner) }
diff --git a/spec/services/ci/runners/update_runner_service_spec.rb b/spec/services/ci/runners/update_runner_service_spec.rb
index 1f953ac4cbb..86875df70a2 100644
--- a/spec/services/ci/runners/update_runner_service_spec.rb
+++ b/spec/services/ci/runners/update_runner_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::Runners::UpdateRunnerService, '#execute' do
+RSpec.describe Ci::Runners::UpdateRunnerService, '#execute', feature_category: :runner_fleet do
subject(:execute) { described_class.new(runner).execute(params) }
let(:runner) { create(:ci_runner) }
diff --git a/spec/services/ci/test_failure_history_service_spec.rb b/spec/services/ci/test_failure_history_service_spec.rb
index c19df6e217b..10f6c6f5007 100644
--- a/spec/services/ci/test_failure_history_service_spec.rb
+++ b/spec/services/ci/test_failure_history_service_spec.rb
@@ -3,16 +3,19 @@
require 'spec_helper'
RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
- describe '#execute' do
- let(:project) { create(:project) }
- let(:pipeline) { create(:ci_empty_pipeline, status: :created, project: project) }
+ let_it_be(:project) { create(:project, :repository) }
+
+ let_it_be_with_reload(:pipeline) do
+ create(:ci_pipeline, status: :created, project: project, ref: project.default_branch)
+ end
+ describe '#execute' do
subject(:execute_service) { described_class.new(pipeline).execute }
context 'when pipeline has failed builds with test reports' do
- before do
+ let_it_be(:job) do
# The test report has 2 unit test failures
- create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
+ create(:ci_build, :failed, :test_reports, pipeline: pipeline)
end
it 'creates unit test failures records' do
@@ -22,6 +25,14 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
expect(Ci::UnitTestFailure.count).to eq(2)
end
+ it 'assigns partition_id to Ci::UnitTestFailure' do
+ execute_service
+
+ unit_test_failure_partition_ids = Ci::UnitTestFailure.distinct.pluck(:partition_id)
+
+ expect(unit_test_failure_partition_ids).to match_array([job.partition_id])
+ end
+
context 'when pipeline is not for the default branch' do
before do
pipeline.update_column(:ref, 'new-feature')
@@ -67,7 +78,7 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
# This other test report has 1 unique unit test failure which brings us to 3 total failures across all builds
# thus exceeding the limit of 2 for MAX_TRACKABLE_FAILURES
- create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline, project: project)
+ create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline)
end
it 'does not persist data' do
@@ -82,7 +93,7 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
context 'when test failure data have duplicates within the same payload (happens when the JUnit report has duplicate unit test names but have different failures)' do
before do
# The test report has 2 unit test failures but with the same unit test keys
- create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline, project: project)
+ create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline)
end
it 'does not fail but does not persist duplicate data' do
@@ -95,8 +106,8 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
context 'when pipeline has no failed builds with test reports' do
before do
- create(:ci_build, :test_reports, pipeline: pipeline, project: project)
- create(:ci_build, :failed, pipeline: pipeline, project: project)
+ create(:ci_build, :test_reports, pipeline: pipeline)
+ create(:ci_build, :failed, pipeline: pipeline)
end
it 'does not persist data' do
@@ -109,14 +120,10 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
end
describe '#should_track_failures?' do
- let(:project) { create(:project, :repository) }
- let(:pipeline) { create(:ci_empty_pipeline, status: :created, project: project, ref: project.default_branch) }
-
subject { described_class.new(pipeline).should_track_failures? }
- before do
- create(:ci_build, :test_reports, :failed, pipeline: pipeline, project: project)
- create(:ci_build, :test_reports, :failed, pipeline: pipeline, project: project)
+ let_it_be(:jobs) do
+ create_list(:ci_build, 2, :test_reports, :failed, pipeline: pipeline)
end
context 'when feature flag is enabled and pipeline ref is the default branch' do
diff --git a/spec/services/ci/track_failed_build_service_spec.rb b/spec/services/ci/track_failed_build_service_spec.rb
index d83e56f0669..676769d2fc7 100644
--- a/spec/services/ci/track_failed_build_service_spec.rb
+++ b/spec/services/ci/track_failed_build_service_spec.rb
@@ -21,19 +21,22 @@ RSpec.describe Ci::TrackFailedBuildService do
expect(response.success?).to be true
+ context = {
+ schema: described_class::SCHEMA_URL,
+ data: {
+ build_id: build.id,
+ build_name: build.name,
+ build_artifact_types: ["sast"],
+ exit_code: exit_code,
+ failure_reason: failure_reason,
+ project: project.id
+ }
+ }
+
expect_snowplow_event(
category: 'ci::build',
action: 'failed',
- context: [{
- schema: described_class::SCHEMA_URL,
- data: {
- build_id: build.id,
- build_name: build.name,
- build_artifact_types: ["sast"],
- exit_code: exit_code,
- failure_reason: failure_reason
- }
- }],
+ context: [context],
user: user,
project: project.id)
end
diff --git a/spec/services/ci/unlock_artifacts_service_spec.rb b/spec/services/ci/unlock_artifacts_service_spec.rb
index f21afc7fe9e..c15e1cb2b5d 100644
--- a/spec/services/ci/unlock_artifacts_service_spec.rb
+++ b/spec/services/ci/unlock_artifacts_service_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe Ci::UnlockArtifactsService do
using RSpec::Parameterized::TableSyntax
- where(:tag, :ci_update_unlocked_job_artifacts) do
- false | false
- false | true
- true | false
- true | true
+ where(:tag) do
+ [
+ [false],
+ [true]
+ ]
end
with_them do
@@ -31,7 +31,6 @@ RSpec.describe Ci::UnlockArtifactsService do
before do
stub_const("#{described_class}::BATCH_SIZE", 1)
- stub_feature_flags(ci_update_unlocked_job_artifacts: ci_update_unlocked_job_artifacts)
end
describe '#execute' do
@@ -69,17 +68,11 @@ RSpec.describe Ci::UnlockArtifactsService do
end
it 'unlocks job artifact records' do
- pending unless ci_update_unlocked_job_artifacts
-
expect { execute }.to change { ::Ci::JobArtifact.artifact_unlocked.count }.from(0).to(2)
end
it 'unlocks pipeline artifact records' do
- if ci_update_unlocked_job_artifacts
- expect { execute }.to change { ::Ci::PipelineArtifact.artifact_unlocked.count }.from(0).to(1)
- else
- expect { execute }.not_to change { ::Ci::PipelineArtifact.artifact_unlocked.count }
- end
+ expect { execute }.to change { ::Ci::PipelineArtifact.artifact_unlocked.count }.from(0).to(1)
end
end
@@ -111,17 +104,11 @@ RSpec.describe Ci::UnlockArtifactsService do
end
it 'unlocks job artifact records' do
- pending unless ci_update_unlocked_job_artifacts
-
expect { execute }.to change { ::Ci::JobArtifact.artifact_unlocked.count }.from(0).to(8)
end
it 'unlocks pipeline artifact records' do
- if ci_update_unlocked_job_artifacts
- expect { execute }.to change { ::Ci::PipelineArtifact.artifact_unlocked.count }.from(0).to(1)
- else
- expect { execute }.not_to change { ::Ci::PipelineArtifact.artifact_unlocked.count }
- end
+ expect { execute }.to change { ::Ci::PipelineArtifact.artifact_unlocked.count }.from(0).to(1)
end
end
end