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/lib/gitlab/ci/pipeline')
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb51
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb97
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb13
-rw-r--r--spec/lib/gitlab/ci/pipeline/duration_spec.rb224
-rw-r--r--spec/lib/gitlab/ci/pipeline/logger_spec.rb13
8 files changed, 349 insertions, 110 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
index b570f2a7f75..fc3de2a14cd 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb
@@ -44,6 +44,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
expect(build_statuses(pipeline)).to contain_exactly('pending')
end
+ it 'logs canceled pipelines' do
+ allow(Gitlab::AppLogger).to receive(:info)
+
+ perform
+
+ expect(Gitlab::AppLogger).to have_received(:info).with(
+ class: described_class.name,
+ message: "Pipeline #{pipeline.id} auto-canceling pipeline #{prev_pipeline.id}",
+ canceled_pipeline_id: prev_pipeline.id,
+ canceled_by_pipeline_id: pipeline.id,
+ canceled_by_pipeline_source: pipeline.source
+ )
+ end
+
it 'cancels the builds with 2 queries to avoid query timeout' do
second_query_regex = /WHERE "ci_pipelines"\."id" = \d+ AND \(NOT EXISTS/
recorder = ActiveRecord::QueryRecorder.new { perform }
@@ -141,7 +155,42 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
end
end
- context 'when the prev pipeline source is webide' do
+ context 'when the pipeline is a child pipeline' do
+ let!(:parent_pipeline) { create(:ci_pipeline, project: project, sha: new_commit.sha) }
+ let(:pipeline) { create(:ci_pipeline, child_of: parent_pipeline) }
+
+ before do
+ create(:ci_build, :interruptible, :running, pipeline: parent_pipeline)
+ create(:ci_build, :interruptible, :running, pipeline: parent_pipeline)
+ end
+
+ it 'does not cancel any builds' do
+ expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
+ expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+
+ perform
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('running', 'success', 'created')
+ expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+ end
+
+ context 'when feature flag ci_skip_auto_cancelation_on_child_pipelines is disabled' do
+ before do
+ stub_feature_flags(ci_skip_auto_cancelation_on_child_pipelines: false)
+ end
+
+ it 'does not cancel the parent pipeline' do
+ expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+
+ perform
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('success', 'canceled', 'canceled')
+ expect(build_statuses(parent_pipeline)).to contain_exactly('running', 'running')
+ end
+ end
+ end
+
+ context 'when the previous pipeline source is webide' do
let(:prev_pipeline) { create(:ci_pipeline, :webide, project: project) }
it 'does not cancel builds of the previous pipeline' do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
index f451bd6bfef..e0d656f456e 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb
@@ -11,9 +11,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
subject { described_class.new(pipeline, command) }
- # TODO: change this to `describe` and remove rubocop-disable
- # when removing the FF ci_project_pipeline_config_refactoring
- shared_context '#perform!' do # rubocop:disable RSpec/ContextWording
+ describe '#perform!' do
context 'when bridge job is passed in as parameter' do
let(:ci_config_path) { nil }
let(:bridge) { create(:ci_bridge) }
@@ -203,14 +201,4 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do
end
end
end
-
- it_behaves_like '#perform!'
-
- context 'when the FF ci_project_pipeline_config_refactoring is disabled' do
- before do
- stub_feature_flags(ci_project_pipeline_config_refactoring: false)
- end
-
- it_behaves_like '#perform!'
- end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb
new file mode 100644
index 00000000000..bc453f1502b
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::ActiveJobs do
+ let_it_be(:namespace) { create(:namespace) }
+ let_it_be(:project) { create(:project, namespace: namespace) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:default_plan) { create(:default_plan) }
+
+ let(:command) do
+ instance_double(
+ ::Gitlab::Ci::Pipeline::Chain::Command,
+ project: project,
+ current_user: user,
+ save_incompleted: true,
+ pipeline_seed: pipeline_seed_double
+ )
+ end
+
+ let(:pipeline_seed_double) do
+ instance_double(::Gitlab::Ci::Pipeline::Seed::Pipeline, size: 5)
+ end
+
+ let(:pipeline) do
+ create(:ci_pipeline, project: project)
+ end
+
+ let(:existing_pipeline) { create(:ci_pipeline, project: project) }
+ let(:step) { described_class.new(pipeline, command) }
+ let(:limit) { 10 }
+
+ subject { step.perform! }
+
+ before do
+ create(:plan_limits, plan: default_plan, ci_active_jobs: limit)
+ namespace.clear_memoization(:actual_plan)
+ end
+
+ shared_examples 'successful step' do
+ it 'doest not fail the pipeline and does not interrupt the chain' do
+ subject
+
+ expect(pipeline).not_to be_failed
+ expect(step).not_to be_break
+ end
+ end
+
+ context 'when active jobs limit is exceeded' do
+ before do
+ create_list(:ci_build, 3, pipeline: existing_pipeline)
+ create_list(:ci_bridge, 3, pipeline: existing_pipeline)
+ end
+
+ it 'fails the pipeline with an error', :aggregate_failures do
+ subject
+
+ expect(pipeline).to be_failed
+ expect(pipeline).to be_job_activity_limit_exceeded
+ expect(pipeline.errors.full_messages).to include(described_class::MESSAGE)
+ end
+
+ it 'logs the failure' do
+ allow(Gitlab::AppLogger).to receive(:info)
+
+ subject
+
+ expect(Gitlab::AppLogger).to have_received(:info).with(
+ class: described_class.name,
+ message: described_class::MESSAGE,
+ project_id: project.id,
+ plan: default_plan.name
+ )
+ end
+
+ it 'breaks the chain' do
+ subject
+
+ expect(step).to be_break
+ end
+
+ context 'when active jobs limit not enabled' do
+ let(:limit) { 0 }
+
+ it_behaves_like 'successful step'
+ end
+ end
+
+ context 'when active jobs limit is not exceeded' do
+ before do
+ create_list(:ci_build, 3, pipeline: existing_pipeline)
+ create_list(:ci_bridge, 1, pipeline: existing_pipeline)
+ end
+
+ it_behaves_like 'successful step'
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 62de4d2e96d..51d1661b586 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -236,4 +236,47 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
end
end
end
+
+ context 'with pipeline name' do
+ let(:config) do
+ { workflow: { name: ' Pipeline name ' }, rspec: { script: 'rspec' } }
+ end
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'does not build pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata).to be_nil
+ end
+ end
+
+ context 'with feature flag enabled' do
+ before do
+ stub_feature_flags(pipeline_name: true)
+ end
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.title).to eq('Pipeline name')
+ expect(pipeline.pipeline_metadata.project).to eq(pipeline.project)
+ end
+
+ context 'with empty name' do
+ let(:config) do
+ { workflow: { name: ' ' }, rspec: { script: 'rspec' } }
+ end
+
+ it 'strips whitespace from name' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata).to be_nil
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
index 8c4f7af0ef4..323bab89e6a 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb
@@ -68,8 +68,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
end
context 'when refs policy is specified' do
+ let(:tag_name) { project.repository.tags.first.name }
+
let(:pipeline) do
- build(:ci_pipeline, project: project, ref: 'feature', tag: true)
+ build(:ci_pipeline, project: project, ref: tag_name, tag: true)
end
let(:config) do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
index ee32661f267..c69aa661b05 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
@@ -100,19 +100,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do
expect(histogram).to have_received(:observe)
.with(hash_including(plan: project.actual_plan_name), 4)
end
-
- context 'when feature flag ci_limit_active_jobs_early is disabled' do
- before do
- stub_feature_flags(ci_limit_active_jobs_early: false)
- end
-
- it 'counts all the active builds' do
- subject.build!
-
- expect(histogram).to have_received(:observe)
- .with(hash_including(plan: project.actual_plan_name), 3)
- end
- end
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/duration_spec.rb b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
index 46c7072ad8e..36714413da6 100644
--- a/spec/lib/gitlab/ci/pipeline/duration_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/duration_spec.rb
@@ -1,117 +1,187 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Duration do
- let(:calculated_duration) { calculate(data) }
+ describe '.from_periods' do
+ let(:calculated_duration) { calculate(data) }
- shared_examples 'calculating duration' do
- it do
- expect(calculated_duration).to eq(duration)
+ shared_examples 'calculating duration' do
+ it do
+ expect(calculated_duration).to eq(duration)
+ end
end
- end
- context 'test sample A' do
- let(:data) do
- [[0, 1],
- [1, 2],
- [3, 4],
- [5, 6]]
+ context 'test sample A' do
+ let(:data) do
+ [[0, 1],
+ [1, 2],
+ [3, 4],
+ [5, 6]]
+ end
+
+ let(:duration) { 4 }
+
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 4 }
+ context 'test sample B' do
+ let(:data) do
+ [[0, 1],
+ [1, 2],
+ [2, 3],
+ [3, 4],
+ [0, 4]]
+ end
- it_behaves_like 'calculating duration'
- end
+ let(:duration) { 4 }
- context 'test sample B' do
- let(:data) do
- [[0, 1],
- [1, 2],
- [2, 3],
- [3, 4],
- [0, 4]]
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 4 }
+ context 'test sample C' do
+ let(:data) do
+ [[0, 4],
+ [2, 6],
+ [5, 7],
+ [8, 9]]
+ end
- it_behaves_like 'calculating duration'
- end
+ let(:duration) { 8 }
- context 'test sample C' do
- let(:data) do
- [[0, 4],
- [2, 6],
- [5, 7],
- [8, 9]]
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 8 }
+ context 'test sample D' do
+ let(:data) do
+ [[0, 1],
+ [2, 3],
+ [4, 5],
+ [6, 7]]
+ end
- it_behaves_like 'calculating duration'
- end
+ let(:duration) { 4 }
+
+ it_behaves_like 'calculating duration'
+ end
- context 'test sample D' do
- let(:data) do
- [[0, 1],
- [2, 3],
- [4, 5],
- [6, 7]]
+ context 'test sample E' do
+ let(:data) do
+ [[0, 1],
+ [3, 9],
+ [3, 4],
+ [3, 5],
+ [3, 8],
+ [4, 5],
+ [4, 7],
+ [5, 8]]
+ end
+
+ let(:duration) { 7 }
+
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 4 }
+ context 'test sample F' do
+ let(:data) do
+ [[1, 3],
+ [2, 4],
+ [2, 4],
+ [2, 4],
+ [5, 8]]
+ end
- it_behaves_like 'calculating duration'
- end
+ let(:duration) { 6 }
- context 'test sample E' do
- let(:data) do
- [[0, 1],
- [3, 9],
- [3, 4],
- [3, 5],
- [3, 8],
- [4, 5],
- [4, 7],
- [5, 8]]
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 7 }
+ context 'test sample G' do
+ let(:data) do
+ [[1, 3],
+ [2, 4],
+ [6, 7]]
+ end
- it_behaves_like 'calculating duration'
- end
+ let(:duration) { 4 }
- context 'test sample F' do
- let(:data) do
- [[1, 3],
- [2, 4],
- [2, 4],
- [2, 4],
- [5, 8]]
+ it_behaves_like 'calculating duration'
end
- let(:duration) { 6 }
+ def calculate(data)
+ periods = data.shuffle.map do |(first, last)|
+ described_class::Period.new(first, last)
+ end
- it_behaves_like 'calculating duration'
+ described_class.from_periods(periods.sort_by(&:first))
+ end
end
- context 'test sample G' do
- let(:data) do
- [[1, 3],
- [2, 4],
- [6, 7]]
+ describe '.from_pipeline' do
+ let_it_be(:start_time) { Time.current.change(usec: 0) }
+ let_it_be(:current) { start_time + 1000 }
+ let_it_be(:pipeline) { create(:ci_pipeline) }
+ let_it_be(:success_build) { create_build(:success, started_at: start_time, finished_at: start_time + 60) }
+ let_it_be(:failed_build) { create_build(:failed, started_at: start_time + 60, finished_at: start_time + 120) }
+ let_it_be(:canceled_build) { create_build(:canceled, started_at: start_time + 120, finished_at: start_time + 180) }
+ let_it_be(:skipped_build) { create_build(:skipped, started_at: start_time) }
+ let_it_be(:pending_build) { create_build(:pending) }
+ let_it_be(:created_build) { create_build(:created) }
+ let_it_be(:preparing_build) { create_build(:preparing) }
+ let_it_be(:scheduled_build) { create_build(:scheduled) }
+ let_it_be(:expired_scheduled_build) { create_build(:expired_scheduled) }
+ let_it_be(:manual_build) { create_build(:manual) }
+
+ let!(:running_build) { create_build(:running, started_at: start_time) }
+
+ it 'returns the duration of the running build' do
+ travel_to(current) do
+ expect(described_class.from_pipeline(pipeline)).to eq 1000.seconds
+ end
end
- let(:duration) { 4 }
+ context 'when there is no running build' do
+ let(:running_build) { nil }
- it_behaves_like 'calculating duration'
- end
+ it 'returns the duration for all the builds' do
+ travel_to(current) do
+ expect(described_class.from_pipeline(pipeline)).to eq 180.seconds
+ end
+ end
+ end
- def calculate(data)
- periods = data.shuffle.map do |(first, last)|
- described_class::Period.new(first, last)
+ context 'when there are bridge jobs' do
+ let!(:success_bridge) { create_bridge(:success, started_at: start_time + 220, finished_at: start_time + 280) }
+ let!(:failed_bridge) { create_bridge(:failed, started_at: start_time + 180, finished_at: start_time + 240) }
+ let!(:skipped_bridge) { create_bridge(:skipped, started_at: start_time) }
+ let!(:created_bridge) { create_bridge(:created) }
+ let!(:manual_bridge) { create_bridge(:manual) }
+
+ it 'returns the duration of the running build' do
+ travel_to(current) do
+ expect(described_class.from_pipeline(pipeline)).to eq 1000.seconds
+ end
+ end
+
+ context 'when there is no running build' do
+ let!(:running_build) { nil }
+
+ it 'returns the duration for all the builds and bridge jobs' do
+ travel_to(current) do
+ expect(described_class.from_pipeline(pipeline)).to eq 280.seconds
+ end
+ end
+ end
end
- described_class.from_periods(periods.sort_by(&:first))
+ private
+
+ def create_build(trait, **opts)
+ create(:ci_build, trait, pipeline: pipeline, **opts)
+ end
+
+ def create_bridge(trait, **opts)
+ create(:ci_bridge, trait, pipeline: pipeline, **opts)
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/logger_spec.rb b/spec/lib/gitlab/ci/pipeline/logger_spec.rb
index f31361431f2..3af0ebe7484 100644
--- a/spec/lib/gitlab/ci/pipeline/logger_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/logger_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
loggable_data = {
'expensive_operation_duration_s' => {
'count' => 1,
+ 'sum' => a_kind_of(Numeric),
'avg' => a_kind_of(Numeric),
'max' => a_kind_of(Numeric),
'min' => a_kind_of(Numeric)
@@ -62,6 +63,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
accumulator[key] = {
'count' => count,
'avg' => a_kind_of(Numeric),
+ 'sum' => a_kind_of(Numeric),
'max' => a_kind_of(Numeric),
'min' => a_kind_of(Numeric)
}
@@ -71,6 +73,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
data['expensive_operation_db_count']['max'] = db_count
data['expensive_operation_db_count']['min'] = db_count
data['expensive_operation_db_count']['avg'] = db_count
+ data['expensive_operation_db_count']['sum'] = count * db_count
end
data
@@ -131,7 +134,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
it 'records durations of observed operations' do
loggable_data = {
'pipeline_creation_duration_s' => {
- 'avg' => 30, 'count' => 1, 'max' => 30, 'min' => 30
+ 'avg' => 30, 'sum' => 30, 'count' => 1, 'max' => 30, 'min' => 30
}
}
@@ -165,10 +168,10 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
'pipeline_creation_caller' => 'source',
'pipeline_source' => pipeline.source,
'pipeline_save_duration_s' => {
- 'avg' => 60, 'count' => 1, 'max' => 60, 'min' => 60
+ 'avg' => 60, 'sum' => 60, 'count' => 1, 'max' => 60, 'min' => 60
},
'pipeline_creation_duration_s' => {
- 'avg' => 20, 'count' => 2, 'max' => 30, 'min' => 10
+ 'avg' => 20, 'sum' => 40, 'count' => 2, 'max' => 30, 'min' => 10
}
}
end
@@ -215,10 +218,10 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Logger do
'pipeline_creation_service_duration_s' => a_kind_of(Numeric),
'pipeline_creation_caller' => 'source',
'pipeline_save_duration_s' => {
- 'avg' => 60, 'count' => 1, 'max' => 60, 'min' => 60
+ 'avg' => 60, 'sum' => 60, 'count' => 1, 'max' => 60, 'min' => 60
},
'pipeline_creation_duration_s' => {
- 'avg' => 20, 'count' => 2, 'max' => 30, 'min' => 10
+ 'avg' => 20, 'sum' => 40, 'count' => 2, 'max' => 30, 'min' => 10
}
}
end