Commit d1b59476 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Make pipeline processing specs more consistent

parent 364fc01e
require 'spec_helper' require 'spec_helper'
describe Ci::ProcessPipelineService, :services do describe Ci::ProcessPipelineService, '#execute', :services do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
...@@ -12,7 +12,6 @@ describe Ci::ProcessPipelineService, :services do ...@@ -12,7 +12,6 @@ describe Ci::ProcessPipelineService, :services do
project.add_developer(user) project.add_developer(user)
end end
describe '#execute' do
context 'start queuing next builds' do context 'start queuing next builds' do
before do before do
create_build('linux', stage_idx: 0) create_build('linux', stage_idx: 0)
...@@ -24,17 +23,20 @@ describe Ci::ProcessPipelineService, :services do ...@@ -24,17 +23,20 @@ describe Ci::ProcessPipelineService, :services do
it 'processes a pipeline' do it 'processes a pipeline' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
succeed_pending succeed_pending
expect(builds.success.count).to eq(2)
expect(builds.success.count).to eq(2)
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
succeed_pending succeed_pending
expect(builds.success.count).to eq(4)
expect(builds.success.count).to eq(4)
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
succeed_pending succeed_pending
expect(builds.success.count).to eq(5)
expect(builds.success.count).to eq(5)
expect(process_pipeline).to be_falsey expect(process_pipeline).to be_falsey
end end
...@@ -55,10 +57,11 @@ describe Ci::ProcessPipelineService, :services do ...@@ -55,10 +57,11 @@ describe Ci::ProcessPipelineService, :services do
it 'automatically triggers a next stage when build finishes' do it 'automatically triggers a next stage when build finishes' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:drop) fail_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('failed', 'pending')
expect(builds_statuses).to eq ['failed', 'pending']
end end
end end
...@@ -76,119 +79,132 @@ describe Ci::ProcessPipelineService, :services do ...@@ -76,119 +79,132 @@ describe Ci::ProcessPipelineService, :services do
context 'when builds are successful' do context 'when builds are successful' do
it 'properly creates builds' do it 'properly creates builds' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build') expect(builds_names).to eq ['build']
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') expect(builds_names).to eq ['build', 'test']
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') expect(builds_statuses).to eq ['success', 'pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending')
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success') expect(builds_names).to eq ['build', 'test', 'deploy']
pipeline.reload expect(builds_statuses).to eq ['success', 'success', 'pending']
expect(pipeline.status).to eq('success')
succeed_running_or_pending
expect(builds_names).to eq ['build', 'test', 'deploy', 'cleanup']
expect(builds_statuses).to eq ['success', 'success', 'success', 'pending']
succeed_running_or_pending
expect(builds_statuses).to eq ['success', 'success', 'success', 'success']
expect(pipeline.reload.status).to eq 'success'
end end
end end
context 'when test job fails' do context 'when test job fails' do
it 'properly creates builds' do it 'properly creates builds' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build') expect(builds_names).to eq ['build']
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
pipeline.builds.running_or_pending.each(&:drop)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') expect(builds_names).to eq ['build', 'test']
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') expect(builds_statuses).to eq ['success', 'pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') fail_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending')
pipeline.builds.running_or_pending.each(&:success) expect(builds_names).to eq ['build', 'test', 'test_failure']
expect(builds_statuses).to eq ['success', 'failed', 'pending']
succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success') expect(builds_names).to eq ['build', 'test', 'test_failure', 'cleanup']
pipeline.reload expect(builds_statuses).to eq ['success', 'failed', 'success', 'pending']
expect(pipeline.status).to eq('failed')
succeed_running_or_pending
expect(builds_statuses).to eq ['success', 'failed', 'success', 'success']
expect(pipeline.reload.status).to eq 'failed'
end end
end end
context 'when test and test_failure jobs fail' do context 'when test and test_failure jobs fail' do
it 'properly creates builds' do it 'properly creates builds' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build') expect(builds_names).to eq ['build']
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
pipeline.builds.running_or_pending.each(&:drop)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure') expect(builds_names).to eq ['build', 'test']
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending') expect(builds_statuses).to eq ['success', 'pending']
pipeline.builds.running_or_pending.each(&:drop)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') fail_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending')
pipeline.builds.running_or_pending.each(&:success) expect(builds_names).to eq ['build', 'test', 'test_failure']
expect(builds_statuses).to eq ['success', 'failed', 'pending']
fail_running_or_pending
expect(builds_names).to eq ['build', 'test', 'test_failure', 'cleanup']
expect(builds_statuses).to eq ['success', 'failed', 'failed', 'pending']
succeed_running_or_pending
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup') expect(builds_names).to eq ['build', 'test', 'test_failure', 'cleanup']
expect(builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success') expect(builds_statuses).to eq ['success', 'failed', 'failed', 'success']
pipeline.reload expect(pipeline.reload.status).to eq('failed')
expect(pipeline.status).to eq('failed')
end end
end end
context 'when deploy job fails' do context 'when deploy job fails' do
it 'properly creates builds' do it 'properly creates builds' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build') expect(builds_names).to eq ['build']
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
pipeline.builds.running_or_pending.each(&:success)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy') expect(builds_names).to eq ['build', 'test']
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'pending') expect(builds_statuses).to eq ['success', 'pending']
pipeline.builds.running_or_pending.each(&:drop)
expect(builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup') succeed_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending')
pipeline.builds.running_or_pending.each(&:success) expect(builds_names).to eq ['build', 'test', 'deploy']
expect(builds_statuses).to eq ['success', 'success', 'pending']
expect(builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success') fail_running_or_pending
pipeline.reload
expect(pipeline.status).to eq('failed') expect(builds_names).to eq ['build', 'test', 'deploy', 'cleanup']
expect(builds_statuses).to eq ['success', 'success', 'failed', 'pending']
succeed_running_or_pending
expect(builds_statuses).to eq ['success', 'success', 'failed', 'success']
expect(pipeline.reload.status).to eq('failed')
end end
end end
context 'when build is canceled in the second stage' do context 'when build is canceled in the second stage' do
it 'does not schedule builds after build has been canceled' do it 'does not schedule builds after build has been canceled' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build') expect(builds_names).to eq ['build']
expect(builds.pluck(:status)).to contain_exactly('pending') expect(builds_statuses).to eq ['pending']
pipeline.builds.running_or_pending.each(&:success)
succeed_running_or_pending
expect(builds.running_or_pending).not_to be_empty expect(builds.running_or_pending).not_to be_empty
expect(builds_names).to eq ['build', 'test']
expect(builds_statuses).to eq ['success', 'pending']
expect(builds.pluck(:name)).to contain_exactly('build', 'test') cancel_running_or_pending
expect(builds.pluck(:status)).to contain_exactly('success', 'pending')
pipeline.builds.running_or_pending.each(&:cancel)
expect(builds.running_or_pending).to be_empty expect(builds.running_or_pending).to be_empty
expect(pipeline.reload.status).to eq('canceled') expect(pipeline.reload.status).to eq 'canceled'
end end
end end
...@@ -199,70 +215,71 @@ describe Ci::ProcessPipelineService, :services do ...@@ -199,70 +215,71 @@ describe Ci::ProcessPipelineService, :services do
expect(manual_actions).to be_empty expect(manual_actions).to be_empty
# succeed stage build # succeed stage build
pipeline.builds.running_or_pending.each(&:success) succeed_running_or_pending
expect(manual_actions).to be_empty expect(manual_actions).to be_empty
# succeed stage test # succeed stage test
pipeline.builds.running_or_pending.each(&:success) succeed_running_or_pending
expect(manual_actions).to be_one # production expect(manual_actions).to be_one # production
# succeed stage deploy # succeed stage deploy
pipeline.builds.running_or_pending.each(&:success) succeed_running_or_pending
expect(manual_actions).to be_many # production and clear cache expect(manual_actions).to be_many # production and clear cache
end end
end end
end end
context 'when there are manual/on_failure jobs in earlier stages' do context 'when there are manual/on_failure jobs in earlier stages' do
context 'when first stage has only optional manual actions' do
before do before do
builds create_build('build', stage_idx: 0, when: 'manual', allow_failure: true)
process_pipeline create_build('check', stage_idx: 1)
builds.each(&:reload) create_build('test', stage_idx: 2)
end
context 'when first stage has only optional manual actions' do process_pipeline
let(:builds) do
[create_build('build', stage_idx: 0, when: 'manual', allow_failure: true),
create_build('check', stage_idx: 1),
create_build('test', stage_idx: 2)]
end end
it 'starts from the second stage' do it 'starts from the second stage' do
expect(builds.map(&:status)).to eq(%w[skipped pending created]) expect(all_builds_statuses).to eq %w[skipped pending created]
end end
end end
context 'when second stage has only optional manual actions' do context 'when second stage has only optional manual actions' do
let(:builds) do before do
[create_build('check', stage_idx: 0), create_build('check', stage_idx: 0)
create_build('build', stage_idx: 1, when: 'manual', allow_failure: true), create_build('build', stage_idx: 1, when: 'manual', allow_failure: true)
create_build('test', stage_idx: 2)] create_build('test', stage_idx: 2)
process_pipeline
end end
it 'skips second stage and continues on third stage' do it 'skips second stage and continues on third stage' do
expect(builds.map(&:status)).to eq(%w[pending created created]) expect(all_builds_statuses).to eq(%w[pending created created])
builds.first.success builds.first.success
builds.each(&:reload)
expect(builds.map(&:status)).to eq(%w[success skipped pending]) expect(all_builds_statuses).to eq(%w[success skipped pending])
end end
end end
context 'when second stage has only on_failure jobs' do context 'when second stage has only on_failure jobs' do
let(:builds) do before do
[create_build('check', stage_idx: 0), create_build('check', stage_idx: 0)
create_build('build', stage_idx: 1, when: 'on_failure'), create_build('build', stage_idx: 1, when: 'on_failure')
create_build('test', stage_idx: 2)] create_build('test', stage_idx: 2)
process_pipeline
end end
it 'skips second stage and continues on third stage' do it 'skips second stage and continues on third stage' do
expect(builds.map(&:status)).to eq(%w[pending created created]) expect(all_builds_statuses).to eq(%w[pending created created])
builds.first.success builds.first.success
builds.each(&:reload)
expect(builds.map(&:status)).to eq(%w[success skipped pending]) expect(all_builds_statuses).to eq(%w[success skipped pending])
end end
end end
end end
...@@ -280,23 +297,21 @@ describe Ci::ProcessPipelineService, :services do ...@@ -280,23 +297,21 @@ describe Ci::ProcessPipelineService, :services do
it 'does trigger builds in the next stage' do it 'does trigger builds in the next stage' do
expect(process_pipeline).to be_truthy expect(process_pipeline).to be_truthy
expect(builds.pluck(:name)).to contain_exactly('build:1', 'build:2') expect(builds_names).to eq ['build:1', 'build:2']
pipeline.builds.running_or_pending.each(&:success) succeed_running_or_pending
expect(builds.pluck(:name)) expect(builds_names).to eq ['build:1', 'build:2', 'test:1', 'test:2']
.to contain_exactly('build:1', 'build:2', 'test:1', 'test:2')
pipeline.builds.find_by(name: 'test:1').success pipeline.builds.find_by(name: 'test:1').success
pipeline.builds.find_by(name: 'test:2').drop pipeline.builds.find_by(name: 'test:2').drop
expect(builds.pluck(:name)) expect(builds_names).to eq ['build:1', 'build:2', 'test:1', 'test:2']
.to contain_exactly('build:1', 'build:2', 'test:1', 'test:2')
Ci::Build.retry(pipeline.builds.find_by(name: 'test:2'), user).success Ci::Build.retry(pipeline.builds.find_by(name: 'test:2'), user).success
expect(builds.pluck(:name)).to contain_exactly( expect(builds_names).to eq ['build:1', 'build:2', 'test:1', 'test:2',
'build:1', 'build:2', 'test:1', 'test:2', 'test:2', 'deploy:1', 'deploy:2') 'test:2', 'deploy:1', 'deploy:2']
end end
end end
end end
...@@ -359,16 +374,27 @@ describe Ci::ProcessPipelineService, :services do ...@@ -359,16 +374,27 @@ describe Ci::ProcessPipelineService, :services do
expect(all_builds.count).to eq(4) expect(all_builds.count).to eq(4)
end end
end end
end
def all_builds def all_builds
pipeline.builds pipeline.builds.order(:stage_idx, :id)
end end
def builds def builds
all_builds.where.not(status: [:created, :skipped]) all_builds.where.not(status: [:created, :skipped])
end end
def builds_names
builds.pluck(:name)
end
def builds_statuses
builds.pluck(:status)
end
def all_builds_statuses
all_builds.pluck(:status)
end
def process_pipeline def process_pipeline
described_class.new(pipeline.project, user).execute(pipeline) described_class.new(pipeline.project, user).execute(pipeline)
end end
...@@ -377,6 +403,18 @@ describe Ci::ProcessPipelineService, :services do ...@@ -377,6 +403,18 @@ describe Ci::ProcessPipelineService, :services do
builds.pending.update_all(status: 'success') builds.pending.update_all(status: 'success')
end end
def succeed_running_or_pending
pipeline.builds.running_or_pending.each(&:success)
end
def fail_running_or_pending
pipeline.builds.running_or_pending.each(&:drop)
end
def cancel_running_or_pending
pipeline.builds.running_or_pending.each(&:cancel)
end
delegate :manual_actions, to: :pipeline delegate :manual_actions, to: :pipeline
def create_build(name, **opts) def create_build(name, **opts)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment