Commit 80c689b2 authored by Arturo Herrero's avatar Arturo Herrero

Merge branch 'pipeline-spec-improvements' into 'master'

Speed up pipeline model specs

See merge request gitlab-org/gitlab!53770
parents b899bbd6 6c5c698f
......@@ -40,6 +40,10 @@ FactoryBot.define do
end
end
trait :created do
status { :created }
end
factory :ci_pipeline do
transient { ci_ref_presence { true } }
......@@ -53,10 +57,6 @@ FactoryBot.define do
failure_reason { :config_error }
end
trait :created do
status { :created }
end
trait :preparing do
status { :preparing }
end
......
......@@ -11,10 +11,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
let_it_be(:namespace) { create_default(:namespace).freeze }
let_it_be(:project) { create_default(:project, :repository).freeze }
let(:pipeline) do
create(:ci_empty_pipeline, status: :created, project: project)
end
it_behaves_like 'having unique enum values'
it { is_expected.to belong_to(:project) }
......@@ -53,6 +49,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'associations' do
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
it 'has a bidirectional relationship with projects' do
expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:all_pipelines)
expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project)
......@@ -82,6 +80,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#set_status' do
let(:pipeline) { build(:ci_empty_pipeline, :created) }
where(:from_status, :to_status) do
from_status_names = described_class.state_machines[:status].states.map(&:name)
to_status_names = from_status_names - [:created] # we never want to transition into created
......@@ -105,6 +105,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '.processables' do
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
before do
create(:ci_build, name: 'build', pipeline: pipeline)
create(:ci_bridge, name: 'bridge', pipeline: pipeline)
......@@ -142,7 +144,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { described_class.for_sha(sha) }
let(:sha) { 'abc' }
let!(:pipeline) { create(:ci_pipeline, sha: 'abc') }
let_it_be(:pipeline) { create(:ci_pipeline, sha: 'abc') }
it 'returns the pipeline' do
is_expected.to contain_exactly(pipeline)
......@@ -170,7 +173,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { described_class.for_source_sha(source_sha) }
let(:source_sha) { 'abc' }
let!(:pipeline) { create(:ci_pipeline, source_sha: 'abc') }
let_it_be(:pipeline) { create(:ci_pipeline, source_sha: 'abc') }
it 'returns the pipeline' do
is_expected.to contain_exactly(pipeline)
......@@ -228,7 +232,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { described_class.for_branch(branch) }
let(:branch) { 'master' }
let!(:pipeline) { create(:ci_pipeline, ref: 'master') }
let_it_be(:pipeline) { create(:ci_pipeline, ref: 'master') }
it 'returns the pipeline' do
is_expected.to contain_exactly(pipeline)
......@@ -247,13 +252,16 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '.ci_sources' do
subject { described_class.ci_sources }
let!(:push_pipeline) { create(:ci_pipeline, source: :push) }
let!(:web_pipeline) { create(:ci_pipeline, source: :web) }
let!(:api_pipeline) { create(:ci_pipeline, source: :api) }
let!(:webide_pipeline) { create(:ci_pipeline, source: :webide) }
let!(:child_pipeline) { create(:ci_pipeline, source: :parent_pipeline) }
let(:push_pipeline) { build(:ci_pipeline, source: :push) }
let(:web_pipeline) { build(:ci_pipeline, source: :web) }
let(:api_pipeline) { build(:ci_pipeline, source: :api) }
let(:webide_pipeline) { build(:ci_pipeline, source: :webide) }
let(:child_pipeline) { build(:ci_pipeline, source: :parent_pipeline) }
let(:pipelines) { [push_pipeline, web_pipeline, api_pipeline, webide_pipeline, child_pipeline] }
it 'contains pipelines having CI only sources' do
pipelines.map(&:save!)
expect(subject).to contain_exactly(push_pipeline, web_pipeline, api_pipeline)
end
......@@ -387,6 +395,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#merge_request_ref?' do
subject { pipeline.merge_request_ref? }
let(:pipeline) { build(:ci_empty_pipeline, :created) }
it 'calls MergeRequest#merge_request_ref?' do
expect(MergeRequest).to receive(:merge_request_ref?).with(pipeline.ref)
......@@ -624,7 +634,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#source' do
context 'when creating new pipeline' do
let(:pipeline) do
build(:ci_empty_pipeline, status: :created, project: project, source: nil)
build(:ci_empty_pipeline, :created, project: project, source: nil)
end
it "prevents from creating an object" do
......@@ -633,17 +643,21 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when updating existing pipeline' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
before do
pipeline.update_attribute(:source, nil)
end
it "object is valid" do
it 'object is valid' do
expect(pipeline).to be_valid
end
end
end
describe '#block' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
it 'changes pipeline status to manual' do
expect(pipeline.block).to be true
expect(pipeline.reload).to be_manual
......@@ -654,7 +668,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#delay' do
subject { pipeline.delay }
let(:pipeline) { build(:ci_pipeline, status: :created) }
let(:pipeline) { build(:ci_pipeline, :created) }
it 'changes pipeline status to schedule' do
subject
......@@ -664,6 +678,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#valid_commit_sha' do
let(:pipeline) { build_stubbed(:ci_empty_pipeline, :created, project: project) }
context 'commit.sha can not start with 00000000' do
before do
pipeline.sha = '0' * 40
......@@ -677,6 +693,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#short_sha' do
subject { pipeline.short_sha }
let(:pipeline) { build_stubbed(:ci_empty_pipeline, :created) }
it 'has 8 items' do
expect(subject.size).to eq(8)
end
......@@ -686,49 +704,58 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#retried' do
subject { pipeline.retried }
let(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
let!(:build1) { create(:ci_build, pipeline: pipeline, name: 'deploy', retried: true) }
before do
@build1 = create(:ci_build, pipeline: pipeline, name: 'deploy', retried: true)
@build2 = create(:ci_build, pipeline: pipeline, name: 'deploy')
create(:ci_build, pipeline: pipeline, name: 'deploy')
end
it 'returns old builds' do
is_expected.to contain_exactly(@build1)
is_expected.to contain_exactly(build1)
end
end
describe '#coverage' do
let(:project) { create(:project, build_coverage_regex: "/.*/") }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline) }
it "calculates average when there are two builds with coverage" do
create(:ci_build, name: "rspec", coverage: 30, pipeline: pipeline)
create(:ci_build, name: "rubocop", coverage: 40, pipeline: pipeline)
expect(pipeline.coverage).to eq("35.00")
end
context 'with multiple pipelines' do
before_all do
create(:ci_build, name: "rspec", coverage: 30, pipeline: pipeline)
create(:ci_build, name: "rubocop", coverage: 40, pipeline: pipeline)
end
it "calculates average when there are two builds with coverage and one with nil" do
create(:ci_build, name: "rspec", coverage: 30, pipeline: pipeline)
create(:ci_build, name: "rubocop", coverage: 40, pipeline: pipeline)
create(:ci_build, pipeline: pipeline)
expect(pipeline.coverage).to eq("35.00")
end
it "calculates average when there are two builds with coverage" do
expect(pipeline.coverage).to eq("35.00")
end
it "calculates average when there are two builds with coverage and one is retried" do
create(:ci_build, name: "rspec", coverage: 30, pipeline: pipeline)
create(:ci_build, name: "rubocop", coverage: 30, pipeline: pipeline, retried: true)
create(:ci_build, name: "rubocop", coverage: 40, pipeline: pipeline)
expect(pipeline.coverage).to eq("35.00")
it "calculates average when there are two builds with coverage and one with nil" do
create(:ci_build, pipeline: pipeline)
expect(pipeline.coverage).to eq("35.00")
end
it "calculates average when there are two builds with coverage and one is retried" do
create(:ci_build, name: "rubocop", coverage: 30, pipeline: pipeline, retried: true)
expect(pipeline.coverage).to eq("35.00")
end
end
it "calculates average when there is one build without coverage" do
FactoryBot.create(:ci_build, pipeline: pipeline)
expect(pipeline.coverage).to be_nil
context 'when there is one build without coverage' do
it "calculates average to nil" do
create(:ci_build, pipeline: pipeline)
expect(pipeline.coverage).to be_nil
end
end
end
describe '#retryable?' do
subject { pipeline.retryable? }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
context 'no failed builds' do
before do
create_build('rspec', 'success')
......@@ -790,6 +817,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#predefined_variables' do
subject { pipeline.predefined_variables }
let(:pipeline) { build(:ci_empty_pipeline, :created) }
it 'includes all predefined variables in a valid order' do
keys = subject.map { |variable| variable[:key] }
......@@ -816,21 +845,18 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when merge request is present' do
let_it_be(:assignees) { create_list(:user, 2) }
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:labels) { create_list(:label, 2) }
let(:merge_request) do
create(:merge_request,
create(:merge_request, :simple,
source_project: project,
source_branch: 'feature',
target_project: project,
target_branch: 'master',
assignees: assignees,
milestone: milestone,
labels: labels)
end
let(:assignees) { create_list(:user, 2) }
let(:milestone) { create(:milestone, project: project) }
let(:labels) { create_list(:label, 2) }
context 'when pipeline for merge request is created' do
let(:pipeline) do
create(:ci_pipeline, :detached_merge_request_pipeline,
......@@ -1016,9 +1042,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#protected_ref?' do
before do
pipeline.project = create(:project, :repository)
end
let(:pipeline) { build(:ci_empty_pipeline, :created) }
it 'delegates method to project' do
expect(pipeline).not_to be_protected_ref
......@@ -1026,11 +1050,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#legacy_trigger' do
let(:trigger_request) { create(:ci_trigger_request) }
before do
pipeline.trigger_requests << trigger_request
end
let(:trigger_request) { build(:ci_trigger_request) }
let(:pipeline) { build(:ci_empty_pipeline, :created, trigger_requests: [trigger_request]) }
it 'returns first trigger request' do
expect(pipeline.legacy_trigger).to eq trigger_request
......@@ -1040,6 +1061,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#auto_canceled?' do
subject { pipeline.auto_canceled? }
let(:pipeline) { build(:ci_empty_pipeline, :created) }
context 'when it is canceled' do
before do
pipeline.cancel
......@@ -1047,7 +1070,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when there is auto_canceled_by' do
before do
pipeline.update!(auto_canceled_by: create(:ci_empty_pipeline))
pipeline.auto_canceled_by = create(:ci_empty_pipeline)
end
it 'is auto canceled' do
......@@ -1075,6 +1098,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'pipeline stages' do
let(:pipeline) { build(:ci_empty_pipeline, :created) }
describe 'legacy stages' do
before do
create(:commit_status, pipeline: pipeline,
......@@ -1180,6 +1205,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#legacy_stage' do
subject { pipeline.legacy_stage('test') }
let(:pipeline) { build(:ci_empty_pipeline, :created) }
context 'with status in stage' do
before do
create(:commit_status, pipeline: pipeline, stage: 'test')
......@@ -1202,6 +1229,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#stages' do
let(:pipeline) { build(:ci_empty_pipeline, :created) }
before do
create(:ci_stage_entity, project: project,
pipeline: pipeline,
......@@ -1256,6 +1285,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'state machine' do
let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, :created) }
let(:current) { Time.current.change(usec: 0) }
let(:build) { create_build('build1', queued_at: 0) }
let(:build_b) { create_build('build2', queued_at: 0) }
......@@ -1459,24 +1489,25 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'auto merge' do
let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
let(:pipeline) do
create(:ci_pipeline, :running, project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha)
end
context 'when auto merge is enabled' do
let_it_be_with_reload(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
let_it_be_with_reload(:pipeline) do
create(:ci_pipeline, :running, project: merge_request.source_project,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha)
end
before do
merge_request.update_head_pipeline
end
before_all do
merge_request.update_head_pipeline
end
%w[succeed! drop! cancel! skip!].each do |action|
context "when the pipeline recieved #{action} event" do
it 'performs AutoMergeProcessWorker' do
expect(AutoMergeProcessWorker).to receive(:perform_async).with(merge_request.id)
%w[succeed! drop! cancel! skip!].each do |action|
context "when the pipeline recieved #{action} event" do
it 'performs AutoMergeProcessWorker' do
expect(AutoMergeProcessWorker).to receive(:perform_async).with(merge_request.id)
pipeline.public_send(action)
pipeline.public_send(action)
end
end
end
end
......@@ -1628,15 +1659,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'multi-project pipelines' do
let!(:downstream_project) { create(:project, :repository) }
let!(:upstream_pipeline) { create(:ci_pipeline, project: project) }
let!(:upstream_pipeline) { create(:ci_pipeline) }
let!(:downstream_pipeline) { create(:ci_pipeline, :with_job, project: downstream_project) }
it_behaves_like 'upstream downstream pipeline'
end
context 'parent-child pipelines' do
let!(:upstream_pipeline) { create(:ci_pipeline, project: project) }
let!(:downstream_pipeline) { create(:ci_pipeline, :with_job, project: project) }
let!(:upstream_pipeline) { create(:ci_pipeline) }
let!(:downstream_pipeline) { create(:ci_pipeline, :with_job) }
it_behaves_like 'upstream downstream pipeline'
end
......@@ -1655,6 +1686,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#branch?' do
subject { pipeline.branch? }
let(:pipeline) { build(:ci_empty_pipeline, :created) }
context 'when ref is not a tag' do
before do
pipeline.tag = false
......@@ -1665,16 +1698,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is merge request' do
let(:pipeline) do
create(:ci_pipeline, merge_request: merge_request)
end
let(:pipeline) { build(:ci_pipeline, merge_request: merge_request) }
let(:merge_request) do
create(:merge_request,
create(:merge_request, :simple,
source_project: project,
source_branch: 'feature',
target_project: project,
target_branch: 'master')
target_project: project)
end
it 'returns false' do
......@@ -1738,6 +1767,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when repository exists' do
using RSpec::Parameterized::TableSyntax
let_it_be(:pipeline, refind: true) { create(:ci_empty_pipeline) }
where(:tag, :ref, :result) do
false | 'master' | true
false | 'non-existent-branch' | false
......@@ -1746,8 +1777,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
with_them do
let(:pipeline) do
create(:ci_empty_pipeline, project: project, tag: tag, ref: ref)
before do
pipeline.update!(tag: tag, ref: ref)
end
it "correctly detects ref" do
......@@ -1757,10 +1788,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when repository does not exist' do
let(:project) { create(:project) }
let(:pipeline) do
create(:ci_empty_pipeline, project: project, ref: 'master')
end
let(:pipeline) { build(:ci_empty_pipeline, ref: 'master', project: build(:project)) }
it 'always returns false' do
expect(pipeline.ref_exists?).to eq false
......@@ -1771,7 +1799,6 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'with non-empty project' do
let(:pipeline) do
create(:ci_pipeline,
project: project,
ref: project.default_branch,
sha: project.commit.sha)
end
......@@ -1779,14 +1806,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#lazy_ref_commit' do
let(:another) do
create(:ci_pipeline,
project: project,
ref: 'feature',
sha: project.commit('feature').sha)
end
let(:unicode) do
create(:ci_pipeline,
project: project,
ref: 'ü/unicode/multi-byte')
end
......@@ -1845,6 +1870,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#manual_actions' do
subject { pipeline.manual_actions }
let(:pipeline) { create(:ci_empty_pipeline, :created) }
it 'when none defined' do
is_expected.to be_empty
end
......@@ -1871,9 +1898,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#branch_updated?' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'when pipeline has before SHA' do
before do
pipeline.update_column(:before_sha, 'a1b2c3d4')
pipeline.update!(before_sha: 'a1b2c3d4')
end
it 'runs on a branch update push' do
......@@ -1884,7 +1913,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline does not have before SHA' do
before do
pipeline.update_column(:before_sha, Gitlab::Git::BLANK_SHA)
pipeline.update!(before_sha: Gitlab::Git::BLANK_SHA)
end
it 'does not run on a branch updating push' do
......@@ -1894,6 +1923,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#modified_paths' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'when old and new revisions are set' do
before do
pipeline.update!(before_sha: '1234abcd', sha: '2345bcde')
......@@ -1910,7 +1941,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when either old or new revision is missing' do
before do
pipeline.update_column(:before_sha, Gitlab::Git::BLANK_SHA)
pipeline.update!(before_sha: Gitlab::Git::BLANK_SHA)
end
it 'returns nil' do
......@@ -1924,11 +1955,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
let(:merge_request) do
create(:merge_request,
create(:merge_request, :simple,
source_project: project,
source_branch: 'feature',
target_project: project,
target_branch: 'master')
target_project: project)
end
it 'returns merge request modified paths' do
......@@ -1962,6 +1991,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#has_kubernetes_active?' do
let(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
context 'when kubernetes is active' do
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
......@@ -1983,6 +2014,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#has_warnings?' do
subject { pipeline.has_warnings? }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'build which is allowed to fail fails' do
before do
create :ci_build, :success, pipeline: pipeline, name: 'rspec'
......@@ -2039,6 +2072,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#number_of_warnings' do
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
it 'returns the number of warnings' do
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
create(:ci_bridge, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
......@@ -2047,7 +2082,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
it 'supports eager loading of the number of warnings' do
pipeline2 = create(:ci_empty_pipeline, status: :created, project: project)
pipeline2 = create(:ci_empty_pipeline, :created)
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline2, name: 'rubocop')
......@@ -2071,6 +2106,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { pipeline.needs_processing? }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
where(:processed, :result) do
nil | true
false | true
......@@ -2090,122 +2127,107 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
shared_context 'with some outdated pipelines' do
before do
create_pipeline(:canceled, 'ref', 'A', project)
create_pipeline(:success, 'ref', 'A', project)
create_pipeline(:failed, 'ref', 'B', project)
create_pipeline(:skipped, 'feature', 'C', project)
context 'with outdated pipelines' do
before_all 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, project)
def create_pipeline(status, ref, sha)
create(
:ci_empty_pipeline,
status: status,
ref: ref,
sha: sha,
project: project
sha: sha
)
end
end
describe '.newest_first' do
include_context 'with some outdated pipelines'
it 'returns the pipelines from new to old' do
expect(described_class.newest_first.pluck(:status))
.to eq(%w[skipped failed success canceled])
end
describe '.newest_first' do
it 'returns the pipelines from new to old' do
expect(described_class.newest_first.pluck(:status))
.to eq(%w[skipped failed success canceled])
end
it 'searches limited backlog' do
expect(described_class.newest_first(limit: 1).pluck(:status))
.to eq(%w[skipped])
it 'searches limited backlog' do
expect(described_class.newest_first(limit: 1).pluck(:status))
.to eq(%w[skipped])
end
end
end
describe '.latest_status' do
include_context 'with some outdated pipelines'
context 'when no ref is specified' do
it 'returns the status of the latest pipeline' do
expect(described_class.latest_status).to eq('skipped')
describe '.latest_status' do
context 'when no ref is specified' do
it 'returns the status of the latest pipeline' do
expect(described_class.latest_status).to eq('skipped')
end
end
end
context 'when ref is specified' do
it 'returns the status of the latest pipeline for the given ref' do
expect(described_class.latest_status('ref')).to eq('failed')
context 'when ref is specified' do
it 'returns the status of the latest pipeline for the given ref' do
expect(described_class.latest_status('ref')).to eq('failed')
end
end
end
end
describe '.latest_successful_for_ref' do
include_context 'with some outdated pipelines'
let!(:latest_successful_pipeline) do
create_pipeline(:success, 'ref', 'D', project)
end
describe '.latest_successful_for_ref' do
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('ref'))
.to eq(latest_successful_pipeline)
it 'returns the latest successful pipeline' do
expect(described_class.latest_successful_for_ref('ref'))
.to eq(latest_successful_pipeline)
end
end
end
describe '.latest_running_for_ref' do
include_context 'with some outdated pipelines'
let!(:latest_running_pipeline) do
create_pipeline(:running, 'ref', 'D', project)
end
describe '.latest_running_for_ref' do
let!(:latest_running_pipeline) do
create_pipeline(:running, 'ref', 'D')
end
it 'returns the latest running pipeline' do
expect(described_class.latest_running_for_ref('ref'))
.to eq(latest_running_pipeline)
it 'returns the latest running pipeline' do
expect(described_class.latest_running_for_ref('ref'))
.to eq(latest_running_pipeline)
end
end
end
describe '.latest_failed_for_ref' do
include_context 'with some outdated pipelines'
let!(:latest_failed_pipeline) do
create_pipeline(:failed, 'ref', 'D', project)
end
describe '.latest_failed_for_ref' do
let!(:latest_failed_pipeline) do
create_pipeline(:failed, 'ref', 'D')
end
it 'returns the latest failed pipeline' do
expect(described_class.latest_failed_for_ref('ref'))
.to eq(latest_failed_pipeline)
it 'returns the latest failed pipeline' do
expect(described_class.latest_failed_for_ref('ref'))
.to eq(latest_failed_pipeline)
end
end
end
describe '.latest_successful_for_sha' do
include_context 'with some outdated pipelines'
let!(:latest_successful_pipeline) do
create_pipeline(:success, 'ref', 'awesomesha', project)
end
describe '.latest_successful_for_sha' do
let!(:latest_successful_pipeline) do
create_pipeline(:success, 'ref', 'awesomesha')
end
it 'returns the latest successful pipeline' do
expect(described_class.latest_successful_for_sha('awesomesha'))
.to eq(latest_successful_pipeline)
it 'returns the latest successful pipeline' do
expect(described_class.latest_successful_for_sha('awesomesha'))
.to eq(latest_successful_pipeline)
end
end
end
describe '.latest_successful_for_refs' do
include_context 'with some outdated pipelines'
let!(:latest_successful_pipeline1) do
create_pipeline(:success, 'ref1', 'D', project)
end
describe '.latest_successful_for_refs' do
let!(:latest_successful_pipeline1) do
create_pipeline(:success, 'ref1', 'D')
end
let!(:latest_successful_pipeline2) do
create_pipeline(:success, 'ref2', 'D', project)
end
let!(:latest_successful_pipeline2) do
create_pipeline(:success, 'ref2', 'D')
end
it 'returns the latest successful pipeline for both refs' do
refs = %w(ref1 ref2 ref3)
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 })
expect(described_class.latest_successful_for_refs(refs)).to eq({ 'ref1' => latest_successful_pipeline1, 'ref2' => latest_successful_pipeline2 })
end
end
end
......@@ -2215,8 +2237,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
:ci_empty_pipeline,
status: 'success',
ref: 'master',
sha: '123',
project: project
sha: '123'
)
end
......@@ -2225,8 +2246,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
:ci_empty_pipeline,
status: 'success',
ref: 'develop',
sha: '123',
project: project
sha: '123'
)
end
......@@ -2235,8 +2255,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
:ci_empty_pipeline,
status: 'success',
ref: 'test',
sha: '456',
project: project
sha: '456'
)
end
......@@ -2333,12 +2352,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#status', :sidekiq_inline do
let(:build) do
create(:ci_build, :created, pipeline: pipeline, name: 'test')
end
subject { pipeline.reload.status }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
let(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') }
context 'on waiting for resource' do
before do
allow(build).to receive(:with_resource_group?) { true }
......@@ -2430,8 +2448,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#detailed_status' do
subject { pipeline.detailed_status(user) }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'when pipeline is created' do
let(:pipeline) { create(:ci_pipeline, status: :created) }
let(:pipeline) { create(:ci_pipeline, :created) }
it 'returns detailed status for created pipeline' do
expect(subject.text).to eq s_('CiStatusText|created')
......@@ -2508,6 +2528,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#cancelable?' do
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
%i[created running pending].each do |status0|
context "when there is a build #{status0}" do
before do
......@@ -2599,7 +2621,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#cancel_running' do
let(:latest_status) { pipeline.statuses.pluck(:status) }
subject(:latest_status) { pipeline.statuses.pluck(:status) }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'when there is a running external job and a regular job' do
before do
......@@ -2642,7 +2666,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#retry_failed' do
let(:latest_status) { pipeline.latest_statuses.pluck(:status) }
subject(:latest_status) { pipeline.latest_statuses.pluck(:status) }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
before do
stub_not_protect_default_branch
......@@ -2691,11 +2717,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#execute_hooks' do
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
let!(:build_a) { create_build('a', 0) }
let!(:build_b) { create_build('b', 0) }
let!(:hook) do
create(:project_hook, project: project, pipeline_events: enabled)
create(:project_hook, pipeline_events: enabled)
end
before do
......@@ -2721,7 +2748,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
it 'builds hook data once' do
create(:pipelines_email_service, project: project)
create(:pipelines_email_service)
expect(Gitlab::DataBuilder::Pipeline).to receive(:build).once.and_call_original
......@@ -2807,7 +2834,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe "#merge_requests_as_head_pipeline" do
let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: 'a288a022a53a5a944fae87bcec6efc87b7061808') }
let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, status: 'created', ref: 'master', sha: 'a288a022a53a5a944fae87bcec6efc87b7061808') }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
allow_next_instance_of(MergeRequest) do |instance|
......@@ -2819,7 +2846,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
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')
create(:merge_request, :simple, source_project: project)
expect(pipeline.merge_requests_as_head_pipeline).to be_empty
end
......@@ -2835,7 +2862,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#all_merge_requests' do
let(:project) { create(:project) }
let_it_be_with_reload(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
shared_examples 'a method that returns all merge requests for a given pipeline' do
let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: pipeline_project, ref: 'master') }
......@@ -2929,10 +2957,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#related_merge_requests' do
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'stable') }
let(:branch_pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
let(:branch_pipeline) { create(:ci_pipeline, ref: 'feature') }
let(:merge_pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline, merge_request: merge_request) }
context 'for a branch pipeline' do
......@@ -2969,9 +2996,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#open_merge_requests_refs' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let!(:pipeline) { create(:ci_pipeline, user: user, project: project, ref: 'feature') }
let!(:pipeline) { create(:ci_pipeline, user: user, ref: 'feature') }
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
subject { pipeline.open_merge_requests_refs }
......@@ -3018,6 +3043,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#same_family_pipeline_ids' do
subject { pipeline.same_family_pipeline_ids.map(&:id) }
let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
context 'when pipeline is not child nor parent' do
it 'returns just the pipeline id' do
expect(subject).to contain_exactly(pipeline.id)
......@@ -3025,7 +3052,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is child' do
let(:parent) { create(:ci_pipeline, project: project) }
let(:parent) { create(:ci_pipeline) }
let!(:pipeline) { create(:ci_pipeline, child_of: parent) }
let!(:sibling) { create(:ci_pipeline, child_of: parent) }
......@@ -3043,7 +3070,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is a child of a child pipeline' do
let(:ancestor) { create(:ci_pipeline, project: project) }
let(:ancestor) { create(:ci_pipeline) }
let!(:parent) { create(:ci_pipeline, child_of: ancestor) }
let!(:pipeline) { create(:ci_pipeline, child_of: parent) }
let!(:cousin_parent) { create(:ci_pipeline, child_of: ancestor) }
......@@ -3068,10 +3095,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#root_ancestor' do
subject { pipeline.root_ancestor }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when pipeline is child of child pipeline' do
let!(:root_ancestor) { create(:ci_pipeline, project: project) }
let!(:root_ancestor) { create(:ci_pipeline) }
let!(:parent_pipeline) { create(:ci_pipeline, child_of: root_ancestor) }
let!(:pipeline) { create(:ci_pipeline, child_of: parent_pipeline) }
......@@ -3106,6 +3133,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#stuck?' do
let(:pipeline) { create(:ci_empty_pipeline, :created) }
before do
create(:ci_build, :pending, pipeline: pipeline)
end
......@@ -3150,6 +3179,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#has_yaml_errors?' do
let(:pipeline) { build_stubbed(:ci_pipeline) }
context 'when yaml_errors is set' do
before do
pipeline.yaml_errors = 'File not found'
......@@ -3219,7 +3250,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline is not the latest' do
before do
create(:ci_pipeline, :success, project: project, ci_ref: pipeline.ci_ref)
create(:ci_pipeline, :success, ci_ref: pipeline.ci_ref)
end
it 'does not pass ref_status' do
......@@ -3320,7 +3351,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#builds_in_self_and_descendants' do
subject(:builds) { pipeline.builds_in_self_and_descendants }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:pipeline) { create(:ci_pipeline) }
let!(:build) { create(:ci_build, pipeline: pipeline) }
context 'when pipeline is standalone' do
......@@ -3351,6 +3382,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#build_with_artifacts_in_self_and_descendants' do
let_it_be(:pipeline) { create(:ci_pipeline) }
let!(:build) { create(:ci_build, name: 'test', pipeline: pipeline) }
let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
let!(:child_build) { create(:ci_build, :artifacts, name: 'test', pipeline: child_pipeline) }
......@@ -3369,6 +3401,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#find_job_with_archive_artifacts' do
let(:pipeline) { create(:ci_pipeline) }
let!(:old_job) { create(:ci_build, name: 'rspec', retried: true, pipeline: pipeline) }
let!(:job_without_artifacts) { create(:ci_build, name: 'rspec', pipeline: pipeline) }
let!(:expected_job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: pipeline ) }
......@@ -3382,6 +3415,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#latest_builds_with_artifacts' do
let(:pipeline) { create(:ci_pipeline) }
let!(:fresh_build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
let!(:stale_build) { create(:ci_build, :success, :expired, :artifacts, pipeline: pipeline) }
......@@ -3408,7 +3442,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#batch_lookup_report_artifact_for_file_type' do
context 'with code quality report artifact' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_codequality_reports) }
it "returns the code quality artifact" do
expect(pipeline.batch_lookup_report_artifact_for_file_type(:codequality)).to eq(pipeline.job_artifacts.sample)
......@@ -3417,24 +3451,26 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#latest_report_builds' do
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
it 'returns build with test artifacts' do
test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project)
coverage_build = create(:ci_build, :coverage_reports, pipeline: pipeline, project: project)
test_build = create(:ci_build, :test_reports, pipeline: pipeline)
coverage_build = create(:ci_build, :coverage_reports, pipeline: pipeline)
create(:ci_build, :artifacts, pipeline: pipeline, project: project)
expect(pipeline.latest_report_builds).to contain_exactly(test_build, coverage_build)
end
it 'filters builds by scope' do
test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :coverage_reports, pipeline: pipeline, project: project)
test_build = create(:ci_build, :test_reports, pipeline: pipeline)
create(:ci_build, :coverage_reports, pipeline: pipeline)
expect(pipeline.latest_report_builds(Ci::JobArtifact.test_reports)).to contain_exactly(test_build)
end
it 'only returns not retried builds' do
test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :test_reports, :retried, pipeline: pipeline, project: project)
test_build = create(:ci_build, :test_reports, pipeline: pipeline)
create(:ci_build, :test_reports, :retried, pipeline: pipeline)
expect(pipeline.latest_report_builds).to contain_exactly(test_build)
end
......@@ -3445,17 +3481,17 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline has builds with test reports' do
before do
create(:ci_build, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :test_reports, pipeline: pipeline)
end
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :running) }
it { is_expected.to be_falsey }
end
context 'when pipeline status is success' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { is_expected.to be_truthy }
end
......@@ -3463,20 +3499,20 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline does not have builds with test reports' do
before do
create(:ci_build, :artifacts, pipeline: pipeline, project: project)
create(:ci_build, :artifacts, pipeline: pipeline)
end
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { is_expected.to be_falsey }
end
context 'when retried build has test reports' do
before do
create(:ci_build, :retried, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :retried, :test_reports, pipeline: pipeline)
end
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { is_expected.to be_falsey }
end
......@@ -3486,13 +3522,13 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { pipeline.has_coverage_reports? }
context 'when pipeline has a code coverage artifact' do
let(:pipeline) { create(:ci_pipeline, :with_coverage_report_artifact, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_coverage_report_artifact, :running) }
it { expect(subject).to be_truthy }
end
context 'when pipeline does not have a code coverage artifact' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { expect(subject).to be_falsey }
end
......@@ -3503,17 +3539,17 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline has builds with coverage reports' do
before do
create(:ci_build, :coverage_reports, pipeline: pipeline, project: project)
create(:ci_build, :coverage_reports, pipeline: pipeline)
end
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :running) }
it { expect(subject).to be_falsey }
end
context 'when pipeline status is success' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { expect(subject).to be_truthy }
end
......@@ -3521,10 +3557,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline does not have builds with coverage reports' do
before do
create(:ci_build, :artifacts, pipeline: pipeline, project: project)
create(:ci_build, :artifacts, pipeline: pipeline)
end
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { expect(subject).to be_falsey }
end
......@@ -3534,13 +3570,13 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
subject { pipeline.has_codequality_mr_diff_report? }
context 'when pipeline has a codequality mr diff report' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_mr_diff_report, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :with_codequality_mr_diff_report, :running) }
it { expect(subject).to be_truthy }
end
context 'when pipeline does not have a codequality mr diff report' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { expect(subject).to be_falsey }
end
......@@ -3551,17 +3587,17 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline has builds with codequality reports' do
before do
create(:ci_build, :codequality_reports, pipeline: pipeline, project: project)
create(:ci_build, :codequality_reports, pipeline: pipeline)
end
context 'when pipeline status is running' do
let(:pipeline) { create(:ci_pipeline, :running, project: project) }
let(:pipeline) { create(:ci_pipeline, :running) }
it { expect(subject).to be_falsey }
end
context 'when pipeline status is success' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it 'can generate a codequality report' do
expect(subject).to be_truthy
......@@ -3581,10 +3617,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline does not have builds with codequality reports' do
before do
create(:ci_build, :artifacts, pipeline: pipeline, project: project)
create(:ci_build, :artifacts, pipeline: pipeline)
end
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
it { expect(subject).to be_falsey }
end
......@@ -3593,12 +3629,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#test_report_summary' do
subject { pipeline.test_report_summary }
context 'when pipeline has multiple builds with report results' do
let(:pipeline) { create(:ci_pipeline, :success, project: project) }
let(:pipeline) { create(:ci_pipeline, :success) }
context 'when pipeline has multiple builds with report results' do
before do
create(:ci_build, :success, :report_results, name: 'rspec', pipeline: pipeline, project: project)
create(:ci_build, :success, :report_results, name: 'java', pipeline: pipeline, project: project)
create(:ci_build, :success, :report_results, name: 'rspec', pipeline: pipeline)
create(:ci_build, :success, :report_results, name: 'java', pipeline: pipeline)
end
it 'returns test report summary with collected data' do
......@@ -3616,13 +3652,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#test_reports' do
subject { pipeline.test_reports }
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when pipeline has multiple builds with test reports' do
let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline, project: project) }
let!(:build_java) { create(:ci_build, :success, name: 'java', pipeline: pipeline, project: project) }
let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
let!(:build_java) { create(:ci_build, :success, name: 'java', pipeline: pipeline) }
before do
create(:ci_job_artifact, :junit, job: build_rspec, project: project)
create(:ci_job_artifact, :junit_with_ant, job: build_java, project: project)
create(:ci_job_artifact, :junit, job: build_rspec)
create(:ci_job_artifact, :junit_with_ant, job: build_java)
end
it 'returns test reports with collected data' do
......@@ -3632,8 +3670,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when builds are retried' do
let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline, project: project) }
let!(:build_java) { create(:ci_build, :retried, :success, name: 'java', pipeline: pipeline, project: project) }
let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
let!(:build_java) { create(:ci_build, :retried, :success, name: 'java', pipeline: pipeline) }
it 'does not take retried builds into account' do
expect(subject.total_count).to be(0)
......@@ -3653,13 +3691,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#accessibility_reports' do
subject { pipeline.accessibility_reports }
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when pipeline has multiple builds with accessibility reports' do
let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline, project: project) }
let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline, project: project) }
let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
before do
create(:ci_job_artifact, :accessibility, job: build_rspec, project: project)
create(:ci_job_artifact, :accessibility_without_errors, job: build_golang, project: project)
create(:ci_job_artifact, :accessibility, job: build_rspec)
create(:ci_job_artifact, :accessibility_without_errors, job: build_golang)
end
it 'returns accessibility report with collected data' do
......@@ -3670,8 +3710,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when builds are retried' do
let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline, project: project) }
let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline, project: project) }
let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
it 'returns empty urls for accessibility reports' do
expect(subject.urls).to be_empty
......@@ -3689,13 +3729,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#coverage_reports' do
subject { pipeline.coverage_reports }
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when pipeline has multiple builds with coverage reports' do
let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline, project: project) }
let!(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline, project: project) }
let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
let!(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
before do
create(:ci_job_artifact, :cobertura, job: build_rspec, project: project)
create(:ci_job_artifact, :coverage_gocov_xml, job: build_golang, project: project)
create(:ci_job_artifact, :cobertura, job: build_rspec)
create(:ci_job_artifact, :coverage_gocov_xml, job: build_golang)
end
it 'returns coverage reports with collected data' do
......@@ -3707,8 +3749,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
it 'does not execute N+1 queries' do
single_build_pipeline = create(:ci_empty_pipeline, status: :created, project: project)
single_rspec = create(:ci_build, :success, name: 'rspec', pipeline: single_build_pipeline, project: project)
single_build_pipeline = create(:ci_empty_pipeline, :created)
single_rspec = create(:ci_build, :success, name: 'rspec', pipeline: single_build_pipeline)
create(:ci_job_artifact, :cobertura, job: single_rspec, project: project)
control = ActiveRecord::QueryRecorder.new { single_build_pipeline.coverage_reports }
......@@ -3717,8 +3759,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when builds are retried' do
let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline, project: project) }
let!(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline, project: project) }
let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
let!(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
it 'does not take retried builds into account' do
expect(subject.files).to eql({})
......@@ -3736,13 +3778,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#codequality_reports' do
subject(:codequality_reports) { pipeline.codequality_reports }
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when pipeline has multiple builds with codequality reports' do
let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline, project: project) }
let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline, project: project) }
let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
before do
create(:ci_job_artifact, :codequality, job: build_rspec, project: project)
create(:ci_job_artifact, :codequality_without_errors, job: build_golang, project: project)
create(:ci_job_artifact, :codequality, job: build_rspec)
create(:ci_job_artifact, :codequality_without_errors, job: build_golang)
end
it 'returns codequality report with collected data' do
......@@ -3750,8 +3794,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when builds are retried' do
let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline, project: project) }
let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline, project: project) }
let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
it 'returns a codequality reports without degradations' do
expect(codequality_reports.degradations).to be_empty
......@@ -3767,6 +3811,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#total_size' do
let(:pipeline) { create(:ci_pipeline) }
let!(:build_job1) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
let!(:build_job2) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
let!(:test_job_failed_and_retried) { create(:ci_build, :failed, :retried, pipeline: pipeline, stage_idx: 1) }
......@@ -3807,7 +3852,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline ref is the default branch of the project' do
let(:pipeline) do
build(:ci_empty_pipeline, status: :created, project: project, ref: project.default_branch)
build(:ci_empty_pipeline, :created, project: project, ref: project.default_branch)
end
it "returns true" do
......@@ -3817,7 +3862,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
context 'when pipeline ref is not the default branch of the project' do
let(:pipeline) do
build(:ci_empty_pipeline, status: :created, project: project, ref: 'another_branch')
build(:ci_empty_pipeline, :created, project: project, ref: 'another_branch')
end
it "returns false" do
......@@ -3827,7 +3872,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#find_stage_by_name' do
let(:pipeline) { create(:ci_pipeline) }
let_it_be(:pipeline) { create(:ci_pipeline) }
let(:stage_name) { 'test' }
let(:stage) do
......@@ -3907,10 +3952,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#parent_pipeline' do
let_it_be(:project) { create(:project) }
let_it_be_with_reload(:pipeline) { create(:ci_pipeline) }
context 'when pipeline is triggered by a pipeline from the same project' do
let_it_be(:upstream_pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:upstream_pipeline) { create(:ci_pipeline) }
let_it_be(:pipeline) { create(:ci_pipeline, child_of: upstream_pipeline) }
it 'returns the parent pipeline' do
......@@ -3923,7 +3968,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is triggered by a pipeline from another project' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:pipeline) { create(:ci_pipeline) }
let!(:upstream_pipeline) { create(:ci_pipeline, project: create(:project), upstream_of: pipeline) }
it 'returns nil' do
......@@ -3950,7 +3995,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#child_pipelines' do
let_it_be(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
context 'when pipeline triggered other pipelines on same project' do
let(:downstream_pipeline) { create(:ci_pipeline, project: pipeline.project) }
......@@ -4004,6 +4049,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'upstream status interactions' do
let_it_be_with_reload(:pipeline) { create(:ci_pipeline, :created) }
context 'when a pipeline has an upstream status' do
context 'when an upstream status is a bridge' do
let(:bridge) { create(:ci_bridge, status: :pending) }
......@@ -4062,6 +4109,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
describe '#source_ref_path' do
subject { pipeline.source_ref_path }
let(:pipeline) { create(:ci_pipeline, :created) }
context 'when pipeline is for a branch' do
it { is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.source_ref.to_s) }
end
......@@ -4074,13 +4123,15 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is for a tag' do
let(:pipeline) { create(:ci_pipeline, project: project, tag: true) }
let(:pipeline) { create(:ci_pipeline, tag: true) }
it { is_expected.to eq(Gitlab::Git::TAG_REF_PREFIX + pipeline.source_ref.to_s) }
end
end
describe "#builds_with_coverage" do
describe '#builds_with_coverage' do
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
it 'returns builds with coverage only' do
rspec = create(:ci_build, name: 'rspec', coverage: 97.1, pipeline: pipeline)
jest = create(:ci_build, name: 'jest', coverage: 94.1, pipeline: pipeline)
......@@ -4104,10 +4155,11 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#base_and_ancestors' do
let(:same_project) { false }
subject { pipeline.base_and_ancestors(same_project: same_project) }
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
let(:same_project) { false }
context 'when pipeline is not child nor parent' do
it 'returns just the pipeline itself' do
expect(subject).to contain_exactly(pipeline)
......@@ -4115,8 +4167,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is child' do
let(:parent) { create(:ci_pipeline, project: pipeline.project) }
let(:sibling) { create(:ci_pipeline, project: pipeline.project) }
let(:parent) { create(:ci_pipeline) }
let(:sibling) { create(:ci_pipeline) }
before do
create_source_pipeline(parent, pipeline)
......@@ -4129,7 +4181,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is parent' do
let(:child) { create(:ci_pipeline, project: pipeline.project) }
let(:child) { create(:ci_pipeline) }
before do
create_source_pipeline(pipeline, child)
......@@ -4141,8 +4193,9 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is a child of a child pipeline' do
let(:ancestor) { create(:ci_pipeline, project: pipeline.project) }
let(:parent) { create(:ci_pipeline, project: pipeline.project) }
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
let(:ancestor) { create(:ci_pipeline) }
let(:parent) { create(:ci_pipeline) }
before do
create_source_pipeline(ancestor, parent)
......@@ -4155,6 +4208,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline is a triggered pipeline' do
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
let(:upstream) { create(:ci_pipeline, project: create(:project)) }
before do
......@@ -4178,8 +4232,10 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'reset_ancestor_bridges!' do
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
context 'when the pipeline is a child pipeline and the bridge is depended' do
let!(:parent_pipeline) { create(:ci_pipeline, project: project) }
let!(:parent_pipeline) { create(:ci_pipeline) }
let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) }
it 'marks source bridge as pending' do
......@@ -4203,7 +4259,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when the pipeline is a child pipeline and the bridge is not depended' do
let!(:parent_pipeline) { create(:ci_pipeline, project: project) }
let!(:parent_pipeline) { create(:ci_pipeline) }
let!(:bridge) { create_bridge(parent_pipeline, pipeline, false) }
it 'does not touch source bridge' do
......@@ -4239,6 +4295,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'test failure history processing' do
let(:pipeline) { build(:ci_pipeline, :created) }
it 'performs the service asynchronously when the pipeline is completed' do
service = double
......@@ -4250,21 +4308,23 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#latest_test_report_builds' do
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
it 'returns pipeline builds with test report artifacts' do
test_build = create(:ci_build, :test_reports, pipeline: pipeline, project: project)
test_build = create(:ci_build, :test_reports, pipeline: pipeline)
create(:ci_build, :artifacts, pipeline: pipeline, project: project)
expect(pipeline.latest_test_report_builds).to contain_exactly(test_build)
end
it 'preloads project on each build to avoid N+1 queries' do
create(:ci_build, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :test_reports, pipeline: pipeline)
control_count = ActiveRecord::QueryRecorder.new do
pipeline.latest_test_report_builds.map(&:project).map(&:full_path)
end
multi_build_pipeline = create(:ci_empty_pipeline, status: :created, project: project)
multi_build_pipeline = create(:ci_empty_pipeline, :created)
create(:ci_build, :test_reports, pipeline: multi_build_pipeline, project: project)
create(:ci_build, :test_reports, pipeline: multi_build_pipeline, project: project)
......@@ -4274,30 +4334,32 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#builds_with_failed_tests' do
let_it_be(:pipeline) { create(:ci_pipeline, :created) }
it 'returns pipeline builds with test report artifacts' do
failed_build = create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :success, :test_reports, pipeline: pipeline, project: project)
failed_build = create(:ci_build, :failed, :test_reports, pipeline: pipeline)
create(:ci_build, :success, :test_reports, pipeline: pipeline)
expect(pipeline.builds_with_failed_tests).to contain_exactly(failed_build)
end
it 'supports limiting the number of builds to fetch' do
create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :failed, :test_reports, pipeline: pipeline)
create(:ci_build, :failed, :test_reports, pipeline: pipeline)
expect(pipeline.builds_with_failed_tests(limit: 1).count).to eq(1)
end
it 'preloads project on each build to avoid N+1 queries' do
create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
create(:ci_build, :failed, :test_reports, pipeline: pipeline)
control_count = ActiveRecord::QueryRecorder.new do
pipeline.builds_with_failed_tests.map(&:project).map(&:full_path)
end
multi_build_pipeline = create(:ci_empty_pipeline, status: :created, project: project)
create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline, project: project)
create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline, project: project)
multi_build_pipeline = create(:ci_empty_pipeline, :created)
create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline)
create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline)
expect { multi_build_pipeline.builds_with_failed_tests.map(&:project).map(&:full_path) }
.not_to exceed_query_limit(control_count)
......
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