3
3
import hudson .model .FreeStyleProject ;
4
4
import hudson .model .Result ;
5
5
import hudson .model .Run ;
6
+
6
7
import org .jenkinsci .plugins .workflow .actions .WarningAction ;
7
8
import org .jenkinsci .plugins .workflow .cps .CpsFlowDefinition ;
8
9
import org .jenkinsci .plugins .workflow .cps .nodes .StepAtomNode ;
11
12
import org .jenkinsci .plugins .workflow .graph .FlowNode ;
12
13
import org .jenkinsci .plugins .workflow .job .WorkflowJob ;
13
14
import org .jenkinsci .plugins .workflow .job .WorkflowRun ;
15
+ import org .jenkinsci .plugins .workflow .test .steps .SemaphoreStep ;
14
16
import org .junit .ClassRule ;
15
17
import org .junit .Rule ;
16
18
import org .junit .Test ;
@@ -31,25 +33,60 @@ public class WaitForBuildStepTest {
31
33
32
34
@ Test public void waitForBuild () throws Exception {
33
35
Result dsResult = Result .FAILURE ;
34
- createWaitingDownStreamJob (dsResult );
36
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , dsResult );
35
37
WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
36
38
us .setDefinition (new CpsFlowDefinition (
37
39
"def ds = build job: 'ds', waitForStart: true\n " +
40
+ "semaphore 'scheduled'\n " +
38
41
"def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
39
42
"def completeDs = waitForBuild runId: dsRunId\n " +
40
43
"echo \" 'ds' completed with status ${completeDs.getResult()}\" " , true ));
41
- j .assertLogContains ("'ds' completed with status " + dsResult .toString (), j .buildAndAssertSuccess (us ));
44
+
45
+ // schedule upstream
46
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
47
+
48
+ // wait for ds to be scheduled
49
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
50
+ SemaphoreStep .success ("scheduled/1" , true );
51
+
52
+ // signal the downstream run to complete after it has been waited on
53
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
54
+ SemaphoreStep .waitForStart ("wait/1" , dsRun );
55
+ waitForWaitForBuildAction (dsRun );
56
+ SemaphoreStep .success ("wait/1" , true );
57
+
58
+ // assert upstream build status
59
+ WorkflowRun completedUsRun = j .waitForCompletion (usRun );
60
+ j .assertBuildStatusSuccess (completedUsRun );
61
+ j .assertLogContains ("'ds' completed with status " + dsResult .toString (), completedUsRun );
42
62
}
43
63
44
64
@ Test public void waitForBuildPropagte () throws Exception {
45
65
Result dsResult = Result .FAILURE ;
46
- createWaitingDownStreamJob (dsResult );
66
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , dsResult );
47
67
WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
48
68
us .setDefinition (new CpsFlowDefinition (
49
69
"def ds = build job: 'ds', waitForStart: true\n " +
70
+ "semaphore 'scheduled'\n " +
50
71
"def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
51
72
"waitForBuild runId: dsRunId, propagate: true" , true ));
52
- j .assertLogContains ("completed with status " + dsResult .toString (), j .buildAndAssertStatus (dsResult , us ));
73
+
74
+ // schedule upstream
75
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
76
+
77
+ // wait for ds to be scheduled
78
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
79
+ SemaphoreStep .success ("scheduled/1" , true );
80
+
81
+ // signal the downstream run to complete after it has been waited on
82
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
83
+ waitForWaitForBuildAction (dsRun );
84
+ SemaphoreStep .success ("wait/1" , true );
85
+
86
+ // assert upstream build status
87
+ WorkflowRun completedUsRun = j .waitForCompletion (usRun );
88
+ j .assertBuildStatus (dsResult , completedUsRun );
89
+ j .assertLogContains ("completed with status " + dsResult .toString (), completedUsRun );
53
90
}
54
91
55
92
@ SuppressWarnings ("rawtypes" )
@@ -82,24 +119,127 @@ public class WaitForBuildStepTest {
82
119
@ Issue ("JENKINS-70983" )
83
120
@ Test public void waitForUnstableBuildWithWarningAction () throws Exception {
84
121
Result dsResult = Result .UNSTABLE ;
85
- createWaitingDownStreamJob (dsResult );
122
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , dsResult );
86
123
WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
87
124
us .setDefinition (new CpsFlowDefinition (
88
125
"def ds = build job: 'ds', waitForStart: true\n " +
126
+ "semaphore 'scheduled'\n " +
89
127
"def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
90
128
"try {\n " +
91
129
" waitForBuild runId: dsRunId, propagate: true\n " +
92
130
"} finally {\n " +
93
131
" echo \" 'ds' completed with status ${ds.getResult()}\" \n " +
94
132
"}" , true ));
95
- j .assertLogContains ("'ds' completed with status " + dsResult .toString (), j .buildAndAssertStatus (dsResult , us ));
96
- WorkflowRun lastUpstreamRun = us .getLastBuild ();
97
- FlowNode buildTriggerNode = findFirstNodeWithDescriptor (lastUpstreamRun .getExecution (), WaitForBuildStep .DescriptorImpl .class );
133
+
134
+ // schedule upstream
135
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
136
+
137
+ // wait for ds to be scheduled
138
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
139
+ SemaphoreStep .success ("scheduled/1" , true );
140
+
141
+ // signal the downstream run to complete after it has been waited on
142
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
143
+ waitForWaitForBuildAction (dsRun );
144
+ SemaphoreStep .success ("wait/1" , true );
145
+
146
+ // assert upstream build status
147
+ WorkflowRun completedUsRun = j .waitForCompletion (usRun );
148
+ j .assertBuildStatus (dsResult , completedUsRun );
149
+ j .assertLogContains ("'ds' completed with status " + dsResult .toString (), completedUsRun );
150
+
151
+ FlowNode buildTriggerNode = findFirstNodeWithDescriptor (completedUsRun .getExecution (), WaitForBuildStep .DescriptorImpl .class );
98
152
WarningAction action = buildTriggerNode .getAction (WarningAction .class );
99
153
assertNotNull (action );
100
154
assertEquals (action .getResult (), Result .UNSTABLE );
101
155
}
102
156
157
+ @ Issue ("JENKINS-71961" )
158
+ @ Test public void abortBuild () throws Exception {
159
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , Result .SUCCESS );
160
+ WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
161
+ us .setDefinition (new CpsFlowDefinition (
162
+ "def ds = build job: 'ds', waitForStart: true\n " +
163
+ "semaphore 'scheduled'\n " +
164
+ "def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
165
+ "def completeDs = waitForBuild runId: dsRunId, propagate: true\n " +
166
+ "echo \" 'ds' completed with status ${completeDs.getResult()}\" " , true ));
167
+
168
+ // schedule upstream
169
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
170
+
171
+ // wait for ds to be scheduled
172
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
173
+ SemaphoreStep .success ("scheduled/1" , true );
174
+
175
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
176
+ waitForWaitForBuildAction (dsRun );
177
+
178
+ // Abort the downstream build
179
+ dsRun .getExecutor ().interrupt ();
180
+
181
+ j .assertBuildStatus (Result .ABORTED , j .waitForCompletion (dsRun ));
182
+ j .assertBuildStatus (Result .ABORTED , j .waitForCompletion (usRun ));
183
+ }
184
+
185
+ @ Issue ("JENKINS-71961" )
186
+ @ Test public void interruptFlowPropagateAbort () throws Exception {
187
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , Result .SUCCESS );
188
+ WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
189
+ us .setDefinition (new CpsFlowDefinition (
190
+ "def ds = build job: 'ds', waitForStart: true\n " +
191
+ "semaphore 'scheduled'\n " +
192
+ "def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
193
+ "def completeDs = waitForBuild runId: dsRunId, propagate: true, propagateAbort: true\n " +
194
+ "echo \" 'ds' completed with status ${completeDs.getResult()}\" " , true ));
195
+
196
+ // schedule upstream
197
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
198
+
199
+ // wait for ds to be scheduled
200
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
201
+ SemaphoreStep .success ("scheduled/1" , true );
202
+
203
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
204
+ waitForWaitForBuildAction (dsRun );
205
+
206
+ // Abort the upstream build
207
+ usRun .doStop ();
208
+
209
+ j .assertBuildStatus (Result .ABORTED , j .waitForCompletion (dsRun ));
210
+ j .assertBuildStatus (Result .ABORTED , j .waitForCompletion (usRun ));
211
+ }
212
+
213
+ @ Issue ("JENKINS-71961" )
214
+ @ Test public void interruptFlowNoPropagateAbort () throws Exception {
215
+ WorkflowJob ds = createWaitingDownStreamJob ("wait" , Result .SUCCESS );
216
+ WorkflowJob us = j .jenkins .createProject (WorkflowJob .class , "us" );
217
+ us .setDefinition (new CpsFlowDefinition (
218
+ "def ds = build job: 'ds', waitForStart: true\n " +
219
+ "semaphore 'scheduled'\n " +
220
+ "def dsRunId = \" ${ds.getFullProjectName()}#${ds.getNumber()}\" \n " +
221
+ "def completeDs = waitForBuild runId: dsRunId, propagate: true, propagateAbort: false\n " +
222
+ "echo \" 'ds' completed with status ${completeDs.getResult()}\" " , true ));
223
+
224
+ // schedule upstream
225
+ WorkflowRun usRun = us .scheduleBuild2 (0 ).waitForStart ();
226
+
227
+ // wait for ds to be scheduled
228
+ SemaphoreStep .waitForStart ("scheduled/1" , usRun );
229
+ SemaphoreStep .success ("scheduled/1" , true );
230
+
231
+ WorkflowRun dsRun = ds .getBuildByNumber (1 );
232
+ waitForWaitForBuildAction (dsRun );
233
+
234
+ // Abort the upstream build
235
+ usRun .doStop ();
236
+ j .assertBuildStatus (Result .ABORTED , j .waitForCompletion (usRun ));
237
+
238
+ // Allow the downstream to complete
239
+ SemaphoreStep .success ("wait/1" , true );
240
+ j .assertBuildStatus (Result .SUCCESS , j .waitForCompletion (dsRun ));
241
+ }
242
+
103
243
private static FlowNode findFirstNodeWithDescriptor (FlowExecution execution , Class <WaitForBuildStep .DescriptorImpl > cls ) {
104
244
for (FlowNode node : new FlowGraphWalker (execution )) {
105
245
if (node instanceof StepAtomNode ) {
@@ -112,22 +252,23 @@ private static FlowNode findFirstNodeWithDescriptor(FlowExecution execution, Cla
112
252
return null ;
113
253
}
114
254
115
- private WorkflowJob createWaitingDownStreamJob (Result result ) throws Exception {
255
+ private WorkflowJob createWaitingDownStreamJob (String semaphoreName , Result result ) throws Exception {
116
256
WorkflowJob ds = j .jenkins .createProject (WorkflowJob .class , "ds" );
117
257
ds .setDefinition (new CpsFlowDefinition (
118
- "import org.jenkinsci.plugins.workflow.support.steps.build.WaitForBuildAction\n " +
119
- "@NonCPS\n " +
120
- "boolean hasWaitForBuildAction() {\n " +
121
- " return currentBuild.getRawBuild().getAction(WaitForBuildAction.class) != null\n " +
122
- "}\n " +
123
- "while(!hasWaitForBuildAction()) {\n " +
124
- " sleep(time: 100, unit: 'MILLISECONDS')\n " +
125
- "}\n " +
258
+ "semaphore('" + semaphoreName + "')\n " +
126
259
"catchError(buildResult: '" + result .toString () + "') {\n " +
127
260
" error('')\n " +
128
261
"}" , false ));
129
262
return ds ;
130
-
263
+ }
264
+
265
+ private void waitForWaitForBuildAction (WorkflowRun r ) throws Exception {
266
+ while (true ) {
267
+ if (r .getAction (WaitForBuildAction .class ) != null ) {
268
+ break ;
269
+ }
270
+ Thread .sleep (10 );
271
+ }
131
272
}
132
273
133
274
}
0 commit comments