blob: b56e227e24edd256f68352059e8172e950439309 [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
James E. Blair1843a552013-07-03 14:19:52 -070023import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040024import urllib2
Maru Newby3fe5f852015-01-13 04:22:14 +000025import yaml
Monty Taylorbc758832013-06-17 17:22:42 -040026
James E. Blair4886cc12012-07-18 15:39:41 -070027import git
Monty Taylorbc758832013-06-17 17:22:42 -040028import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070029
Maru Newby3fe5f852015-01-13 04:22:14 +000030import zuul.change_matcher
James E. Blairb0fcae42012-07-17 11:12:10 -070031import zuul.scheduler
James E. Blairad28e912013-11-27 10:43:22 -080032import zuul.rpcclient
Joshua Hesketh1879cf72013-08-19 14:13:15 +100033import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100034import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070035
Maru Newby3fe5f852015-01-13 04:22:14 +000036from tests.base import (
37 BaseTestCase,
38 ZuulTestCase,
39 repack_repo,
40)
James E. Blairb0fcae42012-07-17 11:12:10 -070041
James E. Blair1f4c2bb2013-04-26 08:40:46 -070042logging.basicConfig(level=logging.DEBUG,
43 format='%(asctime)s %(name)-32s '
44 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070045
46
Maru Newby3fe5f852015-01-13 04:22:14 +000047class TestSchedulerConfigParsing(BaseTestCase):
48
James E. Blair83005782015-12-11 14:46:03 -080049 def setUp(self):
50 self.skip("Disabled for early v3 development")
51
Maru Newby3fe5f852015-01-13 04:22:14 +000052 def test_parse_skip_if(self):
53 job_yaml = """
54jobs:
55 - name: job_name
56 skip-if:
57 - project: ^project_name$
58 branch: ^stable/icehouse$
59 all-files-match-any:
60 - ^filename$
61 - project: ^project2_name$
62 all-files-match-any:
63 - ^filename2$
64 """.strip()
65 data = yaml.load(job_yaml)
66 config_job = data.get('jobs')[0]
Joshua Hesketh352264b2015-08-11 23:42:08 +100067 sched = zuul.scheduler.Scheduler({})
Maru Newby3fe5f852015-01-13 04:22:14 +000068 cm = zuul.change_matcher
69 expected = cm.MatchAny([
70 cm.MatchAll([
71 cm.ProjectMatcher('^project_name$'),
72 cm.BranchMatcher('^stable/icehouse$'),
73 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
74 ]),
75 cm.MatchAll([
76 cm.ProjectMatcher('^project2_name$'),
77 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
78 ]),
79 ])
80 matcher = sched._parseSkipIf(config_job)
81 self.assertEqual(expected, matcher)
82
83
Clark Boylanb640e052014-04-03 16:41:46 -070084class TestScheduler(ZuulTestCase):
Antoine Mussobd86a312014-01-08 14:51:33 +010085
James E. Blair509cada2015-12-08 16:31:16 -080086 def setUp(self):
87 self.skip("Disabled for early v3 development")
88
James E. Blairb0fcae42012-07-17 11:12:10 -070089 def test_jobs_launched(self):
90 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -070091
James E. Blairb0fcae42012-07-17 11:12:10 -070092 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -070093 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070094 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
95 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -040096 self.assertEqual(self.getJobFromHistory('project-merge').result,
97 'SUCCESS')
98 self.assertEqual(self.getJobFromHistory('project-test1').result,
99 'SUCCESS')
100 self.assertEqual(self.getJobFromHistory('project-test2').result,
101 'SUCCESS')
102 self.assertEqual(A.data['status'], 'MERGED')
103 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700104
James E. Blair66eeebf2013-07-27 17:44:32 -0700105 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
106 self.assertReportedStat('zuul.pipeline.gate.current_changes',
107 value='1|g')
108 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
109 kind='ms')
110 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
111 value='1|c')
112 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
113 self.assertReportedStat('zuul.pipeline.gate.total_changes',
114 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700115 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700116 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -0700117 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700118 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700119
James E. Blair5821bd92015-09-16 08:48:15 -0700120 for build in self.builds:
121 self.assertEqual(build.parameters['ZUUL_VOTING'], '1')
122
James E. Blair3cb10702013-08-24 08:56:03 -0700123 def test_initial_pipeline_gauges(self):
124 "Test that each pipeline reported its length on start"
125 pipeline_names = self.sched.layout.pipelines.keys()
126 self.assertNotEqual(len(pipeline_names), 0)
127 for name in pipeline_names:
128 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
129 value='0|g')
130
James E. Blair42f74822013-05-14 15:18:03 -0700131 def test_duplicate_pipelines(self):
132 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -0700133
James E. Blair42f74822013-05-14 15:18:03 -0700134 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
135 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
136 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -0700137
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400138 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400139 self.history[0].name == 'project-test1'
140 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -0700141
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400142 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -0700143 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400144 self.assertIn('dup1/project-test1', A.messages[0])
145 self.assertNotIn('dup2/project-test1', A.messages[0])
146 self.assertNotIn('dup1/project-test1', A.messages[1])
147 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -0700148 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400149 self.assertIn('dup1/project-test1', A.messages[1])
150 self.assertNotIn('dup2/project-test1', A.messages[1])
151 self.assertNotIn('dup1/project-test1', A.messages[0])
152 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -0700153
James E. Blairb0fcae42012-07-17 11:12:10 -0700154 def test_parallel_changes(self):
155 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700156
157 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700158 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
159 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
160 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700161 A.addApproval('CRVW', 2)
162 B.addApproval('CRVW', 2)
163 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700164
165 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
166 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
167 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
168
169 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400170 self.assertEqual(len(self.builds), 1)
171 self.assertEqual(self.builds[0].name, 'project-merge')
172 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700173
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700174 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700175 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400176 self.assertEqual(len(self.builds), 3)
177 self.assertEqual(self.builds[0].name, 'project-test1')
178 self.assertTrue(self.job_has_changes(self.builds[0], A))
179 self.assertEqual(self.builds[1].name, 'project-test2')
180 self.assertTrue(self.job_has_changes(self.builds[1], A))
181 self.assertEqual(self.builds[2].name, 'project-merge')
182 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700183
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700184 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700185 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400186 self.assertEqual(len(self.builds), 5)
187 self.assertEqual(self.builds[0].name, 'project-test1')
188 self.assertTrue(self.job_has_changes(self.builds[0], A))
189 self.assertEqual(self.builds[1].name, 'project-test2')
190 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700191
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400192 self.assertEqual(self.builds[2].name, 'project-test1')
193 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
194 self.assertEqual(self.builds[3].name, 'project-test2')
195 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700196
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400197 self.assertEqual(self.builds[4].name, 'project-merge')
198 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700199
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700200 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700201 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400202 self.assertEqual(len(self.builds), 6)
203 self.assertEqual(self.builds[0].name, 'project-test1')
204 self.assertTrue(self.job_has_changes(self.builds[0], A))
205 self.assertEqual(self.builds[1].name, 'project-test2')
206 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700207
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400208 self.assertEqual(self.builds[2].name, 'project-test1')
209 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
210 self.assertEqual(self.builds[3].name, 'project-test2')
211 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700212
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400213 self.assertEqual(self.builds[4].name, 'project-test1')
214 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
215 self.assertEqual(self.builds[5].name, 'project-test2')
216 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700217
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700218 self.worker.hold_jobs_in_build = False
219 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700220 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400221 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -0700222
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400223 self.assertEqual(len(self.history), 9)
224 self.assertEqual(A.data['status'], 'MERGED')
225 self.assertEqual(B.data['status'], 'MERGED')
226 self.assertEqual(C.data['status'], 'MERGED')
227 self.assertEqual(A.reported, 2)
228 self.assertEqual(B.reported, 2)
229 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700230
231 def test_failed_changes(self):
232 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -0400233 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700234
James E. Blairb02a3bb2012-07-30 17:49:55 -0700235 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
236 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700237 A.addApproval('CRVW', 2)
238 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700239
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700240 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700241
James E. Blaire2819012013-06-28 17:17:26 -0400242 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
243 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700244 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -0400245
246 self.worker.release('.*-merge')
247 self.waitUntilSettled()
248
249 self.worker.hold_jobs_in_build = False
250 self.worker.release()
251
252 self.waitUntilSettled()
253 # It's certain that the merge job for change 2 will run, but
254 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400255 self.assertTrue(len(self.history) > 6)
256 self.assertEqual(A.data['status'], 'NEW')
257 self.assertEqual(B.data['status'], 'MERGED')
258 self.assertEqual(A.reported, 2)
259 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700260
261 def test_independent_queues(self):
262 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700263
264 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900265 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700266 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
267 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700268 A.addApproval('CRVW', 2)
269 B.addApproval('CRVW', 2)
270 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700271
272 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
273 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
274 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
275
James E. Blairb02a3bb2012-07-30 17:49:55 -0700276 self.waitUntilSettled()
277
278 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400279 self.assertEqual(len(self.builds), 2)
280 self.assertEqual(self.builds[0].name, 'project-merge')
281 self.assertTrue(self.job_has_changes(self.builds[0], A))
282 self.assertEqual(self.builds[1].name, 'project1-merge')
283 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700284
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700285 # Release the current merge builds
286 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700287 self.waitUntilSettled()
288 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700289 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700290 self.waitUntilSettled()
291
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700292 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -0700293 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400294 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700295
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700296 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700297 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400298 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700299
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400300 self.assertEqual(len(self.history), 11)
301 self.assertEqual(A.data['status'], 'MERGED')
302 self.assertEqual(B.data['status'], 'MERGED')
303 self.assertEqual(C.data['status'], 'MERGED')
304 self.assertEqual(A.reported, 2)
305 self.assertEqual(B.reported, 2)
306 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700307
308 def test_failed_change_at_head(self):
309 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700310
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700311 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -0700312 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
313 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
314 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700315 A.addApproval('CRVW', 2)
316 B.addApproval('CRVW', 2)
317 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700318
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700319 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700320
321 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
322 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
323 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
324
325 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -0700326
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400327 self.assertEqual(len(self.builds), 1)
328 self.assertEqual(self.builds[0].name, 'project-merge')
329 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700330
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700331 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700332 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700333 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700334 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700335 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700336 self.waitUntilSettled()
337
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400338 self.assertEqual(len(self.builds), 6)
339 self.assertEqual(self.builds[0].name, 'project-test1')
340 self.assertEqual(self.builds[1].name, 'project-test2')
341 self.assertEqual(self.builds[2].name, 'project-test1')
342 self.assertEqual(self.builds[3].name, 'project-test2')
343 self.assertEqual(self.builds[4].name, 'project-test1')
344 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700345
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400346 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700347 self.waitUntilSettled()
348
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400349 # project-test2, project-merge for B
350 self.assertEqual(len(self.builds), 2)
351 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -0700352
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700353 self.worker.hold_jobs_in_build = False
354 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700355 self.waitUntilSettled()
356
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400357 self.assertEqual(len(self.builds), 0)
358 self.assertEqual(len(self.history), 15)
359 self.assertEqual(A.data['status'], 'NEW')
360 self.assertEqual(B.data['status'], 'MERGED')
361 self.assertEqual(C.data['status'], 'MERGED')
362 self.assertEqual(A.reported, 2)
363 self.assertEqual(B.reported, 2)
364 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700365
James E. Blair0aac4872013-08-23 14:02:38 -0700366 def test_failed_change_in_middle(self):
367 "Test a failed change in the middle of the queue"
368
369 self.worker.hold_jobs_in_build = True
370 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
371 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
372 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
373 A.addApproval('CRVW', 2)
374 B.addApproval('CRVW', 2)
375 C.addApproval('CRVW', 2)
376
377 self.worker.addFailTest('project-test1', B)
378
379 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
380 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
381 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
382
383 self.waitUntilSettled()
384
385 self.worker.release('.*-merge')
386 self.waitUntilSettled()
387 self.worker.release('.*-merge')
388 self.waitUntilSettled()
389 self.worker.release('.*-merge')
390 self.waitUntilSettled()
391
392 self.assertEqual(len(self.builds), 6)
393 self.assertEqual(self.builds[0].name, 'project-test1')
394 self.assertEqual(self.builds[1].name, 'project-test2')
395 self.assertEqual(self.builds[2].name, 'project-test1')
396 self.assertEqual(self.builds[3].name, 'project-test2')
397 self.assertEqual(self.builds[4].name, 'project-test1')
398 self.assertEqual(self.builds[5].name, 'project-test2')
399
400 self.release(self.builds[2])
401 self.waitUntilSettled()
402
James E. Blair972e3c72013-08-29 12:04:55 -0700403 # project-test1 and project-test2 for A
404 # project-test2 for B
405 # project-merge for C (without B)
406 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -0700407 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
408
James E. Blair972e3c72013-08-29 12:04:55 -0700409 self.worker.release('.*-merge')
410 self.waitUntilSettled()
411
412 # project-test1 and project-test2 for A
413 # project-test2 for B
414 # project-test1 and project-test2 for C
415 self.assertEqual(len(self.builds), 5)
416
James E. Blair0aac4872013-08-23 14:02:38 -0700417 items = self.sched.layout.pipelines['gate'].getAllItems()
418 builds = items[0].current_build_set.getBuilds()
419 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
420 self.assertEqual(self.countJobResults(builds, None), 2)
421 builds = items[1].current_build_set.getBuilds()
422 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
423 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
424 self.assertEqual(self.countJobResults(builds, None), 1)
425 builds = items[2].current_build_set.getBuilds()
426 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -0700427 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -0700428
429 self.worker.hold_jobs_in_build = False
430 self.worker.release()
431 self.waitUntilSettled()
432
433 self.assertEqual(len(self.builds), 0)
434 self.assertEqual(len(self.history), 12)
435 self.assertEqual(A.data['status'], 'MERGED')
436 self.assertEqual(B.data['status'], 'NEW')
437 self.assertEqual(C.data['status'], 'MERGED')
438 self.assertEqual(A.reported, 2)
439 self.assertEqual(B.reported, 2)
440 self.assertEqual(C.reported, 2)
441
James E. Blaird466dc42012-07-31 10:42:56 -0700442 def test_failed_change_at_head_with_queue(self):
443 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700444
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700445 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -0700446 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
447 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
448 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700449 A.addApproval('CRVW', 2)
450 B.addApproval('CRVW', 2)
451 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700452
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700453 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700454
455 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
456 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
457 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
458
459 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700460 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400461 self.assertEqual(len(self.builds), 0)
462 self.assertEqual(len(queue), 1)
463 self.assertEqual(queue[0].name, 'build:project-merge')
464 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700465
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700466 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700467 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700468 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700469 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700470 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700471 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700472 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -0700473
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400474 self.assertEqual(len(self.builds), 0)
475 self.assertEqual(len(queue), 6)
476 self.assertEqual(queue[0].name, 'build:project-test1')
477 self.assertEqual(queue[1].name, 'build:project-test2')
478 self.assertEqual(queue[2].name, 'build:project-test1')
479 self.assertEqual(queue[3].name, 'build:project-test2')
480 self.assertEqual(queue[4].name, 'build:project-test1')
481 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700482
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700483 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700484 self.waitUntilSettled()
485
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400486 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -0700487 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400488 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
489 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -0700490
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700491 self.gearman_server.hold_jobs_in_queue = False
492 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700493 self.waitUntilSettled()
494
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400495 self.assertEqual(len(self.builds), 0)
496 self.assertEqual(len(self.history), 11)
497 self.assertEqual(A.data['status'], 'NEW')
498 self.assertEqual(B.data['status'], 'MERGED')
499 self.assertEqual(C.data['status'], 'MERGED')
500 self.assertEqual(A.reported, 2)
501 self.assertEqual(B.reported, 2)
502 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700503
James E. Blairfef71632013-09-23 11:15:47 -0700504 def test_two_failed_changes_at_head(self):
505 "Test that changes are reparented correctly if 2 fail at head"
506
507 self.worker.hold_jobs_in_build = True
508 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
509 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
510 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
511 A.addApproval('CRVW', 2)
512 B.addApproval('CRVW', 2)
513 C.addApproval('CRVW', 2)
514
515 self.worker.addFailTest('project-test1', A)
516 self.worker.addFailTest('project-test1', B)
517
518 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
519 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
520 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
521 self.waitUntilSettled()
522
523 self.worker.release('.*-merge')
524 self.waitUntilSettled()
525 self.worker.release('.*-merge')
526 self.waitUntilSettled()
527 self.worker.release('.*-merge')
528 self.waitUntilSettled()
529
530 self.assertEqual(len(self.builds), 6)
531 self.assertEqual(self.builds[0].name, 'project-test1')
532 self.assertEqual(self.builds[1].name, 'project-test2')
533 self.assertEqual(self.builds[2].name, 'project-test1')
534 self.assertEqual(self.builds[3].name, 'project-test2')
535 self.assertEqual(self.builds[4].name, 'project-test1')
536 self.assertEqual(self.builds[5].name, 'project-test2')
537
538 self.assertTrue(self.job_has_changes(self.builds[0], A))
539 self.assertTrue(self.job_has_changes(self.builds[2], A))
540 self.assertTrue(self.job_has_changes(self.builds[2], B))
541 self.assertTrue(self.job_has_changes(self.builds[4], A))
542 self.assertTrue(self.job_has_changes(self.builds[4], B))
543 self.assertTrue(self.job_has_changes(self.builds[4], C))
544
545 # Fail change B first
546 self.release(self.builds[2])
547 self.waitUntilSettled()
548
549 # restart of C after B failure
550 self.worker.release('.*-merge')
551 self.waitUntilSettled()
552
553 self.assertEqual(len(self.builds), 5)
554 self.assertEqual(self.builds[0].name, 'project-test1')
555 self.assertEqual(self.builds[1].name, 'project-test2')
556 self.assertEqual(self.builds[2].name, 'project-test2')
557 self.assertEqual(self.builds[3].name, 'project-test1')
558 self.assertEqual(self.builds[4].name, 'project-test2')
559
560 self.assertTrue(self.job_has_changes(self.builds[1], A))
561 self.assertTrue(self.job_has_changes(self.builds[2], A))
562 self.assertTrue(self.job_has_changes(self.builds[2], B))
563 self.assertTrue(self.job_has_changes(self.builds[4], A))
564 self.assertFalse(self.job_has_changes(self.builds[4], B))
565 self.assertTrue(self.job_has_changes(self.builds[4], C))
566
567 # Finish running all passing jobs for change A
568 self.release(self.builds[1])
569 self.waitUntilSettled()
570 # Fail and report change A
571 self.release(self.builds[0])
572 self.waitUntilSettled()
573
574 # restart of B,C after A failure
575 self.worker.release('.*-merge')
576 self.waitUntilSettled()
577 self.worker.release('.*-merge')
578 self.waitUntilSettled()
579
580 self.assertEqual(len(self.builds), 4)
581 self.assertEqual(self.builds[0].name, 'project-test1') # B
582 self.assertEqual(self.builds[1].name, 'project-test2') # B
583 self.assertEqual(self.builds[2].name, 'project-test1') # C
584 self.assertEqual(self.builds[3].name, 'project-test2') # C
585
586 self.assertFalse(self.job_has_changes(self.builds[1], A))
587 self.assertTrue(self.job_has_changes(self.builds[1], B))
588 self.assertFalse(self.job_has_changes(self.builds[1], C))
589
590 self.assertFalse(self.job_has_changes(self.builds[2], A))
591 # After A failed and B and C restarted, B should be back in
592 # C's tests because it has not failed yet.
593 self.assertTrue(self.job_has_changes(self.builds[2], B))
594 self.assertTrue(self.job_has_changes(self.builds[2], C))
595
596 self.worker.hold_jobs_in_build = False
597 self.worker.release()
598 self.waitUntilSettled()
599
600 self.assertEqual(len(self.builds), 0)
601 self.assertEqual(len(self.history), 21)
602 self.assertEqual(A.data['status'], 'NEW')
603 self.assertEqual(B.data['status'], 'NEW')
604 self.assertEqual(C.data['status'], 'MERGED')
605 self.assertEqual(A.reported, 2)
606 self.assertEqual(B.reported, 2)
607 self.assertEqual(C.reported, 2)
608
James E. Blair8c803f82012-07-31 16:25:42 -0700609 def test_patch_order(self):
610 "Test that dependent patches are tested in the right order"
611 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
612 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
613 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
614 A.addApproval('CRVW', 2)
615 B.addApproval('CRVW', 2)
616 C.addApproval('CRVW', 2)
617
618 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
619 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
620 M2.setMerged()
621 M1.setMerged()
622
623 # C -> B -> A -> M1 -> M2
624 # M2 is here to make sure it is never queried. If it is, it
625 # means zuul is walking down the entire history of merged
626 # changes.
627
628 C.setDependsOn(B, 1)
629 B.setDependsOn(A, 1)
630 A.setDependsOn(M1, 1)
631 M1.setDependsOn(M2, 1)
632
633 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
634
635 self.waitUntilSettled()
636
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400637 self.assertEqual(A.data['status'], 'NEW')
638 self.assertEqual(B.data['status'], 'NEW')
639 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -0700640
641 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
642 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
643
644 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400645 self.assertEqual(M2.queried, 0)
646 self.assertEqual(A.data['status'], 'MERGED')
647 self.assertEqual(B.data['status'], 'MERGED')
648 self.assertEqual(C.data['status'], 'MERGED')
649 self.assertEqual(A.reported, 2)
650 self.assertEqual(B.reported, 2)
651 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700652
James E. Blair063672f2015-01-29 13:09:12 -0800653 def test_needed_changes_enqueue(self):
654 "Test that a needed change is enqueued ahead"
655 # A Given a git tree like this, if we enqueue
656 # / \ change C, we should walk up and down the tree
657 # B G and enqueue changes in the order ABCDEFG.
658 # /|\ This is also the order that you would get if
659 # *C E F you enqueued changes in the order ABCDEFG, so
660 # / the ordering is stable across re-enqueue events.
661 # D
662
663 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
664 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
665 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
666 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
667 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
668 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
669 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
670 B.setDependsOn(A, 1)
671 C.setDependsOn(B, 1)
672 D.setDependsOn(C, 1)
673 E.setDependsOn(B, 1)
674 F.setDependsOn(B, 1)
675 G.setDependsOn(A, 1)
676
677 A.addApproval('CRVW', 2)
678 B.addApproval('CRVW', 2)
679 C.addApproval('CRVW', 2)
680 D.addApproval('CRVW', 2)
681 E.addApproval('CRVW', 2)
682 F.addApproval('CRVW', 2)
683 G.addApproval('CRVW', 2)
684 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
685
686 self.waitUntilSettled()
687
688 self.assertEqual(A.data['status'], 'NEW')
689 self.assertEqual(B.data['status'], 'NEW')
690 self.assertEqual(C.data['status'], 'NEW')
691 self.assertEqual(D.data['status'], 'NEW')
692 self.assertEqual(E.data['status'], 'NEW')
693 self.assertEqual(F.data['status'], 'NEW')
694 self.assertEqual(G.data['status'], 'NEW')
695
696 # We're about to add approvals to changes without adding the
697 # triggering events to Zuul, so that we can be sure that it is
698 # enqueing the changes based on dependencies, not because of
699 # triggering events. Since it will have the changes cached
700 # already (without approvals), we need to clear the cache
701 # first.
702 source = self.sched.layout.pipelines['gate'].source
703 source.maintainCache([])
704
705 self.worker.hold_jobs_in_build = True
706 A.addApproval('APRV', 1)
707 B.addApproval('APRV', 1)
708 D.addApproval('APRV', 1)
709 E.addApproval('APRV', 1)
710 F.addApproval('APRV', 1)
711 G.addApproval('APRV', 1)
712 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
713
714 for x in range(8):
715 self.worker.release('.*-merge')
716 self.waitUntilSettled()
717 self.worker.hold_jobs_in_build = False
718 self.worker.release()
719 self.waitUntilSettled()
720
721 self.assertEqual(A.data['status'], 'MERGED')
722 self.assertEqual(B.data['status'], 'MERGED')
723 self.assertEqual(C.data['status'], 'MERGED')
724 self.assertEqual(D.data['status'], 'MERGED')
725 self.assertEqual(E.data['status'], 'MERGED')
726 self.assertEqual(F.data['status'], 'MERGED')
727 self.assertEqual(G.data['status'], 'MERGED')
728 self.assertEqual(A.reported, 2)
729 self.assertEqual(B.reported, 2)
730 self.assertEqual(C.reported, 2)
731 self.assertEqual(D.reported, 2)
732 self.assertEqual(E.reported, 2)
733 self.assertEqual(F.reported, 2)
734 self.assertEqual(G.reported, 2)
735 self.assertEqual(self.history[6].changes,
736 '1,1 2,1 3,1 4,1 5,1 6,1 7,1')
737
Joshua Hesketh850ccb62014-11-27 11:31:02 +1100738 def test_source_cache(self):
739 "Test that the source cache operates correctly"
James E. Blair0e933c52013-07-11 10:18:52 -0700740 self.worker.hold_jobs_in_build = True
741
742 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
743 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
744 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
745 A.addApproval('CRVW', 2)
746 B.addApproval('CRVW', 2)
747
748 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
749 M1.setMerged()
750
751 B.setDependsOn(A, 1)
752 A.setDependsOn(M1, 1)
753
754 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
755 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
756
757 self.waitUntilSettled()
758
759 for build in self.builds:
760 if build.parameters['ZUUL_PIPELINE'] == 'check':
761 build.release()
762 self.waitUntilSettled()
763 for build in self.builds:
764 if build.parameters['ZUUL_PIPELINE'] == 'check':
765 build.release()
766 self.waitUntilSettled()
767
768 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
769 self.waitUntilSettled()
770
Joshua Hesketh352264b2015-08-11 23:42:08 +1000771 self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -0700772 # there should still be changes in the cache
Joshua Hesketh352264b2015-08-11 23:42:08 +1000773 self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -0700774
775 self.worker.hold_jobs_in_build = False
776 self.worker.release()
777 self.waitUntilSettled()
778
779 self.assertEqual(A.data['status'], 'MERGED')
780 self.assertEqual(B.data['status'], 'MERGED')
781 self.assertEqual(A.queried, 2) # Initial and isMerged
782 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
783
James E. Blair8c803f82012-07-31 16:25:42 -0700784 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -0700785 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -0700786 # TODO: move to test_gerrit (this is a unit test!)
787 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairc0dedf82014-08-06 09:37:52 -0700788 source = self.sched.layout.pipelines['gate'].source
789 a = source._getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -0400790 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blairc0dedf82014-08-06 09:37:52 -0700791 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700792
793 A.addApproval('CRVW', 2)
James E. Blairc0dedf82014-08-06 09:37:52 -0700794 a = source._getChange(1, 2, refresh=True)
795 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700796
797 A.addApproval('APRV', 1)
James E. Blairc0dedf82014-08-06 09:37:52 -0700798 a = source._getChange(1, 2, refresh=True)
799 self.assertTrue(source.canMerge(a, mgr.getSubmitAllowNeeds()))
800 source.maintainCache([])
James E. Blair4886cc12012-07-18 15:39:41 -0700801
802 def test_build_configuration(self):
803 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700804
805 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -0700806 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
807 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
808 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
809 A.addApproval('CRVW', 2)
810 B.addApproval('CRVW', 2)
811 C.addApproval('CRVW', 2)
812 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
813 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
814 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
815 self.waitUntilSettled()
816
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700817 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700818 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700819 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700820 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700821 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700822 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700823 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700824 ref = self.getParameter(queue[-1], 'ZUUL_REF')
825 self.gearman_server.hold_jobs_in_queue = False
826 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700827 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -0700828
Monty Taylorbc758832013-06-17 17:22:42 -0400829 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -0700830 repo = git.Repo(path)
831 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
832 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -0700833 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400834 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -0700835
836 def test_build_configuration_conflict(self):
837 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700838
839 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -0700840 A = self.fake_gerrit.addFakeChange('org/conflict-project',
841 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -0700842 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700843 B = self.fake_gerrit.addFakeChange('org/conflict-project',
844 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -0700845 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700846 C = self.fake_gerrit.addFakeChange('org/conflict-project',
847 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -0700848 A.addApproval('CRVW', 2)
849 B.addApproval('CRVW', 2)
850 C.addApproval('CRVW', 2)
851 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
852 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
853 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
854 self.waitUntilSettled()
855
James E. Blair6736beb2013-07-11 15:18:15 -0700856 self.assertEqual(A.reported, 1)
857 self.assertEqual(B.reported, 1)
858 self.assertEqual(C.reported, 1)
859
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700860 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700861 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700862 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700863 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700864 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700865 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -0700866
867 self.assertEqual(len(self.history), 2) # A and C merge jobs
868
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700869 self.gearman_server.hold_jobs_in_queue = False
870 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700871 self.waitUntilSettled()
872
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400873 self.assertEqual(A.data['status'], 'MERGED')
874 self.assertEqual(B.data['status'], 'NEW')
875 self.assertEqual(C.data['status'], 'MERGED')
876 self.assertEqual(A.reported, 2)
877 self.assertEqual(B.reported, 2)
878 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -0700879 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -0700880
James E. Blairdaabed22012-08-15 15:38:57 -0700881 def test_post(self):
882 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700883
Zhongyue Luo5d556072012-09-21 02:00:47 +0900884 e = {
885 "type": "ref-updated",
886 "submitter": {
887 "name": "User Name",
888 },
889 "refUpdate": {
890 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
891 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
892 "refName": "master",
893 "project": "org/project",
894 }
895 }
James E. Blairdaabed22012-08-15 15:38:57 -0700896 self.fake_gerrit.addEvent(e)
897 self.waitUntilSettled()
898
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400899 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400900 self.assertEqual(len(self.history), 1)
901 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -0700902
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700903 def test_post_ignore_deletes(self):
904 "Test that deleting refs does not trigger post jobs"
905
906 e = {
907 "type": "ref-updated",
908 "submitter": {
909 "name": "User Name",
910 },
911 "refUpdate": {
912 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
913 "newRev": "0000000000000000000000000000000000000000",
914 "refName": "master",
915 "project": "org/project",
916 }
917 }
918 self.fake_gerrit.addEvent(e)
919 self.waitUntilSettled()
920
921 job_names = [x.name for x in self.history]
922 self.assertEqual(len(self.history), 0)
923 self.assertNotIn('project-post', job_names)
924
925 def test_post_ignore_deletes_negative(self):
926 "Test that deleting refs does trigger post jobs"
927
James E. Blairf84026c2015-12-08 16:11:46 -0800928 self.updateConfigLayout(
929 'tests/fixtures/layout-dont-ignore-deletes.yaml')
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700930 self.sched.reconfigure(self.config)
931
932 e = {
933 "type": "ref-updated",
934 "submitter": {
935 "name": "User Name",
936 },
937 "refUpdate": {
938 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
939 "newRev": "0000000000000000000000000000000000000000",
940 "refName": "master",
941 "project": "org/project",
942 }
943 }
944 self.fake_gerrit.addEvent(e)
945 self.waitUntilSettled()
946
947 job_names = [x.name for x in self.history]
948 self.assertEqual(len(self.history), 1)
949 self.assertIn('project-post', job_names)
950
James E. Blairc6294a52012-08-17 10:19:48 -0700951 def test_build_configuration_branch(self):
952 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700953
954 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700955 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
956 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
957 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
958 A.addApproval('CRVW', 2)
959 B.addApproval('CRVW', 2)
960 C.addApproval('CRVW', 2)
961 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
962 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
963 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
964 self.waitUntilSettled()
965
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700966 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700967 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700968 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700969 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700970 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700971 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700972 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700973 ref = self.getParameter(queue[-1], 'ZUUL_REF')
974 self.gearman_server.hold_jobs_in_queue = False
975 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -0700976 self.waitUntilSettled()
977
Monty Taylorbc758832013-06-17 17:22:42 -0400978 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -0700979 repo = git.Repo(path)
980 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
981 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -0700982 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400983 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -0700984
985 def test_build_configuration_branch_interaction(self):
986 "Test that switching between branches works"
987 self.test_build_configuration()
988 self.test_build_configuration_branch()
989 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -0400990 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -0700991 repo = git.Repo(path)
992 repo.heads.master.commit = repo.commit('init')
993 self.test_build_configuration()
994
995 def test_build_configuration_multi_branch(self):
996 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700997
998 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700999 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1000 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1001 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1002 A.addApproval('CRVW', 2)
1003 B.addApproval('CRVW', 2)
1004 C.addApproval('CRVW', 2)
1005 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1006 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1007 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1008 self.waitUntilSettled()
James E. Blairbb1fe502014-03-04 10:15:06 -08001009 queue = self.gearman_server.getQueue()
1010 job_A = None
1011 for job in queue:
1012 if 'project-merge' in job.name:
1013 job_A = job
1014 ref_A = self.getParameter(job_A, 'ZUUL_REF')
1015 commit_A = self.getParameter(job_A, 'ZUUL_COMMIT')
1016 self.log.debug("Got Zuul ref for change A: %s" % ref_A)
1017 self.log.debug("Got Zuul commit for change A: %s" % commit_A)
James E. Blairc6294a52012-08-17 10:19:48 -07001018
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001019 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001020 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001021 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001022 job_B = None
1023 for job in queue:
1024 if 'project-merge' in job.name:
1025 job_B = job
1026 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001027 commit_B = self.getParameter(job_B, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001028 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blairbb1fe502014-03-04 10:15:06 -08001029 self.log.debug("Got Zuul commit for change B: %s" % commit_B)
1030
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001031 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001032 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001033 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001034 for job in queue:
1035 if 'project-merge' in job.name:
1036 job_C = job
1037 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001038 commit_C = self.getParameter(job_C, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001039 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blairbb1fe502014-03-04 10:15:06 -08001040 self.log.debug("Got Zuul commit for change C: %s" % commit_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001041 self.gearman_server.hold_jobs_in_queue = False
1042 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001043 self.waitUntilSettled()
1044
Monty Taylorbc758832013-06-17 17:22:42 -04001045 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001046 repo = git.Repo(path)
1047
1048 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001049 for c in repo.iter_commits(ref_C)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001050 repo_shas = [c.hexsha for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001051 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001052 correct_messages = ['initial commit', 'A-1', 'C-1']
James E. Blairbb1fe502014-03-04 10:15:06 -08001053 # Ensure the right commits are in the history for this ref
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001054 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001055 # Ensure ZUUL_REF -> ZUUL_COMMIT
1056 self.assertEqual(repo_shas[0], commit_C)
James E. Blairc6294a52012-08-17 10:19:48 -07001057
1058 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001059 for c in repo.iter_commits(ref_B)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001060 repo_shas = [c.hexsha for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001061 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001062 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001063 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001064 self.assertEqual(repo_shas[0], commit_B)
1065
1066 repo_messages = [c.message.strip()
1067 for c in repo.iter_commits(ref_A)]
1068 repo_shas = [c.hexsha for c in repo.iter_commits(ref_A)]
1069 repo_messages.reverse()
1070 correct_messages = ['initial commit', 'A-1']
1071 self.assertEqual(repo_messages, correct_messages)
1072 self.assertEqual(repo_shas[0], commit_A)
1073
1074 self.assertNotEqual(ref_A, ref_B, ref_C)
1075 self.assertNotEqual(commit_A, commit_B, commit_C)
James E. Blair7f71c802012-08-22 13:04:32 -07001076
1077 def test_one_job_project(self):
1078 "Test that queueing works with one job"
1079 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1080 'master', 'A')
1081 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1082 'master', 'B')
1083 A.addApproval('CRVW', 2)
1084 B.addApproval('CRVW', 2)
1085 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1086 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1087 self.waitUntilSettled()
1088
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001089 self.assertEqual(A.data['status'], 'MERGED')
1090 self.assertEqual(A.reported, 2)
1091 self.assertEqual(B.data['status'], 'MERGED')
1092 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001093
Antoine Musso80edd5a2013-02-13 15:37:53 +01001094 def test_job_from_templates_launched(self):
1095 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001096
Antoine Musso80edd5a2013-02-13 15:37:53 +01001097 A = self.fake_gerrit.addFakeChange(
1098 'org/templated-project', 'master', 'A')
1099 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1100 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001101
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001102 self.assertEqual(self.getJobFromHistory('project-test1').result,
1103 'SUCCESS')
1104 self.assertEqual(self.getJobFromHistory('project-test2').result,
1105 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001106
James E. Blair3e98c022013-12-16 15:25:38 -08001107 def test_layered_templates(self):
1108 "Test whether a job generated via a template can be launched"
1109
1110 A = self.fake_gerrit.addFakeChange(
1111 'org/layered-project', 'master', 'A')
1112 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1113 self.waitUntilSettled()
1114
1115 self.assertEqual(self.getJobFromHistory('project-test1').result,
1116 'SUCCESS')
1117 self.assertEqual(self.getJobFromHistory('project-test2').result,
1118 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001119 self.assertEqual(self.getJobFromHistory('layered-project-test3'
1120 ).result, 'SUCCESS')
1121 self.assertEqual(self.getJobFromHistory('layered-project-test4'
1122 ).result, 'SUCCESS')
James E. Blair12a92b12014-03-26 11:54:53 -07001123 self.assertEqual(self.getJobFromHistory('layered-project-foo-test5'
1124 ).result, 'SUCCESS')
James E. Blair3e98c022013-12-16 15:25:38 -08001125 self.assertEqual(self.getJobFromHistory('project-test6').result,
1126 'SUCCESS')
1127
James E. Blaircaec0c52012-08-22 14:52:22 -07001128 def test_dependent_changes_dequeue(self):
1129 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001130
James E. Blaircaec0c52012-08-22 14:52:22 -07001131 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1132 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1133 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1134 A.addApproval('CRVW', 2)
1135 B.addApproval('CRVW', 2)
1136 C.addApproval('CRVW', 2)
1137
1138 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1139 M1.setMerged()
1140
1141 # C -> B -> A -> M1
1142
1143 C.setDependsOn(B, 1)
1144 B.setDependsOn(A, 1)
1145 A.setDependsOn(M1, 1)
1146
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001147 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001148
1149 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1150 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1151 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1152
1153 self.waitUntilSettled()
1154
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001155 self.assertEqual(A.data['status'], 'NEW')
1156 self.assertEqual(A.reported, 2)
1157 self.assertEqual(B.data['status'], 'NEW')
1158 self.assertEqual(B.reported, 2)
1159 self.assertEqual(C.data['status'], 'NEW')
1160 self.assertEqual(C.reported, 2)
1161 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001162
James E. Blair972e3c72013-08-29 12:04:55 -07001163 def test_failing_dependent_changes(self):
1164 "Test that failing dependent patches are taken out of stream"
1165 self.worker.hold_jobs_in_build = True
1166 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1167 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1168 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1169 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1170 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1171 A.addApproval('CRVW', 2)
1172 B.addApproval('CRVW', 2)
1173 C.addApproval('CRVW', 2)
1174 D.addApproval('CRVW', 2)
1175 E.addApproval('CRVW', 2)
1176
1177 # E, D -> C -> B, A
1178
1179 D.setDependsOn(C, 1)
1180 C.setDependsOn(B, 1)
1181
1182 self.worker.addFailTest('project-test1', B)
1183
1184 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1185 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1186 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1187 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1188 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1189
1190 self.waitUntilSettled()
1191 self.worker.release('.*-merge')
1192 self.waitUntilSettled()
1193 self.worker.release('.*-merge')
1194 self.waitUntilSettled()
1195 self.worker.release('.*-merge')
1196 self.waitUntilSettled()
1197 self.worker.release('.*-merge')
1198 self.waitUntilSettled()
1199 self.worker.release('.*-merge')
1200 self.waitUntilSettled()
1201
1202 self.worker.hold_jobs_in_build = False
1203 for build in self.builds:
1204 if build.parameters['ZUUL_CHANGE'] != '1':
1205 build.release()
1206 self.waitUntilSettled()
1207
1208 self.worker.release()
1209 self.waitUntilSettled()
1210
1211 self.assertEqual(A.data['status'], 'MERGED')
1212 self.assertEqual(A.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001213 self.assertIn('Build succeeded', A.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001214 self.assertEqual(B.data['status'], 'NEW')
1215 self.assertEqual(B.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001216 self.assertIn('Build failed', B.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001217 self.assertEqual(C.data['status'], 'NEW')
1218 self.assertEqual(C.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001219 self.assertIn('depends on a change', C.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001220 self.assertEqual(D.data['status'], 'NEW')
1221 self.assertEqual(D.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001222 self.assertIn('depends on a change', D.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001223 self.assertEqual(E.data['status'], 'MERGED')
1224 self.assertEqual(E.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001225 self.assertIn('Build succeeded', E.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001226 self.assertEqual(len(self.history), 18)
1227
James E. Blairec590122012-08-22 15:19:31 -07001228 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001229 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001230 # If it's dequeued more than once, we should see extra
1231 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001232
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001233 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001234 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1235 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1236 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1237 A.addApproval('CRVW', 2)
1238 B.addApproval('CRVW', 2)
1239 C.addApproval('CRVW', 2)
1240
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001241 self.worker.addFailTest('project1-test1', A)
1242 self.worker.addFailTest('project1-test2', A)
1243 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001244
1245 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1246 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1247 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1248
1249 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001250
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001251 self.assertEqual(len(self.builds), 1)
1252 self.assertEqual(self.builds[0].name, 'project1-merge')
1253 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001254
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001255 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001256 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001257 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001258 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001259 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001260 self.waitUntilSettled()
1261
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001262 self.assertEqual(len(self.builds), 9)
1263 self.assertEqual(self.builds[0].name, 'project1-test1')
1264 self.assertEqual(self.builds[1].name, 'project1-test2')
1265 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1266 self.assertEqual(self.builds[3].name, 'project1-test1')
1267 self.assertEqual(self.builds[4].name, 'project1-test2')
1268 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1269 self.assertEqual(self.builds[6].name, 'project1-test1')
1270 self.assertEqual(self.builds[7].name, 'project1-test2')
1271 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001272
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001273 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001274 self.waitUntilSettled()
1275
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001276 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1277 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001278
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001279 self.worker.hold_jobs_in_build = False
1280 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001281 self.waitUntilSettled()
1282
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001283 self.assertEqual(len(self.builds), 0)
1284 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001285
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001286 self.assertEqual(A.data['status'], 'NEW')
1287 self.assertEqual(B.data['status'], 'MERGED')
1288 self.assertEqual(C.data['status'], 'MERGED')
1289 self.assertEqual(A.reported, 2)
1290 self.assertEqual(B.reported, 2)
1291 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001292
1293 def test_nonvoting_job(self):
1294 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001295
James E. Blair4ec821f2012-08-23 15:28:28 -07001296 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1297 'master', 'A')
1298 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001299 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001300 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1301
1302 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001303
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001304 self.assertEqual(A.data['status'], 'MERGED')
1305 self.assertEqual(A.reported, 2)
1306 self.assertEqual(
1307 self.getJobFromHistory('nonvoting-project-merge').result,
1308 'SUCCESS')
1309 self.assertEqual(
1310 self.getJobFromHistory('nonvoting-project-test1').result,
1311 'SUCCESS')
1312 self.assertEqual(
1313 self.getJobFromHistory('nonvoting-project-test2').result,
1314 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001315
James E. Blair5821bd92015-09-16 08:48:15 -07001316 for build in self.builds:
1317 self.assertEqual(build.parameters['ZUUL_VOTING'], '0')
1318
James E. Blaire0487072012-08-29 17:38:31 -07001319 def test_check_queue_success(self):
1320 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001321
James E. Blaire0487072012-08-29 17:38:31 -07001322 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1323 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1324
1325 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001326
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001327 self.assertEqual(A.data['status'], 'NEW')
1328 self.assertEqual(A.reported, 1)
1329 self.assertEqual(self.getJobFromHistory('project-merge').result,
1330 'SUCCESS')
1331 self.assertEqual(self.getJobFromHistory('project-test1').result,
1332 'SUCCESS')
1333 self.assertEqual(self.getJobFromHistory('project-test2').result,
1334 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001335
1336 def test_check_queue_failure(self):
1337 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001338
James E. Blaire0487072012-08-29 17:38:31 -07001339 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001340 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001341 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1342
1343 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001344
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001345 self.assertEqual(A.data['status'], 'NEW')
1346 self.assertEqual(A.reported, 1)
1347 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001348 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001349 self.assertEqual(self.getJobFromHistory('project-test1').result,
1350 'SUCCESS')
1351 self.assertEqual(self.getJobFromHistory('project-test2').result,
1352 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001353
1354 def test_dependent_behind_dequeue(self):
1355 "test that dependent changes behind dequeued changes work"
1356 # This complicated test is a reproduction of a real life bug
1357 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001358
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001359 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001360 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1361 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1362 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1363 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1364 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1365 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1366 D.setDependsOn(C, 1)
1367 E.setDependsOn(D, 1)
1368 A.addApproval('CRVW', 2)
1369 B.addApproval('CRVW', 2)
1370 C.addApproval('CRVW', 2)
1371 D.addApproval('CRVW', 2)
1372 E.addApproval('CRVW', 2)
1373 F.addApproval('CRVW', 2)
1374
1375 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001376
1377 # Change object re-use in the gerrit trigger is hidden if
1378 # changes are added in quick succession; waiting makes it more
1379 # like real life.
1380 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1381 self.waitUntilSettled()
1382 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1383 self.waitUntilSettled()
1384
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001385 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001386 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001387 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001388 self.waitUntilSettled()
1389
1390 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1391 self.waitUntilSettled()
1392 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1393 self.waitUntilSettled()
1394 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1395 self.waitUntilSettled()
1396 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1397 self.waitUntilSettled()
1398
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001399 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001400 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001401 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001402 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001403 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001404 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001405 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001406 self.waitUntilSettled()
1407
1408 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001409
1410 # Grab pointers to the jobs we want to release before
1411 # releasing any, because list indexes may change as
1412 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001413 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001414 a.release()
1415 b.release()
1416 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001417 self.waitUntilSettled()
1418
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001419 self.worker.hold_jobs_in_build = False
1420 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001421 self.waitUntilSettled()
1422
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001423 self.assertEqual(A.data['status'], 'NEW')
1424 self.assertEqual(B.data['status'], 'MERGED')
1425 self.assertEqual(C.data['status'], 'MERGED')
1426 self.assertEqual(D.data['status'], 'MERGED')
1427 self.assertEqual(E.data['status'], 'MERGED')
1428 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07001429
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001430 self.assertEqual(A.reported, 2)
1431 self.assertEqual(B.reported, 2)
1432 self.assertEqual(C.reported, 2)
1433 self.assertEqual(D.reported, 2)
1434 self.assertEqual(E.reported, 2)
1435 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07001436
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001437 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
1438 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07001439
1440 def test_merger_repack(self):
1441 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001442
James E. Blair05fed602012-09-07 12:45:24 -07001443 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1444 A.addApproval('CRVW', 2)
1445 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1446 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001447 self.assertEqual(self.getJobFromHistory('project-merge').result,
1448 'SUCCESS')
1449 self.assertEqual(self.getJobFromHistory('project-test1').result,
1450 'SUCCESS')
1451 self.assertEqual(self.getJobFromHistory('project-test2').result,
1452 'SUCCESS')
1453 self.assertEqual(A.data['status'], 'MERGED')
1454 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07001455 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001456 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001457
Monty Taylorbc758832013-06-17 17:22:42 -04001458 path = os.path.join(self.git_root, "org/project")
1459 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07001460
1461 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1462 A.addApproval('CRVW', 2)
1463 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1464 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001465 self.assertEqual(self.getJobFromHistory('project-merge').result,
1466 'SUCCESS')
1467 self.assertEqual(self.getJobFromHistory('project-test1').result,
1468 'SUCCESS')
1469 self.assertEqual(self.getJobFromHistory('project-test2').result,
1470 'SUCCESS')
1471 self.assertEqual(A.data['status'], 'MERGED')
1472 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001473
James E. Blair4886f282012-11-15 09:27:33 -08001474 def test_merger_repack_large_change(self):
1475 "Test that the merger works with large changes after a repack"
1476 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08001477 # This test assumes the repo is already cloned; make sure it is
Joshua Hesketh352264b2015-08-11 23:42:08 +10001478 url = self.fake_gerrit.getGitUrl(
James E. Blairac2c3242014-01-24 13:38:51 -08001479 self.sched.layout.projects['org/project1'])
James E. Blair4076e2b2014-01-28 12:42:20 -08001480 self.merge_server.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08001481 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1482 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001483 path = os.path.join(self.upstream_root, "org/project1")
1484 print repack_repo(path)
1485 path = os.path.join(self.git_root, "org/project1")
1486 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08001487
1488 A.addApproval('CRVW', 2)
1489 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1490 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001491 self.assertEqual(self.getJobFromHistory('project1-merge').result,
1492 'SUCCESS')
1493 self.assertEqual(self.getJobFromHistory('project1-test1').result,
1494 'SUCCESS')
1495 self.assertEqual(self.getJobFromHistory('project1-test2').result,
1496 'SUCCESS')
1497 self.assertEqual(A.data['status'], 'MERGED')
1498 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08001499
James E. Blair7ee88a22012-09-12 18:59:31 +02001500 def test_nonexistent_job(self):
1501 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001502 # Set to the state immediately after a restart
1503 self.resetGearmanServer()
1504 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001505
1506 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1507 A.addApproval('CRVW', 2)
1508 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1509 # There may be a thread about to report a lost change
1510 while A.reported < 2:
1511 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001512 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001513 self.assertFalse(job_names)
1514 self.assertEqual(A.data['status'], 'NEW')
1515 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001516 self.assertEmptyQueues()
1517
1518 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001519 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001520 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1521 A.addApproval('CRVW', 2)
1522 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1523 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001524 self.assertEqual(self.getJobFromHistory('project-merge').result,
1525 'SUCCESS')
1526 self.assertEqual(self.getJobFromHistory('project-test1').result,
1527 'SUCCESS')
1528 self.assertEqual(self.getJobFromHistory('project-test2').result,
1529 'SUCCESS')
1530 self.assertEqual(A.data['status'], 'MERGED')
1531 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08001532
1533 def test_single_nonexistent_post_job(self):
1534 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001535 e = {
1536 "type": "ref-updated",
1537 "submitter": {
1538 "name": "User Name",
1539 },
1540 "refUpdate": {
1541 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1542 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1543 "refName": "master",
1544 "project": "org/project",
1545 }
1546 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001547 # Set to the state immediately after a restart
1548 self.resetGearmanServer()
1549 self.launcher.negative_function_cache_ttl = 0
1550
James E. Blairf62d4282012-12-31 17:01:50 -08001551 self.fake_gerrit.addEvent(e)
1552 self.waitUntilSettled()
1553
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001554 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08001555
1556 def test_new_patchset_dequeues_old(self):
1557 "Test that a new patchset causes the old to be dequeued"
1558 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001559 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001560 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1561 M.setMerged()
1562
1563 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1564 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1565 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1566 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1567 A.addApproval('CRVW', 2)
1568 B.addApproval('CRVW', 2)
1569 C.addApproval('CRVW', 2)
1570 D.addApproval('CRVW', 2)
1571
1572 C.setDependsOn(B, 1)
1573 B.setDependsOn(A, 1)
1574 A.setDependsOn(M, 1)
1575
1576 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1577 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1578 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1579 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1580 self.waitUntilSettled()
1581
1582 B.addPatchset()
1583 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1584 self.waitUntilSettled()
1585
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001586 self.worker.hold_jobs_in_build = False
1587 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001588 self.waitUntilSettled()
1589
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001590 self.assertEqual(A.data['status'], 'MERGED')
1591 self.assertEqual(A.reported, 2)
1592 self.assertEqual(B.data['status'], 'NEW')
1593 self.assertEqual(B.reported, 2)
1594 self.assertEqual(C.data['status'], 'NEW')
1595 self.assertEqual(C.reported, 2)
1596 self.assertEqual(D.data['status'], 'MERGED')
1597 self.assertEqual(D.reported, 2)
1598 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001599
James E. Blairba437362015-02-07 11:41:52 -08001600 def test_new_patchset_check(self):
1601 "Test a new patchset in check"
Antoine Mussobd86a312014-01-08 14:51:33 +01001602
1603 self.worker.hold_jobs_in_build = True
1604
1605 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairba437362015-02-07 11:41:52 -08001606 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1607 check_pipeline = self.sched.layout.pipelines['check']
1608
1609 # Add two git-dependent changes
1610 B.setDependsOn(A, 1)
1611 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1612 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001613 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1614 self.waitUntilSettled()
James E. Blairba437362015-02-07 11:41:52 -08001615
1616 # A live item, and a non-live/live pair
1617 items = check_pipeline.getAllItems()
1618 self.assertEqual(len(items), 3)
1619
1620 self.assertEqual(items[0].change.number, '1')
1621 self.assertEqual(items[0].change.patchset, '1')
1622 self.assertFalse(items[0].live)
1623
1624 self.assertEqual(items[1].change.number, '2')
1625 self.assertEqual(items[1].change.patchset, '1')
1626 self.assertTrue(items[1].live)
1627
1628 self.assertEqual(items[2].change.number, '1')
1629 self.assertEqual(items[2].change.patchset, '1')
1630 self.assertTrue(items[2].live)
1631
1632 # Add a new patchset to A
1633 A.addPatchset()
1634 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1635 self.waitUntilSettled()
1636
1637 # The live copy of A,1 should be gone, but the non-live and B
1638 # should continue, and we should have a new A,2
1639 items = check_pipeline.getAllItems()
1640 self.assertEqual(len(items), 3)
1641
1642 self.assertEqual(items[0].change.number, '1')
1643 self.assertEqual(items[0].change.patchset, '1')
1644 self.assertFalse(items[0].live)
1645
1646 self.assertEqual(items[1].change.number, '2')
1647 self.assertEqual(items[1].change.patchset, '1')
1648 self.assertTrue(items[1].live)
1649
1650 self.assertEqual(items[2].change.number, '1')
1651 self.assertEqual(items[2].change.patchset, '2')
1652 self.assertTrue(items[2].live)
1653
1654 # Add a new patchset to B
1655 B.addPatchset()
1656 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1657 self.waitUntilSettled()
1658
1659 # The live copy of B,1 should be gone, and it's non-live copy of A,1
1660 # but we should have a new B,2 (still based on A,1)
1661 items = check_pipeline.getAllItems()
1662 self.assertEqual(len(items), 3)
1663
1664 self.assertEqual(items[0].change.number, '1')
1665 self.assertEqual(items[0].change.patchset, '2')
1666 self.assertTrue(items[0].live)
1667
1668 self.assertEqual(items[1].change.number, '1')
1669 self.assertEqual(items[1].change.patchset, '1')
1670 self.assertFalse(items[1].live)
1671
1672 self.assertEqual(items[2].change.number, '2')
1673 self.assertEqual(items[2].change.patchset, '2')
1674 self.assertTrue(items[2].live)
1675
1676 self.builds[0].release()
1677 self.waitUntilSettled()
1678 self.builds[0].release()
1679 self.waitUntilSettled()
1680 self.worker.hold_jobs_in_build = False
1681 self.worker.release()
1682 self.waitUntilSettled()
1683
1684 self.assertEqual(A.reported, 1)
1685 self.assertEqual(B.reported, 1)
1686 self.assertEqual(self.history[0].result, 'ABORTED')
1687 self.assertEqual(self.history[0].changes, '1,1')
1688 self.assertEqual(self.history[1].result, 'ABORTED')
1689 self.assertEqual(self.history[1].changes, '1,1 2,1')
1690 self.assertEqual(self.history[2].result, 'SUCCESS')
1691 self.assertEqual(self.history[2].changes, '1,2')
1692 self.assertEqual(self.history[3].result, 'SUCCESS')
1693 self.assertEqual(self.history[3].changes, '1,1 2,2')
1694
1695 def test_abandoned_gate(self):
1696 "Test that an abandoned change is dequeued from gate"
1697
1698 self.worker.hold_jobs_in_build = True
1699
1700 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1701 A.addApproval('CRVW', 2)
1702 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1703 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001704 self.assertEqual(len(self.builds), 1, "One job being built (on hold)")
1705 self.assertEqual(self.builds[0].name, 'project-merge')
1706
1707 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1708 self.waitUntilSettled()
1709
Antoine Mussobd86a312014-01-08 14:51:33 +01001710 self.worker.release('.*-merge')
1711 self.waitUntilSettled()
1712
1713 self.assertEqual(len(self.builds), 0, "No job running")
Antoine Mussobd86a312014-01-08 14:51:33 +01001714 self.assertEqual(len(self.history), 1, "Only one build in history")
1715 self.assertEqual(self.history[0].result, 'ABORTED',
James E. Blairba437362015-02-07 11:41:52 -08001716 "Build should have been aborted")
1717 self.assertEqual(A.reported, 1,
1718 "Abandoned gate change should report only start")
1719
1720 def test_abandoned_check(self):
1721 "Test that an abandoned change is dequeued from check"
1722
1723 self.worker.hold_jobs_in_build = True
1724
1725 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1726 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1727 check_pipeline = self.sched.layout.pipelines['check']
1728
1729 # Add two git-dependent changes
1730 B.setDependsOn(A, 1)
1731 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1732 self.waitUntilSettled()
1733 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1734 self.waitUntilSettled()
1735 # A live item, and a non-live/live pair
1736 items = check_pipeline.getAllItems()
1737 self.assertEqual(len(items), 3)
1738
1739 self.assertEqual(items[0].change.number, '1')
1740 self.assertFalse(items[0].live)
1741
1742 self.assertEqual(items[1].change.number, '2')
1743 self.assertTrue(items[1].live)
1744
1745 self.assertEqual(items[2].change.number, '1')
1746 self.assertTrue(items[2].live)
1747
1748 # Abandon A
1749 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1750 self.waitUntilSettled()
1751
1752 # The live copy of A should be gone, but the non-live and B
1753 # should continue
1754 items = check_pipeline.getAllItems()
1755 self.assertEqual(len(items), 2)
1756
1757 self.assertEqual(items[0].change.number, '1')
1758 self.assertFalse(items[0].live)
1759
1760 self.assertEqual(items[1].change.number, '2')
1761 self.assertTrue(items[1].live)
1762
1763 self.worker.hold_jobs_in_build = False
1764 self.worker.release()
1765 self.waitUntilSettled()
1766
1767 self.assertEqual(len(self.history), 4)
1768 self.assertEqual(self.history[0].result, 'ABORTED',
Antoine Mussobd86a312014-01-08 14:51:33 +01001769 'Build should have been aborted')
1770 self.assertEqual(A.reported, 0, "Abandoned change should not report")
James E. Blairba437362015-02-07 11:41:52 -08001771 self.assertEqual(B.reported, 1, "Change should report")
Antoine Mussobd86a312014-01-08 14:51:33 +01001772
Steve Varnau7b78b312015-04-03 14:49:46 -07001773 def test_abandoned_not_timer(self):
1774 "Test that an abandoned change does not cancel timer jobs"
1775
1776 self.worker.hold_jobs_in_build = True
1777
1778 # Start timer trigger - also org/project
James E. Blairf84026c2015-12-08 16:11:46 -08001779 self.updateConfigLayout(
1780 'tests/fixtures/layout-idle.yaml')
Steve Varnau7b78b312015-04-03 14:49:46 -07001781 self.sched.reconfigure(self.config)
1782 self.registerJobs()
1783 # The pipeline triggers every second, so we should have seen
1784 # several by now.
1785 time.sleep(5)
1786 self.waitUntilSettled()
1787 # Stop queuing timer triggered jobs so that the assertions
1788 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08001789 self.updateConfigLayout(
1790 'tests/fixtures/layout-no-timer.yaml')
Steve Varnau7b78b312015-04-03 14:49:46 -07001791 self.sched.reconfigure(self.config)
1792 self.registerJobs()
1793 self.assertEqual(len(self.builds), 2, "Two timer jobs")
1794
1795 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1796 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1797 self.waitUntilSettled()
1798 self.assertEqual(len(self.builds), 3, "One change plus two timer jobs")
1799
1800 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1801 self.waitUntilSettled()
1802
1803 self.assertEqual(len(self.builds), 2, "Two timer jobs remain")
1804
1805 self.worker.release()
1806 self.waitUntilSettled()
1807
Arx Cruzb1b010d2013-10-28 19:49:59 -02001808 def test_zuul_url_return(self):
1809 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
James E. Blair4076e2b2014-01-28 12:42:20 -08001810 self.assertTrue(self.sched.config.has_option('merger', 'zuul_url'))
Arx Cruzb1b010d2013-10-28 19:49:59 -02001811 self.worker.hold_jobs_in_build = True
1812
1813 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1814 A.addApproval('CRVW', 2)
1815 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1816 self.waitUntilSettled()
1817
1818 self.assertEqual(len(self.builds), 1)
1819 for build in self.builds:
1820 self.assertTrue('ZUUL_URL' in build.parameters)
1821
1822 self.worker.hold_jobs_in_build = False
1823 self.worker.release()
1824 self.waitUntilSettled()
1825
James E. Blair2fa50962013-01-30 21:50:41 -08001826 def test_new_patchset_dequeues_old_on_head(self):
1827 "Test that a new patchset causes the old to be dequeued (at head)"
1828 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001829 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001830 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1831 M.setMerged()
1832 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1833 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1834 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1835 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1836 A.addApproval('CRVW', 2)
1837 B.addApproval('CRVW', 2)
1838 C.addApproval('CRVW', 2)
1839 D.addApproval('CRVW', 2)
1840
1841 C.setDependsOn(B, 1)
1842 B.setDependsOn(A, 1)
1843 A.setDependsOn(M, 1)
1844
1845 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1846 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1847 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1848 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1849 self.waitUntilSettled()
1850
1851 A.addPatchset()
1852 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1853 self.waitUntilSettled()
1854
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001855 self.worker.hold_jobs_in_build = False
1856 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001857 self.waitUntilSettled()
1858
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001859 self.assertEqual(A.data['status'], 'NEW')
1860 self.assertEqual(A.reported, 2)
1861 self.assertEqual(B.data['status'], 'NEW')
1862 self.assertEqual(B.reported, 2)
1863 self.assertEqual(C.data['status'], 'NEW')
1864 self.assertEqual(C.reported, 2)
1865 self.assertEqual(D.data['status'], 'MERGED')
1866 self.assertEqual(D.reported, 2)
1867 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08001868
1869 def test_new_patchset_dequeues_old_without_dependents(self):
1870 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001871 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001872 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1873 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1874 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1875 A.addApproval('CRVW', 2)
1876 B.addApproval('CRVW', 2)
1877 C.addApproval('CRVW', 2)
1878
1879 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1880 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1881 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1882 self.waitUntilSettled()
1883
1884 B.addPatchset()
1885 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1886 self.waitUntilSettled()
1887
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001888 self.worker.hold_jobs_in_build = False
1889 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001890 self.waitUntilSettled()
1891
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001892 self.assertEqual(A.data['status'], 'MERGED')
1893 self.assertEqual(A.reported, 2)
1894 self.assertEqual(B.data['status'], 'NEW')
1895 self.assertEqual(B.reported, 2)
1896 self.assertEqual(C.data['status'], 'MERGED')
1897 self.assertEqual(C.reported, 2)
1898 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08001899
1900 def test_new_patchset_dequeues_old_independent_queue(self):
1901 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001902 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001903 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1904 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1905 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1906 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1907 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1908 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1909 self.waitUntilSettled()
1910
1911 B.addPatchset()
1912 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1913 self.waitUntilSettled()
1914
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001915 self.worker.hold_jobs_in_build = False
1916 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001917 self.waitUntilSettled()
1918
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001919 self.assertEqual(A.data['status'], 'NEW')
1920 self.assertEqual(A.reported, 1)
1921 self.assertEqual(B.data['status'], 'NEW')
1922 self.assertEqual(B.reported, 1)
1923 self.assertEqual(C.data['status'], 'NEW')
1924 self.assertEqual(C.reported, 1)
1925 self.assertEqual(len(self.history), 10)
1926 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001927
James E. Blair18c64442014-03-18 10:14:45 -07001928 def test_noop_job(self):
1929 "Test that the internal noop job works"
1930 A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A')
1931 A.addApproval('CRVW', 2)
1932 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1933 self.waitUntilSettled()
1934
1935 self.assertEqual(len(self.gearman_server.getQueue()), 0)
1936 self.assertTrue(self.sched._areAllBuildsComplete())
1937 self.assertEqual(len(self.history), 0)
1938 self.assertEqual(A.data['status'], 'MERGED')
1939 self.assertEqual(A.reported, 2)
1940
Evgeny Antyshevd6e546c2015-06-11 15:13:57 +00001941 def test_no_job_project(self):
1942 "Test that reports with no jobs don't get sent"
1943 A = self.fake_gerrit.addFakeChange('org/no-jobs-project',
1944 'master', 'A')
1945 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1946 self.waitUntilSettled()
1947
1948 # Change wasn't reported to
1949 self.assertEqual(A.reported, False)
1950
1951 # Check queue is empty afterwards
1952 check_pipeline = self.sched.layout.pipelines['check']
1953 items = check_pipeline.getAllItems()
1954 self.assertEqual(len(items), 0)
1955
1956 self.assertEqual(len(self.history), 0)
1957
James E. Blair7d0dedc2013-02-21 17:26:09 -08001958 def test_zuul_refs(self):
1959 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001960 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08001961 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1962 M1.setMerged()
1963 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1964 M2.setMerged()
1965
1966 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1967 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1968 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1969 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1970 A.addApproval('CRVW', 2)
1971 B.addApproval('CRVW', 2)
1972 C.addApproval('CRVW', 2)
1973 D.addApproval('CRVW', 2)
1974 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1975 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1976 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1977 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1978
1979 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001980 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001981 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001982 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001983 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001984 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001985 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001986 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001987 self.waitUntilSettled()
1988
James E. Blair7d0dedc2013-02-21 17:26:09 -08001989 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001990 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08001991 if x.parameters['ZUUL_CHANGE'] == '3':
1992 a_zref = x.parameters['ZUUL_REF']
1993 if x.parameters['ZUUL_CHANGE'] == '4':
1994 b_zref = x.parameters['ZUUL_REF']
1995 if x.parameters['ZUUL_CHANGE'] == '5':
1996 c_zref = x.parameters['ZUUL_REF']
1997 if x.parameters['ZUUL_CHANGE'] == '6':
1998 d_zref = x.parameters['ZUUL_REF']
1999
2000 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002001 self.assertIsNotNone(a_zref)
2002 self.assertIsNotNone(b_zref)
2003 self.assertIsNotNone(c_zref)
2004 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002005
2006 # And they should all be different
2007 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002008 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002009
2010 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002011 self.assertTrue(self.ref_has_change(a_zref, A))
2012 self.assertFalse(self.ref_has_change(a_zref, B))
2013 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002014
2015 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002016 self.assertTrue(self.ref_has_change(b_zref, A))
2017 self.assertTrue(self.ref_has_change(b_zref, B))
2018 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002019
2020 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002021 self.assertTrue(self.ref_has_change(c_zref, A))
2022 self.assertTrue(self.ref_has_change(c_zref, B))
2023 self.assertTrue(self.ref_has_change(c_zref, C))
2024 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002025
2026 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002027 self.assertTrue(self.ref_has_change(d_zref, A))
2028 self.assertTrue(self.ref_has_change(d_zref, B))
2029 self.assertTrue(self.ref_has_change(d_zref, C))
2030 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002031
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002032 self.worker.hold_jobs_in_build = False
2033 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002034 self.waitUntilSettled()
2035
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002036 self.assertEqual(A.data['status'], 'MERGED')
2037 self.assertEqual(A.reported, 2)
2038 self.assertEqual(B.data['status'], 'MERGED')
2039 self.assertEqual(B.reported, 2)
2040 self.assertEqual(C.data['status'], 'MERGED')
2041 self.assertEqual(C.reported, 2)
2042 self.assertEqual(D.data['status'], 'MERGED')
2043 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002044
James E. Blair4a28a882013-08-23 15:17:33 -07002045 def test_rerun_on_error(self):
2046 "Test that if a worker fails to run a job, it is run again"
2047 self.worker.hold_jobs_in_build = True
2048 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2049 A.addApproval('CRVW', 2)
2050 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2051 self.waitUntilSettled()
2052
2053 self.builds[0].run_error = True
2054 self.worker.hold_jobs_in_build = False
2055 self.worker.release()
2056 self.waitUntilSettled()
2057 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2058 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2059
James E. Blair412e5582013-04-22 15:50:12 -07002060 def test_statsd(self):
2061 "Test each of the statsd methods used in the scheduler"
2062 import extras
2063 statsd = extras.try_import('statsd.statsd')
2064 statsd.incr('test-incr')
2065 statsd.timing('test-timing', 3)
Alex Gaynor813d39b2014-05-17 16:17:16 -07002066 statsd.gauge('test-gauge', 12)
James E. Blair412e5582013-04-22 15:50:12 -07002067 self.assertReportedStat('test-incr', '1|c')
2068 self.assertReportedStat('test-timing', '3|ms')
Alex Gaynor813d39b2014-05-17 16:17:16 -07002069 self.assertReportedStat('test-gauge', '12|g')
James E. Blair412e5582013-04-22 15:50:12 -07002070
James E. Blairdad52252014-02-07 16:59:17 -08002071 def test_stuck_job_cleanup(self):
2072 "Test that pending jobs are cleaned up if removed from layout"
James E. Blair18c64442014-03-18 10:14:45 -07002073 # This job won't be registered at startup because it is not in
2074 # the standard layout, but we need it to already be registerd
2075 # for when we reconfigure, as that is when Zuul will attempt
2076 # to run the new job.
2077 self.worker.registerFunction('build:gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002078 self.gearman_server.hold_jobs_in_queue = True
2079 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2080 A.addApproval('CRVW', 2)
2081 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2082 self.waitUntilSettled()
2083 self.assertEqual(len(self.gearman_server.getQueue()), 1)
2084
James E. Blairf84026c2015-12-08 16:11:46 -08002085 self.updateConfigLayout(
2086 'tests/fixtures/layout-no-jobs.yaml')
James E. Blairdad52252014-02-07 16:59:17 -08002087 self.sched.reconfigure(self.config)
2088 self.waitUntilSettled()
2089
James E. Blair18c64442014-03-18 10:14:45 -07002090 self.gearman_server.release('gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002091 self.waitUntilSettled()
2092 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2093 self.assertTrue(self.sched._areAllBuildsComplete())
2094
2095 self.assertEqual(len(self.history), 1)
James E. Blair18c64442014-03-18 10:14:45 -07002096 self.assertEqual(self.history[0].name, 'gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002097 self.assertEqual(self.history[0].result, 'SUCCESS')
2098
James E. Blair879dafb2015-07-17 14:04:49 -07002099 def test_file_head(self):
2100 # This is a regression test for an observed bug. A change
2101 # with a file named "HEAD" in the root directory of the repo
2102 # was processed by a merger. It then was unable to reset the
2103 # repo because of:
2104 # GitCommandError: 'git reset --hard HEAD' returned
2105 # with exit code 128
2106 # stderr: 'fatal: ambiguous argument 'HEAD': both revision
2107 # and filename
2108 # Use '--' to separate filenames from revisions'
2109
2110 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2111 A.addPatchset(['HEAD'])
2112 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2113
2114 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2115 self.waitUntilSettled()
2116
2117 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2118 self.waitUntilSettled()
2119
2120 self.assertIn('Build succeeded', A.messages[0])
2121 self.assertIn('Build succeeded', B.messages[0])
2122
James E. Blair70c71582013-03-06 08:50:50 -08002123 def test_file_jobs(self):
2124 "Test that file jobs run only when appropriate"
2125 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2126 A.addPatchset(['pip-requires'])
2127 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2128 A.addApproval('CRVW', 2)
2129 B.addApproval('CRVW', 2)
2130 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2131 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2132 self.waitUntilSettled()
2133
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002134 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002135 if x.name == 'project-testfile']
2136
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002137 self.assertEqual(len(testfile_jobs), 1)
2138 self.assertEqual(testfile_jobs[0].changes, '1,2')
2139 self.assertEqual(A.data['status'], 'MERGED')
2140 self.assertEqual(A.reported, 2)
2141 self.assertEqual(B.data['status'], 'MERGED')
2142 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002143
Maru Newby3fe5f852015-01-13 04:22:14 +00002144 def _test_skip_if_jobs(self, branch, should_skip):
2145 "Test that jobs with a skip-if filter run only when appropriate"
James E. Blairf84026c2015-12-08 16:11:46 -08002146 self.updateConfigLayout(
2147 'tests/fixtures/layout-skip-if.yaml')
Maru Newby3fe5f852015-01-13 04:22:14 +00002148 self.sched.reconfigure(self.config)
2149 self.registerJobs()
2150
2151 change = self.fake_gerrit.addFakeChange('org/project',
2152 branch,
2153 'test skip-if')
2154 self.fake_gerrit.addEvent(change.getPatchsetCreatedEvent(1))
2155 self.waitUntilSettled()
2156
2157 tested_change_ids = [x.changes[0] for x in self.history
2158 if x.name == 'project-test-skip-if']
2159
2160 if should_skip:
2161 self.assertEqual([], tested_change_ids)
2162 else:
2163 self.assertIn(change.data['number'], tested_change_ids)
2164
2165 def test_skip_if_match_skips_job(self):
2166 self._test_skip_if_jobs(branch='master', should_skip=True)
2167
2168 def test_skip_if_no_match_runs_job(self):
2169 self._test_skip_if_jobs(branch='mp', should_skip=False)
2170
James E. Blair3c5e5b52013-04-26 11:17:03 -07002171 def test_test_config(self):
2172 "Test that we can test the config"
James E. Blairf84026c2015-12-08 16:11:46 -08002173 self.sched.testConfig(self.config.get('zuul', 'tenant_config'),
Joshua Hesketh352264b2015-08-11 23:42:08 +10002174 self.connections)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002175
2176 def test_build_description(self):
2177 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002178 self.worker.registerFunction('set_description:' +
2179 self.worker.worker_id)
2180
2181 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2182 A.addApproval('CRVW', 2)
2183 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2184 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002185 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002186 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002187 self.assertTrue(re.search("Branch.*master", desc))
2188 self.assertTrue(re.search("Pipeline.*gate", desc))
2189 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2190 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2191 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2192 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002193
James E. Blairc8a1e052014-02-25 09:29:26 -08002194 def test_queue_names(self):
2195 "Test shared change queue names"
2196 project1 = self.sched.layout.projects['org/project1']
2197 project2 = self.sched.layout.projects['org/project2']
2198 q1 = self.sched.layout.pipelines['gate'].getQueue(project1)
2199 q2 = self.sched.layout.pipelines['gate'].getQueue(project2)
2200 self.assertEqual(q1.name, 'integration')
2201 self.assertEqual(q2.name, 'integration')
2202
James E. Blairf84026c2015-12-08 16:11:46 -08002203 self.updateConfigLayout(
2204 'tests/fixtures/layout-bad-queue.yaml')
James E. Blairc8a1e052014-02-25 09:29:26 -08002205 with testtools.ExpectedException(
2206 Exception, "More than one name assigned to change queue"):
2207 self.sched.reconfigure(self.config)
2208
James E. Blair64ed6f22013-07-10 14:07:23 -07002209 def test_queue_precedence(self):
2210 "Test that queue precedence works"
2211
2212 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002213 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002214 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2215 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2216 A.addApproval('CRVW', 2)
2217 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2218
2219 self.waitUntilSettled()
2220 self.gearman_server.hold_jobs_in_queue = False
2221 self.gearman_server.release()
2222 self.waitUntilSettled()
2223
James E. Blair8de58bd2013-07-18 16:23:33 -07002224 # Run one build at a time to ensure non-race order:
James E. Blairb8c16472015-05-05 14:55:26 -07002225 self.orderedRelease()
James E. Blair8de58bd2013-07-18 16:23:33 -07002226 self.worker.hold_jobs_in_build = False
2227 self.waitUntilSettled()
2228
James E. Blair64ed6f22013-07-10 14:07:23 -07002229 self.log.debug(self.history)
2230 self.assertEqual(self.history[0].pipeline, 'gate')
2231 self.assertEqual(self.history[1].pipeline, 'check')
2232 self.assertEqual(self.history[2].pipeline, 'gate')
2233 self.assertEqual(self.history[3].pipeline, 'gate')
2234 self.assertEqual(self.history[4].pipeline, 'check')
2235 self.assertEqual(self.history[5].pipeline, 'check')
2236
Clark Boylana5edbe42014-06-03 16:39:10 -07002237 def test_json_status(self):
James E. Blair1843a552013-07-03 14:19:52 -07002238 "Test that we can retrieve JSON status info"
2239 self.worker.hold_jobs_in_build = True
2240 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2241 A.addApproval('CRVW', 2)
2242 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2243 self.waitUntilSettled()
2244
2245 port = self.webapp.server.socket.getsockname()[1]
2246
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002247 req = urllib2.Request("http://localhost:%s/status.json" % port)
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002248 f = urllib2.urlopen(req)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002249 headers = f.info()
2250 self.assertIn('Content-Length', headers)
2251 self.assertIn('Content-Type', headers)
2252 self.assertEqual(headers['Content-Type'],
2253 'application/json; charset=UTF-8')
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002254 self.assertIn('Access-Control-Allow-Origin', headers)
2255 self.assertIn('Cache-Control', headers)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002256 self.assertIn('Last-Modified', headers)
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002257 self.assertIn('Expires', headers)
James E. Blair1843a552013-07-03 14:19:52 -07002258 data = f.read()
2259
2260 self.worker.hold_jobs_in_build = False
2261 self.worker.release()
2262 self.waitUntilSettled()
2263
2264 data = json.loads(data)
2265 status_jobs = set()
2266 for p in data['pipelines']:
2267 for q in p['change_queues']:
James E. Blairbfb8e042014-12-30 17:01:44 -08002268 if p['name'] in ['gate', 'conflict']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002269 self.assertEqual(q['window'], 20)
2270 else:
2271 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002272 for head in q['heads']:
2273 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002274 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002275 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002276 for job in change['jobs']:
2277 status_jobs.add(job['name'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002278 self.assertIn('project-merge', status_jobs)
2279 self.assertIn('project-test1', status_jobs)
2280 self.assertIn('project-test2', status_jobs)
James E. Blair1843a552013-07-03 14:19:52 -07002281
James E. Blairc3d428e2013-12-03 15:06:48 -08002282 def test_merging_queues(self):
2283 "Test that transitively-connected change queues are merged"
James E. Blairf84026c2015-12-08 16:11:46 -08002284 self.updateConfigLayout(
2285 'tests/fixtures/layout-merge-queues.yaml')
James E. Blairc3d428e2013-12-03 15:06:48 -08002286 self.sched.reconfigure(self.config)
2287 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2288
James E. Blairaf17a972016-02-03 15:07:18 -08002289 def test_mutex(self):
2290 "Test job mutexes"
2291 self.config.set('zuul', 'layout_config',
2292 'tests/fixtures/layout-mutex.yaml')
2293 self.sched.reconfigure(self.config)
2294
2295 self.worker.hold_jobs_in_build = True
2296 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2297 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2298 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2299
2300 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2301 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2302 self.waitUntilSettled()
2303 self.assertEqual(len(self.builds), 3)
2304 self.assertEqual(self.builds[0].name, 'project-test1')
2305 self.assertEqual(self.builds[1].name, 'mutex-one')
2306 self.assertEqual(self.builds[2].name, 'project-test1')
2307
2308 self.worker.release('mutex-one')
2309 self.waitUntilSettled()
2310
2311 self.assertEqual(len(self.builds), 3)
2312 self.assertEqual(self.builds[0].name, 'project-test1')
2313 self.assertEqual(self.builds[1].name, 'project-test1')
2314 self.assertEqual(self.builds[2].name, 'mutex-two')
2315 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2316
2317 self.worker.release('mutex-two')
2318 self.waitUntilSettled()
2319
2320 self.assertEqual(len(self.builds), 3)
2321 self.assertEqual(self.builds[0].name, 'project-test1')
2322 self.assertEqual(self.builds[1].name, 'project-test1')
2323 self.assertEqual(self.builds[2].name, 'mutex-one')
2324 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2325
2326 self.worker.release('mutex-one')
2327 self.waitUntilSettled()
2328
2329 self.assertEqual(len(self.builds), 3)
2330 self.assertEqual(self.builds[0].name, 'project-test1')
2331 self.assertEqual(self.builds[1].name, 'project-test1')
2332 self.assertEqual(self.builds[2].name, 'mutex-two')
2333 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2334
2335 self.worker.release('mutex-two')
2336 self.waitUntilSettled()
2337
2338 self.assertEqual(len(self.builds), 2)
2339 self.assertEqual(self.builds[0].name, 'project-test1')
2340 self.assertEqual(self.builds[1].name, 'project-test1')
2341 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2342
2343 self.worker.hold_jobs_in_build = False
2344 self.worker.release()
2345
2346 self.waitUntilSettled()
2347 self.assertEqual(len(self.builds), 0)
2348
2349 self.assertEqual(A.reported, 1)
2350 self.assertEqual(B.reported, 1)
2351 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2352
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002353 def test_node_label(self):
2354 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002355 self.worker.registerFunction('build:node-project-test1:debian')
2356
2357 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2358 A.addApproval('CRVW', 2)
2359 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2360 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002361
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002362 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2363 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2364 'debian')
2365 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002366
2367 def test_live_reconfiguration(self):
2368 "Test that live reconfiguration works"
2369 self.worker.hold_jobs_in_build = True
2370 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2371 A.addApproval('CRVW', 2)
2372 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2373 self.waitUntilSettled()
2374
2375 self.sched.reconfigure(self.config)
2376
2377 self.worker.hold_jobs_in_build = False
2378 self.worker.release()
2379 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002380 self.assertEqual(self.getJobFromHistory('project-merge').result,
2381 'SUCCESS')
2382 self.assertEqual(self.getJobFromHistory('project-test1').result,
2383 'SUCCESS')
2384 self.assertEqual(self.getJobFromHistory('project-test2').result,
2385 'SUCCESS')
2386 self.assertEqual(A.data['status'], 'MERGED')
2387 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002388
James E. Blair6bc782d2015-07-17 16:20:21 -07002389 def test_live_reconfiguration_merge_conflict(self):
2390 # A real-world bug: a change in a gate queue has a merge
2391 # conflict and a job is added to its project while it's
2392 # sitting in the queue. The job gets added to the change and
2393 # enqueued and the change gets stuck.
2394 self.worker.registerFunction('build:project-test3')
2395 self.worker.hold_jobs_in_build = True
2396
2397 # This change is fine. It's here to stop the queue long
2398 # enough for the next change to be subject to the
2399 # reconfiguration, as well as to provide a conflict for the
2400 # next change. This change will succeed and merge.
2401 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2402 A.addPatchset(['conflict'])
2403 A.addApproval('CRVW', 2)
James E. Blair6bc782d2015-07-17 16:20:21 -07002404
2405 # This change will be in merge conflict. During the
2406 # reconfiguration, we will add a job. We want to make sure
2407 # that doesn't cause it to get stuck.
2408 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2409 B.addPatchset(['conflict'])
2410 B.addApproval('CRVW', 2)
James E. Blair4eb21fa2015-07-27 14:56:47 -07002411
2412 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
James E. Blair6bc782d2015-07-17 16:20:21 -07002413 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2414
2415 self.waitUntilSettled()
2416
2417 # No jobs have run yet
2418 self.assertEqual(A.data['status'], 'NEW')
2419 self.assertEqual(A.reported, 1)
2420 self.assertEqual(B.data['status'], 'NEW')
2421 self.assertEqual(B.reported, 1)
2422 self.assertEqual(len(self.history), 0)
2423
2424 # Add the "project-test3" job.
James E. Blairf84026c2015-12-08 16:11:46 -08002425 self.updateConfigLayout(
2426 'tests/fixtures/layout-live-reconfiguration-add-job.yaml')
James E. Blair6bc782d2015-07-17 16:20:21 -07002427 self.sched.reconfigure(self.config)
2428 self.waitUntilSettled()
2429
2430 self.worker.hold_jobs_in_build = False
2431 self.worker.release()
2432 self.waitUntilSettled()
2433
2434 self.assertEqual(A.data['status'], 'MERGED')
2435 self.assertEqual(A.reported, 2)
2436 self.assertEqual(B.data['status'], 'NEW')
2437 self.assertEqual(B.reported, 2)
2438 self.assertEqual(self.getJobFromHistory('project-merge').result,
2439 'SUCCESS')
2440 self.assertEqual(self.getJobFromHistory('project-test1').result,
2441 'SUCCESS')
2442 self.assertEqual(self.getJobFromHistory('project-test2').result,
2443 'SUCCESS')
2444 self.assertEqual(self.getJobFromHistory('project-test3').result,
2445 'SUCCESS')
2446 self.assertEqual(len(self.history), 4)
2447
James E. Blair400e8fd2015-07-30 17:44:45 -07002448 def test_live_reconfiguration_failed_root(self):
James E. Blair6bc782d2015-07-17 16:20:21 -07002449 # An extrapolation of test_live_reconfiguration_merge_conflict
2450 # that tests a job added to a job tree with a failed root does
2451 # not run.
2452 self.worker.registerFunction('build:project-test3')
2453 self.worker.hold_jobs_in_build = True
2454
2455 # This change is fine. It's here to stop the queue long
2456 # enough for the next change to be subject to the
2457 # reconfiguration. This change will succeed and merge.
2458 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2459 A.addPatchset(['conflict'])
2460 A.addApproval('CRVW', 2)
2461 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2462 self.waitUntilSettled()
2463 self.worker.release('.*-merge')
2464 self.waitUntilSettled()
2465
2466 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2467 self.worker.addFailTest('project-merge', B)
2468 B.addApproval('CRVW', 2)
2469 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2470 self.waitUntilSettled()
2471
2472 self.worker.release('.*-merge')
2473 self.waitUntilSettled()
2474
2475 # Both -merge jobs have run, but no others.
2476 self.assertEqual(A.data['status'], 'NEW')
2477 self.assertEqual(A.reported, 1)
2478 self.assertEqual(B.data['status'], 'NEW')
2479 self.assertEqual(B.reported, 1)
2480 self.assertEqual(self.history[0].result, 'SUCCESS')
2481 self.assertEqual(self.history[0].name, 'project-merge')
2482 self.assertEqual(self.history[1].result, 'FAILURE')
2483 self.assertEqual(self.history[1].name, 'project-merge')
2484 self.assertEqual(len(self.history), 2)
2485
2486 # Add the "project-test3" job.
James E. Blairf84026c2015-12-08 16:11:46 -08002487 self.updateConfigLayout(
2488 'tests/fixtures/layout-live-reconfiguration-add-job.yaml')
James E. Blair6bc782d2015-07-17 16:20:21 -07002489 self.sched.reconfigure(self.config)
2490 self.waitUntilSettled()
2491
2492 self.worker.hold_jobs_in_build = False
2493 self.worker.release()
2494 self.waitUntilSettled()
2495
2496 self.assertEqual(A.data['status'], 'MERGED')
2497 self.assertEqual(A.reported, 2)
2498 self.assertEqual(B.data['status'], 'NEW')
2499 self.assertEqual(B.reported, 2)
2500 self.assertEqual(self.history[0].result, 'SUCCESS')
2501 self.assertEqual(self.history[0].name, 'project-merge')
2502 self.assertEqual(self.history[1].result, 'FAILURE')
2503 self.assertEqual(self.history[1].name, 'project-merge')
2504 self.assertEqual(self.history[2].result, 'SUCCESS')
2505 self.assertEqual(self.history[3].result, 'SUCCESS')
2506 self.assertEqual(self.history[4].result, 'SUCCESS')
2507 self.assertEqual(len(self.history), 5)
2508
James E. Blair400e8fd2015-07-30 17:44:45 -07002509 def test_live_reconfiguration_failed_job(self):
2510 # Test that a change with a removed failing job does not
2511 # disrupt reconfiguration. If a change has a failed job and
2512 # that job is removed during a reconfiguration, we observed a
2513 # bug where the code to re-set build statuses would run on
2514 # that build and raise an exception because the job no longer
2515 # existed.
2516 self.worker.hold_jobs_in_build = True
2517
2518 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2519
2520 # This change will fail and later be removed by the reconfiguration.
2521 self.worker.addFailTest('project-test1', A)
2522
2523 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2524 self.waitUntilSettled()
2525 self.worker.release('.*-merge')
2526 self.waitUntilSettled()
2527 self.worker.release('project-test1')
2528 self.waitUntilSettled()
2529
2530 self.assertEqual(A.data['status'], 'NEW')
2531 self.assertEqual(A.reported, 0)
2532
2533 self.assertEqual(self.getJobFromHistory('project-merge').result,
2534 'SUCCESS')
2535 self.assertEqual(self.getJobFromHistory('project-test1').result,
2536 'FAILURE')
2537 self.assertEqual(len(self.history), 2)
2538
2539 # Remove the test1 job.
James E. Blairf84026c2015-12-08 16:11:46 -08002540 self.updateConfigLayout(
2541 'tests/fixtures/layout-live-reconfiguration-failed-job.yaml')
James E. Blair400e8fd2015-07-30 17:44:45 -07002542 self.sched.reconfigure(self.config)
2543 self.waitUntilSettled()
2544
2545 self.worker.hold_jobs_in_build = False
2546 self.worker.release()
2547 self.waitUntilSettled()
2548
2549 self.assertEqual(self.getJobFromHistory('project-test2').result,
2550 'SUCCESS')
2551 self.assertEqual(self.getJobFromHistory('project-testfile').result,
2552 'SUCCESS')
2553 self.assertEqual(len(self.history), 4)
2554
2555 self.assertEqual(A.data['status'], 'NEW')
2556 self.assertEqual(A.reported, 1)
2557 self.assertIn('Build succeeded', A.messages[0])
2558 # Ensure the removed job was not included in the report.
2559 self.assertNotIn('project-test1', A.messages[0])
2560
James E. Blairfe707d12015-08-05 15:18:15 -07002561 def test_live_reconfiguration_shared_queue(self):
2562 # Test that a change with a failing job which was removed from
2563 # this project but otherwise still exists in the system does
2564 # not disrupt reconfiguration.
2565
2566 self.worker.hold_jobs_in_build = True
2567
2568 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2569
2570 self.worker.addFailTest('project1-project2-integration', A)
2571
2572 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2573 self.waitUntilSettled()
2574 self.worker.release('.*-merge')
2575 self.waitUntilSettled()
2576 self.worker.release('project1-project2-integration')
2577 self.waitUntilSettled()
2578
2579 self.assertEqual(A.data['status'], 'NEW')
2580 self.assertEqual(A.reported, 0)
2581
2582 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2583 'SUCCESS')
2584 self.assertEqual(self.getJobFromHistory(
2585 'project1-project2-integration').result, 'FAILURE')
2586 self.assertEqual(len(self.history), 2)
2587
2588 # Remove the integration job.
James E. Blairf84026c2015-12-08 16:11:46 -08002589 self.updateConfigLayout(
2590 'tests/fixtures/layout-live-reconfiguration-shared-queue.yaml')
James E. Blairfe707d12015-08-05 15:18:15 -07002591 self.sched.reconfigure(self.config)
2592 self.waitUntilSettled()
2593
2594 self.worker.hold_jobs_in_build = False
2595 self.worker.release()
2596 self.waitUntilSettled()
2597
2598 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2599 'SUCCESS')
2600 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2601 'SUCCESS')
2602 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2603 'SUCCESS')
2604 self.assertEqual(self.getJobFromHistory(
2605 'project1-project2-integration').result, 'FAILURE')
2606 self.assertEqual(len(self.history), 4)
2607
2608 self.assertEqual(A.data['status'], 'NEW')
2609 self.assertEqual(A.reported, 1)
2610 self.assertIn('Build succeeded', A.messages[0])
2611 # Ensure the removed job was not included in the report.
2612 self.assertNotIn('project1-project2-integration', A.messages[0])
2613
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002614 def test_live_reconfiguration_del_project(self):
2615 # Test project deletion from layout
2616 # while changes are enqueued
2617
2618 self.worker.hold_jobs_in_build = True
2619 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2620 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2621 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2622
2623 # A Depends-On: B
2624 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2625 A.subject, B.data['id'])
2626 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2627
2628 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2629 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2630 self.waitUntilSettled()
2631 self.worker.release('.*-merge')
2632 self.waitUntilSettled()
2633 self.assertEqual(len(self.builds), 5)
2634
2635 # This layout defines only org/project, not org/project1
James E. Blairf84026c2015-12-08 16:11:46 -08002636 self.updateConfigLayout(
2637 'tests/fixtures/layout-live-reconfiguration-del-project.yaml')
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002638 self.sched.reconfigure(self.config)
2639 self.waitUntilSettled()
2640
2641 # Builds for C aborted, builds for A succeed,
2642 # and have change B applied ahead
2643 job_c = self.getJobFromHistory('project1-test1')
2644 self.assertEqual(job_c.changes, '3,1')
2645 self.assertEqual(job_c.result, 'ABORTED')
2646
2647 self.worker.hold_jobs_in_build = False
2648 self.worker.release()
2649 self.waitUntilSettled()
2650
2651 self.assertEqual(self.getJobFromHistory('project-test1').changes,
2652 '2,1 1,1')
2653
2654 self.assertEqual(A.data['status'], 'NEW')
2655 self.assertEqual(B.data['status'], 'NEW')
2656 self.assertEqual(C.data['status'], 'NEW')
2657 self.assertEqual(A.reported, 1)
2658 self.assertEqual(B.reported, 0)
2659 self.assertEqual(C.reported, 0)
2660
2661 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
2662 self.assertIn('Build succeeded', A.messages[0])
2663
James E. Blaire712d9f2013-07-31 11:40:11 -07002664 def test_live_reconfiguration_functions(self):
2665 "Test live reconfiguration with a custom function"
2666 self.worker.registerFunction('build:node-project-test1:debian')
2667 self.worker.registerFunction('build:node-project-test1:wheezy')
2668 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2669 A.addApproval('CRVW', 2)
2670 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2671 self.waitUntilSettled()
2672
2673 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2674 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2675 'debian')
2676 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2677
James E. Blairf84026c2015-12-08 16:11:46 -08002678 self.updateConfigLayout(
2679 'tests/fixtures/layout-live-reconfiguration-functions.yaml')
James E. Blaire712d9f2013-07-31 11:40:11 -07002680 self.sched.reconfigure(self.config)
2681 self.worker.build_history = []
2682
2683 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2684 B.addApproval('CRVW', 2)
2685 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2686 self.waitUntilSettled()
2687
2688 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2689 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2690 'wheezy')
2691 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2692
James E. Blair287c06d2013-07-24 10:39:30 -07002693 def test_delayed_repo_init(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002694 self.updateConfigLayout(
2695 'tests/fixtures/layout-delayed-repo-init.yaml')
James E. Blair287c06d2013-07-24 10:39:30 -07002696 self.sched.reconfigure(self.config)
2697
2698 self.init_repo("org/new-project")
2699 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2700
2701 A.addApproval('CRVW', 2)
2702 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2703 self.waitUntilSettled()
2704 self.assertEqual(self.getJobFromHistory('project-merge').result,
2705 'SUCCESS')
2706 self.assertEqual(self.getJobFromHistory('project-test1').result,
2707 'SUCCESS')
2708 self.assertEqual(self.getJobFromHistory('project-test2').result,
2709 'SUCCESS')
2710 self.assertEqual(A.data['status'], 'MERGED')
2711 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002712
Clark Boylan6dbbc482013-10-18 10:57:31 -07002713 def test_repo_deleted(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002714 self.updateConfigLayout(
2715 'tests/fixtures/layout-repo-deleted.yaml')
Clark Boylan6dbbc482013-10-18 10:57:31 -07002716 self.sched.reconfigure(self.config)
2717
2718 self.init_repo("org/delete-project")
2719 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2720
2721 A.addApproval('CRVW', 2)
2722 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2723 self.waitUntilSettled()
2724 self.assertEqual(self.getJobFromHistory('project-merge').result,
2725 'SUCCESS')
2726 self.assertEqual(self.getJobFromHistory('project-test1').result,
2727 'SUCCESS')
2728 self.assertEqual(self.getJobFromHistory('project-test2').result,
2729 'SUCCESS')
2730 self.assertEqual(A.data['status'], 'MERGED')
2731 self.assertEqual(A.reported, 2)
2732
2733 # Delete org/new-project zuul repo. Should be recloned.
2734 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2735
2736 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2737
2738 B.addApproval('CRVW', 2)
2739 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2740 self.waitUntilSettled()
2741 self.assertEqual(self.getJobFromHistory('project-merge').result,
2742 'SUCCESS')
2743 self.assertEqual(self.getJobFromHistory('project-test1').result,
2744 'SUCCESS')
2745 self.assertEqual(self.getJobFromHistory('project-test2').result,
2746 'SUCCESS')
2747 self.assertEqual(B.data['status'], 'MERGED')
2748 self.assertEqual(B.reported, 2)
2749
James E. Blair63bb0ef2013-07-29 17:14:51 -07002750 def test_timer(self):
2751 "Test that a periodic job is triggered"
2752 self.worker.hold_jobs_in_build = True
James E. Blairf84026c2015-12-08 16:11:46 -08002753 self.updateConfigLayout(
2754 'tests/fixtures/layout-timer.yaml')
James E. Blair63bb0ef2013-07-29 17:14:51 -07002755 self.sched.reconfigure(self.config)
2756 self.registerJobs()
2757
Clark Boylan3ee090a2014-04-03 20:55:09 -07002758 # The pipeline triggers every second, so we should have seen
2759 # several by now.
2760 time.sleep(5)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002761 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002762
2763 self.assertEqual(len(self.builds), 2)
2764
James E. Blair63bb0ef2013-07-29 17:14:51 -07002765 port = self.webapp.server.socket.getsockname()[1]
2766
2767 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2768 data = f.read()
2769
2770 self.worker.hold_jobs_in_build = False
Clark Boylan3ee090a2014-04-03 20:55:09 -07002771 # Stop queuing timer triggered jobs so that the assertions
2772 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08002773 self.updateConfigLayout(
2774 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002775 self.sched.reconfigure(self.config)
2776 self.registerJobs()
James E. Blair63bb0ef2013-07-29 17:14:51 -07002777 self.worker.release()
2778 self.waitUntilSettled()
2779
2780 self.assertEqual(self.getJobFromHistory(
2781 'project-bitrot-stable-old').result, 'SUCCESS')
2782 self.assertEqual(self.getJobFromHistory(
2783 'project-bitrot-stable-older').result, 'SUCCESS')
2784
2785 data = json.loads(data)
2786 status_jobs = set()
2787 for p in data['pipelines']:
2788 for q in p['change_queues']:
2789 for head in q['heads']:
2790 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07002791 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002792 for job in change['jobs']:
2793 status_jobs.add(job['name'])
2794 self.assertIn('project-bitrot-stable-old', status_jobs)
2795 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002796
James E. Blair4f6033c2014-03-27 15:49:09 -07002797 def test_idle(self):
2798 "Test that frequent periodic jobs work"
2799 self.worker.hold_jobs_in_build = True
James E. Blair4f6033c2014-03-27 15:49:09 -07002800
Clark Boylan3ee090a2014-04-03 20:55:09 -07002801 for x in range(1, 3):
2802 # Test that timer triggers periodic jobs even across
2803 # layout config reloads.
2804 # Start timer trigger
James E. Blairf84026c2015-12-08 16:11:46 -08002805 self.updateConfigLayout(
2806 'tests/fixtures/layout-idle.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002807 self.sched.reconfigure(self.config)
2808 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002809 self.waitUntilSettled()
James E. Blair4f6033c2014-03-27 15:49:09 -07002810
Clark Boylan3ee090a2014-04-03 20:55:09 -07002811 # The pipeline triggers every second, so we should have seen
2812 # several by now.
2813 time.sleep(5)
Clark Boylan3ee090a2014-04-03 20:55:09 -07002814
2815 # Stop queuing timer triggered jobs so that the assertions
2816 # below don't race against more jobs being queued.
James E. Blairf84026c2015-12-08 16:11:46 -08002817 self.updateConfigLayout(
2818 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002819 self.sched.reconfigure(self.config)
2820 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002821 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002822
2823 self.assertEqual(len(self.builds), 2)
2824 self.worker.release('.*')
2825 self.waitUntilSettled()
2826 self.assertEqual(len(self.builds), 0)
2827 self.assertEqual(len(self.history), x * 2)
James E. Blair4f6033c2014-03-27 15:49:09 -07002828
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002829 def test_check_smtp_pool(self):
James E. Blairf84026c2015-12-08 16:11:46 -08002830 self.updateConfigLayout(
2831 'tests/fixtures/layout-smtp.yaml')
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002832 self.sched.reconfigure(self.config)
2833
2834 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2835 self.waitUntilSettled()
2836
2837 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2838 self.waitUntilSettled()
2839
James E. Blairff80a2f2013-12-27 13:24:06 -08002840 self.assertEqual(len(self.smtp_messages), 2)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002841
2842 # A.messages only holds what FakeGerrit places in it. Thus we
2843 # work on the knowledge of what the first message should be as
2844 # it is only configured to go to SMTP.
2845
2846 self.assertEqual('zuul@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002847 self.smtp_messages[0]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002848 self.assertEqual(['you@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002849 self.smtp_messages[0]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002850 self.assertEqual('Starting check jobs.',
James E. Blairff80a2f2013-12-27 13:24:06 -08002851 self.smtp_messages[0]['body'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002852
2853 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002854 self.smtp_messages[1]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002855 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002856 self.smtp_messages[1]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002857 self.assertEqual(A.messages[0],
James E. Blairff80a2f2013-12-27 13:24:06 -08002858 self.smtp_messages[1]['body'])
James E. Blairad28e912013-11-27 10:43:22 -08002859
James E. Blaire5910202013-12-27 09:50:31 -08002860 def test_timer_smtp(self):
2861 "Test that a periodic job is triggered"
Clark Boylan3ee090a2014-04-03 20:55:09 -07002862 self.worker.hold_jobs_in_build = True
James E. Blairf84026c2015-12-08 16:11:46 -08002863 self.updateConfigLayout(
2864 'tests/fixtures/layout-timer-smtp.yaml')
James E. Blaire5910202013-12-27 09:50:31 -08002865 self.sched.reconfigure(self.config)
2866 self.registerJobs()
2867
Clark Boylan3ee090a2014-04-03 20:55:09 -07002868 # The pipeline triggers every second, so we should have seen
2869 # several by now.
2870 time.sleep(5)
James E. Blaire5910202013-12-27 09:50:31 -08002871 self.waitUntilSettled()
2872
Clark Boylan3ee090a2014-04-03 20:55:09 -07002873 self.assertEqual(len(self.builds), 2)
2874 self.worker.release('.*')
2875 self.waitUntilSettled()
2876 self.assertEqual(len(self.history), 2)
2877
James E. Blaire5910202013-12-27 09:50:31 -08002878 self.assertEqual(self.getJobFromHistory(
2879 'project-bitrot-stable-old').result, 'SUCCESS')
2880 self.assertEqual(self.getJobFromHistory(
2881 'project-bitrot-stable-older').result, 'SUCCESS')
2882
James E. Blairff80a2f2013-12-27 13:24:06 -08002883 self.assertEqual(len(self.smtp_messages), 1)
James E. Blaire5910202013-12-27 09:50:31 -08002884
2885 # A.messages only holds what FakeGerrit places in it. Thus we
2886 # work on the knowledge of what the first message should be as
2887 # it is only configured to go to SMTP.
2888
2889 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002890 self.smtp_messages[0]['from_email'])
James E. Blaire5910202013-12-27 09:50:31 -08002891 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002892 self.smtp_messages[0]['to_email'])
James E. Blaire5910202013-12-27 09:50:31 -08002893 self.assertIn('Subject: Periodic check for org/project succeeded',
James E. Blairff80a2f2013-12-27 13:24:06 -08002894 self.smtp_messages[0]['headers'])
James E. Blaire5910202013-12-27 09:50:31 -08002895
Clark Boylan3ee090a2014-04-03 20:55:09 -07002896 # Stop queuing timer triggered jobs and let any that may have
2897 # queued through so that end of test assertions pass.
James E. Blairf84026c2015-12-08 16:11:46 -08002898 self.updateConfigLayout(
2899 'tests/fixtures/layout-no-timer.yaml')
Clark Boylan3ee090a2014-04-03 20:55:09 -07002900 self.sched.reconfigure(self.config)
2901 self.registerJobs()
James E. Blairf8058972014-08-15 16:09:16 -07002902 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002903 self.worker.release('.*')
2904 self.waitUntilSettled()
2905
James E. Blair91e34592015-07-31 16:45:59 -07002906 def test_client_enqueue_change(self):
James E. Blairad28e912013-11-27 10:43:22 -08002907 "Test that the RPC client can enqueue a change"
2908 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2909 A.addApproval('CRVW', 2)
2910 A.addApproval('APRV', 1)
2911
2912 client = zuul.rpcclient.RPCClient('127.0.0.1',
2913 self.gearman_server.port)
2914 r = client.enqueue(pipeline='gate',
2915 project='org/project',
2916 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08002917 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08002918 self.waitUntilSettled()
2919 self.assertEqual(self.getJobFromHistory('project-merge').result,
2920 'SUCCESS')
2921 self.assertEqual(self.getJobFromHistory('project-test1').result,
2922 'SUCCESS')
2923 self.assertEqual(self.getJobFromHistory('project-test2').result,
2924 'SUCCESS')
2925 self.assertEqual(A.data['status'], 'MERGED')
2926 self.assertEqual(A.reported, 2)
2927 self.assertEqual(r, True)
2928
James E. Blair91e34592015-07-31 16:45:59 -07002929 def test_client_enqueue_ref(self):
2930 "Test that the RPC client can enqueue a ref"
2931
2932 client = zuul.rpcclient.RPCClient('127.0.0.1',
2933 self.gearman_server.port)
2934 r = client.enqueue_ref(
2935 pipeline='post',
2936 project='org/project',
2937 trigger='gerrit',
2938 ref='master',
2939 oldrev='90f173846e3af9154517b88543ffbd1691f31366',
2940 newrev='d479a0bfcb34da57a31adb2a595c0cf687812543')
2941 self.waitUntilSettled()
2942 job_names = [x.name for x in self.history]
2943 self.assertEqual(len(self.history), 1)
2944 self.assertIn('project-post', job_names)
2945 self.assertEqual(r, True)
2946
James E. Blairad28e912013-11-27 10:43:22 -08002947 def test_client_enqueue_negative(self):
2948 "Test that the RPC client returns errors"
2949 client = zuul.rpcclient.RPCClient('127.0.0.1',
2950 self.gearman_server.port)
2951 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
2952 "Invalid project"):
2953 r = client.enqueue(pipeline='gate',
2954 project='project-does-not-exist',
2955 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08002956 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08002957 client.shutdown()
2958 self.assertEqual(r, False)
2959
2960 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
2961 "Invalid pipeline"):
2962 r = client.enqueue(pipeline='pipeline-does-not-exist',
2963 project='org/project',
2964 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08002965 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08002966 client.shutdown()
2967 self.assertEqual(r, False)
2968
2969 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
2970 "Invalid trigger"):
2971 r = client.enqueue(pipeline='gate',
2972 project='org/project',
2973 trigger='trigger-does-not-exist',
James E. Blair36658cf2013-12-06 17:53:48 -08002974 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08002975 client.shutdown()
2976 self.assertEqual(r, False)
2977
2978 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
2979 "Invalid change"):
2980 r = client.enqueue(pipeline='gate',
2981 project='org/project',
2982 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08002983 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08002984 client.shutdown()
2985 self.assertEqual(r, False)
2986
2987 self.waitUntilSettled()
2988 self.assertEqual(len(self.history), 0)
2989 self.assertEqual(len(self.builds), 0)
James E. Blair36658cf2013-12-06 17:53:48 -08002990
2991 def test_client_promote(self):
2992 "Test that the RPC client can promote a change"
2993 self.worker.hold_jobs_in_build = True
2994 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2995 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2996 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
2997 A.addApproval('CRVW', 2)
2998 B.addApproval('CRVW', 2)
2999 C.addApproval('CRVW', 2)
3000
3001 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3002 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3003 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3004
3005 self.waitUntilSettled()
3006
Sean Daguef39b9ca2014-01-10 21:34:35 -05003007 items = self.sched.layout.pipelines['gate'].getAllItems()
3008 enqueue_times = {}
3009 for item in items:
3010 enqueue_times[str(item.change)] = item.enqueue_time
3011
James E. Blair36658cf2013-12-06 17:53:48 -08003012 client = zuul.rpcclient.RPCClient('127.0.0.1',
3013 self.gearman_server.port)
3014 r = client.promote(pipeline='gate',
3015 change_ids=['2,1', '3,1'])
3016
Sean Daguef39b9ca2014-01-10 21:34:35 -05003017 # ensure that enqueue times are durable
3018 items = self.sched.layout.pipelines['gate'].getAllItems()
3019 for item in items:
3020 self.assertEqual(
3021 enqueue_times[str(item.change)], item.enqueue_time)
3022
James E. Blair78acec92014-02-06 07:11:32 -08003023 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003024 self.worker.release('.*-merge')
3025 self.waitUntilSettled()
3026 self.worker.release('.*-merge')
3027 self.waitUntilSettled()
3028 self.worker.release('.*-merge')
3029 self.waitUntilSettled()
3030
3031 self.assertEqual(len(self.builds), 6)
3032 self.assertEqual(self.builds[0].name, 'project-test1')
3033 self.assertEqual(self.builds[1].name, 'project-test2')
3034 self.assertEqual(self.builds[2].name, 'project-test1')
3035 self.assertEqual(self.builds[3].name, 'project-test2')
3036 self.assertEqual(self.builds[4].name, 'project-test1')
3037 self.assertEqual(self.builds[5].name, 'project-test2')
3038
3039 self.assertTrue(self.job_has_changes(self.builds[0], B))
3040 self.assertFalse(self.job_has_changes(self.builds[0], A))
3041 self.assertFalse(self.job_has_changes(self.builds[0], C))
3042
3043 self.assertTrue(self.job_has_changes(self.builds[2], B))
3044 self.assertTrue(self.job_has_changes(self.builds[2], C))
3045 self.assertFalse(self.job_has_changes(self.builds[2], A))
3046
3047 self.assertTrue(self.job_has_changes(self.builds[4], B))
3048 self.assertTrue(self.job_has_changes(self.builds[4], C))
3049 self.assertTrue(self.job_has_changes(self.builds[4], A))
3050
3051 self.worker.release()
3052 self.waitUntilSettled()
3053
3054 self.assertEqual(A.data['status'], 'MERGED')
3055 self.assertEqual(A.reported, 2)
3056 self.assertEqual(B.data['status'], 'MERGED')
3057 self.assertEqual(B.reported, 2)
3058 self.assertEqual(C.data['status'], 'MERGED')
3059 self.assertEqual(C.reported, 2)
3060
3061 client.shutdown()
3062 self.assertEqual(r, True)
3063
3064 def test_client_promote_dependent(self):
3065 "Test that the RPC client can promote a dependent change"
3066 # C (depends on B) -> B -> A ; then promote C to get:
3067 # A -> C (depends on B) -> B
3068 self.worker.hold_jobs_in_build = True
3069 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3070 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3071 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3072
3073 C.setDependsOn(B, 1)
3074
3075 A.addApproval('CRVW', 2)
3076 B.addApproval('CRVW', 2)
3077 C.addApproval('CRVW', 2)
3078
3079 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3080 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3081 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3082
3083 self.waitUntilSettled()
3084
3085 client = zuul.rpcclient.RPCClient('127.0.0.1',
3086 self.gearman_server.port)
3087 r = client.promote(pipeline='gate',
3088 change_ids=['3,1'])
3089
James E. Blair78acec92014-02-06 07:11:32 -08003090 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003091 self.worker.release('.*-merge')
3092 self.waitUntilSettled()
3093 self.worker.release('.*-merge')
3094 self.waitUntilSettled()
3095 self.worker.release('.*-merge')
3096 self.waitUntilSettled()
3097
3098 self.assertEqual(len(self.builds), 6)
3099 self.assertEqual(self.builds[0].name, 'project-test1')
3100 self.assertEqual(self.builds[1].name, 'project-test2')
3101 self.assertEqual(self.builds[2].name, 'project-test1')
3102 self.assertEqual(self.builds[3].name, 'project-test2')
3103 self.assertEqual(self.builds[4].name, 'project-test1')
3104 self.assertEqual(self.builds[5].name, 'project-test2')
3105
3106 self.assertTrue(self.job_has_changes(self.builds[0], B))
3107 self.assertFalse(self.job_has_changes(self.builds[0], A))
3108 self.assertFalse(self.job_has_changes(self.builds[0], C))
3109
3110 self.assertTrue(self.job_has_changes(self.builds[2], B))
3111 self.assertTrue(self.job_has_changes(self.builds[2], C))
3112 self.assertFalse(self.job_has_changes(self.builds[2], A))
3113
3114 self.assertTrue(self.job_has_changes(self.builds[4], B))
3115 self.assertTrue(self.job_has_changes(self.builds[4], C))
3116 self.assertTrue(self.job_has_changes(self.builds[4], A))
3117
3118 self.worker.release()
3119 self.waitUntilSettled()
3120
3121 self.assertEqual(A.data['status'], 'MERGED')
3122 self.assertEqual(A.reported, 2)
3123 self.assertEqual(B.data['status'], 'MERGED')
3124 self.assertEqual(B.reported, 2)
3125 self.assertEqual(C.data['status'], 'MERGED')
3126 self.assertEqual(C.reported, 2)
3127
3128 client.shutdown()
3129 self.assertEqual(r, True)
3130
3131 def test_client_promote_negative(self):
3132 "Test that the RPC client returns errors for promotion"
3133 self.worker.hold_jobs_in_build = True
3134 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3135 A.addApproval('CRVW', 2)
3136 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3137 self.waitUntilSettled()
3138
3139 client = zuul.rpcclient.RPCClient('127.0.0.1',
3140 self.gearman_server.port)
3141
3142 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3143 r = client.promote(pipeline='nonexistent',
3144 change_ids=['2,1', '3,1'])
3145 client.shutdown()
3146 self.assertEqual(r, False)
3147
3148 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3149 r = client.promote(pipeline='gate',
3150 change_ids=['4,1'])
3151 client.shutdown()
3152 self.assertEqual(r, False)
3153
3154 self.worker.hold_jobs_in_build = False
3155 self.worker.release()
3156 self.waitUntilSettled()
Clark Boylan7603a372014-01-21 11:43:20 -08003157
3158 def test_queue_rate_limiting(self):
3159 "Test that DependentPipelines are rate limited with dep across window"
James E. Blairf84026c2015-12-08 16:11:46 -08003160 self.updateConfigLayout(
3161 'tests/fixtures/layout-rate-limit.yaml')
Clark Boylan7603a372014-01-21 11:43:20 -08003162 self.sched.reconfigure(self.config)
3163 self.worker.hold_jobs_in_build = True
3164 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3165 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3166 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3167
3168 C.setDependsOn(B, 1)
3169 self.worker.addFailTest('project-test1', A)
3170
3171 A.addApproval('CRVW', 2)
3172 B.addApproval('CRVW', 2)
3173 C.addApproval('CRVW', 2)
3174
3175 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3176 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3177 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3178 self.waitUntilSettled()
3179
3180 # Only A and B will have their merge jobs queued because
3181 # window is 2.
3182 self.assertEqual(len(self.builds), 2)
3183 self.assertEqual(self.builds[0].name, 'project-merge')
3184 self.assertEqual(self.builds[1].name, 'project-merge')
3185
3186 self.worker.release('.*-merge')
3187 self.waitUntilSettled()
3188 self.worker.release('.*-merge')
3189 self.waitUntilSettled()
3190
3191 # Only A and B will have their test jobs queued because
3192 # window is 2.
3193 self.assertEqual(len(self.builds), 4)
3194 self.assertEqual(self.builds[0].name, 'project-test1')
3195 self.assertEqual(self.builds[1].name, 'project-test2')
3196 self.assertEqual(self.builds[2].name, 'project-test1')
3197 self.assertEqual(self.builds[3].name, 'project-test2')
3198
3199 self.worker.release('project-.*')
3200 self.waitUntilSettled()
3201
3202 queue = self.sched.layout.pipelines['gate'].queues[0]
3203 # A failed so window is reduced by 1 to 1.
3204 self.assertEqual(queue.window, 1)
3205 self.assertEqual(queue.window_floor, 1)
3206 self.assertEqual(A.data['status'], 'NEW')
3207
3208 # Gate is reset and only B's merge job is queued because
3209 # window shrunk to 1.
3210 self.assertEqual(len(self.builds), 1)
3211 self.assertEqual(self.builds[0].name, 'project-merge')
3212
3213 self.worker.release('.*-merge')
3214 self.waitUntilSettled()
3215
3216 # Only B's test jobs are queued because window is still 1.
3217 self.assertEqual(len(self.builds), 2)
3218 self.assertEqual(self.builds[0].name, 'project-test1')
3219 self.assertEqual(self.builds[1].name, 'project-test2')
3220
3221 self.worker.release('project-.*')
3222 self.waitUntilSettled()
3223
3224 # B was successfully merged so window is increased to 2.
3225 self.assertEqual(queue.window, 2)
3226 self.assertEqual(queue.window_floor, 1)
3227 self.assertEqual(B.data['status'], 'MERGED')
3228
3229 # Only C is left and its merge job is queued.
3230 self.assertEqual(len(self.builds), 1)
3231 self.assertEqual(self.builds[0].name, 'project-merge')
3232
3233 self.worker.release('.*-merge')
3234 self.waitUntilSettled()
3235
3236 # After successful merge job the test jobs for C are queued.
3237 self.assertEqual(len(self.builds), 2)
3238 self.assertEqual(self.builds[0].name, 'project-test1')
3239 self.assertEqual(self.builds[1].name, 'project-test2')
3240
3241 self.worker.release('project-.*')
3242 self.waitUntilSettled()
3243
3244 # C successfully merged so window is bumped to 3.
3245 self.assertEqual(queue.window, 3)
3246 self.assertEqual(queue.window_floor, 1)
3247 self.assertEqual(C.data['status'], 'MERGED')
3248
3249 def test_queue_rate_limiting_dependent(self):
3250 "Test that DependentPipelines are rate limited with dep in window"
James E. Blairf84026c2015-12-08 16:11:46 -08003251 self.updateConfigLayout(
3252 'tests/fixtures/layout-rate-limit.yaml')
Clark Boylan7603a372014-01-21 11:43:20 -08003253 self.sched.reconfigure(self.config)
3254 self.worker.hold_jobs_in_build = True
3255 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3256 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3257 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3258
3259 B.setDependsOn(A, 1)
3260
3261 self.worker.addFailTest('project-test1', A)
3262
3263 A.addApproval('CRVW', 2)
3264 B.addApproval('CRVW', 2)
3265 C.addApproval('CRVW', 2)
3266
3267 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3268 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3269 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3270 self.waitUntilSettled()
3271
3272 # Only A and B will have their merge jobs queued because
3273 # window is 2.
3274 self.assertEqual(len(self.builds), 2)
3275 self.assertEqual(self.builds[0].name, 'project-merge')
3276 self.assertEqual(self.builds[1].name, 'project-merge')
3277
3278 self.worker.release('.*-merge')
3279 self.waitUntilSettled()
3280 self.worker.release('.*-merge')
3281 self.waitUntilSettled()
3282
3283 # Only A and B will have their test jobs queued because
3284 # window is 2.
3285 self.assertEqual(len(self.builds), 4)
3286 self.assertEqual(self.builds[0].name, 'project-test1')
3287 self.assertEqual(self.builds[1].name, 'project-test2')
3288 self.assertEqual(self.builds[2].name, 'project-test1')
3289 self.assertEqual(self.builds[3].name, 'project-test2')
3290
3291 self.worker.release('project-.*')
3292 self.waitUntilSettled()
3293
3294 queue = self.sched.layout.pipelines['gate'].queues[0]
3295 # A failed so window is reduced by 1 to 1.
3296 self.assertEqual(queue.window, 1)
3297 self.assertEqual(queue.window_floor, 1)
3298 self.assertEqual(A.data['status'], 'NEW')
3299 self.assertEqual(B.data['status'], 'NEW')
3300
3301 # Gate is reset and only C's merge job is queued because
3302 # window shrunk to 1 and A and B were dequeued.
3303 self.assertEqual(len(self.builds), 1)
3304 self.assertEqual(self.builds[0].name, 'project-merge')
3305
3306 self.worker.release('.*-merge')
3307 self.waitUntilSettled()
3308
3309 # Only C's test jobs are queued because window is still 1.
3310 self.assertEqual(len(self.builds), 2)
3311 self.assertEqual(self.builds[0].name, 'project-test1')
3312 self.assertEqual(self.builds[1].name, 'project-test2')
3313
3314 self.worker.release('project-.*')
3315 self.waitUntilSettled()
3316
3317 # C was successfully merged so window is increased to 2.
3318 self.assertEqual(queue.window, 2)
3319 self.assertEqual(queue.window_floor, 1)
3320 self.assertEqual(C.data['status'], 'MERGED')
Joshua Heskethba8776a2014-01-12 14:35:40 +08003321
3322 def test_worker_update_metadata(self):
3323 "Test if a worker can send back metadata about itself"
3324 self.worker.hold_jobs_in_build = True
3325
3326 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3327 A.addApproval('CRVW', 2)
3328 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3329 self.waitUntilSettled()
3330
3331 self.assertEqual(len(self.launcher.builds), 1)
3332
3333 self.log.debug('Current builds:')
3334 self.log.debug(self.launcher.builds)
3335
3336 start = time.time()
3337 while True:
3338 if time.time() - start > 10:
3339 raise Exception("Timeout waiting for gearman server to report "
3340 + "back to the client")
3341 build = self.launcher.builds.values()[0]
3342 if build.worker.name == "My Worker":
3343 break
3344 else:
3345 time.sleep(0)
3346
3347 self.log.debug(build)
3348 self.assertEqual("My Worker", build.worker.name)
3349 self.assertEqual("localhost", build.worker.hostname)
3350 self.assertEqual(['127.0.0.1', '192.168.1.1'], build.worker.ips)
3351 self.assertEqual("zuul.example.org", build.worker.fqdn)
3352 self.assertEqual("FakeBuilder", build.worker.program)
3353 self.assertEqual("v1.1", build.worker.version)
3354 self.assertEqual({'something': 'else'}, build.worker.extra)
3355
3356 self.worker.hold_jobs_in_build = False
3357 self.worker.release()
3358 self.waitUntilSettled()
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003359
3360 def test_footer_message(self):
3361 "Test a pipeline's footer message is correctly added to the report."
James E. Blairf84026c2015-12-08 16:11:46 -08003362 self.updateConfigLayout(
3363 'tests/fixtures/layout-footer-message.yaml')
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003364 self.sched.reconfigure(self.config)
3365 self.registerJobs()
3366
3367 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3368 A.addApproval('CRVW', 2)
3369 self.worker.addFailTest('test1', A)
3370 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3371 self.waitUntilSettled()
3372
3373 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3374 B.addApproval('CRVW', 2)
3375 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3376 self.waitUntilSettled()
3377
3378 self.assertEqual(2, len(self.smtp_messages))
3379
3380 failure_body = """\
3381Build failed. For information on how to proceed, see \
3382http://wiki.example.org/Test_Failures
3383
3384- test1 http://logs.example.com/1/1/gate/test1/0 : FAILURE in 0s
3385- test2 http://logs.example.com/1/1/gate/test2/1 : SUCCESS in 0s
3386
3387For CI problems and help debugging, contact ci@example.org"""
3388
3389 success_body = """\
3390Build succeeded.
3391
3392- test1 http://logs.example.com/2/1/gate/test1/2 : SUCCESS in 0s
3393- test2 http://logs.example.com/2/1/gate/test2/3 : SUCCESS in 0s
3394
3395For CI problems and help debugging, contact ci@example.org"""
3396
3397 self.assertEqual(failure_body, self.smtp_messages[0]['body'])
3398 self.assertEqual(success_body, self.smtp_messages[1]['body'])
Joshua Heskethb7179772014-01-30 23:30:46 +11003399
3400 def test_merge_failure_reporters(self):
3401 """Check that the config is set up correctly"""
3402
James E. Blairf84026c2015-12-08 16:11:46 -08003403 self.updateConfigLayout(
3404 'tests/fixtures/layout-merge-failure.yaml')
Joshua Heskethb7179772014-01-30 23:30:46 +11003405 self.sched.reconfigure(self.config)
3406 self.registerJobs()
3407
3408 self.assertEqual(
Jeremy Stanley1c2c3c22015-06-15 21:23:19 +00003409 "Merge Failed.\n\nThis change or one of its cross-repo "
3410 "dependencies was unable to be automatically merged with the "
3411 "current state of its repository. Please rebase the change and "
3412 "upload a new patchset.",
Joshua Heskethb7179772014-01-30 23:30:46 +11003413 self.sched.layout.pipelines['check'].merge_failure_message)
3414 self.assertEqual(
3415 "The merge failed! For more information...",
3416 self.sched.layout.pipelines['gate'].merge_failure_message)
3417
3418 self.assertEqual(
3419 len(self.sched.layout.pipelines['check'].merge_failure_actions), 1)
3420 self.assertEqual(
3421 len(self.sched.layout.pipelines['gate'].merge_failure_actions), 2)
3422
3423 self.assertTrue(isinstance(
Joshua Heskethde958652015-11-10 19:19:50 +11003424 self.sched.layout.pipelines['check'].merge_failure_actions[0],
3425 zuul.reporter.gerrit.GerritReporter))
Joshua Heskethb7179772014-01-30 23:30:46 +11003426
3427 self.assertTrue(
3428 (
3429 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003430 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003431 zuul.reporter.smtp.SMTPReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003432 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003433 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003434 zuul.reporter.gerrit.GerritReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003435 ) or (
3436 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003437 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003438 zuul.reporter.gerrit.GerritReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003439 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003440 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003441 zuul.reporter.smtp.SMTPReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003442 )
3443 )
3444
3445 def test_merge_failure_reports(self):
3446 """Check that when a change fails to merge the correct message is sent
3447 to the correct reporter"""
James E. Blairf84026c2015-12-08 16:11:46 -08003448 self.updateConfigLayout(
3449 'tests/fixtures/layout-merge-failure.yaml')
Joshua Heskethb7179772014-01-30 23:30:46 +11003450 self.sched.reconfigure(self.config)
3451 self.registerJobs()
3452
3453 # Check a test failure isn't reported to SMTP
3454 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3455 A.addApproval('CRVW', 2)
3456 self.worker.addFailTest('project-test1', A)
3457 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3458 self.waitUntilSettled()
3459
3460 self.assertEqual(3, len(self.history)) # 3 jobs
3461 self.assertEqual(0, len(self.smtp_messages))
3462
3463 # Check a merge failure is reported to SMTP
3464 # B should be merged, but C will conflict with B
3465 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3466 B.addPatchset(['conflict'])
3467 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3468 C.addPatchset(['conflict'])
3469 B.addApproval('CRVW', 2)
3470 C.addApproval('CRVW', 2)
3471 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3472 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3473 self.waitUntilSettled()
3474
3475 self.assertEqual(6, len(self.history)) # A and B jobs
3476 self.assertEqual(1, len(self.smtp_messages))
3477 self.assertEqual('The merge failed! For more information...',
3478 self.smtp_messages[0]['body'])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003479
James E. Blairf760f0e2016-02-09 08:44:52 -08003480 def test_default_merge_failure_reports(self):
3481 """Check that the default merge failure reports are correct."""
3482
3483 # A should report success, B should report merge failure.
3484 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3485 A.addPatchset(['conflict'])
3486 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3487 B.addPatchset(['conflict'])
3488 A.addApproval('CRVW', 2)
3489 B.addApproval('CRVW', 2)
3490 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3491 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3492 self.waitUntilSettled()
3493
3494 self.assertEqual(3, len(self.history)) # A jobs
3495 self.assertEqual(A.reported, 2)
3496 self.assertEqual(B.reported, 2)
3497 self.assertEqual(A.data['status'], 'MERGED')
3498 self.assertEqual(B.data['status'], 'NEW')
3499 self.assertIn('Build succeeded', A.messages[1])
3500 self.assertIn('Merge Failed', B.messages[1])
3501 self.assertIn('automatically merged', B.messages[1])
3502 self.assertNotIn('logs.example.com', B.messages[1])
3503 self.assertNotIn('SKIPPED', B.messages[1])
3504
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003505 def test_swift_instructions(self):
3506 "Test that the correct swift instructions are sent to the workers"
James E. Blairf84026c2015-12-08 16:11:46 -08003507 self.updateConfigLayout(
3508 'tests/fixtures/layout-swift.yaml')
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003509 self.sched.reconfigure(self.config)
3510 self.registerJobs()
3511
3512 self.worker.hold_jobs_in_build = True
3513 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3514
3515 A.addApproval('CRVW', 2)
3516 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3517 self.waitUntilSettled()
3518
3519 self.assertEqual(
3520 "https://storage.example.org/V1/AUTH_account/merge_logs/1/1/1/"
3521 "gate/test-merge/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003522 self.builds[0].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003523 self.assertEqual(5,
3524 len(self.builds[0].parameters['SWIFT_logs_HMAC_BODY'].
3525 split('\n')))
3526 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[0].parameters)
3527
3528 self.assertEqual(
3529 "https://storage.example.org/V1/AUTH_account/logs/1/1/1/"
3530 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003531 self.builds[1].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003532 self.assertEqual(5,
3533 len(self.builds[1].parameters['SWIFT_logs_HMAC_BODY'].
3534 split('\n')))
3535 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[1].parameters)
3536
3537 self.assertEqual(
3538 "https://storage.example.org/V1/AUTH_account/stash/1/1/1/"
3539 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003540 self.builds[1].parameters['SWIFT_MOSTLY_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003541 self.assertEqual(5,
3542 len(self.builds[1].
3543 parameters['SWIFT_MOSTLY_HMAC_BODY'].split('\n')))
3544 self.assertIn('SWIFT_MOSTLY_SIGNATURE', self.builds[1].parameters)
3545
3546 self.worker.hold_jobs_in_build = False
3547 self.worker.release()
3548 self.waitUntilSettled()
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003549
3550 def test_client_get_running_jobs(self):
3551 "Test that the RPC client can get a list of running jobs"
3552 self.worker.hold_jobs_in_build = True
3553 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3554 A.addApproval('CRVW', 2)
3555 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3556 self.waitUntilSettled()
3557
3558 client = zuul.rpcclient.RPCClient('127.0.0.1',
3559 self.gearman_server.port)
3560
3561 # Wait for gearman server to send the initial workData back to zuul
3562 start = time.time()
3563 while True:
3564 if time.time() - start > 10:
3565 raise Exception("Timeout waiting for gearman server to report "
3566 + "back to the client")
3567 build = self.launcher.builds.values()[0]
3568 if build.worker.name == "My Worker":
3569 break
3570 else:
3571 time.sleep(0)
3572
3573 running_items = client.get_running_jobs()
3574
3575 self.assertEqual(1, len(running_items))
3576 running_item = running_items[0]
3577 self.assertEqual([], running_item['failing_reasons'])
3578 self.assertEqual([], running_item['items_behind'])
3579 self.assertEqual('https://hostname/1', running_item['url'])
3580 self.assertEqual(None, running_item['item_ahead'])
3581 self.assertEqual('org/project', running_item['project'])
3582 self.assertEqual(None, running_item['remaining_time'])
3583 self.assertEqual(True, running_item['active'])
3584 self.assertEqual('1,1', running_item['id'])
3585
3586 self.assertEqual(3, len(running_item['jobs']))
3587 for job in running_item['jobs']:
3588 if job['name'] == 'project-merge':
3589 self.assertEqual('project-merge', job['name'])
3590 self.assertEqual('gate', job['pipeline'])
3591 self.assertEqual(False, job['retry'])
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003592 self.assertEqual('https://server/job/project-merge/0/',
3593 job['url'])
3594 self.assertEqual(7, len(job['worker']))
3595 self.assertEqual(False, job['canceled'])
3596 self.assertEqual(True, job['voting'])
3597 self.assertEqual(None, job['result'])
3598 self.assertEqual('gate', job['pipeline'])
3599 break
3600
3601 self.worker.hold_jobs_in_build = False
3602 self.worker.release()
3603 self.waitUntilSettled()
3604
3605 running_items = client.get_running_jobs()
3606 self.assertEqual(0, len(running_items))
James E. Blairbadc1ad2014-04-28 13:55:14 -07003607
3608 def test_nonvoting_pipeline(self):
3609 "Test that a nonvoting pipeline (experimental) can still report"
3610
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003611 A = self.fake_gerrit.addFakeChange('org/experimental-project',
3612 'master', 'A')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003613 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3614 self.waitUntilSettled()
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003615 self.assertEqual(
3616 self.getJobFromHistory('experimental-project-test').result,
3617 'SUCCESS')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003618 self.assertEqual(A.reported, 1)
James E. Blair5ee24252014-12-30 10:12:29 -08003619
3620 def test_crd_gate(self):
3621 "Test cross-repo dependencies"
3622 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3623 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3624 A.addApproval('CRVW', 2)
3625 B.addApproval('CRVW', 2)
3626
3627 AM2 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM2')
3628 AM1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM1')
3629 AM2.setMerged()
3630 AM1.setMerged()
3631
3632 BM2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM2')
3633 BM1 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM1')
3634 BM2.setMerged()
3635 BM1.setMerged()
3636
3637 # A -> AM1 -> AM2
3638 # B -> BM1 -> BM2
3639 # A Depends-On: B
3640 # M2 is here to make sure it is never queried. If it is, it
3641 # means zuul is walking down the entire history of merged
3642 # changes.
3643
3644 B.setDependsOn(BM1, 1)
3645 BM1.setDependsOn(BM2, 1)
3646
3647 A.setDependsOn(AM1, 1)
3648 AM1.setDependsOn(AM2, 1)
3649
3650 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3651 A.subject, B.data['id'])
3652
3653 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3654 self.waitUntilSettled()
3655
3656 self.assertEqual(A.data['status'], 'NEW')
3657 self.assertEqual(B.data['status'], 'NEW')
3658
3659 source = self.sched.layout.pipelines['gate'].source
3660 source.maintainCache([])
3661
3662 self.worker.hold_jobs_in_build = True
3663 B.addApproval('APRV', 1)
3664 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3665 self.waitUntilSettled()
3666
3667 self.worker.release('.*-merge')
3668 self.waitUntilSettled()
3669 self.worker.release('.*-merge')
3670 self.waitUntilSettled()
3671 self.worker.hold_jobs_in_build = False
3672 self.worker.release()
3673 self.waitUntilSettled()
3674
3675 self.assertEqual(AM2.queried, 0)
3676 self.assertEqual(BM2.queried, 0)
3677 self.assertEqual(A.data['status'], 'MERGED')
3678 self.assertEqual(B.data['status'], 'MERGED')
3679 self.assertEqual(A.reported, 2)
3680 self.assertEqual(B.reported, 2)
3681
James E. Blair8f78d882015-02-05 08:51:37 -08003682 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3683 '2,1 1,1')
3684
3685 def test_crd_branch(self):
3686 "Test cross-repo dependencies in multiple branches"
3687 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3688 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3689 C = self.fake_gerrit.addFakeChange('org/project2', 'mp', 'C')
3690 C.data['id'] = B.data['id']
3691 A.addApproval('CRVW', 2)
3692 B.addApproval('CRVW', 2)
3693 C.addApproval('CRVW', 2)
3694
3695 # A Depends-On: B+C
3696 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3697 A.subject, B.data['id'])
3698
3699 self.worker.hold_jobs_in_build = True
3700 B.addApproval('APRV', 1)
3701 C.addApproval('APRV', 1)
3702 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3703 self.waitUntilSettled()
3704
3705 self.worker.release('.*-merge')
3706 self.waitUntilSettled()
3707 self.worker.release('.*-merge')
3708 self.waitUntilSettled()
3709 self.worker.release('.*-merge')
3710 self.waitUntilSettled()
3711 self.worker.hold_jobs_in_build = False
3712 self.worker.release()
3713 self.waitUntilSettled()
3714
3715 self.assertEqual(A.data['status'], 'MERGED')
3716 self.assertEqual(B.data['status'], 'MERGED')
3717 self.assertEqual(C.data['status'], 'MERGED')
3718 self.assertEqual(A.reported, 2)
3719 self.assertEqual(B.reported, 2)
3720 self.assertEqual(C.reported, 2)
3721
3722 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3723 '2,1 3,1 1,1')
3724
3725 def test_crd_multiline(self):
3726 "Test multiple depends-on lines in commit"
3727 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3728 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3729 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
3730 A.addApproval('CRVW', 2)
3731 B.addApproval('CRVW', 2)
3732 C.addApproval('CRVW', 2)
3733
3734 # A Depends-On: B+C
3735 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
3736 A.subject, B.data['id'], C.data['id'])
3737
3738 self.worker.hold_jobs_in_build = True
3739 B.addApproval('APRV', 1)
3740 C.addApproval('APRV', 1)
3741 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3742 self.waitUntilSettled()
3743
3744 self.worker.release('.*-merge')
3745 self.waitUntilSettled()
3746 self.worker.release('.*-merge')
3747 self.waitUntilSettled()
3748 self.worker.release('.*-merge')
3749 self.waitUntilSettled()
3750 self.worker.hold_jobs_in_build = False
3751 self.worker.release()
3752 self.waitUntilSettled()
3753
3754 self.assertEqual(A.data['status'], 'MERGED')
3755 self.assertEqual(B.data['status'], 'MERGED')
3756 self.assertEqual(C.data['status'], 'MERGED')
3757 self.assertEqual(A.reported, 2)
3758 self.assertEqual(B.reported, 2)
3759 self.assertEqual(C.reported, 2)
3760
3761 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3762 '2,1 3,1 1,1')
James E. Blair5ee24252014-12-30 10:12:29 -08003763
3764 def test_crd_unshared_gate(self):
3765 "Test cross-repo dependencies in unshared gate queues"
3766 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3767 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3768 A.addApproval('CRVW', 2)
3769 B.addApproval('CRVW', 2)
3770
3771 # A Depends-On: B
3772 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3773 A.subject, B.data['id'])
3774
3775 # A and B do not share a queue, make sure that A is unable to
3776 # enqueue B (and therefore, A is unable to be enqueued).
3777 B.addApproval('APRV', 1)
3778 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3779 self.waitUntilSettled()
3780
3781 self.assertEqual(A.data['status'], 'NEW')
3782 self.assertEqual(B.data['status'], 'NEW')
3783 self.assertEqual(A.reported, 0)
3784 self.assertEqual(B.reported, 0)
3785 self.assertEqual(len(self.history), 0)
3786
3787 # Enqueue and merge B alone.
3788 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3789 self.waitUntilSettled()
3790
3791 self.assertEqual(B.data['status'], 'MERGED')
3792 self.assertEqual(B.reported, 2)
3793
3794 # Now that B is merged, A should be able to be enqueued and
3795 # merged.
3796 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3797 self.waitUntilSettled()
3798
3799 self.assertEqual(A.data['status'], 'MERGED')
3800 self.assertEqual(A.reported, 2)
3801
James E. Blair96698e22015-04-02 07:48:21 -07003802 def test_crd_gate_reverse(self):
3803 "Test reverse cross-repo dependencies"
3804 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3805 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3806 A.addApproval('CRVW', 2)
3807 B.addApproval('CRVW', 2)
3808
3809 # A Depends-On: B
3810
3811 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3812 A.subject, B.data['id'])
3813
3814 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3815 self.waitUntilSettled()
3816
3817 self.assertEqual(A.data['status'], 'NEW')
3818 self.assertEqual(B.data['status'], 'NEW')
3819
3820 self.worker.hold_jobs_in_build = True
3821 A.addApproval('APRV', 1)
3822 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3823 self.waitUntilSettled()
3824
3825 self.worker.release('.*-merge')
3826 self.waitUntilSettled()
3827 self.worker.release('.*-merge')
3828 self.waitUntilSettled()
3829 self.worker.hold_jobs_in_build = False
3830 self.worker.release()
3831 self.waitUntilSettled()
3832
3833 self.assertEqual(A.data['status'], 'MERGED')
3834 self.assertEqual(B.data['status'], 'MERGED')
3835 self.assertEqual(A.reported, 2)
3836 self.assertEqual(B.reported, 2)
3837
3838 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3839 '2,1 1,1')
3840
James E. Blair5ee24252014-12-30 10:12:29 -08003841 def test_crd_cycle(self):
3842 "Test cross-repo dependency cycles"
3843 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3844 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3845 A.addApproval('CRVW', 2)
3846 B.addApproval('CRVW', 2)
3847
3848 # A -> B -> A (via commit-depends)
3849
3850 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3851 A.subject, B.data['id'])
3852 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3853 B.subject, A.data['id'])
3854
3855 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3856 self.waitUntilSettled()
3857
3858 self.assertEqual(A.reported, 0)
3859 self.assertEqual(B.reported, 0)
3860 self.assertEqual(A.data['status'], 'NEW')
3861 self.assertEqual(B.data['status'], 'NEW')
James E. Blairbfb8e042014-12-30 17:01:44 -08003862
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00003863 def test_crd_gate_unknown(self):
3864 "Test unknown projects in dependent pipeline"
3865 self.init_repo("org/unknown")
3866 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3867 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'B')
3868 A.addApproval('CRVW', 2)
3869 B.addApproval('CRVW', 2)
3870
3871 # A Depends-On: B
3872 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3873 A.subject, B.data['id'])
3874
3875 B.addApproval('APRV', 1)
3876 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3877 self.waitUntilSettled()
3878
3879 # Unknown projects cannot share a queue with any other
3880 # since they don't have common jobs with any other (they have no jobs).
3881 # Changes which depend on unknown project changes
3882 # should not be processed in dependent pipeline
3883 self.assertEqual(A.data['status'], 'NEW')
3884 self.assertEqual(B.data['status'], 'NEW')
3885 self.assertEqual(A.reported, 0)
3886 self.assertEqual(B.reported, 0)
3887 self.assertEqual(len(self.history), 0)
3888
3889 # Simulate change B being gated outside this layout
3890 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3891 B.setMerged()
3892 self.waitUntilSettled()
3893 self.assertEqual(len(self.history), 0)
3894
3895 # Now that B is merged, A should be able to be enqueued and
3896 # merged.
3897 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3898 self.waitUntilSettled()
3899
3900 self.assertEqual(A.data['status'], 'MERGED')
3901 self.assertEqual(A.reported, 2)
3902 self.assertEqual(B.data['status'], 'MERGED')
3903 self.assertEqual(B.reported, 0)
3904
James E. Blairbfb8e042014-12-30 17:01:44 -08003905 def test_crd_check(self):
3906 "Test cross-repo dependencies in independent pipelines"
3907
3908 self.gearman_server.hold_jobs_in_queue = True
3909 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3910 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3911
3912 # A Depends-On: B
3913 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3914 A.subject, B.data['id'])
3915
3916 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3917 self.waitUntilSettled()
3918
3919 queue = self.gearman_server.getQueue()
3920 ref = self.getParameter(queue[-1], 'ZUUL_REF')
3921 self.gearman_server.hold_jobs_in_queue = False
3922 self.gearman_server.release()
3923 self.waitUntilSettled()
3924
3925 path = os.path.join(self.git_root, "org/project1")
3926 repo = git.Repo(path)
3927 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
3928 repo_messages.reverse()
3929 correct_messages = ['initial commit', 'A-1']
3930 self.assertEqual(repo_messages, correct_messages)
3931
3932 path = os.path.join(self.git_root, "org/project2")
3933 repo = git.Repo(path)
3934 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
3935 repo_messages.reverse()
3936 correct_messages = ['initial commit', 'B-1']
3937 self.assertEqual(repo_messages, correct_messages)
3938
3939 self.assertEqual(A.data['status'], 'NEW')
3940 self.assertEqual(B.data['status'], 'NEW')
3941 self.assertEqual(A.reported, 1)
3942 self.assertEqual(B.reported, 0)
3943
3944 self.assertEqual(self.history[0].changes, '2,1 1,1')
3945 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair8f78d882015-02-05 08:51:37 -08003946
James E. Blairdbfe1cd2015-02-07 11:41:19 -08003947 def test_crd_check_git_depends(self):
3948 "Test single-repo dependencies in independent pipelines"
James E. Blairb8c16472015-05-05 14:55:26 -07003949 self.gearman_server.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08003950 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3951 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
3952
3953 # Add two git-dependent changes and make sure they both report
3954 # success.
3955 B.setDependsOn(A, 1)
3956 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3957 self.waitUntilSettled()
3958 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3959 self.waitUntilSettled()
3960
James E. Blairb8c16472015-05-05 14:55:26 -07003961 self.orderedRelease()
3962 self.gearman_server.hold_jobs_in_build = False
James E. Blairdbfe1cd2015-02-07 11:41:19 -08003963 self.waitUntilSettled()
3964
3965 self.assertEqual(A.data['status'], 'NEW')
3966 self.assertEqual(B.data['status'], 'NEW')
3967 self.assertEqual(A.reported, 1)
3968 self.assertEqual(B.reported, 1)
3969
3970 self.assertEqual(self.history[0].changes, '1,1')
3971 self.assertEqual(self.history[-1].changes, '1,1 2,1')
3972 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
3973
3974 self.assertIn('Build succeeded', A.messages[0])
3975 self.assertIn('Build succeeded', B.messages[0])
3976
3977 def test_crd_check_duplicate(self):
3978 "Test duplicate check in independent pipelines"
James E. Blair1e263032015-05-07 14:35:34 -07003979 self.worker.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08003980 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3981 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
3982 check_pipeline = self.sched.layout.pipelines['check']
3983
3984 # Add two git-dependent changes...
3985 B.setDependsOn(A, 1)
3986 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3987 self.waitUntilSettled()
3988 self.assertEqual(len(check_pipeline.getAllItems()), 2)
3989
3990 # ...make sure the live one is not duplicated...
3991 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
3992 self.waitUntilSettled()
3993 self.assertEqual(len(check_pipeline.getAllItems()), 2)
3994
3995 # ...but the non-live one is able to be.
3996 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3997 self.waitUntilSettled()
3998 self.assertEqual(len(check_pipeline.getAllItems()), 3)
3999
Clark Boylandd849822015-03-02 12:38:14 -08004000 # Release jobs in order to avoid races with change A jobs
4001 # finishing before change B jobs.
James E. Blaird7650852015-05-07 15:47:37 -07004002 self.orderedRelease()
James E. Blair1e263032015-05-07 14:35:34 -07004003 self.worker.hold_jobs_in_build = False
4004 self.worker.release()
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004005 self.waitUntilSettled()
4006
4007 self.assertEqual(A.data['status'], 'NEW')
4008 self.assertEqual(B.data['status'], 'NEW')
4009 self.assertEqual(A.reported, 1)
4010 self.assertEqual(B.reported, 1)
4011
4012 self.assertEqual(self.history[0].changes, '1,1 2,1')
4013 self.assertEqual(self.history[1].changes, '1,1')
4014 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4015
4016 self.assertIn('Build succeeded', A.messages[0])
4017 self.assertIn('Build succeeded', B.messages[0])
4018
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004019 def _test_crd_check_reconfiguration(self, project1, project2):
James E. Blair8f78d882015-02-05 08:51:37 -08004020 "Test cross-repo dependencies re-enqueued in independent pipelines"
4021
4022 self.gearman_server.hold_jobs_in_queue = True
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004023 A = self.fake_gerrit.addFakeChange(project1, 'master', 'A')
4024 B = self.fake_gerrit.addFakeChange(project2, 'master', 'B')
James E. Blair8f78d882015-02-05 08:51:37 -08004025
4026 # A Depends-On: B
4027 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4028 A.subject, B.data['id'])
4029
4030 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4031 self.waitUntilSettled()
4032
4033 self.sched.reconfigure(self.config)
4034
4035 # Make sure the items still share a change queue, and the
4036 # first one is not live.
4037 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 1)
4038 queue = self.sched.layout.pipelines['check'].queues[0]
4039 first_item = queue.queue[0]
4040 for item in queue.queue:
4041 self.assertEqual(item.queue, first_item.queue)
4042 self.assertFalse(first_item.live)
4043 self.assertTrue(queue.queue[1].live)
4044
4045 self.gearman_server.hold_jobs_in_queue = False
4046 self.gearman_server.release()
4047 self.waitUntilSettled()
4048
4049 self.assertEqual(A.data['status'], 'NEW')
4050 self.assertEqual(B.data['status'], 'NEW')
4051 self.assertEqual(A.reported, 1)
4052 self.assertEqual(B.reported, 0)
4053
4054 self.assertEqual(self.history[0].changes, '2,1 1,1')
4055 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair17dd6772015-02-09 14:45:18 -08004056
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004057 def test_crd_check_reconfiguration(self):
4058 self._test_crd_check_reconfiguration('org/project1', 'org/project2')
4059
4060 def test_crd_undefined_project(self):
4061 """Test that undefined projects in dependencies are handled for
4062 independent pipelines"""
4063 # It's a hack for fake gerrit,
4064 # as it implies repo creation upon the creation of any change
4065 self.init_repo("org/unknown")
4066 self._test_crd_check_reconfiguration('org/project1', 'org/unknown')
4067
James E. Blair17dd6772015-02-09 14:45:18 -08004068 def test_crd_check_ignore_dependencies(self):
4069 "Test cross-repo dependencies can be ignored"
James E. Blairf84026c2015-12-08 16:11:46 -08004070 self.updateConfigLayout(
4071 'tests/fixtures/layout-ignore-dependencies.yaml')
James E. Blair17dd6772015-02-09 14:45:18 -08004072 self.sched.reconfigure(self.config)
4073 self.registerJobs()
4074
4075 self.gearman_server.hold_jobs_in_queue = True
4076 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4077 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4078 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
4079
4080 # A Depends-On: B
4081 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4082 A.subject, B.data['id'])
4083 # C git-depends on B
4084 C.setDependsOn(B, 1)
4085 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4086 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4087 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4088 self.waitUntilSettled()
4089
4090 # Make sure none of the items share a change queue, and all
4091 # are live.
4092 check_pipeline = self.sched.layout.pipelines['check']
4093 self.assertEqual(len(check_pipeline.queues), 3)
4094 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4095 for item in check_pipeline.getAllItems():
4096 self.assertTrue(item.live)
4097
4098 self.gearman_server.hold_jobs_in_queue = False
4099 self.gearman_server.release()
4100 self.waitUntilSettled()
4101
4102 self.assertEqual(A.data['status'], 'NEW')
4103 self.assertEqual(B.data['status'], 'NEW')
4104 self.assertEqual(C.data['status'], 'NEW')
4105 self.assertEqual(A.reported, 1)
4106 self.assertEqual(B.reported, 1)
4107 self.assertEqual(C.reported, 1)
4108
4109 # Each job should have tested exactly one change
4110 for job in self.history:
4111 self.assertEqual(len(job.changes.split()), 1)
James E. Blair96698e22015-04-02 07:48:21 -07004112
4113 def test_crd_check_transitive(self):
4114 "Test transitive cross-repo dependencies"
4115 # Specifically, if A -> B -> C, and C gets a new patchset and
4116 # A gets a new patchset, ensure the test of A,2 includes B,1
4117 # and C,2 (not C,1 which would indicate stale data in the
4118 # cache for B).
4119 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4120 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4121 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
4122
4123 # A Depends-On: B
4124 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4125 A.subject, B.data['id'])
4126
4127 # B Depends-On: C
4128 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4129 B.subject, C.data['id'])
4130
4131 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4132 self.waitUntilSettled()
4133 self.assertEqual(self.history[-1].changes, '3,1 2,1 1,1')
4134
4135 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4136 self.waitUntilSettled()
4137 self.assertEqual(self.history[-1].changes, '3,1 2,1')
4138
4139 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4140 self.waitUntilSettled()
4141 self.assertEqual(self.history[-1].changes, '3,1')
4142
4143 C.addPatchset()
4144 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(2))
4145 self.waitUntilSettled()
4146 self.assertEqual(self.history[-1].changes, '3,2')
4147
4148 A.addPatchset()
4149 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
4150 self.waitUntilSettled()
4151 self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004152
4153 def test_disable_at(self):
4154 "Test a pipeline will only report to the disabled trigger when failing"
4155
James E. Blairf84026c2015-12-08 16:11:46 -08004156 self.updateConfigLayout(
4157 'tests/fixtures/layout-disable-at.yaml')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004158 self.sched.reconfigure(self.config)
4159
4160 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4161 self.assertEqual(
4162 0, self.sched.layout.pipelines['check']._consecutive_failures)
4163 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4164
4165 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
4166 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
4167 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
4168 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
4169 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
4170 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
4171 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
4172 H = self.fake_gerrit.addFakeChange('org/project', 'master', 'H')
4173 I = self.fake_gerrit.addFakeChange('org/project', 'master', 'I')
4174 J = self.fake_gerrit.addFakeChange('org/project', 'master', 'J')
4175 K = self.fake_gerrit.addFakeChange('org/project', 'master', 'K')
4176
4177 self.worker.addFailTest('project-test1', A)
4178 self.worker.addFailTest('project-test1', B)
4179 # Let C pass, resetting the counter
4180 self.worker.addFailTest('project-test1', D)
4181 self.worker.addFailTest('project-test1', E)
4182 self.worker.addFailTest('project-test1', F)
4183 self.worker.addFailTest('project-test1', G)
4184 self.worker.addFailTest('project-test1', H)
4185 # I also passes but should only report to the disabled reporters
4186 self.worker.addFailTest('project-test1', J)
4187 self.worker.addFailTest('project-test1', K)
4188
4189 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4190 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4191 self.waitUntilSettled()
4192
4193 self.assertEqual(
4194 2, self.sched.layout.pipelines['check']._consecutive_failures)
4195 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4196
4197 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4198 self.waitUntilSettled()
4199
4200 self.assertEqual(
4201 0, self.sched.layout.pipelines['check']._consecutive_failures)
4202 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4203
4204 self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(1))
4205 self.fake_gerrit.addEvent(E.getPatchsetCreatedEvent(1))
4206 self.fake_gerrit.addEvent(F.getPatchsetCreatedEvent(1))
4207 self.waitUntilSettled()
4208
4209 # We should be disabled now
4210 self.assertEqual(
4211 3, self.sched.layout.pipelines['check']._consecutive_failures)
4212 self.assertTrue(self.sched.layout.pipelines['check']._disabled)
4213
4214 # We need to wait between each of these patches to make sure the
4215 # smtp messages come back in an expected order
4216 self.fake_gerrit.addEvent(G.getPatchsetCreatedEvent(1))
4217 self.waitUntilSettled()
4218 self.fake_gerrit.addEvent(H.getPatchsetCreatedEvent(1))
4219 self.waitUntilSettled()
4220 self.fake_gerrit.addEvent(I.getPatchsetCreatedEvent(1))
4221 self.waitUntilSettled()
4222
4223 # The first 6 (ABCDEF) jobs should have reported back to gerrt thus
4224 # leaving a message on each change
4225 self.assertEqual(1, len(A.messages))
4226 self.assertIn('Build failed.', A.messages[0])
4227 self.assertEqual(1, len(B.messages))
4228 self.assertIn('Build failed.', B.messages[0])
4229 self.assertEqual(1, len(C.messages))
4230 self.assertIn('Build succeeded.', C.messages[0])
4231 self.assertEqual(1, len(D.messages))
4232 self.assertIn('Build failed.', D.messages[0])
4233 self.assertEqual(1, len(E.messages))
4234 self.assertIn('Build failed.', E.messages[0])
4235 self.assertEqual(1, len(F.messages))
4236 self.assertIn('Build failed.', F.messages[0])
4237
4238 # The last 3 (GHI) would have only reported via smtp.
4239 self.assertEqual(3, len(self.smtp_messages))
4240 self.assertEqual(0, len(G.messages))
4241 self.assertIn('Build failed.', self.smtp_messages[0]['body'])
4242 self.assertIn('/7/1/check', self.smtp_messages[0]['body'])
4243 self.assertEqual(0, len(H.messages))
4244 self.assertIn('Build failed.', self.smtp_messages[1]['body'])
4245 self.assertIn('/8/1/check', self.smtp_messages[1]['body'])
4246 self.assertEqual(0, len(I.messages))
4247 self.assertIn('Build succeeded.', self.smtp_messages[2]['body'])
4248 self.assertIn('/9/1/check', self.smtp_messages[2]['body'])
4249
4250 # Now reload the configuration (simulate a HUP) to check the pipeline
4251 # comes out of disabled
4252 self.sched.reconfigure(self.config)
4253
4254 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4255 self.assertEqual(
4256 0, self.sched.layout.pipelines['check']._consecutive_failures)
4257 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4258
4259 self.fake_gerrit.addEvent(J.getPatchsetCreatedEvent(1))
4260 self.fake_gerrit.addEvent(K.getPatchsetCreatedEvent(1))
4261 self.waitUntilSettled()
4262
4263 self.assertEqual(
4264 2, self.sched.layout.pipelines['check']._consecutive_failures)
4265 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4266
4267 # J and K went back to gerrit
4268 self.assertEqual(1, len(J.messages))
4269 self.assertIn('Build failed.', J.messages[0])
4270 self.assertEqual(1, len(K.messages))
4271 self.assertIn('Build failed.', K.messages[0])
4272 # No more messages reported via smtp
4273 self.assertEqual(3, len(self.smtp_messages))