diff options
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline/chain')
6 files changed, 280 insertions, 24 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 31bffcbeb2a..00f834fcf80 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 @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } - let_it_be(:pipeline) { create(:ci_pipeline, project: project) } + let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) } let_it_be(:command) { Gitlab::Ci::Pipeline::Chain::Command.new(project: project, current_user: user) } let_it_be(:step) { described_class.new(pipeline, command) } @@ -17,5 +17,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines, feature_cate subject end + + context 'with scheduled pipelines' do + before do + pipeline.source = :schedule + end + + it 'enqueues LowUrgencyCancelRedundantPipelinesWorker' do + expect(Ci::LowUrgencyCancelRedundantPipelinesWorker) + .to receive(:perform_async).with(pipeline.id) + + subject + end + end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb index eb5a37f19f4..44ccb1eeae1 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/evaluate_workflow_rules_spec.rb @@ -12,10 +12,13 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do end let(:step) { described_class.new(pipeline, command) } + let(:ff_always_set_pipeline_failure_reason) { true } describe '#perform!' do context 'when pipeline has been skipped by workflow configuration' do before do + stub_feature_flags(always_set_pipeline_failure_reason: ff_always_set_pipeline_failure_reason) + allow(step).to receive(:workflow_rules_result) .and_return( double(pass?: false, variables: {}) @@ -39,6 +42,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do it 'saves workflow_rules_result' do expect(command.workflow_rules_result.variables).to eq({}) end + + it 'sets the failure reason', :aggregate_failures do + expect(pipeline).to be_failed + expect(pipeline).to be_filtered_by_workflow_rules + end + + context 'when always_set_pipeline_failure_reason is disabled' do + let(:ff_always_set_pipeline_failure_reason) { false } + + it 'does not set the failure reason', :aggregate_failures do + expect(pipeline).not_to be_failed + expect(pipeline.failure_reason).to be_blank + end + end end context 'when pipeline has not been skipped by workflow configuration' do @@ -67,6 +84,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules do it 'saves workflow_rules_result' do expect(command.workflow_rules_result.variables).to eq({ 'VAR1' => 'val2', 'VAR2' => 3 }) end + + it 'does not set a failure reason' do + expect(pipeline).not_to be_filtered_by_workflow_rules + end end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb index 96ada90b4e1..84c2fb6525e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/helpers_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do +RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers, feature_category: :continuous_integration do let(:helper_class) do Class.new do include Gitlab::Ci::Pipeline::Chain::Helpers @@ -38,14 +38,35 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do describe '.error' do shared_examples 'error function' do specify do - expect(pipeline).to receive(:drop!).with(drop_reason).and_call_original expect(pipeline).to receive(:add_error_message).with(message).and_call_original - expect(pipeline).to receive(:ensure_project_iid!).twice.and_call_original + + if command.save_incompleted + expect(pipeline).to receive(:ensure_project_iid!).twice.and_call_original + expect(pipeline).to receive(:drop!).with(drop_reason).and_call_original + end subject.error(message, config_error: config_error, drop_reason: drop_reason) expect(pipeline.yaml_errors).to eq(yaml_error) expect(pipeline.errors[:base]).to include(message) + expect(pipeline.status).to eq 'failed' + expect(pipeline.failure_reason).to eq drop_reason.to_s + end + + context 'when feature flag always_set_pipeline_failure_reason is false' do + before do + stub_feature_flags(always_set_pipeline_failure_reason: false) + end + + specify do + subject.error(message, config_error: config_error, drop_reason: drop_reason) + + if command.save_incompleted + expect(pipeline.failure_reason).to eq drop_reason.to_s + else + expect(pipeline.failure_reason).not_to be_present + end + end end end @@ -79,6 +100,43 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Helpers do let(:yaml_error) { nil } it_behaves_like "error function" + + specify do + subject.error(message, config_error: config_error, drop_reason: drop_reason) + + expect(pipeline).to be_persisted + end + + context ' when the drop reason is not persistable' do + let(:drop_reason) { :filtered_by_rules } + let(:command) { double(project: nil) } + + specify do + expect(command).to receive(:increment_pipeline_failure_reason_counter) + + subject.error(message, config_error: config_error, drop_reason: drop_reason) + + expect(pipeline).to be_failed + expect(pipeline.failure_reason).to eq drop_reason.to_s + expect(pipeline).not_to be_persisted + end + end + + context 'when save_incompleted is false' do + let(:command) { double(save_incompleted: false, project: nil) } + + before do + allow(command).to receive(:increment_pipeline_failure_reason_counter) + end + + it_behaves_like "error function" + + specify do + subject.error(message, config_error: config_error, drop_reason: drop_reason) + + expect(pipeline).not_to be_persisted + end + end end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb index 00200b57b1e..732748d8c8b 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do +RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata, feature_category: :pipeline_composition do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } @@ -43,16 +43,28 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do stub_ci_pipeline_yaml_file(YAML.dump(config)) end - context 'with pipeline name' do - let(:config) do - { workflow: { name: ' Pipeline name ' }, rspec: { script: 'rspec' } } - end - + shared_examples 'not breaking the chain' do it 'does not break the chain' do run_chain expect(step.break?).to be false end + end + + shared_examples 'not saving pipeline metadata' do + it 'does not save pipeline metadata' do + run_chain + + expect(pipeline.pipeline_metadata).to be_nil + end + end + + context 'with pipeline name' do + let(:config) do + { workflow: { name: ' Pipeline name ' }, rspec: { script: 'rspec' } } + end + + it_behaves_like 'not breaking the chain' it 'builds pipeline_metadata' do run_chain @@ -67,22 +79,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do { workflow: { name: ' ' }, rspec: { script: 'rspec' } } end - it 'strips whitespace from name' do - run_chain - - expect(pipeline.pipeline_metadata).to be_nil - end + it_behaves_like 'not saving pipeline metadata' context 'with empty name after variable substitution' do let(:config) do { workflow: { name: '$VAR1' }, rspec: { script: 'rspec' } } end - it 'does not save empty name' do - run_chain - - expect(pipeline.pipeline_metadata).to be_nil - end + it_behaves_like 'not saving pipeline metadata' end end @@ -127,4 +131,140 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do end end end + + context 'with auto_cancel' do + let(:on_new_commit) { 'interruptible' } + let(:on_job_failure) { 'all' } + let(:auto_cancel) { { on_new_commit: on_new_commit, on_job_failure: on_job_failure } } + let(:config) { { workflow: { auto_cancel: auto_cancel }, rspec: { script: 'rspec' } } } + + it_behaves_like 'not breaking the chain' + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + + context 'with no auto_cancel' do + let(:config) do + { rspec: { script: 'rspec' } } + end + + it_behaves_like 'not saving pipeline metadata' + end + + context 'with auto_cancel: nil' do + let(:auto_cancel) { nil } + + it_behaves_like 'not saving pipeline metadata' + end + + context 'with auto_cancel_on_new_commit and no auto_cancel_on_job_failure' do + let(:auto_cancel) { { on_new_commit: on_new_commit } } + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + + context 'with auto_cancel_on_job_failure and no auto_cancel_on_new_commit' do + let(:auto_cancel) { { on_job_failure: on_job_failure } } + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('conservative') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + + context 'with auto_cancel_on_new_commit: nil and auto_cancel_on_job_failure: nil' do + let(:on_new_commit) { nil } + let(:on_job_failure) { nil } + + it_behaves_like 'not saving pipeline metadata' + end + + context 'with auto_cancel_on_new_commit valid and auto_cancel_on_job_failure: nil' do + let(:on_job_failure) { nil } + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + + context 'with auto_cancel_on_new_commit: nil and auto_cancel_on_job_failure valid' do + let(:on_new_commit) { nil } + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('conservative') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('all') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + + context 'when auto_cancel_on_job_failure: none' do + let(:on_job_failure) { 'none' } + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + + context 'when auto_cancel_pipeline_on_job_failure feature is disabled' do + before do + stub_feature_flags(auto_cancel_pipeline_on_job_failure: false) + end + + it 'ignores the auto_cancel_on_job_failure value' do + run_chain + + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + end + end + + context 'with both pipeline name and auto_cancel' do + let(:config) do + { + workflow: { + name: 'Pipeline name', + auto_cancel: { + on_new_commit: 'interruptible', + on_job_failure: 'none' + } + }, + rspec: { script: 'rspec' } + } + end + + it_behaves_like 'not breaking the chain' + + it 'builds pipeline_metadata' do + run_chain + + expect(pipeline.pipeline_metadata.name).to eq('Pipeline name') + expect(pipeline.pipeline_metadata.auto_cancel_on_new_commit).to eq('interruptible') + expect(pipeline.pipeline_metadata.auto_cancel_on_job_failure).to eq('none') + expect(pipeline.pipeline_metadata).not_to be_persisted + end + 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 91bb94bbb11..476b1be35a9 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb @@ -34,12 +34,15 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate, feature_category: :continu { rspec: { script: 'rspec' } } end + let(:ff_always_set_pipeline_failure_reason) { true } + def run_chain dependencies.map(&:perform!) step.perform! end before do + stub_feature_flags(always_set_pipeline_failure_reason: ff_always_set_pipeline_failure_reason) stub_ci_pipeline_yaml_file(YAML.dump(config)) end @@ -100,7 +103,27 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate, feature_category: :continu it 'increments the error metric' do counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc') - expect { run_chain }.to change { counter.get(reason: 'unknown_failure') }.by(1) + expect { run_chain }.to change { counter.get(reason: 'filtered_by_rules') }.by(1) + end + + it 'sets the failure reason without persisting the pipeline', :aggregate_failures do + run_chain + + expect(pipeline).not_to be_persisted + expect(pipeline).to be_failed + expect(pipeline).to be_filtered_by_rules + end + + context 'when ff always_set_pipeline_failure_reason is disabled' do + let(:ff_always_set_pipeline_failure_reason) { false } + + it 'sets the failure reason without persisting the pipeline', :aggregate_failures do + run_chain + + expect(pipeline).not_to be_persisted + expect(pipeline).not_to be_failed + expect(pipeline).not_to be_filtered_by_rules + end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb index 52a00e0d501..4017076d29f 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do +RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user, :with_sign_ins) } @@ -328,11 +328,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do context 'when save_incompleted is false' do let(:save_incompleted) { false } - it 'adds errors to the pipeline without dropping it' do + it 'adds errors to the pipeline without persisting it', :aggregate_failures do perform! - expect(pipeline.status).to eq('pending') expect(pipeline).not_to be_persisted + expect(pipeline.status).to eq('failed') + expect(pipeline).to be_external_validation_failure expect(pipeline.errors.to_a).to include('External validation failed') end |