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