gitlab-org--gitlab-foss/spec/models/ci/pipeline_spec.rb

1127 lines
30 KiB
Ruby
Raw Normal View History

2015-08-25 21:42:46 -04:00
require 'spec_helper'
describe Ci::Pipeline, models: true do
include EmailHelpers
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:pipeline) do
create(:ci_empty_pipeline, status: :created, project: project)
end
2015-08-25 21:42:46 -04:00
2015-12-04 06:55:23 -05:00
it { is_expected.to belong_to(:project) }
2016-07-15 09:42:29 -04:00
it { is_expected.to belong_to(:user) }
2016-03-10 05:06:33 -05:00
it { is_expected.to have_many(:statuses) }
2015-10-06 06:01:16 -04:00
it { is_expected.to have_many(:trigger_requests) }
2015-09-10 09:52:52 -04:00
it { is_expected.to have_many(:builds) }
2016-07-15 09:42:29 -04:00
2015-09-10 09:52:52 -04:00
it { is_expected.to validate_presence_of :sha }
2016-04-16 16:43:40 -04:00
it { is_expected.to validate_presence_of :status }
2015-08-25 21:42:46 -04:00
2015-09-10 09:52:52 -04:00
it { is_expected.to respond_to :git_author_name }
it { is_expected.to respond_to :git_author_email }
it { is_expected.to respond_to :short_sha }
2015-08-25 21:42:46 -04:00
describe '#block' do
it 'changes pipeline status to manual' do
expect(pipeline.block).to be true
expect(pipeline.reload).to be_manual
expect(pipeline.reload).to be_blocked
end
end
2016-07-11 18:12:31 -04:00
describe '#valid_commit_sha' do
2015-08-25 21:42:46 -04:00
context 'commit.sha can not start with 00000000' do
before do
pipeline.sha = '0' * 40
pipeline.valid_commit_sha
2015-08-25 21:42:46 -04:00
end
it('commit errors should not be empty') { expect(pipeline.errors).not_to be_empty }
2015-08-25 21:42:46 -04:00
end
end
2016-07-11 18:12:31 -04:00
describe '#short_sha' do
subject { pipeline.short_sha }
2015-08-25 21:42:46 -04:00
2015-09-10 09:52:52 -04:00
it 'has 8 items' do
expect(subject.size).to eq(8)
end
it { expect(pipeline.sha).to start_with(subject) }
2015-08-25 21:42:46 -04:00
end
2016-07-11 18:12:31 -04:00
describe '#retried' do
subject { pipeline.retried }
2015-10-06 06:01:16 -04:00
before do
@build1 = FactoryGirl.create :ci_build, pipeline: pipeline, name: 'deploy'
@build2 = FactoryGirl.create :ci_build, pipeline: pipeline, name: 'deploy'
2015-10-06 06:01:16 -04:00
end
it 'returns old builds' do
is_expected.to contain_exactly(@build1)
2015-10-06 06:01:16 -04:00
end
end
2015-08-25 21:42:46 -04:00
describe "coverage" do
2015-12-04 06:55:23 -05:00
let(:project) { FactoryGirl.create :empty_project, build_coverage_regex: "/.*/" }
let(:pipeline) { FactoryGirl.create :ci_empty_pipeline, project: project }
2015-08-25 21:42:46 -04:00
it "calculates average when there are two builds with coverage" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
expect(pipeline.coverage).to eq("35.00")
2015-08-25 21:42:46 -04:00
end
it "calculates average when there are two builds with coverage and one with nil" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
FactoryGirl.create :ci_build, pipeline: pipeline
expect(pipeline.coverage).to eq("35.00")
2015-08-25 21:42:46 -04:00
end
it "calculates average when there are two builds with coverage and one is retried" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, pipeline: pipeline
FactoryGirl.create :ci_build, name: "rubocop", coverage: 30, pipeline: pipeline
FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, pipeline: pipeline
expect(pipeline.coverage).to eq("35.00")
2015-08-25 21:42:46 -04:00
end
it "calculates average when there is one build without coverage" do
FactoryGirl.create :ci_build, pipeline: pipeline
expect(pipeline.coverage).to be_nil
2015-08-25 21:42:46 -04:00
end
end
2016-04-16 16:43:40 -04:00
describe '#retryable?' do
subject { pipeline.retryable? }
2016-04-16 16:43:40 -04:00
context 'no failed builds' do
before do
create_build('rspec', 'success')
2016-04-16 16:43:40 -04:00
end
it 'is not retryable' do
2016-04-16 16:43:40 -04:00
is_expected.to be_falsey
end
context 'one canceled job' do
before do
create_build('rubocop', 'canceled')
end
it 'is retryable' do
is_expected.to be_truthy
end
end
2016-04-16 16:43:40 -04:00
end
context 'with failed builds' do
before do
create_build('rspec', 'running')
create_build('rubocop', 'failed')
2016-04-16 16:43:40 -04:00
end
it 'is retryable' do
2016-04-16 16:43:40 -04:00
is_expected.to be_truthy
end
end
def create_build(name, status)
create(:ci_build, name: name, status: status, pipeline: pipeline)
end
2016-04-16 16:43:40 -04:00
end
describe 'pipeline stages' do
2016-04-16 16:43:40 -04:00
before do
create(:commit_status, pipeline: pipeline,
stage: 'build',
name: 'linux',
stage_idx: 0,
status: 'success')
create(:commit_status, pipeline: pipeline,
stage: 'build',
name: 'mac',
stage_idx: 0,
status: 'failed')
create(:commit_status, pipeline: pipeline,
stage: 'deploy',
name: 'staging',
stage_idx: 2,
status: 'running')
create(:commit_status, pipeline: pipeline,
stage: 'test',
name: 'rspec',
stage_idx: 1,
status: 'success')
end
describe '#stages' do
subject { pipeline.stages }
context 'stages list' do
it 'returns ordered list of stages' do
expect(subject.map(&:name)).to eq(%w[build test deploy])
end
end
context 'stages with statuses' do
let(:statuses) do
subject.map { |stage| [stage.name, stage.status] }
end
it 'returns list of stages with correct statuses' do
2017-02-22 12:46:57 -05:00
expect(statuses).to eq([%w(build failed),
%w(test success),
%w(deploy running)])
end
2016-12-06 08:49:37 -05:00
context 'when commit status is retried' do
before do
create(:commit_status, pipeline: pipeline,
stage: 'build',
name: 'mac',
stage_idx: 0,
status: 'success')
end
it 'ignores the previous state' do
2017-02-22 12:46:57 -05:00
expect(statuses).to eq([%w(build success),
%w(test success),
%w(deploy running)])
end
end
end
context 'when there is a stage with warnings' do
before do
create(:commit_status, pipeline: pipeline,
stage: 'deploy',
name: 'prod:2',
stage_idx: 2,
status: 'failed',
allow_failure: true)
end
it 'populates stage with correct number of warnings' do
deploy_stage = pipeline.stages.third
expect(deploy_stage).not_to receive(:statuses)
expect(deploy_stage).to have_warnings
end
end
end
describe '#stages_count' do
it 'returns a valid number of stages' do
expect(pipeline.stages_count).to eq(3)
end
end
describe '#stages_name' do
it 'returns a valid names of stages' do
2017-02-22 12:46:57 -05:00
expect(pipeline.stages_name).to eq(%w(build test deploy))
end
2016-04-16 16:43:40 -04:00
end
end
2016-12-20 05:00:56 -05:00
describe '#stage' do
subject { pipeline.stage('test') }
context 'with status in stage' do
2016-12-20 05:26:24 -05:00
before do
create(:commit_status, pipeline: pipeline, stage: 'test')
2016-12-20 05:00:56 -05:00
end
2016-12-20 05:26:24 -05:00
it { expect(subject).to be_a Ci::Stage }
it { expect(subject.name).to eq 'test' }
it { expect(subject.statuses).not_to be_empty }
2016-12-20 05:00:56 -05:00
end
context 'without status in stage' do
2016-12-20 05:26:24 -05:00
before do
create(:commit_status, pipeline: pipeline, stage: 'build')
end
2016-12-20 05:00:56 -05:00
it 'return stage object' do
is_expected.to be_nil
end
end
end
describe 'state machine' do
let(:current) { Time.now.change(usec: 0) }
2016-10-26 05:34:40 -04:00
let(:build) { create_build('build1', 0) }
let(:build_b) { create_build('build2', 0) }
let(:build_c) { create_build('build3', 0) }
2016-04-16 16:43:40 -04:00
describe '#duration' do
before do
travel_to(current + 30) do
2016-10-26 05:47:30 -04:00
build.run!
build.success!
build_b.run!
build_c.run!
2016-08-29 14:54:07 -04:00
end
travel_to(current + 40) do
2016-10-26 05:47:30 -04:00
build_b.drop!
end
travel_to(current + 70) do
2016-10-26 05:47:30 -04:00
build_c.success!
end
end
it 'matches sum of builds duration' do
pipeline.reload
expect(pipeline.duration).to eq(40)
end
2016-04-16 16:43:40 -04:00
end
describe '#started_at' do
it 'updates on transitioning to running' do
build.run
2016-04-16 16:43:40 -04:00
expect(pipeline.reload.started_at).not_to be_nil
end
2016-08-12 07:57:58 -04:00
it 'does not update on transitioning to success' do
build.success
expect(pipeline.reload.started_at).to be_nil
2016-04-16 16:43:40 -04:00
end
end
describe '#finished_at' do
it 'updates on transitioning to success' do
build.success
2016-04-16 16:43:40 -04:00
expect(pipeline.reload.finished_at).not_to be_nil
2016-04-16 16:43:40 -04:00
end
2016-08-12 07:57:58 -04:00
it 'does not update on transitioning to running' do
build.run
expect(pipeline.reload.finished_at).to be_nil
2016-04-16 16:43:40 -04:00
end
end
describe 'merge request metrics' do
let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
before do
expect(PipelineMetricsWorker).to receive(:perform_async).with(pipeline.id)
end
context 'when transitioning to running' do
it 'schedules metrics workers' do
pipeline.run
end
end
context 'when transitioning to success' do
it 'schedules metrics workers' do
pipeline.succeed
end
end
end
def create_build(name, queued_at = current, started_from = 0)
2016-08-29 14:54:07 -04:00
create(:ci_build,
name: name,
pipeline: pipeline,
queued_at: queued_at,
started_at: queued_at + started_from)
2016-08-29 14:54:07 -04:00
end
2016-04-16 16:43:40 -04:00
end
2016-04-18 07:35:43 -04:00
describe '#branch?' do
subject { pipeline.branch? }
2016-04-18 07:35:43 -04:00
context 'is not a tag' do
before do
pipeline.tag = false
2016-04-18 07:35:43 -04:00
end
it 'return true when tag is set to false' do
is_expected.to be_truthy
end
end
context 'is not a tag' do
before do
pipeline.tag = true
2016-04-18 07:35:43 -04:00
end
it 'return false when tag is set to true' do
is_expected.to be_falsey
end
end
end
context 'with non-empty project' do
let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
project: project,
ref: project.default_branch,
sha: project.commit.sha)
end
describe '#latest?' do
context 'with latest sha' do
it 'returns true' do
expect(pipeline).to be_latest
end
end
context 'with not latest sha' do
before do
pipeline.update(
sha: project.commit("#{project.default_branch}~1").sha)
end
it 'returns false' do
expect(pipeline).not_to be_latest
end
end
end
end
describe '#manual_actions' do
subject { pipeline.manual_actions }
it 'when none defined' do
is_expected.to be_empty
end
context 'when action defined' do
let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
it 'returns one action' do
is_expected.to contain_exactly(manual)
end
context 'there are multiple of the same name' do
let!(:manual2) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
it 'returns latest one' do
is_expected.to contain_exactly(manual2)
end
end
end
end
2016-07-14 10:58:05 -04:00
describe '#has_warnings?' do
subject { pipeline.has_warnings? }
context 'build which is allowed to fail fails' do
before do
2016-07-14 10:58:05 -04:00
create :ci_build, :success, pipeline: pipeline, name: 'rspec'
create :ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop'
end
it 'returns true' do
is_expected.to be_truthy
end
end
context 'build which is allowed to fail succeeds' do
before do
2016-07-14 10:58:05 -04:00
create :ci_build, :success, pipeline: pipeline, name: 'rspec'
create :ci_build, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop'
end
it 'returns false' do
is_expected.to be_falsey
end
end
2016-07-14 10:58:05 -04:00
context 'build is retried and succeeds' do
before do
create :ci_build, :success, pipeline: pipeline, name: 'rubocop'
create :ci_build, :failed, pipeline: pipeline, name: 'rspec'
create :ci_build, :success, pipeline: pipeline, name: 'rspec'
end
it 'returns false' do
is_expected.to be_falsey
end
end
end
shared_context 'with some outdated pipelines' do
before do
create_pipeline(:canceled, 'ref', 'A')
create_pipeline(:success, 'ref', 'A')
create_pipeline(:failed, 'ref', 'B')
create_pipeline(:skipped, 'feature', 'C')
end
def create_pipeline(status, ref, sha)
create(:ci_empty_pipeline, status: status, ref: ref, sha: sha)
end
end
describe '.latest' do
include_context 'with some outdated pipelines'
context 'when no ref is specified' do
let(:pipelines) { described_class.latest.all }
it 'returns the latest pipeline for the same ref and different sha' do
expect(pipelines.map(&:sha)).to contain_exactly('A', 'B', 'C')
expect(pipelines.map(&:status)).
to contain_exactly('success', 'failed', 'skipped')
end
end
context 'when ref is specified' do
let(:pipelines) { described_class.latest('ref').all }
it 'returns the latest pipeline for ref and different sha' do
expect(pipelines.map(&:sha)).to contain_exactly('A', 'B')
expect(pipelines.map(&:status)).
to contain_exactly('success', 'failed')
end
end
end
describe '.latest_status' do
include_context 'with some outdated pipelines'
context 'when no ref is specified' do
let(:latest_status) { described_class.latest_status }
it 'returns the latest status for the same ref and different sha' do
expect(latest_status).to eq(described_class.latest.status)
expect(latest_status).to eq('failed')
end
end
context 'when ref is specified' do
let(:latest_status) { described_class.latest_status('ref') }
it 'returns the latest status for ref and different sha' do
expect(latest_status).to eq(described_class.latest_status('ref'))
expect(latest_status).to eq('failed')
end
end
end
2016-12-26 01:33:08 -05:00
describe '.latest_successful_for' do
include_context 'with some outdated pipelines'
let!(:latest_successful_pipeline) do
create_pipeline(:success, 'ref', 'D')
end
it 'returns the latest successful pipeline' do
expect(described_class.latest_successful_for('ref')).
to eq(latest_successful_pipeline)
2016-12-26 01:33:08 -05:00
end
end
describe '.latest_successful_for_refs' do
include_context 'with some outdated pipelines'
let!(:latest_successful_pipeline1) { create_pipeline(:success, 'ref1', 'D') }
let!(:latest_successful_pipeline2) { create_pipeline(:success, 'ref2', 'D') }
it 'returns the latest successful pipeline for both refs' do
refs = %w(ref1 ref2 ref3)
expect(described_class.latest_successful_for_refs(refs)).to eq({ 'ref1' => latest_successful_pipeline1, 'ref2' => latest_successful_pipeline2 })
end
end
describe '#status' do
let(:build) do
create(:ci_build, :created, pipeline: pipeline, name: 'test')
end
subject { pipeline.reload.status }
context 'on queuing' do
2016-08-12 07:57:58 -04:00
before do
build.enqueue
end
it { is_expected.to eq('pending') }
end
context 'on run' do
before do
2016-08-12 07:57:58 -04:00
build.enqueue
build.run
end
it { is_expected.to eq('running') }
end
context 'on drop' do
before do
build.drop
end
it { is_expected.to eq('failed') }
end
context 'on success' do
before do
build.success
end
it { is_expected.to eq('success') }
end
context 'on cancel' do
before do
build.cancel
end
context 'when build is pending' do
let(:build) do
create(:ci_build, :pending, pipeline: pipeline)
end
it { is_expected.to eq('canceled') }
end
end
2016-08-12 07:57:58 -04:00
context 'on failure and build retry' do
before do
build.drop
project.add_developer(user)
Ci::Build.retry(build, user)
2016-08-12 07:57:58 -04:00
end
# We are changing a state: created > failed > running
# Instead of: created > failed > pending
# Since the pipeline already run, so it should not be pending anymore
it { is_expected.to eq('running') }
end
end
describe '#detailed_status' do
subject { pipeline.detailed_status(user) }
context 'when pipeline is created' do
let(:pipeline) { create(:ci_pipeline, status: :created) }
it 'returns detailed status for created pipeline' do
expect(subject.text).to eq 'created'
end
end
context 'when pipeline is pending' do
let(:pipeline) { create(:ci_pipeline, status: :pending) }
it 'returns detailed status for pending pipeline' do
expect(subject.text).to eq 'pending'
end
end
context 'when pipeline is running' do
let(:pipeline) { create(:ci_pipeline, status: :running) }
it 'returns detailed status for running pipeline' do
expect(subject.text).to eq 'running'
end
end
context 'when pipeline is successful' do
let(:pipeline) { create(:ci_pipeline, status: :success) }
it 'returns detailed status for successful pipeline' do
expect(subject.text).to eq 'passed'
end
end
context 'when pipeline is failed' do
let(:pipeline) { create(:ci_pipeline, status: :failed) }
it 'returns detailed status for failed pipeline' do
expect(subject.text).to eq 'failed'
end
end
context 'when pipeline is canceled' do
let(:pipeline) { create(:ci_pipeline, status: :canceled) }
it 'returns detailed status for canceled pipeline' do
expect(subject.text).to eq 'canceled'
end
end
context 'when pipeline is skipped' do
let(:pipeline) { create(:ci_pipeline, status: :skipped) }
it 'returns detailed status for skipped pipeline' do
expect(subject.text).to eq 'skipped'
end
end
context 'when pipeline is blocked' do
let(:pipeline) { create(:ci_pipeline, status: :manual) }
it 'returns detailed status for blocked pipeline' do
expect(subject.text).to eq 'blocked'
end
end
context 'when pipeline is successful but with warnings' do
let(:pipeline) { create(:ci_pipeline, status: :success) }
before do
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline)
end
it 'retruns detailed status for successful pipeline with warnings' do
expect(subject.label).to eq 'passed with warnings'
end
end
end
describe '#cancelable?' do
%i[created running pending].each do |status0|
context "when there is a build #{status0}" do
before do
create(:ci_build, status0, pipeline: pipeline)
end
it 'is cancelable' do
expect(pipeline.cancelable?).to be_truthy
end
end
context "when there is an external job #{status0}" do
before do
create(:generic_commit_status, status0, pipeline: pipeline)
end
it 'is cancelable' do
expect(pipeline.cancelable?).to be_truthy
end
end
%i[success failed canceled].each do |status1|
context "when there are generic_commit_status jobs for #{status0} and #{status1}" do
before do
create(:generic_commit_status, status0, pipeline: pipeline)
create(:generic_commit_status, status1, pipeline: pipeline)
end
it 'is cancelable' do
expect(pipeline.cancelable?).to be_truthy
end
end
context "when there are generic_commit_status and ci_build jobs for #{status0} and #{status1}" do
before do
create(:generic_commit_status, status0, pipeline: pipeline)
create(:ci_build, status1, pipeline: pipeline)
end
it 'is cancelable' do
expect(pipeline.cancelable?).to be_truthy
end
end
context "when there are ci_build jobs for #{status0} and #{status1}" do
before do
create(:ci_build, status0, pipeline: pipeline)
create(:ci_build, status1, pipeline: pipeline)
end
it 'is cancelable' do
expect(pipeline.cancelable?).to be_truthy
end
end
end
end
%i[success failed canceled].each do |status|
context "when there is a build #{status}" do
before do
create(:ci_build, status, pipeline: pipeline)
end
it 'is not cancelable' do
expect(pipeline.cancelable?).to be_falsey
end
end
context "when there is an external job #{status}" do
before do
create(:generic_commit_status, status, pipeline: pipeline)
end
it 'is not cancelable' do
expect(pipeline.cancelable?).to be_falsey
end
end
end
end
describe '#cancel_running' do
let(:latest_status) { pipeline.statuses.pluck(:status) }
context 'when there is a running external job and a regular job' do
before do
create(:ci_build, :running, pipeline: pipeline)
create(:generic_commit_status, :running, pipeline: pipeline)
pipeline.cancel_running
end
it 'cancels both jobs' do
expect(latest_status).to contain_exactly('canceled', 'canceled')
end
end
context 'when jobs are in different stages' do
before do
create(:ci_build, :running, stage_idx: 0, pipeline: pipeline)
create(:ci_build, :running, stage_idx: 1, pipeline: pipeline)
pipeline.cancel_running
end
it 'cancels both jobs' do
expect(latest_status).to contain_exactly('canceled', 'canceled')
end
end
context 'when there are created builds present in the pipeline' do
before do
create(:ci_build, :running, stage_idx: 0, pipeline: pipeline)
create(:ci_build, :created, stage_idx: 1, pipeline: pipeline)
pipeline.cancel_running
end
it 'cancels created builds' do
2017-02-22 12:46:57 -05:00
expect(latest_status).to eq %w(canceled canceled)
end
end
end
describe '#retry_failed' do
let(:latest_status) { pipeline.statuses.latest.pluck(:status) }
before do
project.add_developer(user)
end
context 'when there is a failed build and failed external status' do
before do
create(:ci_build, :failed, name: 'build', pipeline: pipeline)
create(:generic_commit_status, :failed, name: 'jenkins', pipeline: pipeline)
pipeline.retry_failed(user)
end
it 'retries only build' do
expect(latest_status).to contain_exactly('pending', 'failed')
end
end
context 'when builds are in different stages' do
before do
create(:ci_build, :failed, name: 'build', stage_idx: 0, pipeline: pipeline)
create(:ci_build, :failed, name: 'jenkins', stage_idx: 1, pipeline: pipeline)
pipeline.retry_failed(user)
end
it 'retries both builds' do
expect(latest_status).to contain_exactly('pending', 'created')
end
end
context 'when there are canceled and failed' do
before do
create(:ci_build, :failed, name: 'build', stage_idx: 0, pipeline: pipeline)
create(:ci_build, :canceled, name: 'jenkins', stage_idx: 1, pipeline: pipeline)
pipeline.retry_failed(user)
end
it 'retries both builds' do
expect(latest_status).to contain_exactly('pending', 'created')
end
end
end
describe '#execute_hooks' do
let!(:build_a) { create_build('a', 0) }
let!(:build_b) { create_build('b', 1) }
2016-08-11 12:37:50 -04:00
let!(:hook) do
create(:project_hook, project: project, pipeline_events: enabled)
end
before do
ProjectWebHookWorker.drain
end
context 'with pipeline hooks enabled' do
let(:enabled) { true }
2016-08-11 12:37:50 -04:00
before do
WebMock.stub_request(:post, hook.url)
end
context 'with multiple builds' do
2016-08-11 12:37:50 -04:00
context 'when build is queued' do
before do
2016-08-12 11:34:43 -04:00
build_a.enqueue
build_b.enqueue
2016-08-11 12:37:50 -04:00
end
2016-09-13 04:22:02 -04:00
it 'receives a pending event once' do
expect(WebMock).to have_requested_pipeline_hook('pending').once
2016-08-11 12:37:50 -04:00
end
end
2016-08-11 12:37:50 -04:00
context 'when build is run' do
before do
2016-08-12 11:34:43 -04:00
build_a.enqueue
2016-08-11 12:37:50 -04:00
build_a.run
2016-08-12 11:34:43 -04:00
build_b.enqueue
2016-08-11 12:37:50 -04:00
build_b.run
end
2016-09-13 04:22:02 -04:00
it 'receives a running event once' do
expect(WebMock).to have_requested_pipeline_hook('running').once
2016-08-11 12:37:50 -04:00
end
end
2016-08-11 12:37:50 -04:00
context 'when all builds succeed' do
before do
build_a.success
2016-10-26 05:34:40 -04:00
# We have to reload build_b as this is in next stage and it gets triggered by PipelineProcessWorker
build_b.reload.success
2016-08-11 12:37:50 -04:00
end
2016-09-13 04:22:02 -04:00
it 'receives a success event once' do
expect(WebMock).to have_requested_pipeline_hook('success').once
2016-08-11 12:37:50 -04:00
end
end
context 'when stage one failed' do
before do
build_a.drop
end
2016-09-13 04:22:02 -04:00
it 'receives a failed event once' do
expect(WebMock).to have_requested_pipeline_hook('failed').once
end
end
def have_requested_pipeline_hook(status)
2016-08-11 12:37:50 -04:00
have_requested(:post, hook.url).with do |req|
json_body = JSON.parse(req.body)
json_body['object_attributes']['status'] == status &&
json_body['builds'].length == 2
end
end
end
end
context 'with pipeline hooks disabled' do
let(:enabled) { false }
2016-08-11 12:37:50 -04:00
before do
2016-08-12 11:34:43 -04:00
build_a.enqueue
build_b.enqueue
2016-08-11 12:37:50 -04:00
end
it 'did not execute pipeline_hook after touched' do
expect(WebMock).not_to have_requested(:post, hook.url)
end
end
2016-08-11 12:37:50 -04:00
def create_build(name, stage_idx)
create(:ci_build,
:created,
pipeline: pipeline,
name: name,
stage_idx: stage_idx)
2016-08-11 12:37:50 -04:00
end
end
describe "#merge_requests" do
let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
merge_request = create(:merge_request, source_project: project, source_branch: pipeline.ref)
expect(pipeline.merge_requests).to eq([merge_request])
end
it "doesn't return merge requests whose source branch doesn't match the pipeline's ref" do
create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master')
expect(pipeline.merge_requests).to be_empty
end
it "doesn't return merge requests whose `diff_head_sha` doesn't match the pipeline's SHA" do
create(:merge_request, source_project: project, source_branch: pipeline.ref)
allow_any_instance_of(MergeRequest).to receive(:diff_head_sha) { '97de212e80737a608d939f648d959671fb0a0142b' }
expect(pipeline.merge_requests).to be_empty
end
end
describe '#stuck?' do
before do
create(:ci_build, :pending, pipeline: pipeline)
end
context 'when pipeline is stuck' do
it 'is stuck' do
expect(pipeline).to be_stuck
end
end
context 'when pipeline is not stuck' do
before { create(:ci_runner, :shared, :online) }
it 'is not stuck' do
expect(pipeline).not_to be_stuck
end
end
end
describe '#has_yaml_errors?' do
context 'when pipeline has errors' do
let(:pipeline) do
create(:ci_pipeline, config: { rspec: nil })
end
it 'contains yaml errors' do
expect(pipeline).to have_yaml_errors
end
end
context 'when pipeline does not have errors' do
let(:pipeline) do
create(:ci_pipeline, config: { rspec: { script: 'rake test' } })
end
it 'does not containyaml errors' do
expect(pipeline).not_to have_yaml_errors
end
end
end
describe '#update_status' do
let(:pipeline) { create(:ci_pipeline, sha: '123456') }
it 'updates the cached status' do
fake_status = double
# after updating the status, the status is set to `skipped` for this pipeline's builds
expect(Ci::PipelineStatus).to receive(:new).with(pipeline.project, sha: '123456', status: 'skipped').and_return(fake_status)
expect(fake_status).to receive(:store_in_cache_if_needed)
pipeline.update_status
end
end
describe 'notifications when pipeline success or failed' do
let(:project) { create(:project, :repository) }
2016-09-26 07:04:02 -04:00
let(:pipeline) do
create(:ci_pipeline,
project: project,
sha: project.commit('master').sha,
user: create(:user))
end
before do
project.team << [pipeline.user, Gitlab::Access::DEVELOPER]
pipeline.user.global_notification_setting.
update(level: 'custom', failed_pipeline: true, success_pipeline: true)
reset_delivered_emails!
perform_enqueued_jobs do
pipeline.enqueue
pipeline.run
end
end
shared_examples 'sending a notification' do
it 'sends an email' do
should_only_email(pipeline.user, kind: :bcc)
end
end
shared_examples 'not sending any notification' do
it 'does not send any email' do
should_not_email_anyone
end
end
context 'with success pipeline' do
before do
perform_enqueued_jobs do
2016-09-14 10:12:31 -04:00
pipeline.succeed
end
end
2016-09-14 10:12:31 -04:00
it_behaves_like 'sending a notification'
end
context 'with failed pipeline' do
before do
perform_enqueued_jobs do
create(:ci_build, :failed, pipeline: pipeline)
create(:generic_commit_status, :failed, pipeline: pipeline)
pipeline.drop
end
end
2016-09-14 10:12:31 -04:00
it_behaves_like 'sending a notification'
end
context 'with skipped pipeline' do
before do
perform_enqueued_jobs do
pipeline.skip
end
end
2016-09-14 10:12:31 -04:00
it_behaves_like 'not sending any notification'
end
context 'with cancelled pipeline' do
before do
perform_enqueued_jobs do
pipeline.cancel
end
end
2016-09-14 10:12:31 -04:00
it_behaves_like 'not sending any notification'
end
end
2015-08-25 21:42:46 -04:00
end