diff options
Diffstat (limited to 'spec/services/ci/create_downstream_pipeline_service_spec.rb')
-rw-r--r-- | spec/services/ci/create_downstream_pipeline_service_spec.rb | 101 |
1 files changed, 78 insertions, 23 deletions
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb index d61abf6a6ee..43eb57df66c 100644 --- a/spec/services/ci/create_downstream_pipeline_service_spec.rb +++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb @@ -441,44 +441,99 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do end end - context 'when relationship between pipelines is cyclical' do - before do - pipeline_a = create(:ci_pipeline, project: upstream_project) - pipeline_b = create(:ci_pipeline, project: downstream_project) - pipeline_c = create(:ci_pipeline, project: upstream_project) + describe 'cyclical dependency detection' do + shared_examples 'detects cyclical pipelines' do + it 'does not create a new pipeline' do + expect { service.execute(bridge) } + .not_to change { Ci::Pipeline.count } + end + + it 'changes status of the bridge build' do + service.execute(bridge) - create_source_pipeline(pipeline_a, pipeline_b) - create_source_pipeline(pipeline_b, pipeline_c) - create_source_pipeline(pipeline_c, upstream_pipeline) + expect(bridge.reload).to be_failed + expect(bridge.failure_reason).to eq 'pipeline_loop_detected' + end end - it 'does not create a new pipeline' do - expect { service.execute(bridge) } - .not_to change { Ci::Pipeline.count } + shared_examples 'passes cyclical pipeline precondition' do + it 'creates a new pipeline' do + expect { service.execute(bridge) } + .to change { Ci::Pipeline.count } + end + + it 'expect bridge build not to be failed' do + service.execute(bridge) + + expect(bridge.reload).not_to be_failed + end end - it 'changes status of the bridge build' do - service.execute(bridge) + context 'when pipeline ancestry contains 2 cycles of dependencies' do + before do + # A(push on master) -> B(pipeline on master) -> A(push on master) -> + # B(pipeline on master) -> A(push on master) + pipeline_1 = create(:ci_pipeline, project: upstream_project, source: :push) + pipeline_2 = create(:ci_pipeline, project: downstream_project, source: :pipeline) + pipeline_3 = create(:ci_pipeline, project: upstream_project, source: :push) + pipeline_4 = create(:ci_pipeline, project: downstream_project, source: :pipeline) + + create_source_pipeline(pipeline_1, pipeline_2) + create_source_pipeline(pipeline_2, pipeline_3) + create_source_pipeline(pipeline_3, pipeline_4) + create_source_pipeline(pipeline_4, upstream_pipeline) + end - expect(bridge.reload).to be_failed - expect(bridge.failure_reason).to eq 'pipeline_loop_detected' + it_behaves_like 'detects cyclical pipelines' + + context 'when ci_drop_cyclical_triggered_pipelines is not enabled' do + before do + stub_feature_flags(ci_drop_cyclical_triggered_pipelines: false) + end + + it_behaves_like 'passes cyclical pipeline precondition' + end end - context 'when ci_drop_cyclical_triggered_pipelines is not enabled' do + context 'when source in the ancestry differ' do before do - stub_feature_flags(ci_drop_cyclical_triggered_pipelines: false) + # A(push on master) -> B(pipeline on master) -> A(pipeline on master) + pipeline_1 = create(:ci_pipeline, project: upstream_project, source: :push) + pipeline_2 = create(:ci_pipeline, project: downstream_project, source: :pipeline) + upstream_pipeline.update!(source: :pipeline) + + create_source_pipeline(pipeline_1, pipeline_2) + create_source_pipeline(pipeline_2, upstream_pipeline) end - it 'creates a new pipeline' do - expect { service.execute(bridge) } - .to change { Ci::Pipeline.count } + it_behaves_like 'passes cyclical pipeline precondition' + end + + context 'when ref in the ancestry differ' do + before do + # A(push on master) -> B(pipeline on master) -> A(push on feature-1) + pipeline_1 = create(:ci_pipeline, ref: 'master', project: upstream_project, source: :push) + pipeline_2 = create(:ci_pipeline, ref: 'master', project: downstream_project, source: :pipeline) + upstream_pipeline.update!(ref: 'feature-1') + + create_source_pipeline(pipeline_1, pipeline_2) + create_source_pipeline(pipeline_2, upstream_pipeline) end - it 'expect bridge build not to be failed' do - service.execute(bridge) + it_behaves_like 'passes cyclical pipeline precondition' + end - expect(bridge.reload).not_to be_failed + context 'when only 1 cycle is detected' do + before do + # A(push on master) -> B(pipeline on master) -> A(push on master) + pipeline_1 = create(:ci_pipeline, ref: 'master', project: upstream_project, source: :push) + pipeline_2 = create(:ci_pipeline, ref: 'master', project: downstream_project, source: :pipeline) + + create_source_pipeline(pipeline_1, pipeline_2) + create_source_pipeline(pipeline_2, upstream_pipeline) end + + it_behaves_like 'passes cyclical pipeline precondition' end end |