blob: df6bc1bcf48d3d19a640f4e2a093d2183b5224e6 [file] [log] [blame]
James E. Blairb0fcae42012-07-17 11:12:10 -07001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
James E. Blairb0fcae42012-07-17 11:12:10 -070017import json
Monty Taylorbc758832013-06-17 17:22:42 -040018import logging
19import os
James E. Blairb0fcae42012-07-17 11:12:10 -070020import re
James E. Blair4886cc12012-07-18 15:39:41 -070021import shutil
Monty Taylorbc758832013-06-17 17:22:42 -040022import time
Maru Newby3fe5f852015-01-13 04:22:14 +000023import yaml
Monty Taylorbc758832013-06-17 17:22:42 -040024
James E. Blair4886cc12012-07-18 15:39:41 -070025import git
Morgan Fainberg293f7f82016-05-30 14:01:22 -070026from six.moves import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040027import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070028
Maru Newby3fe5f852015-01-13 04:22:14 +000029import zuul.change_matcher
James E. Blairb0fcae42012-07-17 11:12:10 -070030import zuul.scheduler
James E. Blairad28e912013-11-27 10:43:22 -080031import zuul.rpcclient
Joshua Hesketh1879cf72013-08-19 14:13:15 +100032import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100033import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070034
Maru Newby3fe5f852015-01-13 04:22:14 +000035from tests.base import (
36 BaseTestCase,
37 ZuulTestCase,
38 repack_repo,
39)
James E. Blairb0fcae42012-07-17 11:12:10 -070040
James E. Blair1f4c2bb2013-04-26 08:40:46 -070041logging.basicConfig(level=logging.DEBUG,
42 format='%(asctime)s %(name)-32s '
43 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070044
45
Maru Newby3fe5f852015-01-13 04:22:14 +000046class TestSchedulerConfigParsing(BaseTestCase):
47
James E. Blair83005782015-12-11 14:46:03 -080048 def setUp(self):
49 self.skip("Disabled for early v3 development")
50
Maru Newby3fe5f852015-01-13 04:22:14 +000051 def test_parse_skip_if(self):
52 job_yaml = """
53jobs:
54 - name: job_name
55 skip-if:
56 - project: ^project_name$
57 branch: ^stable/icehouse$
58 all-files-match-any:
59 - ^filename$
60 - project: ^project2_name$
61 all-files-match-any:
62 - ^filename2$
63 """.strip()
64 data = yaml.load(job_yaml)
65 config_job = data.get('jobs')[0]
Joshua Hesketh352264b2015-08-11 23:42:08 +100066 sched = zuul.scheduler.Scheduler({})
Maru Newby3fe5f852015-01-13 04:22:14 +000067 cm = zuul.change_matcher
68 expected = cm.MatchAny([
69 cm.MatchAll([
70 cm.ProjectMatcher('^project_name$'),
71 cm.BranchMatcher('^stable/icehouse$'),
72 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
73 ]),
74 cm.MatchAll([
75 cm.ProjectMatcher('^project2_name$'),
76 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
77 ]),
78 ])
79 matcher = sched._parseSkipIf(config_job)
80 self.assertEqual(expected, matcher)
81
82
Clark Boylanb640e052014-04-03 16:41:46 -070083class TestScheduler(ZuulTestCase):
Antoine Mussobd86a312014-01-08 14:51:33 +010084
James E. Blair509cada2015-12-08 16:31:16 -080085 def setUp(self):
86 self.skip("Disabled for early v3 development")
87
James E. Blairb0fcae42012-07-17 11:12:10 -070088 def test_jobs_launched(self):
89 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -070090
James E. Blairb0fcae42012-07-17 11:12:10 -070091 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -070092 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070093 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
94 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -040095 self.assertEqual(self.getJobFromHistory('project-merge').result,
96 'SUCCESS')
97 self.assertEqual(self.getJobFromHistory('project-test1').result,
98 'SUCCESS')
99 self.assertEqual(self.getJobFromHistory('project-test2').result,
100 'SUCCESS')
101 self.assertEqual(A.data['status'], 'MERGED')
102 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700103
James E. Blair66eeebf2013-07-27 17:44:32 -0700104 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
105 self.assertReportedStat('zuul.pipeline.gate.current_changes',
106 value='1|g')
107 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
108 kind='ms')
109 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
110 value='1|c')
111 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
112 self.assertReportedStat('zuul.pipeline.gate.total_changes',
113 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700114 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700115 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -0700116 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700117 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700118
James E. Blair5821bd92015-09-16 08:48:15 -0700119 for build in self.builds:
120 self.assertEqual(build.parameters['ZUUL_VOTING'], '1')
121
James E. Blair3cb10702013-08-24 08:56:03 -0700122 def test_initial_pipeline_gauges(self):
123 "Test that each pipeline reported its length on start"
124 pipeline_names = self.sched.layout.pipelines.keys()
125 self.assertNotEqual(len(pipeline_names), 0)
126 for name in pipeline_names:
127 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
128 value='0|g')
129
James E. Blair42f74822013-05-14 15:18:03 -0700130 def test_duplicate_pipelines(self):
131 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -0700132
James E. Blair42f74822013-05-14 15:18:03 -0700133 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
134 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
135 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -0700136
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400137 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400138 self.history[0].name == 'project-test1'
139 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -0700140
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400141 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -0700142 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400143 self.assertIn('dup1/project-test1', A.messages[0])
144 self.assertNotIn('dup2/project-test1', A.messages[0])
145 self.assertNotIn('dup1/project-test1', A.messages[1])
146 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -0700147 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400148 self.assertIn('dup1/project-test1', A.messages[1])
149 self.assertNotIn('dup2/project-test1', A.messages[1])
150 self.assertNotIn('dup1/project-test1', A.messages[0])
151 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -0700152
James E. Blairb0fcae42012-07-17 11:12:10 -0700153 def test_parallel_changes(self):
154 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700155
156 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700157 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
158 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
159 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700160 A.addApproval('CRVW', 2)
161 B.addApproval('CRVW', 2)
162 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700163
164 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
165 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
166 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
167
168 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400169 self.assertEqual(len(self.builds), 1)
170 self.assertEqual(self.builds[0].name, 'project-merge')
171 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700172
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700173 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700174 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400175 self.assertEqual(len(self.builds), 3)
176 self.assertEqual(self.builds[0].name, 'project-test1')
177 self.assertTrue(self.job_has_changes(self.builds[0], A))
178 self.assertEqual(self.builds[1].name, 'project-test2')
179 self.assertTrue(self.job_has_changes(self.builds[1], A))
180 self.assertEqual(self.builds[2].name, 'project-merge')
181 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700182
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700183 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700184 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400185 self.assertEqual(len(self.builds), 5)
186 self.assertEqual(self.builds[0].name, 'project-test1')
187 self.assertTrue(self.job_has_changes(self.builds[0], A))
188 self.assertEqual(self.builds[1].name, 'project-test2')
189 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700190
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400191 self.assertEqual(self.builds[2].name, 'project-test1')
192 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
193 self.assertEqual(self.builds[3].name, 'project-test2')
194 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700195
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400196 self.assertEqual(self.builds[4].name, 'project-merge')
197 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700198
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700199 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700200 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400201 self.assertEqual(len(self.builds), 6)
202 self.assertEqual(self.builds[0].name, 'project-test1')
203 self.assertTrue(self.job_has_changes(self.builds[0], A))
204 self.assertEqual(self.builds[1].name, 'project-test2')
205 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700206
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400207 self.assertEqual(self.builds[2].name, 'project-test1')
208 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
209 self.assertEqual(self.builds[3].name, 'project-test2')
210 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700211
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400212 self.assertEqual(self.builds[4].name, 'project-test1')
213 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
214 self.assertEqual(self.builds[5].name, 'project-test2')
215 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700216
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700217 self.worker.hold_jobs_in_build = False
218 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700219 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400220 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -0700221
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400222 self.assertEqual(len(self.history), 9)
223 self.assertEqual(A.data['status'], 'MERGED')
224 self.assertEqual(B.data['status'], 'MERGED')
225 self.assertEqual(C.data['status'], 'MERGED')
226 self.assertEqual(A.reported, 2)
227 self.assertEqual(B.reported, 2)
228 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700229
230 def test_failed_changes(self):
231 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -0400232 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700233
James E. Blairb02a3bb2012-07-30 17:49:55 -0700234 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
235 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700236 A.addApproval('CRVW', 2)
237 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700238
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700239 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700240
James E. Blaire2819012013-06-28 17:17:26 -0400241 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
242 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700243 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -0400244
245 self.worker.release('.*-merge')
246 self.waitUntilSettled()
247
248 self.worker.hold_jobs_in_build = False
249 self.worker.release()
250
251 self.waitUntilSettled()
252 # It's certain that the merge job for change 2 will run, but
253 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400254 self.assertTrue(len(self.history) > 6)
255 self.assertEqual(A.data['status'], 'NEW')
256 self.assertEqual(B.data['status'], 'MERGED')
257 self.assertEqual(A.reported, 2)
258 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700259
260 def test_independent_queues(self):
261 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700262
263 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900264 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700265 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
266 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700267 A.addApproval('CRVW', 2)
268 B.addApproval('CRVW', 2)
269 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700270
271 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
272 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
273 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
274
James E. Blairb02a3bb2012-07-30 17:49:55 -0700275 self.waitUntilSettled()
276
277 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400278 self.assertEqual(len(self.builds), 2)
279 self.assertEqual(self.builds[0].name, 'project-merge')
280 self.assertTrue(self.job_has_changes(self.builds[0], A))
281 self.assertEqual(self.builds[1].name, 'project1-merge')
282 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700283
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700284 # Release the current merge builds
285 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700286 self.waitUntilSettled()
287 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700288 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700289 self.waitUntilSettled()
290
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700291 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -0700292 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400293 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700294
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700295 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700296 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400297 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700298
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400299 self.assertEqual(len(self.history), 11)
300 self.assertEqual(A.data['status'], 'MERGED')
301 self.assertEqual(B.data['status'], 'MERGED')
302 self.assertEqual(C.data['status'], 'MERGED')
303 self.assertEqual(A.reported, 2)
304 self.assertEqual(B.reported, 2)
305 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700306
307 def test_failed_change_at_head(self):
308 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700309
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700310 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -0700311 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
312 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
313 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700314 A.addApproval('CRVW', 2)
315 B.addApproval('CRVW', 2)
316 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700317
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700318 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700319
320 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
321 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
322 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
323
324 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -0700325
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400326 self.assertEqual(len(self.builds), 1)
327 self.assertEqual(self.builds[0].name, 'project-merge')
328 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700329
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700330 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700331 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700332 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700333 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700334 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700335 self.waitUntilSettled()
336
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400337 self.assertEqual(len(self.builds), 6)
338 self.assertEqual(self.builds[0].name, 'project-test1')
339 self.assertEqual(self.builds[1].name, 'project-test2')
340 self.assertEqual(self.builds[2].name, 'project-test1')
341 self.assertEqual(self.builds[3].name, 'project-test2')
342 self.assertEqual(self.builds[4].name, 'project-test1')
343 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700344
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400345 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700346 self.waitUntilSettled()
347
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400348 # project-test2, project-merge for B
349 self.assertEqual(len(self.builds), 2)
350 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -0700351
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700352 self.worker.hold_jobs_in_build = False
353 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700354 self.waitUntilSettled()
355
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400356 self.assertEqual(len(self.builds), 0)
357 self.assertEqual(len(self.history), 15)
358 self.assertEqual(A.data['status'], 'NEW')
359 self.assertEqual(B.data['status'], 'MERGED')
360 self.assertEqual(C.data['status'], 'MERGED')
361 self.assertEqual(A.reported, 2)
362 self.assertEqual(B.reported, 2)
363 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700364
James E. Blair0aac4872013-08-23 14:02:38 -0700365 def test_failed_change_in_middle(self):
366 "Test a failed change in the middle of the queue"
367
368 self.worker.hold_jobs_in_build = True
369 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
370 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
371 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
372 A.addApproval('CRVW', 2)
373 B.addApproval('CRVW', 2)
374 C.addApproval('CRVW', 2)
375
376 self.worker.addFailTest('project-test1', B)
377
378 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
379 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
380 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
381
382 self.waitUntilSettled()
383
384 self.worker.release('.*-merge')
385 self.waitUntilSettled()
386 self.worker.release('.*-merge')
387 self.waitUntilSettled()
388 self.worker.release('.*-merge')
389 self.waitUntilSettled()
390
391 self.assertEqual(len(self.builds), 6)
392 self.assertEqual(self.builds[0].name, 'project-test1')
393 self.assertEqual(self.builds[1].name, 'project-test2')
394 self.assertEqual(self.builds[2].name, 'project-test1')
395 self.assertEqual(self.builds[3].name, 'project-test2')
396 self.assertEqual(self.builds[4].name, 'project-test1')
397 self.assertEqual(self.builds[5].name, 'project-test2')
398
399 self.release(self.builds[2])
400 self.waitUntilSettled()
401
James E. Blair972e3c72013-08-29 12:04:55 -0700402 # project-test1 and project-test2 for A
403 # project-test2 for B
404 # project-merge for C (without B)
405 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -0700406 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
407
James E. Blair972e3c72013-08-29 12:04:55 -0700408 self.worker.release('.*-merge')
409 self.waitUntilSettled()
410
411 # project-test1 and project-test2 for A
412 # project-test2 for B
413 # project-test1 and project-test2 for C
414 self.assertEqual(len(self.builds), 5)
415
James E. Blair0aac4872013-08-23 14:02:38 -0700416 items = self.sched.layout.pipelines['gate'].getAllItems()
417 builds = items[0].current_build_set.getBuilds()
418 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
419 self.assertEqual(self.countJobResults(builds, None), 2)
420 builds = items[1].current_build_set.getBuilds()
421 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
422 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
423 self.assertEqual(self.countJobResults(builds, None), 1)
424 builds = items[2].current_build_set.getBuilds()
425 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -0700426 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -0700427
428 self.worker.hold_jobs_in_build = False
429 self.worker.release()
430 self.waitUntilSettled()
431
432 self.assertEqual(len(self.builds), 0)
433 self.assertEqual(len(self.history), 12)
434 self.assertEqual(A.data['status'], 'MERGED')
435 self.assertEqual(B.data['status'], 'NEW')
436 self.assertEqual(C.data['status'], 'MERGED')
437 self.assertEqual(A.reported, 2)
438 self.assertEqual(B.reported, 2)
439 self.assertEqual(C.reported, 2)
440
James E. Blaird466dc42012-07-31 10:42:56 -0700441 def test_failed_change_at_head_with_queue(self):
442 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700443
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700444 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -0700445 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
446 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
447 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700448 A.addApproval('CRVW', 2)
449 B.addApproval('CRVW', 2)
450 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700451
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700452 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700453
454 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
455 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
456 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
457
458 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700459 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400460 self.assertEqual(len(self.builds), 0)
461 self.assertEqual(len(queue), 1)
462 self.assertEqual(queue[0].name, 'build:project-merge')
463 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700464
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700465 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700466 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700467 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700468 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700469 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700470 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700471 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -0700472
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400473 self.assertEqual(len(self.builds), 0)
474 self.assertEqual(len(queue), 6)
475 self.assertEqual(queue[0].name, 'build:project-test1')
476 self.assertEqual(queue[1].name, 'build:project-test2')
477 self.assertEqual(queue[2].name, 'build:project-test1')
478 self.assertEqual(queue[3].name, 'build:project-test2')
479 self.assertEqual(queue[4].name, 'build:project-test1')
480 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700481
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700482 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700483 self.waitUntilSettled()
484
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400485 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -0700486 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400487 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
488 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -0700489
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700490 self.gearman_server.hold_jobs_in_queue = False
491 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700492 self.waitUntilSettled()
493
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400494 self.assertEqual(len(self.builds), 0)
495 self.assertEqual(len(self.history), 11)
496 self.assertEqual(A.data['status'], 'NEW')
497 self.assertEqual(B.data['status'], 'MERGED')
498 self.assertEqual(C.data['status'], 'MERGED')
499 self.assertEqual(A.reported, 2)
500 self.assertEqual(B.reported, 2)
501 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700502
James E. Blairce8a2132016-05-19 15:21:52 -0700503 def _test_time_database(self, iteration):
504 self.worker.hold_jobs_in_build = True
505 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
506 A.addApproval('CRVW', 2)
507 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
508 self.waitUntilSettled()
509 time.sleep(2)
510
511 data = json.loads(self.sched.formatStatusJSON())
512 found_job = None
513 for pipeline in data['pipelines']:
514 if pipeline['name'] != 'gate':
515 continue
516 for queue in pipeline['change_queues']:
517 for head in queue['heads']:
518 for item in head:
519 for job in item['jobs']:
520 if job['name'] == 'project-merge':
521 found_job = job
522 break
523
524 self.assertIsNotNone(found_job)
525 if iteration == 1:
526 self.assertIsNotNone(found_job['estimated_time'])
527 self.assertIsNone(found_job['remaining_time'])
528 else:
529 self.assertIsNotNone(found_job['estimated_time'])
530 self.assertTrue(found_job['estimated_time'] >= 2)
531 self.assertIsNotNone(found_job['remaining_time'])
532
533 self.worker.hold_jobs_in_build = False
534 self.worker.release()
535 self.waitUntilSettled()
536
537 def test_time_database(self):
538 "Test the time database"
539
540 self._test_time_database(1)
541 self._test_time_database(2)
542
James E. Blairfef71632013-09-23 11:15:47 -0700543 def test_two_failed_changes_at_head(self):
544 "Test that changes are reparented correctly if 2 fail at head"
545
546 self.worker.hold_jobs_in_build = True
547 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
548 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
549 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
550 A.addApproval('CRVW', 2)
551 B.addApproval('CRVW', 2)
552 C.addApproval('CRVW', 2)
553
554 self.worker.addFailTest('project-test1', A)
555 self.worker.addFailTest('project-test1', B)
556
557 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
558 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
559 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
560 self.waitUntilSettled()
561
562 self.worker.release('.*-merge')
563 self.waitUntilSettled()
564 self.worker.release('.*-merge')
565 self.waitUntilSettled()
566 self.worker.release('.*-merge')
567 self.waitUntilSettled()
568
569 self.assertEqual(len(self.builds), 6)
570 self.assertEqual(self.builds[0].name, 'project-test1')
571 self.assertEqual(self.builds[1].name, 'project-test2')
572 self.assertEqual(self.builds[2].name, 'project-test1')
573 self.assertEqual(self.builds[3].name, 'project-test2')
574 self.assertEqual(self.builds[4].name, 'project-test1')
575 self.assertEqual(self.builds[5].name, 'project-test2')
576
577 self.assertTrue(self.job_has_changes(self.builds[0], A))
578 self.assertTrue(self.job_has_changes(self.builds[2], A))
579 self.assertTrue(self.job_has_changes(self.builds[2], B))
580 self.assertTrue(self.job_has_changes(self.builds[4], A))
581 self.assertTrue(self.job_has_changes(self.builds[4], B))
582 self.assertTrue(self.job_has_changes(self.builds[4], C))
583
584 # Fail change B first
585 self.release(self.builds[2])
586 self.waitUntilSettled()
587
588 # restart of C after B failure
589 self.worker.release('.*-merge')
590 self.waitUntilSettled()
591
592 self.assertEqual(len(self.builds), 5)
593 self.assertEqual(self.builds[0].name, 'project-test1')
594 self.assertEqual(self.builds[1].name, 'project-test2')
595 self.assertEqual(self.builds[2].name, 'project-test2')
596 self.assertEqual(self.builds[3].name, 'project-test1')
597 self.assertEqual(self.builds[4].name, 'project-test2')
598
599 self.assertTrue(self.job_has_changes(self.builds[1], A))
600 self.assertTrue(self.job_has_changes(self.builds[2], A))
601 self.assertTrue(self.job_has_changes(self.builds[2], B))
602 self.assertTrue(self.job_has_changes(self.builds[4], A))
603 self.assertFalse(self.job_has_changes(self.builds[4], B))
604 self.assertTrue(self.job_has_changes(self.builds[4], C))
605
606 # Finish running all passing jobs for change A
607 self.release(self.builds[1])
608 self.waitUntilSettled()
609 # Fail and report change A
610 self.release(self.builds[0])
611 self.waitUntilSettled()
612
613 # restart of B,C after A failure
614 self.worker.release('.*-merge')
615 self.waitUntilSettled()
616 self.worker.release('.*-merge')
617 self.waitUntilSettled()
618
619 self.assertEqual(len(self.builds), 4)
620 self.assertEqual(self.builds[0].name, 'project-test1') # B
621 self.assertEqual(self.builds[1].name, 'project-test2') # B
622 self.assertEqual(self.builds[2].name, 'project-test1') # C
623 self.assertEqual(self.builds[3].name, 'project-test2') # C
624
625 self.assertFalse(self.job_has_changes(self.builds[1], A))
626 self.assertTrue(self.job_has_changes(self.builds[1], B))
627 self.assertFalse(self.job_has_changes(self.builds[1], C))
628
629 self.assertFalse(self.job_has_changes(self.builds[2], A))
630 # After A failed and B and C restarted, B should be back in
631 # C's tests because it has not failed yet.
632 self.assertTrue(self.job_has_changes(self.builds[2], B))
633 self.assertTrue(self.job_has_changes(self.builds[2], C))
634
635 self.worker.hold_jobs_in_build = False
636 self.worker.release()
637 self.waitUntilSettled()
638
639 self.assertEqual(len(self.builds), 0)
640 self.assertEqual(len(self.history), 21)
641 self.assertEqual(A.data['status'], 'NEW')
642 self.assertEqual(B.data['status'], 'NEW')
643 self.assertEqual(C.data['status'], 'MERGED')
644 self.assertEqual(A.reported, 2)
645 self.assertEqual(B.reported, 2)
646 self.assertEqual(C.reported, 2)
647
James E. Blairce8a2132016-05-19 15:21:52 -0700648 def test_parse_skip_if(self):
649 job_yaml = """
650jobs:
651 - name: job_name
652 skip-if:
653 - project: ^project_name$
654 branch: ^stable/icehouse$
655 all-files-match-any:
656 - ^filename$
657 - project: ^project2_name$
658 all-files-match-any:
659 - ^filename2$
660 """.strip()
661 data = yaml.load(job_yaml)
662 config_job = data.get('jobs')[0]
663 cm = zuul.change_matcher
664 expected = cm.MatchAny([
665 cm.MatchAll([
666 cm.ProjectMatcher('^project_name$'),
667 cm.BranchMatcher('^stable/icehouse$'),
668 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
669 ]),
670 cm.MatchAll([
671 cm.ProjectMatcher('^project2_name$'),
672 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
673 ]),
674 ])
675 matcher = self.sched._parseSkipIf(config_job)
676 self.assertEqual(expected, matcher)
677
James E. Blair8c803f82012-07-31 16:25:42 -0700678 def test_patch_order(self):
679 "Test that dependent patches are tested in the right order"
680 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
681 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
682 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
683 A.addApproval('CRVW', 2)
684 B.addApproval('CRVW', 2)
685 C.addApproval('CRVW', 2)
686
687 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
688 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
689 M2.setMerged()
690 M1.setMerged()
691
692 # C -> B -> A -> M1 -> M2
693 # M2 is here to make sure it is never queried. If it is, it
694 # means zuul is walking down the entire history of merged
695 # changes.
696
697 C.setDependsOn(B, 1)
698 B.setDependsOn(A, 1)
699 A.setDependsOn(M1, 1)
700 M1.setDependsOn(M2, 1)
701
702 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
703
704 self.waitUntilSettled()
705
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400706 self.assertEqual(A.data['status'], 'NEW')
707 self.assertEqual(B.data['status'], 'NEW')
708 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -0700709
710 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
711 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
712
713 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400714 self.assertEqual(M2.queried, 0)
715 self.assertEqual(A.data['status'], 'MERGED')
716 self.assertEqual(B.data['status'], 'MERGED')
717 self.assertEqual(C.data['status'], 'MERGED')
718 self.assertEqual(A.reported, 2)
719 self.assertEqual(B.reported, 2)
720 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700721
James E. Blair063672f2015-01-29 13:09:12 -0800722 def test_needed_changes_enqueue(self):
723 "Test that a needed change is enqueued ahead"
724 # A Given a git tree like this, if we enqueue
725 # / \ change C, we should walk up and down the tree
726 # B G and enqueue changes in the order ABCDEFG.
727 # /|\ This is also the order that you would get if
728 # *C E F you enqueued changes in the order ABCDEFG, so
729 # / the ordering is stable across re-enqueue events.
730 # D
731
732 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
733 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
734 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
735 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
736 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
737 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
738 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
739 B.setDependsOn(A, 1)
740 C.setDependsOn(B, 1)
741 D.setDependsOn(C, 1)
742 E.setDependsOn(B, 1)
743 F.setDependsOn(B, 1)
744 G.setDependsOn(A, 1)
745
746 A.addApproval('CRVW', 2)
747 B.addApproval('CRVW', 2)
748 C.addApproval('CRVW', 2)
749 D.addApproval('CRVW', 2)
750 E.addApproval('CRVW', 2)
751 F.addApproval('CRVW', 2)
752 G.addApproval('CRVW', 2)
753 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
754
755 self.waitUntilSettled()
756
757 self.assertEqual(A.data['status'], 'NEW')
758 self.assertEqual(B.data['status'], 'NEW')
759 self.assertEqual(C.data['status'], 'NEW')
760 self.assertEqual(D.data['status'], 'NEW')
761 self.assertEqual(E.data['status'], 'NEW')
762 self.assertEqual(F.data['status'], 'NEW')
763 self.assertEqual(G.data['status'], 'NEW')
764
765 # We're about to add approvals to changes without adding the
766 # triggering events to Zuul, so that we can be sure that it is
767 # enqueing the changes based on dependencies, not because of
768 # triggering events. Since it will have the changes cached
769 # already (without approvals), we need to clear the cache
770 # first.
Joshua Hesketh4bd7da32016-02-17 20:58:47 +1100771 for connection in self.connections.values():
772 connection.maintainCache([])
James E. Blair063672f2015-01-29 13:09:12 -0800773
774 self.worker.hold_jobs_in_build = True
775 A.addApproval('APRV', 1)
776 B.addApproval('APRV', 1)
777 D.addApproval('APRV', 1)
778 E.addApproval('APRV', 1)
779 F.addApproval('APRV', 1)
780 G.addApproval('APRV', 1)
781 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
782
783 for x in range(8):
784 self.worker.release('.*-merge')
785 self.waitUntilSettled()
786 self.worker.hold_jobs_in_build = False
787 self.worker.release()
788 self.waitUntilSettled()
789
790 self.assertEqual(A.data['status'], 'MERGED')
791 self.assertEqual(B.data['status'], 'MERGED')
792 self.assertEqual(C.data['status'], 'MERGED')
793 self.assertEqual(D.data['status'], 'MERGED')
794 self.assertEqual(E.data['status'], 'MERGED')
795 self.assertEqual(F.data['status'], 'MERGED')
796 self.assertEqual(G.data['status'], 'MERGED')
797 self.assertEqual(A.reported, 2)
798 self.assertEqual(B.reported, 2)
799 self.assertEqual(C.reported, 2)
800 self.assertEqual(D.reported, 2)
801 self.assertEqual(E.reported, 2)
802 self.assertEqual(F.reported, 2)
803 self.assertEqual(G.reported, 2)
804 self.assertEqual(self.history[6].changes,
805 '1,1 2,1 3,1 4,1 5,1 6,1 7,1')
806
Joshua Hesketh850ccb62014-11-27 11:31:02 +1100807 def test_source_cache(self):
808 "Test that the source cache operates correctly"
James E. Blair0e933c52013-07-11 10:18:52 -0700809 self.worker.hold_jobs_in_build = True
810
811 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
812 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
813 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
814 A.addApproval('CRVW', 2)
815 B.addApproval('CRVW', 2)
816
817 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
818 M1.setMerged()
819
820 B.setDependsOn(A, 1)
821 A.setDependsOn(M1, 1)
822
823 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
824 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
825
826 self.waitUntilSettled()
827
828 for build in self.builds:
829 if build.parameters['ZUUL_PIPELINE'] == 'check':
830 build.release()
831 self.waitUntilSettled()
832 for build in self.builds:
833 if build.parameters['ZUUL_PIPELINE'] == 'check':
834 build.release()
835 self.waitUntilSettled()
836
837 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
838 self.waitUntilSettled()
839
Joshua Hesketh352264b2015-08-11 23:42:08 +1000840 self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -0700841 # there should still be changes in the cache
Joshua Hesketh352264b2015-08-11 23:42:08 +1000842 self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -0700843
844 self.worker.hold_jobs_in_build = False
845 self.worker.release()
846 self.waitUntilSettled()
847
848 self.assertEqual(A.data['status'], 'MERGED')
849 self.assertEqual(B.data['status'], 'MERGED')
850 self.assertEqual(A.queried, 2) # Initial and isMerged
851 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
852
James E. Blair8c803f82012-07-31 16:25:42 -0700853 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -0700854 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -0700855 # TODO: move to test_gerrit (this is a unit test!)
856 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairc0dedf82014-08-06 09:37:52 -0700857 source = self.sched.layout.pipelines['gate'].source
858 a = source._getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -0400859 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blairc0dedf82014-08-06 09:37:52 -0700860 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700861
862 A.addApproval('CRVW', 2)
James E. Blairc0dedf82014-08-06 09:37:52 -0700863 a = source._getChange(1, 2, refresh=True)
864 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700865
866 A.addApproval('APRV', 1)
James E. Blairc0dedf82014-08-06 09:37:52 -0700867 a = source._getChange(1, 2, refresh=True)
868 self.assertTrue(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair4886cc12012-07-18 15:39:41 -0700869
870 def test_build_configuration(self):
871 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700872
873 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -0700874 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
875 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
876 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
877 A.addApproval('CRVW', 2)
878 B.addApproval('CRVW', 2)
879 C.addApproval('CRVW', 2)
880 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
881 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
882 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
883 self.waitUntilSettled()
884
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700885 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700886 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700887 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700888 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700889 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700890 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700891 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700892 ref = self.getParameter(queue[-1], 'ZUUL_REF')
893 self.gearman_server.hold_jobs_in_queue = False
894 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700895 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -0700896
Monty Taylorbc758832013-06-17 17:22:42 -0400897 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -0700898 repo = git.Repo(path)
899 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
900 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -0700901 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400902 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -0700903
904 def test_build_configuration_conflict(self):
905 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700906
907 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -0700908 A = self.fake_gerrit.addFakeChange('org/conflict-project',
909 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -0700910 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700911 B = self.fake_gerrit.addFakeChange('org/conflict-project',
912 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -0700913 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700914 C = self.fake_gerrit.addFakeChange('org/conflict-project',
915 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -0700916 A.addApproval('CRVW', 2)
917 B.addApproval('CRVW', 2)
918 C.addApproval('CRVW', 2)
919 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
920 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
921 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
922 self.waitUntilSettled()
923
James E. Blair6736beb2013-07-11 15:18:15 -0700924 self.assertEqual(A.reported, 1)
925 self.assertEqual(B.reported, 1)
926 self.assertEqual(C.reported, 1)
927
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700928 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700929 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700930 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700931 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700932 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700933 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -0700934
935 self.assertEqual(len(self.history), 2) # A and C merge jobs
936
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700937 self.gearman_server.hold_jobs_in_queue = False
938 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700939 self.waitUntilSettled()
940
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400941 self.assertEqual(A.data['status'], 'MERGED')
942 self.assertEqual(B.data['status'], 'NEW')
943 self.assertEqual(C.data['status'], 'MERGED')
944 self.assertEqual(A.reported, 2)
945 self.assertEqual(B.reported, 2)
946 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -0700947 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -0700948
James E. Blairdaabed22012-08-15 15:38:57 -0700949 def test_post(self):
950 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700951
Zhongyue Luo5d556072012-09-21 02:00:47 +0900952 e = {
953 "type": "ref-updated",
954 "submitter": {
955 "name": "User Name",
956 },
957 "refUpdate": {
958 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
959 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
960 "refName": "master",
961 "project": "org/project",
962 }
963 }
James E. Blairdaabed22012-08-15 15:38:57 -0700964 self.fake_gerrit.addEvent(e)
965 self.waitUntilSettled()
966
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400967 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400968 self.assertEqual(len(self.history), 1)
969 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -0700970
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700971 def test_post_ignore_deletes(self):
972 "Test that deleting refs does not trigger post jobs"
973
974 e = {
975 "type": "ref-updated",
976 "submitter": {
977 "name": "User Name",
978 },
979 "refUpdate": {
980 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
981 "newRev": "0000000000000000000000000000000000000000",
982 "refName": "master",
983 "project": "org/project",
984 }
985 }
986 self.fake_gerrit.addEvent(e)
987 self.waitUntilSettled()
988
989 job_names = [x.name for x in self.history]
990 self.assertEqual(len(self.history), 0)
991 self.assertNotIn('project-post', job_names)
992
993 def test_post_ignore_deletes_negative(self):
994 "Test that deleting refs does trigger post jobs"
995
James E. Blairf84026c2015-12-08 16:11:46 -0800996 self.updateConfigLayout(
997 'tests/fixtures/layout-dont-ignore-deletes.yaml')
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700998 self.sched.reconfigure(self.config)
999
1000 e = {
1001 "type": "ref-updated",
1002 "submitter": {
1003 "name": "User Name",
1004 },
1005 "refUpdate": {
1006 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1007 "newRev": "0000000000000000000000000000000000000000",
1008 "refName": "master",
1009 "project": "org/project",
1010 }
1011 }
1012 self.fake_gerrit.addEvent(e)
1013 self.waitUntilSettled()
1014
1015 job_names = [x.name for x in self.history]
1016 self.assertEqual(len(self.history), 1)
1017 self.assertIn('project-post', job_names)
1018
James E. Blairc6294a52012-08-17 10:19:48 -07001019 def test_build_configuration_branch(self):
1020 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001021
1022 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001023 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
1024 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1025 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
1026 A.addApproval('CRVW', 2)
1027 B.addApproval('CRVW', 2)
1028 C.addApproval('CRVW', 2)
1029 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1030 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1031 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1032 self.waitUntilSettled()
1033
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001034 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001035 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001036 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001037 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001038 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001039 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001040 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001041 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1042 self.gearman_server.hold_jobs_in_queue = False
1043 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001044 self.waitUntilSettled()
1045
Monty Taylorbc758832013-06-17 17:22:42 -04001046 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001047 repo = git.Repo(path)
1048 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1049 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001050 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001051 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001052
1053 def test_build_configuration_branch_interaction(self):
1054 "Test that switching between branches works"
1055 self.test_build_configuration()
1056 self.test_build_configuration_branch()
1057 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001058 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001059 repo = git.Repo(path)
1060 repo.heads.master.commit = repo.commit('init')
1061 self.test_build_configuration()
1062
1063 def test_build_configuration_multi_branch(self):
1064 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001065
1066 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001067 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1068 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1069 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1070 A.addApproval('CRVW', 2)
1071 B.addApproval('CRVW', 2)
1072 C.addApproval('CRVW', 2)
1073 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1074 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1075 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1076 self.waitUntilSettled()
James E. Blairbb1fe502014-03-04 10:15:06 -08001077 queue = self.gearman_server.getQueue()
1078 job_A = None
1079 for job in queue:
1080 if 'project-merge' in job.name:
1081 job_A = job
1082 ref_A = self.getParameter(job_A, 'ZUUL_REF')
1083 commit_A = self.getParameter(job_A, 'ZUUL_COMMIT')
1084 self.log.debug("Got Zuul ref for change A: %s" % ref_A)
1085 self.log.debug("Got Zuul commit for change A: %s" % commit_A)
James E. Blairc6294a52012-08-17 10:19:48 -07001086
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001087 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001088 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001089 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001090 job_B = None
1091 for job in queue:
1092 if 'project-merge' in job.name:
1093 job_B = job
1094 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001095 commit_B = self.getParameter(job_B, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001096 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blairbb1fe502014-03-04 10:15:06 -08001097 self.log.debug("Got Zuul commit for change B: %s" % commit_B)
1098
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001099 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001100 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001101 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001102 for job in queue:
1103 if 'project-merge' in job.name:
1104 job_C = job
1105 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001106 commit_C = self.getParameter(job_C, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001107 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blairbb1fe502014-03-04 10:15:06 -08001108 self.log.debug("Got Zuul commit for change C: %s" % commit_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001109 self.gearman_server.hold_jobs_in_queue = False
1110 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001111 self.waitUntilSettled()
1112
Monty Taylorbc758832013-06-17 17:22:42 -04001113 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001114 repo = git.Repo(path)
1115
1116 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001117 for c in repo.iter_commits(ref_C)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001118 repo_shas = [c.hexsha for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001119 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001120 correct_messages = ['initial commit', 'A-1', 'C-1']
James E. Blairbb1fe502014-03-04 10:15:06 -08001121 # Ensure the right commits are in the history for this ref
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001122 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001123 # Ensure ZUUL_REF -> ZUUL_COMMIT
1124 self.assertEqual(repo_shas[0], commit_C)
James E. Blairc6294a52012-08-17 10:19:48 -07001125
1126 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001127 for c in repo.iter_commits(ref_B)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001128 repo_shas = [c.hexsha for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001129 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001130 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001131 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001132 self.assertEqual(repo_shas[0], commit_B)
1133
1134 repo_messages = [c.message.strip()
1135 for c in repo.iter_commits(ref_A)]
1136 repo_shas = [c.hexsha for c in repo.iter_commits(ref_A)]
1137 repo_messages.reverse()
1138 correct_messages = ['initial commit', 'A-1']
1139 self.assertEqual(repo_messages, correct_messages)
1140 self.assertEqual(repo_shas[0], commit_A)
1141
1142 self.assertNotEqual(ref_A, ref_B, ref_C)
1143 self.assertNotEqual(commit_A, commit_B, commit_C)
James E. Blair7f71c802012-08-22 13:04:32 -07001144
1145 def test_one_job_project(self):
1146 "Test that queueing works with one job"
1147 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1148 'master', 'A')
1149 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1150 'master', 'B')
1151 A.addApproval('CRVW', 2)
1152 B.addApproval('CRVW', 2)
1153 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1154 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1155 self.waitUntilSettled()
1156
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001157 self.assertEqual(A.data['status'], 'MERGED')
1158 self.assertEqual(A.reported, 2)
1159 self.assertEqual(B.data['status'], 'MERGED')
1160 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001161
Antoine Musso80edd5a2013-02-13 15:37:53 +01001162 def test_job_from_templates_launched(self):
1163 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001164
Antoine Musso80edd5a2013-02-13 15:37:53 +01001165 A = self.fake_gerrit.addFakeChange(
1166 'org/templated-project', 'master', 'A')
1167 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1168 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001169
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001170 self.assertEqual(self.getJobFromHistory('project-test1').result,
1171 'SUCCESS')
1172 self.assertEqual(self.getJobFromHistory('project-test2').result,
1173 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001174
James E. Blair3e98c022013-12-16 15:25:38 -08001175 def test_layered_templates(self):
1176 "Test whether a job generated via a template can be launched"
1177
1178 A = self.fake_gerrit.addFakeChange(
1179 'org/layered-project', 'master', 'A')
1180 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1181 self.waitUntilSettled()
1182
1183 self.assertEqual(self.getJobFromHistory('project-test1').result,
1184 'SUCCESS')
1185 self.assertEqual(self.getJobFromHistory('project-test2').result,
1186 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001187 self.assertEqual(self.getJobFromHistory('layered-project-test3'
1188 ).result, 'SUCCESS')
1189 self.assertEqual(self.getJobFromHistory('layered-project-test4'
1190 ).result, 'SUCCESS')
James E. Blair12a92b12014-03-26 11:54:53 -07001191 self.assertEqual(self.getJobFromHistory('layered-project-foo-test5'
1192 ).result, 'SUCCESS')
James E. Blair3e98c022013-12-16 15:25:38 -08001193 self.assertEqual(self.getJobFromHistory('project-test6').result,
1194 'SUCCESS')
1195
James E. Blaircaec0c52012-08-22 14:52:22 -07001196 def test_dependent_changes_dequeue(self):
1197 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001198
James E. Blaircaec0c52012-08-22 14:52:22 -07001199 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1200 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1201 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1202 A.addApproval('CRVW', 2)
1203 B.addApproval('CRVW', 2)
1204 C.addApproval('CRVW', 2)
1205
1206 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1207 M1.setMerged()
1208
1209 # C -> B -> A -> M1
1210
1211 C.setDependsOn(B, 1)
1212 B.setDependsOn(A, 1)
1213 A.setDependsOn(M1, 1)
1214
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001215 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001216
1217 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1218 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1219 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1220
1221 self.waitUntilSettled()
1222
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001223 self.assertEqual(A.data['status'], 'NEW')
1224 self.assertEqual(A.reported, 2)
1225 self.assertEqual(B.data['status'], 'NEW')
1226 self.assertEqual(B.reported, 2)
1227 self.assertEqual(C.data['status'], 'NEW')
1228 self.assertEqual(C.reported, 2)
1229 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001230
James E. Blair972e3c72013-08-29 12:04:55 -07001231 def test_failing_dependent_changes(self):
1232 "Test that failing dependent patches are taken out of stream"
1233 self.worker.hold_jobs_in_build = True
1234 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1235 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1236 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1237 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1238 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1239 A.addApproval('CRVW', 2)
1240 B.addApproval('CRVW', 2)
1241 C.addApproval('CRVW', 2)
1242 D.addApproval('CRVW', 2)
1243 E.addApproval('CRVW', 2)
1244
1245 # E, D -> C -> B, A
1246
1247 D.setDependsOn(C, 1)
1248 C.setDependsOn(B, 1)
1249
1250 self.worker.addFailTest('project-test1', B)
1251
1252 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1253 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1254 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1255 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1256 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1257
1258 self.waitUntilSettled()
1259 self.worker.release('.*-merge')
1260 self.waitUntilSettled()
1261 self.worker.release('.*-merge')
1262 self.waitUntilSettled()
1263 self.worker.release('.*-merge')
1264 self.waitUntilSettled()
1265 self.worker.release('.*-merge')
1266 self.waitUntilSettled()
1267 self.worker.release('.*-merge')
1268 self.waitUntilSettled()
1269
1270 self.worker.hold_jobs_in_build = False
1271 for build in self.builds:
1272 if build.parameters['ZUUL_CHANGE'] != '1':
1273 build.release()
1274 self.waitUntilSettled()
1275
1276 self.worker.release()
1277 self.waitUntilSettled()
1278
1279 self.assertEqual(A.data['status'], 'MERGED')
1280 self.assertEqual(A.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001281 self.assertIn('Build succeeded', A.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001282 self.assertEqual(B.data['status'], 'NEW')
1283 self.assertEqual(B.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001284 self.assertIn('Build failed', B.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001285 self.assertEqual(C.data['status'], 'NEW')
1286 self.assertEqual(C.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001287 self.assertIn('depends on a change', C.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001288 self.assertEqual(D.data['status'], 'NEW')
1289 self.assertEqual(D.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001290 self.assertIn('depends on a change', D.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001291 self.assertEqual(E.data['status'], 'MERGED')
1292 self.assertEqual(E.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001293 self.assertIn('Build succeeded', E.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001294 self.assertEqual(len(self.history), 18)
1295
James E. Blairec590122012-08-22 15:19:31 -07001296 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001297 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001298 # If it's dequeued more than once, we should see extra
1299 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001300
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001301 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001302 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1303 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1304 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1305 A.addApproval('CRVW', 2)
1306 B.addApproval('CRVW', 2)
1307 C.addApproval('CRVW', 2)
1308
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001309 self.worker.addFailTest('project1-test1', A)
1310 self.worker.addFailTest('project1-test2', A)
1311 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001312
1313 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1314 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1315 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1316
1317 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001318
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001319 self.assertEqual(len(self.builds), 1)
1320 self.assertEqual(self.builds[0].name, 'project1-merge')
1321 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001322
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001323 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001324 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001325 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001326 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001327 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001328 self.waitUntilSettled()
1329
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001330 self.assertEqual(len(self.builds), 9)
1331 self.assertEqual(self.builds[0].name, 'project1-test1')
1332 self.assertEqual(self.builds[1].name, 'project1-test2')
1333 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1334 self.assertEqual(self.builds[3].name, 'project1-test1')
1335 self.assertEqual(self.builds[4].name, 'project1-test2')
1336 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1337 self.assertEqual(self.builds[6].name, 'project1-test1')
1338 self.assertEqual(self.builds[7].name, 'project1-test2')
1339 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001340
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001341 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001342 self.waitUntilSettled()
1343
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001344 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1345 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001346
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001347 self.worker.hold_jobs_in_build = False
1348 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001349 self.waitUntilSettled()
1350
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001351 self.assertEqual(len(self.builds), 0)
1352 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001353
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001354 self.assertEqual(A.data['status'], 'NEW')
1355 self.assertEqual(B.data['status'], 'MERGED')
1356 self.assertEqual(C.data['status'], 'MERGED')
1357 self.assertEqual(A.reported, 2)
1358 self.assertEqual(B.reported, 2)
1359 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001360
1361 def test_nonvoting_job(self):
1362 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001363
James E. Blair4ec821f2012-08-23 15:28:28 -07001364 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1365 'master', 'A')
1366 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001367 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001368 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1369
1370 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001371
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001372 self.assertEqual(A.data['status'], 'MERGED')
1373 self.assertEqual(A.reported, 2)
1374 self.assertEqual(
1375 self.getJobFromHistory('nonvoting-project-merge').result,
1376 'SUCCESS')
1377 self.assertEqual(
1378 self.getJobFromHistory('nonvoting-project-test1').result,
1379 'SUCCESS')
1380 self.assertEqual(
1381 self.getJobFromHistory('nonvoting-project-test2').result,
1382 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001383
James E. Blair5821bd92015-09-16 08:48:15 -07001384 for build in self.builds:
1385 self.assertEqual(build.parameters['ZUUL_VOTING'], '0')
1386
James E. Blaire0487072012-08-29 17:38:31 -07001387 def test_check_queue_success(self):
1388 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001389
James E. Blaire0487072012-08-29 17:38:31 -07001390 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1391 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1392
1393 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001394
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001395 self.assertEqual(A.data['status'], 'NEW')
1396 self.assertEqual(A.reported, 1)
1397 self.assertEqual(self.getJobFromHistory('project-merge').result,
1398 'SUCCESS')
1399 self.assertEqual(self.getJobFromHistory('project-test1').result,
1400 'SUCCESS')
1401 self.assertEqual(self.getJobFromHistory('project-test2').result,
1402 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001403
1404 def test_check_queue_failure(self):
1405 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001406
James E. Blaire0487072012-08-29 17:38:31 -07001407 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001408 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001409 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1410
1411 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001412
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001413 self.assertEqual(A.data['status'], 'NEW')
1414 self.assertEqual(A.reported, 1)
1415 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001416 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001417 self.assertEqual(self.getJobFromHistory('project-test1').result,
1418 'SUCCESS')
1419 self.assertEqual(self.getJobFromHistory('project-test2').result,
1420 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001421
1422 def test_dependent_behind_dequeue(self):
1423 "test that dependent changes behind dequeued changes work"
1424 # This complicated test is a reproduction of a real life bug
1425 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001426
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001427 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001428 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1429 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1430 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1431 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1432 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1433 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1434 D.setDependsOn(C, 1)
1435 E.setDependsOn(D, 1)
1436 A.addApproval('CRVW', 2)
1437 B.addApproval('CRVW', 2)
1438 C.addApproval('CRVW', 2)
1439 D.addApproval('CRVW', 2)
1440 E.addApproval('CRVW', 2)
1441 F.addApproval('CRVW', 2)
1442
1443 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001444
1445 # Change object re-use in the gerrit trigger is hidden if
1446 # changes are added in quick succession; waiting makes it more
1447 # like real life.
1448 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1449 self.waitUntilSettled()
1450 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1451 self.waitUntilSettled()
1452
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001453 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001454 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001455 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001456 self.waitUntilSettled()
1457
1458 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1459 self.waitUntilSettled()
1460 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1461 self.waitUntilSettled()
1462 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1463 self.waitUntilSettled()
1464 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1465 self.waitUntilSettled()
1466
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001467 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001468 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001469 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001470 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001471 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001472 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001473 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001474 self.waitUntilSettled()
1475
1476 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001477
1478 # Grab pointers to the jobs we want to release before
1479 # releasing any, because list indexes may change as
1480 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001481 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001482 a.release()
1483 b.release()
1484 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001485 self.waitUntilSettled()
1486
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001487 self.worker.hold_jobs_in_build = False
1488 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001489 self.waitUntilSettled()
1490
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001491 self.assertEqual(A.data['status'], 'NEW')
1492 self.assertEqual(B.data['status'], 'MERGED')
1493 self.assertEqual(C.data['status'], 'MERGED')
1494 self.assertEqual(D.data['status'], 'MERGED')
1495 self.assertEqual(E.data['status'], 'MERGED')
1496 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07001497
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001498 self.assertEqual(A.reported, 2)
1499 self.assertEqual(B.reported, 2)
1500 self.assertEqual(C.reported, 2)
1501 self.assertEqual(D.reported, 2)
1502 self.assertEqual(E.reported, 2)
1503 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07001504
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001505 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
1506 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07001507
1508 def test_merger_repack(self):
1509 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001510
James E. Blair05fed602012-09-07 12:45:24 -07001511 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1512 A.addApproval('CRVW', 2)
1513 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1514 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001515 self.assertEqual(self.getJobFromHistory('project-merge').result,
1516 'SUCCESS')
1517 self.assertEqual(self.getJobFromHistory('project-test1').result,
1518 'SUCCESS')
1519 self.assertEqual(self.getJobFromHistory('project-test2').result,
1520 'SUCCESS')
1521 self.assertEqual(A.data['status'], 'MERGED')
1522 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07001523 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001524 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001525
Monty Taylorbc758832013-06-17 17:22:42 -04001526 path = os.path.join(self.git_root, "org/project")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001527 print(repack_repo(path))
James E. Blair05fed602012-09-07 12:45:24 -07001528
1529 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1530 A.addApproval('CRVW', 2)
1531 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1532 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001533 self.assertEqual(self.getJobFromHistory('project-merge').result,
1534 'SUCCESS')
1535 self.assertEqual(self.getJobFromHistory('project-test1').result,
1536 'SUCCESS')
1537 self.assertEqual(self.getJobFromHistory('project-test2').result,
1538 'SUCCESS')
1539 self.assertEqual(A.data['status'], 'MERGED')
1540 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001541
James E. Blair4886f282012-11-15 09:27:33 -08001542 def test_merger_repack_large_change(self):
1543 "Test that the merger works with large changes after a repack"
1544 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08001545 # This test assumes the repo is already cloned; make sure it is
Joshua Hesketh352264b2015-08-11 23:42:08 +10001546 url = self.fake_gerrit.getGitUrl(
James E. Blairac2c3242014-01-24 13:38:51 -08001547 self.sched.layout.projects['org/project1'])
James E. Blair4076e2b2014-01-28 12:42:20 -08001548 self.merge_server.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08001549 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1550 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001551 path = os.path.join(self.upstream_root, "org/project1")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001552 print(repack_repo(path))
Monty Taylorbc758832013-06-17 17:22:42 -04001553 path = os.path.join(self.git_root, "org/project1")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001554 print(repack_repo(path))
James E. Blair4886f282012-11-15 09:27:33 -08001555
1556 A.addApproval('CRVW', 2)
1557 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1558 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001559 self.assertEqual(self.getJobFromHistory('project1-merge').result,
1560 'SUCCESS')
1561 self.assertEqual(self.getJobFromHistory('project1-test1').result,
1562 'SUCCESS')
1563 self.assertEqual(self.getJobFromHistory('project1-test2').result,
1564 'SUCCESS')
1565 self.assertEqual(A.data['status'], 'MERGED')
1566 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08001567
James E. Blair7ee88a22012-09-12 18:59:31 +02001568 def test_nonexistent_job(self):
1569 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001570 # Set to the state immediately after a restart
1571 self.resetGearmanServer()
1572 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001573
1574 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1575 A.addApproval('CRVW', 2)
1576 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1577 # There may be a thread about to report a lost change
1578 while A.reported < 2:
1579 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001580 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001581 self.assertFalse(job_names)
1582 self.assertEqual(A.data['status'], 'NEW')
1583 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001584 self.assertEmptyQueues()
1585
1586 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001587 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001588 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1589 A.addApproval('CRVW', 2)
1590 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1591 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001592 self.assertEqual(self.getJobFromHistory('project-merge').result,
1593 'SUCCESS')
1594 self.assertEqual(self.getJobFromHistory('project-test1').result,
1595 'SUCCESS')
1596 self.assertEqual(self.getJobFromHistory('project-test2').result,
1597 'SUCCESS')
1598 self.assertEqual(A.data['status'], 'MERGED')
1599 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08001600
1601 def test_single_nonexistent_post_job(self):
1602 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001603 e = {
1604 "type": "ref-updated",
1605 "submitter": {
1606 "name": "User Name",
1607 },
1608 "refUpdate": {
1609 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1610 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1611 "refName": "master",
1612 "project": "org/project",
1613 }
1614 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001615 # Set to the state immediately after a restart
1616 self.resetGearmanServer()
1617 self.launcher.negative_function_cache_ttl = 0
1618
James E. Blairf62d4282012-12-31 17:01:50 -08001619 self.fake_gerrit.addEvent(e)
1620 self.waitUntilSettled()
1621
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001622 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08001623
1624 def test_new_patchset_dequeues_old(self):
1625 "Test that a new patchset causes the old to be dequeued"
1626 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001627 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001628 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1629 M.setMerged()
1630
1631 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1632 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1633 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1634 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1635 A.addApproval('CRVW', 2)
1636 B.addApproval('CRVW', 2)
1637 C.addApproval('CRVW', 2)
1638 D.addApproval('CRVW', 2)
1639
1640 C.setDependsOn(B, 1)
1641 B.setDependsOn(A, 1)
1642 A.setDependsOn(M, 1)
1643
1644 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1645 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1646 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1647 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1648 self.waitUntilSettled()
1649
1650 B.addPatchset()
1651 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1652 self.waitUntilSettled()
1653
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001654 self.worker.hold_jobs_in_build = False
1655 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001656 self.waitUntilSettled()
1657
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001658 self.assertEqual(A.data['status'], 'MERGED')
1659 self.assertEqual(A.reported, 2)
1660 self.assertEqual(B.data['status'], 'NEW')
1661 self.assertEqual(B.reported, 2)
1662 self.assertEqual(C.data['status'], 'NEW')
1663 self.assertEqual(C.reported, 2)
1664 self.assertEqual(D.data['status'], 'MERGED')
1665 self.assertEqual(D.reported, 2)
1666 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001667
James E. Blairba437362015-02-07 11:41:52 -08001668 def test_new_patchset_check(self):
1669 "Test a new patchset in check"
Antoine Mussobd86a312014-01-08 14:51:33 +01001670
1671 self.worker.hold_jobs_in_build = True
1672
1673 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairba437362015-02-07 11:41:52 -08001674 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1675 check_pipeline = self.sched.layout.pipelines['check']
1676
1677 # Add two git-dependent changes
1678 B.setDependsOn(A, 1)
1679 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1680 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001681 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1682 self.waitUntilSettled()
James E. Blairba437362015-02-07 11:41:52 -08001683
1684 # A live item, and a non-live/live pair
1685 items = check_pipeline.getAllItems()
1686 self.assertEqual(len(items), 3)
1687
1688 self.assertEqual(items[0].change.number, '1')
1689 self.assertEqual(items[0].change.patchset, '1')
1690 self.assertFalse(items[0].live)
1691
1692 self.assertEqual(items[1].change.number, '2')
1693 self.assertEqual(items[1].change.patchset, '1')
1694 self.assertTrue(items[1].live)
1695
1696 self.assertEqual(items[2].change.number, '1')
1697 self.assertEqual(items[2].change.patchset, '1')
1698 self.assertTrue(items[2].live)
1699
1700 # Add a new patchset to A
1701 A.addPatchset()
1702 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1703 self.waitUntilSettled()
1704
1705 # The live copy of A,1 should be gone, but the non-live and B
1706 # should continue, and we should have a new A,2
1707 items = check_pipeline.getAllItems()
1708 self.assertEqual(len(items), 3)
1709
1710 self.assertEqual(items[0].change.number, '1')
1711 self.assertEqual(items[0].change.patchset, '1')
1712 self.assertFalse(items[0].live)
1713
1714 self.assertEqual(items[1].change.number, '2')
1715 self.assertEqual(items[1].change.patchset, '1')
1716 self.assertTrue(items[1].live)
1717
1718 self.assertEqual(items[2].change.number, '1')
1719 self.assertEqual(items[2].change.patchset, '2')
1720 self.assertTrue(items[2].live)
1721
1722 # Add a new patchset to B
1723 B.addPatchset()
1724 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1725 self.waitUntilSettled()
1726
1727 # The live copy of B,1 should be gone, and it's non-live copy of A,1
1728 # but we should have a new B,2 (still based on A,1)
1729 items = check_pipeline.getAllItems()
1730 self.assertEqual(len(items), 3)
1731
1732 self.assertEqual(items[0].change.number, '1')
1733 self.assertEqual(items[0].change.patchset, '2')
1734 self.assertTrue(items[0].live)
1735
1736 self.assertEqual(items[1].change.number, '1')
1737 self.assertEqual(items[1].change.patchset, '1')
1738 self.assertFalse(items[1].live)
1739
1740 self.assertEqual(items[2].change.number, '2')
1741 self.assertEqual(items[2].change.patchset, '2')
1742 self.assertTrue(items[2].live)
1743
1744 self.builds[0].release()
1745 self.waitUntilSettled()
1746 self.builds[0].release()
1747 self.waitUntilSettled()
1748 self.worker.hold_jobs_in_build = False
1749 self.worker.release()
1750 self.waitUntilSettled()
1751
1752 self.assertEqual(A.reported, 1)
1753 self.assertEqual(B.reported, 1)
1754 self.assertEqual(self.history[0].result, 'ABORTED')
1755 self.assertEqual(self.history[0].changes, '1,1')
1756 self.assertEqual(self.history[1].result, 'ABORTED')
1757 self.assertEqual(self.history[1].changes, '1,1 2,1')
1758 self.assertEqual(self.history[2].result, 'SUCCESS')
1759 self.assertEqual(self.history[2].changes, '1,2')
1760 self.assertEqual(self.history[3].result, 'SUCCESS')
1761 self.assertEqual(self.history[3].changes, '1,1 2,2')
1762
1763 def test_abandoned_gate(self):
1764 "Test that an abandoned change is dequeued from gate"
1765
1766 self.worker.hold_jobs_in_build = True
1767
1768 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1769 A.addApproval('CRVW', 2)
1770 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1771 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001772 self.assertEqual(len(self.builds), 1, "One job being built (on hold)")
1773 self.assertEqual(self.builds[0].name, 'project-merge')
1774
1775 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1776 self.waitUntilSettled()
1777
Antoine Mussobd86a312014-01-08 14:51:33 +01001778 self.worker.release('.*-merge')
1779 self.waitUntilSettled()
1780
1781 self.assertEqual(len(self.builds), 0, "No job running")
Antoine Mussobd86a312014-01-08 14:51:33 +01001782 self.assertEqual(len(self.history), 1, "Only one build in history")
1783 self.assertEqual(self.history[0].result, 'ABORTED',
James E. Blairba437362015-02-07 11:41:52 -08001784 "Build should have been aborted")
1785 self.assertEqual(A.reported, 1,
1786 "Abandoned gate change should report only start")
1787
1788 def test_abandoned_check(self):
1789 "Test that an abandoned change is dequeued from check"
1790
1791 self.worker.hold_jobs_in_build = True
1792
1793 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1794 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1795 check_pipeline = self.sched.layout.pipelines['check']
1796
1797 # Add two git-dependent changes
1798 B.setDependsOn(A, 1)
1799 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1800 self.waitUntilSettled()
1801 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1802 self.waitUntilSettled()
1803 # A live item, and a non-live/live pair
1804 items = check_pipeline.getAllItems()
1805 self.assertEqual(len(items), 3)
1806
1807 self.assertEqual(items[0].change.number, '1')
1808 self.assertFalse(items[0].live)
1809
1810 self.assertEqual(items[1].change.number, '2')
1811 self.assertTrue(items[1].live)
1812
1813 self.assertEqual(items[2].change.number, '1')
1814 self.assertTrue(items[2].live)
1815
1816 # Abandon A
1817 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1818 self.waitUntilSettled()
1819
1820 # The live copy of A should be gone, but the non-live and B
1821 # should continue
1822 items = check_pipeline.getAllItems()
1823 self.assertEqual(len(items), 2)
1824
1825 self.assertEqual(items[0].change.number, '1')
1826 self.assertFalse(items[0].live)
1827
1828 self.assertEqual(items[1].change.number, '2')
1829 self.assertTrue(items[1].live)
1830
1831 self.worker.hold_jobs_in_build = False
1832 self.worker.release()
1833 self.waitUntilSettled()
1834
1835 self.assertEqual(len(self.history), 4)
1836 self.assertEqual(self.history[0].result, 'ABORTED',
Antoine Mussobd86a312014-01-08 14:51:33 +01001837 'Build should have been aborted')
1838 self.assertEqual(A.reported, 0, "Abandoned change should not report")
James E. Blairba437362015-02-07 11:41:52 -08001839 self.assertEqual(B.reported, 1, "Change should report")
Antoine Mussobd86a312014-01-08 14:51:33 +01001840
Steve Varnau7b78b312015-04-03 14:49:46 -07001841 def test_abandoned_not_timer(self):
1842 "Test that an abandoned change does not cancel timer jobs"
1843
1844 self.worker.hold_jobs_in_build = True
1845
1846 # Start timer trigger - also org/project
James E. Blairf84026c2015-12-08 16:11:46 -08001847 self.updateConfigLayout(
1848 'tests/fixtures/layout-idle.yaml')
Steve Varnau7b78b312015-04-03 14:49:46 -07001849 self.sched.reconfigure(self.config)
1850 self.registerJobs()
1851 # The pipeline triggers every second, so we should have seen
1852 # several by now.
1853 time.sleep(5)
1854 self.waitUntilSettled()
1855 # Stop queuing timer triggered jobs so that the assertions
1856 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08001857 self.updateConfigLayout(
1858 'tests/fixtures/layout-no-timer.yaml')
Steve Varnau7b78b312015-04-03 14:49:46 -07001859 self.sched.reconfigure(self.config)
1860 self.registerJobs()
1861 self.assertEqual(len(self.builds), 2, "Two timer jobs")
1862
1863 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1864 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1865 self.waitUntilSettled()
1866 self.assertEqual(len(self.builds), 3, "One change plus two timer jobs")
1867
1868 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1869 self.waitUntilSettled()
1870
1871 self.assertEqual(len(self.builds), 2, "Two timer jobs remain")
1872
1873 self.worker.release()
1874 self.waitUntilSettled()
1875
Arx Cruzb1b010d2013-10-28 19:49:59 -02001876 def test_zuul_url_return(self):
1877 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
James E. Blair4076e2b2014-01-28 12:42:20 -08001878 self.assertTrue(self.sched.config.has_option('merger', 'zuul_url'))
Arx Cruzb1b010d2013-10-28 19:49:59 -02001879 self.worker.hold_jobs_in_build = True
1880
1881 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1882 A.addApproval('CRVW', 2)
1883 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1884 self.waitUntilSettled()
1885
1886 self.assertEqual(len(self.builds), 1)
1887 for build in self.builds:
1888 self.assertTrue('ZUUL_URL' in build.parameters)
1889
1890 self.worker.hold_jobs_in_build = False
1891 self.worker.release()
1892 self.waitUntilSettled()
1893
James E. Blair2fa50962013-01-30 21:50:41 -08001894 def test_new_patchset_dequeues_old_on_head(self):
1895 "Test that a new patchset causes the old to be dequeued (at head)"
1896 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001897 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001898 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1899 M.setMerged()
1900 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1901 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1902 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1903 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1904 A.addApproval('CRVW', 2)
1905 B.addApproval('CRVW', 2)
1906 C.addApproval('CRVW', 2)
1907 D.addApproval('CRVW', 2)
1908
1909 C.setDependsOn(B, 1)
1910 B.setDependsOn(A, 1)
1911 A.setDependsOn(M, 1)
1912
1913 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1914 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1915 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1916 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1917 self.waitUntilSettled()
1918
1919 A.addPatchset()
1920 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1921 self.waitUntilSettled()
1922
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001923 self.worker.hold_jobs_in_build = False
1924 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001925 self.waitUntilSettled()
1926
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001927 self.assertEqual(A.data['status'], 'NEW')
1928 self.assertEqual(A.reported, 2)
1929 self.assertEqual(B.data['status'], 'NEW')
1930 self.assertEqual(B.reported, 2)
1931 self.assertEqual(C.data['status'], 'NEW')
1932 self.assertEqual(C.reported, 2)
1933 self.assertEqual(D.data['status'], 'MERGED')
1934 self.assertEqual(D.reported, 2)
1935 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08001936
1937 def test_new_patchset_dequeues_old_without_dependents(self):
1938 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001939 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001940 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1941 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1942 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1943 A.addApproval('CRVW', 2)
1944 B.addApproval('CRVW', 2)
1945 C.addApproval('CRVW', 2)
1946
1947 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1948 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1949 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1950 self.waitUntilSettled()
1951
1952 B.addPatchset()
1953 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1954 self.waitUntilSettled()
1955
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001956 self.worker.hold_jobs_in_build = False
1957 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001958 self.waitUntilSettled()
1959
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001960 self.assertEqual(A.data['status'], 'MERGED')
1961 self.assertEqual(A.reported, 2)
1962 self.assertEqual(B.data['status'], 'NEW')
1963 self.assertEqual(B.reported, 2)
1964 self.assertEqual(C.data['status'], 'MERGED')
1965 self.assertEqual(C.reported, 2)
1966 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08001967
1968 def test_new_patchset_dequeues_old_independent_queue(self):
1969 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001970 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001971 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1972 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1973 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1974 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1975 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1976 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1977 self.waitUntilSettled()
1978
1979 B.addPatchset()
1980 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1981 self.waitUntilSettled()
1982
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001983 self.worker.hold_jobs_in_build = False
1984 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001985 self.waitUntilSettled()
1986
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001987 self.assertEqual(A.data['status'], 'NEW')
1988 self.assertEqual(A.reported, 1)
1989 self.assertEqual(B.data['status'], 'NEW')
1990 self.assertEqual(B.reported, 1)
1991 self.assertEqual(C.data['status'], 'NEW')
1992 self.assertEqual(C.reported, 1)
1993 self.assertEqual(len(self.history), 10)
1994 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001995
James E. Blair18c64442014-03-18 10:14:45 -07001996 def test_noop_job(self):
1997 "Test that the internal noop job works"
1998 A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A')
1999 A.addApproval('CRVW', 2)
2000 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2001 self.waitUntilSettled()
2002
2003 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2004 self.assertTrue(self.sched._areAllBuildsComplete())
2005 self.assertEqual(len(self.history), 0)
2006 self.assertEqual(A.data['status'], 'MERGED')
2007 self.assertEqual(A.reported, 2)
2008
Evgeny Antyshevd6e546c2015-06-11 15:13:57 +00002009 def test_no_job_project(self):
2010 "Test that reports with no jobs don't get sent"
2011 A = self.fake_gerrit.addFakeChange('org/no-jobs-project',
2012 'master', 'A')
2013 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2014 self.waitUntilSettled()
2015
2016 # Change wasn't reported to
2017 self.assertEqual(A.reported, False)
2018
2019 # Check queue is empty afterwards
2020 check_pipeline = self.sched.layout.pipelines['check']
2021 items = check_pipeline.getAllItems()
2022 self.assertEqual(len(items), 0)
2023
2024 self.assertEqual(len(self.history), 0)
2025
James E. Blair7d0dedc2013-02-21 17:26:09 -08002026 def test_zuul_refs(self):
2027 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002028 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08002029 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
2030 M1.setMerged()
2031 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
2032 M2.setMerged()
2033
2034 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2035 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2036 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
2037 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
2038 A.addApproval('CRVW', 2)
2039 B.addApproval('CRVW', 2)
2040 C.addApproval('CRVW', 2)
2041 D.addApproval('CRVW', 2)
2042 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2043 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2044 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2045 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2046
2047 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002048 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002049 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002050 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002051 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002052 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002053 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002054 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002055 self.waitUntilSettled()
2056
James E. Blair7d0dedc2013-02-21 17:26:09 -08002057 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002058 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002059 if x.parameters['ZUUL_CHANGE'] == '3':
2060 a_zref = x.parameters['ZUUL_REF']
2061 if x.parameters['ZUUL_CHANGE'] == '4':
2062 b_zref = x.parameters['ZUUL_REF']
2063 if x.parameters['ZUUL_CHANGE'] == '5':
2064 c_zref = x.parameters['ZUUL_REF']
2065 if x.parameters['ZUUL_CHANGE'] == '6':
2066 d_zref = x.parameters['ZUUL_REF']
2067
2068 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002069 self.assertIsNotNone(a_zref)
2070 self.assertIsNotNone(b_zref)
2071 self.assertIsNotNone(c_zref)
2072 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002073
2074 # And they should all be different
2075 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002076 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002077
2078 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002079 self.assertTrue(self.ref_has_change(a_zref, A))
2080 self.assertFalse(self.ref_has_change(a_zref, B))
2081 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002082
2083 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002084 self.assertTrue(self.ref_has_change(b_zref, A))
2085 self.assertTrue(self.ref_has_change(b_zref, B))
2086 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002087
2088 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002089 self.assertTrue(self.ref_has_change(c_zref, A))
2090 self.assertTrue(self.ref_has_change(c_zref, B))
2091 self.assertTrue(self.ref_has_change(c_zref, C))
2092 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002093
2094 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002095 self.assertTrue(self.ref_has_change(d_zref, A))
2096 self.assertTrue(self.ref_has_change(d_zref, B))
2097 self.assertTrue(self.ref_has_change(d_zref, C))
2098 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002099
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002100 self.worker.hold_jobs_in_build = False
2101 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002102 self.waitUntilSettled()
2103
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002104 self.assertEqual(A.data['status'], 'MERGED')
2105 self.assertEqual(A.reported, 2)
2106 self.assertEqual(B.data['status'], 'MERGED')
2107 self.assertEqual(B.reported, 2)
2108 self.assertEqual(C.data['status'], 'MERGED')
2109 self.assertEqual(C.reported, 2)
2110 self.assertEqual(D.data['status'], 'MERGED')
2111 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002112
James E. Blair4a28a882013-08-23 15:17:33 -07002113 def test_rerun_on_error(self):
2114 "Test that if a worker fails to run a job, it is run again"
2115 self.worker.hold_jobs_in_build = True
2116 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2117 A.addApproval('CRVW', 2)
2118 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2119 self.waitUntilSettled()
2120
2121 self.builds[0].run_error = True
2122 self.worker.hold_jobs_in_build = False
2123 self.worker.release()
2124 self.waitUntilSettled()
2125 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2126 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2127
James E. Blair412e5582013-04-22 15:50:12 -07002128 def test_statsd(self):
2129 "Test each of the statsd methods used in the scheduler"
2130 import extras
2131 statsd = extras.try_import('statsd.statsd')
2132 statsd.incr('test-incr')
2133 statsd.timing('test-timing', 3)
Alex Gaynor813d39b2014-05-17 16:17:16 -07002134 statsd.gauge('test-gauge', 12)
James E. Blair412e5582013-04-22 15:50:12 -07002135 self.assertReportedStat('test-incr', '1|c')
2136 self.assertReportedStat('test-timing', '3|ms')
Alex Gaynor813d39b2014-05-17 16:17:16 -07002137 self.assertReportedStat('test-gauge', '12|g')
James E. Blair412e5582013-04-22 15:50:12 -07002138
James E. Blairdad52252014-02-07 16:59:17 -08002139 def test_stuck_job_cleanup(self):
2140 "Test that pending jobs are cleaned up if removed from layout"
James E. Blair18c64442014-03-18 10:14:45 -07002141 # This job won't be registered at startup because it is not in
2142 # the standard layout, but we need it to already be registerd
2143 # for when we reconfigure, as that is when Zuul will attempt
2144 # to run the new job.
2145 self.worker.registerFunction('build:gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002146 self.gearman_server.hold_jobs_in_queue = True
2147 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2148 A.addApproval('CRVW', 2)
2149 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2150 self.waitUntilSettled()
2151 self.assertEqual(len(self.gearman_server.getQueue()), 1)
2152
James E. Blairf84026c2015-12-08 16:11:46 -08002153 self.updateConfigLayout(
2154 'tests/fixtures/layout-no-jobs.yaml')
James E. Blairdad52252014-02-07 16:59:17 -08002155 self.sched.reconfigure(self.config)
2156 self.waitUntilSettled()
2157
James E. Blair18c64442014-03-18 10:14:45 -07002158 self.gearman_server.release('gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002159 self.waitUntilSettled()
2160 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2161 self.assertTrue(self.sched._areAllBuildsComplete())
2162
2163 self.assertEqual(len(self.history), 1)
James E. Blair18c64442014-03-18 10:14:45 -07002164 self.assertEqual(self.history[0].name, 'gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002165 self.assertEqual(self.history[0].result, 'SUCCESS')
2166
James E. Blair879dafb2015-07-17 14:04:49 -07002167 def test_file_head(self):
2168 # This is a regression test for an observed bug. A change
2169 # with a file named "HEAD" in the root directory of the repo
2170 # was processed by a merger. It then was unable to reset the
2171 # repo because of:
2172 # GitCommandError: 'git reset --hard HEAD' returned
2173 # with exit code 128
2174 # stderr: 'fatal: ambiguous argument 'HEAD': both revision
2175 # and filename
2176 # Use '--' to separate filenames from revisions'
2177
2178 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2179 A.addPatchset(['HEAD'])
2180 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2181
2182 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2183 self.waitUntilSettled()
2184
2185 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2186 self.waitUntilSettled()
2187
2188 self.assertIn('Build succeeded', A.messages[0])
2189 self.assertIn('Build succeeded', B.messages[0])
2190
James E. Blair70c71582013-03-06 08:50:50 -08002191 def test_file_jobs(self):
2192 "Test that file jobs run only when appropriate"
2193 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2194 A.addPatchset(['pip-requires'])
2195 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2196 A.addApproval('CRVW', 2)
2197 B.addApproval('CRVW', 2)
2198 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2199 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2200 self.waitUntilSettled()
2201
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002202 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002203 if x.name == 'project-testfile']
2204
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002205 self.assertEqual(len(testfile_jobs), 1)
2206 self.assertEqual(testfile_jobs[0].changes, '1,2')
2207 self.assertEqual(A.data['status'], 'MERGED')
2208 self.assertEqual(A.reported, 2)
2209 self.assertEqual(B.data['status'], 'MERGED')
2210 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002211
Maru Newby3fe5f852015-01-13 04:22:14 +00002212 def _test_skip_if_jobs(self, branch, should_skip):
2213 "Test that jobs with a skip-if filter run only when appropriate"
James E. Blairf84026c2015-12-08 16:11:46 -08002214 self.updateConfigLayout(
2215 'tests/fixtures/layout-skip-if.yaml')
Maru Newby3fe5f852015-01-13 04:22:14 +00002216 self.sched.reconfigure(self.config)
2217 self.registerJobs()
2218
2219 change = self.fake_gerrit.addFakeChange('org/project',
2220 branch,
2221 'test skip-if')
2222 self.fake_gerrit.addEvent(change.getPatchsetCreatedEvent(1))
2223 self.waitUntilSettled()
2224
2225 tested_change_ids = [x.changes[0] for x in self.history
2226 if x.name == 'project-test-skip-if']
2227
2228 if should_skip:
2229 self.assertEqual([], tested_change_ids)
2230 else:
2231 self.assertIn(change.data['number'], tested_change_ids)
2232
2233 def test_skip_if_match_skips_job(self):
2234 self._test_skip_if_jobs(branch='master', should_skip=True)
2235
2236 def test_skip_if_no_match_runs_job(self):
2237 self._test_skip_if_jobs(branch='mp', should_skip=False)
2238
James E. Blair3c5e5b52013-04-26 11:17:03 -07002239 def test_test_config(self):
2240 "Test that we can test the config"
James E. Blairf84026c2015-12-08 16:11:46 -08002241 self.sched.testConfig(self.config.get('zuul', 'tenant_config'),
Joshua Hesketh352264b2015-08-11 23:42:08 +10002242 self.connections)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002243
2244 def test_build_description(self):
2245 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002246 self.worker.registerFunction('set_description:' +
2247 self.worker.worker_id)
2248
2249 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2250 A.addApproval('CRVW', 2)
2251 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2252 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002253 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002254 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002255 self.assertTrue(re.search("Branch.*master", desc))
2256 self.assertTrue(re.search("Pipeline.*gate", desc))
2257 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2258 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2259 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2260 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002261
James E. Blairc8a1e052014-02-25 09:29:26 -08002262 def test_queue_names(self):
2263 "Test shared change queue names"
2264 project1 = self.sched.layout.projects['org/project1']
2265 project2 = self.sched.layout.projects['org/project2']
2266 q1 = self.sched.layout.pipelines['gate'].getQueue(project1)
2267 q2 = self.sched.layout.pipelines['gate'].getQueue(project2)
2268 self.assertEqual(q1.name, 'integration')
2269 self.assertEqual(q2.name, 'integration')
2270
James E. Blairf84026c2015-12-08 16:11:46 -08002271 self.updateConfigLayout(
2272 'tests/fixtures/layout-bad-queue.yaml')
James E. Blairc8a1e052014-02-25 09:29:26 -08002273 with testtools.ExpectedException(
2274 Exception, "More than one name assigned to change queue"):
2275 self.sched.reconfigure(self.config)
2276
James E. Blair64ed6f22013-07-10 14:07:23 -07002277 def test_queue_precedence(self):
2278 "Test that queue precedence works"
2279
2280 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002281 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002282 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2283 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2284 A.addApproval('CRVW', 2)
2285 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2286
2287 self.waitUntilSettled()
2288 self.gearman_server.hold_jobs_in_queue = False
2289 self.gearman_server.release()
2290 self.waitUntilSettled()
2291
James E. Blair8de58bd2013-07-18 16:23:33 -07002292 # Run one build at a time to ensure non-race order:
James E. Blairb8c16472015-05-05 14:55:26 -07002293 self.orderedRelease()
James E. Blair8de58bd2013-07-18 16:23:33 -07002294 self.worker.hold_jobs_in_build = False
2295 self.waitUntilSettled()
2296
James E. Blair64ed6f22013-07-10 14:07:23 -07002297 self.log.debug(self.history)
2298 self.assertEqual(self.history[0].pipeline, 'gate')
2299 self.assertEqual(self.history[1].pipeline, 'check')
2300 self.assertEqual(self.history[2].pipeline, 'gate')
2301 self.assertEqual(self.history[3].pipeline, 'gate')
2302 self.assertEqual(self.history[4].pipeline, 'check')
2303 self.assertEqual(self.history[5].pipeline, 'check')
2304
Clark Boylana5edbe42014-06-03 16:39:10 -07002305 def test_json_status(self):
James E. Blair1843a552013-07-03 14:19:52 -07002306 "Test that we can retrieve JSON status info"
2307 self.worker.hold_jobs_in_build = True
2308 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2309 A.addApproval('CRVW', 2)
2310 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2311 self.waitUntilSettled()
2312
James E. Blairb7273ef2016-04-19 08:58:51 -07002313 self.worker.release('project-merge')
2314 self.waitUntilSettled()
2315
James E. Blair1843a552013-07-03 14:19:52 -07002316 port = self.webapp.server.socket.getsockname()[1]
2317
Morgan Fainberg293f7f82016-05-30 14:01:22 -07002318 req = urllib.request.Request("http://localhost:%s/status.json" % port)
2319 f = urllib.request.urlopen(req)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002320 headers = f.info()
2321 self.assertIn('Content-Length', headers)
2322 self.assertIn('Content-Type', headers)
Sachi Kingdc963fc2016-03-23 16:00:33 +11002323 self.assertIsNotNone(re.match('^application/json(; charset=UTF-8)?$',
2324 headers['Content-Type']))
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002325 self.assertIn('Access-Control-Allow-Origin', headers)
2326 self.assertIn('Cache-Control', headers)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002327 self.assertIn('Last-Modified', headers)
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002328 self.assertIn('Expires', headers)
James E. Blair1843a552013-07-03 14:19:52 -07002329 data = f.read()
2330
2331 self.worker.hold_jobs_in_build = False
2332 self.worker.release()
2333 self.waitUntilSettled()
2334
2335 data = json.loads(data)
James E. Blairb7273ef2016-04-19 08:58:51 -07002336 status_jobs = []
James E. Blair1843a552013-07-03 14:19:52 -07002337 for p in data['pipelines']:
2338 for q in p['change_queues']:
James E. Blairbfb8e042014-12-30 17:01:44 -08002339 if p['name'] in ['gate', 'conflict']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002340 self.assertEqual(q['window'], 20)
2341 else:
2342 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002343 for head in q['heads']:
2344 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002345 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002346 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002347 for job in change['jobs']:
James E. Blairb7273ef2016-04-19 08:58:51 -07002348 status_jobs.append(job)
2349 self.assertEqual('project-merge', status_jobs[0]['name'])
2350 self.assertEqual('https://server/job/project-merge/0/',
2351 status_jobs[0]['url'])
2352 self.assertEqual('http://logs.example.com/1/1/gate/project-merge/0',
2353 status_jobs[0]['report_url'])
2354
2355 self.assertEqual('project-test1', status_jobs[1]['name'])
2356 self.assertEqual('https://server/job/project-test1/1/',
2357 status_jobs[1]['url'])
2358 self.assertEqual('http://logs.example.com/1/1/gate/project-test1/1',
2359 status_jobs[1]['report_url'])
2360
2361 self.assertEqual('project-test2', status_jobs[2]['name'])
2362 self.assertEqual('https://server/job/project-test2/2/',
2363 status_jobs[2]['url'])
2364 self.assertEqual('http://logs.example.com/1/1/gate/project-test2/2',
2365 status_jobs[2]['report_url'])
James E. Blair1843a552013-07-03 14:19:52 -07002366
James E. Blairc3d428e2013-12-03 15:06:48 -08002367 def test_merging_queues(self):
2368 "Test that transitively-connected change queues are merged"
James E. Blairf84026c2015-12-08 16:11:46 -08002369 self.updateConfigLayout(
2370 'tests/fixtures/layout-merge-queues.yaml')
James E. Blairc3d428e2013-12-03 15:06:48 -08002371 self.sched.reconfigure(self.config)
2372 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2373
James E. Blairaf17a972016-02-03 15:07:18 -08002374 def test_mutex(self):
2375 "Test job mutexes"
2376 self.config.set('zuul', 'layout_config',
2377 'tests/fixtures/layout-mutex.yaml')
2378 self.sched.reconfigure(self.config)
2379
2380 self.worker.hold_jobs_in_build = True
2381 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2382 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2383 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2384
2385 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2386 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2387 self.waitUntilSettled()
2388 self.assertEqual(len(self.builds), 3)
2389 self.assertEqual(self.builds[0].name, 'project-test1')
2390 self.assertEqual(self.builds[1].name, 'mutex-one')
2391 self.assertEqual(self.builds[2].name, 'project-test1')
2392
2393 self.worker.release('mutex-one')
2394 self.waitUntilSettled()
2395
2396 self.assertEqual(len(self.builds), 3)
2397 self.assertEqual(self.builds[0].name, 'project-test1')
2398 self.assertEqual(self.builds[1].name, 'project-test1')
2399 self.assertEqual(self.builds[2].name, 'mutex-two')
2400 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2401
2402 self.worker.release('mutex-two')
2403 self.waitUntilSettled()
2404
2405 self.assertEqual(len(self.builds), 3)
2406 self.assertEqual(self.builds[0].name, 'project-test1')
2407 self.assertEqual(self.builds[1].name, 'project-test1')
2408 self.assertEqual(self.builds[2].name, 'mutex-one')
2409 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2410
2411 self.worker.release('mutex-one')
2412 self.waitUntilSettled()
2413
2414 self.assertEqual(len(self.builds), 3)
2415 self.assertEqual(self.builds[0].name, 'project-test1')
2416 self.assertEqual(self.builds[1].name, 'project-test1')
2417 self.assertEqual(self.builds[2].name, 'mutex-two')
2418 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2419
2420 self.worker.release('mutex-two')
2421 self.waitUntilSettled()
2422
2423 self.assertEqual(len(self.builds), 2)
2424 self.assertEqual(self.builds[0].name, 'project-test1')
2425 self.assertEqual(self.builds[1].name, 'project-test1')
2426 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2427
2428 self.worker.hold_jobs_in_build = False
2429 self.worker.release()
2430
2431 self.waitUntilSettled()
2432 self.assertEqual(len(self.builds), 0)
2433
2434 self.assertEqual(A.reported, 1)
2435 self.assertEqual(B.reported, 1)
2436 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2437
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002438 def test_node_label(self):
2439 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002440 self.worker.registerFunction('build:node-project-test1:debian')
2441
2442 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2443 A.addApproval('CRVW', 2)
2444 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2445 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002446
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002447 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2448 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2449 'debian')
2450 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002451
2452 def test_live_reconfiguration(self):
2453 "Test that live reconfiguration works"
2454 self.worker.hold_jobs_in_build = True
2455 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2456 A.addApproval('CRVW', 2)
2457 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2458 self.waitUntilSettled()
2459
2460 self.sched.reconfigure(self.config)
2461
2462 self.worker.hold_jobs_in_build = False
2463 self.worker.release()
2464 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002465 self.assertEqual(self.getJobFromHistory('project-merge').result,
2466 'SUCCESS')
2467 self.assertEqual(self.getJobFromHistory('project-test1').result,
2468 'SUCCESS')
2469 self.assertEqual(self.getJobFromHistory('project-test2').result,
2470 'SUCCESS')
2471 self.assertEqual(A.data['status'], 'MERGED')
2472 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002473
James E. Blair6bc782d2015-07-17 16:20:21 -07002474 def test_live_reconfiguration_merge_conflict(self):
2475 # A real-world bug: a change in a gate queue has a merge
2476 # conflict and a job is added to its project while it's
2477 # sitting in the queue. The job gets added to the change and
2478 # enqueued and the change gets stuck.
2479 self.worker.registerFunction('build:project-test3')
2480 self.worker.hold_jobs_in_build = True
2481
2482 # This change is fine. It's here to stop the queue long
2483 # enough for the next change to be subject to the
2484 # reconfiguration, as well as to provide a conflict for the
2485 # next change. This change will succeed and merge.
2486 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2487 A.addPatchset(['conflict'])
2488 A.addApproval('CRVW', 2)
James E. Blair6bc782d2015-07-17 16:20:21 -07002489
2490 # This change will be in merge conflict. During the
2491 # reconfiguration, we will add a job. We want to make sure
2492 # that doesn't cause it to get stuck.
2493 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2494 B.addPatchset(['conflict'])
2495 B.addApproval('CRVW', 2)
James E. Blair4eb21fa2015-07-27 14:56:47 -07002496
2497 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
James E. Blair6bc782d2015-07-17 16:20:21 -07002498 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2499
2500 self.waitUntilSettled()
2501
2502 # No jobs have run yet
2503 self.assertEqual(A.data['status'], 'NEW')
2504 self.assertEqual(A.reported, 1)
2505 self.assertEqual(B.data['status'], 'NEW')
2506 self.assertEqual(B.reported, 1)
2507 self.assertEqual(len(self.history), 0)
2508
2509 # Add the "project-test3" job.
James E. Blairf84026c2015-12-08 16:11:46 -08002510 self.updateConfigLayout(
2511 'tests/fixtures/layout-live-reconfiguration-add-job.yaml')
James E. Blair6bc782d2015-07-17 16:20:21 -07002512 self.sched.reconfigure(self.config)
2513 self.waitUntilSettled()
2514
2515 self.worker.hold_jobs_in_build = False
2516 self.worker.release()
2517 self.waitUntilSettled()
2518
2519 self.assertEqual(A.data['status'], 'MERGED')
2520 self.assertEqual(A.reported, 2)
2521 self.assertEqual(B.data['status'], 'NEW')
2522 self.assertEqual(B.reported, 2)
2523 self.assertEqual(self.getJobFromHistory('project-merge').result,
2524 'SUCCESS')
2525 self.assertEqual(self.getJobFromHistory('project-test1').result,
2526 'SUCCESS')
2527 self.assertEqual(self.getJobFromHistory('project-test2').result,
2528 'SUCCESS')
2529 self.assertEqual(self.getJobFromHistory('project-test3').result,
2530 'SUCCESS')
2531 self.assertEqual(len(self.history), 4)
2532
James E. Blair400e8fd2015-07-30 17:44:45 -07002533 def test_live_reconfiguration_failed_root(self):
James E. Blair6bc782d2015-07-17 16:20:21 -07002534 # An extrapolation of test_live_reconfiguration_merge_conflict
2535 # that tests a job added to a job tree with a failed root does
2536 # not run.
2537 self.worker.registerFunction('build:project-test3')
2538 self.worker.hold_jobs_in_build = True
2539
2540 # This change is fine. It's here to stop the queue long
2541 # enough for the next change to be subject to the
2542 # reconfiguration. This change will succeed and merge.
2543 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2544 A.addPatchset(['conflict'])
2545 A.addApproval('CRVW', 2)
2546 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2547 self.waitUntilSettled()
2548 self.worker.release('.*-merge')
2549 self.waitUntilSettled()
2550
2551 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2552 self.worker.addFailTest('project-merge', B)
2553 B.addApproval('CRVW', 2)
2554 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2555 self.waitUntilSettled()
2556
2557 self.worker.release('.*-merge')
2558 self.waitUntilSettled()
2559
2560 # Both -merge jobs have run, but no others.
2561 self.assertEqual(A.data['status'], 'NEW')
2562 self.assertEqual(A.reported, 1)
2563 self.assertEqual(B.data['status'], 'NEW')
2564 self.assertEqual(B.reported, 1)
2565 self.assertEqual(self.history[0].result, 'SUCCESS')
2566 self.assertEqual(self.history[0].name, 'project-merge')
2567 self.assertEqual(self.history[1].result, 'FAILURE')
2568 self.assertEqual(self.history[1].name, 'project-merge')
2569 self.assertEqual(len(self.history), 2)
2570
2571 # Add the "project-test3" job.
James E. Blairf84026c2015-12-08 16:11:46 -08002572 self.updateConfigLayout(
2573 'tests/fixtures/layout-live-reconfiguration-add-job.yaml')
James E. Blair6bc782d2015-07-17 16:20:21 -07002574 self.sched.reconfigure(self.config)
2575 self.waitUntilSettled()
2576
2577 self.worker.hold_jobs_in_build = False
2578 self.worker.release()
2579 self.waitUntilSettled()
2580
2581 self.assertEqual(A.data['status'], 'MERGED')
2582 self.assertEqual(A.reported, 2)
2583 self.assertEqual(B.data['status'], 'NEW')
2584 self.assertEqual(B.reported, 2)
2585 self.assertEqual(self.history[0].result, 'SUCCESS')
2586 self.assertEqual(self.history[0].name, 'project-merge')
2587 self.assertEqual(self.history[1].result, 'FAILURE')
2588 self.assertEqual(self.history[1].name, 'project-merge')
2589 self.assertEqual(self.history[2].result, 'SUCCESS')
2590 self.assertEqual(self.history[3].result, 'SUCCESS')
2591 self.assertEqual(self.history[4].result, 'SUCCESS')
2592 self.assertEqual(len(self.history), 5)
2593
James E. Blair400e8fd2015-07-30 17:44:45 -07002594 def test_live_reconfiguration_failed_job(self):
2595 # Test that a change with a removed failing job does not
2596 # disrupt reconfiguration. If a change has a failed job and
2597 # that job is removed during a reconfiguration, we observed a
2598 # bug where the code to re-set build statuses would run on
2599 # that build and raise an exception because the job no longer
2600 # existed.
2601 self.worker.hold_jobs_in_build = True
2602
2603 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2604
2605 # This change will fail and later be removed by the reconfiguration.
2606 self.worker.addFailTest('project-test1', A)
2607
2608 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2609 self.waitUntilSettled()
2610 self.worker.release('.*-merge')
2611 self.waitUntilSettled()
2612 self.worker.release('project-test1')
2613 self.waitUntilSettled()
2614
2615 self.assertEqual(A.data['status'], 'NEW')
2616 self.assertEqual(A.reported, 0)
2617
2618 self.assertEqual(self.getJobFromHistory('project-merge').result,
2619 'SUCCESS')
2620 self.assertEqual(self.getJobFromHistory('project-test1').result,
2621 'FAILURE')
2622 self.assertEqual(len(self.history), 2)
2623
2624 # Remove the test1 job.
James E. Blairf84026c2015-12-08 16:11:46 -08002625 self.updateConfigLayout(
2626 'tests/fixtures/layout-live-reconfiguration-failed-job.yaml')
James E. Blair400e8fd2015-07-30 17:44:45 -07002627 self.sched.reconfigure(self.config)
2628 self.waitUntilSettled()
2629
2630 self.worker.hold_jobs_in_build = False
2631 self.worker.release()
2632 self.waitUntilSettled()
2633
2634 self.assertEqual(self.getJobFromHistory('project-test2').result,
2635 'SUCCESS')
2636 self.assertEqual(self.getJobFromHistory('project-testfile').result,
2637 'SUCCESS')
2638 self.assertEqual(len(self.history), 4)
2639
2640 self.assertEqual(A.data['status'], 'NEW')
2641 self.assertEqual(A.reported, 1)
2642 self.assertIn('Build succeeded', A.messages[0])
2643 # Ensure the removed job was not included in the report.
2644 self.assertNotIn('project-test1', A.messages[0])
2645
James E. Blairfe707d12015-08-05 15:18:15 -07002646 def test_live_reconfiguration_shared_queue(self):
2647 # Test that a change with a failing job which was removed from
2648 # this project but otherwise still exists in the system does
2649 # not disrupt reconfiguration.
2650
2651 self.worker.hold_jobs_in_build = True
2652
2653 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2654
2655 self.worker.addFailTest('project1-project2-integration', A)
2656
2657 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2658 self.waitUntilSettled()
2659 self.worker.release('.*-merge')
2660 self.waitUntilSettled()
2661 self.worker.release('project1-project2-integration')
2662 self.waitUntilSettled()
2663
2664 self.assertEqual(A.data['status'], 'NEW')
2665 self.assertEqual(A.reported, 0)
2666
2667 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2668 'SUCCESS')
2669 self.assertEqual(self.getJobFromHistory(
2670 'project1-project2-integration').result, 'FAILURE')
2671 self.assertEqual(len(self.history), 2)
2672
2673 # Remove the integration job.
James E. Blairf84026c2015-12-08 16:11:46 -08002674 self.updateConfigLayout(
2675 'tests/fixtures/layout-live-reconfiguration-shared-queue.yaml')
James E. Blairfe707d12015-08-05 15:18:15 -07002676 self.sched.reconfigure(self.config)
2677 self.waitUntilSettled()
2678
2679 self.worker.hold_jobs_in_build = False
2680 self.worker.release()
2681 self.waitUntilSettled()
2682
2683 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2684 'SUCCESS')
2685 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2686 'SUCCESS')
2687 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2688 'SUCCESS')
2689 self.assertEqual(self.getJobFromHistory(
2690 'project1-project2-integration').result, 'FAILURE')
2691 self.assertEqual(len(self.history), 4)
2692
2693 self.assertEqual(A.data['status'], 'NEW')
2694 self.assertEqual(A.reported, 1)
2695 self.assertIn('Build succeeded', A.messages[0])
2696 # Ensure the removed job was not included in the report.
2697 self.assertNotIn('project1-project2-integration', A.messages[0])
2698
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11002699 def test_double_live_reconfiguration_shared_queue(self):
2700 # This was a real-world regression. A change is added to
2701 # gate; a reconfigure happens, a second change which depends
2702 # on the first is added, and a second reconfiguration happens.
2703 # Ensure that both changes merge.
2704
2705 # A failure may indicate incorrect caching or cleaning up of
2706 # references during a reconfiguration.
2707 self.worker.hold_jobs_in_build = True
2708
2709 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2710 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2711 B.setDependsOn(A, 1)
2712 A.addApproval('CRVW', 2)
2713 B.addApproval('CRVW', 2)
2714
2715 # Add the parent change.
2716 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2717 self.waitUntilSettled()
2718 self.worker.release('.*-merge')
2719 self.waitUntilSettled()
2720
2721 # Reconfigure (with only one change in the pipeline).
2722 self.sched.reconfigure(self.config)
2723 self.waitUntilSettled()
2724
2725 # Add the child change.
2726 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2727 self.waitUntilSettled()
2728 self.worker.release('.*-merge')
2729 self.waitUntilSettled()
2730
2731 # Reconfigure (with both in the pipeline).
2732 self.sched.reconfigure(self.config)
2733 self.waitUntilSettled()
2734
2735 self.worker.hold_jobs_in_build = False
2736 self.worker.release()
2737 self.waitUntilSettled()
2738
2739 self.assertEqual(len(self.history), 8)
2740
2741 self.assertEqual(A.data['status'], 'MERGED')
2742 self.assertEqual(A.reported, 2)
2743 self.assertEqual(B.data['status'], 'MERGED')
2744 self.assertEqual(B.reported, 2)
2745
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002746 def test_live_reconfiguration_del_project(self):
2747 # Test project deletion from layout
2748 # while changes are enqueued
2749
2750 self.worker.hold_jobs_in_build = True
2751 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2752 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2753 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2754
2755 # A Depends-On: B
2756 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2757 A.subject, B.data['id'])
2758 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2759
2760 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2761 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2762 self.waitUntilSettled()
2763 self.worker.release('.*-merge')
2764 self.waitUntilSettled()
2765 self.assertEqual(len(self.builds), 5)
2766
2767 # This layout defines only org/project, not org/project1
James E. Blairf84026c2015-12-08 16:11:46 -08002768 self.updateConfigLayout(
2769 'tests/fixtures/layout-live-reconfiguration-del-project.yaml')
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002770 self.sched.reconfigure(self.config)
2771 self.waitUntilSettled()
2772
2773 # Builds for C aborted, builds for A succeed,
2774 # and have change B applied ahead
2775 job_c = self.getJobFromHistory('project1-test1')
2776 self.assertEqual(job_c.changes, '3,1')
2777 self.assertEqual(job_c.result, 'ABORTED')
2778
2779 self.worker.hold_jobs_in_build = False
2780 self.worker.release()
2781 self.waitUntilSettled()
2782
2783 self.assertEqual(self.getJobFromHistory('project-test1').changes,
2784 '2,1 1,1')
2785
2786 self.assertEqual(A.data['status'], 'NEW')
2787 self.assertEqual(B.data['status'], 'NEW')
2788 self.assertEqual(C.data['status'], 'NEW')
2789 self.assertEqual(A.reported, 1)
2790 self.assertEqual(B.reported, 0)
2791 self.assertEqual(C.reported, 0)
2792
2793 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
2794 self.assertIn('Build succeeded', A.messages[0])
2795
James E. Blaire712d9f2013-07-31 11:40:11 -07002796 def test_live_reconfiguration_functions(self):
2797 "Test live reconfiguration with a custom function"
2798 self.worker.registerFunction('build:node-project-test1:debian')
2799 self.worker.registerFunction('build:node-project-test1:wheezy')
2800 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2801 A.addApproval('CRVW', 2)
2802 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2803 self.waitUntilSettled()
2804
2805 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2806 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2807 'debian')
2808 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2809
James E. Blairf84026c2015-12-08 16:11:46 -08002810 self.updateConfigLayout(
2811 'tests/fixtures/layout-live-reconfiguration-functions.yaml')
James E. Blaire712d9f2013-07-31 11:40:11 -07002812 self.sched.reconfigure(self.config)
2813 self.worker.build_history = []
2814
2815 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2816 B.addApproval('CRVW', 2)
2817 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2818 self.waitUntilSettled()
2819
2820 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2821 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2822 'wheezy')
2823 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2824
James E. Blair287c06d2013-07-24 10:39:30 -07002825 def test_delayed_repo_init(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002826 self.updateConfigLayout(
2827 'tests/fixtures/layout-delayed-repo-init.yaml')
James E. Blair287c06d2013-07-24 10:39:30 -07002828 self.sched.reconfigure(self.config)
2829
2830 self.init_repo("org/new-project")
2831 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2832
2833 A.addApproval('CRVW', 2)
2834 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2835 self.waitUntilSettled()
2836 self.assertEqual(self.getJobFromHistory('project-merge').result,
2837 'SUCCESS')
2838 self.assertEqual(self.getJobFromHistory('project-test1').result,
2839 'SUCCESS')
2840 self.assertEqual(self.getJobFromHistory('project-test2').result,
2841 'SUCCESS')
2842 self.assertEqual(A.data['status'], 'MERGED')
2843 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002844
Clark Boylan6dbbc482013-10-18 10:57:31 -07002845 def test_repo_deleted(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002846 self.updateConfigLayout(
2847 'tests/fixtures/layout-repo-deleted.yaml')
Clark Boylan6dbbc482013-10-18 10:57:31 -07002848 self.sched.reconfigure(self.config)
2849
2850 self.init_repo("org/delete-project")
2851 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2852
2853 A.addApproval('CRVW', 2)
2854 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2855 self.waitUntilSettled()
2856 self.assertEqual(self.getJobFromHistory('project-merge').result,
2857 'SUCCESS')
2858 self.assertEqual(self.getJobFromHistory('project-test1').result,
2859 'SUCCESS')
2860 self.assertEqual(self.getJobFromHistory('project-test2').result,
2861 'SUCCESS')
2862 self.assertEqual(A.data['status'], 'MERGED')
2863 self.assertEqual(A.reported, 2)
2864
2865 # Delete org/new-project zuul repo. Should be recloned.
2866 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2867
2868 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2869
2870 B.addApproval('CRVW', 2)
2871 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2872 self.waitUntilSettled()
2873 self.assertEqual(self.getJobFromHistory('project-merge').result,
2874 'SUCCESS')
2875 self.assertEqual(self.getJobFromHistory('project-test1').result,
2876 'SUCCESS')
2877 self.assertEqual(self.getJobFromHistory('project-test2').result,
2878 'SUCCESS')
2879 self.assertEqual(B.data['status'], 'MERGED')
2880 self.assertEqual(B.reported, 2)
2881
James E. Blair456f2fb2016-02-09 09:29:33 -08002882 def test_tags(self):
2883 "Test job tags"
2884 self.config.set('zuul', 'layout_config',
2885 'tests/fixtures/layout-tags.yaml')
2886 self.sched.reconfigure(self.config)
2887
2888 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2889 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
2890 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2891 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2892 self.waitUntilSettled()
2893
2894 results = {'project1-merge': 'extratag merge project1',
2895 'project2-merge': 'merge'}
2896
2897 for build in self.history:
2898 self.assertEqual(results.get(build.name, ''),
2899 build.parameters.get('BUILD_TAGS'))
2900
James E. Blair63bb0ef2013-07-29 17:14:51 -07002901 def test_timer(self):
2902 "Test that a periodic job is triggered"
2903 self.worker.hold_jobs_in_build = True
James E. Blairf84026c2015-12-08 16:11:46 -08002904 self.updateConfigLayout(
2905 'tests/fixtures/layout-timer.yaml')
James E. Blair63bb0ef2013-07-29 17:14:51 -07002906 self.sched.reconfigure(self.config)
2907 self.registerJobs()
2908
Clark Boylan3ee090a2014-04-03 20:55:09 -07002909 # The pipeline triggers every second, so we should have seen
2910 # several by now.
2911 time.sleep(5)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002912 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002913
2914 self.assertEqual(len(self.builds), 2)
2915
James E. Blair63bb0ef2013-07-29 17:14:51 -07002916 port = self.webapp.server.socket.getsockname()[1]
2917
Morgan Fainberg293f7f82016-05-30 14:01:22 -07002918 req = urllib.request.Request("http://localhost:%s/status.json" % port)
2919 f = urllib.request.urlopen(req)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002920 data = f.read()
2921
2922 self.worker.hold_jobs_in_build = False
Clark Boylan3ee090a2014-04-03 20:55:09 -07002923 # Stop queuing timer triggered jobs so that the assertions
2924 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08002925 self.updateConfigLayout(
2926 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002927 self.sched.reconfigure(self.config)
2928 self.registerJobs()
James E. Blair63bb0ef2013-07-29 17:14:51 -07002929 self.worker.release()
2930 self.waitUntilSettled()
2931
2932 self.assertEqual(self.getJobFromHistory(
2933 'project-bitrot-stable-old').result, 'SUCCESS')
2934 self.assertEqual(self.getJobFromHistory(
2935 'project-bitrot-stable-older').result, 'SUCCESS')
2936
2937 data = json.loads(data)
2938 status_jobs = set()
2939 for p in data['pipelines']:
2940 for q in p['change_queues']:
2941 for head in q['heads']:
2942 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07002943 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002944 for job in change['jobs']:
2945 status_jobs.add(job['name'])
2946 self.assertIn('project-bitrot-stable-old', status_jobs)
2947 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002948
James E. Blair4f6033c2014-03-27 15:49:09 -07002949 def test_idle(self):
2950 "Test that frequent periodic jobs work"
2951 self.worker.hold_jobs_in_build = True
James E. Blair4f6033c2014-03-27 15:49:09 -07002952
Clark Boylan3ee090a2014-04-03 20:55:09 -07002953 for x in range(1, 3):
2954 # Test that timer triggers periodic jobs even across
2955 # layout config reloads.
2956 # Start timer trigger
James E. Blairf84026c2015-12-08 16:11:46 -08002957 self.updateConfigLayout(
2958 'tests/fixtures/layout-idle.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002959 self.sched.reconfigure(self.config)
2960 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002961 self.waitUntilSettled()
James E. Blair4f6033c2014-03-27 15:49:09 -07002962
Clark Boylan3ee090a2014-04-03 20:55:09 -07002963 # The pipeline triggers every second, so we should have seen
2964 # several by now.
2965 time.sleep(5)
Clark Boylan3ee090a2014-04-03 20:55:09 -07002966
2967 # Stop queuing timer triggered jobs so that the assertions
2968 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08002969 self.updateConfigLayout(
2970 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002971 self.sched.reconfigure(self.config)
2972 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002973 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002974
2975 self.assertEqual(len(self.builds), 2)
2976 self.worker.release('.*')
2977 self.waitUntilSettled()
2978 self.assertEqual(len(self.builds), 0)
2979 self.assertEqual(len(self.history), x * 2)
James E. Blair4f6033c2014-03-27 15:49:09 -07002980
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002981 def test_check_smtp_pool(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002982 self.updateConfigLayout(
2983 'tests/fixtures/layout-smtp.yaml')
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002984 self.sched.reconfigure(self.config)
2985
2986 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2987 self.waitUntilSettled()
2988
2989 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2990 self.waitUntilSettled()
2991
James E. Blairff80a2f2013-12-27 13:24:06 -08002992 self.assertEqual(len(self.smtp_messages), 2)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002993
2994 # A.messages only holds what FakeGerrit places in it. Thus we
2995 # work on the knowledge of what the first message should be as
2996 # it is only configured to go to SMTP.
2997
2998 self.assertEqual('zuul@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002999 self.smtp_messages[0]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003000 self.assertEqual(['you@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003001 self.smtp_messages[0]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003002 self.assertEqual('Starting check jobs.',
James E. Blairff80a2f2013-12-27 13:24:06 -08003003 self.smtp_messages[0]['body'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003004
3005 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003006 self.smtp_messages[1]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003007 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003008 self.smtp_messages[1]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10003009 self.assertEqual(A.messages[0],
James E. Blairff80a2f2013-12-27 13:24:06 -08003010 self.smtp_messages[1]['body'])
James E. Blairad28e912013-11-27 10:43:22 -08003011
James E. Blaire5910202013-12-27 09:50:31 -08003012 def test_timer_smtp(self):
3013 "Test that a periodic job is triggered"
Clark Boylan3ee090a2014-04-03 20:55:09 -07003014 self.worker.hold_jobs_in_build = True
James E. Blairf84026c2015-12-08 16:11:46 -08003015 self.updateConfigLayout(
3016 'tests/fixtures/layout-timer-smtp.yaml')
James E. Blaire5910202013-12-27 09:50:31 -08003017 self.sched.reconfigure(self.config)
3018 self.registerJobs()
3019
Clark Boylan3ee090a2014-04-03 20:55:09 -07003020 # The pipeline triggers every second, so we should have seen
3021 # several by now.
3022 time.sleep(5)
James E. Blaire5910202013-12-27 09:50:31 -08003023 self.waitUntilSettled()
3024
Clark Boylan3ee090a2014-04-03 20:55:09 -07003025 self.assertEqual(len(self.builds), 2)
3026 self.worker.release('.*')
3027 self.waitUntilSettled()
3028 self.assertEqual(len(self.history), 2)
3029
James E. Blaire5910202013-12-27 09:50:31 -08003030 self.assertEqual(self.getJobFromHistory(
3031 'project-bitrot-stable-old').result, 'SUCCESS')
3032 self.assertEqual(self.getJobFromHistory(
3033 'project-bitrot-stable-older').result, 'SUCCESS')
3034
James E. Blairff80a2f2013-12-27 13:24:06 -08003035 self.assertEqual(len(self.smtp_messages), 1)
James E. Blaire5910202013-12-27 09:50:31 -08003036
3037 # A.messages only holds what FakeGerrit places in it. Thus we
3038 # work on the knowledge of what the first message should be as
3039 # it is only configured to go to SMTP.
3040
3041 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003042 self.smtp_messages[0]['from_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003043 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003044 self.smtp_messages[0]['to_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003045 self.assertIn('Subject: Periodic check for org/project succeeded',
James E. Blairff80a2f2013-12-27 13:24:06 -08003046 self.smtp_messages[0]['headers'])
James E. Blaire5910202013-12-27 09:50:31 -08003047
Clark Boylan3ee090a2014-04-03 20:55:09 -07003048 # Stop queuing timer triggered jobs and let any that may have
3049 # queued through so that end of test assertions pass.
James E. Blairf84026c2015-12-08 16:11:46 -08003050 self.updateConfigLayout(
3051 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07003052 self.sched.reconfigure(self.config)
3053 self.registerJobs()
James E. Blairf8058972014-08-15 16:09:16 -07003054 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07003055 self.worker.release('.*')
3056 self.waitUntilSettled()
3057
James E. Blair91e34592015-07-31 16:45:59 -07003058 def test_client_enqueue_change(self):
James E. Blairad28e912013-11-27 10:43:22 -08003059 "Test that the RPC client can enqueue a change"
3060 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3061 A.addApproval('CRVW', 2)
3062 A.addApproval('APRV', 1)
3063
3064 client = zuul.rpcclient.RPCClient('127.0.0.1',
3065 self.gearman_server.port)
3066 r = client.enqueue(pipeline='gate',
3067 project='org/project',
3068 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003069 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003070 self.waitUntilSettled()
3071 self.assertEqual(self.getJobFromHistory('project-merge').result,
3072 'SUCCESS')
3073 self.assertEqual(self.getJobFromHistory('project-test1').result,
3074 'SUCCESS')
3075 self.assertEqual(self.getJobFromHistory('project-test2').result,
3076 'SUCCESS')
3077 self.assertEqual(A.data['status'], 'MERGED')
3078 self.assertEqual(A.reported, 2)
3079 self.assertEqual(r, True)
3080
James E. Blair91e34592015-07-31 16:45:59 -07003081 def test_client_enqueue_ref(self):
3082 "Test that the RPC client can enqueue a ref"
3083
3084 client = zuul.rpcclient.RPCClient('127.0.0.1',
3085 self.gearman_server.port)
3086 r = client.enqueue_ref(
3087 pipeline='post',
3088 project='org/project',
3089 trigger='gerrit',
3090 ref='master',
3091 oldrev='90f173846e3af9154517b88543ffbd1691f31366',
3092 newrev='d479a0bfcb34da57a31adb2a595c0cf687812543')
3093 self.waitUntilSettled()
3094 job_names = [x.name for x in self.history]
3095 self.assertEqual(len(self.history), 1)
3096 self.assertIn('project-post', job_names)
3097 self.assertEqual(r, True)
3098
James E. Blairad28e912013-11-27 10:43:22 -08003099 def test_client_enqueue_negative(self):
3100 "Test that the RPC client returns errors"
3101 client = zuul.rpcclient.RPCClient('127.0.0.1',
3102 self.gearman_server.port)
3103 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3104 "Invalid project"):
3105 r = client.enqueue(pipeline='gate',
3106 project='project-does-not-exist',
3107 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003108 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003109 client.shutdown()
3110 self.assertEqual(r, False)
3111
3112 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3113 "Invalid pipeline"):
3114 r = client.enqueue(pipeline='pipeline-does-not-exist',
3115 project='org/project',
3116 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003117 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003118 client.shutdown()
3119 self.assertEqual(r, False)
3120
3121 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3122 "Invalid trigger"):
3123 r = client.enqueue(pipeline='gate',
3124 project='org/project',
3125 trigger='trigger-does-not-exist',
James E. Blair36658cf2013-12-06 17:53:48 -08003126 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003127 client.shutdown()
3128 self.assertEqual(r, False)
3129
3130 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3131 "Invalid change"):
3132 r = client.enqueue(pipeline='gate',
3133 project='org/project',
3134 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003135 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003136 client.shutdown()
3137 self.assertEqual(r, False)
3138
3139 self.waitUntilSettled()
3140 self.assertEqual(len(self.history), 0)
3141 self.assertEqual(len(self.builds), 0)
James E. Blair36658cf2013-12-06 17:53:48 -08003142
3143 def test_client_promote(self):
3144 "Test that the RPC client can promote a change"
3145 self.worker.hold_jobs_in_build = True
3146 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3147 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3148 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3149 A.addApproval('CRVW', 2)
3150 B.addApproval('CRVW', 2)
3151 C.addApproval('CRVW', 2)
3152
3153 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3154 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3155 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3156
3157 self.waitUntilSettled()
3158
Sean Daguef39b9ca2014-01-10 21:34:35 -05003159 items = self.sched.layout.pipelines['gate'].getAllItems()
3160 enqueue_times = {}
3161 for item in items:
3162 enqueue_times[str(item.change)] = item.enqueue_time
3163
James E. Blair36658cf2013-12-06 17:53:48 -08003164 client = zuul.rpcclient.RPCClient('127.0.0.1',
3165 self.gearman_server.port)
3166 r = client.promote(pipeline='gate',
3167 change_ids=['2,1', '3,1'])
3168
Sean Daguef39b9ca2014-01-10 21:34:35 -05003169 # ensure that enqueue times are durable
3170 items = self.sched.layout.pipelines['gate'].getAllItems()
3171 for item in items:
3172 self.assertEqual(
3173 enqueue_times[str(item.change)], item.enqueue_time)
3174
James E. Blair78acec92014-02-06 07:11:32 -08003175 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003176 self.worker.release('.*-merge')
3177 self.waitUntilSettled()
3178 self.worker.release('.*-merge')
3179 self.waitUntilSettled()
3180 self.worker.release('.*-merge')
3181 self.waitUntilSettled()
3182
3183 self.assertEqual(len(self.builds), 6)
3184 self.assertEqual(self.builds[0].name, 'project-test1')
3185 self.assertEqual(self.builds[1].name, 'project-test2')
3186 self.assertEqual(self.builds[2].name, 'project-test1')
3187 self.assertEqual(self.builds[3].name, 'project-test2')
3188 self.assertEqual(self.builds[4].name, 'project-test1')
3189 self.assertEqual(self.builds[5].name, 'project-test2')
3190
3191 self.assertTrue(self.job_has_changes(self.builds[0], B))
3192 self.assertFalse(self.job_has_changes(self.builds[0], A))
3193 self.assertFalse(self.job_has_changes(self.builds[0], C))
3194
3195 self.assertTrue(self.job_has_changes(self.builds[2], B))
3196 self.assertTrue(self.job_has_changes(self.builds[2], C))
3197 self.assertFalse(self.job_has_changes(self.builds[2], A))
3198
3199 self.assertTrue(self.job_has_changes(self.builds[4], B))
3200 self.assertTrue(self.job_has_changes(self.builds[4], C))
3201 self.assertTrue(self.job_has_changes(self.builds[4], A))
3202
3203 self.worker.release()
3204 self.waitUntilSettled()
3205
3206 self.assertEqual(A.data['status'], 'MERGED')
3207 self.assertEqual(A.reported, 2)
3208 self.assertEqual(B.data['status'], 'MERGED')
3209 self.assertEqual(B.reported, 2)
3210 self.assertEqual(C.data['status'], 'MERGED')
3211 self.assertEqual(C.reported, 2)
3212
3213 client.shutdown()
3214 self.assertEqual(r, True)
3215
3216 def test_client_promote_dependent(self):
3217 "Test that the RPC client can promote a dependent change"
3218 # C (depends on B) -> B -> A ; then promote C to get:
3219 # A -> C (depends on B) -> B
3220 self.worker.hold_jobs_in_build = True
3221 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3222 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3223 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3224
3225 C.setDependsOn(B, 1)
3226
3227 A.addApproval('CRVW', 2)
3228 B.addApproval('CRVW', 2)
3229 C.addApproval('CRVW', 2)
3230
3231 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3232 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3233 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3234
3235 self.waitUntilSettled()
3236
3237 client = zuul.rpcclient.RPCClient('127.0.0.1',
3238 self.gearman_server.port)
3239 r = client.promote(pipeline='gate',
3240 change_ids=['3,1'])
3241
James E. Blair78acec92014-02-06 07:11:32 -08003242 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003243 self.worker.release('.*-merge')
3244 self.waitUntilSettled()
3245 self.worker.release('.*-merge')
3246 self.waitUntilSettled()
3247 self.worker.release('.*-merge')
3248 self.waitUntilSettled()
3249
3250 self.assertEqual(len(self.builds), 6)
3251 self.assertEqual(self.builds[0].name, 'project-test1')
3252 self.assertEqual(self.builds[1].name, 'project-test2')
3253 self.assertEqual(self.builds[2].name, 'project-test1')
3254 self.assertEqual(self.builds[3].name, 'project-test2')
3255 self.assertEqual(self.builds[4].name, 'project-test1')
3256 self.assertEqual(self.builds[5].name, 'project-test2')
3257
3258 self.assertTrue(self.job_has_changes(self.builds[0], B))
3259 self.assertFalse(self.job_has_changes(self.builds[0], A))
3260 self.assertFalse(self.job_has_changes(self.builds[0], C))
3261
3262 self.assertTrue(self.job_has_changes(self.builds[2], B))
3263 self.assertTrue(self.job_has_changes(self.builds[2], C))
3264 self.assertFalse(self.job_has_changes(self.builds[2], A))
3265
3266 self.assertTrue(self.job_has_changes(self.builds[4], B))
3267 self.assertTrue(self.job_has_changes(self.builds[4], C))
3268 self.assertTrue(self.job_has_changes(self.builds[4], A))
3269
3270 self.worker.release()
3271 self.waitUntilSettled()
3272
3273 self.assertEqual(A.data['status'], 'MERGED')
3274 self.assertEqual(A.reported, 2)
3275 self.assertEqual(B.data['status'], 'MERGED')
3276 self.assertEqual(B.reported, 2)
3277 self.assertEqual(C.data['status'], 'MERGED')
3278 self.assertEqual(C.reported, 2)
3279
3280 client.shutdown()
3281 self.assertEqual(r, True)
3282
3283 def test_client_promote_negative(self):
3284 "Test that the RPC client returns errors for promotion"
3285 self.worker.hold_jobs_in_build = True
3286 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3287 A.addApproval('CRVW', 2)
3288 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3289 self.waitUntilSettled()
3290
3291 client = zuul.rpcclient.RPCClient('127.0.0.1',
3292 self.gearman_server.port)
3293
3294 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3295 r = client.promote(pipeline='nonexistent',
3296 change_ids=['2,1', '3,1'])
3297 client.shutdown()
3298 self.assertEqual(r, False)
3299
3300 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3301 r = client.promote(pipeline='gate',
3302 change_ids=['4,1'])
3303 client.shutdown()
3304 self.assertEqual(r, False)
3305
3306 self.worker.hold_jobs_in_build = False
3307 self.worker.release()
3308 self.waitUntilSettled()
Clark Boylan7603a372014-01-21 11:43:20 -08003309
3310 def test_queue_rate_limiting(self):
3311 "Test that DependentPipelines are rate limited with dep across window"
James E. Blairf84026c2015-12-08 16:11:46 -08003312 self.updateConfigLayout(
3313 'tests/fixtures/layout-rate-limit.yaml')
Clark Boylan7603a372014-01-21 11:43:20 -08003314 self.sched.reconfigure(self.config)
3315 self.worker.hold_jobs_in_build = True
3316 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3317 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3318 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3319
3320 C.setDependsOn(B, 1)
3321 self.worker.addFailTest('project-test1', A)
3322
3323 A.addApproval('CRVW', 2)
3324 B.addApproval('CRVW', 2)
3325 C.addApproval('CRVW', 2)
3326
3327 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3328 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3329 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3330 self.waitUntilSettled()
3331
3332 # Only A and B will have their merge jobs queued because
3333 # window is 2.
3334 self.assertEqual(len(self.builds), 2)
3335 self.assertEqual(self.builds[0].name, 'project-merge')
3336 self.assertEqual(self.builds[1].name, 'project-merge')
3337
3338 self.worker.release('.*-merge')
3339 self.waitUntilSettled()
3340 self.worker.release('.*-merge')
3341 self.waitUntilSettled()
3342
3343 # Only A and B will have their test jobs queued because
3344 # window is 2.
3345 self.assertEqual(len(self.builds), 4)
3346 self.assertEqual(self.builds[0].name, 'project-test1')
3347 self.assertEqual(self.builds[1].name, 'project-test2')
3348 self.assertEqual(self.builds[2].name, 'project-test1')
3349 self.assertEqual(self.builds[3].name, 'project-test2')
3350
3351 self.worker.release('project-.*')
3352 self.waitUntilSettled()
3353
3354 queue = self.sched.layout.pipelines['gate'].queues[0]
3355 # A failed so window is reduced by 1 to 1.
3356 self.assertEqual(queue.window, 1)
3357 self.assertEqual(queue.window_floor, 1)
3358 self.assertEqual(A.data['status'], 'NEW')
3359
3360 # Gate is reset and only B's merge job is queued because
3361 # window shrunk to 1.
3362 self.assertEqual(len(self.builds), 1)
3363 self.assertEqual(self.builds[0].name, 'project-merge')
3364
3365 self.worker.release('.*-merge')
3366 self.waitUntilSettled()
3367
3368 # Only B's test jobs are queued because window is still 1.
3369 self.assertEqual(len(self.builds), 2)
3370 self.assertEqual(self.builds[0].name, 'project-test1')
3371 self.assertEqual(self.builds[1].name, 'project-test2')
3372
3373 self.worker.release('project-.*')
3374 self.waitUntilSettled()
3375
3376 # B was successfully merged so window is increased to 2.
3377 self.assertEqual(queue.window, 2)
3378 self.assertEqual(queue.window_floor, 1)
3379 self.assertEqual(B.data['status'], 'MERGED')
3380
3381 # Only C is left and its merge job is queued.
3382 self.assertEqual(len(self.builds), 1)
3383 self.assertEqual(self.builds[0].name, 'project-merge')
3384
3385 self.worker.release('.*-merge')
3386 self.waitUntilSettled()
3387
3388 # After successful merge job the test jobs for C are queued.
3389 self.assertEqual(len(self.builds), 2)
3390 self.assertEqual(self.builds[0].name, 'project-test1')
3391 self.assertEqual(self.builds[1].name, 'project-test2')
3392
3393 self.worker.release('project-.*')
3394 self.waitUntilSettled()
3395
3396 # C successfully merged so window is bumped to 3.
3397 self.assertEqual(queue.window, 3)
3398 self.assertEqual(queue.window_floor, 1)
3399 self.assertEqual(C.data['status'], 'MERGED')
3400
3401 def test_queue_rate_limiting_dependent(self):
3402 "Test that DependentPipelines are rate limited with dep in window"
James E. Blairf84026c2015-12-08 16:11:46 -08003403 self.updateConfigLayout(
3404 'tests/fixtures/layout-rate-limit.yaml')
Clark Boylan7603a372014-01-21 11:43:20 -08003405 self.sched.reconfigure(self.config)
3406 self.worker.hold_jobs_in_build = True
3407 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3408 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3409 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3410
3411 B.setDependsOn(A, 1)
3412
3413 self.worker.addFailTest('project-test1', A)
3414
3415 A.addApproval('CRVW', 2)
3416 B.addApproval('CRVW', 2)
3417 C.addApproval('CRVW', 2)
3418
3419 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3420 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3421 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3422 self.waitUntilSettled()
3423
3424 # Only A and B will have their merge jobs queued because
3425 # window is 2.
3426 self.assertEqual(len(self.builds), 2)
3427 self.assertEqual(self.builds[0].name, 'project-merge')
3428 self.assertEqual(self.builds[1].name, 'project-merge')
3429
3430 self.worker.release('.*-merge')
3431 self.waitUntilSettled()
3432 self.worker.release('.*-merge')
3433 self.waitUntilSettled()
3434
3435 # Only A and B will have their test jobs queued because
3436 # window is 2.
3437 self.assertEqual(len(self.builds), 4)
3438 self.assertEqual(self.builds[0].name, 'project-test1')
3439 self.assertEqual(self.builds[1].name, 'project-test2')
3440 self.assertEqual(self.builds[2].name, 'project-test1')
3441 self.assertEqual(self.builds[3].name, 'project-test2')
3442
3443 self.worker.release('project-.*')
3444 self.waitUntilSettled()
3445
3446 queue = self.sched.layout.pipelines['gate'].queues[0]
3447 # A failed so window is reduced by 1 to 1.
3448 self.assertEqual(queue.window, 1)
3449 self.assertEqual(queue.window_floor, 1)
3450 self.assertEqual(A.data['status'], 'NEW')
3451 self.assertEqual(B.data['status'], 'NEW')
3452
3453 # Gate is reset and only C's merge job is queued because
3454 # window shrunk to 1 and A and B were dequeued.
3455 self.assertEqual(len(self.builds), 1)
3456 self.assertEqual(self.builds[0].name, 'project-merge')
3457
3458 self.worker.release('.*-merge')
3459 self.waitUntilSettled()
3460
3461 # Only C's test jobs are queued because window is still 1.
3462 self.assertEqual(len(self.builds), 2)
3463 self.assertEqual(self.builds[0].name, 'project-test1')
3464 self.assertEqual(self.builds[1].name, 'project-test2')
3465
3466 self.worker.release('project-.*')
3467 self.waitUntilSettled()
3468
3469 # C was successfully merged so window is increased to 2.
3470 self.assertEqual(queue.window, 2)
3471 self.assertEqual(queue.window_floor, 1)
3472 self.assertEqual(C.data['status'], 'MERGED')
Joshua Heskethba8776a2014-01-12 14:35:40 +08003473
3474 def test_worker_update_metadata(self):
3475 "Test if a worker can send back metadata about itself"
3476 self.worker.hold_jobs_in_build = True
3477
3478 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3479 A.addApproval('CRVW', 2)
3480 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3481 self.waitUntilSettled()
3482
3483 self.assertEqual(len(self.launcher.builds), 1)
3484
3485 self.log.debug('Current builds:')
3486 self.log.debug(self.launcher.builds)
3487
3488 start = time.time()
3489 while True:
3490 if time.time() - start > 10:
3491 raise Exception("Timeout waiting for gearman server to report "
3492 + "back to the client")
3493 build = self.launcher.builds.values()[0]
3494 if build.worker.name == "My Worker":
3495 break
3496 else:
3497 time.sleep(0)
3498
3499 self.log.debug(build)
3500 self.assertEqual("My Worker", build.worker.name)
3501 self.assertEqual("localhost", build.worker.hostname)
3502 self.assertEqual(['127.0.0.1', '192.168.1.1'], build.worker.ips)
3503 self.assertEqual("zuul.example.org", build.worker.fqdn)
3504 self.assertEqual("FakeBuilder", build.worker.program)
3505 self.assertEqual("v1.1", build.worker.version)
3506 self.assertEqual({'something': 'else'}, build.worker.extra)
3507
3508 self.worker.hold_jobs_in_build = False
3509 self.worker.release()
3510 self.waitUntilSettled()
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003511
3512 def test_footer_message(self):
3513 "Test a pipeline's footer message is correctly added to the report."
James E. Blairf84026c2015-12-08 16:11:46 -08003514 self.updateConfigLayout(
3515 'tests/fixtures/layout-footer-message.yaml')
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003516 self.sched.reconfigure(self.config)
3517 self.registerJobs()
3518
3519 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3520 A.addApproval('CRVW', 2)
3521 self.worker.addFailTest('test1', A)
3522 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3523 self.waitUntilSettled()
3524
3525 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3526 B.addApproval('CRVW', 2)
3527 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3528 self.waitUntilSettled()
3529
3530 self.assertEqual(2, len(self.smtp_messages))
3531
3532 failure_body = """\
3533Build failed. For information on how to proceed, see \
3534http://wiki.example.org/Test_Failures
3535
3536- test1 http://logs.example.com/1/1/gate/test1/0 : FAILURE in 0s
3537- test2 http://logs.example.com/1/1/gate/test2/1 : SUCCESS in 0s
3538
3539For CI problems and help debugging, contact ci@example.org"""
3540
3541 success_body = """\
3542Build succeeded.
3543
3544- test1 http://logs.example.com/2/1/gate/test1/2 : SUCCESS in 0s
3545- test2 http://logs.example.com/2/1/gate/test2/3 : SUCCESS in 0s
3546
3547For CI problems and help debugging, contact ci@example.org"""
3548
3549 self.assertEqual(failure_body, self.smtp_messages[0]['body'])
3550 self.assertEqual(success_body, self.smtp_messages[1]['body'])
Joshua Heskethb7179772014-01-30 23:30:46 +11003551
3552 def test_merge_failure_reporters(self):
3553 """Check that the config is set up correctly"""
3554
James E. Blairf84026c2015-12-08 16:11:46 -08003555 self.updateConfigLayout(
3556 'tests/fixtures/layout-merge-failure.yaml')
Joshua Heskethb7179772014-01-30 23:30:46 +11003557 self.sched.reconfigure(self.config)
3558 self.registerJobs()
3559
3560 self.assertEqual(
Jeremy Stanley1c2c3c22015-06-15 21:23:19 +00003561 "Merge Failed.\n\nThis change or one of its cross-repo "
3562 "dependencies was unable to be automatically merged with the "
3563 "current state of its repository. Please rebase the change and "
3564 "upload a new patchset.",
Joshua Heskethb7179772014-01-30 23:30:46 +11003565 self.sched.layout.pipelines['check'].merge_failure_message)
3566 self.assertEqual(
3567 "The merge failed! For more information...",
3568 self.sched.layout.pipelines['gate'].merge_failure_message)
3569
3570 self.assertEqual(
3571 len(self.sched.layout.pipelines['check'].merge_failure_actions), 1)
3572 self.assertEqual(
3573 len(self.sched.layout.pipelines['gate'].merge_failure_actions), 2)
3574
3575 self.assertTrue(isinstance(
Joshua Heskethde958652015-11-10 19:19:50 +11003576 self.sched.layout.pipelines['check'].merge_failure_actions[0],
3577 zuul.reporter.gerrit.GerritReporter))
Joshua Heskethb7179772014-01-30 23:30:46 +11003578
3579 self.assertTrue(
3580 (
3581 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003582 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003583 zuul.reporter.smtp.SMTPReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003584 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003585 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003586 zuul.reporter.gerrit.GerritReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003587 ) or (
3588 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003589 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003590 zuul.reporter.gerrit.GerritReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003591 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003592 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003593 zuul.reporter.smtp.SMTPReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003594 )
3595 )
3596
3597 def test_merge_failure_reports(self):
3598 """Check that when a change fails to merge the correct message is sent
3599 to the correct reporter"""
James E. Blairf84026c2015-12-08 16:11:46 -08003600 self.updateConfigLayout(
3601 'tests/fixtures/layout-merge-failure.yaml')
Joshua Heskethb7179772014-01-30 23:30:46 +11003602 self.sched.reconfigure(self.config)
3603 self.registerJobs()
3604
3605 # Check a test failure isn't reported to SMTP
3606 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3607 A.addApproval('CRVW', 2)
3608 self.worker.addFailTest('project-test1', A)
3609 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3610 self.waitUntilSettled()
3611
3612 self.assertEqual(3, len(self.history)) # 3 jobs
3613 self.assertEqual(0, len(self.smtp_messages))
3614
3615 # Check a merge failure is reported to SMTP
3616 # B should be merged, but C will conflict with B
3617 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3618 B.addPatchset(['conflict'])
3619 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3620 C.addPatchset(['conflict'])
3621 B.addApproval('CRVW', 2)
3622 C.addApproval('CRVW', 2)
3623 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3624 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3625 self.waitUntilSettled()
3626
3627 self.assertEqual(6, len(self.history)) # A and B jobs
3628 self.assertEqual(1, len(self.smtp_messages))
3629 self.assertEqual('The merge failed! For more information...',
3630 self.smtp_messages[0]['body'])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003631
James E. Blairf760f0e2016-02-09 08:44:52 -08003632 def test_default_merge_failure_reports(self):
3633 """Check that the default merge failure reports are correct."""
3634
3635 # A should report success, B should report merge failure.
3636 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3637 A.addPatchset(['conflict'])
3638 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3639 B.addPatchset(['conflict'])
3640 A.addApproval('CRVW', 2)
3641 B.addApproval('CRVW', 2)
3642 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3643 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3644 self.waitUntilSettled()
3645
3646 self.assertEqual(3, len(self.history)) # A jobs
3647 self.assertEqual(A.reported, 2)
3648 self.assertEqual(B.reported, 2)
3649 self.assertEqual(A.data['status'], 'MERGED')
3650 self.assertEqual(B.data['status'], 'NEW')
3651 self.assertIn('Build succeeded', A.messages[1])
3652 self.assertIn('Merge Failed', B.messages[1])
3653 self.assertIn('automatically merged', B.messages[1])
3654 self.assertNotIn('logs.example.com', B.messages[1])
3655 self.assertNotIn('SKIPPED', B.messages[1])
3656
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003657 def test_swift_instructions(self):
3658 "Test that the correct swift instructions are sent to the workers"
James E. Blairf84026c2015-12-08 16:11:46 -08003659 self.updateConfigLayout(
3660 'tests/fixtures/layout-swift.yaml')
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003661 self.sched.reconfigure(self.config)
3662 self.registerJobs()
3663
3664 self.worker.hold_jobs_in_build = True
3665 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3666
3667 A.addApproval('CRVW', 2)
3668 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3669 self.waitUntilSettled()
3670
3671 self.assertEqual(
3672 "https://storage.example.org/V1/AUTH_account/merge_logs/1/1/1/"
3673 "gate/test-merge/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003674 self.builds[0].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003675 self.assertEqual(5,
3676 len(self.builds[0].parameters['SWIFT_logs_HMAC_BODY'].
3677 split('\n')))
3678 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[0].parameters)
3679
3680 self.assertEqual(
3681 "https://storage.example.org/V1/AUTH_account/logs/1/1/1/"
3682 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003683 self.builds[1].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003684 self.assertEqual(5,
3685 len(self.builds[1].parameters['SWIFT_logs_HMAC_BODY'].
3686 split('\n')))
3687 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[1].parameters)
3688
3689 self.assertEqual(
3690 "https://storage.example.org/V1/AUTH_account/stash/1/1/1/"
3691 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003692 self.builds[1].parameters['SWIFT_MOSTLY_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003693 self.assertEqual(5,
3694 len(self.builds[1].
3695 parameters['SWIFT_MOSTLY_HMAC_BODY'].split('\n')))
3696 self.assertIn('SWIFT_MOSTLY_SIGNATURE', self.builds[1].parameters)
3697
3698 self.worker.hold_jobs_in_build = False
3699 self.worker.release()
3700 self.waitUntilSettled()
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003701
3702 def test_client_get_running_jobs(self):
3703 "Test that the RPC client can get a list of running jobs"
3704 self.worker.hold_jobs_in_build = True
3705 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3706 A.addApproval('CRVW', 2)
3707 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3708 self.waitUntilSettled()
3709
3710 client = zuul.rpcclient.RPCClient('127.0.0.1',
3711 self.gearman_server.port)
3712
3713 # Wait for gearman server to send the initial workData back to zuul
3714 start = time.time()
3715 while True:
3716 if time.time() - start > 10:
3717 raise Exception("Timeout waiting for gearman server to report "
3718 + "back to the client")
3719 build = self.launcher.builds.values()[0]
3720 if build.worker.name == "My Worker":
3721 break
3722 else:
3723 time.sleep(0)
3724
3725 running_items = client.get_running_jobs()
3726
3727 self.assertEqual(1, len(running_items))
3728 running_item = running_items[0]
3729 self.assertEqual([], running_item['failing_reasons'])
3730 self.assertEqual([], running_item['items_behind'])
3731 self.assertEqual('https://hostname/1', running_item['url'])
3732 self.assertEqual(None, running_item['item_ahead'])
3733 self.assertEqual('org/project', running_item['project'])
3734 self.assertEqual(None, running_item['remaining_time'])
3735 self.assertEqual(True, running_item['active'])
3736 self.assertEqual('1,1', running_item['id'])
3737
3738 self.assertEqual(3, len(running_item['jobs']))
3739 for job in running_item['jobs']:
3740 if job['name'] == 'project-merge':
3741 self.assertEqual('project-merge', job['name'])
3742 self.assertEqual('gate', job['pipeline'])
3743 self.assertEqual(False, job['retry'])
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003744 self.assertEqual('https://server/job/project-merge/0/',
3745 job['url'])
3746 self.assertEqual(7, len(job['worker']))
3747 self.assertEqual(False, job['canceled'])
3748 self.assertEqual(True, job['voting'])
3749 self.assertEqual(None, job['result'])
3750 self.assertEqual('gate', job['pipeline'])
3751 break
3752
3753 self.worker.hold_jobs_in_build = False
3754 self.worker.release()
3755 self.waitUntilSettled()
3756
3757 running_items = client.get_running_jobs()
3758 self.assertEqual(0, len(running_items))
James E. Blairbadc1ad2014-04-28 13:55:14 -07003759
3760 def test_nonvoting_pipeline(self):
3761 "Test that a nonvoting pipeline (experimental) can still report"
3762
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003763 A = self.fake_gerrit.addFakeChange('org/experimental-project',
3764 'master', 'A')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003765 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3766 self.waitUntilSettled()
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003767 self.assertEqual(
3768 self.getJobFromHistory('experimental-project-test').result,
3769 'SUCCESS')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003770 self.assertEqual(A.reported, 1)
James E. Blair5ee24252014-12-30 10:12:29 -08003771
3772 def test_crd_gate(self):
3773 "Test cross-repo dependencies"
3774 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3775 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3776 A.addApproval('CRVW', 2)
3777 B.addApproval('CRVW', 2)
3778
3779 AM2 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM2')
3780 AM1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM1')
3781 AM2.setMerged()
3782 AM1.setMerged()
3783
3784 BM2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM2')
3785 BM1 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM1')
3786 BM2.setMerged()
3787 BM1.setMerged()
3788
3789 # A -> AM1 -> AM2
3790 # B -> BM1 -> BM2
3791 # A Depends-On: B
3792 # M2 is here to make sure it is never queried. If it is, it
3793 # means zuul is walking down the entire history of merged
3794 # changes.
3795
3796 B.setDependsOn(BM1, 1)
3797 BM1.setDependsOn(BM2, 1)
3798
3799 A.setDependsOn(AM1, 1)
3800 AM1.setDependsOn(AM2, 1)
3801
3802 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3803 A.subject, B.data['id'])
3804
3805 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3806 self.waitUntilSettled()
3807
3808 self.assertEqual(A.data['status'], 'NEW')
3809 self.assertEqual(B.data['status'], 'NEW')
3810
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11003811 for connection in self.connections.values():
3812 connection.maintainCache([])
James E. Blair5ee24252014-12-30 10:12:29 -08003813
3814 self.worker.hold_jobs_in_build = True
3815 B.addApproval('APRV', 1)
3816 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3817 self.waitUntilSettled()
3818
3819 self.worker.release('.*-merge')
3820 self.waitUntilSettled()
3821 self.worker.release('.*-merge')
3822 self.waitUntilSettled()
3823 self.worker.hold_jobs_in_build = False
3824 self.worker.release()
3825 self.waitUntilSettled()
3826
3827 self.assertEqual(AM2.queried, 0)
3828 self.assertEqual(BM2.queried, 0)
3829 self.assertEqual(A.data['status'], 'MERGED')
3830 self.assertEqual(B.data['status'], 'MERGED')
3831 self.assertEqual(A.reported, 2)
3832 self.assertEqual(B.reported, 2)
3833
James E. Blair8f78d882015-02-05 08:51:37 -08003834 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3835 '2,1 1,1')
3836
3837 def test_crd_branch(self):
3838 "Test cross-repo dependencies in multiple branches"
3839 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3840 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3841 C = self.fake_gerrit.addFakeChange('org/project2', 'mp', 'C')
3842 C.data['id'] = B.data['id']
3843 A.addApproval('CRVW', 2)
3844 B.addApproval('CRVW', 2)
3845 C.addApproval('CRVW', 2)
3846
3847 # A Depends-On: B+C
3848 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3849 A.subject, B.data['id'])
3850
3851 self.worker.hold_jobs_in_build = True
3852 B.addApproval('APRV', 1)
3853 C.addApproval('APRV', 1)
3854 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3855 self.waitUntilSettled()
3856
3857 self.worker.release('.*-merge')
3858 self.waitUntilSettled()
3859 self.worker.release('.*-merge')
3860 self.waitUntilSettled()
3861 self.worker.release('.*-merge')
3862 self.waitUntilSettled()
3863 self.worker.hold_jobs_in_build = False
3864 self.worker.release()
3865 self.waitUntilSettled()
3866
3867 self.assertEqual(A.data['status'], 'MERGED')
3868 self.assertEqual(B.data['status'], 'MERGED')
3869 self.assertEqual(C.data['status'], 'MERGED')
3870 self.assertEqual(A.reported, 2)
3871 self.assertEqual(B.reported, 2)
3872 self.assertEqual(C.reported, 2)
3873
3874 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3875 '2,1 3,1 1,1')
3876
3877 def test_crd_multiline(self):
3878 "Test multiple depends-on lines in commit"
3879 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3880 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3881 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
3882 A.addApproval('CRVW', 2)
3883 B.addApproval('CRVW', 2)
3884 C.addApproval('CRVW', 2)
3885
3886 # A Depends-On: B+C
3887 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
3888 A.subject, B.data['id'], C.data['id'])
3889
3890 self.worker.hold_jobs_in_build = True
3891 B.addApproval('APRV', 1)
3892 C.addApproval('APRV', 1)
3893 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3894 self.waitUntilSettled()
3895
3896 self.worker.release('.*-merge')
3897 self.waitUntilSettled()
3898 self.worker.release('.*-merge')
3899 self.waitUntilSettled()
3900 self.worker.release('.*-merge')
3901 self.waitUntilSettled()
3902 self.worker.hold_jobs_in_build = False
3903 self.worker.release()
3904 self.waitUntilSettled()
3905
3906 self.assertEqual(A.data['status'], 'MERGED')
3907 self.assertEqual(B.data['status'], 'MERGED')
3908 self.assertEqual(C.data['status'], 'MERGED')
3909 self.assertEqual(A.reported, 2)
3910 self.assertEqual(B.reported, 2)
3911 self.assertEqual(C.reported, 2)
3912
3913 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3914 '2,1 3,1 1,1')
James E. Blair5ee24252014-12-30 10:12:29 -08003915
3916 def test_crd_unshared_gate(self):
3917 "Test cross-repo dependencies in unshared gate queues"
3918 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3919 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3920 A.addApproval('CRVW', 2)
3921 B.addApproval('CRVW', 2)
3922
3923 # A Depends-On: B
3924 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3925 A.subject, B.data['id'])
3926
3927 # A and B do not share a queue, make sure that A is unable to
3928 # enqueue B (and therefore, A is unable to be enqueued).
3929 B.addApproval('APRV', 1)
3930 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3931 self.waitUntilSettled()
3932
3933 self.assertEqual(A.data['status'], 'NEW')
3934 self.assertEqual(B.data['status'], 'NEW')
3935 self.assertEqual(A.reported, 0)
3936 self.assertEqual(B.reported, 0)
3937 self.assertEqual(len(self.history), 0)
3938
3939 # Enqueue and merge B alone.
3940 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3941 self.waitUntilSettled()
3942
3943 self.assertEqual(B.data['status'], 'MERGED')
3944 self.assertEqual(B.reported, 2)
3945
3946 # Now that B is merged, A should be able to be enqueued and
3947 # merged.
3948 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3949 self.waitUntilSettled()
3950
3951 self.assertEqual(A.data['status'], 'MERGED')
3952 self.assertEqual(A.reported, 2)
3953
James E. Blair96698e22015-04-02 07:48:21 -07003954 def test_crd_gate_reverse(self):
3955 "Test reverse cross-repo dependencies"
3956 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3957 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3958 A.addApproval('CRVW', 2)
3959 B.addApproval('CRVW', 2)
3960
3961 # A Depends-On: B
3962
3963 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3964 A.subject, B.data['id'])
3965
3966 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3967 self.waitUntilSettled()
3968
3969 self.assertEqual(A.data['status'], 'NEW')
3970 self.assertEqual(B.data['status'], 'NEW')
3971
3972 self.worker.hold_jobs_in_build = True
3973 A.addApproval('APRV', 1)
3974 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3975 self.waitUntilSettled()
3976
3977 self.worker.release('.*-merge')
3978 self.waitUntilSettled()
3979 self.worker.release('.*-merge')
3980 self.waitUntilSettled()
3981 self.worker.hold_jobs_in_build = False
3982 self.worker.release()
3983 self.waitUntilSettled()
3984
3985 self.assertEqual(A.data['status'], 'MERGED')
3986 self.assertEqual(B.data['status'], 'MERGED')
3987 self.assertEqual(A.reported, 2)
3988 self.assertEqual(B.reported, 2)
3989
3990 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3991 '2,1 1,1')
3992
James E. Blair5ee24252014-12-30 10:12:29 -08003993 def test_crd_cycle(self):
3994 "Test cross-repo dependency cycles"
3995 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3996 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3997 A.addApproval('CRVW', 2)
3998 B.addApproval('CRVW', 2)
3999
4000 # A -> B -> A (via commit-depends)
4001
4002 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4003 A.subject, B.data['id'])
4004 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4005 B.subject, A.data['id'])
4006
4007 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
4008 self.waitUntilSettled()
4009
4010 self.assertEqual(A.reported, 0)
4011 self.assertEqual(B.reported, 0)
4012 self.assertEqual(A.data['status'], 'NEW')
4013 self.assertEqual(B.data['status'], 'NEW')
James E. Blairbfb8e042014-12-30 17:01:44 -08004014
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004015 def test_crd_gate_unknown(self):
4016 "Test unknown projects in dependent pipeline"
4017 self.init_repo("org/unknown")
4018 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
4019 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'B')
4020 A.addApproval('CRVW', 2)
4021 B.addApproval('CRVW', 2)
4022
4023 # A Depends-On: B
4024 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4025 A.subject, B.data['id'])
4026
4027 B.addApproval('APRV', 1)
4028 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
4029 self.waitUntilSettled()
4030
4031 # Unknown projects cannot share a queue with any other
4032 # since they don't have common jobs with any other (they have no jobs).
4033 # Changes which depend on unknown project changes
4034 # should not be processed in dependent pipeline
4035 self.assertEqual(A.data['status'], 'NEW')
4036 self.assertEqual(B.data['status'], 'NEW')
4037 self.assertEqual(A.reported, 0)
4038 self.assertEqual(B.reported, 0)
4039 self.assertEqual(len(self.history), 0)
4040
4041 # Simulate change B being gated outside this layout
4042 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
4043 B.setMerged()
4044 self.waitUntilSettled()
4045 self.assertEqual(len(self.history), 0)
4046
4047 # Now that B is merged, A should be able to be enqueued and
4048 # merged.
4049 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
4050 self.waitUntilSettled()
4051
4052 self.assertEqual(A.data['status'], 'MERGED')
4053 self.assertEqual(A.reported, 2)
4054 self.assertEqual(B.data['status'], 'MERGED')
4055 self.assertEqual(B.reported, 0)
4056
James E. Blairbfb8e042014-12-30 17:01:44 -08004057 def test_crd_check(self):
4058 "Test cross-repo dependencies in independent pipelines"
4059
4060 self.gearman_server.hold_jobs_in_queue = True
4061 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4062 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4063
4064 # A Depends-On: B
4065 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4066 A.subject, B.data['id'])
4067
4068 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4069 self.waitUntilSettled()
4070
4071 queue = self.gearman_server.getQueue()
4072 ref = self.getParameter(queue[-1], 'ZUUL_REF')
4073 self.gearman_server.hold_jobs_in_queue = False
4074 self.gearman_server.release()
4075 self.waitUntilSettled()
4076
4077 path = os.path.join(self.git_root, "org/project1")
4078 repo = git.Repo(path)
4079 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4080 repo_messages.reverse()
4081 correct_messages = ['initial commit', 'A-1']
4082 self.assertEqual(repo_messages, correct_messages)
4083
4084 path = os.path.join(self.git_root, "org/project2")
4085 repo = git.Repo(path)
4086 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4087 repo_messages.reverse()
4088 correct_messages = ['initial commit', 'B-1']
4089 self.assertEqual(repo_messages, correct_messages)
4090
4091 self.assertEqual(A.data['status'], 'NEW')
4092 self.assertEqual(B.data['status'], 'NEW')
4093 self.assertEqual(A.reported, 1)
4094 self.assertEqual(B.reported, 0)
4095
4096 self.assertEqual(self.history[0].changes, '2,1 1,1')
4097 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair8f78d882015-02-05 08:51:37 -08004098
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004099 def test_crd_check_git_depends(self):
4100 "Test single-repo dependencies in independent pipelines"
James E. Blairb8c16472015-05-05 14:55:26 -07004101 self.gearman_server.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004102 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4103 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4104
4105 # Add two git-dependent changes and make sure they both report
4106 # success.
4107 B.setDependsOn(A, 1)
4108 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4109 self.waitUntilSettled()
4110 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4111 self.waitUntilSettled()
4112
James E. Blairb8c16472015-05-05 14:55:26 -07004113 self.orderedRelease()
4114 self.gearman_server.hold_jobs_in_build = False
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004115 self.waitUntilSettled()
4116
4117 self.assertEqual(A.data['status'], 'NEW')
4118 self.assertEqual(B.data['status'], 'NEW')
4119 self.assertEqual(A.reported, 1)
4120 self.assertEqual(B.reported, 1)
4121
4122 self.assertEqual(self.history[0].changes, '1,1')
4123 self.assertEqual(self.history[-1].changes, '1,1 2,1')
4124 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4125
4126 self.assertIn('Build succeeded', A.messages[0])
4127 self.assertIn('Build succeeded', B.messages[0])
4128
4129 def test_crd_check_duplicate(self):
4130 "Test duplicate check in independent pipelines"
James E. Blair1e263032015-05-07 14:35:34 -07004131 self.worker.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004132 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4133 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4134 check_pipeline = self.sched.layout.pipelines['check']
4135
4136 # Add two git-dependent changes...
4137 B.setDependsOn(A, 1)
4138 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4139 self.waitUntilSettled()
4140 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4141
4142 # ...make sure the live one is not duplicated...
4143 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4144 self.waitUntilSettled()
4145 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4146
4147 # ...but the non-live one is able to be.
4148 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4149 self.waitUntilSettled()
4150 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4151
Clark Boylandd849822015-03-02 12:38:14 -08004152 # Release jobs in order to avoid races with change A jobs
4153 # finishing before change B jobs.
James E. Blaird7650852015-05-07 15:47:37 -07004154 self.orderedRelease()
James E. Blair1e263032015-05-07 14:35:34 -07004155 self.worker.hold_jobs_in_build = False
4156 self.worker.release()
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004157 self.waitUntilSettled()
4158
4159 self.assertEqual(A.data['status'], 'NEW')
4160 self.assertEqual(B.data['status'], 'NEW')
4161 self.assertEqual(A.reported, 1)
4162 self.assertEqual(B.reported, 1)
4163
4164 self.assertEqual(self.history[0].changes, '1,1 2,1')
4165 self.assertEqual(self.history[1].changes, '1,1')
4166 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4167
4168 self.assertIn('Build succeeded', A.messages[0])
4169 self.assertIn('Build succeeded', B.messages[0])
4170
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004171 def _test_crd_check_reconfiguration(self, project1, project2):
James E. Blair8f78d882015-02-05 08:51:37 -08004172 "Test cross-repo dependencies re-enqueued in independent pipelines"
4173
4174 self.gearman_server.hold_jobs_in_queue = True
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004175 A = self.fake_gerrit.addFakeChange(project1, 'master', 'A')
4176 B = self.fake_gerrit.addFakeChange(project2, 'master', 'B')
James E. Blair8f78d882015-02-05 08:51:37 -08004177
4178 # A Depends-On: B
4179 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4180 A.subject, B.data['id'])
4181
4182 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4183 self.waitUntilSettled()
4184
4185 self.sched.reconfigure(self.config)
4186
4187 # Make sure the items still share a change queue, and the
4188 # first one is not live.
4189 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 1)
4190 queue = self.sched.layout.pipelines['check'].queues[0]
4191 first_item = queue.queue[0]
4192 for item in queue.queue:
4193 self.assertEqual(item.queue, first_item.queue)
4194 self.assertFalse(first_item.live)
4195 self.assertTrue(queue.queue[1].live)
4196
4197 self.gearman_server.hold_jobs_in_queue = False
4198 self.gearman_server.release()
4199 self.waitUntilSettled()
4200
4201 self.assertEqual(A.data['status'], 'NEW')
4202 self.assertEqual(B.data['status'], 'NEW')
4203 self.assertEqual(A.reported, 1)
4204 self.assertEqual(B.reported, 0)
4205
4206 self.assertEqual(self.history[0].changes, '2,1 1,1')
4207 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair17dd6772015-02-09 14:45:18 -08004208
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004209 def test_crd_check_reconfiguration(self):
4210 self._test_crd_check_reconfiguration('org/project1', 'org/project2')
4211
4212 def test_crd_undefined_project(self):
4213 """Test that undefined projects in dependencies are handled for
4214 independent pipelines"""
4215 # It's a hack for fake gerrit,
4216 # as it implies repo creation upon the creation of any change
4217 self.init_repo("org/unknown")
4218 self._test_crd_check_reconfiguration('org/project1', 'org/unknown')
4219
James E. Blair17dd6772015-02-09 14:45:18 -08004220 def test_crd_check_ignore_dependencies(self):
4221 "Test cross-repo dependencies can be ignored"
James E. Blairf84026c2015-12-08 16:11:46 -08004222 self.updateConfigLayout(
4223 'tests/fixtures/layout-ignore-dependencies.yaml')
James E. Blair17dd6772015-02-09 14:45:18 -08004224 self.sched.reconfigure(self.config)
4225 self.registerJobs()
4226
4227 self.gearman_server.hold_jobs_in_queue = True
4228 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4229 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4230 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
4231
4232 # A Depends-On: B
4233 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4234 A.subject, B.data['id'])
4235 # C git-depends on B
4236 C.setDependsOn(B, 1)
4237 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4238 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4239 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4240 self.waitUntilSettled()
4241
4242 # Make sure none of the items share a change queue, and all
4243 # are live.
4244 check_pipeline = self.sched.layout.pipelines['check']
4245 self.assertEqual(len(check_pipeline.queues), 3)
4246 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4247 for item in check_pipeline.getAllItems():
4248 self.assertTrue(item.live)
4249
4250 self.gearman_server.hold_jobs_in_queue = False
4251 self.gearman_server.release()
4252 self.waitUntilSettled()
4253
4254 self.assertEqual(A.data['status'], 'NEW')
4255 self.assertEqual(B.data['status'], 'NEW')
4256 self.assertEqual(C.data['status'], 'NEW')
4257 self.assertEqual(A.reported, 1)
4258 self.assertEqual(B.reported, 1)
4259 self.assertEqual(C.reported, 1)
4260
4261 # Each job should have tested exactly one change
4262 for job in self.history:
4263 self.assertEqual(len(job.changes.split()), 1)
James E. Blair96698e22015-04-02 07:48:21 -07004264
4265 def test_crd_check_transitive(self):
4266 "Test transitive cross-repo dependencies"
4267 # Specifically, if A -> B -> C, and C gets a new patchset and
4268 # A gets a new patchset, ensure the test of A,2 includes B,1
4269 # and C,2 (not C,1 which would indicate stale data in the
4270 # cache for B).
4271 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4272 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4273 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
4274
4275 # A Depends-On: B
4276 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4277 A.subject, B.data['id'])
4278
4279 # B Depends-On: C
4280 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4281 B.subject, C.data['id'])
4282
4283 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4284 self.waitUntilSettled()
4285 self.assertEqual(self.history[-1].changes, '3,1 2,1 1,1')
4286
4287 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4288 self.waitUntilSettled()
4289 self.assertEqual(self.history[-1].changes, '3,1 2,1')
4290
4291 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4292 self.waitUntilSettled()
4293 self.assertEqual(self.history[-1].changes, '3,1')
4294
4295 C.addPatchset()
4296 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(2))
4297 self.waitUntilSettled()
4298 self.assertEqual(self.history[-1].changes, '3,2')
4299
4300 A.addPatchset()
4301 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
4302 self.waitUntilSettled()
4303 self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004304
James E. Blair92464a22016-04-05 10:21:26 -07004305 def test_crd_cycle_join(self):
4306 "Test an updated change creates a cycle"
4307 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
4308
4309 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4310 self.waitUntilSettled()
4311
4312 # Create B->A
4313 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4314 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4315 B.subject, A.data['id'])
4316 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4317 self.waitUntilSettled()
4318
4319 # Update A to add A->B (a cycle).
4320 A.addPatchset()
4321 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4322 A.subject, B.data['id'])
4323 # Normally we would submit the patchset-created event for
4324 # processing here, however, we have no way of noting whether
4325 # the dependency cycle detection correctly raised an
4326 # exception, so instead, we reach into the source driver and
4327 # call the method that would ultimately be called by the event
4328 # processing.
4329
4330 source = self.sched.layout.pipelines['gate'].source
4331 with testtools.ExpectedException(
4332 Exception, "Dependency cycle detected"):
4333 source._getChange(u'1', u'2', True)
4334 self.log.debug("Got expected dependency cycle exception")
4335
4336 # Now if we update B to remove the depends-on, everything
4337 # should be okay. B; A->B
4338
4339 B.addPatchset()
4340 B.data['commitMessage'] = '%s\n' % (B.subject,)
4341 source._getChange(u'1', u'2', True)
4342 source._getChange(u'2', u'2', True)
4343
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004344 def test_disable_at(self):
4345 "Test a pipeline will only report to the disabled trigger when failing"
4346
James E. Blairf84026c2015-12-08 16:11:46 -08004347 self.updateConfigLayout(
4348 'tests/fixtures/layout-disable-at.yaml')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004349 self.sched.reconfigure(self.config)
4350
4351 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4352 self.assertEqual(
4353 0, self.sched.layout.pipelines['check']._consecutive_failures)
4354 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4355
4356 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
4357 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
4358 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
4359 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
4360 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
4361 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
4362 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
4363 H = self.fake_gerrit.addFakeChange('org/project', 'master', 'H')
4364 I = self.fake_gerrit.addFakeChange('org/project', 'master', 'I')
4365 J = self.fake_gerrit.addFakeChange('org/project', 'master', 'J')
4366 K = self.fake_gerrit.addFakeChange('org/project', 'master', 'K')
4367
4368 self.worker.addFailTest('project-test1', A)
4369 self.worker.addFailTest('project-test1', B)
4370 # Let C pass, resetting the counter
4371 self.worker.addFailTest('project-test1', D)
4372 self.worker.addFailTest('project-test1', E)
4373 self.worker.addFailTest('project-test1', F)
4374 self.worker.addFailTest('project-test1', G)
4375 self.worker.addFailTest('project-test1', H)
4376 # I also passes but should only report to the disabled reporters
4377 self.worker.addFailTest('project-test1', J)
4378 self.worker.addFailTest('project-test1', K)
4379
4380 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4381 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4382 self.waitUntilSettled()
4383
4384 self.assertEqual(
4385 2, self.sched.layout.pipelines['check']._consecutive_failures)
4386 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4387
4388 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4389 self.waitUntilSettled()
4390
4391 self.assertEqual(
4392 0, self.sched.layout.pipelines['check']._consecutive_failures)
4393 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4394
4395 self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(1))
4396 self.fake_gerrit.addEvent(E.getPatchsetCreatedEvent(1))
4397 self.fake_gerrit.addEvent(F.getPatchsetCreatedEvent(1))
4398 self.waitUntilSettled()
4399
4400 # We should be disabled now
4401 self.assertEqual(
4402 3, self.sched.layout.pipelines['check']._consecutive_failures)
4403 self.assertTrue(self.sched.layout.pipelines['check']._disabled)
4404
4405 # We need to wait between each of these patches to make sure the
4406 # smtp messages come back in an expected order
4407 self.fake_gerrit.addEvent(G.getPatchsetCreatedEvent(1))
4408 self.waitUntilSettled()
4409 self.fake_gerrit.addEvent(H.getPatchsetCreatedEvent(1))
4410 self.waitUntilSettled()
4411 self.fake_gerrit.addEvent(I.getPatchsetCreatedEvent(1))
4412 self.waitUntilSettled()
4413
4414 # The first 6 (ABCDEF) jobs should have reported back to gerrt thus
4415 # leaving a message on each change
4416 self.assertEqual(1, len(A.messages))
4417 self.assertIn('Build failed.', A.messages[0])
4418 self.assertEqual(1, len(B.messages))
4419 self.assertIn('Build failed.', B.messages[0])
4420 self.assertEqual(1, len(C.messages))
4421 self.assertIn('Build succeeded.', C.messages[0])
4422 self.assertEqual(1, len(D.messages))
4423 self.assertIn('Build failed.', D.messages[0])
4424 self.assertEqual(1, len(E.messages))
4425 self.assertIn('Build failed.', E.messages[0])
4426 self.assertEqual(1, len(F.messages))
4427 self.assertIn('Build failed.', F.messages[0])
4428
4429 # The last 3 (GHI) would have only reported via smtp.
4430 self.assertEqual(3, len(self.smtp_messages))
4431 self.assertEqual(0, len(G.messages))
4432 self.assertIn('Build failed.', self.smtp_messages[0]['body'])
4433 self.assertIn('/7/1/check', self.smtp_messages[0]['body'])
4434 self.assertEqual(0, len(H.messages))
4435 self.assertIn('Build failed.', self.smtp_messages[1]['body'])
4436 self.assertIn('/8/1/check', self.smtp_messages[1]['body'])
4437 self.assertEqual(0, len(I.messages))
4438 self.assertIn('Build succeeded.', self.smtp_messages[2]['body'])
4439 self.assertIn('/9/1/check', self.smtp_messages[2]['body'])
4440
4441 # Now reload the configuration (simulate a HUP) to check the pipeline
4442 # comes out of disabled
4443 self.sched.reconfigure(self.config)
4444
4445 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4446 self.assertEqual(
4447 0, self.sched.layout.pipelines['check']._consecutive_failures)
4448 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4449
4450 self.fake_gerrit.addEvent(J.getPatchsetCreatedEvent(1))
4451 self.fake_gerrit.addEvent(K.getPatchsetCreatedEvent(1))
4452 self.waitUntilSettled()
4453
4454 self.assertEqual(
4455 2, self.sched.layout.pipelines['check']._consecutive_failures)
4456 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4457
4458 # J and K went back to gerrit
4459 self.assertEqual(1, len(J.messages))
4460 self.assertIn('Build failed.', J.messages[0])
4461 self.assertEqual(1, len(K.messages))
4462 self.assertIn('Build failed.', K.messages[0])
4463 # No more messages reported via smtp
4464 self.assertEqual(3, len(self.smtp_messages))
Joshua Heskethd6dbd682015-12-22 10:06:54 +11004465
4466 def test_success_pattern(self):
4467 "Ensure bad build params are ignored"
4468
4469 # Use SMTP reporter to grab the result message easier
4470 self.init_repo("org/docs")
4471 self.config.set('zuul', 'layout_config',
4472 'tests/fixtures/layout-success-pattern.yaml')
4473 self.sched.reconfigure(self.config)
4474 self.worker.hold_jobs_in_build = True
4475 self.registerJobs()
4476
4477 A = self.fake_gerrit.addFakeChange('org/docs', 'master', 'A')
4478 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4479 self.waitUntilSettled()
4480
4481 # Grab build id
4482 self.assertEqual(len(self.builds), 1)
4483 uuid = self.builds[0].unique[:7]
4484
4485 self.worker.hold_jobs_in_build = False
4486 self.worker.release()
4487 self.waitUntilSettled()
4488
4489 self.assertEqual(len(self.smtp_messages), 1)
4490 body = self.smtp_messages[0]['body'].splitlines()
4491 self.assertEqual('Build succeeded.', body[0])
4492
4493 self.assertIn(
4494 '- docs-draft-test http://docs-draft.example.org/1/1/1/check/'
4495 'docs-draft-test/%s/publish-docs/' % uuid,
4496 body[2])
4497 self.assertIn(
4498 '- docs-draft-test2 https://server/job/docs-draft-test2/1/',
4499 body[3])