blob: 37d1e20111d6a2436d15c8b842ee83cc6ec341fb (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
describe 'Run pipeline with manual jobs' do
let(:executor) { "qa-runner-#{SecureRandom.hex(4)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'pipeline-with-manual-job'
project.description = 'Project for pipeline with manual job'
end
end
let!(:runner) do
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]
end
end
let!(:ci_file) do
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files(
[
{
file_path: '.gitlab-ci.yml',
content: <<~YAML
default:
tags: ["#{executor}"]
stages:
- Stage1
- Stage2
- Stage3
Prep:
stage: Stage1
script: exit 0
when: manual
Build:
stage: Stage2
needs: ['Prep']
script: exit 0
parallel: 6
Test:
stage: Stage3
needs: ['Build']
script: exit 0
Deploy:
stage: Stage3
needs: ['Test']
script: exit 0
parallel: 6
YAML
}
]
)
end
end
before do
make_sure_to_have_a_skipped_pipeline
Flow::Login.sign_in
project.visit!
Flow::Pipeline.visit_latest_pipeline(status: 'skipped')
end
after do
runner&.remove_via_api!
end
it(
'does not leave any job in skipped state',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349158'
) do
Page::Project::Pipeline::Show.perform do |show|
show.click_job_action('Prep') # Trigger pipeline manually
show.wait_until(max_duration: 300, sleep_interval: 2, reload: false) do
project.latest_pipeline[:status] == 'success'
end
aggregate_failures do
expect(show).to have_build('Test', status: :success)
show.click_job_dropdown('Build')
expect(show).not_to have_skipped_job_in_group
show.click_job_dropdown('Build') # Close Build dropdown
show.click_job_dropdown('Deploy')
expect(show).not_to have_skipped_job_in_group
end
end
end
private
# Wait for first pipeline to finish and have "skipped" status
# If it takes too long, create new pipeline and retry (2 times)
def make_sure_to_have_a_skipped_pipeline
attempts ||= 1
Runtime::Logger.info('Waiting for pipeline to have status "skipped"...')
Support::Waiter.wait_until(max_duration: 120, sleep_interval: 3, retry_on_exception: true) do
project.latest_pipeline[:status] == 'skipped'
end
rescue Support::Repeater::WaitExceededError
raise 'Failed to create skipped pipeline after 3 attempts.' unless (attempts += 1) < 4
Runtime::Logger.debug(
"Previous pipeline took too long to finish. Potential jobs with problems:\n#{problematic_jobs}"
)
Runtime::Logger.info("Triggering a new pipeline...")
trigger_new_pipeline
retry
end
def trigger_new_pipeline
original_count = project.pipelines.length
Resource::Pipeline.fabricate_via_api! do |pipeline|
pipeline.project = project
end
Support::Waiter.wait_until(sleep_interval: 1) { project.pipelines.length > original_count }
end
# We know that all the jobs in pipeline are purposely skipped
# The pipeline should have status "skipped" almost right away after being created
# If pipeline is held up, likely because there are some jobs that
# doesn't have either "skipped" or "manual" status
def problematic_jobs
pipeline = Resource::Pipeline.fabricate_via_api! do |pipeline|
pipeline.project = project
pipeline.id = project.latest_pipeline[:id]
end
acceptable_statuses = %w[skipped manual]
pipeline.pipeline_jobs.select { |job| !(acceptable_statuses.include? job[:status]) }
end
end
end
end
|