blob: ad25c4714b9588abefdb9e2249a35051607ce24e [file] [log] [blame]
James E. Blair1c2023c2018-01-08 09:42:22 -08001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4# Copyright 2018 Red Hat, Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
18from tests.base import (
19 ZuulTestCase,
20 simple_layout,
21)
22
23
24class TestGerritCRD(ZuulTestCase):
25 tenant_config_file = 'config/single-tenant/main.yaml'
26
James E. Blair1c2023c2018-01-08 09:42:22 -080027 def test_crd_gate(self):
28 "Test cross-repo dependencies"
29 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
30 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
31 A.addApproval('Code-Review', 2)
32 B.addApproval('Code-Review', 2)
33
34 AM2 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM2')
35 AM1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM1')
36 AM2.setMerged()
37 AM1.setMerged()
38
39 BM2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM2')
40 BM1 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM1')
41 BM2.setMerged()
42 BM1.setMerged()
43
44 # A -> AM1 -> AM2
45 # B -> BM1 -> BM2
46 # A Depends-On: B
47 # M2 is here to make sure it is never queried. If it is, it
48 # means zuul is walking down the entire history of merged
49 # changes.
50
51 B.setDependsOn(BM1, 1)
52 BM1.setDependsOn(BM2, 1)
53
54 A.setDependsOn(AM1, 1)
55 AM1.setDependsOn(AM2, 1)
56
James E. Blairdf31eb62018-01-31 14:11:39 -080057 # So that at least one test uses the /#/c/ form of the url,
58 # use it here.
59 url = 'https://%s/#/c/%s' % (B.gerrit.server, B.number)
James E. Blair1c2023c2018-01-08 09:42:22 -080060 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
James E. Blairdf31eb62018-01-31 14:11:39 -080061 A.subject, url)
James E. Blair1c2023c2018-01-08 09:42:22 -080062
63 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
64 self.waitUntilSettled()
65
66 self.assertEqual(A.data['status'], 'NEW')
67 self.assertEqual(B.data['status'], 'NEW')
68
69 for connection in self.connections.connections.values():
70 connection.maintainCache([])
71
72 self.executor_server.hold_jobs_in_build = True
73 B.addApproval('Approved', 1)
74 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
75 self.waitUntilSettled()
76
77 self.executor_server.release('.*-merge')
78 self.waitUntilSettled()
79 self.executor_server.release('.*-merge')
80 self.waitUntilSettled()
81 self.executor_server.hold_jobs_in_build = False
82 self.executor_server.release()
83 self.waitUntilSettled()
84
85 self.assertEqual(AM2.queried, 0)
86 self.assertEqual(BM2.queried, 0)
87 self.assertEqual(A.data['status'], 'MERGED')
88 self.assertEqual(B.data['status'], 'MERGED')
89 self.assertEqual(A.reported, 2)
90 self.assertEqual(B.reported, 2)
91
92 changes = self.getJobFromHistory(
93 'project-merge', 'org/project1').changes
94 self.assertEqual(changes, '2,1 1,1')
95
James E. Blaira86134f2018-01-16 13:32:14 -080096 def test_crd_gate_triangle(self):
97 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
98 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
99 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
100 A.addApproval('Code-Review', 2)
101 B.addApproval('Code-Review', 2)
102 C.addApproval('Code-Review', 2)
103 A.addApproval('Approved', 1)
104 B.addApproval('Approved', 1)
105
106 # C-->B
107 # \ /
108 # v
109 # A
110
111 # C Depends-On: A
112 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
113 C.subject, A.data['url'])
114 # B Depends-On: A
115 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
116 B.subject, A.data['url'])
117 # C git-depends on B
118 C.setDependsOn(B, 1)
119 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
120 self.waitUntilSettled()
121
122 self.assertEqual(A.reported, 2)
123 self.assertEqual(B.reported, 2)
124 self.assertEqual(C.reported, 2)
125 self.assertEqual(A.data['status'], 'MERGED')
126 self.assertEqual(B.data['status'], 'MERGED')
127 self.assertEqual(C.data['status'], 'MERGED')
128 self.assertEqual(self.history[-1].changes, '1,1 2,1 3,1')
129
James E. Blair1c2023c2018-01-08 09:42:22 -0800130 def test_crd_branch(self):
131 "Test cross-repo dependencies in multiple branches"
132
133 self.create_branch('org/project2', 'mp')
134 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
135 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
136 C1 = self.fake_gerrit.addFakeChange('org/project2', 'mp', 'C1')
James E. Blair1c2023c2018-01-08 09:42:22 -0800137
138 A.addApproval('Code-Review', 2)
139 B.addApproval('Code-Review', 2)
140 C1.addApproval('Code-Review', 2)
141
142 # A Depends-On: B+C1
James E. Blair0e4c7912018-01-02 14:20:17 -0800143 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
144 A.subject, B.data['url'], C1.data['url'])
James E. Blair1c2023c2018-01-08 09:42:22 -0800145
146 self.executor_server.hold_jobs_in_build = True
147 B.addApproval('Approved', 1)
148 C1.addApproval('Approved', 1)
149 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
150 self.waitUntilSettled()
151
152 self.executor_server.release('.*-merge')
153 self.waitUntilSettled()
154 self.executor_server.release('.*-merge')
155 self.waitUntilSettled()
156 self.executor_server.release('.*-merge')
157 self.waitUntilSettled()
158 self.executor_server.hold_jobs_in_build = False
159 self.executor_server.release()
160 self.waitUntilSettled()
161
162 self.assertEqual(A.data['status'], 'MERGED')
163 self.assertEqual(B.data['status'], 'MERGED')
164 self.assertEqual(C1.data['status'], 'MERGED')
165 self.assertEqual(A.reported, 2)
166 self.assertEqual(B.reported, 2)
167 self.assertEqual(C1.reported, 2)
168
169 changes = self.getJobFromHistory(
170 'project-merge', 'org/project1').changes
171 self.assertEqual(changes, '2,1 3,1 1,1')
172
173 def test_crd_multiline(self):
174 "Test multiple depends-on lines in commit"
175 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
176 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
177 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
178 A.addApproval('Code-Review', 2)
179 B.addApproval('Code-Review', 2)
180 C.addApproval('Code-Review', 2)
181
182 # A Depends-On: B+C
183 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
184 A.subject, B.data['url'], C.data['url'])
185
186 self.executor_server.hold_jobs_in_build = True
187 B.addApproval('Approved', 1)
188 C.addApproval('Approved', 1)
189 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
190 self.waitUntilSettled()
191
192 self.executor_server.release('.*-merge')
193 self.waitUntilSettled()
194 self.executor_server.release('.*-merge')
195 self.waitUntilSettled()
196 self.executor_server.release('.*-merge')
197 self.waitUntilSettled()
198 self.executor_server.hold_jobs_in_build = False
199 self.executor_server.release()
200 self.waitUntilSettled()
201
202 self.assertEqual(A.data['status'], 'MERGED')
203 self.assertEqual(B.data['status'], 'MERGED')
204 self.assertEqual(C.data['status'], 'MERGED')
205 self.assertEqual(A.reported, 2)
206 self.assertEqual(B.reported, 2)
207 self.assertEqual(C.reported, 2)
208
209 changes = self.getJobFromHistory(
210 'project-merge', 'org/project1').changes
211 self.assertEqual(changes, '2,1 3,1 1,1')
212
213 def test_crd_unshared_gate(self):
214 "Test cross-repo dependencies in unshared gate queues"
215 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
216 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
217 A.addApproval('Code-Review', 2)
218 B.addApproval('Code-Review', 2)
219
220 # A Depends-On: B
221 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
222 A.subject, B.data['url'])
223
224 # A and B do not share a queue, make sure that A is unable to
225 # enqueue B (and therefore, A is unable to be enqueued).
226 B.addApproval('Approved', 1)
227 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
228 self.waitUntilSettled()
229
230 self.assertEqual(A.data['status'], 'NEW')
231 self.assertEqual(B.data['status'], 'NEW')
232 self.assertEqual(A.reported, 0)
233 self.assertEqual(B.reported, 0)
234 self.assertEqual(len(self.history), 0)
235
236 # Enqueue and merge B alone.
237 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
238 self.waitUntilSettled()
239
240 self.assertEqual(B.data['status'], 'MERGED')
241 self.assertEqual(B.reported, 2)
242
243 # Now that B is merged, A should be able to be enqueued and
244 # merged.
245 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
246 self.waitUntilSettled()
247
248 self.assertEqual(A.data['status'], 'MERGED')
249 self.assertEqual(A.reported, 2)
250
251 def test_crd_gate_reverse(self):
252 "Test reverse cross-repo dependencies"
253 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
254 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
255 A.addApproval('Code-Review', 2)
256 B.addApproval('Code-Review', 2)
257
258 # A Depends-On: B
259
260 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
261 A.subject, B.data['url'])
262
263 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
264 self.waitUntilSettled()
265
266 self.assertEqual(A.data['status'], 'NEW')
267 self.assertEqual(B.data['status'], 'NEW')
268
269 self.executor_server.hold_jobs_in_build = True
270 A.addApproval('Approved', 1)
271 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
272 self.waitUntilSettled()
273
274 self.executor_server.release('.*-merge')
275 self.waitUntilSettled()
276 self.executor_server.release('.*-merge')
277 self.waitUntilSettled()
278 self.executor_server.hold_jobs_in_build = False
279 self.executor_server.release()
280 self.waitUntilSettled()
281
282 self.assertEqual(A.data['status'], 'MERGED')
283 self.assertEqual(B.data['status'], 'MERGED')
284 self.assertEqual(A.reported, 2)
285 self.assertEqual(B.reported, 2)
286
287 changes = self.getJobFromHistory(
288 'project-merge', 'org/project1').changes
289 self.assertEqual(changes, '2,1 1,1')
290
291 def test_crd_cycle(self):
292 "Test cross-repo dependency cycles"
293 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
294 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
295 A.addApproval('Code-Review', 2)
296 B.addApproval('Code-Review', 2)
James E. Blaira86134f2018-01-16 13:32:14 -0800297 B.addApproval('Approved', 1)
James E. Blair1c2023c2018-01-08 09:42:22 -0800298
299 # A -> B -> A (via commit-depends)
300
301 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
302 A.subject, B.data['url'])
303 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
304 B.subject, A.data['url'])
305
306 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
307 self.waitUntilSettled()
308
309 self.assertEqual(A.reported, 0)
310 self.assertEqual(B.reported, 0)
311 self.assertEqual(A.data['status'], 'NEW')
312 self.assertEqual(B.data['status'], 'NEW')
313
314 def test_crd_gate_unknown(self):
315 "Test unknown projects in dependent pipeline"
316 self.init_repo("org/unknown", tag='init')
317 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
318 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'B')
319 A.addApproval('Code-Review', 2)
320 B.addApproval('Code-Review', 2)
321
322 # A Depends-On: B
323 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
324 A.subject, B.data['url'])
325
326 B.addApproval('Approved', 1)
327 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
328 self.waitUntilSettled()
329
330 # Unknown projects cannot share a queue with any other
331 # since they don't have common jobs with any other (they have no jobs).
332 # Changes which depend on unknown project changes
333 # should not be processed in dependent pipeline
334 self.assertEqual(A.data['status'], 'NEW')
335 self.assertEqual(B.data['status'], 'NEW')
336 self.assertEqual(A.reported, 0)
337 self.assertEqual(B.reported, 0)
338 self.assertEqual(len(self.history), 0)
339
340 # Simulate change B being gated outside this layout Set the
341 # change merged before submitting the event so that when the
342 # event triggers a gerrit query to update the change, we get
343 # the information that it was merged.
344 B.setMerged()
345 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
346 self.waitUntilSettled()
347 self.assertEqual(len(self.history), 0)
348
349 # Now that B is merged, A should be able to be enqueued and
350 # merged.
351 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
352 self.waitUntilSettled()
353
354 self.assertEqual(A.data['status'], 'MERGED')
355 self.assertEqual(A.reported, 2)
356 self.assertEqual(B.data['status'], 'MERGED')
357 self.assertEqual(B.reported, 0)
358
359 def test_crd_check(self):
360 "Test cross-repo dependencies in independent pipelines"
361
362 self.executor_server.hold_jobs_in_build = True
363 self.gearman_server.hold_jobs_in_queue = True
364 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
365 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
366
367 # A Depends-On: B
368 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
369 A.subject, B.data['url'])
370
371 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
372 self.waitUntilSettled()
373
374 self.gearman_server.hold_jobs_in_queue = False
375 self.gearman_server.release()
376 self.waitUntilSettled()
377
378 self.executor_server.release('.*-merge')
379 self.waitUntilSettled()
380
381 self.assertTrue(self.builds[0].hasChanges(A, B))
382
383 self.executor_server.hold_jobs_in_build = False
384 self.executor_server.release()
385 self.waitUntilSettled()
386
387 self.assertEqual(A.data['status'], 'NEW')
388 self.assertEqual(B.data['status'], 'NEW')
389 self.assertEqual(A.reported, 1)
390 self.assertEqual(B.reported, 0)
391
392 self.assertEqual(self.history[0].changes, '2,1 1,1')
393 tenant = self.sched.abide.tenants.get('tenant-one')
394 self.assertEqual(len(tenant.layout.pipelines['check'].queues), 0)
395
396 def test_crd_check_git_depends(self):
397 "Test single-repo dependencies in independent pipelines"
398 self.gearman_server.hold_jobs_in_build = True
399 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
400 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
401
402 # Add two git-dependent changes and make sure they both report
403 # success.
404 B.setDependsOn(A, 1)
405 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
406 self.waitUntilSettled()
407 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
408 self.waitUntilSettled()
409
410 self.orderedRelease()
411 self.gearman_server.hold_jobs_in_build = False
412 self.waitUntilSettled()
413
414 self.assertEqual(A.data['status'], 'NEW')
415 self.assertEqual(B.data['status'], 'NEW')
416 self.assertEqual(A.reported, 1)
417 self.assertEqual(B.reported, 1)
418
419 self.assertEqual(self.history[0].changes, '1,1')
420 self.assertEqual(self.history[-1].changes, '1,1 2,1')
421 tenant = self.sched.abide.tenants.get('tenant-one')
422 self.assertEqual(len(tenant.layout.pipelines['check'].queues), 0)
423
424 self.assertIn('Build succeeded', A.messages[0])
425 self.assertIn('Build succeeded', B.messages[0])
426
427 def test_crd_check_duplicate(self):
428 "Test duplicate check in independent pipelines"
429 self.executor_server.hold_jobs_in_build = True
430 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
431 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
432 tenant = self.sched.abide.tenants.get('tenant-one')
433 check_pipeline = tenant.layout.pipelines['check']
434
435 # Add two git-dependent changes...
436 B.setDependsOn(A, 1)
437 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
438 self.waitUntilSettled()
439 self.assertEqual(len(check_pipeline.getAllItems()), 2)
440
441 # ...make sure the live one is not duplicated...
442 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
443 self.waitUntilSettled()
444 self.assertEqual(len(check_pipeline.getAllItems()), 2)
445
446 # ...but the non-live one is able to be.
447 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
448 self.waitUntilSettled()
449 self.assertEqual(len(check_pipeline.getAllItems()), 3)
450
451 # Release jobs in order to avoid races with change A jobs
452 # finishing before change B jobs.
453 self.orderedRelease()
454 self.executor_server.hold_jobs_in_build = False
455 self.executor_server.release()
456 self.waitUntilSettled()
457
458 self.assertEqual(A.data['status'], 'NEW')
459 self.assertEqual(B.data['status'], 'NEW')
460 self.assertEqual(A.reported, 1)
461 self.assertEqual(B.reported, 1)
462
463 self.assertEqual(self.history[0].changes, '1,1 2,1')
464 self.assertEqual(self.history[1].changes, '1,1')
465 self.assertEqual(len(tenant.layout.pipelines['check'].queues), 0)
466
467 self.assertIn('Build succeeded', A.messages[0])
468 self.assertIn('Build succeeded', B.messages[0])
469
470 def _test_crd_check_reconfiguration(self, project1, project2):
471 "Test cross-repo dependencies re-enqueued in independent pipelines"
472
473 self.gearman_server.hold_jobs_in_queue = True
474 A = self.fake_gerrit.addFakeChange(project1, 'master', 'A')
475 B = self.fake_gerrit.addFakeChange(project2, 'master', 'B')
476
477 # A Depends-On: B
478 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
479 A.subject, B.data['url'])
480
481 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
482 self.waitUntilSettled()
483
484 self.sched.reconfigure(self.config)
485
486 # Make sure the items still share a change queue, and the
487 # first one is not live.
488 tenant = self.sched.abide.tenants.get('tenant-one')
489 self.assertEqual(len(tenant.layout.pipelines['check'].queues), 1)
490 queue = tenant.layout.pipelines['check'].queues[0]
491 first_item = queue.queue[0]
492 for item in queue.queue:
493 self.assertEqual(item.queue, first_item.queue)
494 self.assertFalse(first_item.live)
495 self.assertTrue(queue.queue[1].live)
496
497 self.gearman_server.hold_jobs_in_queue = False
498 self.gearman_server.release()
499 self.waitUntilSettled()
500
501 self.assertEqual(A.data['status'], 'NEW')
502 self.assertEqual(B.data['status'], 'NEW')
503 self.assertEqual(A.reported, 1)
504 self.assertEqual(B.reported, 0)
505
506 self.assertEqual(self.history[0].changes, '2,1 1,1')
507 self.assertEqual(len(tenant.layout.pipelines['check'].queues), 0)
508
509 def test_crd_check_reconfiguration(self):
510 self._test_crd_check_reconfiguration('org/project1', 'org/project2')
511
512 def test_crd_undefined_project(self):
513 """Test that undefined projects in dependencies are handled for
514 independent pipelines"""
515 # It's a hack for fake gerrit,
516 # as it implies repo creation upon the creation of any change
517 self.init_repo("org/unknown", tag='init')
518 self._test_crd_check_reconfiguration('org/project1', 'org/unknown')
519
520 @simple_layout('layouts/ignore-dependencies.yaml')
521 def test_crd_check_ignore_dependencies(self):
522 "Test cross-repo dependencies can be ignored"
523
524 self.gearman_server.hold_jobs_in_queue = True
525 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
526 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
527 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
528
529 # A Depends-On: B
530 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
531 A.subject, B.data['url'])
532 # C git-depends on B
533 C.setDependsOn(B, 1)
534 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
535 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
536 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
537 self.waitUntilSettled()
538
539 # Make sure none of the items share a change queue, and all
540 # are live.
541 tenant = self.sched.abide.tenants.get('tenant-one')
542 check_pipeline = tenant.layout.pipelines['check']
543 self.assertEqual(len(check_pipeline.queues), 3)
544 self.assertEqual(len(check_pipeline.getAllItems()), 3)
545 for item in check_pipeline.getAllItems():
546 self.assertTrue(item.live)
547
548 self.gearman_server.hold_jobs_in_queue = False
549 self.gearman_server.release()
550 self.waitUntilSettled()
551
552 self.assertEqual(A.data['status'], 'NEW')
553 self.assertEqual(B.data['status'], 'NEW')
554 self.assertEqual(C.data['status'], 'NEW')
555 self.assertEqual(A.reported, 1)
556 self.assertEqual(B.reported, 1)
557 self.assertEqual(C.reported, 1)
558
559 # Each job should have tested exactly one change
560 for job in self.history:
561 self.assertEqual(len(job.changes.split()), 1)
562
James E. Blaira86134f2018-01-16 13:32:14 -0800563 def test_crd_check_triangle(self):
564 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
565 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
566 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
567
568 # C-->B
569 # \ /
570 # v
571 # A
572
573 # C Depends-On: A
574 C.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
575 C.subject, A.data['url'])
576 # B Depends-On: A
577 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
578 B.subject, A.data['url'])
579 # C git-depends on B
580 C.setDependsOn(B, 1)
581 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
582 self.waitUntilSettled()
583
584 self.assertEqual(C.reported, 1)
585 self.assertEqual(self.history[0].changes, '1,1 2,1 3,1')
586
James E. Blair1c2023c2018-01-08 09:42:22 -0800587 @simple_layout('layouts/three-projects.yaml')
588 def test_crd_check_transitive(self):
589 "Test transitive cross-repo dependencies"
590 # Specifically, if A -> B -> C, and C gets a new patchset and
591 # A gets a new patchset, ensure the test of A,2 includes B,1
592 # and C,2 (not C,1 which would indicate stale data in the
593 # cache for B).
594 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
595 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
596 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
597
598 # A Depends-On: B
599 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
600 A.subject, B.data['url'])
601
602 # B Depends-On: C
603 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
604 B.subject, C.data['url'])
605
606 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
607 self.waitUntilSettled()
608 self.assertEqual(self.history[-1].changes, '3,1 2,1 1,1')
609
610 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
611 self.waitUntilSettled()
612 self.assertEqual(self.history[-1].changes, '3,1 2,1')
613
614 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
615 self.waitUntilSettled()
616 self.assertEqual(self.history[-1].changes, '3,1')
617
618 C.addPatchset()
619 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(2))
620 self.waitUntilSettled()
621 self.assertEqual(self.history[-1].changes, '3,2')
622
623 A.addPatchset()
624 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
625 self.waitUntilSettled()
626 self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
627
628 def test_crd_check_unknown(self):
629 "Test unknown projects in independent pipeline"
630 self.init_repo("org/unknown", tag='init')
631 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
632 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'D')
633 # A Depends-On: B
634 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
635 A.subject, B.data['url'])
636
637 # Make sure zuul has seen an event on B.
638 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
639 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
640 self.waitUntilSettled()
641
642 self.assertEqual(A.data['status'], 'NEW')
643 self.assertEqual(A.reported, 1)
644 self.assertEqual(B.data['status'], 'NEW')
645 self.assertEqual(B.reported, 0)
646
647 def test_crd_cycle_join(self):
648 "Test an updated change creates a cycle"
649 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
650
651 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
652 self.waitUntilSettled()
653 self.assertEqual(A.reported, 1)
654
655 # Create B->A
656 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
657 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
658 B.subject, A.data['url'])
659 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
660 self.waitUntilSettled()
661
662 # Dep is there so zuul should have reported on B
663 self.assertEqual(B.reported, 1)
664
665 # Update A to add A->B (a cycle).
666 A.addPatchset()
667 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
668 A.subject, B.data['url'])
669 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
670 self.waitUntilSettled()
671
672 # Dependency cycle injected so zuul should not have reported again on A
673 self.assertEqual(A.reported, 1)
674
675 # Now if we update B to remove the depends-on, everything
676 # should be okay. B; A->B
677
678 B.addPatchset()
679 B.data['commitMessage'] = '%s\n' % (B.subject,)
680 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
681 self.waitUntilSettled()
682
683 # Cycle was removed so now zuul should have reported again on A
684 self.assertEqual(A.reported, 2)
685
686 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
687 self.waitUntilSettled()
688 self.assertEqual(B.reported, 2)