1# frozen_string_literal: true
2
3require 'spec_helper'
4
5RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
6  include ProjectForksHelper
7  include StubRequests
8  include Ci::SourcePipelineHelpers
9
10  let_it_be(:user) { create(:user, :public_email) }
11  let_it_be(:namespace) { create_default(:namespace).freeze }
12  let_it_be(:project) { create_default(:project, :repository).freeze }
13
14  it 'paginates 15 pipeleines per page' do
15    expect(described_class.default_per_page).to eq(15)
16  end
17
18  it_behaves_like 'having unique enum values'
19
20  it { is_expected.to belong_to(:project) }
21  it { is_expected.to belong_to(:user) }
22  it { is_expected.to belong_to(:auto_canceled_by) }
23  it { is_expected.to belong_to(:pipeline_schedule) }
24  it { is_expected.to belong_to(:merge_request) }
25  it { is_expected.to belong_to(:external_pull_request) }
26
27  it { is_expected.to have_many(:statuses) }
28  it { is_expected.to have_many(:trigger_requests) }
29  it { is_expected.to have_many(:variables) }
30  it { is_expected.to have_many(:builds) }
31  it { is_expected.to have_many(:statuses_order_id_desc) }
32  it { is_expected.to have_many(:bridges) }
33  it { is_expected.to have_many(:job_artifacts).through(:builds) }
34  it { is_expected.to have_many(:auto_canceled_pipelines) }
35  it { is_expected.to have_many(:auto_canceled_jobs) }
36  it { is_expected.to have_many(:sourced_pipelines) }
37  it { is_expected.to have_many(:triggered_pipelines) }
38  it { is_expected.to have_many(:pipeline_artifacts) }
39
40  it { is_expected.to have_one(:chat_data) }
41  it { is_expected.to have_one(:source_pipeline) }
42  it { is_expected.to have_one(:triggered_by_pipeline) }
43  it { is_expected.to have_one(:source_job) }
44  it { is_expected.to have_one(:pipeline_config) }
45
46  it { is_expected.to respond_to :git_author_name }
47  it { is_expected.to respond_to :git_author_email }
48  it { is_expected.to respond_to :git_author_full_text }
49  it { is_expected.to respond_to :short_sha }
50  it { is_expected.to delegate_method(:full_path).to(:project).with_prefix }
51
52  describe 'validations' do
53    it { is_expected.to validate_presence_of(:sha) }
54    it { is_expected.to validate_presence_of(:status) }
55  end
56
57  describe 'associations' do
58    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
59
60    it 'has a bidirectional relationship with projects' do
61      expect(described_class.reflect_on_association(:project).has_inverse?).to eq(:all_pipelines)
62      expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project)
63      expect(Project.reflect_on_association(:ci_pipelines).has_inverse?).to eq(:project)
64    end
65
66    describe '#latest_builds' do
67      it 'has a one to many relationship with its latest builds' do
68        _old_build = create(:ci_build, :retried, pipeline: pipeline)
69        latest_build = create(:ci_build, :expired, pipeline: pipeline)
70
71        expect(pipeline.latest_builds).to contain_exactly(latest_build)
72      end
73    end
74
75    describe '#downloadable_artifacts' do
76      let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
77      let_it_be(:downloadable_artifact) { create(:ci_job_artifact, :codequality, job: build) }
78      let_it_be(:expired_artifact) { create(:ci_job_artifact, :junit, :expired, job: build) }
79      let_it_be(:undownloadable_artifact) { create(:ci_job_artifact, :trace, job: build) }
80
81      context 'when artifacts are locked' do
82        it 'returns downloadable artifacts including locked artifacts' do
83          expect(pipeline.downloadable_artifacts).to contain_exactly(downloadable_artifact, expired_artifact)
84        end
85      end
86
87      context 'when artifacts are unlocked' do
88        it 'returns only downloadable artifacts not expired' do
89          expired_artifact.job.pipeline.unlocked!
90
91          expect(pipeline.reload.downloadable_artifacts).to contain_exactly(downloadable_artifact)
92        end
93      end
94    end
95  end
96
97  describe '#set_status' do
98    let(:pipeline) { build(:ci_empty_pipeline, :created) }
99
100    where(:from_status, :to_status) do
101      from_status_names = described_class.state_machines[:status].states.map(&:name)
102      to_status_names = from_status_names - [:created] # we never want to transition into created
103
104      from_status_names.product(to_status_names)
105    end
106
107    with_them do
108      it do
109        pipeline.status = from_status.to_s
110
111        if from_status != to_status
112          expect(pipeline.set_status(to_status.to_s))
113            .to eq(true)
114        else
115          expect(pipeline.set_status(to_status.to_s))
116            .to eq(false), "loopback transitions are not allowed"
117        end
118      end
119    end
120  end
121
122  describe '.processables' do
123    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
124
125    before do
126      create(:ci_build, name: 'build', pipeline: pipeline)
127      create(:ci_bridge, name: 'bridge', pipeline: pipeline)
128      create(:commit_status, name: 'commit status', pipeline: pipeline)
129      create(:generic_commit_status, name: 'generic status', pipeline: pipeline)
130    end
131
132    it 'has an association with processable CI/CD entities' do
133      pipeline.processables.pluck('name').yield_self do |processables|
134        expect(processables).to match_array %w[build bridge]
135      end
136    end
137
138    it 'makes it possible to append a new processable' do
139      pipeline.processables << build(:ci_bridge)
140
141      pipeline.save!
142
143      expect(pipeline.processables.reload.count).to eq 3
144    end
145  end
146
147  describe '.for_iid' do
148    subject { described_class.for_iid(iid) }
149
150    let(:iid) { '1234' }
151    let!(:pipeline) { create(:ci_pipeline, iid: '1234') }
152
153    it 'returns the pipeline' do
154      is_expected.to contain_exactly(pipeline)
155    end
156  end
157
158  describe '.for_sha' do
159    subject { described_class.for_sha(sha) }
160
161    let(:sha) { 'abc' }
162
163    let_it_be(:pipeline) { create(:ci_pipeline, sha: 'abc') }
164
165    it 'returns the pipeline' do
166      is_expected.to contain_exactly(pipeline)
167    end
168
169    context 'when argument is array' do
170      let(:sha) { %w[abc def] }
171      let!(:pipeline_2) { create(:ci_pipeline, sha: 'def') }
172
173      it 'returns the pipelines' do
174        is_expected.to contain_exactly(pipeline, pipeline_2)
175      end
176    end
177
178    context 'when sha is empty' do
179      let(:sha) { nil }
180
181      it 'does not return anything' do
182        is_expected.to be_empty
183      end
184    end
185  end
186
187  describe '.where_not_sha' do
188    let_it_be(:pipeline) { create(:ci_pipeline, sha: 'abcx') }
189    let_it_be(:pipeline_2) { create(:ci_pipeline, sha: 'abc') }
190
191    let(:sha) { 'abc' }
192
193    subject { described_class.where_not_sha(sha) }
194
195    it 'returns the pipeline without the specified sha' do
196      is_expected.to contain_exactly(pipeline)
197    end
198
199    context 'when argument is array' do
200      let(:sha) { %w[abc abcx] }
201
202      it 'returns the pipelines without the specified shas' do
203        pipeline_3 = create(:ci_pipeline, sha: 'abcy')
204        is_expected.to contain_exactly(pipeline_3)
205      end
206    end
207  end
208
209  describe '.for_source_sha' do
210    subject { described_class.for_source_sha(source_sha) }
211
212    let(:source_sha) { 'abc' }
213
214    let_it_be(:pipeline) { create(:ci_pipeline, source_sha: 'abc') }
215
216    it 'returns the pipeline' do
217      is_expected.to contain_exactly(pipeline)
218    end
219
220    context 'when argument is array' do
221      let(:source_sha) { %w[abc def] }
222      let!(:pipeline_2) { create(:ci_pipeline, source_sha: 'def') }
223
224      it 'returns the pipelines' do
225        is_expected.to contain_exactly(pipeline, pipeline_2)
226      end
227    end
228
229    context 'when source_sha is empty' do
230      let(:source_sha) { nil }
231
232      it 'does not return anything' do
233        is_expected.to be_empty
234      end
235    end
236  end
237
238  describe '.for_sha_or_source_sha' do
239    subject { described_class.for_sha_or_source_sha(sha) }
240
241    let(:sha) { 'abc' }
242
243    context 'when sha is matched' do
244      let!(:pipeline) { create(:ci_pipeline, sha: sha) }
245
246      it 'returns the pipeline' do
247        is_expected.to contain_exactly(pipeline)
248      end
249    end
250
251    context 'when source sha is matched' do
252      let!(:pipeline) { create(:ci_pipeline, source_sha: sha) }
253
254      it 'returns the pipeline' do
255        is_expected.to contain_exactly(pipeline)
256      end
257    end
258
259    context 'when both sha and source sha are not matched' do
260      let!(:pipeline) { create(:ci_pipeline, sha: 'bcd', source_sha: 'bcd') }
261
262      it 'does not return anything' do
263        is_expected.to be_empty
264      end
265    end
266  end
267
268  describe '.for_branch' do
269    subject { described_class.for_branch(branch) }
270
271    let(:branch) { 'master' }
272
273    let_it_be(:pipeline) { create(:ci_pipeline, ref: 'master') }
274
275    it 'returns the pipeline' do
276      is_expected.to contain_exactly(pipeline)
277    end
278
279    context 'with tag pipeline' do
280      let(:branch) { 'v1.0' }
281      let!(:pipeline) { create(:ci_pipeline, ref: 'v1.0', tag: true) }
282
283      it 'returns nothing' do
284        is_expected.to be_empty
285      end
286    end
287  end
288
289  describe '.with_pipeline_source' do
290    subject { described_class.with_pipeline_source(source) }
291
292    let(:source) { 'web' }
293
294    let_it_be(:push_pipeline)   { create(:ci_pipeline, source: :push) }
295    let_it_be(:web_pipeline)    { create(:ci_pipeline, source: :web) }
296    let_it_be(:api_pipeline)    { create(:ci_pipeline, source: :api) }
297
298    it 'contains pipelines created due to specified source' do
299      expect(subject).to contain_exactly(web_pipeline)
300    end
301  end
302
303  describe '.ci_sources' do
304    subject { described_class.ci_sources }
305
306    let(:push_pipeline)   { build(:ci_pipeline, source: :push) }
307    let(:web_pipeline)    { build(:ci_pipeline, source: :web) }
308    let(:api_pipeline)    { build(:ci_pipeline, source: :api) }
309    let(:webide_pipeline) { build(:ci_pipeline, source: :webide) }
310    let(:child_pipeline)  { build(:ci_pipeline, source: :parent_pipeline) }
311    let(:pipelines) { [push_pipeline, web_pipeline, api_pipeline, webide_pipeline, child_pipeline] }
312
313    it 'contains pipelines having CI only sources' do
314      pipelines.map(&:save!)
315
316      expect(subject).to contain_exactly(push_pipeline, web_pipeline, api_pipeline)
317    end
318
319    it 'filters on expected sources' do
320      expect(::Enums::Ci::Pipeline.ci_sources.keys).to contain_exactly(
321        *%i[unknown push web trigger schedule api external pipeline chat
322            merge_request_event external_pull_request_event])
323    end
324  end
325
326  describe '.ci_branch_sources' do
327    subject { described_class.ci_branch_sources }
328
329    let_it_be(:push_pipeline)   { create(:ci_pipeline, source: :push) }
330    let_it_be(:web_pipeline)    { create(:ci_pipeline, source: :web) }
331    let_it_be(:api_pipeline)    { create(:ci_pipeline, source: :api) }
332    let_it_be(:webide_pipeline) { create(:ci_pipeline, source: :webide) }
333    let_it_be(:child_pipeline)  { create(:ci_pipeline, source: :parent_pipeline) }
334    let_it_be(:merge_request_pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline) }
335
336    it 'contains pipelines having CI only sources' do
337      expect(subject).to contain_exactly(push_pipeline, web_pipeline, api_pipeline)
338    end
339
340    it 'filters on expected sources' do
341      expect(::Enums::Ci::Pipeline.ci_branch_sources.keys).to contain_exactly(
342        *%i[unknown push web trigger schedule api external pipeline chat
343            external_pull_request_event])
344    end
345  end
346
347  describe '.outside_pipeline_family' do
348    subject(:outside_pipeline_family) { described_class.outside_pipeline_family(upstream_pipeline) }
349
350    let(:upstream_pipeline) { create(:ci_pipeline, project: project) }
351    let(:child_pipeline) { create(:ci_pipeline, project: project) }
352
353    let!(:other_pipeline) { create(:ci_pipeline, project: project) }
354
355    before do
356      create(:ci_sources_pipeline,
357             source_job: create(:ci_build, pipeline: upstream_pipeline),
358             source_project: project,
359             pipeline: child_pipeline,
360             project: project)
361    end
362
363    it 'only returns pipelines outside pipeline family' do
364      expect(outside_pipeline_family).to contain_exactly(other_pipeline)
365    end
366  end
367
368  describe '.before_pipeline' do
369    subject(:before_pipeline) { described_class.before_pipeline(child_pipeline) }
370
371    let!(:older_other_pipeline) { create(:ci_pipeline, project: project) }
372
373    let!(:upstream_pipeline) { create(:ci_pipeline, project: project) }
374    let!(:child_pipeline) { create(:ci_pipeline, child_of: upstream_pipeline) }
375
376    let!(:other_pipeline) { create(:ci_pipeline, project: project) }
377
378    before do
379      create(:ci_sources_pipeline,
380             source_job: create(:ci_build, pipeline: upstream_pipeline),
381             source_project: project,
382             pipeline: child_pipeline,
383             project: project)
384    end
385
386    it 'only returns older pipelines outside pipeline family' do
387      expect(before_pipeline).to contain_exactly(older_other_pipeline)
388    end
389  end
390
391  describe '#merge_request?' do
392    let(:pipeline) { create(:ci_pipeline, merge_request: merge_request) }
393    let(:merge_request) { create(:merge_request) }
394
395    it 'returns true' do
396      expect(pipeline).to be_merge_request
397    end
398
399    context 'when merge request is nil' do
400      let(:merge_request) { nil }
401
402      it 'returns false' do
403        expect(pipeline).not_to be_merge_request
404      end
405    end
406  end
407
408  describe '#detached_merge_request_pipeline?' do
409    subject { pipeline.detached_merge_request_pipeline? }
410
411    let!(:pipeline) do
412      create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, target_sha: target_sha)
413    end
414
415    let(:merge_request) { create(:merge_request) }
416    let(:target_sha) { nil }
417
418    it { is_expected.to be_truthy }
419
420    context 'when target sha exists' do
421      let(:target_sha) { merge_request.target_branch_sha }
422
423      it { is_expected.to be_falsy }
424    end
425  end
426
427  describe '#merged_result_pipeline?' do
428    subject { pipeline.merged_result_pipeline? }
429
430    let!(:pipeline) do
431      create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, target_sha: target_sha)
432    end
433
434    let(:merge_request) { create(:merge_request) }
435    let(:target_sha) { merge_request.target_branch_sha }
436
437    it { is_expected.to be_truthy }
438
439    context 'when target sha is empty' do
440      let(:target_sha) { nil }
441
442      it { is_expected.to be_falsy }
443    end
444  end
445
446  describe '#merge_request_ref?' do
447    subject { pipeline.merge_request_ref? }
448
449    let(:pipeline) { build(:ci_empty_pipeline, :created) }
450
451    it 'calls MergeRequest#merge_request_ref?' do
452      expect(MergeRequest).to receive(:merge_request_ref?).with(pipeline.ref)
453
454      subject
455    end
456  end
457
458  describe '#merge_request_event_type' do
459    subject { pipeline.merge_request_event_type }
460
461    let(:pipeline) { merge_request.all_pipelines.last }
462
463    context 'when pipeline is merge request pipeline' do
464      let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) }
465
466      it { is_expected.to eq(:merged_result) }
467    end
468
469    context 'when pipeline is detached merge request pipeline' do
470      let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
471
472      it { is_expected.to eq(:detached) }
473    end
474  end
475
476  describe '#legacy_detached_merge_request_pipeline?' do
477    subject { pipeline.legacy_detached_merge_request_pipeline? }
478
479    let_it_be(:merge_request) { create(:merge_request) }
480
481    let(:ref) { 'feature' }
482    let(:target_sha) { nil }
483
484    let(:pipeline) do
485      build(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: target_sha)
486    end
487
488    it { is_expected.to be_truthy }
489
490    context 'when pipeline ref is a merge request ref' do
491      let(:ref) { 'refs/merge-requests/1/head' }
492
493      it { is_expected.to be_falsy }
494    end
495
496    context 'when target sha is set' do
497      let(:target_sha) { 'target-sha' }
498
499      it { is_expected.to be_falsy }
500    end
501  end
502
503  describe '#matches_sha_or_source_sha?' do
504    subject { pipeline.matches_sha_or_source_sha?(sample_sha) }
505
506    let(:sample_sha) { Digest::SHA1.hexdigest(SecureRandom.hex) }
507
508    context 'when sha matches' do
509      let(:pipeline) { build(:ci_pipeline, sha: sample_sha) }
510
511      it { is_expected.to be_truthy }
512    end
513
514    context 'when source_sha matches' do
515      let(:pipeline) { build(:ci_pipeline, source_sha: sample_sha) }
516
517      it { is_expected.to be_truthy }
518    end
519
520    context 'when both sha and source_sha do not matche' do
521      let(:pipeline) { build(:ci_pipeline, sha: 'test', source_sha: 'test') }
522
523      it { is_expected.to be_falsy }
524    end
525  end
526
527  describe '#source_ref' do
528    subject { pipeline.source_ref }
529
530    let(:pipeline) { create(:ci_pipeline, ref: 'feature') }
531
532    it 'returns source ref' do
533      is_expected.to eq('feature')
534    end
535
536    context 'when the pipeline is a detached merge request pipeline' do
537      let(:merge_request) { create(:merge_request) }
538
539      let(:pipeline) do
540        create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: merge_request.ref_path)
541      end
542
543      it 'returns source ref' do
544        is_expected.to eq(merge_request.source_branch)
545      end
546    end
547  end
548
549  describe '#source_ref_slug' do
550    subject { pipeline.source_ref_slug }
551
552    let(:pipeline) { create(:ci_pipeline, ref: 'feature') }
553
554    it 'slugifies with the source ref' do
555      expect(Gitlab::Utils).to receive(:slugify).with('feature')
556
557      subject
558    end
559
560    context 'when the pipeline is a detached merge request pipeline' do
561      let(:merge_request) { create(:merge_request) }
562
563      let(:pipeline) do
564        create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: merge_request.ref_path)
565      end
566
567      it 'slugifies with the source ref of the merge request' do
568        expect(Gitlab::Utils).to receive(:slugify).with(merge_request.source_branch)
569
570        subject
571      end
572    end
573  end
574
575  describe '.with_reports' do
576    context 'when pipeline has a test report' do
577      subject { described_class.with_reports(Ci::JobArtifact.test_reports) }
578
579      let!(:pipeline_with_report) { create(:ci_pipeline, :with_test_reports) }
580
581      it 'selects the pipeline' do
582        is_expected.to eq([pipeline_with_report])
583      end
584    end
585
586    context 'when pipeline has a coverage report' do
587      subject { described_class.with_reports(Ci::JobArtifact.coverage_reports) }
588
589      let!(:pipeline_with_report) { create(:ci_pipeline, :with_coverage_reports) }
590
591      it 'selects the pipeline' do
592        is_expected.to eq([pipeline_with_report])
593      end
594    end
595
596    context 'when pipeline has an accessibility report' do
597      subject { described_class.with_reports(Ci::JobArtifact.accessibility_reports) }
598
599      let(:pipeline_with_report) { create(:ci_pipeline, :with_accessibility_reports) }
600
601      it 'selects the pipeline' do
602        is_expected.to eq([pipeline_with_report])
603      end
604    end
605
606    context 'when pipeline has a codequality report' do
607      subject { described_class.with_reports(Ci::JobArtifact.codequality_reports) }
608
609      let(:pipeline_with_report) { create(:ci_pipeline, :with_codequality_reports) }
610
611      it 'selects the pipeline' do
612        is_expected.to eq([pipeline_with_report])
613      end
614    end
615
616    context 'when pipeline has a terraform report' do
617      it 'selects the pipeline' do
618        pipeline_with_report = create(:ci_pipeline, :with_terraform_reports)
619
620        expect(described_class.with_reports(Ci::JobArtifact.terraform_reports)).to eq(
621          [pipeline_with_report]
622        )
623      end
624    end
625
626    context 'when pipeline does not have metrics reports' do
627      subject { described_class.with_reports(Ci::JobArtifact.test_reports) }
628
629      let!(:pipeline_without_report) { create(:ci_empty_pipeline) }
630
631      it 'does not select the pipeline' do
632        is_expected.to be_empty
633      end
634    end
635  end
636
637  describe '.merge_request_event' do
638    subject { described_class.merge_request_event }
639
640    context 'when there is a merge request pipeline' do
641      let!(:pipeline) { create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request) }
642      let(:merge_request) { create(:merge_request) }
643
644      it 'returns merge request pipeline first' do
645        expect(subject).to eq([pipeline])
646      end
647    end
648
649    context 'when there are no merge request pipelines' do
650      let!(:pipeline) { create(:ci_pipeline, source: :push) }
651
652      it 'returns empty array' do
653        expect(subject).to be_empty
654      end
655    end
656  end
657
658  describe 'modules' do
659    it_behaves_like 'AtomicInternalId', validate_presence: false do
660      let(:internal_id_attribute) { :iid }
661      let(:instance) { build(:ci_pipeline) }
662      let(:scope) { :project }
663      let(:scope_attrs) { { project: instance.project } }
664      let(:usage) { :ci_pipelines }
665    end
666  end
667
668  describe '#source' do
669    context 'when creating new pipeline' do
670      let(:pipeline) do
671        build(:ci_empty_pipeline, :created, project: project, source: nil)
672      end
673
674      it "prevents from creating an object" do
675        expect(pipeline).not_to be_valid
676      end
677    end
678
679    context 'when updating existing pipeline' do
680      let(:pipeline) { create(:ci_empty_pipeline, :created) }
681
682      before do
683        pipeline.update_attribute(:source, nil)
684      end
685
686      it 'object is valid' do
687        expect(pipeline).to be_valid
688      end
689    end
690  end
691
692  describe '#block' do
693    let(:pipeline) { create(:ci_empty_pipeline, :created) }
694
695    it 'changes pipeline status to manual' do
696      expect(pipeline.block).to be true
697      expect(pipeline.reload).to be_manual
698      expect(pipeline.reload).to be_blocked
699    end
700  end
701
702  describe '#delay' do
703    subject { pipeline.delay }
704
705    let(:pipeline) { build(:ci_pipeline, :created) }
706
707    it 'changes pipeline status to schedule' do
708      subject
709
710      expect(pipeline).to be_scheduled
711    end
712  end
713
714  describe '#valid_commit_sha' do
715    let(:pipeline) { build_stubbed(:ci_empty_pipeline, :created, project: project) }
716
717    context 'commit.sha can not start with 00000000' do
718      before do
719        pipeline.sha = '0' * 40
720        pipeline.valid_commit_sha
721      end
722
723      it('commit errors should not be empty') { expect(pipeline.errors).not_to be_empty }
724    end
725  end
726
727  describe '#short_sha' do
728    subject { pipeline.short_sha }
729
730    let(:pipeline) { build_stubbed(:ci_empty_pipeline, :created) }
731
732    it 'has 8 items' do
733      expect(subject.size).to eq(8)
734    end
735    it { expect(pipeline.sha).to start_with(subject) }
736  end
737
738  describe '#retried' do
739    subject { pipeline.retried }
740
741    let(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
742    let!(:build1) { create(:ci_build, pipeline: pipeline, name: 'deploy', retried: true) }
743
744    before do
745      create(:ci_build, pipeline: pipeline, name: 'deploy')
746    end
747
748    it 'returns old builds' do
749      is_expected.to contain_exactly(build1)
750    end
751  end
752
753  describe '#coverage' do
754    let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline) }
755
756    context 'with multiple pipelines' do
757      before_all do
758        create(:ci_build, name: "rspec", coverage: 30, pipeline: pipeline)
759        create(:ci_build, name: "rubocop", coverage: 35, pipeline: pipeline)
760      end
761
762      it "calculates average when there are two builds with coverage" do
763        expect(pipeline.coverage).to be_within(0.001).of(32.5)
764      end
765
766      it "calculates average when there are two builds with coverage and one with nil" do
767        create(:ci_build, pipeline: pipeline)
768
769        expect(pipeline.coverage).to be_within(0.001).of(32.5)
770      end
771
772      it "calculates average when there are two builds with coverage and one is retried" do
773        create(:ci_build, name: "rubocop", coverage: 30, pipeline: pipeline, retried: true)
774
775        expect(pipeline.coverage).to be_within(0.001).of(32.5)
776      end
777    end
778
779    context 'when there is one build without coverage' do
780      it "calculates average to nil" do
781        create(:ci_build, pipeline: pipeline)
782
783        expect(pipeline.coverage).to be_nil
784      end
785    end
786  end
787
788  describe '#update_builds_coverage' do
789    let_it_be(:pipeline) { create(:ci_empty_pipeline) }
790
791    context 'builds with coverage_regex defined' do
792      let!(:build_1) { create(:ci_build, :success, :trace_with_coverage, trace_coverage: 60.0, pipeline: pipeline) }
793      let!(:build_2) { create(:ci_build, :success, :trace_with_coverage, trace_coverage: 80.0, pipeline: pipeline) }
794
795      it 'updates the coverage value of each build from the trace' do
796        pipeline.update_builds_coverage
797
798        expect(build_1.reload.coverage).to eq(60.0)
799        expect(build_2.reload.coverage).to eq(80.0)
800      end
801    end
802
803    context 'builds without coverage_regex defined' do
804      let!(:build) { create(:ci_build, :success, :trace_with_coverage, coverage_regex: nil, trace_coverage: 60.0, pipeline: pipeline) }
805
806      it 'does not update the coverage value of each build from the trace' do
807        pipeline.update_builds_coverage
808
809        expect(build.reload.coverage).to eq(nil)
810      end
811    end
812
813    context 'builds with coverage values already present' do
814      let!(:build) { create(:ci_build, :success, :trace_with_coverage, trace_coverage: 60.0, coverage: 10.0, pipeline: pipeline) }
815
816      it 'does not update the coverage value of each build from the trace' do
817        pipeline.update_builds_coverage
818
819        expect(build.reload.coverage).to eq(10.0)
820      end
821    end
822  end
823
824  describe '#retryable?' do
825    subject { pipeline.retryable? }
826
827    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
828
829    context 'no failed builds' do
830      before do
831        create_build('rspec', 'success')
832      end
833
834      it 'is not retryable' do
835        is_expected.to be_falsey
836      end
837
838      context 'one canceled job' do
839        before do
840          create_build('rubocop', 'canceled')
841        end
842
843        it 'is retryable' do
844          is_expected.to be_truthy
845        end
846      end
847    end
848
849    context 'with failed builds' do
850      before do
851        create_build('rspec', 'running')
852        create_build('rubocop', 'failed')
853      end
854
855      it 'is retryable' do
856        is_expected.to be_truthy
857      end
858    end
859
860    def create_build(name, status)
861      create(:ci_build, name: name, status: status, pipeline: pipeline)
862    end
863  end
864
865  describe '#persisted_variables' do
866    context 'when pipeline is not persisted yet' do
867      subject { build(:ci_pipeline).persisted_variables }
868
869      it 'does not contain some variables' do
870        keys = subject.map { |variable| variable[:key] }
871
872        expect(keys).not_to include 'CI_PIPELINE_ID'
873      end
874    end
875
876    context 'when pipeline is persisted' do
877      subject { build_stubbed(:ci_pipeline).persisted_variables }
878
879      it 'does contains persisted variables' do
880        keys = subject.map { |variable| variable[:key] }
881
882        expect(keys).to eq %w[CI_PIPELINE_ID CI_PIPELINE_URL]
883      end
884    end
885  end
886
887  describe '#predefined_variables' do
888    subject { pipeline.predefined_variables }
889
890    let(:pipeline) { build(:ci_empty_pipeline, :created) }
891
892    it 'includes all predefined variables in a valid order' do
893      keys = subject.map { |variable| variable[:key] }
894
895      expect(keys).to eq %w[
896        CI_PIPELINE_IID
897        CI_PIPELINE_SOURCE
898        CI_PIPELINE_CREATED_AT
899        CI_COMMIT_SHA
900        CI_COMMIT_SHORT_SHA
901        CI_COMMIT_BEFORE_SHA
902        CI_COMMIT_REF_NAME
903        CI_COMMIT_REF_SLUG
904        CI_COMMIT_BRANCH
905        CI_COMMIT_MESSAGE
906        CI_COMMIT_TITLE
907        CI_COMMIT_DESCRIPTION
908        CI_COMMIT_REF_PROTECTED
909        CI_COMMIT_TIMESTAMP
910        CI_COMMIT_AUTHOR
911        CI_BUILD_REF
912        CI_BUILD_BEFORE_SHA
913        CI_BUILD_REF_NAME
914        CI_BUILD_REF_SLUG
915      ]
916    end
917
918    context 'when merge request is present' do
919      let_it_be(:assignees) { create_list(:user, 2) }
920      let_it_be(:milestone) { create(:milestone, project: project) }
921      let_it_be(:labels) { create_list(:label, 2) }
922
923      let(:merge_request) do
924        create(:merge_request, :simple,
925               source_project: project,
926               target_project: project,
927               assignees: assignees,
928               milestone: milestone,
929               labels: labels)
930      end
931
932      context 'when pipeline for merge request is created' do
933        let(:pipeline) do
934          create(:ci_pipeline, :detached_merge_request_pipeline,
935            ci_ref_presence: false,
936            user: user,
937            merge_request: merge_request)
938        end
939
940        before do
941          project.add_developer(user)
942        end
943
944        it 'exposes merge request pipeline variables' do
945          expect(subject.to_hash)
946            .to include(
947              'CI_MERGE_REQUEST_ID' => merge_request.id.to_s,
948              'CI_MERGE_REQUEST_IID' => merge_request.iid.to_s,
949              'CI_MERGE_REQUEST_REF_PATH' => merge_request.ref_path.to_s,
950              'CI_MERGE_REQUEST_PROJECT_ID' => merge_request.project.id.to_s,
951              'CI_MERGE_REQUEST_PROJECT_PATH' => merge_request.project.full_path,
952              'CI_MERGE_REQUEST_PROJECT_URL' => merge_request.project.web_url,
953              'CI_MERGE_REQUEST_TARGET_BRANCH_NAME' => merge_request.target_branch.to_s,
954              'CI_MERGE_REQUEST_TARGET_BRANCH_SHA' => '',
955              'CI_MERGE_REQUEST_SOURCE_PROJECT_ID' => merge_request.source_project.id.to_s,
956              'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' => merge_request.source_project.full_path,
957              'CI_MERGE_REQUEST_SOURCE_PROJECT_URL' => merge_request.source_project.web_url,
958              'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' => merge_request.source_branch.to_s,
959              'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => '',
960              'CI_MERGE_REQUEST_TITLE' => merge_request.title,
961              'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
962              'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
963              'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).sort.join(','),
964              'CI_MERGE_REQUEST_EVENT_TYPE' => 'detached',
965              'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true))
966        end
967
968        it 'exposes diff variables' do
969          expect(subject.to_hash)
970            .to include(
971              'CI_MERGE_REQUEST_DIFF_ID' => merge_request.merge_request_diff.id.to_s,
972              'CI_MERGE_REQUEST_DIFF_BASE_SHA' => merge_request.merge_request_diff.base_commit_sha)
973        end
974
975        context 'without assignee' do
976          let(:assignees) { [] }
977
978          it 'does not expose assignee variable' do
979            expect(subject.to_hash.keys).not_to include('CI_MERGE_REQUEST_ASSIGNEES')
980          end
981        end
982
983        context 'without milestone' do
984          let(:milestone) { nil }
985
986          it 'does not expose milestone variable' do
987            expect(subject.to_hash.keys).not_to include('CI_MERGE_REQUEST_MILESTONE')
988          end
989        end
990
991        context 'without labels' do
992          let(:labels) { [] }
993
994          it 'does not expose labels variable' do
995            expect(subject.to_hash.keys).not_to include('CI_MERGE_REQUEST_LABELS')
996          end
997        end
998      end
999
1000      context 'when pipeline on branch is created' do
1001        let(:pipeline) do
1002          create(:ci_pipeline, project: project, user: user, ref: 'feature')
1003        end
1004
1005        context 'when a merge request is created' do
1006          before do
1007            merge_request
1008          end
1009
1010          context 'when user has access to project' do
1011            before do
1012              project.add_developer(user)
1013            end
1014
1015            it 'merge request references are returned matching the pipeline' do
1016              expect(subject.to_hash).to include(
1017                'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true))
1018            end
1019          end
1020
1021          context 'when user does not have access to project' do
1022            it 'CI_OPEN_MERGE_REQUESTS is not returned' do
1023              expect(subject.to_hash).not_to have_key('CI_OPEN_MERGE_REQUESTS')
1024            end
1025          end
1026        end
1027
1028        context 'when no a merge request is created' do
1029          it 'CI_OPEN_MERGE_REQUESTS is not returned' do
1030            expect(subject.to_hash).not_to have_key('CI_OPEN_MERGE_REQUESTS')
1031          end
1032        end
1033      end
1034
1035      context 'with merged results' do
1036        let(:pipeline) do
1037          create(:ci_pipeline, :merged_result_pipeline, merge_request: merge_request)
1038        end
1039
1040        it 'exposes merge request pipeline variables' do
1041          expect(subject.to_hash)
1042            .to include(
1043              'CI_MERGE_REQUEST_ID' => merge_request.id.to_s,
1044              'CI_MERGE_REQUEST_IID' => merge_request.iid.to_s,
1045              'CI_MERGE_REQUEST_REF_PATH' => merge_request.ref_path.to_s,
1046              'CI_MERGE_REQUEST_PROJECT_ID' => merge_request.project.id.to_s,
1047              'CI_MERGE_REQUEST_PROJECT_PATH' => merge_request.project.full_path,
1048              'CI_MERGE_REQUEST_PROJECT_URL' => merge_request.project.web_url,
1049              'CI_MERGE_REQUEST_TARGET_BRANCH_NAME' => merge_request.target_branch.to_s,
1050              'CI_MERGE_REQUEST_TARGET_BRANCH_SHA' => merge_request.target_branch_sha,
1051              'CI_MERGE_REQUEST_SOURCE_PROJECT_ID' => merge_request.source_project.id.to_s,
1052              'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH' => merge_request.source_project.full_path,
1053              'CI_MERGE_REQUEST_SOURCE_PROJECT_URL' => merge_request.source_project.web_url,
1054              'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' => merge_request.source_branch.to_s,
1055              'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => merge_request.source_branch_sha,
1056              'CI_MERGE_REQUEST_TITLE' => merge_request.title,
1057              'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
1058              'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
1059              'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).sort.join(','),
1060              'CI_MERGE_REQUEST_EVENT_TYPE' => 'merged_result')
1061        end
1062
1063        it 'exposes diff variables' do
1064          expect(subject.to_hash)
1065            .to include(
1066              'CI_MERGE_REQUEST_DIFF_ID' => merge_request.merge_request_diff.id.to_s,
1067              'CI_MERGE_REQUEST_DIFF_BASE_SHA' => merge_request.merge_request_diff.base_commit_sha)
1068        end
1069      end
1070    end
1071
1072    context 'when source is external pull request' do
1073      let(:pipeline) do
1074        create(:ci_pipeline, source: :external_pull_request_event, external_pull_request: pull_request)
1075      end
1076
1077      let(:pull_request) { create(:external_pull_request, project: project) }
1078
1079      it 'exposes external pull request pipeline variables' do
1080        expect(subject.to_hash)
1081          .to include(
1082            'CI_EXTERNAL_PULL_REQUEST_IID' => pull_request.pull_request_iid.to_s,
1083            'CI_EXTERNAL_PULL_REQUEST_SOURCE_REPOSITORY' => pull_request.source_repository,
1084            'CI_EXTERNAL_PULL_REQUEST_TARGET_REPOSITORY' => pull_request.target_repository,
1085            'CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_SHA' => pull_request.source_sha,
1086            'CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_SHA' => pull_request.target_sha,
1087            'CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME' => pull_request.source_branch,
1088            'CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME' => pull_request.target_branch
1089          )
1090      end
1091    end
1092
1093    describe 'variable CI_KUBERNETES_ACTIVE' do
1094      context 'when pipeline.has_kubernetes_active? is true' do
1095        before do
1096          allow(pipeline).to receive(:has_kubernetes_active?).and_return(true)
1097        end
1098
1099        it "is included with value 'true'" do
1100          expect(subject.to_hash).to include('CI_KUBERNETES_ACTIVE' => 'true')
1101        end
1102      end
1103
1104      context 'when pipeline.has_kubernetes_active? is false' do
1105        before do
1106          allow(pipeline).to receive(:has_kubernetes_active?).and_return(false)
1107        end
1108
1109        it 'is not included' do
1110          expect(subject.to_hash).not_to have_key('CI_KUBERNETES_ACTIVE')
1111        end
1112      end
1113    end
1114  end
1115
1116  describe '#protected_ref?' do
1117    let(:pipeline) { build(:ci_empty_pipeline, :created) }
1118
1119    it 'delegates method to project' do
1120      expect(pipeline).not_to be_protected_ref
1121    end
1122  end
1123
1124  describe '#legacy_trigger' do
1125    let(:trigger_request) { build(:ci_trigger_request) }
1126    let(:pipeline) { build(:ci_empty_pipeline, :created, trigger_requests: [trigger_request]) }
1127
1128    it 'returns first trigger request' do
1129      expect(pipeline.legacy_trigger).to eq trigger_request
1130    end
1131  end
1132
1133  describe '#auto_canceled?' do
1134    subject { pipeline.auto_canceled? }
1135
1136    let(:pipeline) { build(:ci_empty_pipeline, :created) }
1137
1138    context 'when it is canceled' do
1139      before do
1140        pipeline.cancel
1141      end
1142
1143      context 'when there is auto_canceled_by' do
1144        before do
1145          pipeline.auto_canceled_by = create(:ci_empty_pipeline)
1146        end
1147
1148        it 'is auto canceled' do
1149          is_expected.to be_truthy
1150        end
1151      end
1152
1153      context 'when there is no auto_canceled_by' do
1154        it 'is not auto canceled' do
1155          is_expected.to be_falsey
1156        end
1157      end
1158
1159      context 'when it is retried and canceled manually' do
1160        before do
1161          pipeline.enqueue
1162          pipeline.cancel
1163        end
1164
1165        it 'is not auto canceled' do
1166          is_expected.to be_falsey
1167        end
1168      end
1169    end
1170  end
1171
1172  describe 'pipeline stages' do
1173    let(:pipeline) { build(:ci_empty_pipeline, :created) }
1174
1175    describe 'legacy stages' do
1176      before do
1177        create(:commit_status, pipeline: pipeline,
1178                               stage: 'build',
1179                               name: 'linux',
1180                               stage_idx: 0,
1181                               status: 'success')
1182
1183        create(:commit_status, pipeline: pipeline,
1184                               stage: 'build',
1185                               name: 'mac',
1186                               stage_idx: 0,
1187                               status: 'failed')
1188
1189        create(:commit_status, pipeline: pipeline,
1190                               stage: 'deploy',
1191                               name: 'staging',
1192                               stage_idx: 2,
1193                               status: 'running')
1194
1195        create(:commit_status, pipeline: pipeline,
1196                               stage: 'test',
1197                               name: 'rspec',
1198                               stage_idx: 1,
1199                               status: 'success')
1200      end
1201
1202      describe '#legacy_stages' do
1203        using RSpec::Parameterized::TableSyntax
1204
1205        subject { pipeline.legacy_stages }
1206
1207        context 'stages list' do
1208          it 'returns ordered list of stages' do
1209            expect(subject.map(&:name)).to eq(%w[build test deploy])
1210          end
1211        end
1212
1213        context 'stages with statuses' do
1214          let(:statuses) do
1215            subject.map { |stage| [stage.name, stage.status] }
1216          end
1217
1218          it 'returns list of stages with correct statuses' do
1219            expect(statuses).to eq([%w(build failed),
1220                                    %w(test success),
1221                                    %w(deploy running)])
1222          end
1223        end
1224
1225        context 'when there is a stage with warnings' do
1226          before do
1227            create(:commit_status, pipeline: pipeline,
1228                                  stage: 'deploy',
1229                                  name: 'prod:2',
1230                                  stage_idx: 2,
1231                                  status: 'failed',
1232                                  allow_failure: true)
1233          end
1234
1235          it 'populates stage with correct number of warnings' do
1236            deploy_stage = pipeline.legacy_stages.third
1237
1238            expect(deploy_stage).not_to receive(:statuses)
1239            expect(deploy_stage).to have_warnings
1240          end
1241        end
1242      end
1243
1244      describe '#stages_count' do
1245        it 'returns a valid number of stages' do
1246          expect(pipeline.stages_count).to eq(3)
1247        end
1248      end
1249
1250      describe '#stages_names' do
1251        it 'returns a valid names of stages' do
1252          expect(pipeline.stages_names).to eq(%w(build test deploy))
1253        end
1254      end
1255    end
1256
1257    describe '#legacy_stage' do
1258      subject { pipeline.legacy_stage('test') }
1259
1260      let(:pipeline) { build(:ci_empty_pipeline, :created) }
1261
1262      context 'with status in stage' do
1263        before do
1264          create(:commit_status, pipeline: pipeline, stage: 'test')
1265        end
1266
1267        it { expect(subject).to be_a Ci::LegacyStage }
1268        it { expect(subject.name).to eq 'test' }
1269        it { expect(subject.statuses).not_to be_empty }
1270      end
1271
1272      context 'without status in stage' do
1273        before do
1274          create(:commit_status, pipeline: pipeline, stage: 'build')
1275        end
1276
1277        it 'return stage object' do
1278          is_expected.to be_nil
1279        end
1280      end
1281    end
1282
1283    describe '#stages' do
1284      let(:pipeline) { build(:ci_empty_pipeline, :created) }
1285
1286      before do
1287        create(:ci_stage_entity, project: project,
1288                                 pipeline: pipeline,
1289                                 position: 4,
1290                                 name: 'deploy')
1291
1292        create(:ci_build, project: project,
1293                          pipeline: pipeline,
1294                          stage: 'test',
1295                          stage_idx: 3,
1296                          name: 'test')
1297
1298        create(:ci_build, project: project,
1299                          pipeline: pipeline,
1300                          stage: 'build',
1301                          stage_idx: 2,
1302                          name: 'build')
1303
1304        create(:ci_stage_entity, project: project,
1305                                 pipeline: pipeline,
1306                                 position: 1,
1307                                 name: 'sanity')
1308
1309        create(:ci_stage_entity, project: project,
1310                                 pipeline: pipeline,
1311                                 position: 5,
1312                                 name: 'cleanup')
1313      end
1314
1315      subject { pipeline.stages }
1316
1317      context 'when pipelines is not complete' do
1318        it 'returns stages in valid order' do
1319          expect(subject).to all(be_a Ci::Stage)
1320          expect(subject.map(&:name))
1321            .to eq %w[sanity build test deploy cleanup]
1322        end
1323      end
1324
1325      context 'when pipeline is complete' do
1326        before do
1327          pipeline.succeed!
1328        end
1329
1330        it 'returns stages in valid order' do
1331          expect(subject).to all(be_a Ci::Stage)
1332          expect(subject.map(&:name))
1333            .to eq %w[sanity build test deploy cleanup]
1334        end
1335      end
1336    end
1337  end
1338
1339  describe 'state machine' do
1340    let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, :created) }
1341
1342    let(:current) { Time.current.change(usec: 0) }
1343    let(:build) { create_build('build1', queued_at: 0) }
1344    let(:build_b) { create_build('build2', queued_at: 0) }
1345    let(:build_c) { create_build('build3', queued_at: 0) }
1346
1347    %w[succeed! drop! cancel! skip!].each do |action|
1348      context "when the pipeline recieved #{action} event" do
1349        it 'deletes a persistent ref' do
1350          expect(pipeline.persistent_ref).to receive(:delete).once
1351
1352          pipeline.public_send(action)
1353        end
1354      end
1355    end
1356
1357    describe 'synching status to Jira' do
1358      let(:worker) { ::JiraConnect::SyncBuildsWorker }
1359
1360      context 'when Jira Connect subscription does not exist' do
1361        it 'does not trigger a Jira synch worker' do
1362          expect(worker).not_to receive(:perform_async)
1363
1364          pipeline.prepare!
1365        end
1366      end
1367
1368      context 'when Jira Connect subscription exists' do
1369        before_all do
1370          create(:jira_connect_subscription, namespace: project.namespace)
1371        end
1372
1373        %i[prepare! run! skip! drop! succeed! cancel! block! delay!].each do |event|
1374          context "when we call pipeline.#{event}" do
1375            it 'triggers a Jira synch worker' do
1376              expect(worker).to receive(:perform_async).with(pipeline.id, Integer)
1377
1378              pipeline.send(event)
1379            end
1380          end
1381        end
1382      end
1383    end
1384
1385    describe '#duration', :sidekiq_inline do
1386      context 'when multiple builds are finished' do
1387        before do
1388          travel_to(current + 30) do
1389            build.run!
1390            build.reload.success!
1391            build_b.run!
1392            build_c.run!
1393          end
1394
1395          travel_to(current + 40) do
1396            build_b.reload.drop!
1397          end
1398
1399          travel_to(current + 70) do
1400            build_c.reload.success!
1401          end
1402        end
1403
1404        it 'matches sum of builds duration' do
1405          pipeline.reload
1406
1407          expect(pipeline.duration).to eq(40)
1408        end
1409      end
1410
1411      context 'when pipeline becomes blocked' do
1412        let!(:build) { create_build('build:1') }
1413        let!(:action) { create_build('manual:action', :manual) }
1414
1415        before do
1416          travel_to(current + 1.minute) do
1417            build.run!
1418          end
1419
1420          travel_to(current + 5.minutes) do
1421            build.reload.success!
1422          end
1423        end
1424
1425        it 'recalculates pipeline duration' do
1426          pipeline.reload
1427
1428          expect(pipeline).to be_manual
1429          expect(pipeline.duration).to eq 4.minutes
1430        end
1431      end
1432    end
1433
1434    describe '#started_at' do
1435      let(:pipeline) { create(:ci_empty_pipeline, status: from_status) }
1436
1437      %i[created preparing pending].each do |status|
1438        context "from #{status}" do
1439          let(:from_status) { status }
1440
1441          it 'updates on transitioning to running' do
1442            pipeline.run
1443
1444            expect(pipeline.started_at).not_to be_nil
1445          end
1446        end
1447      end
1448
1449      context 'from created' do
1450        let(:from_status) { :created }
1451
1452        it 'does not update on transitioning to success' do
1453          pipeline.succeed
1454
1455          expect(pipeline.started_at).to be_nil
1456        end
1457      end
1458    end
1459
1460    describe '#finished_at' do
1461      it 'updates on transitioning to success', :sidekiq_might_not_need_inline do
1462        build.success
1463
1464        expect(pipeline.reload.finished_at).not_to be_nil
1465      end
1466
1467      it 'does not update on transitioning to running' do
1468        build.run
1469
1470        expect(pipeline.reload.finished_at).to be_nil
1471      end
1472    end
1473
1474    describe 'merge request metrics' do
1475      let(:pipeline) { create(:ci_empty_pipeline, status: from_status) }
1476
1477      before do
1478        expect(PipelineMetricsWorker).to receive(:perform_async).with(pipeline.id)
1479      end
1480
1481      context 'when transitioning to running' do
1482        %i[created preparing pending].each do |status|
1483          context "from #{status}" do
1484            let(:from_status) { status }
1485
1486            it 'schedules metrics workers' do
1487              pipeline.run
1488            end
1489          end
1490        end
1491      end
1492
1493      context 'when transitioning to success' do
1494        let(:from_status) { 'created' }
1495
1496        it 'schedules metrics workers' do
1497          pipeline.succeed
1498        end
1499      end
1500    end
1501
1502    describe 'merge on success' do
1503      let(:pipeline) { create(:ci_empty_pipeline, status: from_status) }
1504
1505      %i[created preparing pending running].each do |status|
1506        context "from #{status}" do
1507          let(:from_status) { status }
1508
1509          it 'schedules daily build group report results worker' do
1510            expect(Ci::DailyBuildGroupReportResultsWorker).to receive(:perform_in).with(10.minutes, pipeline.id)
1511
1512            pipeline.succeed
1513          end
1514        end
1515      end
1516    end
1517
1518    describe 'pipeline caching' do
1519      context 'when expire_job_and_pipeline_cache_synchronously is enabled' do
1520        before do
1521          stub_feature_flags(expire_job_and_pipeline_cache_synchronously: true)
1522        end
1523
1524        it 'executes Ci::ExpirePipelineCacheService' do
1525          expect_next_instance_of(Ci::ExpirePipelineCacheService) do |service|
1526            expect(service).to receive(:execute).with(pipeline)
1527          end
1528
1529          pipeline.cancel
1530        end
1531      end
1532
1533      context 'when expire_job_and_pipeline_cache_synchronously is disabled' do
1534        before do
1535          stub_feature_flags(expire_job_and_pipeline_cache_synchronously: false)
1536        end
1537
1538        it 'performs ExpirePipelinesCacheWorker' do
1539          expect(ExpirePipelineCacheWorker).to receive(:perform_async).with(pipeline.id)
1540
1541          pipeline.cancel
1542        end
1543      end
1544    end
1545
1546    describe '#dangling?' do
1547      it 'returns true if pipeline comes from any dangling sources' do
1548        pipeline.source = Enums::Ci::Pipeline.dangling_sources.each_key.first
1549
1550        expect(pipeline).to be_dangling
1551      end
1552
1553      it 'returns true if pipeline comes from any CI sources' do
1554        pipeline.source = Enums::Ci::Pipeline.ci_sources.each_key.first
1555
1556        expect(pipeline).not_to be_dangling
1557      end
1558    end
1559
1560    describe 'auto merge' do
1561      context 'when auto merge is enabled' do
1562        let_it_be_with_reload(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
1563        let_it_be_with_reload(:pipeline) do
1564          create(:ci_pipeline, :running, project: merge_request.source_project,
1565                                        ref: merge_request.source_branch,
1566                                        sha: merge_request.diff_head_sha)
1567        end
1568
1569        before_all do
1570          merge_request.update_head_pipeline
1571        end
1572
1573        %w[succeed! drop! cancel! skip!].each do |action|
1574          context "when the pipeline recieved #{action} event" do
1575            it 'performs AutoMergeProcessWorker' do
1576              expect(AutoMergeProcessWorker).to receive(:perform_async).with(merge_request.id)
1577
1578              pipeline.public_send(action)
1579            end
1580          end
1581        end
1582      end
1583
1584      context 'when auto merge is not enabled in the merge request' do
1585        let(:merge_request) { create(:merge_request) }
1586
1587        it 'performs AutoMergeProcessWorker' do
1588          expect(AutoMergeProcessWorker).not_to receive(:perform_async)
1589
1590          pipeline.succeed!
1591        end
1592      end
1593    end
1594
1595    describe 'auto devops pipeline metrics' do
1596      using RSpec::Parameterized::TableSyntax
1597
1598      let(:pipeline) { create(:ci_empty_pipeline, config_source: config_source) }
1599      let(:config_source) { :auto_devops_source }
1600
1601      where(:action, :status) do
1602        :succeed | 'success'
1603        :drop    | 'failed'
1604        :skip    | 'skipped'
1605        :cancel  | 'canceled'
1606      end
1607
1608      with_them do
1609        context "when pipeline receives action '#{params[:action]}'" do
1610          subject { pipeline.public_send(action) }
1611
1612          it { expect { subject }.to change { auto_devops_pipelines_completed_total(status) }.by(1) }
1613
1614          context 'when not auto_devops_source?' do
1615            let(:config_source) { :repository_source }
1616
1617            it { expect { subject }.not_to change { auto_devops_pipelines_completed_total(status) } }
1618          end
1619        end
1620      end
1621
1622      def auto_devops_pipelines_completed_total(status)
1623        Gitlab::Metrics.counter(:auto_devops_pipelines_completed_total, 'Number of completed auto devops pipelines').get(status: status)
1624      end
1625    end
1626
1627    describe 'bridge triggered pipeline' do
1628      shared_examples 'upstream downstream pipeline' do
1629        let!(:source_pipeline) { create(:ci_sources_pipeline, pipeline: downstream_pipeline, source_job: bridge) }
1630        let!(:job) { downstream_pipeline.builds.first }
1631
1632        context 'when source bridge is dependent on pipeline status' do
1633          let!(:bridge) { create(:ci_bridge, :strategy_depend, pipeline: upstream_pipeline) }
1634
1635          it 'schedules the pipeline bridge worker' do
1636            expect(::Ci::PipelineBridgeStatusWorker).to receive(:perform_async).with(downstream_pipeline.id)
1637
1638            downstream_pipeline.succeed!
1639          end
1640
1641          context 'when the downstream pipeline first fails then retries and succeeds' do
1642            it 'makes the upstream pipeline successful' do
1643              Sidekiq::Testing.inline! { job.drop! }
1644
1645              expect(downstream_pipeline.reload).to be_failed
1646              expect(upstream_pipeline.reload).to be_failed
1647
1648              Sidekiq::Testing.inline! do
1649                new_job = Ci::Build.retry(job, project.users.first)
1650
1651                expect(downstream_pipeline.reload).to be_running
1652                expect(upstream_pipeline.reload).to be_running
1653
1654                new_job.success!
1655              end
1656
1657              expect(downstream_pipeline.reload).to be_success
1658              expect(upstream_pipeline.reload).to be_success
1659            end
1660          end
1661
1662          context 'when the downstream pipeline first succeeds then retries and fails' do
1663            it 'makes the upstream pipeline failed' do
1664              Sidekiq::Testing.inline! { job.success! }
1665
1666              expect(downstream_pipeline.reload).to be_success
1667              expect(upstream_pipeline.reload).to be_success
1668
1669              Sidekiq::Testing.inline! do
1670                new_job = Ci::Build.retry(job, project.users.first)
1671
1672                expect(downstream_pipeline.reload).to be_running
1673                expect(upstream_pipeline.reload).to be_running
1674
1675                new_job.drop!
1676              end
1677
1678              expect(downstream_pipeline.reload).to be_failed
1679              expect(upstream_pipeline.reload).to be_failed
1680            end
1681          end
1682
1683          context 'when the upstream pipeline has another dependent upstream pipeline' do
1684            let!(:upstream_of_upstream_pipeline) { create(:ci_pipeline) }
1685
1686            before do
1687              upstream_bridge = create(:ci_bridge, :strategy_depend, pipeline: upstream_of_upstream_pipeline)
1688              create(:ci_sources_pipeline, pipeline: upstream_pipeline,
1689                                           source_job: upstream_bridge)
1690            end
1691
1692            context 'when the downstream pipeline first fails then retries and succeeds' do
1693              it 'makes upstream pipelines successful' do
1694                Sidekiq::Testing.inline! { job.drop! }
1695
1696                expect(downstream_pipeline.reload).to be_failed
1697                expect(upstream_pipeline.reload).to be_failed
1698                expect(upstream_of_upstream_pipeline.reload).to be_failed
1699
1700                Sidekiq::Testing.inline! do
1701                  new_job = Ci::Build.retry(job, project.users.first)
1702
1703                  expect(downstream_pipeline.reload).to be_running
1704                  expect(upstream_pipeline.reload).to be_running
1705                  expect(upstream_of_upstream_pipeline.reload).to be_running
1706
1707                  new_job.success!
1708                end
1709
1710                expect(downstream_pipeline.reload).to be_success
1711                expect(upstream_pipeline.reload).to be_success
1712                expect(upstream_of_upstream_pipeline.reload).to be_success
1713              end
1714            end
1715          end
1716        end
1717
1718        context 'when source bridge is not dependent on pipeline status' do
1719          let!(:bridge) { create(:ci_bridge, pipeline: upstream_pipeline) }
1720
1721          it 'does not schedule the pipeline bridge worker' do
1722            expect(::Ci::PipelineBridgeStatusWorker).not_to receive(:perform_async)
1723
1724            downstream_pipeline.succeed!
1725          end
1726        end
1727      end
1728
1729      context 'multi-project pipelines' do
1730        let!(:downstream_project) { create(:project, :repository) }
1731        let!(:upstream_pipeline) { create(:ci_pipeline) }
1732        let!(:downstream_pipeline) { create(:ci_pipeline, :with_job, project: downstream_project) }
1733
1734        it_behaves_like 'upstream downstream pipeline'
1735      end
1736
1737      context 'parent-child pipelines' do
1738        let!(:upstream_pipeline) { create(:ci_pipeline) }
1739        let!(:downstream_pipeline) { create(:ci_pipeline, :with_job) }
1740
1741        it_behaves_like 'upstream downstream pipeline'
1742      end
1743    end
1744
1745    def create_build(name, *traits, queued_at: current, started_from: 0, **opts)
1746      create(:ci_build, *traits,
1747             name: name,
1748             pipeline: pipeline,
1749             queued_at: queued_at,
1750             started_at: queued_at + started_from,
1751             **opts)
1752    end
1753  end
1754
1755  describe '#branch?' do
1756    subject { pipeline.branch? }
1757
1758    let(:pipeline) { build(:ci_empty_pipeline, :created) }
1759
1760    context 'when ref is not a tag' do
1761      before do
1762        pipeline.tag = false
1763      end
1764
1765      it 'return true' do
1766        is_expected.to be_truthy
1767      end
1768
1769      context 'when pipeline is merge request' do
1770        let(:pipeline) { build(:ci_pipeline, merge_request: merge_request) }
1771
1772        let(:merge_request) do
1773          create(:merge_request, :simple,
1774                 source_project: project,
1775                 target_project: project)
1776        end
1777
1778        it 'returns false' do
1779          is_expected.to be_falsey
1780        end
1781      end
1782    end
1783
1784    context 'when ref is a tag' do
1785      before do
1786        pipeline.tag = true
1787      end
1788
1789      it 'return false' do
1790        is_expected.to be_falsey
1791      end
1792    end
1793  end
1794
1795  describe '#git_ref' do
1796    subject { pipeline.send(:git_ref) }
1797
1798    context 'when ref is branch' do
1799      let(:pipeline) { create(:ci_pipeline, tag: false) }
1800
1801      it 'returns branch ref' do
1802        is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.ref.to_s)
1803      end
1804    end
1805
1806    context 'when ref is tag' do
1807      let(:pipeline) { create(:ci_pipeline, tag: true) }
1808
1809      it 'returns branch ref' do
1810        is_expected.to eq(Gitlab::Git::TAG_REF_PREFIX + pipeline.ref.to_s)
1811      end
1812    end
1813
1814    context 'when ref is merge request' do
1815      let(:pipeline) do
1816        create(:ci_pipeline,
1817               source: :merge_request_event,
1818               merge_request: merge_request)
1819      end
1820
1821      let(:merge_request) do
1822        create(:merge_request,
1823               source_project: project,
1824               source_branch: 'feature',
1825               target_project: project,
1826               target_branch: 'master')
1827      end
1828
1829      it 'returns branch ref' do
1830        is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.ref.to_s)
1831      end
1832    end
1833  end
1834
1835  describe 'ref_exists?' do
1836    context 'when repository exists' do
1837      using RSpec::Parameterized::TableSyntax
1838
1839      let_it_be(:pipeline, refind: true) { create(:ci_empty_pipeline) }
1840
1841      where(:tag, :ref, :result) do
1842        false | 'master'              | true
1843        false | 'non-existent-branch' | false
1844        true  | 'v1.1.0'              | true
1845        true  | 'non-existent-tag'    | false
1846      end
1847
1848      with_them do
1849        before do
1850          pipeline.update!(tag: tag, ref: ref)
1851        end
1852
1853        it "correctly detects ref" do
1854          expect(pipeline.ref_exists?).to be result
1855        end
1856      end
1857    end
1858
1859    context 'when repository does not exist' do
1860      let(:pipeline) { build(:ci_empty_pipeline, ref: 'master', project: build(:project)) }
1861
1862      it 'always returns false' do
1863        expect(pipeline.ref_exists?).to eq false
1864      end
1865    end
1866  end
1867
1868  context 'with non-empty project' do
1869    let(:pipeline) do
1870      create(:ci_pipeline,
1871             ref: project.default_branch,
1872             sha: project.commit.sha)
1873    end
1874
1875    describe '#lazy_ref_commit' do
1876      let(:another) do
1877        create(:ci_pipeline,
1878               ref: 'feature',
1879               sha: project.commit('feature').sha)
1880      end
1881
1882      let(:unicode) do
1883        create(:ci_pipeline,
1884               ref: 'ü/unicode/multi-byte')
1885      end
1886
1887      it 'returns the latest commit for a ref lazily' do
1888        expect(project.repository)
1889          .to receive(:list_commits_by_ref_name).once
1890          .and_call_original
1891
1892        pipeline.lazy_ref_commit
1893        another.lazy_ref_commit
1894        unicode.lazy_ref_commit
1895
1896        expect(pipeline.lazy_ref_commit.id).to eq pipeline.sha
1897        expect(another.lazy_ref_commit.id).to eq another.sha
1898        expect(unicode.lazy_ref_commit).to be_nil
1899      end
1900    end
1901
1902    describe '#latest?' do
1903      context 'with latest sha' do
1904        it 'returns true' do
1905          expect(pipeline).to be_latest
1906        end
1907      end
1908
1909      context 'with a branch name as the ref' do
1910        it 'looks up a commit for a branch' do
1911          expect(pipeline.ref).to eq 'master'
1912          expect(pipeline).to be_latest
1913        end
1914      end
1915
1916      context 'with a tag name as a ref' do
1917        it 'looks up a commit for a tag' do
1918          expect(project.repository.branch_names).not_to include 'v1.0.0'
1919
1920          pipeline.update!(sha: project.commit('v1.0.0').sha, ref: 'v1.0.0', tag: true)
1921
1922          expect(pipeline).to be_tag
1923          expect(pipeline).to be_latest
1924        end
1925      end
1926
1927      context 'with not latest sha' do
1928        before do
1929          pipeline.update!(sha: project.commit("#{project.default_branch}~1").sha)
1930        end
1931
1932        it 'returns false' do
1933          expect(pipeline).not_to be_latest
1934        end
1935      end
1936    end
1937  end
1938
1939  describe '#manual_actions' do
1940    subject { pipeline.manual_actions }
1941
1942    let(:pipeline) { create(:ci_empty_pipeline, :created) }
1943
1944    it 'when none defined' do
1945      is_expected.to be_empty
1946    end
1947
1948    context 'when action defined' do
1949      let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
1950
1951      it 'returns one action' do
1952        is_expected.to contain_exactly(manual)
1953      end
1954
1955      context 'there are multiple of the same name' do
1956        let!(:manual2) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy') }
1957
1958        before do
1959          manual.update!(retried: true)
1960        end
1961
1962        it 'returns latest one' do
1963          is_expected.to contain_exactly(manual2)
1964        end
1965      end
1966    end
1967  end
1968
1969  describe '#branch_updated?' do
1970    let(:pipeline) { create(:ci_empty_pipeline, :created) }
1971
1972    context 'when pipeline has before SHA' do
1973      before do
1974        pipeline.update!(before_sha: 'a1b2c3d4')
1975      end
1976
1977      it 'runs on a branch update push' do
1978        expect(pipeline.before_sha).not_to be Gitlab::Git::BLANK_SHA
1979        expect(pipeline.branch_updated?).to be true
1980      end
1981    end
1982
1983    context 'when pipeline does not have before SHA' do
1984      before do
1985        pipeline.update!(before_sha: Gitlab::Git::BLANK_SHA)
1986      end
1987
1988      it 'does not run on a branch updating push' do
1989        expect(pipeline.branch_updated?).to be false
1990      end
1991    end
1992  end
1993
1994  describe '#modified_paths' do
1995    let(:pipeline) { create(:ci_empty_pipeline, :created) }
1996
1997    context 'when old and new revisions are set' do
1998      before do
1999        pipeline.update!(before_sha: '1234abcd', sha: '2345bcde')
2000      end
2001
2002      it 'fetches stats for changes between commits' do
2003        expect(project.repository)
2004          .to receive(:diff_stats).with('1234abcd', '2345bcde')
2005          .and_call_original
2006
2007        pipeline.modified_paths
2008      end
2009    end
2010
2011    context 'when either old or new revision is missing' do
2012      before do
2013        pipeline.update!(before_sha: Gitlab::Git::BLANK_SHA)
2014      end
2015
2016      it 'returns nil' do
2017        expect(pipeline.modified_paths).to be_nil
2018      end
2019    end
2020
2021    context 'when source is merge request' do
2022      let(:pipeline) do
2023        create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request)
2024      end
2025
2026      let(:merge_request) do
2027        create(:merge_request, :simple,
2028               source_project: project,
2029               target_project: project)
2030      end
2031
2032      it 'returns merge request modified paths' do
2033        expect(pipeline.modified_paths).to match(merge_request.modified_paths)
2034      end
2035    end
2036
2037    context 'when source is an external pull request' do
2038      let(:pipeline) do
2039        create(:ci_pipeline, source: :external_pull_request_event, external_pull_request: external_pull_request)
2040      end
2041
2042      let(:external_pull_request) do
2043        create(:external_pull_request, project: project, target_sha: '281d3a7', source_sha: '498214d')
2044      end
2045
2046      it 'returns external pull request modified paths' do
2047        expect(pipeline.modified_paths).to match(external_pull_request.modified_paths)
2048      end
2049    end
2050  end
2051
2052  describe '#all_worktree_paths' do
2053    let(:files) { { 'main.go' => '', 'mocks/mocks.go' => '' } }
2054    let(:project) { create(:project, :custom_repo, files: files) }
2055    let(:pipeline) { build(:ci_pipeline, project: project, sha: project.repository.head_commit.sha) }
2056
2057    it 'returns all file paths cached' do
2058      expect(project.repository).to receive(:ls_files).with(pipeline.sha).once.and_call_original
2059      expect(pipeline.all_worktree_paths).to eq(files.keys)
2060      expect(pipeline.all_worktree_paths).to eq(files.keys)
2061    end
2062  end
2063
2064  describe '#top_level_worktree_paths' do
2065    let(:files) { { 'main.go' => '', 'mocks/mocks.go' => '' } }
2066    let(:project) { create(:project, :custom_repo, files: files) }
2067    let(:pipeline) { build(:ci_pipeline, project: project, sha: project.repository.head_commit.sha) }
2068
2069    it 'returns top-level file paths cached' do
2070      expect(project.repository).to receive(:tree).with(pipeline.sha).once.and_call_original
2071      expect(pipeline.top_level_worktree_paths).to eq(['main.go'])
2072      expect(pipeline.top_level_worktree_paths).to eq(['main.go'])
2073    end
2074  end
2075
2076  describe '#has_kubernetes_active?' do
2077    let(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
2078
2079    context 'when kubernetes is active' do
2080      context 'when user configured kubernetes from CI/CD > Clusters' do
2081        let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
2082        let(:project) { cluster.project }
2083
2084        it 'returns true' do
2085          expect(pipeline).to have_kubernetes_active
2086        end
2087      end
2088    end
2089
2090    context 'when kubernetes is not active' do
2091      it 'returns false' do
2092        expect(pipeline).not_to have_kubernetes_active
2093      end
2094    end
2095  end
2096
2097  describe '#has_warnings?' do
2098    subject { pipeline.has_warnings? }
2099
2100    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2101
2102    context 'build which is allowed to fail fails' do
2103      before do
2104        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
2105        create :ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop'
2106      end
2107
2108      it 'returns true' do
2109        is_expected.to be_truthy
2110      end
2111    end
2112
2113    context 'build which is allowed to fail succeeds' do
2114      before do
2115        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
2116        create :ci_build, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop'
2117      end
2118
2119      it 'returns false' do
2120        is_expected.to be_falsey
2121      end
2122    end
2123
2124    context 'build is retried and succeeds' do
2125      before do
2126        create :ci_build, :success, pipeline: pipeline, name: 'rubocop'
2127        create :ci_build, :failed, pipeline: pipeline, name: 'rspec'
2128        create :ci_build, :success, pipeline: pipeline, name: 'rspec'
2129      end
2130
2131      it 'returns false' do
2132        is_expected.to be_falsey
2133      end
2134    end
2135
2136    context 'bridge which is allowed to fail fails' do
2137      before do
2138        create :ci_bridge, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop'
2139      end
2140
2141      it 'returns true' do
2142        is_expected.to be_truthy
2143      end
2144    end
2145
2146    context 'bridge which is allowed to fail is successful' do
2147      before do
2148        create :ci_bridge, :allowed_to_fail, :success, pipeline: pipeline, name: 'rubocop'
2149      end
2150
2151      it 'returns false' do
2152        is_expected.to be_falsey
2153      end
2154    end
2155  end
2156
2157  describe '#number_of_warnings' do
2158    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2159
2160    it 'returns the number of warnings' do
2161      create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
2162      create(:ci_bridge, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
2163
2164      expect(pipeline.number_of_warnings).to eq(2)
2165    end
2166
2167    it 'supports eager loading of the number of warnings' do
2168      pipeline2 = create(:ci_empty_pipeline, :created)
2169
2170      create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline, name: 'rubocop')
2171      create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline2, name: 'rubocop')
2172
2173      pipelines = project.ci_pipelines.to_a
2174
2175      pipelines.each(&:number_of_warnings)
2176
2177      # To run the queries we need to actually use the lazy objects, which we do
2178      # by just sending "to_i" to them.
2179      amount = ActiveRecord::QueryRecorder
2180        .new { pipelines.each { |p| p.number_of_warnings.to_i } }
2181        .count
2182
2183      expect(amount).to eq(1)
2184    end
2185  end
2186
2187  describe '#needs_processing?' do
2188    using RSpec::Parameterized::TableSyntax
2189
2190    subject { pipeline.needs_processing? }
2191
2192    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2193
2194    where(:processed, :result) do
2195      nil   | true
2196      false | true
2197      true  | false
2198    end
2199
2200    with_them do
2201      let(:build) do
2202        create(:ci_build, :success, pipeline: pipeline, name: 'rubocop')
2203      end
2204
2205      before do
2206        build.update_column(:processed, processed)
2207      end
2208
2209      it { is_expected.to eq(result) }
2210    end
2211  end
2212
2213  context 'with outdated pipelines' do
2214    before_all do
2215      create_pipeline(:canceled, 'ref', 'A')
2216      create_pipeline(:success, 'ref', 'A')
2217      create_pipeline(:failed, 'ref', 'B')
2218      create_pipeline(:skipped, 'feature', 'C')
2219    end
2220
2221    def create_pipeline(status, ref, sha)
2222      create(
2223        :ci_empty_pipeline,
2224        status: status,
2225        ref: ref,
2226        sha: sha
2227      )
2228    end
2229
2230    describe '.newest_first' do
2231      it 'returns the pipelines from new to old' do
2232        expect(described_class.newest_first.pluck(:status))
2233          .to eq(%w[skipped failed success canceled])
2234      end
2235
2236      it 'searches limited backlog' do
2237        expect(described_class.newest_first(limit: 1).pluck(:status))
2238          .to eq(%w[skipped])
2239      end
2240    end
2241
2242    describe '.latest_status' do
2243      context 'when no ref is specified' do
2244        it 'returns the status of the latest pipeline' do
2245          expect(described_class.latest_status).to eq('skipped')
2246        end
2247      end
2248
2249      context 'when ref is specified' do
2250        it 'returns the status of the latest pipeline for the given ref' do
2251          expect(described_class.latest_status('ref')).to eq('failed')
2252        end
2253      end
2254    end
2255
2256    describe '.latest_successful_for_ref' do
2257      let!(:latest_successful_pipeline) do
2258        create_pipeline(:success, 'ref', 'D')
2259      end
2260
2261      it 'returns the latest successful pipeline' do
2262        expect(described_class.latest_successful_for_ref('ref'))
2263          .to eq(latest_successful_pipeline)
2264      end
2265    end
2266
2267    describe '.latest_running_for_ref' do
2268      let!(:latest_running_pipeline) do
2269        create_pipeline(:running, 'ref', 'D')
2270      end
2271
2272      it 'returns the latest running pipeline' do
2273        expect(described_class.latest_running_for_ref('ref'))
2274          .to eq(latest_running_pipeline)
2275      end
2276    end
2277
2278    describe '.latest_failed_for_ref' do
2279      let!(:latest_failed_pipeline) do
2280        create_pipeline(:failed, 'ref', 'D')
2281      end
2282
2283      it 'returns the latest failed pipeline' do
2284        expect(described_class.latest_failed_for_ref('ref'))
2285          .to eq(latest_failed_pipeline)
2286      end
2287    end
2288
2289    describe '.latest_successful_for_sha' do
2290      let!(:latest_successful_pipeline) do
2291        create_pipeline(:success, 'ref', 'awesomesha')
2292      end
2293
2294      it 'returns the latest successful pipeline' do
2295        expect(described_class.latest_successful_for_sha('awesomesha'))
2296          .to eq(latest_successful_pipeline)
2297      end
2298    end
2299
2300    describe '.latest_successful_for_refs' do
2301      subject(:latest_successful_for_refs) { described_class.latest_successful_for_refs(refs) }
2302
2303      context 'when refs are specified' do
2304        let(:refs) { %w(first_ref second_ref third_ref) }
2305
2306        before do
2307          create(:ci_empty_pipeline, id: 1001, status: :success, ref: 'first_ref', sha: 'sha')
2308          create(:ci_empty_pipeline, id: 1002, status: :success, ref: 'second_ref', sha: 'sha')
2309        end
2310
2311        let!(:latest_successful_pipeline_for_first_ref) do
2312          create(:ci_empty_pipeline, id: 2001, status: :success, ref: 'first_ref', sha: 'sha')
2313        end
2314
2315        let!(:latest_successful_pipeline_for_second_ref) do
2316          create(:ci_empty_pipeline, id: 2002, status: :success, ref: 'second_ref', sha: 'sha')
2317        end
2318
2319        it 'returns the latest successful pipeline for both refs' do
2320          expect(latest_successful_for_refs).to eq({
2321            'first_ref' => latest_successful_pipeline_for_first_ref,
2322            'second_ref' => latest_successful_pipeline_for_second_ref
2323          })
2324        end
2325      end
2326
2327      context 'when no refs are specified' do
2328        let(:refs) { [] }
2329
2330        it 'returns an empty relation whenno refs are specified' do
2331          expect(latest_successful_for_refs).to be_empty
2332        end
2333      end
2334    end
2335  end
2336
2337  describe '.latest_pipeline_per_commit' do
2338    let!(:commit_123_ref_master) do
2339      create(
2340        :ci_empty_pipeline,
2341        status: 'success',
2342        ref: 'master',
2343        sha: '123'
2344      )
2345    end
2346
2347    let!(:commit_123_ref_develop) do
2348      create(
2349        :ci_empty_pipeline,
2350        status: 'success',
2351        ref: 'develop',
2352        sha: '123'
2353      )
2354    end
2355
2356    let!(:commit_456_ref_test) do
2357      create(
2358        :ci_empty_pipeline,
2359        status: 'success',
2360        ref: 'test',
2361        sha: '456'
2362      )
2363    end
2364
2365    context 'without a ref' do
2366      it 'returns a Hash containing the latest pipeline per commit for all refs' do
2367        result = described_class.latest_pipeline_per_commit(%w[123 456])
2368
2369        expect(result).to match(
2370          '123' => commit_123_ref_develop,
2371          '456' => commit_456_ref_test
2372        )
2373      end
2374
2375      it 'only includes the latest pipeline of the given commit SHAs' do
2376        result = described_class.latest_pipeline_per_commit(%w[123])
2377
2378        expect(result).to match(
2379          '123' => commit_123_ref_develop
2380        )
2381      end
2382
2383      context 'when there are two pipelines for a ref and SHA' do
2384        let!(:commit_123_ref_master_latest) do
2385          create(
2386            :ci_empty_pipeline,
2387            status: 'failed',
2388            ref: 'master',
2389            sha: '123',
2390            project: project
2391          )
2392        end
2393
2394        it 'returns the latest pipeline' do
2395          result = described_class.latest_pipeline_per_commit(%w[123])
2396
2397          expect(result).to match(
2398            '123' => commit_123_ref_master_latest
2399          )
2400        end
2401      end
2402    end
2403
2404    context 'with a ref' do
2405      it 'only includes the pipelines for the given ref' do
2406        result = described_class.latest_pipeline_per_commit(%w[123 456], 'master')
2407
2408        expect(result).to match(
2409          '123' => commit_123_ref_master
2410        )
2411      end
2412    end
2413
2414    context 'when method is scoped' do
2415      let!(:commit_123_ref_master_parent_pipeline) do
2416        create(
2417          :ci_pipeline,
2418          sha: '123',
2419          ref: 'master',
2420          project: project
2421        )
2422      end
2423
2424      let!(:commit_123_ref_master_child_pipeline) do
2425        create(
2426          :ci_pipeline,
2427          sha: '123',
2428          ref: 'master',
2429          project: project,
2430          child_of: commit_123_ref_master_parent_pipeline
2431        )
2432      end
2433
2434      it 'returns the latest pipeline after applying the scope' do
2435        result = described_class.ci_sources.latest_pipeline_per_commit(%w[123], 'master')
2436
2437        expect(result).to match(
2438          '123' => commit_123_ref_master_parent_pipeline
2439        )
2440      end
2441    end
2442  end
2443
2444  describe '.latest_successful_ids_per_project' do
2445    let(:projects) { create_list(:project, 2) }
2446    let!(:pipeline1) { create(:ci_pipeline, :success, project: projects[0]) }
2447    let!(:pipeline2) { create(:ci_pipeline, :success, project: projects[0]) }
2448    let!(:pipeline3) { create(:ci_pipeline, :failed, project: projects[0]) }
2449    let!(:pipeline4) { create(:ci_pipeline, :success, project: projects[1]) }
2450
2451    it 'returns expected pipeline ids' do
2452      expect(described_class.latest_successful_ids_per_project)
2453        .to contain_exactly(pipeline2, pipeline4)
2454    end
2455  end
2456
2457  describe '.last_finished_for_ref_id' do
2458    let(:branch) { project.default_branch }
2459    let(:ref) { project.ci_refs.take }
2460    let(:dangling_source) { Enums::Ci::Pipeline.sources[:ondemand_dast_scan] }
2461    let!(:pipeline1) { create(:ci_pipeline, :success, project: project, ref: branch) }
2462    let!(:pipeline2) { create(:ci_pipeline, :success, project: project, ref: branch) }
2463    let!(:pipeline3) { create(:ci_pipeline, :failed, project: project, ref: branch) }
2464    let!(:pipeline4) { create(:ci_pipeline, :success, project: project, ref: branch) }
2465    let!(:pipeline5) { create(:ci_pipeline, :success, project: project, ref: branch, source: dangling_source) }
2466
2467    it 'returns the expected pipeline' do
2468      result = described_class.last_finished_for_ref_id(ref.id)
2469      expect(result).to eq(pipeline4)
2470    end
2471  end
2472
2473  describe '.internal_sources' do
2474    subject { described_class.internal_sources }
2475
2476    it { is_expected.to be_an(Array) }
2477  end
2478
2479  describe '.bridgeable_statuses' do
2480    subject { described_class.bridgeable_statuses }
2481
2482    it { is_expected.to be_an(Array) }
2483    it { is_expected.not_to include('created', 'waiting_for_resource', 'preparing', 'pending') }
2484  end
2485
2486  describe '#status', :sidekiq_inline do
2487    subject { pipeline.reload.status }
2488
2489    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2490
2491    let(:build) { create(:ci_build, :created, pipeline: pipeline, name: 'test') }
2492
2493    context 'on waiting for resource' do
2494      before do
2495        allow(build).to receive(:with_resource_group?) { true }
2496        allow(Ci::ResourceGroups::AssignResourceFromResourceGroupWorker).to receive(:perform_async)
2497
2498        build.enqueue
2499      end
2500
2501      it { is_expected.to eq('waiting_for_resource') }
2502    end
2503
2504    context 'on prepare' do
2505      before do
2506        # Prevent skipping directly to 'pending'
2507        allow(build).to receive(:prerequisites).and_return([double])
2508        allow(Ci::BuildPrepareWorker).to receive(:perform_async)
2509
2510        build.enqueue
2511      end
2512
2513      it { is_expected.to eq('preparing') }
2514    end
2515
2516    context 'on queuing' do
2517      before do
2518        build.enqueue
2519      end
2520
2521      it { is_expected.to eq('pending') }
2522    end
2523
2524    context 'on run' do
2525      before do
2526        build.enqueue
2527        build.reload.run
2528      end
2529
2530      it { is_expected.to eq('running') }
2531    end
2532
2533    context 'on drop' do
2534      before do
2535        build.drop
2536      end
2537
2538      it { is_expected.to eq('failed') }
2539    end
2540
2541    context 'on success' do
2542      before do
2543        build.success
2544      end
2545
2546      it { is_expected.to eq('success') }
2547    end
2548
2549    context 'on cancel' do
2550      before do
2551        build.cancel
2552      end
2553
2554      context 'when build is pending' do
2555        let(:build) do
2556          create(:ci_build, :pending, pipeline: pipeline)
2557        end
2558
2559        it { is_expected.to eq('canceled') }
2560      end
2561    end
2562
2563    context 'on failure and build retry' do
2564      before do
2565        stub_not_protect_default_branch
2566
2567        build.drop
2568        project.add_developer(user)
2569
2570        Ci::Build.retry(build, user)
2571      end
2572
2573      # We are changing a state: created > failed > running
2574      # Instead of: created > failed > pending
2575      # Since the pipeline already run, so it should not be pending anymore
2576
2577      it { is_expected.to eq('running') }
2578    end
2579  end
2580
2581  describe '#detailed_status' do
2582    subject { pipeline.detailed_status(user) }
2583
2584    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2585
2586    context 'when pipeline is created' do
2587      let(:pipeline) { create(:ci_pipeline, :created) }
2588
2589      it 'returns detailed status for created pipeline' do
2590        expect(subject.text).to eq s_('CiStatusText|created')
2591      end
2592    end
2593
2594    context 'when pipeline is pending' do
2595      let(:pipeline) { create(:ci_pipeline, status: :pending) }
2596
2597      it 'returns detailed status for pending pipeline' do
2598        expect(subject.text).to eq s_('CiStatusText|pending')
2599      end
2600    end
2601
2602    context 'when pipeline is running' do
2603      let(:pipeline) { create(:ci_pipeline, status: :running) }
2604
2605      it 'returns detailed status for running pipeline' do
2606        expect(subject.text).to eq s_('CiStatus|running')
2607      end
2608    end
2609
2610    context 'when pipeline is successful' do
2611      let(:pipeline) { create(:ci_pipeline, status: :success) }
2612
2613      it 'returns detailed status for successful pipeline' do
2614        expect(subject.text).to eq s_('CiStatusText|passed')
2615      end
2616    end
2617
2618    context 'when pipeline is failed' do
2619      let(:pipeline) { create(:ci_pipeline, status: :failed) }
2620
2621      it 'returns detailed status for failed pipeline' do
2622        expect(subject.text).to eq s_('CiStatusText|failed')
2623      end
2624    end
2625
2626    context 'when pipeline is canceled' do
2627      let(:pipeline) { create(:ci_pipeline, status: :canceled) }
2628
2629      it 'returns detailed status for canceled pipeline' do
2630        expect(subject.text).to eq s_('CiStatusText|canceled')
2631      end
2632    end
2633
2634    context 'when pipeline is skipped' do
2635      let(:pipeline) { create(:ci_pipeline, status: :skipped) }
2636
2637      it 'returns detailed status for skipped pipeline' do
2638        expect(subject.text).to eq s_('CiStatusText|skipped')
2639      end
2640    end
2641
2642    context 'when pipeline is blocked' do
2643      let(:pipeline) { create(:ci_pipeline, status: :manual) }
2644
2645      it 'returns detailed status for blocked pipeline' do
2646        expect(subject.text).to eq s_('CiStatusText|blocked')
2647      end
2648    end
2649
2650    context 'when pipeline is successful but with warnings' do
2651      let(:pipeline) { create(:ci_pipeline, status: :success) }
2652
2653      before do
2654        create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline)
2655      end
2656
2657      it 'retruns detailed status for successful pipeline with warnings' do
2658        expect(subject.label).to eq(s_('CiStatusLabel|passed with warnings'))
2659      end
2660    end
2661  end
2662
2663  describe '#cancelable?' do
2664    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2665
2666    %i[created running pending].each do |status0|
2667      context "when there is a build #{status0}" do
2668        before do
2669          create(:ci_build, status0, pipeline: pipeline)
2670        end
2671
2672        it 'is cancelable' do
2673          expect(pipeline.cancelable?).to be_truthy
2674        end
2675      end
2676
2677      context "when there is an external job #{status0}" do
2678        before do
2679          create(:generic_commit_status, status0, pipeline: pipeline)
2680        end
2681
2682        it 'is cancelable' do
2683          expect(pipeline.cancelable?).to be_truthy
2684        end
2685      end
2686
2687      %i[success failed canceled].each do |status1|
2688        context "when there are generic_commit_status jobs for #{status0} and #{status1}" do
2689          before do
2690            create(:generic_commit_status, status0, pipeline: pipeline)
2691            create(:generic_commit_status, status1, pipeline: pipeline)
2692          end
2693
2694          it 'is cancelable' do
2695            expect(pipeline.cancelable?).to be_truthy
2696          end
2697        end
2698
2699        context "when there are generic_commit_status and ci_build jobs for #{status0} and #{status1}" do
2700          before do
2701            create(:generic_commit_status, status0, pipeline: pipeline)
2702            create(:ci_build, status1, pipeline: pipeline)
2703          end
2704
2705          it 'is cancelable' do
2706            expect(pipeline.cancelable?).to be_truthy
2707          end
2708        end
2709
2710        context "when there are ci_build jobs for #{status0} and #{status1}" do
2711          before do
2712            create(:ci_build, status0, pipeline: pipeline)
2713            create(:ci_build, status1, pipeline: pipeline)
2714          end
2715
2716          it 'is cancelable' do
2717            expect(pipeline.cancelable?).to be_truthy
2718          end
2719        end
2720      end
2721    end
2722
2723    %i[success failed canceled].each do |status|
2724      context "when there is a build #{status}" do
2725        before do
2726          create(:ci_build, status, pipeline: pipeline)
2727        end
2728
2729        it 'is not cancelable' do
2730          expect(pipeline.cancelable?).to be_falsey
2731        end
2732      end
2733
2734      context "when there is an external job #{status}" do
2735        before do
2736          create(:generic_commit_status, status, pipeline: pipeline)
2737        end
2738
2739        it 'is not cancelable' do
2740          expect(pipeline.cancelable?).to be_falsey
2741        end
2742      end
2743    end
2744
2745    context 'when there is a manual action present in the pipeline' do
2746      before do
2747        create(:ci_build, :manual, pipeline: pipeline)
2748      end
2749
2750      it 'is not cancelable' do
2751        expect(pipeline).not_to be_cancelable
2752      end
2753    end
2754  end
2755
2756  describe '#cancel_running' do
2757    subject(:latest_status) { pipeline.statuses.pluck(:status) }
2758
2759    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2760
2761    context 'when there is a running external job and a regular job' do
2762      before do
2763        create(:ci_build, :running, pipeline: pipeline)
2764        create(:generic_commit_status, :running, pipeline: pipeline)
2765
2766        pipeline.cancel_running
2767      end
2768
2769      it 'cancels both jobs' do
2770        expect(latest_status).to contain_exactly('canceled', 'canceled')
2771      end
2772    end
2773
2774    context 'when jobs are in different stages' do
2775      before do
2776        create(:ci_build, :running, stage_idx: 0, pipeline: pipeline)
2777        create(:ci_build, :running, stage_idx: 1, pipeline: pipeline)
2778
2779        pipeline.cancel_running
2780      end
2781
2782      it 'cancels both jobs' do
2783        expect(latest_status).to contain_exactly('canceled', 'canceled')
2784      end
2785    end
2786
2787    context 'when there are created builds present in the pipeline' do
2788      before do
2789        create(:ci_build, :running, stage_idx: 0, pipeline: pipeline)
2790        create(:ci_build, :created, stage_idx: 1, pipeline: pipeline)
2791
2792        pipeline.cancel_running
2793      end
2794
2795      it 'cancels created builds' do
2796        expect(latest_status).to eq %w(canceled canceled)
2797      end
2798    end
2799
2800    context 'preloading relations' do
2801      let(:pipeline1) { create(:ci_empty_pipeline, :created) }
2802      let(:pipeline2) { create(:ci_empty_pipeline, :created) }
2803
2804      before do
2805        create(:ci_build, :pending, pipeline: pipeline1)
2806        create(:generic_commit_status, :pending, pipeline: pipeline1)
2807
2808        create(:ci_build, :pending, pipeline: pipeline2)
2809        create(:ci_build, :pending, pipeline: pipeline2)
2810        create(:generic_commit_status, :pending, pipeline: pipeline2)
2811        create(:generic_commit_status, :pending, pipeline: pipeline2)
2812        create(:generic_commit_status, :pending, pipeline: pipeline2)
2813      end
2814
2815      it 'preloads relations for each build to avoid N+1 queries' do
2816        control1 = ActiveRecord::QueryRecorder.new do
2817          pipeline1.cancel_running
2818        end
2819
2820        control2 = ActiveRecord::QueryRecorder.new do
2821          pipeline2.cancel_running
2822        end
2823
2824        extra_update_queries = 4 # transition ... => :canceled, queue pop
2825        extra_generic_commit_status_validation_queries = 2 # name_uniqueness_across_types
2826
2827        expect(control2.count).to eq(control1.count + extra_update_queries + extra_generic_commit_status_validation_queries)
2828      end
2829    end
2830
2831    context 'when the first try cannot get an exclusive lock' do
2832      let(:retries) { 1 }
2833
2834      subject(:cancel_running) { pipeline.cancel_running(retries: retries) }
2835
2836      before do
2837        build = create(:ci_build, :running, pipeline: pipeline)
2838
2839        allow(pipeline.cancelable_statuses).to receive(:find_in_batches).and_yield([build])
2840
2841        call_count = 0
2842        allow(build).to receive(:cancel).and_wrap_original do |original, *args|
2843          call_count >= retries ? raise(ActiveRecord::StaleObjectError) : original.call(*args)
2844
2845          call_count += 1
2846        end
2847      end
2848
2849      it 'retries again and cancels the build' do
2850        cancel_running
2851
2852        expect(latest_status).to contain_exactly('canceled')
2853      end
2854
2855      context 'when the retries parameter is 0' do
2856        let(:retries) { 0 }
2857
2858        it 'raises error' do
2859          expect do
2860            cancel_running
2861          end.to raise_error(ActiveRecord::StaleObjectError)
2862        end
2863      end
2864    end
2865  end
2866
2867  describe '#retry_failed' do
2868    subject(:latest_status) { pipeline.latest_statuses.pluck(:status) }
2869
2870    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2871
2872    before do
2873      stub_not_protect_default_branch
2874
2875      project.add_developer(user)
2876    end
2877
2878    context 'when there is a failed build and failed external status' do
2879      before do
2880        create(:ci_build, :failed, name: 'build', pipeline: pipeline)
2881        create(:generic_commit_status, :failed, name: 'jenkins', pipeline: pipeline)
2882
2883        pipeline.retry_failed(user)
2884      end
2885
2886      it 'retries only build' do
2887        expect(latest_status).to contain_exactly('pending', 'failed')
2888      end
2889    end
2890
2891    context 'when builds are in different stages' do
2892      before do
2893        create(:ci_build, :failed, name: 'build', stage_idx: 0, pipeline: pipeline)
2894        create(:ci_build, :failed, name: 'jenkins', stage_idx: 1, pipeline: pipeline)
2895
2896        pipeline.retry_failed(user)
2897      end
2898
2899      it 'retries both builds' do
2900        expect(latest_status).to contain_exactly('pending', 'created')
2901      end
2902    end
2903
2904    context 'when there are canceled and failed' do
2905      before do
2906        create(:ci_build, :failed, name: 'build', stage_idx: 0, pipeline: pipeline)
2907        create(:ci_build, :canceled, name: 'jenkins', stage_idx: 1, pipeline: pipeline)
2908
2909        pipeline.retry_failed(user)
2910      end
2911
2912      it 'retries both builds' do
2913        expect(latest_status).to contain_exactly('pending', 'created')
2914      end
2915    end
2916  end
2917
2918  describe 'hooks trigerring' do
2919    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
2920
2921    %i[
2922      enqueue
2923      request_resource
2924      prepare
2925      run
2926      skip
2927      drop
2928      succeed
2929      cancel
2930      block
2931      delay
2932    ].each do |action|
2933      context "when pipeline action is #{action}" do
2934        let(:pipeline_action) { action }
2935
2936        it 'schedules a new PipelineHooksWorker job' do
2937          expect(PipelineHooksWorker).to receive(:perform_async).with(pipeline.id)
2938
2939          pipeline.reload.public_send(pipeline_action)
2940        end
2941      end
2942    end
2943  end
2944
2945  describe "#merge_requests_as_head_pipeline" do
2946    let_it_be_with_reload(:pipeline) { create(:ci_empty_pipeline, status: 'created', ref: 'master', sha: 'a288a022a53a5a944fae87bcec6efc87b7061808') }
2947
2948    it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
2949      allow_next_instance_of(MergeRequest) do |instance|
2950        allow(instance).to receive(:diff_head_sha) { 'a288a022a53a5a944fae87bcec6efc87b7061808' }
2951      end
2952      merge_request = create(:merge_request, source_project: project, head_pipeline: pipeline, source_branch: pipeline.ref)
2953
2954      expect(pipeline.merge_requests_as_head_pipeline).to eq([merge_request])
2955    end
2956
2957    it "doesn't return merge requests whose source branch doesn't match the pipeline's ref" do
2958      create(:merge_request, :simple, source_project: project)
2959
2960      expect(pipeline.merge_requests_as_head_pipeline).to be_empty
2961    end
2962
2963    it "doesn't return merge requests whose `diff_head_sha` doesn't match the pipeline's SHA" do
2964      create(:merge_request, source_project: project, source_branch: pipeline.ref)
2965      allow_next_instance_of(MergeRequest) do |instance|
2966        allow(instance).to receive(:diff_head_sha) { '97de212e80737a608d939f648d959671fb0a0142b' }
2967      end
2968
2969      expect(pipeline.merge_requests_as_head_pipeline).to be_empty
2970    end
2971  end
2972
2973  describe '#all_merge_requests' do
2974    let_it_be_with_reload(:project) { create(:project) }
2975    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created, project: project) }
2976
2977    shared_examples 'a method that returns all merge requests for a given pipeline' do
2978      let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: pipeline_project, ref: 'master') }
2979
2980      it 'returns all merge requests having the same source branch and the pipeline sha' do
2981        merge_request = create(:merge_request, source_project: pipeline_project, target_project: project, source_branch: pipeline.ref)
2982
2983        create(:merge_request_diff, merge_request: merge_request).tap do |diff|
2984          create(:merge_request_diff_commit, merge_request_diff: diff, sha: pipeline.sha)
2985        end
2986
2987        expect(pipeline.all_merge_requests).to eq([merge_request])
2988      end
2989
2990      it "doesn't return merge requests having the same source branch without the pipeline sha" do
2991        merge_request = create(:merge_request, source_project: pipeline_project, target_project: project, source_branch: pipeline.ref)
2992        create(:merge_request_diff, merge_request: merge_request).tap do |diff|
2993          create(:merge_request_diff_commit, merge_request_diff: diff, sha: 'unrelated')
2994        end
2995
2996        expect(pipeline.all_merge_requests).to be_empty
2997      end
2998
2999      it "doesn't return merge requests having a different source branch" do
3000        create(:merge_request, source_project: pipeline_project, target_project: project, source_branch: 'feature', target_branch: 'master')
3001
3002        expect(pipeline.all_merge_requests).to be_empty
3003      end
3004
3005      context 'when there is a merge request pipeline' do
3006        let(:source_branch) { 'feature' }
3007        let(:target_branch) { 'master' }
3008
3009        let!(:pipeline) do
3010          create(:ci_pipeline,
3011                 source: :merge_request_event,
3012                 project: pipeline_project,
3013                 ref: source_branch,
3014                 merge_request: merge_request)
3015        end
3016
3017        let(:merge_request) do
3018          create(:merge_request,
3019                 source_project: pipeline_project,
3020                 source_branch: source_branch,
3021                 target_project: project,
3022                 target_branch: target_branch)
3023        end
3024
3025        it 'returns an associated merge request' do
3026          expect(pipeline.all_merge_requests).to eq([merge_request])
3027        end
3028
3029        context 'when there is another merge request pipeline that targets a different branch' do
3030          let(:target_branch_2) { 'merge-test' }
3031
3032          let!(:pipeline_2) do
3033            create(:ci_pipeline,
3034                   source: :merge_request_event,
3035                   project: pipeline_project,
3036                   ref: source_branch,
3037                   merge_request: merge_request_2)
3038          end
3039
3040          let(:merge_request_2) do
3041            create(:merge_request,
3042                   source_project: pipeline_project,
3043                   source_branch: source_branch,
3044                   target_project: project,
3045                   target_branch: target_branch_2)
3046          end
3047
3048          it 'does not return an associated merge request' do
3049            expect(pipeline.all_merge_requests).not_to include(merge_request_2)
3050          end
3051        end
3052      end
3053    end
3054
3055    it_behaves_like 'a method that returns all merge requests for a given pipeline' do
3056      let(:pipeline_project) { project }
3057    end
3058
3059    context 'for a fork' do
3060      let(:fork) { fork_project(project) }
3061
3062      it_behaves_like 'a method that returns all merge requests for a given pipeline' do
3063        let(:pipeline_project) { fork }
3064      end
3065    end
3066  end
3067
3068  describe '#related_merge_requests' do
3069    let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
3070    let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'stable') }
3071    let(:branch_pipeline) { create(:ci_pipeline, ref: 'feature') }
3072    let(:merge_pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline, merge_request: merge_request) }
3073
3074    context 'for a branch pipeline' do
3075      subject { branch_pipeline.related_merge_requests }
3076
3077      it 'when no merge request is created' do
3078        is_expected.to be_empty
3079      end
3080
3081      it 'when another merge requests are created' do
3082        merge_request
3083        other_merge_request
3084
3085        is_expected.to contain_exactly(merge_request, other_merge_request)
3086      end
3087    end
3088
3089    context 'for a merge pipeline' do
3090      subject { merge_pipeline.related_merge_requests }
3091
3092      it 'when only merge pipeline is created' do
3093        merge_pipeline
3094
3095        is_expected.to contain_exactly(merge_request)
3096      end
3097
3098      it 'when a merge request is created' do
3099        merge_pipeline
3100        other_merge_request
3101
3102        is_expected.to contain_exactly(merge_request, other_merge_request)
3103      end
3104    end
3105  end
3106
3107  describe '#open_merge_requests_refs' do
3108    let!(:pipeline) { create(:ci_pipeline, user: user, ref: 'feature') }
3109    let!(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
3110
3111    subject { pipeline.open_merge_requests_refs }
3112
3113    context 'when user is a developer' do
3114      before do
3115        project.add_developer(user)
3116      end
3117
3118      it 'returns open merge requests' do
3119        is_expected.to eq([merge_request.to_reference(full: true)])
3120      end
3121
3122      it 'does not return closed merge requests' do
3123        merge_request.close!
3124
3125        is_expected.to be_empty
3126      end
3127
3128      context 'limits amount of returned merge requests' do
3129        let!(:other_merge_requests) do
3130          Array.new(4) do |idx|
3131            create(:merge_request, source_project: project, source_branch: 'feature', target_branch: "master-#{idx}")
3132          end
3133        end
3134
3135        let(:other_merge_requests_refs) do
3136          other_merge_requests.map { |mr| mr.to_reference(full: true) }
3137        end
3138
3139        it 'returns only last 4 in a reverse order' do
3140          is_expected.to eq(other_merge_requests_refs.reverse)
3141        end
3142      end
3143    end
3144
3145    context 'when user does not have permissions' do
3146      it 'does not return any merge requests' do
3147        is_expected.to be_empty
3148      end
3149    end
3150  end
3151
3152  describe '#same_family_pipeline_ids' do
3153    subject { pipeline.same_family_pipeline_ids.map(&:id) }
3154
3155    let_it_be(:pipeline) { create(:ci_empty_pipeline, :created) }
3156
3157    context 'when pipeline is not child nor parent' do
3158      it 'returns just the pipeline id' do
3159        expect(subject).to contain_exactly(pipeline.id)
3160      end
3161    end
3162
3163    context 'when pipeline is child' do
3164      let(:parent) { create(:ci_pipeline) }
3165      let!(:pipeline) { create(:ci_pipeline, child_of: parent) }
3166      let!(:sibling) { create(:ci_pipeline, child_of: parent) }
3167
3168      it 'returns parent sibling and self ids' do
3169        expect(subject).to contain_exactly(parent.id, pipeline.id, sibling.id)
3170      end
3171    end
3172
3173    context 'when pipeline is parent' do
3174      let!(:child) { create(:ci_pipeline, child_of: pipeline) }
3175
3176      it 'returns self and child ids' do
3177        expect(subject).to contain_exactly(pipeline.id, child.id)
3178      end
3179    end
3180
3181    context 'when pipeline is a child of a child pipeline' do
3182      let(:ancestor) { create(:ci_pipeline) }
3183      let!(:parent) { create(:ci_pipeline, child_of: ancestor) }
3184      let!(:pipeline) { create(:ci_pipeline, child_of: parent) }
3185      let!(:cousin_parent) { create(:ci_pipeline, child_of: ancestor) }
3186      let!(:cousin) { create(:ci_pipeline, child_of: cousin_parent) }
3187
3188      it 'returns all family ids' do
3189        expect(subject).to contain_exactly(
3190          ancestor.id, parent.id, cousin_parent.id, cousin.id, pipeline.id
3191        )
3192      end
3193    end
3194
3195    context 'when pipeline is a triggered pipeline' do
3196      let!(:upstream) { create(:ci_pipeline, project: create(:project), upstream_of: pipeline)}
3197
3198      it 'returns self id' do
3199        expect(subject).to contain_exactly(pipeline.id)
3200      end
3201    end
3202  end
3203
3204  describe '#environments_in_self_and_descendants' do
3205    subject { pipeline.environments_in_self_and_descendants }
3206
3207    context 'when pipeline is not child nor parent' do
3208      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
3209      let_it_be(:build, refind: true) { create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline) }
3210
3211      it 'returns just the pipeline environment' do
3212        expect(subject).to contain_exactly(build.deployment.environment)
3213      end
3214
3215      context 'when deployment SHA is not matched' do
3216        before do
3217          build.deployment.update!(sha: 'old-sha')
3218        end
3219
3220        it 'does not return environments' do
3221          expect(subject).to be_empty
3222        end
3223      end
3224    end
3225
3226    context 'when an associated environment does not have deployments' do
3227      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
3228      let_it_be(:build) { create(:ci_build, :stop_review_app, pipeline: pipeline) }
3229      let_it_be(:environment) { create(:environment, project: pipeline.project) }
3230
3231      before_all do
3232        build.metadata.update!(expanded_environment_name: environment.name)
3233      end
3234
3235      it 'does not return environments' do
3236        expect(subject).to be_empty
3237      end
3238    end
3239
3240    context 'when pipeline is in extended family' do
3241      let_it_be(:parent) { create(:ci_pipeline) }
3242      let_it_be(:parent_build) { create(:ci_build, :with_deployment, environment: 'staging', pipeline: parent) }
3243
3244      let_it_be(:pipeline) { create(:ci_pipeline, child_of: parent) }
3245      let_it_be(:build) { create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline) }
3246
3247      let_it_be(:child) { create(:ci_pipeline, child_of: pipeline) }
3248      let_it_be(:child_build) { create(:ci_build, :with_deployment, environment: 'canary', pipeline: child) }
3249
3250      let_it_be(:grandchild) { create(:ci_pipeline, child_of: child) }
3251      let_it_be(:grandchild_build) { create(:ci_build, :with_deployment, environment: 'test', pipeline: grandchild) }
3252
3253      let_it_be(:sibling) { create(:ci_pipeline, child_of: parent) }
3254      let_it_be(:sibling_build) { create(:ci_build, :with_deployment, environment: 'review', pipeline: sibling) }
3255
3256      it 'returns its own environment and from all descendants' do
3257        expected_environments = [
3258          build.deployment.environment,
3259          child_build.deployment.environment,
3260          grandchild_build.deployment.environment
3261        ]
3262        expect(subject).to match_array(expected_environments)
3263      end
3264
3265      it 'does not return parent environment' do
3266        expect(subject).not_to include(parent_build.deployment.environment)
3267      end
3268
3269      it 'does not return sibling environment' do
3270        expect(subject).not_to include(sibling_build.deployment.environment)
3271      end
3272    end
3273
3274    context 'when each pipeline has multiple environments' do
3275      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
3276      let_it_be(:build1) { create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline) }
3277      let_it_be(:build2) { create(:ci_build, :with_deployment, environment: 'staging', pipeline: pipeline) }
3278
3279      let_it_be(:child) { create(:ci_pipeline, child_of: pipeline) }
3280      let_it_be(:child_build1) { create(:ci_build, :with_deployment, environment: 'canary', pipeline: child) }
3281      let_it_be(:child_build2) { create(:ci_build, :with_deployment, environment: 'test', pipeline: child) }
3282
3283      it 'returns all related environments' do
3284        expected_environments = [
3285          build1.deployment.environment,
3286          build2.deployment.environment,
3287          child_build1.deployment.environment,
3288          child_build2.deployment.environment
3289        ]
3290        expect(subject).to match_array(expected_environments)
3291      end
3292    end
3293
3294    context 'when pipeline has no environment' do
3295      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
3296
3297      it 'returns empty' do
3298        expect(subject).to be_empty
3299      end
3300    end
3301  end
3302
3303  describe '#root_ancestor' do
3304    subject { pipeline.root_ancestor }
3305
3306    let_it_be(:pipeline) { create(:ci_pipeline) }
3307
3308    context 'when pipeline is child of child pipeline' do
3309      let!(:root_ancestor) { create(:ci_pipeline) }
3310      let!(:parent_pipeline) { create(:ci_pipeline, child_of: root_ancestor) }
3311      let!(:pipeline) { create(:ci_pipeline, child_of: parent_pipeline) }
3312
3313      it 'returns the root ancestor' do
3314        expect(subject).to eq(root_ancestor)
3315      end
3316    end
3317
3318    context 'when pipeline is root ancestor' do
3319      let!(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
3320
3321      it 'returns itself' do
3322        expect(subject).to eq(pipeline)
3323      end
3324    end
3325
3326    context 'when pipeline is standalone' do
3327      it 'returns itself' do
3328        expect(subject).to eq(pipeline)
3329      end
3330    end
3331
3332    context 'when pipeline is multi-project downstream pipeline' do
3333      let!(:upstream_pipeline) do
3334        create(:ci_pipeline, project: create(:project), upstream_of: pipeline)
3335      end
3336
3337      it 'ignores cross project ancestors' do
3338        expect(subject).to eq(pipeline)
3339      end
3340    end
3341  end
3342
3343  describe '#stuck?' do
3344    let(:pipeline) { create(:ci_empty_pipeline, :created) }
3345
3346    before do
3347      create(:ci_build, :pending, pipeline: pipeline)
3348    end
3349
3350    context 'when pipeline is stuck' do
3351      it 'is stuck' do
3352        expect(pipeline).to be_stuck
3353      end
3354    end
3355
3356    context 'when pipeline is not stuck' do
3357      before do
3358        create(:ci_runner, :instance, :online)
3359      end
3360
3361      it 'is not stuck' do
3362        expect(pipeline).not_to be_stuck
3363      end
3364    end
3365  end
3366
3367  describe '#add_error_message' do
3368    let(:pipeline) { build_stubbed(:ci_pipeline) }
3369
3370    it 'adds a new pipeline error message' do
3371      pipeline.add_error_message('The error message')
3372
3373      expect(pipeline.messages.map(&:content)).to contain_exactly('The error message')
3374    end
3375  end
3376
3377  describe '#has_yaml_errors?' do
3378    let(:pipeline) { build_stubbed(:ci_pipeline) }
3379
3380    context 'when yaml_errors is set' do
3381      before do
3382        pipeline.yaml_errors = 'File not found'
3383      end
3384
3385      it 'returns true if yaml_errors is set' do
3386        expect(pipeline).to have_yaml_errors
3387        expect(pipeline.yaml_errors).to include('File not foun')
3388      end
3389    end
3390
3391    it 'returns false if yaml_errors is not set' do
3392      expect(pipeline).not_to have_yaml_errors
3393    end
3394  end
3395
3396  describe 'notifications when pipeline success or failed' do
3397    let(:namespace) { create(:namespace) }
3398    let(:project) { create(:project, :repository, namespace: namespace) }
3399
3400    let(:pipeline) do
3401      create(:ci_pipeline,
3402             project: project,
3403             sha: project.commit('master').sha,
3404             user: project.owner)
3405    end
3406
3407    before do
3408      project.add_developer(pipeline.user)
3409
3410      pipeline.user.global_notification_setting
3411        .update!(level: 'custom', failed_pipeline: true, success_pipeline: true)
3412
3413      perform_enqueued_jobs do
3414        pipeline.enqueue
3415        pipeline.run
3416      end
3417    end
3418
3419    shared_examples 'sending a notification' do
3420      it 'sends an email', :sidekiq_might_not_need_inline do
3421        should_only_email(pipeline.user)
3422      end
3423    end
3424
3425    shared_examples 'not sending any notification' do
3426      it 'does not send any email' do
3427        should_not_email_anyone
3428      end
3429    end
3430
3431    context 'with success pipeline' do
3432      it_behaves_like 'sending a notification' do
3433        before do
3434          perform_enqueued_jobs do
3435            pipeline.succeed
3436          end
3437        end
3438      end
3439
3440      it 'enqueues PipelineNotificationWorker' do
3441        expect(PipelineNotificationWorker)
3442          .to receive(:perform_async).with(pipeline.id, ref_status: :success)
3443
3444        pipeline.succeed
3445      end
3446
3447      context 'when pipeline is not the latest' do
3448        before do
3449          create(:ci_pipeline, :success, ci_ref: pipeline.ci_ref)
3450        end
3451
3452        it 'does not pass ref_status' do
3453          expect(PipelineNotificationWorker)
3454            .to receive(:perform_async).with(pipeline.id, ref_status: nil)
3455
3456          pipeline.succeed!
3457        end
3458      end
3459    end
3460
3461    context 'with failed pipeline' do
3462      it_behaves_like 'sending a notification' do
3463        before do
3464          perform_enqueued_jobs do
3465            create(:ci_build, :failed, pipeline: pipeline)
3466            create(:generic_commit_status, :failed, pipeline: pipeline)
3467
3468            pipeline.drop
3469          end
3470        end
3471      end
3472
3473      it 'enqueues PipelineNotificationWorker' do
3474        expect(PipelineNotificationWorker)
3475          .to receive(:perform_async).with(pipeline.id, ref_status: :failed)
3476
3477        pipeline.drop
3478      end
3479    end
3480
3481    context 'with skipped pipeline' do
3482      before do
3483        perform_enqueued_jobs do
3484          pipeline.skip
3485        end
3486      end
3487
3488      it_behaves_like 'not sending any notification'
3489    end
3490
3491    context 'with cancelled pipeline' do
3492      before do
3493        perform_enqueued_jobs do
3494          pipeline.cancel
3495        end
3496      end
3497
3498      it_behaves_like 'not sending any notification'
3499    end
3500  end
3501
3502  describe 'updates ci_ref when pipeline finished' do
3503    context 'when ci_ref exists' do
3504      let!(:pipeline) { create(:ci_pipeline, :running) }
3505
3506      it 'updates the ci_ref' do
3507        expect(pipeline.ci_ref)
3508          .to receive(:update_status_by!).with(pipeline).and_call_original
3509
3510        pipeline.succeed!
3511      end
3512    end
3513
3514    context 'when ci_ref does not exist' do
3515      let!(:pipeline) { create(:ci_pipeline, :running, ci_ref_presence: false) }
3516
3517      it 'does not raise an exception' do
3518        expect { pipeline.succeed! }.not_to raise_error
3519      end
3520    end
3521  end
3522
3523  describe '#ensure_ci_ref!' do
3524    subject { pipeline.ensure_ci_ref! }
3525
3526    context 'when ci_ref does not exist yet' do
3527      let!(:pipeline) { create(:ci_pipeline, ci_ref_presence: false) }
3528
3529      it 'creates a new ci_ref and assigns it' do
3530        expect { subject }.to change { Ci::Ref.count }.by(1)
3531
3532        expect(pipeline.ci_ref).to be_present
3533      end
3534    end
3535
3536    context 'when ci_ref already exists' do
3537      let!(:pipeline) { create(:ci_pipeline) }
3538
3539      it 'fetches a new ci_ref and assigns it' do
3540        expect { subject }.not_to change { Ci::Ref.count }
3541
3542        expect(pipeline.ci_ref).to be_present
3543      end
3544    end
3545  end
3546
3547  describe '#builds_in_self_and_descendants' do
3548    subject(:builds) { pipeline.builds_in_self_and_descendants }
3549
3550    let(:pipeline) { create(:ci_pipeline) }
3551    let!(:build) { create(:ci_build, pipeline: pipeline) }
3552
3553    context 'when pipeline is standalone' do
3554      it 'returns the list of builds' do
3555        expect(builds).to contain_exactly(build)
3556      end
3557    end
3558
3559    context 'when pipeline is parent of another pipeline' do
3560      let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
3561      let!(:child_build) { create(:ci_build, pipeline: child_pipeline) }
3562
3563      it 'returns the list of builds' do
3564        expect(builds).to contain_exactly(build, child_build)
3565      end
3566    end
3567
3568    context 'when pipeline is parent of another parent pipeline' do
3569      let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
3570      let!(:child_build) { create(:ci_build, pipeline: child_pipeline) }
3571      let(:child_of_child_pipeline) { create(:ci_pipeline, child_of: child_pipeline) }
3572      let!(:child_of_child_build) { create(:ci_build, pipeline: child_of_child_pipeline) }
3573
3574      it 'returns the list of builds' do
3575        expect(builds).to contain_exactly(build, child_build, child_of_child_build)
3576      end
3577    end
3578  end
3579
3580  describe '#build_with_artifacts_in_self_and_descendants' do
3581    let_it_be(:pipeline) { create(:ci_pipeline) }
3582
3583    let!(:build) { create(:ci_build, name: 'test', pipeline: pipeline) }
3584    let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
3585    let!(:child_build) { create(:ci_build, :artifacts, name: 'test', pipeline: child_pipeline) }
3586
3587    it 'returns the build with a given name, having artifacts' do
3588      expect(pipeline.build_with_artifacts_in_self_and_descendants('test')).to eq(child_build)
3589    end
3590
3591    context 'when same job name is present in both parent and child pipeline' do
3592      let!(:build) { create(:ci_build, :artifacts, name: 'test', pipeline: pipeline) }
3593
3594      it 'returns the job in the parent pipeline' do
3595        expect(pipeline.build_with_artifacts_in_self_and_descendants('test')).to eq(build)
3596      end
3597    end
3598  end
3599
3600  describe '#find_job_with_archive_artifacts' do
3601    let(:pipeline) { create(:ci_pipeline) }
3602    let!(:old_job) { create(:ci_build, name: 'rspec', retried: true, pipeline: pipeline) }
3603    let!(:job_without_artifacts) { create(:ci_build, name: 'rspec', pipeline: pipeline) }
3604    let!(:expected_job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: pipeline ) }
3605    let!(:different_job) { create(:ci_build, name: 'deploy', pipeline: pipeline) }
3606
3607    subject { pipeline.find_job_with_archive_artifacts('rspec') }
3608
3609    it 'finds the expected job' do
3610      expect(subject).to eq(expected_job)
3611    end
3612  end
3613
3614  describe '#latest_builds_with_artifacts' do
3615    let(:pipeline) { create(:ci_pipeline) }
3616    let!(:fresh_build) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
3617    let!(:stale_build) { create(:ci_build, :success, :expired, :artifacts, pipeline: pipeline) }
3618
3619    it 'returns an Array' do
3620      expect(pipeline.latest_builds_with_artifacts).to be_an_instance_of(Array)
3621    end
3622
3623    it 'returns the latest builds with non-expired artifacts' do
3624      expect(pipeline.latest_builds_with_artifacts).to contain_exactly(fresh_build)
3625    end
3626
3627    it 'does not return builds with expired artifacts' do
3628      expect(pipeline.latest_builds_with_artifacts).not_to include(stale_build)
3629    end
3630
3631    it 'memoizes the returned relation' do
3632      query_count = ActiveRecord::QueryRecorder
3633        .new { 2.times { pipeline.latest_builds_with_artifacts.to_a } }
3634        .count
3635
3636      expect(query_count).to eq(1)
3637    end
3638  end
3639
3640  describe '#batch_lookup_report_artifact_for_file_type' do
3641    context 'with code quality report artifact' do
3642      let(:pipeline) { create(:ci_pipeline, :with_codequality_reports) }
3643
3644      it "returns the code quality artifact" do
3645        expect(pipeline.batch_lookup_report_artifact_for_file_type(:codequality)).to eq(pipeline.job_artifacts.sample)
3646      end
3647    end
3648  end
3649
3650  describe '#latest_report_builds' do
3651    let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
3652
3653    it 'returns build with test artifacts' do
3654      test_build = create(:ci_build, :test_reports, pipeline: pipeline)
3655      coverage_build = create(:ci_build, :coverage_reports, pipeline: pipeline)
3656      create(:ci_build, :artifacts, pipeline: pipeline, project: project)
3657
3658      expect(pipeline.latest_report_builds).to contain_exactly(test_build, coverage_build)
3659    end
3660
3661    it 'filters builds by scope' do
3662      test_build = create(:ci_build, :test_reports, pipeline: pipeline)
3663      create(:ci_build, :coverage_reports, pipeline: pipeline)
3664
3665      expect(pipeline.latest_report_builds(Ci::JobArtifact.test_reports)).to contain_exactly(test_build)
3666    end
3667
3668    it 'only returns not retried builds' do
3669      test_build = create(:ci_build, :test_reports, pipeline: pipeline)
3670      create(:ci_build, :test_reports, :retried, pipeline: pipeline)
3671
3672      expect(pipeline.latest_report_builds).to contain_exactly(test_build)
3673    end
3674  end
3675
3676  describe '#has_reports?' do
3677    subject { pipeline.has_reports?(Ci::JobArtifact.test_reports) }
3678
3679    context 'when pipeline has builds with test reports' do
3680      before do
3681        create(:ci_build, :test_reports, pipeline: pipeline)
3682      end
3683
3684      context 'when pipeline status is running' do
3685        let(:pipeline) { create(:ci_pipeline, :running) }
3686
3687        it { is_expected.to be_falsey }
3688      end
3689
3690      context 'when pipeline status is success' do
3691        let(:pipeline) { create(:ci_pipeline, :success) }
3692
3693        it { is_expected.to be_truthy }
3694      end
3695    end
3696
3697    context 'when pipeline does not have builds with test reports' do
3698      before do
3699        create(:ci_build, :artifacts, pipeline: pipeline)
3700      end
3701
3702      let(:pipeline) { create(:ci_pipeline, :success) }
3703
3704      it { is_expected.to be_falsey }
3705    end
3706
3707    context 'when retried build has test reports' do
3708      before do
3709        create(:ci_build, :retried, :test_reports, pipeline: pipeline)
3710      end
3711
3712      let(:pipeline) { create(:ci_pipeline, :success) }
3713
3714      it { is_expected.to be_falsey }
3715    end
3716  end
3717
3718  describe '#has_coverage_reports?' do
3719    subject { pipeline.has_coverage_reports? }
3720
3721    context 'when pipeline has a code coverage artifact' do
3722      let(:pipeline) { create(:ci_pipeline, :with_coverage_report_artifact, :running) }
3723
3724      it { expect(subject).to be_truthy }
3725    end
3726
3727    context 'when pipeline does not have a code coverage artifact' do
3728      let(:pipeline) { create(:ci_pipeline, :success) }
3729
3730      it { expect(subject).to be_falsey }
3731    end
3732  end
3733
3734  describe '#can_generate_coverage_reports?' do
3735    subject { pipeline.can_generate_coverage_reports? }
3736
3737    context 'when pipeline has builds with coverage reports' do
3738      before do
3739        create(:ci_build, :coverage_reports, pipeline: pipeline)
3740      end
3741
3742      context 'when pipeline status is running' do
3743        let(:pipeline) { create(:ci_pipeline, :running) }
3744
3745        it { expect(subject).to be_falsey }
3746      end
3747
3748      context 'when pipeline status is success' do
3749        let(:pipeline) { create(:ci_pipeline, :success) }
3750
3751        it { expect(subject).to be_truthy }
3752      end
3753    end
3754
3755    context 'when pipeline does not have builds with coverage reports' do
3756      before do
3757        create(:ci_build, :artifacts, pipeline: pipeline)
3758      end
3759
3760      let(:pipeline) { create(:ci_pipeline, :success) }
3761
3762      it { expect(subject).to be_falsey }
3763    end
3764  end
3765
3766  describe '#has_codequality_mr_diff_report?' do
3767    subject { pipeline.has_codequality_mr_diff_report? }
3768
3769    context 'when pipeline has a codequality mr diff report' do
3770      let(:pipeline) { create(:ci_pipeline, :with_codequality_mr_diff_report, :running) }
3771
3772      it { expect(subject).to be_truthy }
3773    end
3774
3775    context 'when pipeline does not have a codequality mr diff report' do
3776      let(:pipeline) { create(:ci_pipeline, :success) }
3777
3778      it { expect(subject).to be_falsey }
3779    end
3780  end
3781
3782  describe '#can_generate_codequality_reports?' do
3783    subject { pipeline.can_generate_codequality_reports? }
3784
3785    context 'when pipeline has builds with codequality reports' do
3786      before do
3787        create(:ci_build, :codequality_reports, pipeline: pipeline)
3788      end
3789
3790      context 'when pipeline status is running' do
3791        let(:pipeline) { create(:ci_pipeline, :running) }
3792
3793        it { expect(subject).to be_falsey }
3794      end
3795
3796      context 'when pipeline status is success' do
3797        let(:pipeline) { create(:ci_pipeline, :success) }
3798
3799        it 'can generate a codequality report' do
3800          expect(subject).to be_truthy
3801        end
3802      end
3803    end
3804
3805    context 'when pipeline does not have builds with codequality reports' do
3806      before do
3807        create(:ci_build, :artifacts, pipeline: pipeline)
3808      end
3809
3810      let(:pipeline) { create(:ci_pipeline, :success) }
3811
3812      it { expect(subject).to be_falsey }
3813    end
3814  end
3815
3816  describe '#test_report_summary' do
3817    subject { pipeline.test_report_summary }
3818
3819    let(:pipeline) { create(:ci_pipeline, :success) }
3820
3821    context 'when pipeline has multiple builds with report results' do
3822      before do
3823        create(:ci_build, :success, :report_results, name: 'rspec', pipeline: pipeline)
3824        create(:ci_build, :success, :report_results, name: 'java', pipeline: pipeline)
3825      end
3826
3827      it 'returns test report summary with collected data' do
3828        expect(subject.total).to include(time: 0.84, count: 4, success: 0, failed: 0, skipped: 0, error: 4)
3829      end
3830    end
3831
3832    context 'when pipeline does not have any builds with report results' do
3833      it 'returns empty test report summary' do
3834        expect(subject.total).to include(time: 0, count: 0, success: 0, failed: 0, skipped: 0, error: 0)
3835      end
3836    end
3837  end
3838
3839  describe '#test_reports' do
3840    subject { pipeline.test_reports }
3841
3842    let_it_be(:pipeline) { create(:ci_pipeline) }
3843
3844    context 'when pipeline has multiple builds with test reports' do
3845      let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
3846      let!(:build_java) { create(:ci_build, :success, name: 'java', pipeline: pipeline) }
3847
3848      before do
3849        create(:ci_job_artifact, :junit, job: build_rspec)
3850        create(:ci_job_artifact, :junit_with_ant, job: build_java)
3851      end
3852
3853      it 'returns test reports with collected data' do
3854        expect(subject.total_count).to be(7)
3855        expect(subject.success_count).to be(5)
3856        expect(subject.failed_count).to be(2)
3857      end
3858
3859      context 'when builds are retried' do
3860        let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
3861        let!(:build_java) { create(:ci_build, :retried, :success, name: 'java', pipeline: pipeline) }
3862
3863        it 'does not take retried builds into account' do
3864          expect(subject.total_count).to be(0)
3865          expect(subject.success_count).to be(0)
3866          expect(subject.failed_count).to be(0)
3867        end
3868      end
3869    end
3870
3871    context 'when pipeline does not have any builds with test reports' do
3872      it 'returns empty test reports' do
3873        expect(subject.total_count).to be(0)
3874      end
3875    end
3876  end
3877
3878  describe '#accessibility_reports' do
3879    subject { pipeline.accessibility_reports }
3880
3881    let_it_be(:pipeline) { create(:ci_pipeline) }
3882
3883    context 'when pipeline has multiple builds with accessibility reports' do
3884      let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
3885      let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
3886
3887      before do
3888        create(:ci_job_artifact, :accessibility, job: build_rspec)
3889        create(:ci_job_artifact, :accessibility_without_errors, job: build_golang)
3890      end
3891
3892      it 'returns accessibility report with collected data' do
3893        expect(subject.urls.keys).to match_array([
3894          "https://pa11y.org/",
3895          "https://about.gitlab.com/"
3896        ])
3897      end
3898
3899      context 'when builds are retried' do
3900        let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
3901        let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
3902
3903        it 'returns empty urls for accessibility reports' do
3904          expect(subject.urls).to be_empty
3905        end
3906      end
3907    end
3908
3909    context 'when pipeline does not have any builds with accessibility reports' do
3910      it 'returns empty urls for accessibility reports' do
3911        expect(subject.urls).to be_empty
3912      end
3913    end
3914  end
3915
3916  describe '#coverage_reports' do
3917    subject { pipeline.coverage_reports }
3918
3919    let_it_be(:pipeline) { create(:ci_pipeline) }
3920
3921    context 'when pipeline has multiple builds with coverage reports' do
3922      let!(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
3923      let!(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
3924
3925      before do
3926        create(:ci_job_artifact, :cobertura, job: build_rspec)
3927        create(:ci_job_artifact, :coverage_gocov_xml, job: build_golang)
3928      end
3929
3930      it 'returns coverage reports with collected data' do
3931        expect(subject.files.keys).to match_array([
3932          "auth/token.go",
3933          "auth/rpccredentials.go",
3934          "app/controllers/abuse_reports_controller.rb"
3935        ])
3936      end
3937
3938      it 'does not execute N+1 queries' do
3939        single_build_pipeline = create(:ci_empty_pipeline, :created)
3940        single_rspec = create(:ci_build, :success, name: 'rspec', pipeline: single_build_pipeline)
3941        create(:ci_job_artifact, :cobertura, job: single_rspec, project: project)
3942
3943        control = ActiveRecord::QueryRecorder.new { single_build_pipeline.coverage_reports }
3944
3945        expect { subject }.not_to exceed_query_limit(control)
3946      end
3947
3948      context 'when builds are retried' do
3949        let!(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
3950        let!(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
3951
3952        it 'does not take retried builds into account' do
3953          expect(subject.files).to eql({})
3954        end
3955      end
3956    end
3957
3958    context 'when pipeline does not have any builds with coverage reports' do
3959      it 'returns empty coverage reports' do
3960        expect(subject.files).to eql({})
3961      end
3962    end
3963  end
3964
3965  describe '#codequality_reports' do
3966    subject(:codequality_reports) { pipeline.codequality_reports }
3967
3968    let_it_be(:pipeline) { create(:ci_pipeline) }
3969
3970    context 'when pipeline has multiple builds with codequality reports' do
3971      let(:build_rspec) { create(:ci_build, :success, name: 'rspec', pipeline: pipeline) }
3972      let(:build_golang) { create(:ci_build, :success, name: 'golang', pipeline: pipeline) }
3973
3974      before do
3975        create(:ci_job_artifact, :codequality, job: build_rspec)
3976        create(:ci_job_artifact, :codequality_without_errors, job: build_golang)
3977      end
3978
3979      it 'returns codequality report with collected data' do
3980        expect(codequality_reports.degradations_count).to eq(3)
3981      end
3982
3983      context 'when builds are retried' do
3984        let(:build_rspec) { create(:ci_build, :retried, :success, name: 'rspec', pipeline: pipeline) }
3985        let(:build_golang) { create(:ci_build, :retried, :success, name: 'golang', pipeline: pipeline) }
3986
3987        it 'returns a codequality reports without degradations' do
3988          expect(codequality_reports.degradations).to be_empty
3989        end
3990      end
3991    end
3992
3993    context 'when pipeline does not have any builds with codequality reports' do
3994      it 'returns codequality reports without degradations' do
3995        expect(codequality_reports.degradations).to be_empty
3996      end
3997    end
3998  end
3999
4000  describe '#uses_needs?' do
4001    let_it_be(:pipeline) { create(:ci_pipeline) }
4002
4003    context 'when the scheduling type is `dag`' do
4004      it 'returns true' do
4005        create(:ci_build, pipeline: pipeline, scheduling_type: :dag)
4006
4007        expect(pipeline.uses_needs?).to eq(true)
4008      end
4009    end
4010
4011    context 'when the scheduling type is nil or stage' do
4012      it 'returns false' do
4013        create(:ci_build, pipeline: pipeline, scheduling_type: :stage)
4014
4015        expect(pipeline.uses_needs?).to eq(false)
4016      end
4017    end
4018  end
4019
4020  describe '#total_size' do
4021    let(:pipeline) { create(:ci_pipeline) }
4022    let!(:build_job1) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
4023    let!(:build_job2) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
4024    let!(:test_job_failed_and_retried) { create(:ci_build, :failed, :retried, pipeline: pipeline, stage_idx: 1) }
4025    let!(:second_test_job) { create(:ci_build, pipeline: pipeline, stage_idx: 1) }
4026    let!(:deploy_job) { create(:ci_build, pipeline: pipeline, stage_idx: 2) }
4027
4028    it 'returns all jobs (including failed and retried)' do
4029      expect(pipeline.total_size).to eq(5)
4030    end
4031  end
4032
4033  describe '#status' do
4034    context 'when transitioning to failed' do
4035      context 'when pipeline has autodevops as source' do
4036        let(:pipeline) { create(:ci_pipeline, :running, :auto_devops_source) }
4037
4038        it 'calls autodevops disable service' do
4039          expect(AutoDevops::DisableWorker).to receive(:perform_async).with(pipeline.id)
4040
4041          pipeline.drop
4042        end
4043      end
4044
4045      context 'when pipeline has other source' do
4046        let(:pipeline) { create(:ci_pipeline, :running, :repository_source) }
4047
4048        it 'does not call auto devops disable service' do
4049          expect(AutoDevops::DisableWorker).not_to receive(:perform_async)
4050
4051          pipeline.drop
4052        end
4053      end
4054
4055      context 'with failure_reason' do
4056        let(:pipeline) { create(:ci_pipeline, :running) }
4057        let(:failure_reason) { 'config_error' }
4058        let(:counter) { Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc') }
4059
4060        it 'increments the counter with the failure_reason' do
4061          expect { pipeline.drop!(failure_reason) }.to change { counter.get(reason: failure_reason) }.by(1)
4062        end
4063      end
4064    end
4065  end
4066
4067  describe '#default_branch?' do
4068    subject { pipeline.default_branch? }
4069
4070    context 'when pipeline ref is the default branch of the project' do
4071      let(:pipeline) do
4072        build(:ci_empty_pipeline, :created, project: project, ref: project.default_branch)
4073      end
4074
4075      it "returns true" do
4076        expect(subject).to be_truthy
4077      end
4078    end
4079
4080    context 'when pipeline ref is not the default branch of the project' do
4081      let(:pipeline) do
4082        build(:ci_empty_pipeline, :created, project: project, ref: 'another_branch')
4083      end
4084
4085      it "returns false" do
4086        expect(subject).to be_falsey
4087      end
4088    end
4089  end
4090
4091  describe '#find_stage_by_name' do
4092    let_it_be(:pipeline) { create(:ci_pipeline) }
4093
4094    let(:stage_name) { 'test' }
4095
4096    let(:stage) do
4097      create(:ci_stage_entity,
4098             pipeline: pipeline,
4099             project: pipeline.project,
4100             name: 'test')
4101    end
4102
4103    before do
4104      create_list(:ci_build, 2, pipeline: pipeline, stage: stage.name)
4105    end
4106
4107    subject { pipeline.find_stage_by_name!(stage_name) }
4108
4109    context 'when stage exists' do
4110      it { is_expected.to eq(stage) }
4111    end
4112
4113    context 'when stage does not exist' do
4114      let(:stage_name) { 'build' }
4115
4116      it 'raises an ActiveRecord exception' do
4117        expect do
4118          subject
4119        end.to raise_exception(ActiveRecord::RecordNotFound)
4120      end
4121    end
4122  end
4123
4124  describe '#full_error_messages' do
4125    subject { pipeline.full_error_messages }
4126
4127    before do
4128      pipeline.valid?
4129    end
4130
4131    context 'when pipeline has errors' do
4132      let(:pipeline) { build(:ci_pipeline, sha: nil, ref: nil) }
4133
4134      it 'returns the full error messages' do
4135        is_expected.to eq("Sha can't be blank and Ref can't be blank")
4136      end
4137    end
4138
4139    context 'when pipeline does not have errors' do
4140      let(:pipeline) { build(:ci_pipeline) }
4141
4142      it 'returns empty string' do
4143        is_expected.to be_empty
4144      end
4145    end
4146  end
4147
4148  describe '#created_successfully?' do
4149    subject { pipeline.created_successfully? }
4150
4151    context 'when pipeline is not persisted' do
4152      let(:pipeline) { build(:ci_pipeline) }
4153
4154      it { is_expected.to be_falsey }
4155    end
4156
4157    context 'when pipeline is persisted' do
4158      context 'when pipeline has failure reasons' do
4159        let(:pipeline) { create(:ci_pipeline, failure_reason: :config_error) }
4160
4161        it { is_expected.to be_falsey }
4162      end
4163
4164      context 'when pipeline has no failure reasons' do
4165        let(:pipeline) { create(:ci_pipeline, failure_reason: nil) }
4166
4167        it { is_expected.to be_truthy }
4168      end
4169    end
4170  end
4171
4172  describe '#parent_pipeline' do
4173    let_it_be_with_reload(:pipeline) { create(:ci_pipeline) }
4174
4175    context 'when pipeline is triggered by a pipeline from the same project' do
4176      let_it_be(:upstream_pipeline) { create(:ci_pipeline) }
4177      let_it_be(:pipeline) { create(:ci_pipeline, child_of: upstream_pipeline) }
4178
4179      it 'returns the parent pipeline' do
4180        expect(pipeline.parent_pipeline).to eq(upstream_pipeline)
4181      end
4182
4183      it 'is child' do
4184        expect(pipeline).to be_child
4185      end
4186    end
4187
4188    context 'when pipeline is triggered by a pipeline from another project' do
4189      let(:pipeline) { create(:ci_pipeline) }
4190      let!(:upstream_pipeline) { create(:ci_pipeline, project: create(:project), upstream_of: pipeline) }
4191
4192      it 'returns nil' do
4193        expect(pipeline.parent_pipeline).to be_nil
4194      end
4195
4196      it 'is not child' do
4197        expect(pipeline).not_to be_child
4198      end
4199    end
4200
4201    context 'when pipeline is not triggered by a pipeline' do
4202      let_it_be(:pipeline) { create(:ci_pipeline) }
4203
4204      it 'returns nil' do
4205        expect(pipeline.parent_pipeline).to be_nil
4206      end
4207
4208      it 'is not child' do
4209        expect(pipeline).not_to be_child
4210      end
4211    end
4212  end
4213
4214  describe '#child_pipelines' do
4215    let_it_be(:project) { create(:project) }
4216    let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
4217
4218    context 'when pipeline triggered other pipelines on same project' do
4219      let(:downstream_pipeline) { create(:ci_pipeline, project: pipeline.project) }
4220
4221      before do
4222        create(:ci_sources_pipeline,
4223          source_pipeline: pipeline,
4224          source_project: pipeline.project,
4225          pipeline: downstream_pipeline,
4226          project: pipeline.project)
4227      end
4228
4229      it 'returns the child pipelines' do
4230        expect(pipeline.child_pipelines).to eq [downstream_pipeline]
4231      end
4232
4233      it 'is parent' do
4234        expect(pipeline).to be_parent
4235      end
4236    end
4237
4238    context 'when pipeline triggered other pipelines on another project' do
4239      let(:downstream_pipeline) { create(:ci_pipeline) }
4240
4241      before do
4242        create(:ci_sources_pipeline,
4243          source_pipeline: pipeline,
4244          source_project: pipeline.project,
4245          pipeline: downstream_pipeline,
4246          project: downstream_pipeline.project)
4247      end
4248
4249      it 'returns empty array' do
4250        expect(pipeline.child_pipelines).to be_empty
4251      end
4252
4253      it 'is not parent' do
4254        expect(pipeline).not_to be_parent
4255      end
4256    end
4257
4258    context 'when pipeline did not trigger any pipelines' do
4259      it 'returns empty array' do
4260        expect(pipeline.child_pipelines).to be_empty
4261      end
4262
4263      it 'is not parent' do
4264        expect(pipeline).not_to be_parent
4265      end
4266    end
4267  end
4268
4269  describe 'upstream status interactions' do
4270    let_it_be_with_reload(:pipeline) { create(:ci_pipeline, :created) }
4271
4272    context 'when a pipeline has an upstream status' do
4273      context 'when an upstream status is a bridge' do
4274        let(:bridge) { create(:ci_bridge, status: :pending) }
4275
4276        before do
4277          create(:ci_sources_pipeline, pipeline: pipeline, source_job: bridge)
4278        end
4279
4280        describe '#bridge_triggered?' do
4281          it 'is a pipeline triggered by a bridge' do
4282            expect(pipeline).to be_bridge_triggered
4283          end
4284        end
4285
4286        describe '#source_job' do
4287          it 'has a correct source job' do
4288            expect(pipeline.source_job).to eq bridge
4289          end
4290        end
4291
4292        describe '#source_bridge' do
4293          it 'has a correct bridge source' do
4294            expect(pipeline.source_bridge).to eq bridge
4295          end
4296        end
4297      end
4298
4299      context 'when an upstream status is a build' do
4300        let(:build) { create(:ci_build) }
4301
4302        before do
4303          create(:ci_sources_pipeline, pipeline: pipeline, source_job: build)
4304        end
4305
4306        describe '#bridge_triggered?' do
4307          it 'is a pipeline that has not been triggered by a bridge' do
4308            expect(pipeline).not_to be_bridge_triggered
4309          end
4310        end
4311
4312        describe '#source_job' do
4313          it 'has a correct source job' do
4314            expect(pipeline.source_job).to eq build
4315          end
4316        end
4317
4318        describe '#source_bridge' do
4319          it 'does not have a bridge source' do
4320            expect(pipeline.source_bridge).to be_nil
4321          end
4322        end
4323      end
4324    end
4325  end
4326
4327  describe '#source_ref_path' do
4328    subject { pipeline.source_ref_path }
4329
4330    let(:pipeline) { create(:ci_pipeline, :created) }
4331
4332    context 'when pipeline is for a branch' do
4333      it { is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.source_ref.to_s) }
4334    end
4335
4336    context 'when pipeline is for a merge request' do
4337      let(:merge_request) { create(:merge_request, source_project: project) }
4338      let(:pipeline) { create(:ci_pipeline, project: project, head_pipeline_of: merge_request) }
4339
4340      it { is_expected.to eq(Gitlab::Git::BRANCH_REF_PREFIX + pipeline.source_ref.to_s) }
4341    end
4342
4343    context 'when pipeline is for a tag' do
4344      let(:pipeline) { create(:ci_pipeline, tag: true) }
4345
4346      it { is_expected.to eq(Gitlab::Git::TAG_REF_PREFIX + pipeline.source_ref.to_s) }
4347    end
4348  end
4349
4350  describe '#builds_with_coverage' do
4351    let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4352
4353    it 'returns builds with coverage only' do
4354      rspec = create(:ci_build, name: 'rspec', coverage: 97.1, pipeline: pipeline)
4355      jest  = create(:ci_build, name: 'jest', coverage: 94.1, pipeline: pipeline)
4356      karma = create(:ci_build, name: 'karma', coverage: nil, pipeline: pipeline)
4357
4358      builds = pipeline.builds_with_coverage
4359
4360      expect(builds).to include(rspec, jest)
4361      expect(builds).not_to include(karma)
4362    end
4363
4364    it 'returns only latest builds' do
4365      obsolete = create(:ci_build, name: "jest", coverage: 10.12, pipeline: pipeline, retried: true)
4366      retried  = create(:ci_build, name: "jest", coverage: 20.11, pipeline: pipeline)
4367
4368      builds = pipeline.builds_with_coverage
4369
4370      expect(builds).to include(retried)
4371      expect(builds).not_to include(obsolete)
4372    end
4373  end
4374
4375  describe '#self_and_upstreams' do
4376    subject(:self_and_upstreams) { pipeline.self_and_upstreams }
4377
4378    let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4379
4380    context 'when pipeline is not child nor parent' do
4381      it 'returns just the pipeline itself' do
4382        expect(self_and_upstreams).to contain_exactly(pipeline)
4383      end
4384    end
4385
4386    context 'when pipeline is child' do
4387      let(:parent) { create(:ci_pipeline) }
4388      let(:sibling) { create(:ci_pipeline) }
4389
4390      before do
4391        create_source_pipeline(parent, pipeline)
4392        create_source_pipeline(parent, sibling)
4393      end
4394
4395      it 'returns parent and self' do
4396        expect(self_and_upstreams).to contain_exactly(parent, pipeline)
4397      end
4398    end
4399
4400    context 'when pipeline is parent' do
4401      let(:child) { create(:ci_pipeline) }
4402
4403      before do
4404        create_source_pipeline(pipeline, child)
4405      end
4406
4407      it 'returns self' do
4408        expect(self_and_upstreams).to contain_exactly(pipeline)
4409      end
4410    end
4411
4412    context 'when pipeline is a child of a child pipeline' do
4413      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4414
4415      let(:ancestor) { create(:ci_pipeline) }
4416      let(:parent) { create(:ci_pipeline) }
4417
4418      before do
4419        create_source_pipeline(ancestor, parent)
4420        create_source_pipeline(parent, pipeline)
4421      end
4422
4423      it 'returns self, parent and ancestor' do
4424        expect(self_and_upstreams).to contain_exactly(ancestor, parent, pipeline)
4425      end
4426    end
4427
4428    context 'when pipeline is a triggered pipeline from a different project' do
4429      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4430
4431      let(:upstream) { create(:ci_pipeline, project: create(:project)) }
4432
4433      before do
4434        create_source_pipeline(upstream, pipeline)
4435      end
4436
4437      it 'returns upstream and self' do
4438        expect(self_and_upstreams).to contain_exactly(pipeline, upstream)
4439      end
4440    end
4441  end
4442
4443  describe '#self_and_ancestors' do
4444    subject(:self_and_ancestors) { pipeline.self_and_ancestors }
4445
4446    context 'when pipeline is child' do
4447      let(:pipeline) { create(:ci_pipeline, :created) }
4448      let(:parent) { create(:ci_pipeline) }
4449      let(:sibling) { create(:ci_pipeline) }
4450
4451      before do
4452        create_source_pipeline(parent, pipeline)
4453        create_source_pipeline(parent, sibling)
4454      end
4455
4456      it 'returns parent and self' do
4457        expect(self_and_ancestors).to contain_exactly(parent, pipeline)
4458      end
4459    end
4460
4461    context 'when pipeline is a triggered pipeline from a different project' do
4462      let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4463
4464      let(:upstream) { create(:ci_pipeline, project: create(:project)) }
4465
4466      before do
4467        create_source_pipeline(upstream, pipeline)
4468      end
4469
4470      it 'returns only self' do
4471        expect(self_and_ancestors).to contain_exactly(pipeline)
4472      end
4473    end
4474  end
4475
4476  describe '#reset_source_bridge!' do
4477    let(:pipeline) { create(:ci_pipeline, :created, project: project) }
4478
4479    subject(:reset_bridge) { pipeline.reset_source_bridge!(project.owner) }
4480
4481    context 'when the pipeline is a child pipeline and the bridge is depended' do
4482      let!(:parent_pipeline) { create(:ci_pipeline) }
4483      let!(:bridge) { create_bridge(parent_pipeline, pipeline, true) }
4484
4485      it 'marks source bridge as pending' do
4486        reset_bridge
4487
4488        expect(bridge.reload).to be_pending
4489      end
4490
4491      context 'when the parent pipeline has subsequent jobs after the bridge' do
4492        let!(:after_bridge_job) { create(:ci_build, :skipped, pipeline: parent_pipeline, stage_idx: bridge.stage_idx + 1) }
4493
4494        it 'marks subsequent jobs of the bridge as processable' do
4495          reset_bridge
4496
4497          expect(after_bridge_job.reload).to be_created
4498        end
4499      end
4500
4501      context 'when the parent pipeline has a dependent upstream pipeline' do
4502        let!(:upstream_bridge) do
4503          create_bridge(create(:ci_pipeline, project: create(:project)), parent_pipeline, true)
4504        end
4505
4506        it 'marks all source bridges as pending' do
4507          reset_bridge
4508
4509          expect(bridge.reload).to be_pending
4510          expect(upstream_bridge.reload).to be_pending
4511        end
4512      end
4513    end
4514
4515    context 'when the pipeline is a child pipeline and the bridge is not depended' do
4516      let!(:parent_pipeline) { create(:ci_pipeline) }
4517      let!(:bridge) { create_bridge(parent_pipeline, pipeline, false) }
4518
4519      it 'does not touch source bridge' do
4520        reset_bridge
4521
4522        expect(bridge.reload).to be_success
4523      end
4524
4525      context 'when the parent pipeline has a dependent upstream pipeline' do
4526        let!(:upstream_bridge) do
4527          create_bridge(create(:ci_pipeline, project: create(:project)), parent_pipeline, true)
4528        end
4529
4530        it 'does not touch any source bridge' do
4531          reset_bridge
4532
4533          expect(bridge.reload).to be_success
4534          expect(upstream_bridge.reload).to be_success
4535        end
4536      end
4537    end
4538
4539    private
4540
4541    def create_bridge(upstream, downstream, depend = false)
4542      options = depend ? { trigger: { strategy: 'depend' } } : {}
4543
4544      bridge = create(:ci_bridge, pipeline: upstream, status: 'success', options: options)
4545      create(:ci_sources_pipeline, pipeline: downstream, source_job: bridge)
4546
4547      bridge
4548    end
4549  end
4550
4551  describe 'test failure history processing' do
4552    let(:pipeline) { build(:ci_pipeline, :created) }
4553
4554    it 'performs the service asynchronously when the pipeline is completed' do
4555      service = double
4556
4557      expect(Ci::TestFailureHistoryService).to receive(:new).with(pipeline).and_return(service)
4558      expect(service).to receive_message_chain(:async, :perform_if_needed)
4559
4560      pipeline.succeed!
4561    end
4562  end
4563
4564  describe '#latest_test_report_builds' do
4565    let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4566
4567    it 'returns pipeline builds with test report artifacts' do
4568      test_build = create(:ci_build, :test_reports, pipeline: pipeline)
4569      create(:ci_build, :artifacts, pipeline: pipeline, project: project)
4570
4571      expect(pipeline.latest_test_report_builds).to contain_exactly(test_build)
4572    end
4573
4574    it 'preloads project on each build to avoid N+1 queries' do
4575      create(:ci_build, :test_reports, pipeline: pipeline)
4576
4577      control_count = ActiveRecord::QueryRecorder.new do
4578        pipeline.latest_test_report_builds.map(&:project).map(&:full_path)
4579      end
4580
4581      multi_build_pipeline = create(:ci_empty_pipeline, :created)
4582      create(:ci_build, :test_reports, pipeline: multi_build_pipeline, project: project)
4583      create(:ci_build, :test_reports, pipeline: multi_build_pipeline, project: project)
4584
4585      expect { multi_build_pipeline.latest_test_report_builds.map(&:project).map(&:full_path) }
4586        .not_to exceed_query_limit(control_count)
4587    end
4588  end
4589
4590  describe '#builds_with_failed_tests' do
4591    let_it_be(:pipeline) { create(:ci_pipeline, :created) }
4592
4593    it 'returns pipeline builds with test report artifacts' do
4594      failed_build = create(:ci_build, :failed, :test_reports, pipeline: pipeline)
4595      create(:ci_build, :success, :test_reports, pipeline: pipeline)
4596
4597      expect(pipeline.builds_with_failed_tests).to contain_exactly(failed_build)
4598    end
4599
4600    it 'supports limiting the number of builds to fetch' do
4601      create(:ci_build, :failed, :test_reports, pipeline: pipeline)
4602      create(:ci_build, :failed, :test_reports, pipeline: pipeline)
4603
4604      expect(pipeline.builds_with_failed_tests(limit: 1).count).to eq(1)
4605    end
4606
4607    it 'preloads project on each build to avoid N+1 queries' do
4608      create(:ci_build, :failed, :test_reports, pipeline: pipeline)
4609
4610      control_count = ActiveRecord::QueryRecorder.new do
4611        pipeline.builds_with_failed_tests.map(&:project).map(&:full_path)
4612      end
4613
4614      multi_build_pipeline = create(:ci_empty_pipeline, :created)
4615      create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline)
4616      create(:ci_build, :failed, :test_reports, pipeline: multi_build_pipeline)
4617
4618      expect { multi_build_pipeline.builds_with_failed_tests.map(&:project).map(&:full_path) }
4619        .not_to exceed_query_limit(control_count)
4620    end
4621  end
4622
4623  describe '#build_matchers' do
4624    let_it_be(:user) { create(:user) }
4625    let_it_be(:pipeline) { create(:ci_pipeline, user: user) }
4626    let_it_be(:builds) { create_list(:ci_build, 2, pipeline: pipeline, project: pipeline.project, user: user) }
4627
4628    let(:project) { pipeline.project }
4629
4630    subject(:matchers) { pipeline.build_matchers }
4631
4632    it 'returns build matchers' do
4633      expect(matchers.size).to eq(1)
4634      expect(matchers).to all be_a(Gitlab::Ci::Matching::BuildMatcher)
4635      expect(matchers.first.build_ids).to match_array(builds.map(&:id))
4636    end
4637
4638    context 'with retried builds' do
4639      let(:retried_build) { builds.first }
4640
4641      before do
4642        stub_not_protect_default_branch
4643        project.add_developer(user)
4644
4645        retried_build.cancel!
4646        ::Ci::Build.retry(retried_build, user)
4647      end
4648
4649      it 'does not include retried builds' do
4650        expect(matchers.size).to eq(1)
4651        expect(matchers.first.build_ids).not_to include(retried_build.id)
4652      end
4653    end
4654  end
4655
4656  describe '#authorized_cluster_agents' do
4657    let(:pipeline) { create(:ci_empty_pipeline, :created) }
4658    let(:agent) { instance_double(Clusters::Agent) }
4659    let(:authorization) { instance_double(Clusters::Agents::GroupAuthorization, agent: agent) }
4660    let(:finder) { double(execute: [authorization]) }
4661
4662    it 'retrieves agent records from the finder and caches the result' do
4663      expect(Clusters::AgentAuthorizationsFinder).to receive(:new).once
4664        .with(pipeline.project)
4665        .and_return(finder)
4666
4667      expect(pipeline.authorized_cluster_agents).to contain_exactly(agent)
4668      expect(pipeline.authorized_cluster_agents).to contain_exactly(agent) # cached
4669    end
4670  end
4671
4672  it_behaves_like 'it has loose foreign keys' do
4673    let(:factory_name) { :ci_pipeline }
4674  end
4675
4676  it_behaves_like 'cleanup by a loose foreign key' do
4677    let!(:model) { create(:ci_pipeline, user: create(:user)) }
4678    let!(:parent) { model.user }
4679  end
4680end
4681