Commit d1b59476 authored by Grzegorz Bizon's avatar Grzegorz Bizon

Make pipeline processing specs more consistent

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