blob: 8ac53683b9006f3e9ba5641e9335a20b7159d2fe [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
49 def test_parse_skip_if(self):
50 job_yaml = """
51jobs:
52 - name: job_name
53 skip-if:
54 - project: ^project_name$
55 branch: ^stable/icehouse$
56 all-files-match-any:
57 - ^filename$
58 - project: ^project2_name$
59 all-files-match-any:
60 - ^filename2$
61 """.strip()
62 data = yaml.load(job_yaml)
63 config_job = data.get('jobs')[0]
Joshua Hesketh352264b2015-08-11 23:42:08 +100064 sched = zuul.scheduler.Scheduler({})
Maru Newby3fe5f852015-01-13 04:22:14 +000065 cm = zuul.change_matcher
66 expected = cm.MatchAny([
67 cm.MatchAll([
68 cm.ProjectMatcher('^project_name$'),
69 cm.BranchMatcher('^stable/icehouse$'),
70 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
71 ]),
72 cm.MatchAll([
73 cm.ProjectMatcher('^project2_name$'),
74 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
75 ]),
76 ])
77 matcher = sched._parseSkipIf(config_job)
78 self.assertEqual(expected, matcher)
79
80
Clark Boylanb640e052014-04-03 16:41:46 -070081class TestScheduler(ZuulTestCase):
Antoine Mussobd86a312014-01-08 14:51:33 +010082
James E. Blairb0fcae42012-07-17 11:12:10 -070083 def test_jobs_launched(self):
84 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -070085
James E. Blairb0fcae42012-07-17 11:12:10 -070086 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -070087 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070088 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
89 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -040090 self.assertEqual(self.getJobFromHistory('project-merge').result,
91 'SUCCESS')
92 self.assertEqual(self.getJobFromHistory('project-test1').result,
93 'SUCCESS')
94 self.assertEqual(self.getJobFromHistory('project-test2').result,
95 'SUCCESS')
96 self.assertEqual(A.data['status'], 'MERGED')
97 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070098
James E. Blair66eeebf2013-07-27 17:44:32 -070099 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
100 self.assertReportedStat('zuul.pipeline.gate.current_changes',
101 value='1|g')
102 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
103 kind='ms')
104 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
105 value='1|c')
106 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
107 self.assertReportedStat('zuul.pipeline.gate.total_changes',
108 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700109 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700110 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -0700111 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -0700112 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -0700113
James E. Blair5821bd92015-09-16 08:48:15 -0700114 for build in self.builds:
115 self.assertEqual(build.parameters['ZUUL_VOTING'], '1')
116
James E. Blair3cb10702013-08-24 08:56:03 -0700117 def test_initial_pipeline_gauges(self):
118 "Test that each pipeline reported its length on start"
119 pipeline_names = self.sched.layout.pipelines.keys()
120 self.assertNotEqual(len(pipeline_names), 0)
121 for name in pipeline_names:
122 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
123 value='0|g')
124
James E. Blair42f74822013-05-14 15:18:03 -0700125 def test_duplicate_pipelines(self):
126 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -0700127
James E. Blair42f74822013-05-14 15:18:03 -0700128 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
129 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
130 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -0700131
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400132 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400133 self.history[0].name == 'project-test1'
134 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -0700135
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400136 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -0700137 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400138 self.assertIn('dup1/project-test1', A.messages[0])
139 self.assertNotIn('dup2/project-test1', A.messages[0])
140 self.assertNotIn('dup1/project-test1', A.messages[1])
141 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -0700142 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400143 self.assertIn('dup1/project-test1', A.messages[1])
144 self.assertNotIn('dup2/project-test1', A.messages[1])
145 self.assertNotIn('dup1/project-test1', A.messages[0])
146 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -0700147
James E. Blairb0fcae42012-07-17 11:12:10 -0700148 def test_parallel_changes(self):
149 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700150
151 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700152 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
153 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
154 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700155 A.addApproval('CRVW', 2)
156 B.addApproval('CRVW', 2)
157 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700158
159 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
160 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
161 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
162
163 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400164 self.assertEqual(len(self.builds), 1)
165 self.assertEqual(self.builds[0].name, 'project-merge')
166 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700167
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700168 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700169 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400170 self.assertEqual(len(self.builds), 3)
171 self.assertEqual(self.builds[0].name, 'project-test1')
172 self.assertTrue(self.job_has_changes(self.builds[0], A))
173 self.assertEqual(self.builds[1].name, 'project-test2')
174 self.assertTrue(self.job_has_changes(self.builds[1], A))
175 self.assertEqual(self.builds[2].name, 'project-merge')
176 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700177
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700178 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400180 self.assertEqual(len(self.builds), 5)
181 self.assertEqual(self.builds[0].name, 'project-test1')
182 self.assertTrue(self.job_has_changes(self.builds[0], A))
183 self.assertEqual(self.builds[1].name, 'project-test2')
184 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700185
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400186 self.assertEqual(self.builds[2].name, 'project-test1')
187 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
188 self.assertEqual(self.builds[3].name, 'project-test2')
189 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700190
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400191 self.assertEqual(self.builds[4].name, 'project-merge')
192 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700193
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700194 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700195 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400196 self.assertEqual(len(self.builds), 6)
197 self.assertEqual(self.builds[0].name, 'project-test1')
198 self.assertTrue(self.job_has_changes(self.builds[0], A))
199 self.assertEqual(self.builds[1].name, 'project-test2')
200 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700201
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400202 self.assertEqual(self.builds[2].name, 'project-test1')
203 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
204 self.assertEqual(self.builds[3].name, 'project-test2')
205 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700206
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400207 self.assertEqual(self.builds[4].name, 'project-test1')
208 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
209 self.assertEqual(self.builds[5].name, 'project-test2')
210 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700211
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700212 self.worker.hold_jobs_in_build = False
213 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700214 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400215 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -0700216
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400217 self.assertEqual(len(self.history), 9)
218 self.assertEqual(A.data['status'], 'MERGED')
219 self.assertEqual(B.data['status'], 'MERGED')
220 self.assertEqual(C.data['status'], 'MERGED')
221 self.assertEqual(A.reported, 2)
222 self.assertEqual(B.reported, 2)
223 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700224
225 def test_failed_changes(self):
226 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -0400227 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700228
James E. Blairb02a3bb2012-07-30 17:49:55 -0700229 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
230 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700231 A.addApproval('CRVW', 2)
232 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700233
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700234 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700235
James E. Blaire2819012013-06-28 17:17:26 -0400236 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
237 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700238 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -0400239
240 self.worker.release('.*-merge')
241 self.waitUntilSettled()
242
243 self.worker.hold_jobs_in_build = False
244 self.worker.release()
245
246 self.waitUntilSettled()
247 # It's certain that the merge job for change 2 will run, but
248 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400249 self.assertTrue(len(self.history) > 6)
250 self.assertEqual(A.data['status'], 'NEW')
251 self.assertEqual(B.data['status'], 'MERGED')
252 self.assertEqual(A.reported, 2)
253 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700254
255 def test_independent_queues(self):
256 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700257
258 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900259 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700260 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
261 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700262 A.addApproval('CRVW', 2)
263 B.addApproval('CRVW', 2)
264 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700265
266 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
267 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
268 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
269
James E. Blairb02a3bb2012-07-30 17:49:55 -0700270 self.waitUntilSettled()
271
272 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400273 self.assertEqual(len(self.builds), 2)
274 self.assertEqual(self.builds[0].name, 'project-merge')
275 self.assertTrue(self.job_has_changes(self.builds[0], A))
276 self.assertEqual(self.builds[1].name, 'project1-merge')
277 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700278
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700279 # Release the current merge builds
280 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700281 self.waitUntilSettled()
282 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700283 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700284 self.waitUntilSettled()
285
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700286 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -0700287 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400288 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700289
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700290 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700291 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400292 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700293
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400294 self.assertEqual(len(self.history), 11)
295 self.assertEqual(A.data['status'], 'MERGED')
296 self.assertEqual(B.data['status'], 'MERGED')
297 self.assertEqual(C.data['status'], 'MERGED')
298 self.assertEqual(A.reported, 2)
299 self.assertEqual(B.reported, 2)
300 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700301
302 def test_failed_change_at_head(self):
303 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700304
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700305 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -0700306 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
307 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
308 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700309 A.addApproval('CRVW', 2)
310 B.addApproval('CRVW', 2)
311 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700312
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700313 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700314
315 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
316 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
317 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
318
319 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -0700320
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400321 self.assertEqual(len(self.builds), 1)
322 self.assertEqual(self.builds[0].name, 'project-merge')
323 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700324
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700325 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700326 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700327 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700328 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700329 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700330 self.waitUntilSettled()
331
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400332 self.assertEqual(len(self.builds), 6)
333 self.assertEqual(self.builds[0].name, 'project-test1')
334 self.assertEqual(self.builds[1].name, 'project-test2')
335 self.assertEqual(self.builds[2].name, 'project-test1')
336 self.assertEqual(self.builds[3].name, 'project-test2')
337 self.assertEqual(self.builds[4].name, 'project-test1')
338 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700339
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400340 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700341 self.waitUntilSettled()
342
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400343 # project-test2, project-merge for B
344 self.assertEqual(len(self.builds), 2)
345 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -0700346
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700347 self.worker.hold_jobs_in_build = False
348 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700349 self.waitUntilSettled()
350
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400351 self.assertEqual(len(self.builds), 0)
352 self.assertEqual(len(self.history), 15)
353 self.assertEqual(A.data['status'], 'NEW')
354 self.assertEqual(B.data['status'], 'MERGED')
355 self.assertEqual(C.data['status'], 'MERGED')
356 self.assertEqual(A.reported, 2)
357 self.assertEqual(B.reported, 2)
358 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700359
James E. Blair0aac4872013-08-23 14:02:38 -0700360 def test_failed_change_in_middle(self):
361 "Test a failed change in the middle of the queue"
362
363 self.worker.hold_jobs_in_build = True
364 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
365 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
366 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
367 A.addApproval('CRVW', 2)
368 B.addApproval('CRVW', 2)
369 C.addApproval('CRVW', 2)
370
371 self.worker.addFailTest('project-test1', B)
372
373 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
374 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
375 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
376
377 self.waitUntilSettled()
378
379 self.worker.release('.*-merge')
380 self.waitUntilSettled()
381 self.worker.release('.*-merge')
382 self.waitUntilSettled()
383 self.worker.release('.*-merge')
384 self.waitUntilSettled()
385
386 self.assertEqual(len(self.builds), 6)
387 self.assertEqual(self.builds[0].name, 'project-test1')
388 self.assertEqual(self.builds[1].name, 'project-test2')
389 self.assertEqual(self.builds[2].name, 'project-test1')
390 self.assertEqual(self.builds[3].name, 'project-test2')
391 self.assertEqual(self.builds[4].name, 'project-test1')
392 self.assertEqual(self.builds[5].name, 'project-test2')
393
394 self.release(self.builds[2])
395 self.waitUntilSettled()
396
James E. Blair972e3c72013-08-29 12:04:55 -0700397 # project-test1 and project-test2 for A
398 # project-test2 for B
399 # project-merge for C (without B)
400 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -0700401 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
402
James E. Blair972e3c72013-08-29 12:04:55 -0700403 self.worker.release('.*-merge')
404 self.waitUntilSettled()
405
406 # project-test1 and project-test2 for A
407 # project-test2 for B
408 # project-test1 and project-test2 for C
409 self.assertEqual(len(self.builds), 5)
410
James E. Blair0aac4872013-08-23 14:02:38 -0700411 items = self.sched.layout.pipelines['gate'].getAllItems()
412 builds = items[0].current_build_set.getBuilds()
413 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
414 self.assertEqual(self.countJobResults(builds, None), 2)
415 builds = items[1].current_build_set.getBuilds()
416 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
417 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
418 self.assertEqual(self.countJobResults(builds, None), 1)
419 builds = items[2].current_build_set.getBuilds()
420 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -0700421 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -0700422
423 self.worker.hold_jobs_in_build = False
424 self.worker.release()
425 self.waitUntilSettled()
426
427 self.assertEqual(len(self.builds), 0)
428 self.assertEqual(len(self.history), 12)
429 self.assertEqual(A.data['status'], 'MERGED')
430 self.assertEqual(B.data['status'], 'NEW')
431 self.assertEqual(C.data['status'], 'MERGED')
432 self.assertEqual(A.reported, 2)
433 self.assertEqual(B.reported, 2)
434 self.assertEqual(C.reported, 2)
435
James E. Blaird466dc42012-07-31 10:42:56 -0700436 def test_failed_change_at_head_with_queue(self):
437 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700438
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700439 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -0700440 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
441 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
442 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700443 A.addApproval('CRVW', 2)
444 B.addApproval('CRVW', 2)
445 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700446
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700447 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700448
449 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
450 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
451 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
452
453 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700454 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400455 self.assertEqual(len(self.builds), 0)
456 self.assertEqual(len(queue), 1)
457 self.assertEqual(queue[0].name, 'build:project-merge')
458 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700459
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700460 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700461 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700462 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700463 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700464 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700465 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700466 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -0700467
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400468 self.assertEqual(len(self.builds), 0)
469 self.assertEqual(len(queue), 6)
470 self.assertEqual(queue[0].name, 'build:project-test1')
471 self.assertEqual(queue[1].name, 'build:project-test2')
472 self.assertEqual(queue[2].name, 'build:project-test1')
473 self.assertEqual(queue[3].name, 'build:project-test2')
474 self.assertEqual(queue[4].name, 'build:project-test1')
475 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700476
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700477 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700478 self.waitUntilSettled()
479
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400480 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -0700481 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400482 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
483 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -0700484
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700485 self.gearman_server.hold_jobs_in_queue = False
486 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700487 self.waitUntilSettled()
488
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400489 self.assertEqual(len(self.builds), 0)
490 self.assertEqual(len(self.history), 11)
491 self.assertEqual(A.data['status'], 'NEW')
492 self.assertEqual(B.data['status'], 'MERGED')
493 self.assertEqual(C.data['status'], 'MERGED')
494 self.assertEqual(A.reported, 2)
495 self.assertEqual(B.reported, 2)
496 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700497
James E. Blairfef71632013-09-23 11:15:47 -0700498 def test_two_failed_changes_at_head(self):
499 "Test that changes are reparented correctly if 2 fail at head"
500
501 self.worker.hold_jobs_in_build = True
502 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
503 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
504 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
505 A.addApproval('CRVW', 2)
506 B.addApproval('CRVW', 2)
507 C.addApproval('CRVW', 2)
508
509 self.worker.addFailTest('project-test1', A)
510 self.worker.addFailTest('project-test1', B)
511
512 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
513 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
514 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
515 self.waitUntilSettled()
516
517 self.worker.release('.*-merge')
518 self.waitUntilSettled()
519 self.worker.release('.*-merge')
520 self.waitUntilSettled()
521 self.worker.release('.*-merge')
522 self.waitUntilSettled()
523
524 self.assertEqual(len(self.builds), 6)
525 self.assertEqual(self.builds[0].name, 'project-test1')
526 self.assertEqual(self.builds[1].name, 'project-test2')
527 self.assertEqual(self.builds[2].name, 'project-test1')
528 self.assertEqual(self.builds[3].name, 'project-test2')
529 self.assertEqual(self.builds[4].name, 'project-test1')
530 self.assertEqual(self.builds[5].name, 'project-test2')
531
532 self.assertTrue(self.job_has_changes(self.builds[0], A))
533 self.assertTrue(self.job_has_changes(self.builds[2], A))
534 self.assertTrue(self.job_has_changes(self.builds[2], B))
535 self.assertTrue(self.job_has_changes(self.builds[4], A))
536 self.assertTrue(self.job_has_changes(self.builds[4], B))
537 self.assertTrue(self.job_has_changes(self.builds[4], C))
538
539 # Fail change B first
540 self.release(self.builds[2])
541 self.waitUntilSettled()
542
543 # restart of C after B failure
544 self.worker.release('.*-merge')
545 self.waitUntilSettled()
546
547 self.assertEqual(len(self.builds), 5)
548 self.assertEqual(self.builds[0].name, 'project-test1')
549 self.assertEqual(self.builds[1].name, 'project-test2')
550 self.assertEqual(self.builds[2].name, 'project-test2')
551 self.assertEqual(self.builds[3].name, 'project-test1')
552 self.assertEqual(self.builds[4].name, 'project-test2')
553
554 self.assertTrue(self.job_has_changes(self.builds[1], A))
555 self.assertTrue(self.job_has_changes(self.builds[2], A))
556 self.assertTrue(self.job_has_changes(self.builds[2], B))
557 self.assertTrue(self.job_has_changes(self.builds[4], A))
558 self.assertFalse(self.job_has_changes(self.builds[4], B))
559 self.assertTrue(self.job_has_changes(self.builds[4], C))
560
561 # Finish running all passing jobs for change A
562 self.release(self.builds[1])
563 self.waitUntilSettled()
564 # Fail and report change A
565 self.release(self.builds[0])
566 self.waitUntilSettled()
567
568 # restart of B,C after A failure
569 self.worker.release('.*-merge')
570 self.waitUntilSettled()
571 self.worker.release('.*-merge')
572 self.waitUntilSettled()
573
574 self.assertEqual(len(self.builds), 4)
575 self.assertEqual(self.builds[0].name, 'project-test1') # B
576 self.assertEqual(self.builds[1].name, 'project-test2') # B
577 self.assertEqual(self.builds[2].name, 'project-test1') # C
578 self.assertEqual(self.builds[3].name, 'project-test2') # C
579
580 self.assertFalse(self.job_has_changes(self.builds[1], A))
581 self.assertTrue(self.job_has_changes(self.builds[1], B))
582 self.assertFalse(self.job_has_changes(self.builds[1], C))
583
584 self.assertFalse(self.job_has_changes(self.builds[2], A))
585 # After A failed and B and C restarted, B should be back in
586 # C's tests because it has not failed yet.
587 self.assertTrue(self.job_has_changes(self.builds[2], B))
588 self.assertTrue(self.job_has_changes(self.builds[2], C))
589
590 self.worker.hold_jobs_in_build = False
591 self.worker.release()
592 self.waitUntilSettled()
593
594 self.assertEqual(len(self.builds), 0)
595 self.assertEqual(len(self.history), 21)
596 self.assertEqual(A.data['status'], 'NEW')
597 self.assertEqual(B.data['status'], 'NEW')
598 self.assertEqual(C.data['status'], 'MERGED')
599 self.assertEqual(A.reported, 2)
600 self.assertEqual(B.reported, 2)
601 self.assertEqual(C.reported, 2)
602
James E. Blair8c803f82012-07-31 16:25:42 -0700603 def test_patch_order(self):
604 "Test that dependent patches are tested in the right order"
605 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
606 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
607 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
608 A.addApproval('CRVW', 2)
609 B.addApproval('CRVW', 2)
610 C.addApproval('CRVW', 2)
611
612 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
613 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
614 M2.setMerged()
615 M1.setMerged()
616
617 # C -> B -> A -> M1 -> M2
618 # M2 is here to make sure it is never queried. If it is, it
619 # means zuul is walking down the entire history of merged
620 # changes.
621
622 C.setDependsOn(B, 1)
623 B.setDependsOn(A, 1)
624 A.setDependsOn(M1, 1)
625 M1.setDependsOn(M2, 1)
626
627 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
628
629 self.waitUntilSettled()
630
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400631 self.assertEqual(A.data['status'], 'NEW')
632 self.assertEqual(B.data['status'], 'NEW')
633 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -0700634
635 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
636 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
637
638 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400639 self.assertEqual(M2.queried, 0)
640 self.assertEqual(A.data['status'], 'MERGED')
641 self.assertEqual(B.data['status'], 'MERGED')
642 self.assertEqual(C.data['status'], 'MERGED')
643 self.assertEqual(A.reported, 2)
644 self.assertEqual(B.reported, 2)
645 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700646
James E. Blair063672f2015-01-29 13:09:12 -0800647 def test_needed_changes_enqueue(self):
648 "Test that a needed change is enqueued ahead"
649 # A Given a git tree like this, if we enqueue
650 # / \ change C, we should walk up and down the tree
651 # B G and enqueue changes in the order ABCDEFG.
652 # /|\ This is also the order that you would get if
653 # *C E F you enqueued changes in the order ABCDEFG, so
654 # / the ordering is stable across re-enqueue events.
655 # D
656
657 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
658 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
659 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
660 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
661 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
662 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
663 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
664 B.setDependsOn(A, 1)
665 C.setDependsOn(B, 1)
666 D.setDependsOn(C, 1)
667 E.setDependsOn(B, 1)
668 F.setDependsOn(B, 1)
669 G.setDependsOn(A, 1)
670
671 A.addApproval('CRVW', 2)
672 B.addApproval('CRVW', 2)
673 C.addApproval('CRVW', 2)
674 D.addApproval('CRVW', 2)
675 E.addApproval('CRVW', 2)
676 F.addApproval('CRVW', 2)
677 G.addApproval('CRVW', 2)
678 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
679
680 self.waitUntilSettled()
681
682 self.assertEqual(A.data['status'], 'NEW')
683 self.assertEqual(B.data['status'], 'NEW')
684 self.assertEqual(C.data['status'], 'NEW')
685 self.assertEqual(D.data['status'], 'NEW')
686 self.assertEqual(E.data['status'], 'NEW')
687 self.assertEqual(F.data['status'], 'NEW')
688 self.assertEqual(G.data['status'], 'NEW')
689
690 # We're about to add approvals to changes without adding the
691 # triggering events to Zuul, so that we can be sure that it is
692 # enqueing the changes based on dependencies, not because of
693 # triggering events. Since it will have the changes cached
694 # already (without approvals), we need to clear the cache
695 # first.
Joshua Hesketh4bd7da32016-02-17 20:58:47 +1100696 for connection in self.connections.values():
697 connection.maintainCache([])
James E. Blair063672f2015-01-29 13:09:12 -0800698
699 self.worker.hold_jobs_in_build = True
700 A.addApproval('APRV', 1)
701 B.addApproval('APRV', 1)
702 D.addApproval('APRV', 1)
703 E.addApproval('APRV', 1)
704 F.addApproval('APRV', 1)
705 G.addApproval('APRV', 1)
706 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
707
708 for x in range(8):
709 self.worker.release('.*-merge')
710 self.waitUntilSettled()
711 self.worker.hold_jobs_in_build = False
712 self.worker.release()
713 self.waitUntilSettled()
714
715 self.assertEqual(A.data['status'], 'MERGED')
716 self.assertEqual(B.data['status'], 'MERGED')
717 self.assertEqual(C.data['status'], 'MERGED')
718 self.assertEqual(D.data['status'], 'MERGED')
719 self.assertEqual(E.data['status'], 'MERGED')
720 self.assertEqual(F.data['status'], 'MERGED')
721 self.assertEqual(G.data['status'], 'MERGED')
722 self.assertEqual(A.reported, 2)
723 self.assertEqual(B.reported, 2)
724 self.assertEqual(C.reported, 2)
725 self.assertEqual(D.reported, 2)
726 self.assertEqual(E.reported, 2)
727 self.assertEqual(F.reported, 2)
728 self.assertEqual(G.reported, 2)
729 self.assertEqual(self.history[6].changes,
730 '1,1 2,1 3,1 4,1 5,1 6,1 7,1')
731
Joshua Hesketh850ccb62014-11-27 11:31:02 +1100732 def test_source_cache(self):
733 "Test that the source cache operates correctly"
James E. Blair0e933c52013-07-11 10:18:52 -0700734 self.worker.hold_jobs_in_build = True
735
736 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
737 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
738 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
739 A.addApproval('CRVW', 2)
740 B.addApproval('CRVW', 2)
741
742 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
743 M1.setMerged()
744
745 B.setDependsOn(A, 1)
746 A.setDependsOn(M1, 1)
747
748 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
749 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
750
751 self.waitUntilSettled()
752
753 for build in self.builds:
754 if build.parameters['ZUUL_PIPELINE'] == 'check':
755 build.release()
756 self.waitUntilSettled()
757 for build in self.builds:
758 if build.parameters['ZUUL_PIPELINE'] == 'check':
759 build.release()
760 self.waitUntilSettled()
761
762 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
763 self.waitUntilSettled()
764
Joshua Hesketh352264b2015-08-11 23:42:08 +1000765 self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -0700766 # there should still be changes in the cache
Joshua Hesketh352264b2015-08-11 23:42:08 +1000767 self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -0700768
769 self.worker.hold_jobs_in_build = False
770 self.worker.release()
771 self.waitUntilSettled()
772
773 self.assertEqual(A.data['status'], 'MERGED')
774 self.assertEqual(B.data['status'], 'MERGED')
775 self.assertEqual(A.queried, 2) # Initial and isMerged
776 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
777
James E. Blair8c803f82012-07-31 16:25:42 -0700778 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -0700779 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -0700780 # TODO: move to test_gerrit (this is a unit test!)
781 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairc0dedf82014-08-06 09:37:52 -0700782 source = self.sched.layout.pipelines['gate'].source
783 a = source._getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -0400784 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blairc0dedf82014-08-06 09:37:52 -0700785 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700786
787 A.addApproval('CRVW', 2)
James E. Blairc0dedf82014-08-06 09:37:52 -0700788 a = source._getChange(1, 2, refresh=True)
789 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700790
791 A.addApproval('APRV', 1)
James E. Blairc0dedf82014-08-06 09:37:52 -0700792 a = source._getChange(1, 2, refresh=True)
793 self.assertTrue(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair4886cc12012-07-18 15:39:41 -0700794
795 def test_build_configuration(self):
796 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700797
798 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -0700799 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
800 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
801 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
802 A.addApproval('CRVW', 2)
803 B.addApproval('CRVW', 2)
804 C.addApproval('CRVW', 2)
805 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
806 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
807 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
808 self.waitUntilSettled()
809
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700810 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700811 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700812 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700813 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700814 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700815 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700816 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700817 ref = self.getParameter(queue[-1], 'ZUUL_REF')
818 self.gearman_server.hold_jobs_in_queue = False
819 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700820 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -0700821
Monty Taylorbc758832013-06-17 17:22:42 -0400822 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -0700823 repo = git.Repo(path)
824 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
825 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -0700826 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400827 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -0700828
829 def test_build_configuration_conflict(self):
830 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700831
832 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -0700833 A = self.fake_gerrit.addFakeChange('org/conflict-project',
834 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -0700835 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700836 B = self.fake_gerrit.addFakeChange('org/conflict-project',
837 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -0700838 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700839 C = self.fake_gerrit.addFakeChange('org/conflict-project',
840 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -0700841 A.addApproval('CRVW', 2)
842 B.addApproval('CRVW', 2)
843 C.addApproval('CRVW', 2)
844 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
845 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
846 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
847 self.waitUntilSettled()
848
James E. Blair6736beb2013-07-11 15:18:15 -0700849 self.assertEqual(A.reported, 1)
850 self.assertEqual(B.reported, 1)
851 self.assertEqual(C.reported, 1)
852
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700853 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700854 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700855 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700856 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700857 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700858 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -0700859
860 self.assertEqual(len(self.history), 2) # A and C merge jobs
861
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700862 self.gearman_server.hold_jobs_in_queue = False
863 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700864 self.waitUntilSettled()
865
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400866 self.assertEqual(A.data['status'], 'MERGED')
867 self.assertEqual(B.data['status'], 'NEW')
868 self.assertEqual(C.data['status'], 'MERGED')
869 self.assertEqual(A.reported, 2)
870 self.assertEqual(B.reported, 2)
871 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -0700872 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -0700873
James E. Blairdaabed22012-08-15 15:38:57 -0700874 def test_post(self):
875 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700876
Zhongyue Luo5d556072012-09-21 02:00:47 +0900877 e = {
878 "type": "ref-updated",
879 "submitter": {
880 "name": "User Name",
881 },
882 "refUpdate": {
883 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
884 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
885 "refName": "master",
886 "project": "org/project",
887 }
888 }
James E. Blairdaabed22012-08-15 15:38:57 -0700889 self.fake_gerrit.addEvent(e)
890 self.waitUntilSettled()
891
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400892 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400893 self.assertEqual(len(self.history), 1)
894 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -0700895
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700896 def test_post_ignore_deletes(self):
897 "Test that deleting refs does not trigger post jobs"
898
899 e = {
900 "type": "ref-updated",
901 "submitter": {
902 "name": "User Name",
903 },
904 "refUpdate": {
905 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
906 "newRev": "0000000000000000000000000000000000000000",
907 "refName": "master",
908 "project": "org/project",
909 }
910 }
911 self.fake_gerrit.addEvent(e)
912 self.waitUntilSettled()
913
914 job_names = [x.name for x in self.history]
915 self.assertEqual(len(self.history), 0)
916 self.assertNotIn('project-post', job_names)
917
918 def test_post_ignore_deletes_negative(self):
919 "Test that deleting refs does trigger post jobs"
920
921 self.config.set('zuul', 'layout_config',
922 'tests/fixtures/layout-dont-ignore-deletes.yaml')
923 self.sched.reconfigure(self.config)
924
925 e = {
926 "type": "ref-updated",
927 "submitter": {
928 "name": "User Name",
929 },
930 "refUpdate": {
931 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
932 "newRev": "0000000000000000000000000000000000000000",
933 "refName": "master",
934 "project": "org/project",
935 }
936 }
937 self.fake_gerrit.addEvent(e)
938 self.waitUntilSettled()
939
940 job_names = [x.name for x in self.history]
941 self.assertEqual(len(self.history), 1)
942 self.assertIn('project-post', job_names)
943
James E. Blairc6294a52012-08-17 10:19:48 -0700944 def test_build_configuration_branch(self):
945 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700946
947 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700948 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
949 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
950 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
951 A.addApproval('CRVW', 2)
952 B.addApproval('CRVW', 2)
953 C.addApproval('CRVW', 2)
954 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
955 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
956 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
957 self.waitUntilSettled()
958
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700959 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700960 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700961 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700962 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700963 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700964 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700965 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700966 ref = self.getParameter(queue[-1], 'ZUUL_REF')
967 self.gearman_server.hold_jobs_in_queue = False
968 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -0700969 self.waitUntilSettled()
970
Monty Taylorbc758832013-06-17 17:22:42 -0400971 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -0700972 repo = git.Repo(path)
973 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
974 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -0700975 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400976 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -0700977
978 def test_build_configuration_branch_interaction(self):
979 "Test that switching between branches works"
980 self.test_build_configuration()
981 self.test_build_configuration_branch()
982 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -0400983 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -0700984 repo = git.Repo(path)
985 repo.heads.master.commit = repo.commit('init')
986 self.test_build_configuration()
987
988 def test_build_configuration_multi_branch(self):
989 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700990
991 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700992 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
993 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
994 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
995 A.addApproval('CRVW', 2)
996 B.addApproval('CRVW', 2)
997 C.addApproval('CRVW', 2)
998 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
999 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1000 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1001 self.waitUntilSettled()
James E. Blairbb1fe502014-03-04 10:15:06 -08001002 queue = self.gearman_server.getQueue()
1003 job_A = None
1004 for job in queue:
1005 if 'project-merge' in job.name:
1006 job_A = job
1007 ref_A = self.getParameter(job_A, 'ZUUL_REF')
1008 commit_A = self.getParameter(job_A, 'ZUUL_COMMIT')
1009 self.log.debug("Got Zuul ref for change A: %s" % ref_A)
1010 self.log.debug("Got Zuul commit for change A: %s" % commit_A)
James E. Blairc6294a52012-08-17 10:19:48 -07001011
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001012 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001013 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001014 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001015 job_B = None
1016 for job in queue:
1017 if 'project-merge' in job.name:
1018 job_B = job
1019 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001020 commit_B = self.getParameter(job_B, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001021 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blairbb1fe502014-03-04 10:15:06 -08001022 self.log.debug("Got Zuul commit for change B: %s" % commit_B)
1023
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001024 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001025 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001026 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001027 for job in queue:
1028 if 'project-merge' in job.name:
1029 job_C = job
1030 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001031 commit_C = self.getParameter(job_C, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001032 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blairbb1fe502014-03-04 10:15:06 -08001033 self.log.debug("Got Zuul commit for change C: %s" % commit_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001034 self.gearman_server.hold_jobs_in_queue = False
1035 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001036 self.waitUntilSettled()
1037
Monty Taylorbc758832013-06-17 17:22:42 -04001038 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001039 repo = git.Repo(path)
1040
1041 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001042 for c in repo.iter_commits(ref_C)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001043 repo_shas = [c.hexsha for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001044 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001045 correct_messages = ['initial commit', 'A-1', 'C-1']
James E. Blairbb1fe502014-03-04 10:15:06 -08001046 # Ensure the right commits are in the history for this ref
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001047 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001048 # Ensure ZUUL_REF -> ZUUL_COMMIT
1049 self.assertEqual(repo_shas[0], commit_C)
James E. Blairc6294a52012-08-17 10:19:48 -07001050
1051 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001052 for c in repo.iter_commits(ref_B)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001053 repo_shas = [c.hexsha for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001054 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001055 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001056 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001057 self.assertEqual(repo_shas[0], commit_B)
1058
1059 repo_messages = [c.message.strip()
1060 for c in repo.iter_commits(ref_A)]
1061 repo_shas = [c.hexsha for c in repo.iter_commits(ref_A)]
1062 repo_messages.reverse()
1063 correct_messages = ['initial commit', 'A-1']
1064 self.assertEqual(repo_messages, correct_messages)
1065 self.assertEqual(repo_shas[0], commit_A)
1066
1067 self.assertNotEqual(ref_A, ref_B, ref_C)
1068 self.assertNotEqual(commit_A, commit_B, commit_C)
James E. Blair7f71c802012-08-22 13:04:32 -07001069
1070 def test_one_job_project(self):
1071 "Test that queueing works with one job"
1072 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1073 'master', 'A')
1074 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1075 'master', 'B')
1076 A.addApproval('CRVW', 2)
1077 B.addApproval('CRVW', 2)
1078 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1079 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1080 self.waitUntilSettled()
1081
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001082 self.assertEqual(A.data['status'], 'MERGED')
1083 self.assertEqual(A.reported, 2)
1084 self.assertEqual(B.data['status'], 'MERGED')
1085 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001086
Antoine Musso80edd5a2013-02-13 15:37:53 +01001087 def test_job_from_templates_launched(self):
1088 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001089
Antoine Musso80edd5a2013-02-13 15:37:53 +01001090 A = self.fake_gerrit.addFakeChange(
1091 'org/templated-project', 'master', 'A')
1092 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1093 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001094
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001095 self.assertEqual(self.getJobFromHistory('project-test1').result,
1096 'SUCCESS')
1097 self.assertEqual(self.getJobFromHistory('project-test2').result,
1098 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001099
James E. Blair3e98c022013-12-16 15:25:38 -08001100 def test_layered_templates(self):
1101 "Test whether a job generated via a template can be launched"
1102
1103 A = self.fake_gerrit.addFakeChange(
1104 'org/layered-project', 'master', 'A')
1105 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1106 self.waitUntilSettled()
1107
1108 self.assertEqual(self.getJobFromHistory('project-test1').result,
1109 'SUCCESS')
1110 self.assertEqual(self.getJobFromHistory('project-test2').result,
1111 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001112 self.assertEqual(self.getJobFromHistory('layered-project-test3'
1113 ).result, 'SUCCESS')
1114 self.assertEqual(self.getJobFromHistory('layered-project-test4'
1115 ).result, 'SUCCESS')
James E. Blair12a92b12014-03-26 11:54:53 -07001116 self.assertEqual(self.getJobFromHistory('layered-project-foo-test5'
1117 ).result, 'SUCCESS')
James E. Blair3e98c022013-12-16 15:25:38 -08001118 self.assertEqual(self.getJobFromHistory('project-test6').result,
1119 'SUCCESS')
1120
James E. Blaircaec0c52012-08-22 14:52:22 -07001121 def test_dependent_changes_dequeue(self):
1122 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001123
James E. Blaircaec0c52012-08-22 14:52:22 -07001124 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1125 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1126 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1127 A.addApproval('CRVW', 2)
1128 B.addApproval('CRVW', 2)
1129 C.addApproval('CRVW', 2)
1130
1131 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1132 M1.setMerged()
1133
1134 # C -> B -> A -> M1
1135
1136 C.setDependsOn(B, 1)
1137 B.setDependsOn(A, 1)
1138 A.setDependsOn(M1, 1)
1139
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001140 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001141
1142 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1143 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1144 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1145
1146 self.waitUntilSettled()
1147
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001148 self.assertEqual(A.data['status'], 'NEW')
1149 self.assertEqual(A.reported, 2)
1150 self.assertEqual(B.data['status'], 'NEW')
1151 self.assertEqual(B.reported, 2)
1152 self.assertEqual(C.data['status'], 'NEW')
1153 self.assertEqual(C.reported, 2)
1154 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001155
James E. Blair972e3c72013-08-29 12:04:55 -07001156 def test_failing_dependent_changes(self):
1157 "Test that failing dependent patches are taken out of stream"
1158 self.worker.hold_jobs_in_build = True
1159 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1160 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1161 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1162 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1163 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1164 A.addApproval('CRVW', 2)
1165 B.addApproval('CRVW', 2)
1166 C.addApproval('CRVW', 2)
1167 D.addApproval('CRVW', 2)
1168 E.addApproval('CRVW', 2)
1169
1170 # E, D -> C -> B, A
1171
1172 D.setDependsOn(C, 1)
1173 C.setDependsOn(B, 1)
1174
1175 self.worker.addFailTest('project-test1', B)
1176
1177 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1178 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1179 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1180 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1181 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1182
1183 self.waitUntilSettled()
1184 self.worker.release('.*-merge')
1185 self.waitUntilSettled()
1186 self.worker.release('.*-merge')
1187 self.waitUntilSettled()
1188 self.worker.release('.*-merge')
1189 self.waitUntilSettled()
1190 self.worker.release('.*-merge')
1191 self.waitUntilSettled()
1192 self.worker.release('.*-merge')
1193 self.waitUntilSettled()
1194
1195 self.worker.hold_jobs_in_build = False
1196 for build in self.builds:
1197 if build.parameters['ZUUL_CHANGE'] != '1':
1198 build.release()
1199 self.waitUntilSettled()
1200
1201 self.worker.release()
1202 self.waitUntilSettled()
1203
1204 self.assertEqual(A.data['status'], 'MERGED')
1205 self.assertEqual(A.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001206 self.assertIn('Build succeeded', A.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001207 self.assertEqual(B.data['status'], 'NEW')
1208 self.assertEqual(B.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001209 self.assertIn('Build failed', B.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001210 self.assertEqual(C.data['status'], 'NEW')
1211 self.assertEqual(C.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001212 self.assertIn('depends on a change', C.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001213 self.assertEqual(D.data['status'], 'NEW')
1214 self.assertEqual(D.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001215 self.assertIn('depends on a change', D.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001216 self.assertEqual(E.data['status'], 'MERGED')
1217 self.assertEqual(E.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001218 self.assertIn('Build succeeded', E.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001219 self.assertEqual(len(self.history), 18)
1220
James E. Blairec590122012-08-22 15:19:31 -07001221 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001222 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001223 # If it's dequeued more than once, we should see extra
1224 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001225
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001226 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001227 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1228 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1229 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1230 A.addApproval('CRVW', 2)
1231 B.addApproval('CRVW', 2)
1232 C.addApproval('CRVW', 2)
1233
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001234 self.worker.addFailTest('project1-test1', A)
1235 self.worker.addFailTest('project1-test2', A)
1236 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001237
1238 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1239 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1240 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1241
1242 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001243
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001244 self.assertEqual(len(self.builds), 1)
1245 self.assertEqual(self.builds[0].name, 'project1-merge')
1246 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001247
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001248 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001249 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001250 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001251 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001252 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001253 self.waitUntilSettled()
1254
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001255 self.assertEqual(len(self.builds), 9)
1256 self.assertEqual(self.builds[0].name, 'project1-test1')
1257 self.assertEqual(self.builds[1].name, 'project1-test2')
1258 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1259 self.assertEqual(self.builds[3].name, 'project1-test1')
1260 self.assertEqual(self.builds[4].name, 'project1-test2')
1261 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1262 self.assertEqual(self.builds[6].name, 'project1-test1')
1263 self.assertEqual(self.builds[7].name, 'project1-test2')
1264 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001265
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001266 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001267 self.waitUntilSettled()
1268
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001269 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1270 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001271
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001272 self.worker.hold_jobs_in_build = False
1273 self.worker.release()
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), 0)
1277 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001278
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001279 self.assertEqual(A.data['status'], 'NEW')
1280 self.assertEqual(B.data['status'], 'MERGED')
1281 self.assertEqual(C.data['status'], 'MERGED')
1282 self.assertEqual(A.reported, 2)
1283 self.assertEqual(B.reported, 2)
1284 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001285
1286 def test_nonvoting_job(self):
1287 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001288
James E. Blair4ec821f2012-08-23 15:28:28 -07001289 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1290 'master', 'A')
1291 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001292 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001293 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1294
1295 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001296
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001297 self.assertEqual(A.data['status'], 'MERGED')
1298 self.assertEqual(A.reported, 2)
1299 self.assertEqual(
1300 self.getJobFromHistory('nonvoting-project-merge').result,
1301 'SUCCESS')
1302 self.assertEqual(
1303 self.getJobFromHistory('nonvoting-project-test1').result,
1304 'SUCCESS')
1305 self.assertEqual(
1306 self.getJobFromHistory('nonvoting-project-test2').result,
1307 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001308
James E. Blair5821bd92015-09-16 08:48:15 -07001309 for build in self.builds:
1310 self.assertEqual(build.parameters['ZUUL_VOTING'], '0')
1311
James E. Blaire0487072012-08-29 17:38:31 -07001312 def test_check_queue_success(self):
1313 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001314
James E. Blaire0487072012-08-29 17:38:31 -07001315 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1316 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1317
1318 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001319
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001320 self.assertEqual(A.data['status'], 'NEW')
1321 self.assertEqual(A.reported, 1)
1322 self.assertEqual(self.getJobFromHistory('project-merge').result,
1323 'SUCCESS')
1324 self.assertEqual(self.getJobFromHistory('project-test1').result,
1325 'SUCCESS')
1326 self.assertEqual(self.getJobFromHistory('project-test2').result,
1327 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001328
1329 def test_check_queue_failure(self):
1330 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001331
James E. Blaire0487072012-08-29 17:38:31 -07001332 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001333 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001334 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1335
1336 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001337
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001338 self.assertEqual(A.data['status'], 'NEW')
1339 self.assertEqual(A.reported, 1)
1340 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001341 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001342 self.assertEqual(self.getJobFromHistory('project-test1').result,
1343 'SUCCESS')
1344 self.assertEqual(self.getJobFromHistory('project-test2').result,
1345 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001346
1347 def test_dependent_behind_dequeue(self):
1348 "test that dependent changes behind dequeued changes work"
1349 # This complicated test is a reproduction of a real life bug
1350 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001351
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001352 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001353 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1354 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1355 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1356 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1357 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1358 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1359 D.setDependsOn(C, 1)
1360 E.setDependsOn(D, 1)
1361 A.addApproval('CRVW', 2)
1362 B.addApproval('CRVW', 2)
1363 C.addApproval('CRVW', 2)
1364 D.addApproval('CRVW', 2)
1365 E.addApproval('CRVW', 2)
1366 F.addApproval('CRVW', 2)
1367
1368 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001369
1370 # Change object re-use in the gerrit trigger is hidden if
1371 # changes are added in quick succession; waiting makes it more
1372 # like real life.
1373 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1374 self.waitUntilSettled()
1375 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1376 self.waitUntilSettled()
1377
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001378 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001379 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001380 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001381 self.waitUntilSettled()
1382
1383 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1384 self.waitUntilSettled()
1385 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1386 self.waitUntilSettled()
1387 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1388 self.waitUntilSettled()
1389 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1390 self.waitUntilSettled()
1391
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001392 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001393 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001394 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001395 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001396 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001397 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001398 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001399 self.waitUntilSettled()
1400
1401 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001402
1403 # Grab pointers to the jobs we want to release before
1404 # releasing any, because list indexes may change as
1405 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001406 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001407 a.release()
1408 b.release()
1409 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001410 self.waitUntilSettled()
1411
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001412 self.worker.hold_jobs_in_build = False
1413 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001414 self.waitUntilSettled()
1415
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001416 self.assertEqual(A.data['status'], 'NEW')
1417 self.assertEqual(B.data['status'], 'MERGED')
1418 self.assertEqual(C.data['status'], 'MERGED')
1419 self.assertEqual(D.data['status'], 'MERGED')
1420 self.assertEqual(E.data['status'], 'MERGED')
1421 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07001422
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001423 self.assertEqual(A.reported, 2)
1424 self.assertEqual(B.reported, 2)
1425 self.assertEqual(C.reported, 2)
1426 self.assertEqual(D.reported, 2)
1427 self.assertEqual(E.reported, 2)
1428 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07001429
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001430 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
1431 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07001432
1433 def test_merger_repack(self):
1434 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001435
James E. Blair05fed602012-09-07 12:45:24 -07001436 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1437 A.addApproval('CRVW', 2)
1438 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1439 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001440 self.assertEqual(self.getJobFromHistory('project-merge').result,
1441 'SUCCESS')
1442 self.assertEqual(self.getJobFromHistory('project-test1').result,
1443 'SUCCESS')
1444 self.assertEqual(self.getJobFromHistory('project-test2').result,
1445 'SUCCESS')
1446 self.assertEqual(A.data['status'], 'MERGED')
1447 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07001448 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001449 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001450
Monty Taylorbc758832013-06-17 17:22:42 -04001451 path = os.path.join(self.git_root, "org/project")
1452 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07001453
1454 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1455 A.addApproval('CRVW', 2)
1456 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1457 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001458 self.assertEqual(self.getJobFromHistory('project-merge').result,
1459 'SUCCESS')
1460 self.assertEqual(self.getJobFromHistory('project-test1').result,
1461 'SUCCESS')
1462 self.assertEqual(self.getJobFromHistory('project-test2').result,
1463 'SUCCESS')
1464 self.assertEqual(A.data['status'], 'MERGED')
1465 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001466
James E. Blair4886f282012-11-15 09:27:33 -08001467 def test_merger_repack_large_change(self):
1468 "Test that the merger works with large changes after a repack"
1469 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08001470 # This test assumes the repo is already cloned; make sure it is
Joshua Hesketh352264b2015-08-11 23:42:08 +10001471 url = self.fake_gerrit.getGitUrl(
James E. Blairac2c3242014-01-24 13:38:51 -08001472 self.sched.layout.projects['org/project1'])
James E. Blair4076e2b2014-01-28 12:42:20 -08001473 self.merge_server.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08001474 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1475 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001476 path = os.path.join(self.upstream_root, "org/project1")
1477 print repack_repo(path)
1478 path = os.path.join(self.git_root, "org/project1")
1479 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08001480
1481 A.addApproval('CRVW', 2)
1482 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1483 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001484 self.assertEqual(self.getJobFromHistory('project1-merge').result,
1485 'SUCCESS')
1486 self.assertEqual(self.getJobFromHistory('project1-test1').result,
1487 'SUCCESS')
1488 self.assertEqual(self.getJobFromHistory('project1-test2').result,
1489 'SUCCESS')
1490 self.assertEqual(A.data['status'], 'MERGED')
1491 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08001492
James E. Blair7ee88a22012-09-12 18:59:31 +02001493 def test_nonexistent_job(self):
1494 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001495 # Set to the state immediately after a restart
1496 self.resetGearmanServer()
1497 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001498
1499 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1500 A.addApproval('CRVW', 2)
1501 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1502 # There may be a thread about to report a lost change
1503 while A.reported < 2:
1504 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001505 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001506 self.assertFalse(job_names)
1507 self.assertEqual(A.data['status'], 'NEW')
1508 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001509 self.assertEmptyQueues()
1510
1511 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001512 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001513 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1514 A.addApproval('CRVW', 2)
1515 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1516 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001517 self.assertEqual(self.getJobFromHistory('project-merge').result,
1518 'SUCCESS')
1519 self.assertEqual(self.getJobFromHistory('project-test1').result,
1520 'SUCCESS')
1521 self.assertEqual(self.getJobFromHistory('project-test2').result,
1522 'SUCCESS')
1523 self.assertEqual(A.data['status'], 'MERGED')
1524 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08001525
1526 def test_single_nonexistent_post_job(self):
1527 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001528 e = {
1529 "type": "ref-updated",
1530 "submitter": {
1531 "name": "User Name",
1532 },
1533 "refUpdate": {
1534 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1535 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1536 "refName": "master",
1537 "project": "org/project",
1538 }
1539 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001540 # Set to the state immediately after a restart
1541 self.resetGearmanServer()
1542 self.launcher.negative_function_cache_ttl = 0
1543
James E. Blairf62d4282012-12-31 17:01:50 -08001544 self.fake_gerrit.addEvent(e)
1545 self.waitUntilSettled()
1546
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001547 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08001548
1549 def test_new_patchset_dequeues_old(self):
1550 "Test that a new patchset causes the old to be dequeued"
1551 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001552 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001553 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1554 M.setMerged()
1555
1556 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1557 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1558 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1559 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1560 A.addApproval('CRVW', 2)
1561 B.addApproval('CRVW', 2)
1562 C.addApproval('CRVW', 2)
1563 D.addApproval('CRVW', 2)
1564
1565 C.setDependsOn(B, 1)
1566 B.setDependsOn(A, 1)
1567 A.setDependsOn(M, 1)
1568
1569 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1570 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1571 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1572 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1573 self.waitUntilSettled()
1574
1575 B.addPatchset()
1576 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1577 self.waitUntilSettled()
1578
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001579 self.worker.hold_jobs_in_build = False
1580 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001581 self.waitUntilSettled()
1582
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001583 self.assertEqual(A.data['status'], 'MERGED')
1584 self.assertEqual(A.reported, 2)
1585 self.assertEqual(B.data['status'], 'NEW')
1586 self.assertEqual(B.reported, 2)
1587 self.assertEqual(C.data['status'], 'NEW')
1588 self.assertEqual(C.reported, 2)
1589 self.assertEqual(D.data['status'], 'MERGED')
1590 self.assertEqual(D.reported, 2)
1591 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001592
James E. Blairba437362015-02-07 11:41:52 -08001593 def test_new_patchset_check(self):
1594 "Test a new patchset in check"
Antoine Mussobd86a312014-01-08 14:51:33 +01001595
1596 self.worker.hold_jobs_in_build = True
1597
1598 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairba437362015-02-07 11:41:52 -08001599 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1600 check_pipeline = self.sched.layout.pipelines['check']
1601
1602 # Add two git-dependent changes
1603 B.setDependsOn(A, 1)
1604 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1605 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001606 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1607 self.waitUntilSettled()
James E. Blairba437362015-02-07 11:41:52 -08001608
1609 # A live item, and a non-live/live pair
1610 items = check_pipeline.getAllItems()
1611 self.assertEqual(len(items), 3)
1612
1613 self.assertEqual(items[0].change.number, '1')
1614 self.assertEqual(items[0].change.patchset, '1')
1615 self.assertFalse(items[0].live)
1616
1617 self.assertEqual(items[1].change.number, '2')
1618 self.assertEqual(items[1].change.patchset, '1')
1619 self.assertTrue(items[1].live)
1620
1621 self.assertEqual(items[2].change.number, '1')
1622 self.assertEqual(items[2].change.patchset, '1')
1623 self.assertTrue(items[2].live)
1624
1625 # Add a new patchset to A
1626 A.addPatchset()
1627 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1628 self.waitUntilSettled()
1629
1630 # The live copy of A,1 should be gone, but the non-live and B
1631 # should continue, and we should have a new A,2
1632 items = check_pipeline.getAllItems()
1633 self.assertEqual(len(items), 3)
1634
1635 self.assertEqual(items[0].change.number, '1')
1636 self.assertEqual(items[0].change.patchset, '1')
1637 self.assertFalse(items[0].live)
1638
1639 self.assertEqual(items[1].change.number, '2')
1640 self.assertEqual(items[1].change.patchset, '1')
1641 self.assertTrue(items[1].live)
1642
1643 self.assertEqual(items[2].change.number, '1')
1644 self.assertEqual(items[2].change.patchset, '2')
1645 self.assertTrue(items[2].live)
1646
1647 # Add a new patchset to B
1648 B.addPatchset()
1649 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1650 self.waitUntilSettled()
1651
1652 # The live copy of B,1 should be gone, and it's non-live copy of A,1
1653 # but we should have a new B,2 (still based on A,1)
1654 items = check_pipeline.getAllItems()
1655 self.assertEqual(len(items), 3)
1656
1657 self.assertEqual(items[0].change.number, '1')
1658 self.assertEqual(items[0].change.patchset, '2')
1659 self.assertTrue(items[0].live)
1660
1661 self.assertEqual(items[1].change.number, '1')
1662 self.assertEqual(items[1].change.patchset, '1')
1663 self.assertFalse(items[1].live)
1664
1665 self.assertEqual(items[2].change.number, '2')
1666 self.assertEqual(items[2].change.patchset, '2')
1667 self.assertTrue(items[2].live)
1668
1669 self.builds[0].release()
1670 self.waitUntilSettled()
1671 self.builds[0].release()
1672 self.waitUntilSettled()
1673 self.worker.hold_jobs_in_build = False
1674 self.worker.release()
1675 self.waitUntilSettled()
1676
1677 self.assertEqual(A.reported, 1)
1678 self.assertEqual(B.reported, 1)
1679 self.assertEqual(self.history[0].result, 'ABORTED')
1680 self.assertEqual(self.history[0].changes, '1,1')
1681 self.assertEqual(self.history[1].result, 'ABORTED')
1682 self.assertEqual(self.history[1].changes, '1,1 2,1')
1683 self.assertEqual(self.history[2].result, 'SUCCESS')
1684 self.assertEqual(self.history[2].changes, '1,2')
1685 self.assertEqual(self.history[3].result, 'SUCCESS')
1686 self.assertEqual(self.history[3].changes, '1,1 2,2')
1687
1688 def test_abandoned_gate(self):
1689 "Test that an abandoned change is dequeued from gate"
1690
1691 self.worker.hold_jobs_in_build = True
1692
1693 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1694 A.addApproval('CRVW', 2)
1695 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1696 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001697 self.assertEqual(len(self.builds), 1, "One job being built (on hold)")
1698 self.assertEqual(self.builds[0].name, 'project-merge')
1699
1700 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1701 self.waitUntilSettled()
1702
Antoine Mussobd86a312014-01-08 14:51:33 +01001703 self.worker.release('.*-merge')
1704 self.waitUntilSettled()
1705
1706 self.assertEqual(len(self.builds), 0, "No job running")
Antoine Mussobd86a312014-01-08 14:51:33 +01001707 self.assertEqual(len(self.history), 1, "Only one build in history")
1708 self.assertEqual(self.history[0].result, 'ABORTED',
James E. Blairba437362015-02-07 11:41:52 -08001709 "Build should have been aborted")
1710 self.assertEqual(A.reported, 1,
1711 "Abandoned gate change should report only start")
1712
1713 def test_abandoned_check(self):
1714 "Test that an abandoned change is dequeued from check"
1715
1716 self.worker.hold_jobs_in_build = True
1717
1718 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1719 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1720 check_pipeline = self.sched.layout.pipelines['check']
1721
1722 # Add two git-dependent changes
1723 B.setDependsOn(A, 1)
1724 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1725 self.waitUntilSettled()
1726 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1727 self.waitUntilSettled()
1728 # A live item, and a non-live/live pair
1729 items = check_pipeline.getAllItems()
1730 self.assertEqual(len(items), 3)
1731
1732 self.assertEqual(items[0].change.number, '1')
1733 self.assertFalse(items[0].live)
1734
1735 self.assertEqual(items[1].change.number, '2')
1736 self.assertTrue(items[1].live)
1737
1738 self.assertEqual(items[2].change.number, '1')
1739 self.assertTrue(items[2].live)
1740
1741 # Abandon A
1742 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1743 self.waitUntilSettled()
1744
1745 # The live copy of A should be gone, but the non-live and B
1746 # should continue
1747 items = check_pipeline.getAllItems()
1748 self.assertEqual(len(items), 2)
1749
1750 self.assertEqual(items[0].change.number, '1')
1751 self.assertFalse(items[0].live)
1752
1753 self.assertEqual(items[1].change.number, '2')
1754 self.assertTrue(items[1].live)
1755
1756 self.worker.hold_jobs_in_build = False
1757 self.worker.release()
1758 self.waitUntilSettled()
1759
1760 self.assertEqual(len(self.history), 4)
1761 self.assertEqual(self.history[0].result, 'ABORTED',
Antoine Mussobd86a312014-01-08 14:51:33 +01001762 'Build should have been aborted')
1763 self.assertEqual(A.reported, 0, "Abandoned change should not report")
James E. Blairba437362015-02-07 11:41:52 -08001764 self.assertEqual(B.reported, 1, "Change should report")
Antoine Mussobd86a312014-01-08 14:51:33 +01001765
Steve Varnau7b78b312015-04-03 14:49:46 -07001766 def test_abandoned_not_timer(self):
1767 "Test that an abandoned change does not cancel timer jobs"
1768
1769 self.worker.hold_jobs_in_build = True
1770
1771 # Start timer trigger - also org/project
1772 self.config.set('zuul', 'layout_config',
1773 'tests/fixtures/layout-idle.yaml')
1774 self.sched.reconfigure(self.config)
1775 self.registerJobs()
1776 # The pipeline triggers every second, so we should have seen
1777 # several by now.
1778 time.sleep(5)
1779 self.waitUntilSettled()
1780 # Stop queuing timer triggered jobs so that the assertions
1781 # below don't race against more jobs being queued.
1782 self.config.set('zuul', 'layout_config',
1783 'tests/fixtures/layout-no-timer.yaml')
1784 self.sched.reconfigure(self.config)
1785 self.registerJobs()
1786 self.assertEqual(len(self.builds), 2, "Two timer jobs")
1787
1788 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1789 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1790 self.waitUntilSettled()
1791 self.assertEqual(len(self.builds), 3, "One change plus two timer jobs")
1792
1793 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1794 self.waitUntilSettled()
1795
1796 self.assertEqual(len(self.builds), 2, "Two timer jobs remain")
1797
1798 self.worker.release()
1799 self.waitUntilSettled()
1800
Arx Cruzb1b010d2013-10-28 19:49:59 -02001801 def test_zuul_url_return(self):
1802 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
James E. Blair4076e2b2014-01-28 12:42:20 -08001803 self.assertTrue(self.sched.config.has_option('merger', 'zuul_url'))
Arx Cruzb1b010d2013-10-28 19:49:59 -02001804 self.worker.hold_jobs_in_build = True
1805
1806 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1807 A.addApproval('CRVW', 2)
1808 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1809 self.waitUntilSettled()
1810
1811 self.assertEqual(len(self.builds), 1)
1812 for build in self.builds:
1813 self.assertTrue('ZUUL_URL' in build.parameters)
1814
1815 self.worker.hold_jobs_in_build = False
1816 self.worker.release()
1817 self.waitUntilSettled()
1818
James E. Blair2fa50962013-01-30 21:50:41 -08001819 def test_new_patchset_dequeues_old_on_head(self):
1820 "Test that a new patchset causes the old to be dequeued (at head)"
1821 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001822 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001823 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1824 M.setMerged()
1825 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1826 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1827 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1828 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1829 A.addApproval('CRVW', 2)
1830 B.addApproval('CRVW', 2)
1831 C.addApproval('CRVW', 2)
1832 D.addApproval('CRVW', 2)
1833
1834 C.setDependsOn(B, 1)
1835 B.setDependsOn(A, 1)
1836 A.setDependsOn(M, 1)
1837
1838 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1839 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1840 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1841 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1842 self.waitUntilSettled()
1843
1844 A.addPatchset()
1845 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1846 self.waitUntilSettled()
1847
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001848 self.worker.hold_jobs_in_build = False
1849 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001850 self.waitUntilSettled()
1851
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001852 self.assertEqual(A.data['status'], 'NEW')
1853 self.assertEqual(A.reported, 2)
1854 self.assertEqual(B.data['status'], 'NEW')
1855 self.assertEqual(B.reported, 2)
1856 self.assertEqual(C.data['status'], 'NEW')
1857 self.assertEqual(C.reported, 2)
1858 self.assertEqual(D.data['status'], 'MERGED')
1859 self.assertEqual(D.reported, 2)
1860 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08001861
1862 def test_new_patchset_dequeues_old_without_dependents(self):
1863 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001864 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001865 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1866 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1867 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1868 A.addApproval('CRVW', 2)
1869 B.addApproval('CRVW', 2)
1870 C.addApproval('CRVW', 2)
1871
1872 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1873 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1874 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1875 self.waitUntilSettled()
1876
1877 B.addPatchset()
1878 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1879 self.waitUntilSettled()
1880
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001881 self.worker.hold_jobs_in_build = False
1882 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001883 self.waitUntilSettled()
1884
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001885 self.assertEqual(A.data['status'], 'MERGED')
1886 self.assertEqual(A.reported, 2)
1887 self.assertEqual(B.data['status'], 'NEW')
1888 self.assertEqual(B.reported, 2)
1889 self.assertEqual(C.data['status'], 'MERGED')
1890 self.assertEqual(C.reported, 2)
1891 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08001892
1893 def test_new_patchset_dequeues_old_independent_queue(self):
1894 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001895 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001896 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1897 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1898 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1899 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1900 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1901 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1902 self.waitUntilSettled()
1903
1904 B.addPatchset()
1905 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1906 self.waitUntilSettled()
1907
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001908 self.worker.hold_jobs_in_build = False
1909 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001910 self.waitUntilSettled()
1911
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001912 self.assertEqual(A.data['status'], 'NEW')
1913 self.assertEqual(A.reported, 1)
1914 self.assertEqual(B.data['status'], 'NEW')
1915 self.assertEqual(B.reported, 1)
1916 self.assertEqual(C.data['status'], 'NEW')
1917 self.assertEqual(C.reported, 1)
1918 self.assertEqual(len(self.history), 10)
1919 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001920
James E. Blair18c64442014-03-18 10:14:45 -07001921 def test_noop_job(self):
1922 "Test that the internal noop job works"
1923 A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A')
1924 A.addApproval('CRVW', 2)
1925 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1926 self.waitUntilSettled()
1927
1928 self.assertEqual(len(self.gearman_server.getQueue()), 0)
1929 self.assertTrue(self.sched._areAllBuildsComplete())
1930 self.assertEqual(len(self.history), 0)
1931 self.assertEqual(A.data['status'], 'MERGED')
1932 self.assertEqual(A.reported, 2)
1933
Evgeny Antyshevd6e546c2015-06-11 15:13:57 +00001934 def test_no_job_project(self):
1935 "Test that reports with no jobs don't get sent"
1936 A = self.fake_gerrit.addFakeChange('org/no-jobs-project',
1937 'master', 'A')
1938 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1939 self.waitUntilSettled()
1940
1941 # Change wasn't reported to
1942 self.assertEqual(A.reported, False)
1943
1944 # Check queue is empty afterwards
1945 check_pipeline = self.sched.layout.pipelines['check']
1946 items = check_pipeline.getAllItems()
1947 self.assertEqual(len(items), 0)
1948
1949 self.assertEqual(len(self.history), 0)
1950
James E. Blair7d0dedc2013-02-21 17:26:09 -08001951 def test_zuul_refs(self):
1952 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001953 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08001954 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1955 M1.setMerged()
1956 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1957 M2.setMerged()
1958
1959 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1960 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1961 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1962 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1963 A.addApproval('CRVW', 2)
1964 B.addApproval('CRVW', 2)
1965 C.addApproval('CRVW', 2)
1966 D.addApproval('CRVW', 2)
1967 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1968 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1969 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1970 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1971
1972 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001973 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001974 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001975 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001976 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001977 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001978 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001979 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08001980 self.waitUntilSettled()
1981
James E. Blair7d0dedc2013-02-21 17:26:09 -08001982 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001983 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08001984 if x.parameters['ZUUL_CHANGE'] == '3':
1985 a_zref = x.parameters['ZUUL_REF']
1986 if x.parameters['ZUUL_CHANGE'] == '4':
1987 b_zref = x.parameters['ZUUL_REF']
1988 if x.parameters['ZUUL_CHANGE'] == '5':
1989 c_zref = x.parameters['ZUUL_REF']
1990 if x.parameters['ZUUL_CHANGE'] == '6':
1991 d_zref = x.parameters['ZUUL_REF']
1992
1993 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001994 self.assertIsNotNone(a_zref)
1995 self.assertIsNotNone(b_zref)
1996 self.assertIsNotNone(c_zref)
1997 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001998
1999 # And they should all be different
2000 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002001 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002002
2003 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002004 self.assertTrue(self.ref_has_change(a_zref, A))
2005 self.assertFalse(self.ref_has_change(a_zref, B))
2006 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002007
2008 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002009 self.assertTrue(self.ref_has_change(b_zref, A))
2010 self.assertTrue(self.ref_has_change(b_zref, B))
2011 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002012
2013 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002014 self.assertTrue(self.ref_has_change(c_zref, A))
2015 self.assertTrue(self.ref_has_change(c_zref, B))
2016 self.assertTrue(self.ref_has_change(c_zref, C))
2017 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002018
2019 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002020 self.assertTrue(self.ref_has_change(d_zref, A))
2021 self.assertTrue(self.ref_has_change(d_zref, B))
2022 self.assertTrue(self.ref_has_change(d_zref, C))
2023 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002024
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002025 self.worker.hold_jobs_in_build = False
2026 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002027 self.waitUntilSettled()
2028
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002029 self.assertEqual(A.data['status'], 'MERGED')
2030 self.assertEqual(A.reported, 2)
2031 self.assertEqual(B.data['status'], 'MERGED')
2032 self.assertEqual(B.reported, 2)
2033 self.assertEqual(C.data['status'], 'MERGED')
2034 self.assertEqual(C.reported, 2)
2035 self.assertEqual(D.data['status'], 'MERGED')
2036 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002037
James E. Blair4a28a882013-08-23 15:17:33 -07002038 def test_rerun_on_error(self):
2039 "Test that if a worker fails to run a job, it is run again"
2040 self.worker.hold_jobs_in_build = True
2041 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2042 A.addApproval('CRVW', 2)
2043 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2044 self.waitUntilSettled()
2045
2046 self.builds[0].run_error = True
2047 self.worker.hold_jobs_in_build = False
2048 self.worker.release()
2049 self.waitUntilSettled()
2050 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2051 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2052
James E. Blair412e5582013-04-22 15:50:12 -07002053 def test_statsd(self):
2054 "Test each of the statsd methods used in the scheduler"
2055 import extras
2056 statsd = extras.try_import('statsd.statsd')
2057 statsd.incr('test-incr')
2058 statsd.timing('test-timing', 3)
Alex Gaynor813d39b2014-05-17 16:17:16 -07002059 statsd.gauge('test-gauge', 12)
James E. Blair412e5582013-04-22 15:50:12 -07002060 self.assertReportedStat('test-incr', '1|c')
2061 self.assertReportedStat('test-timing', '3|ms')
Alex Gaynor813d39b2014-05-17 16:17:16 -07002062 self.assertReportedStat('test-gauge', '12|g')
James E. Blair412e5582013-04-22 15:50:12 -07002063
James E. Blairdad52252014-02-07 16:59:17 -08002064 def test_stuck_job_cleanup(self):
2065 "Test that pending jobs are cleaned up if removed from layout"
James E. Blair18c64442014-03-18 10:14:45 -07002066 # This job won't be registered at startup because it is not in
2067 # the standard layout, but we need it to already be registerd
2068 # for when we reconfigure, as that is when Zuul will attempt
2069 # to run the new job.
2070 self.worker.registerFunction('build:gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002071 self.gearman_server.hold_jobs_in_queue = True
2072 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2073 A.addApproval('CRVW', 2)
2074 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2075 self.waitUntilSettled()
2076 self.assertEqual(len(self.gearman_server.getQueue()), 1)
2077
2078 self.config.set('zuul', 'layout_config',
2079 'tests/fixtures/layout-no-jobs.yaml')
2080 self.sched.reconfigure(self.config)
2081 self.waitUntilSettled()
2082
James E. Blair18c64442014-03-18 10:14:45 -07002083 self.gearman_server.release('gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002084 self.waitUntilSettled()
2085 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2086 self.assertTrue(self.sched._areAllBuildsComplete())
2087
2088 self.assertEqual(len(self.history), 1)
James E. Blair18c64442014-03-18 10:14:45 -07002089 self.assertEqual(self.history[0].name, 'gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002090 self.assertEqual(self.history[0].result, 'SUCCESS')
2091
James E. Blair879dafb2015-07-17 14:04:49 -07002092 def test_file_head(self):
2093 # This is a regression test for an observed bug. A change
2094 # with a file named "HEAD" in the root directory of the repo
2095 # was processed by a merger. It then was unable to reset the
2096 # repo because of:
2097 # GitCommandError: 'git reset --hard HEAD' returned
2098 # with exit code 128
2099 # stderr: 'fatal: ambiguous argument 'HEAD': both revision
2100 # and filename
2101 # Use '--' to separate filenames from revisions'
2102
2103 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2104 A.addPatchset(['HEAD'])
2105 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2106
2107 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2108 self.waitUntilSettled()
2109
2110 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2111 self.waitUntilSettled()
2112
2113 self.assertIn('Build succeeded', A.messages[0])
2114 self.assertIn('Build succeeded', B.messages[0])
2115
James E. Blair70c71582013-03-06 08:50:50 -08002116 def test_file_jobs(self):
2117 "Test that file jobs run only when appropriate"
2118 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2119 A.addPatchset(['pip-requires'])
2120 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2121 A.addApproval('CRVW', 2)
2122 B.addApproval('CRVW', 2)
2123 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2124 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2125 self.waitUntilSettled()
2126
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002127 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002128 if x.name == 'project-testfile']
2129
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002130 self.assertEqual(len(testfile_jobs), 1)
2131 self.assertEqual(testfile_jobs[0].changes, '1,2')
2132 self.assertEqual(A.data['status'], 'MERGED')
2133 self.assertEqual(A.reported, 2)
2134 self.assertEqual(B.data['status'], 'MERGED')
2135 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002136
Maru Newby3fe5f852015-01-13 04:22:14 +00002137 def _test_skip_if_jobs(self, branch, should_skip):
2138 "Test that jobs with a skip-if filter run only when appropriate"
2139 self.config.set('zuul', 'layout_config',
2140 'tests/fixtures/layout-skip-if.yaml')
2141 self.sched.reconfigure(self.config)
2142 self.registerJobs()
2143
2144 change = self.fake_gerrit.addFakeChange('org/project',
2145 branch,
2146 'test skip-if')
2147 self.fake_gerrit.addEvent(change.getPatchsetCreatedEvent(1))
2148 self.waitUntilSettled()
2149
2150 tested_change_ids = [x.changes[0] for x in self.history
2151 if x.name == 'project-test-skip-if']
2152
2153 if should_skip:
2154 self.assertEqual([], tested_change_ids)
2155 else:
2156 self.assertIn(change.data['number'], tested_change_ids)
2157
2158 def test_skip_if_match_skips_job(self):
2159 self._test_skip_if_jobs(branch='master', should_skip=True)
2160
2161 def test_skip_if_no_match_runs_job(self):
2162 self._test_skip_if_jobs(branch='mp', should_skip=False)
2163
James E. Blair3c5e5b52013-04-26 11:17:03 -07002164 def test_test_config(self):
2165 "Test that we can test the config"
Joshua Hesketh352264b2015-08-11 23:42:08 +10002166 self.sched.testConfig(self.config.get('zuul', 'layout_config'),
2167 self.connections)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002168
2169 def test_build_description(self):
2170 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002171 self.worker.registerFunction('set_description:' +
2172 self.worker.worker_id)
2173
2174 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2175 A.addApproval('CRVW', 2)
2176 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2177 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002178 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002179 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002180 self.assertTrue(re.search("Branch.*master", desc))
2181 self.assertTrue(re.search("Pipeline.*gate", desc))
2182 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2183 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2184 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2185 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002186
James E. Blairc8a1e052014-02-25 09:29:26 -08002187 def test_queue_names(self):
2188 "Test shared change queue names"
2189 project1 = self.sched.layout.projects['org/project1']
2190 project2 = self.sched.layout.projects['org/project2']
2191 q1 = self.sched.layout.pipelines['gate'].getQueue(project1)
2192 q2 = self.sched.layout.pipelines['gate'].getQueue(project2)
2193 self.assertEqual(q1.name, 'integration')
2194 self.assertEqual(q2.name, 'integration')
2195
2196 self.config.set('zuul', 'layout_config',
2197 'tests/fixtures/layout-bad-queue.yaml')
2198 with testtools.ExpectedException(
2199 Exception, "More than one name assigned to change queue"):
2200 self.sched.reconfigure(self.config)
2201
James E. Blair64ed6f22013-07-10 14:07:23 -07002202 def test_queue_precedence(self):
2203 "Test that queue precedence works"
2204
2205 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002206 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002207 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2208 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2209 A.addApproval('CRVW', 2)
2210 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2211
2212 self.waitUntilSettled()
2213 self.gearman_server.hold_jobs_in_queue = False
2214 self.gearman_server.release()
2215 self.waitUntilSettled()
2216
James E. Blair8de58bd2013-07-18 16:23:33 -07002217 # Run one build at a time to ensure non-race order:
James E. Blairb8c16472015-05-05 14:55:26 -07002218 self.orderedRelease()
James E. Blair8de58bd2013-07-18 16:23:33 -07002219 self.worker.hold_jobs_in_build = False
2220 self.waitUntilSettled()
2221
James E. Blair64ed6f22013-07-10 14:07:23 -07002222 self.log.debug(self.history)
2223 self.assertEqual(self.history[0].pipeline, 'gate')
2224 self.assertEqual(self.history[1].pipeline, 'check')
2225 self.assertEqual(self.history[2].pipeline, 'gate')
2226 self.assertEqual(self.history[3].pipeline, 'gate')
2227 self.assertEqual(self.history[4].pipeline, 'check')
2228 self.assertEqual(self.history[5].pipeline, 'check')
2229
Clark Boylana5edbe42014-06-03 16:39:10 -07002230 def test_json_status(self):
James E. Blair1843a552013-07-03 14:19:52 -07002231 "Test that we can retrieve JSON status info"
2232 self.worker.hold_jobs_in_build = True
2233 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2234 A.addApproval('CRVW', 2)
2235 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2236 self.waitUntilSettled()
2237
James E. Blairb7273ef2016-04-19 08:58:51 -07002238 self.worker.release('project-merge')
2239 self.waitUntilSettled()
2240
James E. Blair1843a552013-07-03 14:19:52 -07002241 port = self.webapp.server.socket.getsockname()[1]
2242
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002243 req = urllib2.Request("http://localhost:%s/status.json" % port)
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002244 f = urllib2.urlopen(req)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002245 headers = f.info()
2246 self.assertIn('Content-Length', headers)
2247 self.assertIn('Content-Type', headers)
Sachi Kingdc963fc2016-03-23 16:00:33 +11002248 self.assertIsNotNone(re.match('^application/json(; charset=UTF-8)?$',
2249 headers['Content-Type']))
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002250 self.assertIn('Access-Control-Allow-Origin', headers)
2251 self.assertIn('Cache-Control', headers)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002252 self.assertIn('Last-Modified', headers)
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002253 self.assertIn('Expires', headers)
James E. Blair1843a552013-07-03 14:19:52 -07002254 data = f.read()
2255
2256 self.worker.hold_jobs_in_build = False
2257 self.worker.release()
2258 self.waitUntilSettled()
2259
2260 data = json.loads(data)
James E. Blairb7273ef2016-04-19 08:58:51 -07002261 status_jobs = []
James E. Blair1843a552013-07-03 14:19:52 -07002262 for p in data['pipelines']:
2263 for q in p['change_queues']:
James E. Blairbfb8e042014-12-30 17:01:44 -08002264 if p['name'] in ['gate', 'conflict']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002265 self.assertEqual(q['window'], 20)
2266 else:
2267 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002268 for head in q['heads']:
2269 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002270 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002271 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002272 for job in change['jobs']:
James E. Blairb7273ef2016-04-19 08:58:51 -07002273 status_jobs.append(job)
2274 self.assertEqual('project-merge', status_jobs[0]['name'])
2275 self.assertEqual('https://server/job/project-merge/0/',
2276 status_jobs[0]['url'])
2277 self.assertEqual('http://logs.example.com/1/1/gate/project-merge/0',
2278 status_jobs[0]['report_url'])
2279
2280 self.assertEqual('project-test1', status_jobs[1]['name'])
2281 self.assertEqual('https://server/job/project-test1/1/',
2282 status_jobs[1]['url'])
2283 self.assertEqual('http://logs.example.com/1/1/gate/project-test1/1',
2284 status_jobs[1]['report_url'])
2285
2286 self.assertEqual('project-test2', status_jobs[2]['name'])
2287 self.assertEqual('https://server/job/project-test2/2/',
2288 status_jobs[2]['url'])
2289 self.assertEqual('http://logs.example.com/1/1/gate/project-test2/2',
2290 status_jobs[2]['report_url'])
James E. Blair1843a552013-07-03 14:19:52 -07002291
James E. Blairc3d428e2013-12-03 15:06:48 -08002292 def test_merging_queues(self):
2293 "Test that transitively-connected change queues are merged"
2294 self.config.set('zuul', 'layout_config',
2295 'tests/fixtures/layout-merge-queues.yaml')
2296 self.sched.reconfigure(self.config)
2297 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2298
James E. Blairaf17a972016-02-03 15:07:18 -08002299 def test_mutex(self):
2300 "Test job mutexes"
2301 self.config.set('zuul', 'layout_config',
2302 'tests/fixtures/layout-mutex.yaml')
2303 self.sched.reconfigure(self.config)
2304
2305 self.worker.hold_jobs_in_build = True
2306 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2307 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2308 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2309
2310 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2311 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2312 self.waitUntilSettled()
2313 self.assertEqual(len(self.builds), 3)
2314 self.assertEqual(self.builds[0].name, 'project-test1')
2315 self.assertEqual(self.builds[1].name, 'mutex-one')
2316 self.assertEqual(self.builds[2].name, 'project-test1')
2317
2318 self.worker.release('mutex-one')
2319 self.waitUntilSettled()
2320
2321 self.assertEqual(len(self.builds), 3)
2322 self.assertEqual(self.builds[0].name, 'project-test1')
2323 self.assertEqual(self.builds[1].name, 'project-test1')
2324 self.assertEqual(self.builds[2].name, 'mutex-two')
2325 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2326
2327 self.worker.release('mutex-two')
2328 self.waitUntilSettled()
2329
2330 self.assertEqual(len(self.builds), 3)
2331 self.assertEqual(self.builds[0].name, 'project-test1')
2332 self.assertEqual(self.builds[1].name, 'project-test1')
2333 self.assertEqual(self.builds[2].name, 'mutex-one')
2334 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2335
2336 self.worker.release('mutex-one')
2337 self.waitUntilSettled()
2338
2339 self.assertEqual(len(self.builds), 3)
2340 self.assertEqual(self.builds[0].name, 'project-test1')
2341 self.assertEqual(self.builds[1].name, 'project-test1')
2342 self.assertEqual(self.builds[2].name, 'mutex-two')
2343 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2344
2345 self.worker.release('mutex-two')
2346 self.waitUntilSettled()
2347
2348 self.assertEqual(len(self.builds), 2)
2349 self.assertEqual(self.builds[0].name, 'project-test1')
2350 self.assertEqual(self.builds[1].name, 'project-test1')
2351 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2352
2353 self.worker.hold_jobs_in_build = False
2354 self.worker.release()
2355
2356 self.waitUntilSettled()
2357 self.assertEqual(len(self.builds), 0)
2358
2359 self.assertEqual(A.reported, 1)
2360 self.assertEqual(B.reported, 1)
2361 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2362
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002363 def test_node_label(self):
2364 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002365 self.worker.registerFunction('build:node-project-test1:debian')
2366
2367 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2368 A.addApproval('CRVW', 2)
2369 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2370 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002371
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002372 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2373 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2374 'debian')
2375 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002376
2377 def test_live_reconfiguration(self):
2378 "Test that live reconfiguration works"
2379 self.worker.hold_jobs_in_build = True
2380 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2381 A.addApproval('CRVW', 2)
2382 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2383 self.waitUntilSettled()
2384
2385 self.sched.reconfigure(self.config)
2386
2387 self.worker.hold_jobs_in_build = False
2388 self.worker.release()
2389 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002390 self.assertEqual(self.getJobFromHistory('project-merge').result,
2391 'SUCCESS')
2392 self.assertEqual(self.getJobFromHistory('project-test1').result,
2393 'SUCCESS')
2394 self.assertEqual(self.getJobFromHistory('project-test2').result,
2395 'SUCCESS')
2396 self.assertEqual(A.data['status'], 'MERGED')
2397 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002398
James E. Blair6bc782d2015-07-17 16:20:21 -07002399 def test_live_reconfiguration_merge_conflict(self):
2400 # A real-world bug: a change in a gate queue has a merge
2401 # conflict and a job is added to its project while it's
2402 # sitting in the queue. The job gets added to the change and
2403 # enqueued and the change gets stuck.
2404 self.worker.registerFunction('build:project-test3')
2405 self.worker.hold_jobs_in_build = True
2406
2407 # This change is fine. It's here to stop the queue long
2408 # enough for the next change to be subject to the
2409 # reconfiguration, as well as to provide a conflict for the
2410 # next change. This change will succeed and merge.
2411 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2412 A.addPatchset(['conflict'])
2413 A.addApproval('CRVW', 2)
James E. Blair6bc782d2015-07-17 16:20:21 -07002414
2415 # This change will be in merge conflict. During the
2416 # reconfiguration, we will add a job. We want to make sure
2417 # that doesn't cause it to get stuck.
2418 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2419 B.addPatchset(['conflict'])
2420 B.addApproval('CRVW', 2)
James E. Blair4eb21fa2015-07-27 14:56:47 -07002421
2422 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
James E. Blair6bc782d2015-07-17 16:20:21 -07002423 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2424
2425 self.waitUntilSettled()
2426
2427 # No jobs have run yet
2428 self.assertEqual(A.data['status'], 'NEW')
2429 self.assertEqual(A.reported, 1)
2430 self.assertEqual(B.data['status'], 'NEW')
2431 self.assertEqual(B.reported, 1)
2432 self.assertEqual(len(self.history), 0)
2433
2434 # Add the "project-test3" job.
2435 self.config.set('zuul', 'layout_config',
2436 'tests/fixtures/layout-live-'
2437 'reconfiguration-add-job.yaml')
2438 self.sched.reconfigure(self.config)
2439 self.waitUntilSettled()
2440
2441 self.worker.hold_jobs_in_build = False
2442 self.worker.release()
2443 self.waitUntilSettled()
2444
2445 self.assertEqual(A.data['status'], 'MERGED')
2446 self.assertEqual(A.reported, 2)
2447 self.assertEqual(B.data['status'], 'NEW')
2448 self.assertEqual(B.reported, 2)
2449 self.assertEqual(self.getJobFromHistory('project-merge').result,
2450 'SUCCESS')
2451 self.assertEqual(self.getJobFromHistory('project-test1').result,
2452 'SUCCESS')
2453 self.assertEqual(self.getJobFromHistory('project-test2').result,
2454 'SUCCESS')
2455 self.assertEqual(self.getJobFromHistory('project-test3').result,
2456 'SUCCESS')
2457 self.assertEqual(len(self.history), 4)
2458
James E. Blair400e8fd2015-07-30 17:44:45 -07002459 def test_live_reconfiguration_failed_root(self):
James E. Blair6bc782d2015-07-17 16:20:21 -07002460 # An extrapolation of test_live_reconfiguration_merge_conflict
2461 # that tests a job added to a job tree with a failed root does
2462 # not run.
2463 self.worker.registerFunction('build:project-test3')
2464 self.worker.hold_jobs_in_build = True
2465
2466 # This change is fine. It's here to stop the queue long
2467 # enough for the next change to be subject to the
2468 # reconfiguration. This change will succeed and merge.
2469 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2470 A.addPatchset(['conflict'])
2471 A.addApproval('CRVW', 2)
2472 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2473 self.waitUntilSettled()
2474 self.worker.release('.*-merge')
2475 self.waitUntilSettled()
2476
2477 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2478 self.worker.addFailTest('project-merge', B)
2479 B.addApproval('CRVW', 2)
2480 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2481 self.waitUntilSettled()
2482
2483 self.worker.release('.*-merge')
2484 self.waitUntilSettled()
2485
2486 # Both -merge jobs have run, but no others.
2487 self.assertEqual(A.data['status'], 'NEW')
2488 self.assertEqual(A.reported, 1)
2489 self.assertEqual(B.data['status'], 'NEW')
2490 self.assertEqual(B.reported, 1)
2491 self.assertEqual(self.history[0].result, 'SUCCESS')
2492 self.assertEqual(self.history[0].name, 'project-merge')
2493 self.assertEqual(self.history[1].result, 'FAILURE')
2494 self.assertEqual(self.history[1].name, 'project-merge')
2495 self.assertEqual(len(self.history), 2)
2496
2497 # Add the "project-test3" job.
2498 self.config.set('zuul', 'layout_config',
2499 'tests/fixtures/layout-live-'
2500 'reconfiguration-add-job.yaml')
2501 self.sched.reconfigure(self.config)
2502 self.waitUntilSettled()
2503
2504 self.worker.hold_jobs_in_build = False
2505 self.worker.release()
2506 self.waitUntilSettled()
2507
2508 self.assertEqual(A.data['status'], 'MERGED')
2509 self.assertEqual(A.reported, 2)
2510 self.assertEqual(B.data['status'], 'NEW')
2511 self.assertEqual(B.reported, 2)
2512 self.assertEqual(self.history[0].result, 'SUCCESS')
2513 self.assertEqual(self.history[0].name, 'project-merge')
2514 self.assertEqual(self.history[1].result, 'FAILURE')
2515 self.assertEqual(self.history[1].name, 'project-merge')
2516 self.assertEqual(self.history[2].result, 'SUCCESS')
2517 self.assertEqual(self.history[3].result, 'SUCCESS')
2518 self.assertEqual(self.history[4].result, 'SUCCESS')
2519 self.assertEqual(len(self.history), 5)
2520
James E. Blair400e8fd2015-07-30 17:44:45 -07002521 def test_live_reconfiguration_failed_job(self):
2522 # Test that a change with a removed failing job does not
2523 # disrupt reconfiguration. If a change has a failed job and
2524 # that job is removed during a reconfiguration, we observed a
2525 # bug where the code to re-set build statuses would run on
2526 # that build and raise an exception because the job no longer
2527 # existed.
2528 self.worker.hold_jobs_in_build = True
2529
2530 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2531
2532 # This change will fail and later be removed by the reconfiguration.
2533 self.worker.addFailTest('project-test1', A)
2534
2535 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2536 self.waitUntilSettled()
2537 self.worker.release('.*-merge')
2538 self.waitUntilSettled()
2539 self.worker.release('project-test1')
2540 self.waitUntilSettled()
2541
2542 self.assertEqual(A.data['status'], 'NEW')
2543 self.assertEqual(A.reported, 0)
2544
2545 self.assertEqual(self.getJobFromHistory('project-merge').result,
2546 'SUCCESS')
2547 self.assertEqual(self.getJobFromHistory('project-test1').result,
2548 'FAILURE')
2549 self.assertEqual(len(self.history), 2)
2550
2551 # Remove the test1 job.
2552 self.config.set('zuul', 'layout_config',
2553 'tests/fixtures/layout-live-'
2554 'reconfiguration-failed-job.yaml')
2555 self.sched.reconfigure(self.config)
2556 self.waitUntilSettled()
2557
2558 self.worker.hold_jobs_in_build = False
2559 self.worker.release()
2560 self.waitUntilSettled()
2561
2562 self.assertEqual(self.getJobFromHistory('project-test2').result,
2563 'SUCCESS')
2564 self.assertEqual(self.getJobFromHistory('project-testfile').result,
2565 'SUCCESS')
2566 self.assertEqual(len(self.history), 4)
2567
2568 self.assertEqual(A.data['status'], 'NEW')
2569 self.assertEqual(A.reported, 1)
2570 self.assertIn('Build succeeded', A.messages[0])
2571 # Ensure the removed job was not included in the report.
2572 self.assertNotIn('project-test1', A.messages[0])
2573
James E. Blairfe707d12015-08-05 15:18:15 -07002574 def test_live_reconfiguration_shared_queue(self):
2575 # Test that a change with a failing job which was removed from
2576 # this project but otherwise still exists in the system does
2577 # not disrupt reconfiguration.
2578
2579 self.worker.hold_jobs_in_build = True
2580
2581 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2582
2583 self.worker.addFailTest('project1-project2-integration', A)
2584
2585 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2586 self.waitUntilSettled()
2587 self.worker.release('.*-merge')
2588 self.waitUntilSettled()
2589 self.worker.release('project1-project2-integration')
2590 self.waitUntilSettled()
2591
2592 self.assertEqual(A.data['status'], 'NEW')
2593 self.assertEqual(A.reported, 0)
2594
2595 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2596 'SUCCESS')
2597 self.assertEqual(self.getJobFromHistory(
2598 'project1-project2-integration').result, 'FAILURE')
2599 self.assertEqual(len(self.history), 2)
2600
2601 # Remove the integration job.
2602 self.config.set('zuul', 'layout_config',
2603 'tests/fixtures/layout-live-'
2604 'reconfiguration-shared-queue.yaml')
2605 self.sched.reconfigure(self.config)
2606 self.waitUntilSettled()
2607
2608 self.worker.hold_jobs_in_build = False
2609 self.worker.release()
2610 self.waitUntilSettled()
2611
2612 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2613 'SUCCESS')
2614 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2615 'SUCCESS')
2616 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2617 'SUCCESS')
2618 self.assertEqual(self.getJobFromHistory(
2619 'project1-project2-integration').result, 'FAILURE')
2620 self.assertEqual(len(self.history), 4)
2621
2622 self.assertEqual(A.data['status'], 'NEW')
2623 self.assertEqual(A.reported, 1)
2624 self.assertIn('Build succeeded', A.messages[0])
2625 # Ensure the removed job was not included in the report.
2626 self.assertNotIn('project1-project2-integration', A.messages[0])
2627
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11002628 def test_double_live_reconfiguration_shared_queue(self):
2629 # This was a real-world regression. A change is added to
2630 # gate; a reconfigure happens, a second change which depends
2631 # on the first is added, and a second reconfiguration happens.
2632 # Ensure that both changes merge.
2633
2634 # A failure may indicate incorrect caching or cleaning up of
2635 # references during a reconfiguration.
2636 self.worker.hold_jobs_in_build = True
2637
2638 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2639 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2640 B.setDependsOn(A, 1)
2641 A.addApproval('CRVW', 2)
2642 B.addApproval('CRVW', 2)
2643
2644 # Add the parent change.
2645 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2646 self.waitUntilSettled()
2647 self.worker.release('.*-merge')
2648 self.waitUntilSettled()
2649
2650 # Reconfigure (with only one change in the pipeline).
2651 self.sched.reconfigure(self.config)
2652 self.waitUntilSettled()
2653
2654 # Add the child change.
2655 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2656 self.waitUntilSettled()
2657 self.worker.release('.*-merge')
2658 self.waitUntilSettled()
2659
2660 # Reconfigure (with both in the pipeline).
2661 self.sched.reconfigure(self.config)
2662 self.waitUntilSettled()
2663
2664 self.worker.hold_jobs_in_build = False
2665 self.worker.release()
2666 self.waitUntilSettled()
2667
2668 self.assertEqual(len(self.history), 8)
2669
2670 self.assertEqual(A.data['status'], 'MERGED')
2671 self.assertEqual(A.reported, 2)
2672 self.assertEqual(B.data['status'], 'MERGED')
2673 self.assertEqual(B.reported, 2)
2674
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002675 def test_live_reconfiguration_del_project(self):
2676 # Test project deletion from layout
2677 # while changes are enqueued
2678
2679 self.worker.hold_jobs_in_build = True
2680 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2681 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2682 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2683
2684 # A Depends-On: B
2685 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2686 A.subject, B.data['id'])
2687 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2688
2689 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2690 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2691 self.waitUntilSettled()
2692 self.worker.release('.*-merge')
2693 self.waitUntilSettled()
2694 self.assertEqual(len(self.builds), 5)
2695
2696 # This layout defines only org/project, not org/project1
2697 self.config.set('zuul', 'layout_config',
2698 'tests/fixtures/layout-live-'
2699 'reconfiguration-del-project.yaml')
2700 self.sched.reconfigure(self.config)
2701 self.waitUntilSettled()
2702
2703 # Builds for C aborted, builds for A succeed,
2704 # and have change B applied ahead
2705 job_c = self.getJobFromHistory('project1-test1')
2706 self.assertEqual(job_c.changes, '3,1')
2707 self.assertEqual(job_c.result, 'ABORTED')
2708
2709 self.worker.hold_jobs_in_build = False
2710 self.worker.release()
2711 self.waitUntilSettled()
2712
2713 self.assertEqual(self.getJobFromHistory('project-test1').changes,
2714 '2,1 1,1')
2715
2716 self.assertEqual(A.data['status'], 'NEW')
2717 self.assertEqual(B.data['status'], 'NEW')
2718 self.assertEqual(C.data['status'], 'NEW')
2719 self.assertEqual(A.reported, 1)
2720 self.assertEqual(B.reported, 0)
2721 self.assertEqual(C.reported, 0)
2722
2723 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
2724 self.assertIn('Build succeeded', A.messages[0])
2725
James E. Blaire712d9f2013-07-31 11:40:11 -07002726 def test_live_reconfiguration_functions(self):
2727 "Test live reconfiguration with a custom function"
2728 self.worker.registerFunction('build:node-project-test1:debian')
2729 self.worker.registerFunction('build:node-project-test1:wheezy')
2730 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2731 A.addApproval('CRVW', 2)
2732 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2733 self.waitUntilSettled()
2734
2735 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2736 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2737 'debian')
2738 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2739
2740 self.config.set('zuul', 'layout_config',
2741 'tests/fixtures/layout-live-'
2742 'reconfiguration-functions.yaml')
2743 self.sched.reconfigure(self.config)
2744 self.worker.build_history = []
2745
2746 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2747 B.addApproval('CRVW', 2)
2748 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2749 self.waitUntilSettled()
2750
2751 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2752 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2753 'wheezy')
2754 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2755
James E. Blair287c06d2013-07-24 10:39:30 -07002756 def test_delayed_repo_init(self):
2757 self.config.set('zuul', 'layout_config',
2758 'tests/fixtures/layout-delayed-repo-init.yaml')
2759 self.sched.reconfigure(self.config)
2760
2761 self.init_repo("org/new-project")
2762 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2763
2764 A.addApproval('CRVW', 2)
2765 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2766 self.waitUntilSettled()
2767 self.assertEqual(self.getJobFromHistory('project-merge').result,
2768 'SUCCESS')
2769 self.assertEqual(self.getJobFromHistory('project-test1').result,
2770 'SUCCESS')
2771 self.assertEqual(self.getJobFromHistory('project-test2').result,
2772 'SUCCESS')
2773 self.assertEqual(A.data['status'], 'MERGED')
2774 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002775
Clark Boylan6dbbc482013-10-18 10:57:31 -07002776 def test_repo_deleted(self):
2777 self.config.set('zuul', 'layout_config',
2778 'tests/fixtures/layout-repo-deleted.yaml')
2779 self.sched.reconfigure(self.config)
2780
2781 self.init_repo("org/delete-project")
2782 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2783
2784 A.addApproval('CRVW', 2)
2785 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2786 self.waitUntilSettled()
2787 self.assertEqual(self.getJobFromHistory('project-merge').result,
2788 'SUCCESS')
2789 self.assertEqual(self.getJobFromHistory('project-test1').result,
2790 'SUCCESS')
2791 self.assertEqual(self.getJobFromHistory('project-test2').result,
2792 'SUCCESS')
2793 self.assertEqual(A.data['status'], 'MERGED')
2794 self.assertEqual(A.reported, 2)
2795
2796 # Delete org/new-project zuul repo. Should be recloned.
2797 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2798
2799 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2800
2801 B.addApproval('CRVW', 2)
2802 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2803 self.waitUntilSettled()
2804 self.assertEqual(self.getJobFromHistory('project-merge').result,
2805 'SUCCESS')
2806 self.assertEqual(self.getJobFromHistory('project-test1').result,
2807 'SUCCESS')
2808 self.assertEqual(self.getJobFromHistory('project-test2').result,
2809 'SUCCESS')
2810 self.assertEqual(B.data['status'], 'MERGED')
2811 self.assertEqual(B.reported, 2)
2812
James E. Blair456f2fb2016-02-09 09:29:33 -08002813 def test_tags(self):
2814 "Test job tags"
2815 self.config.set('zuul', 'layout_config',
2816 'tests/fixtures/layout-tags.yaml')
2817 self.sched.reconfigure(self.config)
2818
2819 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2820 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
2821 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2822 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2823 self.waitUntilSettled()
2824
2825 results = {'project1-merge': 'extratag merge project1',
2826 'project2-merge': 'merge'}
2827
2828 for build in self.history:
2829 self.assertEqual(results.get(build.name, ''),
2830 build.parameters.get('BUILD_TAGS'))
2831
James E. Blair63bb0ef2013-07-29 17:14:51 -07002832 def test_timer(self):
2833 "Test that a periodic job is triggered"
2834 self.worker.hold_jobs_in_build = True
2835 self.config.set('zuul', 'layout_config',
2836 'tests/fixtures/layout-timer.yaml')
2837 self.sched.reconfigure(self.config)
2838 self.registerJobs()
2839
Clark Boylan3ee090a2014-04-03 20:55:09 -07002840 # The pipeline triggers every second, so we should have seen
2841 # several by now.
2842 time.sleep(5)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002843 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002844
2845 self.assertEqual(len(self.builds), 2)
2846
James E. Blair63bb0ef2013-07-29 17:14:51 -07002847 port = self.webapp.server.socket.getsockname()[1]
2848
2849 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2850 data = f.read()
2851
2852 self.worker.hold_jobs_in_build = False
Clark Boylan3ee090a2014-04-03 20:55:09 -07002853 # Stop queuing timer triggered jobs so that the assertions
2854 # below don't race against more jobs being queued.
2855 self.config.set('zuul', 'layout_config',
2856 'tests/fixtures/layout-no-timer.yaml')
2857 self.sched.reconfigure(self.config)
2858 self.registerJobs()
James E. Blair63bb0ef2013-07-29 17:14:51 -07002859 self.worker.release()
2860 self.waitUntilSettled()
2861
2862 self.assertEqual(self.getJobFromHistory(
2863 'project-bitrot-stable-old').result, 'SUCCESS')
2864 self.assertEqual(self.getJobFromHistory(
2865 'project-bitrot-stable-older').result, 'SUCCESS')
2866
2867 data = json.loads(data)
2868 status_jobs = set()
2869 for p in data['pipelines']:
2870 for q in p['change_queues']:
2871 for head in q['heads']:
2872 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07002873 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002874 for job in change['jobs']:
2875 status_jobs.add(job['name'])
2876 self.assertIn('project-bitrot-stable-old', status_jobs)
2877 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002878
James E. Blair4f6033c2014-03-27 15:49:09 -07002879 def test_idle(self):
2880 "Test that frequent periodic jobs work"
2881 self.worker.hold_jobs_in_build = True
James E. Blair4f6033c2014-03-27 15:49:09 -07002882
Clark Boylan3ee090a2014-04-03 20:55:09 -07002883 for x in range(1, 3):
2884 # Test that timer triggers periodic jobs even across
2885 # layout config reloads.
2886 # Start timer trigger
2887 self.config.set('zuul', 'layout_config',
2888 'tests/fixtures/layout-idle.yaml')
2889 self.sched.reconfigure(self.config)
2890 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002891 self.waitUntilSettled()
James E. Blair4f6033c2014-03-27 15:49:09 -07002892
Clark Boylan3ee090a2014-04-03 20:55:09 -07002893 # The pipeline triggers every second, so we should have seen
2894 # several by now.
2895 time.sleep(5)
Clark Boylan3ee090a2014-04-03 20:55:09 -07002896
2897 # Stop queuing timer triggered jobs so that the assertions
2898 # below don't race against more jobs being queued.
2899 self.config.set('zuul', 'layout_config',
2900 'tests/fixtures/layout-no-timer.yaml')
2901 self.sched.reconfigure(self.config)
2902 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002903 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002904
2905 self.assertEqual(len(self.builds), 2)
2906 self.worker.release('.*')
2907 self.waitUntilSettled()
2908 self.assertEqual(len(self.builds), 0)
2909 self.assertEqual(len(self.history), x * 2)
James E. Blair4f6033c2014-03-27 15:49:09 -07002910
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002911 def test_check_smtp_pool(self):
2912 self.config.set('zuul', 'layout_config',
2913 'tests/fixtures/layout-smtp.yaml')
2914 self.sched.reconfigure(self.config)
2915
2916 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2917 self.waitUntilSettled()
2918
2919 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2920 self.waitUntilSettled()
2921
James E. Blairff80a2f2013-12-27 13:24:06 -08002922 self.assertEqual(len(self.smtp_messages), 2)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002923
2924 # A.messages only holds what FakeGerrit places in it. Thus we
2925 # work on the knowledge of what the first message should be as
2926 # it is only configured to go to SMTP.
2927
2928 self.assertEqual('zuul@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002929 self.smtp_messages[0]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002930 self.assertEqual(['you@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002931 self.smtp_messages[0]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002932 self.assertEqual('Starting check jobs.',
James E. Blairff80a2f2013-12-27 13:24:06 -08002933 self.smtp_messages[0]['body'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002934
2935 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002936 self.smtp_messages[1]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002937 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002938 self.smtp_messages[1]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002939 self.assertEqual(A.messages[0],
James E. Blairff80a2f2013-12-27 13:24:06 -08002940 self.smtp_messages[1]['body'])
James E. Blairad28e912013-11-27 10:43:22 -08002941
James E. Blaire5910202013-12-27 09:50:31 -08002942 def test_timer_smtp(self):
2943 "Test that a periodic job is triggered"
Clark Boylan3ee090a2014-04-03 20:55:09 -07002944 self.worker.hold_jobs_in_build = True
James E. Blaire5910202013-12-27 09:50:31 -08002945 self.config.set('zuul', 'layout_config',
2946 'tests/fixtures/layout-timer-smtp.yaml')
2947 self.sched.reconfigure(self.config)
2948 self.registerJobs()
2949
Clark Boylan3ee090a2014-04-03 20:55:09 -07002950 # The pipeline triggers every second, so we should have seen
2951 # several by now.
2952 time.sleep(5)
James E. Blaire5910202013-12-27 09:50:31 -08002953 self.waitUntilSettled()
2954
Clark Boylan3ee090a2014-04-03 20:55:09 -07002955 self.assertEqual(len(self.builds), 2)
2956 self.worker.release('.*')
2957 self.waitUntilSettled()
2958 self.assertEqual(len(self.history), 2)
2959
James E. Blaire5910202013-12-27 09:50:31 -08002960 self.assertEqual(self.getJobFromHistory(
2961 'project-bitrot-stable-old').result, 'SUCCESS')
2962 self.assertEqual(self.getJobFromHistory(
2963 'project-bitrot-stable-older').result, 'SUCCESS')
2964
James E. Blairff80a2f2013-12-27 13:24:06 -08002965 self.assertEqual(len(self.smtp_messages), 1)
James E. Blaire5910202013-12-27 09:50:31 -08002966
2967 # A.messages only holds what FakeGerrit places in it. Thus we
2968 # work on the knowledge of what the first message should be as
2969 # it is only configured to go to SMTP.
2970
2971 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002972 self.smtp_messages[0]['from_email'])
James E. Blaire5910202013-12-27 09:50:31 -08002973 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002974 self.smtp_messages[0]['to_email'])
James E. Blaire5910202013-12-27 09:50:31 -08002975 self.assertIn('Subject: Periodic check for org/project succeeded',
James E. Blairff80a2f2013-12-27 13:24:06 -08002976 self.smtp_messages[0]['headers'])
James E. Blaire5910202013-12-27 09:50:31 -08002977
Clark Boylan3ee090a2014-04-03 20:55:09 -07002978 # Stop queuing timer triggered jobs and let any that may have
2979 # queued through so that end of test assertions pass.
2980 self.config.set('zuul', 'layout_config',
2981 'tests/fixtures/layout-no-timer.yaml')
2982 self.sched.reconfigure(self.config)
2983 self.registerJobs()
James E. Blairf8058972014-08-15 16:09:16 -07002984 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002985 self.worker.release('.*')
2986 self.waitUntilSettled()
2987
James E. Blair91e34592015-07-31 16:45:59 -07002988 def test_client_enqueue_change(self):
James E. Blairad28e912013-11-27 10:43:22 -08002989 "Test that the RPC client can enqueue a change"
2990 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2991 A.addApproval('CRVW', 2)
2992 A.addApproval('APRV', 1)
2993
2994 client = zuul.rpcclient.RPCClient('127.0.0.1',
2995 self.gearman_server.port)
2996 r = client.enqueue(pipeline='gate',
2997 project='org/project',
2998 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08002999 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003000 self.waitUntilSettled()
3001 self.assertEqual(self.getJobFromHistory('project-merge').result,
3002 'SUCCESS')
3003 self.assertEqual(self.getJobFromHistory('project-test1').result,
3004 'SUCCESS')
3005 self.assertEqual(self.getJobFromHistory('project-test2').result,
3006 'SUCCESS')
3007 self.assertEqual(A.data['status'], 'MERGED')
3008 self.assertEqual(A.reported, 2)
3009 self.assertEqual(r, True)
3010
James E. Blair91e34592015-07-31 16:45:59 -07003011 def test_client_enqueue_ref(self):
3012 "Test that the RPC client can enqueue a ref"
3013
3014 client = zuul.rpcclient.RPCClient('127.0.0.1',
3015 self.gearman_server.port)
3016 r = client.enqueue_ref(
3017 pipeline='post',
3018 project='org/project',
3019 trigger='gerrit',
3020 ref='master',
3021 oldrev='90f173846e3af9154517b88543ffbd1691f31366',
3022 newrev='d479a0bfcb34da57a31adb2a595c0cf687812543')
3023 self.waitUntilSettled()
3024 job_names = [x.name for x in self.history]
3025 self.assertEqual(len(self.history), 1)
3026 self.assertIn('project-post', job_names)
3027 self.assertEqual(r, True)
3028
James E. Blairad28e912013-11-27 10:43:22 -08003029 def test_client_enqueue_negative(self):
3030 "Test that the RPC client returns errors"
3031 client = zuul.rpcclient.RPCClient('127.0.0.1',
3032 self.gearman_server.port)
3033 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3034 "Invalid project"):
3035 r = client.enqueue(pipeline='gate',
3036 project='project-does-not-exist',
3037 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003038 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003039 client.shutdown()
3040 self.assertEqual(r, False)
3041
3042 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3043 "Invalid pipeline"):
3044 r = client.enqueue(pipeline='pipeline-does-not-exist',
3045 project='org/project',
3046 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003047 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003048 client.shutdown()
3049 self.assertEqual(r, False)
3050
3051 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3052 "Invalid trigger"):
3053 r = client.enqueue(pipeline='gate',
3054 project='org/project',
3055 trigger='trigger-does-not-exist',
James E. Blair36658cf2013-12-06 17:53:48 -08003056 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003057 client.shutdown()
3058 self.assertEqual(r, False)
3059
3060 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3061 "Invalid change"):
3062 r = client.enqueue(pipeline='gate',
3063 project='org/project',
3064 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003065 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003066 client.shutdown()
3067 self.assertEqual(r, False)
3068
3069 self.waitUntilSettled()
3070 self.assertEqual(len(self.history), 0)
3071 self.assertEqual(len(self.builds), 0)
James E. Blair36658cf2013-12-06 17:53:48 -08003072
3073 def test_client_promote(self):
3074 "Test that the RPC client can promote a change"
3075 self.worker.hold_jobs_in_build = True
3076 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3077 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3078 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3079 A.addApproval('CRVW', 2)
3080 B.addApproval('CRVW', 2)
3081 C.addApproval('CRVW', 2)
3082
3083 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3084 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3085 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3086
3087 self.waitUntilSettled()
3088
Sean Daguef39b9ca2014-01-10 21:34:35 -05003089 items = self.sched.layout.pipelines['gate'].getAllItems()
3090 enqueue_times = {}
3091 for item in items:
3092 enqueue_times[str(item.change)] = item.enqueue_time
3093
James E. Blair36658cf2013-12-06 17:53:48 -08003094 client = zuul.rpcclient.RPCClient('127.0.0.1',
3095 self.gearman_server.port)
3096 r = client.promote(pipeline='gate',
3097 change_ids=['2,1', '3,1'])
3098
Sean Daguef39b9ca2014-01-10 21:34:35 -05003099 # ensure that enqueue times are durable
3100 items = self.sched.layout.pipelines['gate'].getAllItems()
3101 for item in items:
3102 self.assertEqual(
3103 enqueue_times[str(item.change)], item.enqueue_time)
3104
James E. Blair78acec92014-02-06 07:11:32 -08003105 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003106 self.worker.release('.*-merge')
3107 self.waitUntilSettled()
3108 self.worker.release('.*-merge')
3109 self.waitUntilSettled()
3110 self.worker.release('.*-merge')
3111 self.waitUntilSettled()
3112
3113 self.assertEqual(len(self.builds), 6)
3114 self.assertEqual(self.builds[0].name, 'project-test1')
3115 self.assertEqual(self.builds[1].name, 'project-test2')
3116 self.assertEqual(self.builds[2].name, 'project-test1')
3117 self.assertEqual(self.builds[3].name, 'project-test2')
3118 self.assertEqual(self.builds[4].name, 'project-test1')
3119 self.assertEqual(self.builds[5].name, 'project-test2')
3120
3121 self.assertTrue(self.job_has_changes(self.builds[0], B))
3122 self.assertFalse(self.job_has_changes(self.builds[0], A))
3123 self.assertFalse(self.job_has_changes(self.builds[0], C))
3124
3125 self.assertTrue(self.job_has_changes(self.builds[2], B))
3126 self.assertTrue(self.job_has_changes(self.builds[2], C))
3127 self.assertFalse(self.job_has_changes(self.builds[2], A))
3128
3129 self.assertTrue(self.job_has_changes(self.builds[4], B))
3130 self.assertTrue(self.job_has_changes(self.builds[4], C))
3131 self.assertTrue(self.job_has_changes(self.builds[4], A))
3132
3133 self.worker.release()
3134 self.waitUntilSettled()
3135
3136 self.assertEqual(A.data['status'], 'MERGED')
3137 self.assertEqual(A.reported, 2)
3138 self.assertEqual(B.data['status'], 'MERGED')
3139 self.assertEqual(B.reported, 2)
3140 self.assertEqual(C.data['status'], 'MERGED')
3141 self.assertEqual(C.reported, 2)
3142
3143 client.shutdown()
3144 self.assertEqual(r, True)
3145
3146 def test_client_promote_dependent(self):
3147 "Test that the RPC client can promote a dependent change"
3148 # C (depends on B) -> B -> A ; then promote C to get:
3149 # A -> C (depends on B) -> B
3150 self.worker.hold_jobs_in_build = True
3151 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3152 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3153 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3154
3155 C.setDependsOn(B, 1)
3156
3157 A.addApproval('CRVW', 2)
3158 B.addApproval('CRVW', 2)
3159 C.addApproval('CRVW', 2)
3160
3161 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3162 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3163 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3164
3165 self.waitUntilSettled()
3166
3167 client = zuul.rpcclient.RPCClient('127.0.0.1',
3168 self.gearman_server.port)
3169 r = client.promote(pipeline='gate',
3170 change_ids=['3,1'])
3171
James E. Blair78acec92014-02-06 07:11:32 -08003172 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003173 self.worker.release('.*-merge')
3174 self.waitUntilSettled()
3175 self.worker.release('.*-merge')
3176 self.waitUntilSettled()
3177 self.worker.release('.*-merge')
3178 self.waitUntilSettled()
3179
3180 self.assertEqual(len(self.builds), 6)
3181 self.assertEqual(self.builds[0].name, 'project-test1')
3182 self.assertEqual(self.builds[1].name, 'project-test2')
3183 self.assertEqual(self.builds[2].name, 'project-test1')
3184 self.assertEqual(self.builds[3].name, 'project-test2')
3185 self.assertEqual(self.builds[4].name, 'project-test1')
3186 self.assertEqual(self.builds[5].name, 'project-test2')
3187
3188 self.assertTrue(self.job_has_changes(self.builds[0], B))
3189 self.assertFalse(self.job_has_changes(self.builds[0], A))
3190 self.assertFalse(self.job_has_changes(self.builds[0], C))
3191
3192 self.assertTrue(self.job_has_changes(self.builds[2], B))
3193 self.assertTrue(self.job_has_changes(self.builds[2], C))
3194 self.assertFalse(self.job_has_changes(self.builds[2], A))
3195
3196 self.assertTrue(self.job_has_changes(self.builds[4], B))
3197 self.assertTrue(self.job_has_changes(self.builds[4], C))
3198 self.assertTrue(self.job_has_changes(self.builds[4], A))
3199
3200 self.worker.release()
3201 self.waitUntilSettled()
3202
3203 self.assertEqual(A.data['status'], 'MERGED')
3204 self.assertEqual(A.reported, 2)
3205 self.assertEqual(B.data['status'], 'MERGED')
3206 self.assertEqual(B.reported, 2)
3207 self.assertEqual(C.data['status'], 'MERGED')
3208 self.assertEqual(C.reported, 2)
3209
3210 client.shutdown()
3211 self.assertEqual(r, True)
3212
3213 def test_client_promote_negative(self):
3214 "Test that the RPC client returns errors for promotion"
3215 self.worker.hold_jobs_in_build = True
3216 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3217 A.addApproval('CRVW', 2)
3218 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3219 self.waitUntilSettled()
3220
3221 client = zuul.rpcclient.RPCClient('127.0.0.1',
3222 self.gearman_server.port)
3223
3224 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3225 r = client.promote(pipeline='nonexistent',
3226 change_ids=['2,1', '3,1'])
3227 client.shutdown()
3228 self.assertEqual(r, False)
3229
3230 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3231 r = client.promote(pipeline='gate',
3232 change_ids=['4,1'])
3233 client.shutdown()
3234 self.assertEqual(r, False)
3235
3236 self.worker.hold_jobs_in_build = False
3237 self.worker.release()
3238 self.waitUntilSettled()
Clark Boylan7603a372014-01-21 11:43:20 -08003239
3240 def test_queue_rate_limiting(self):
3241 "Test that DependentPipelines are rate limited with dep across window"
3242 self.config.set('zuul', 'layout_config',
3243 'tests/fixtures/layout-rate-limit.yaml')
3244 self.sched.reconfigure(self.config)
3245 self.worker.hold_jobs_in_build = True
3246 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3247 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3248 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3249
3250 C.setDependsOn(B, 1)
3251 self.worker.addFailTest('project-test1', A)
3252
3253 A.addApproval('CRVW', 2)
3254 B.addApproval('CRVW', 2)
3255 C.addApproval('CRVW', 2)
3256
3257 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3258 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3259 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3260 self.waitUntilSettled()
3261
3262 # Only A and B will have their merge jobs queued because
3263 # window is 2.
3264 self.assertEqual(len(self.builds), 2)
3265 self.assertEqual(self.builds[0].name, 'project-merge')
3266 self.assertEqual(self.builds[1].name, 'project-merge')
3267
3268 self.worker.release('.*-merge')
3269 self.waitUntilSettled()
3270 self.worker.release('.*-merge')
3271 self.waitUntilSettled()
3272
3273 # Only A and B will have their test jobs queued because
3274 # window is 2.
3275 self.assertEqual(len(self.builds), 4)
3276 self.assertEqual(self.builds[0].name, 'project-test1')
3277 self.assertEqual(self.builds[1].name, 'project-test2')
3278 self.assertEqual(self.builds[2].name, 'project-test1')
3279 self.assertEqual(self.builds[3].name, 'project-test2')
3280
3281 self.worker.release('project-.*')
3282 self.waitUntilSettled()
3283
3284 queue = self.sched.layout.pipelines['gate'].queues[0]
3285 # A failed so window is reduced by 1 to 1.
3286 self.assertEqual(queue.window, 1)
3287 self.assertEqual(queue.window_floor, 1)
3288 self.assertEqual(A.data['status'], 'NEW')
3289
3290 # Gate is reset and only B's merge job is queued because
3291 # window shrunk to 1.
3292 self.assertEqual(len(self.builds), 1)
3293 self.assertEqual(self.builds[0].name, 'project-merge')
3294
3295 self.worker.release('.*-merge')
3296 self.waitUntilSettled()
3297
3298 # Only B's test jobs are queued because window is still 1.
3299 self.assertEqual(len(self.builds), 2)
3300 self.assertEqual(self.builds[0].name, 'project-test1')
3301 self.assertEqual(self.builds[1].name, 'project-test2')
3302
3303 self.worker.release('project-.*')
3304 self.waitUntilSettled()
3305
3306 # B was successfully merged so window is increased to 2.
3307 self.assertEqual(queue.window, 2)
3308 self.assertEqual(queue.window_floor, 1)
3309 self.assertEqual(B.data['status'], 'MERGED')
3310
3311 # Only C is left and its merge job is queued.
3312 self.assertEqual(len(self.builds), 1)
3313 self.assertEqual(self.builds[0].name, 'project-merge')
3314
3315 self.worker.release('.*-merge')
3316 self.waitUntilSettled()
3317
3318 # After successful merge job the test jobs for C are queued.
3319 self.assertEqual(len(self.builds), 2)
3320 self.assertEqual(self.builds[0].name, 'project-test1')
3321 self.assertEqual(self.builds[1].name, 'project-test2')
3322
3323 self.worker.release('project-.*')
3324 self.waitUntilSettled()
3325
3326 # C successfully merged so window is bumped to 3.
3327 self.assertEqual(queue.window, 3)
3328 self.assertEqual(queue.window_floor, 1)
3329 self.assertEqual(C.data['status'], 'MERGED')
3330
3331 def test_queue_rate_limiting_dependent(self):
3332 "Test that DependentPipelines are rate limited with dep in window"
3333 self.config.set('zuul', 'layout_config',
3334 'tests/fixtures/layout-rate-limit.yaml')
3335 self.sched.reconfigure(self.config)
3336 self.worker.hold_jobs_in_build = True
3337 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3338 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3339 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3340
3341 B.setDependsOn(A, 1)
3342
3343 self.worker.addFailTest('project-test1', A)
3344
3345 A.addApproval('CRVW', 2)
3346 B.addApproval('CRVW', 2)
3347 C.addApproval('CRVW', 2)
3348
3349 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3350 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3351 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3352 self.waitUntilSettled()
3353
3354 # Only A and B will have their merge jobs queued because
3355 # window is 2.
3356 self.assertEqual(len(self.builds), 2)
3357 self.assertEqual(self.builds[0].name, 'project-merge')
3358 self.assertEqual(self.builds[1].name, 'project-merge')
3359
3360 self.worker.release('.*-merge')
3361 self.waitUntilSettled()
3362 self.worker.release('.*-merge')
3363 self.waitUntilSettled()
3364
3365 # Only A and B will have their test jobs queued because
3366 # window is 2.
3367 self.assertEqual(len(self.builds), 4)
3368 self.assertEqual(self.builds[0].name, 'project-test1')
3369 self.assertEqual(self.builds[1].name, 'project-test2')
3370 self.assertEqual(self.builds[2].name, 'project-test1')
3371 self.assertEqual(self.builds[3].name, 'project-test2')
3372
3373 self.worker.release('project-.*')
3374 self.waitUntilSettled()
3375
3376 queue = self.sched.layout.pipelines['gate'].queues[0]
3377 # A failed so window is reduced by 1 to 1.
3378 self.assertEqual(queue.window, 1)
3379 self.assertEqual(queue.window_floor, 1)
3380 self.assertEqual(A.data['status'], 'NEW')
3381 self.assertEqual(B.data['status'], 'NEW')
3382
3383 # Gate is reset and only C's merge job is queued because
3384 # window shrunk to 1 and A and B were dequeued.
3385 self.assertEqual(len(self.builds), 1)
3386 self.assertEqual(self.builds[0].name, 'project-merge')
3387
3388 self.worker.release('.*-merge')
3389 self.waitUntilSettled()
3390
3391 # Only C's test jobs are queued because window is still 1.
3392 self.assertEqual(len(self.builds), 2)
3393 self.assertEqual(self.builds[0].name, 'project-test1')
3394 self.assertEqual(self.builds[1].name, 'project-test2')
3395
3396 self.worker.release('project-.*')
3397 self.waitUntilSettled()
3398
3399 # C was successfully merged so window is increased to 2.
3400 self.assertEqual(queue.window, 2)
3401 self.assertEqual(queue.window_floor, 1)
3402 self.assertEqual(C.data['status'], 'MERGED')
Joshua Heskethba8776a2014-01-12 14:35:40 +08003403
3404 def test_worker_update_metadata(self):
3405 "Test if a worker can send back metadata about itself"
3406 self.worker.hold_jobs_in_build = True
3407
3408 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3409 A.addApproval('CRVW', 2)
3410 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3411 self.waitUntilSettled()
3412
3413 self.assertEqual(len(self.launcher.builds), 1)
3414
3415 self.log.debug('Current builds:')
3416 self.log.debug(self.launcher.builds)
3417
3418 start = time.time()
3419 while True:
3420 if time.time() - start > 10:
3421 raise Exception("Timeout waiting for gearman server to report "
3422 + "back to the client")
3423 build = self.launcher.builds.values()[0]
3424 if build.worker.name == "My Worker":
3425 break
3426 else:
3427 time.sleep(0)
3428
3429 self.log.debug(build)
3430 self.assertEqual("My Worker", build.worker.name)
3431 self.assertEqual("localhost", build.worker.hostname)
3432 self.assertEqual(['127.0.0.1', '192.168.1.1'], build.worker.ips)
3433 self.assertEqual("zuul.example.org", build.worker.fqdn)
3434 self.assertEqual("FakeBuilder", build.worker.program)
3435 self.assertEqual("v1.1", build.worker.version)
3436 self.assertEqual({'something': 'else'}, build.worker.extra)
3437
3438 self.worker.hold_jobs_in_build = False
3439 self.worker.release()
3440 self.waitUntilSettled()
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003441
3442 def test_footer_message(self):
3443 "Test a pipeline's footer message is correctly added to the report."
3444 self.config.set('zuul', 'layout_config',
3445 'tests/fixtures/layout-footer-message.yaml')
3446 self.sched.reconfigure(self.config)
3447 self.registerJobs()
3448
3449 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3450 A.addApproval('CRVW', 2)
3451 self.worker.addFailTest('test1', A)
3452 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3453 self.waitUntilSettled()
3454
3455 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3456 B.addApproval('CRVW', 2)
3457 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3458 self.waitUntilSettled()
3459
3460 self.assertEqual(2, len(self.smtp_messages))
3461
3462 failure_body = """\
3463Build failed. For information on how to proceed, see \
3464http://wiki.example.org/Test_Failures
3465
3466- test1 http://logs.example.com/1/1/gate/test1/0 : FAILURE in 0s
3467- test2 http://logs.example.com/1/1/gate/test2/1 : SUCCESS in 0s
3468
3469For CI problems and help debugging, contact ci@example.org"""
3470
3471 success_body = """\
3472Build succeeded.
3473
3474- test1 http://logs.example.com/2/1/gate/test1/2 : SUCCESS in 0s
3475- test2 http://logs.example.com/2/1/gate/test2/3 : SUCCESS in 0s
3476
3477For CI problems and help debugging, contact ci@example.org"""
3478
3479 self.assertEqual(failure_body, self.smtp_messages[0]['body'])
3480 self.assertEqual(success_body, self.smtp_messages[1]['body'])
Joshua Heskethb7179772014-01-30 23:30:46 +11003481
3482 def test_merge_failure_reporters(self):
3483 """Check that the config is set up correctly"""
3484
3485 self.config.set('zuul', 'layout_config',
3486 'tests/fixtures/layout-merge-failure.yaml')
3487 self.sched.reconfigure(self.config)
3488 self.registerJobs()
3489
3490 self.assertEqual(
Jeremy Stanley1c2c3c22015-06-15 21:23:19 +00003491 "Merge Failed.\n\nThis change or one of its cross-repo "
3492 "dependencies was unable to be automatically merged with the "
3493 "current state of its repository. Please rebase the change and "
3494 "upload a new patchset.",
Joshua Heskethb7179772014-01-30 23:30:46 +11003495 self.sched.layout.pipelines['check'].merge_failure_message)
3496 self.assertEqual(
3497 "The merge failed! For more information...",
3498 self.sched.layout.pipelines['gate'].merge_failure_message)
3499
3500 self.assertEqual(
3501 len(self.sched.layout.pipelines['check'].merge_failure_actions), 1)
3502 self.assertEqual(
3503 len(self.sched.layout.pipelines['gate'].merge_failure_actions), 2)
3504
3505 self.assertTrue(isinstance(
Joshua Heskethde958652015-11-10 19:19:50 +11003506 self.sched.layout.pipelines['check'].merge_failure_actions[0],
3507 zuul.reporter.gerrit.GerritReporter))
Joshua Heskethb7179772014-01-30 23:30:46 +11003508
3509 self.assertTrue(
3510 (
3511 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003512 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003513 zuul.reporter.smtp.SMTPReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003514 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003515 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003516 zuul.reporter.gerrit.GerritReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003517 ) or (
3518 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003519 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003520 zuul.reporter.gerrit.GerritReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003521 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003522 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003523 zuul.reporter.smtp.SMTPReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003524 )
3525 )
3526
3527 def test_merge_failure_reports(self):
3528 """Check that when a change fails to merge the correct message is sent
3529 to the correct reporter"""
3530 self.config.set('zuul', 'layout_config',
3531 'tests/fixtures/layout-merge-failure.yaml')
3532 self.sched.reconfigure(self.config)
3533 self.registerJobs()
3534
3535 # Check a test failure isn't reported to SMTP
3536 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3537 A.addApproval('CRVW', 2)
3538 self.worker.addFailTest('project-test1', A)
3539 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3540 self.waitUntilSettled()
3541
3542 self.assertEqual(3, len(self.history)) # 3 jobs
3543 self.assertEqual(0, len(self.smtp_messages))
3544
3545 # Check a merge failure is reported to SMTP
3546 # B should be merged, but C will conflict with B
3547 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3548 B.addPatchset(['conflict'])
3549 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3550 C.addPatchset(['conflict'])
3551 B.addApproval('CRVW', 2)
3552 C.addApproval('CRVW', 2)
3553 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3554 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3555 self.waitUntilSettled()
3556
3557 self.assertEqual(6, len(self.history)) # A and B jobs
3558 self.assertEqual(1, len(self.smtp_messages))
3559 self.assertEqual('The merge failed! For more information...',
3560 self.smtp_messages[0]['body'])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003561
James E. Blairf760f0e2016-02-09 08:44:52 -08003562 def test_default_merge_failure_reports(self):
3563 """Check that the default merge failure reports are correct."""
3564
3565 # A should report success, B should report merge failure.
3566 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3567 A.addPatchset(['conflict'])
3568 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3569 B.addPatchset(['conflict'])
3570 A.addApproval('CRVW', 2)
3571 B.addApproval('CRVW', 2)
3572 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3573 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3574 self.waitUntilSettled()
3575
3576 self.assertEqual(3, len(self.history)) # A jobs
3577 self.assertEqual(A.reported, 2)
3578 self.assertEqual(B.reported, 2)
3579 self.assertEqual(A.data['status'], 'MERGED')
3580 self.assertEqual(B.data['status'], 'NEW')
3581 self.assertIn('Build succeeded', A.messages[1])
3582 self.assertIn('Merge Failed', B.messages[1])
3583 self.assertIn('automatically merged', B.messages[1])
3584 self.assertNotIn('logs.example.com', B.messages[1])
3585 self.assertNotIn('SKIPPED', B.messages[1])
3586
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003587 def test_swift_instructions(self):
3588 "Test that the correct swift instructions are sent to the workers"
3589 self.config.set('zuul', 'layout_config',
3590 'tests/fixtures/layout-swift.yaml')
3591 self.sched.reconfigure(self.config)
3592 self.registerJobs()
3593
3594 self.worker.hold_jobs_in_build = True
3595 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3596
3597 A.addApproval('CRVW', 2)
3598 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3599 self.waitUntilSettled()
3600
3601 self.assertEqual(
3602 "https://storage.example.org/V1/AUTH_account/merge_logs/1/1/1/"
3603 "gate/test-merge/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003604 self.builds[0].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003605 self.assertEqual(5,
3606 len(self.builds[0].parameters['SWIFT_logs_HMAC_BODY'].
3607 split('\n')))
3608 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[0].parameters)
3609
3610 self.assertEqual(
3611 "https://storage.example.org/V1/AUTH_account/logs/1/1/1/"
3612 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003613 self.builds[1].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003614 self.assertEqual(5,
3615 len(self.builds[1].parameters['SWIFT_logs_HMAC_BODY'].
3616 split('\n')))
3617 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[1].parameters)
3618
3619 self.assertEqual(
3620 "https://storage.example.org/V1/AUTH_account/stash/1/1/1/"
3621 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003622 self.builds[1].parameters['SWIFT_MOSTLY_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003623 self.assertEqual(5,
3624 len(self.builds[1].
3625 parameters['SWIFT_MOSTLY_HMAC_BODY'].split('\n')))
3626 self.assertIn('SWIFT_MOSTLY_SIGNATURE', self.builds[1].parameters)
3627
3628 self.worker.hold_jobs_in_build = False
3629 self.worker.release()
3630 self.waitUntilSettled()
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003631
3632 def test_client_get_running_jobs(self):
3633 "Test that the RPC client can get a list of running jobs"
3634 self.worker.hold_jobs_in_build = True
3635 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3636 A.addApproval('CRVW', 2)
3637 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3638 self.waitUntilSettled()
3639
3640 client = zuul.rpcclient.RPCClient('127.0.0.1',
3641 self.gearman_server.port)
3642
3643 # Wait for gearman server to send the initial workData back to zuul
3644 start = time.time()
3645 while True:
3646 if time.time() - start > 10:
3647 raise Exception("Timeout waiting for gearman server to report "
3648 + "back to the client")
3649 build = self.launcher.builds.values()[0]
3650 if build.worker.name == "My Worker":
3651 break
3652 else:
3653 time.sleep(0)
3654
3655 running_items = client.get_running_jobs()
3656
3657 self.assertEqual(1, len(running_items))
3658 running_item = running_items[0]
3659 self.assertEqual([], running_item['failing_reasons'])
3660 self.assertEqual([], running_item['items_behind'])
3661 self.assertEqual('https://hostname/1', running_item['url'])
3662 self.assertEqual(None, running_item['item_ahead'])
3663 self.assertEqual('org/project', running_item['project'])
3664 self.assertEqual(None, running_item['remaining_time'])
3665 self.assertEqual(True, running_item['active'])
3666 self.assertEqual('1,1', running_item['id'])
3667
3668 self.assertEqual(3, len(running_item['jobs']))
3669 for job in running_item['jobs']:
3670 if job['name'] == 'project-merge':
3671 self.assertEqual('project-merge', job['name'])
3672 self.assertEqual('gate', job['pipeline'])
3673 self.assertEqual(False, job['retry'])
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003674 self.assertEqual('https://server/job/project-merge/0/',
3675 job['url'])
3676 self.assertEqual(7, len(job['worker']))
3677 self.assertEqual(False, job['canceled'])
3678 self.assertEqual(True, job['voting'])
3679 self.assertEqual(None, job['result'])
3680 self.assertEqual('gate', job['pipeline'])
3681 break
3682
3683 self.worker.hold_jobs_in_build = False
3684 self.worker.release()
3685 self.waitUntilSettled()
3686
3687 running_items = client.get_running_jobs()
3688 self.assertEqual(0, len(running_items))
James E. Blairbadc1ad2014-04-28 13:55:14 -07003689
3690 def test_nonvoting_pipeline(self):
3691 "Test that a nonvoting pipeline (experimental) can still report"
3692
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003693 A = self.fake_gerrit.addFakeChange('org/experimental-project',
3694 'master', 'A')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003695 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3696 self.waitUntilSettled()
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003697 self.assertEqual(
3698 self.getJobFromHistory('experimental-project-test').result,
3699 'SUCCESS')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003700 self.assertEqual(A.reported, 1)
James E. Blair5ee24252014-12-30 10:12:29 -08003701
3702 def test_crd_gate(self):
3703 "Test cross-repo dependencies"
3704 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3705 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3706 A.addApproval('CRVW', 2)
3707 B.addApproval('CRVW', 2)
3708
3709 AM2 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM2')
3710 AM1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM1')
3711 AM2.setMerged()
3712 AM1.setMerged()
3713
3714 BM2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM2')
3715 BM1 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM1')
3716 BM2.setMerged()
3717 BM1.setMerged()
3718
3719 # A -> AM1 -> AM2
3720 # B -> BM1 -> BM2
3721 # A Depends-On: B
3722 # M2 is here to make sure it is never queried. If it is, it
3723 # means zuul is walking down the entire history of merged
3724 # changes.
3725
3726 B.setDependsOn(BM1, 1)
3727 BM1.setDependsOn(BM2, 1)
3728
3729 A.setDependsOn(AM1, 1)
3730 AM1.setDependsOn(AM2, 1)
3731
3732 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3733 A.subject, B.data['id'])
3734
3735 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3736 self.waitUntilSettled()
3737
3738 self.assertEqual(A.data['status'], 'NEW')
3739 self.assertEqual(B.data['status'], 'NEW')
3740
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11003741 for connection in self.connections.values():
3742 connection.maintainCache([])
James E. Blair5ee24252014-12-30 10:12:29 -08003743
3744 self.worker.hold_jobs_in_build = True
3745 B.addApproval('APRV', 1)
3746 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3747 self.waitUntilSettled()
3748
3749 self.worker.release('.*-merge')
3750 self.waitUntilSettled()
3751 self.worker.release('.*-merge')
3752 self.waitUntilSettled()
3753 self.worker.hold_jobs_in_build = False
3754 self.worker.release()
3755 self.waitUntilSettled()
3756
3757 self.assertEqual(AM2.queried, 0)
3758 self.assertEqual(BM2.queried, 0)
3759 self.assertEqual(A.data['status'], 'MERGED')
3760 self.assertEqual(B.data['status'], 'MERGED')
3761 self.assertEqual(A.reported, 2)
3762 self.assertEqual(B.reported, 2)
3763
James E. Blair8f78d882015-02-05 08:51:37 -08003764 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3765 '2,1 1,1')
3766
3767 def test_crd_branch(self):
3768 "Test cross-repo dependencies in multiple branches"
3769 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3770 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3771 C = self.fake_gerrit.addFakeChange('org/project2', 'mp', 'C')
3772 C.data['id'] = B.data['id']
3773 A.addApproval('CRVW', 2)
3774 B.addApproval('CRVW', 2)
3775 C.addApproval('CRVW', 2)
3776
3777 # A Depends-On: B+C
3778 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3779 A.subject, B.data['id'])
3780
3781 self.worker.hold_jobs_in_build = True
3782 B.addApproval('APRV', 1)
3783 C.addApproval('APRV', 1)
3784 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3785 self.waitUntilSettled()
3786
3787 self.worker.release('.*-merge')
3788 self.waitUntilSettled()
3789 self.worker.release('.*-merge')
3790 self.waitUntilSettled()
3791 self.worker.release('.*-merge')
3792 self.waitUntilSettled()
3793 self.worker.hold_jobs_in_build = False
3794 self.worker.release()
3795 self.waitUntilSettled()
3796
3797 self.assertEqual(A.data['status'], 'MERGED')
3798 self.assertEqual(B.data['status'], 'MERGED')
3799 self.assertEqual(C.data['status'], 'MERGED')
3800 self.assertEqual(A.reported, 2)
3801 self.assertEqual(B.reported, 2)
3802 self.assertEqual(C.reported, 2)
3803
3804 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3805 '2,1 3,1 1,1')
3806
3807 def test_crd_multiline(self):
3808 "Test multiple depends-on lines in commit"
3809 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3810 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3811 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
3812 A.addApproval('CRVW', 2)
3813 B.addApproval('CRVW', 2)
3814 C.addApproval('CRVW', 2)
3815
3816 # A Depends-On: B+C
3817 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
3818 A.subject, B.data['id'], C.data['id'])
3819
3820 self.worker.hold_jobs_in_build = True
3821 B.addApproval('APRV', 1)
3822 C.addApproval('APRV', 1)
3823 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3824 self.waitUntilSettled()
3825
3826 self.worker.release('.*-merge')
3827 self.waitUntilSettled()
3828 self.worker.release('.*-merge')
3829 self.waitUntilSettled()
3830 self.worker.release('.*-merge')
3831 self.waitUntilSettled()
3832 self.worker.hold_jobs_in_build = False
3833 self.worker.release()
3834 self.waitUntilSettled()
3835
3836 self.assertEqual(A.data['status'], 'MERGED')
3837 self.assertEqual(B.data['status'], 'MERGED')
3838 self.assertEqual(C.data['status'], 'MERGED')
3839 self.assertEqual(A.reported, 2)
3840 self.assertEqual(B.reported, 2)
3841 self.assertEqual(C.reported, 2)
3842
3843 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3844 '2,1 3,1 1,1')
James E. Blair5ee24252014-12-30 10:12:29 -08003845
3846 def test_crd_unshared_gate(self):
3847 "Test cross-repo dependencies in unshared gate queues"
3848 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3849 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3850 A.addApproval('CRVW', 2)
3851 B.addApproval('CRVW', 2)
3852
3853 # A Depends-On: B
3854 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3855 A.subject, B.data['id'])
3856
3857 # A and B do not share a queue, make sure that A is unable to
3858 # enqueue B (and therefore, A is unable to be enqueued).
3859 B.addApproval('APRV', 1)
3860 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3861 self.waitUntilSettled()
3862
3863 self.assertEqual(A.data['status'], 'NEW')
3864 self.assertEqual(B.data['status'], 'NEW')
3865 self.assertEqual(A.reported, 0)
3866 self.assertEqual(B.reported, 0)
3867 self.assertEqual(len(self.history), 0)
3868
3869 # Enqueue and merge B alone.
3870 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3871 self.waitUntilSettled()
3872
3873 self.assertEqual(B.data['status'], 'MERGED')
3874 self.assertEqual(B.reported, 2)
3875
3876 # Now that B is merged, A should be able to be enqueued and
3877 # merged.
3878 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3879 self.waitUntilSettled()
3880
3881 self.assertEqual(A.data['status'], 'MERGED')
3882 self.assertEqual(A.reported, 2)
3883
James E. Blair96698e22015-04-02 07:48:21 -07003884 def test_crd_gate_reverse(self):
3885 "Test reverse cross-repo dependencies"
3886 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3887 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3888 A.addApproval('CRVW', 2)
3889 B.addApproval('CRVW', 2)
3890
3891 # A Depends-On: B
3892
3893 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3894 A.subject, B.data['id'])
3895
3896 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3897 self.waitUntilSettled()
3898
3899 self.assertEqual(A.data['status'], 'NEW')
3900 self.assertEqual(B.data['status'], 'NEW')
3901
3902 self.worker.hold_jobs_in_build = True
3903 A.addApproval('APRV', 1)
3904 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3905 self.waitUntilSettled()
3906
3907 self.worker.release('.*-merge')
3908 self.waitUntilSettled()
3909 self.worker.release('.*-merge')
3910 self.waitUntilSettled()
3911 self.worker.hold_jobs_in_build = False
3912 self.worker.release()
3913 self.waitUntilSettled()
3914
3915 self.assertEqual(A.data['status'], 'MERGED')
3916 self.assertEqual(B.data['status'], 'MERGED')
3917 self.assertEqual(A.reported, 2)
3918 self.assertEqual(B.reported, 2)
3919
3920 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3921 '2,1 1,1')
3922
James E. Blair5ee24252014-12-30 10:12:29 -08003923 def test_crd_cycle(self):
3924 "Test cross-repo dependency cycles"
3925 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3926 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3927 A.addApproval('CRVW', 2)
3928 B.addApproval('CRVW', 2)
3929
3930 # A -> B -> A (via commit-depends)
3931
3932 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3933 A.subject, B.data['id'])
3934 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3935 B.subject, A.data['id'])
3936
3937 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3938 self.waitUntilSettled()
3939
3940 self.assertEqual(A.reported, 0)
3941 self.assertEqual(B.reported, 0)
3942 self.assertEqual(A.data['status'], 'NEW')
3943 self.assertEqual(B.data['status'], 'NEW')
James E. Blairbfb8e042014-12-30 17:01:44 -08003944
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00003945 def test_crd_gate_unknown(self):
3946 "Test unknown projects in dependent pipeline"
3947 self.init_repo("org/unknown")
3948 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3949 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'B')
3950 A.addApproval('CRVW', 2)
3951 B.addApproval('CRVW', 2)
3952
3953 # A Depends-On: B
3954 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3955 A.subject, B.data['id'])
3956
3957 B.addApproval('APRV', 1)
3958 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3959 self.waitUntilSettled()
3960
3961 # Unknown projects cannot share a queue with any other
3962 # since they don't have common jobs with any other (they have no jobs).
3963 # Changes which depend on unknown project changes
3964 # should not be processed in dependent pipeline
3965 self.assertEqual(A.data['status'], 'NEW')
3966 self.assertEqual(B.data['status'], 'NEW')
3967 self.assertEqual(A.reported, 0)
3968 self.assertEqual(B.reported, 0)
3969 self.assertEqual(len(self.history), 0)
3970
3971 # Simulate change B being gated outside this layout
3972 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3973 B.setMerged()
3974 self.waitUntilSettled()
3975 self.assertEqual(len(self.history), 0)
3976
3977 # Now that B is merged, A should be able to be enqueued and
3978 # merged.
3979 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3980 self.waitUntilSettled()
3981
3982 self.assertEqual(A.data['status'], 'MERGED')
3983 self.assertEqual(A.reported, 2)
3984 self.assertEqual(B.data['status'], 'MERGED')
3985 self.assertEqual(B.reported, 0)
3986
James E. Blairbfb8e042014-12-30 17:01:44 -08003987 def test_crd_check(self):
3988 "Test cross-repo dependencies in independent pipelines"
3989
3990 self.gearman_server.hold_jobs_in_queue = True
3991 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3992 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3993
3994 # A Depends-On: B
3995 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3996 A.subject, B.data['id'])
3997
3998 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3999 self.waitUntilSettled()
4000
4001 queue = self.gearman_server.getQueue()
4002 ref = self.getParameter(queue[-1], 'ZUUL_REF')
4003 self.gearman_server.hold_jobs_in_queue = False
4004 self.gearman_server.release()
4005 self.waitUntilSettled()
4006
4007 path = os.path.join(self.git_root, "org/project1")
4008 repo = git.Repo(path)
4009 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4010 repo_messages.reverse()
4011 correct_messages = ['initial commit', 'A-1']
4012 self.assertEqual(repo_messages, correct_messages)
4013
4014 path = os.path.join(self.git_root, "org/project2")
4015 repo = git.Repo(path)
4016 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4017 repo_messages.reverse()
4018 correct_messages = ['initial commit', 'B-1']
4019 self.assertEqual(repo_messages, correct_messages)
4020
4021 self.assertEqual(A.data['status'], 'NEW')
4022 self.assertEqual(B.data['status'], 'NEW')
4023 self.assertEqual(A.reported, 1)
4024 self.assertEqual(B.reported, 0)
4025
4026 self.assertEqual(self.history[0].changes, '2,1 1,1')
4027 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair8f78d882015-02-05 08:51:37 -08004028
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004029 def test_crd_check_git_depends(self):
4030 "Test single-repo dependencies in independent pipelines"
James E. Blairb8c16472015-05-05 14:55:26 -07004031 self.gearman_server.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004032 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4033 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4034
4035 # Add two git-dependent changes and make sure they both report
4036 # success.
4037 B.setDependsOn(A, 1)
4038 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4039 self.waitUntilSettled()
4040 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4041 self.waitUntilSettled()
4042
James E. Blairb8c16472015-05-05 14:55:26 -07004043 self.orderedRelease()
4044 self.gearman_server.hold_jobs_in_build = False
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004045 self.waitUntilSettled()
4046
4047 self.assertEqual(A.data['status'], 'NEW')
4048 self.assertEqual(B.data['status'], 'NEW')
4049 self.assertEqual(A.reported, 1)
4050 self.assertEqual(B.reported, 1)
4051
4052 self.assertEqual(self.history[0].changes, '1,1')
4053 self.assertEqual(self.history[-1].changes, '1,1 2,1')
4054 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4055
4056 self.assertIn('Build succeeded', A.messages[0])
4057 self.assertIn('Build succeeded', B.messages[0])
4058
4059 def test_crd_check_duplicate(self):
4060 "Test duplicate check in independent pipelines"
James E. Blair1e263032015-05-07 14:35:34 -07004061 self.worker.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004062 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4063 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4064 check_pipeline = self.sched.layout.pipelines['check']
4065
4066 # Add two git-dependent changes...
4067 B.setDependsOn(A, 1)
4068 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4069 self.waitUntilSettled()
4070 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4071
4072 # ...make sure the live one is not duplicated...
4073 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4074 self.waitUntilSettled()
4075 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4076
4077 # ...but the non-live one is able to be.
4078 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4079 self.waitUntilSettled()
4080 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4081
Clark Boylandd849822015-03-02 12:38:14 -08004082 # Release jobs in order to avoid races with change A jobs
4083 # finishing before change B jobs.
James E. Blaird7650852015-05-07 15:47:37 -07004084 self.orderedRelease()
James E. Blair1e263032015-05-07 14:35:34 -07004085 self.worker.hold_jobs_in_build = False
4086 self.worker.release()
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004087 self.waitUntilSettled()
4088
4089 self.assertEqual(A.data['status'], 'NEW')
4090 self.assertEqual(B.data['status'], 'NEW')
4091 self.assertEqual(A.reported, 1)
4092 self.assertEqual(B.reported, 1)
4093
4094 self.assertEqual(self.history[0].changes, '1,1 2,1')
4095 self.assertEqual(self.history[1].changes, '1,1')
4096 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4097
4098 self.assertIn('Build succeeded', A.messages[0])
4099 self.assertIn('Build succeeded', B.messages[0])
4100
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004101 def _test_crd_check_reconfiguration(self, project1, project2):
James E. Blair8f78d882015-02-05 08:51:37 -08004102 "Test cross-repo dependencies re-enqueued in independent pipelines"
4103
4104 self.gearman_server.hold_jobs_in_queue = True
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004105 A = self.fake_gerrit.addFakeChange(project1, 'master', 'A')
4106 B = self.fake_gerrit.addFakeChange(project2, 'master', 'B')
James E. Blair8f78d882015-02-05 08:51:37 -08004107
4108 # A Depends-On: B
4109 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4110 A.subject, B.data['id'])
4111
4112 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4113 self.waitUntilSettled()
4114
4115 self.sched.reconfigure(self.config)
4116
4117 # Make sure the items still share a change queue, and the
4118 # first one is not live.
4119 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 1)
4120 queue = self.sched.layout.pipelines['check'].queues[0]
4121 first_item = queue.queue[0]
4122 for item in queue.queue:
4123 self.assertEqual(item.queue, first_item.queue)
4124 self.assertFalse(first_item.live)
4125 self.assertTrue(queue.queue[1].live)
4126
4127 self.gearman_server.hold_jobs_in_queue = False
4128 self.gearman_server.release()
4129 self.waitUntilSettled()
4130
4131 self.assertEqual(A.data['status'], 'NEW')
4132 self.assertEqual(B.data['status'], 'NEW')
4133 self.assertEqual(A.reported, 1)
4134 self.assertEqual(B.reported, 0)
4135
4136 self.assertEqual(self.history[0].changes, '2,1 1,1')
4137 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair17dd6772015-02-09 14:45:18 -08004138
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004139 def test_crd_check_reconfiguration(self):
4140 self._test_crd_check_reconfiguration('org/project1', 'org/project2')
4141
4142 def test_crd_undefined_project(self):
4143 """Test that undefined projects in dependencies are handled for
4144 independent pipelines"""
4145 # It's a hack for fake gerrit,
4146 # as it implies repo creation upon the creation of any change
4147 self.init_repo("org/unknown")
4148 self._test_crd_check_reconfiguration('org/project1', 'org/unknown')
4149
James E. Blair17dd6772015-02-09 14:45:18 -08004150 def test_crd_check_ignore_dependencies(self):
4151 "Test cross-repo dependencies can be ignored"
4152 self.config.set('zuul', 'layout_config',
4153 'tests/fixtures/layout-ignore-dependencies.yaml')
4154 self.sched.reconfigure(self.config)
4155 self.registerJobs()
4156
4157 self.gearman_server.hold_jobs_in_queue = True
4158 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4159 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4160 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
4161
4162 # A Depends-On: B
4163 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4164 A.subject, B.data['id'])
4165 # C git-depends on B
4166 C.setDependsOn(B, 1)
4167 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4168 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4169 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4170 self.waitUntilSettled()
4171
4172 # Make sure none of the items share a change queue, and all
4173 # are live.
4174 check_pipeline = self.sched.layout.pipelines['check']
4175 self.assertEqual(len(check_pipeline.queues), 3)
4176 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4177 for item in check_pipeline.getAllItems():
4178 self.assertTrue(item.live)
4179
4180 self.gearman_server.hold_jobs_in_queue = False
4181 self.gearman_server.release()
4182 self.waitUntilSettled()
4183
4184 self.assertEqual(A.data['status'], 'NEW')
4185 self.assertEqual(B.data['status'], 'NEW')
4186 self.assertEqual(C.data['status'], 'NEW')
4187 self.assertEqual(A.reported, 1)
4188 self.assertEqual(B.reported, 1)
4189 self.assertEqual(C.reported, 1)
4190
4191 # Each job should have tested exactly one change
4192 for job in self.history:
4193 self.assertEqual(len(job.changes.split()), 1)
James E. Blair96698e22015-04-02 07:48:21 -07004194
4195 def test_crd_check_transitive(self):
4196 "Test transitive cross-repo dependencies"
4197 # Specifically, if A -> B -> C, and C gets a new patchset and
4198 # A gets a new patchset, ensure the test of A,2 includes B,1
4199 # and C,2 (not C,1 which would indicate stale data in the
4200 # cache for B).
4201 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4202 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4203 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
4204
4205 # A Depends-On: B
4206 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4207 A.subject, B.data['id'])
4208
4209 # B Depends-On: C
4210 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4211 B.subject, C.data['id'])
4212
4213 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4214 self.waitUntilSettled()
4215 self.assertEqual(self.history[-1].changes, '3,1 2,1 1,1')
4216
4217 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4218 self.waitUntilSettled()
4219 self.assertEqual(self.history[-1].changes, '3,1 2,1')
4220
4221 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4222 self.waitUntilSettled()
4223 self.assertEqual(self.history[-1].changes, '3,1')
4224
4225 C.addPatchset()
4226 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(2))
4227 self.waitUntilSettled()
4228 self.assertEqual(self.history[-1].changes, '3,2')
4229
4230 A.addPatchset()
4231 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
4232 self.waitUntilSettled()
4233 self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004234
James E. Blair92464a22016-04-05 10:21:26 -07004235 def test_crd_cycle_join(self):
4236 "Test an updated change creates a cycle"
4237 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
4238
4239 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4240 self.waitUntilSettled()
4241
4242 # Create B->A
4243 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4244 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4245 B.subject, A.data['id'])
4246 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4247 self.waitUntilSettled()
4248
4249 # Update A to add A->B (a cycle).
4250 A.addPatchset()
4251 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4252 A.subject, B.data['id'])
4253 # Normally we would submit the patchset-created event for
4254 # processing here, however, we have no way of noting whether
4255 # the dependency cycle detection correctly raised an
4256 # exception, so instead, we reach into the source driver and
4257 # call the method that would ultimately be called by the event
4258 # processing.
4259
4260 source = self.sched.layout.pipelines['gate'].source
4261 with testtools.ExpectedException(
4262 Exception, "Dependency cycle detected"):
4263 source._getChange(u'1', u'2', True)
4264 self.log.debug("Got expected dependency cycle exception")
4265
4266 # Now if we update B to remove the depends-on, everything
4267 # should be okay. B; A->B
4268
4269 B.addPatchset()
4270 B.data['commitMessage'] = '%s\n' % (B.subject,)
4271 source._getChange(u'1', u'2', True)
4272 source._getChange(u'2', u'2', True)
4273
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004274 def test_disable_at(self):
4275 "Test a pipeline will only report to the disabled trigger when failing"
4276
4277 self.config.set('zuul', 'layout_config',
4278 'tests/fixtures/layout-disable-at.yaml')
4279 self.sched.reconfigure(self.config)
4280
4281 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4282 self.assertEqual(
4283 0, self.sched.layout.pipelines['check']._consecutive_failures)
4284 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4285
4286 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
4287 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
4288 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
4289 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
4290 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
4291 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
4292 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
4293 H = self.fake_gerrit.addFakeChange('org/project', 'master', 'H')
4294 I = self.fake_gerrit.addFakeChange('org/project', 'master', 'I')
4295 J = self.fake_gerrit.addFakeChange('org/project', 'master', 'J')
4296 K = self.fake_gerrit.addFakeChange('org/project', 'master', 'K')
4297
4298 self.worker.addFailTest('project-test1', A)
4299 self.worker.addFailTest('project-test1', B)
4300 # Let C pass, resetting the counter
4301 self.worker.addFailTest('project-test1', D)
4302 self.worker.addFailTest('project-test1', E)
4303 self.worker.addFailTest('project-test1', F)
4304 self.worker.addFailTest('project-test1', G)
4305 self.worker.addFailTest('project-test1', H)
4306 # I also passes but should only report to the disabled reporters
4307 self.worker.addFailTest('project-test1', J)
4308 self.worker.addFailTest('project-test1', K)
4309
4310 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4311 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4312 self.waitUntilSettled()
4313
4314 self.assertEqual(
4315 2, self.sched.layout.pipelines['check']._consecutive_failures)
4316 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4317
4318 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4319 self.waitUntilSettled()
4320
4321 self.assertEqual(
4322 0, self.sched.layout.pipelines['check']._consecutive_failures)
4323 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4324
4325 self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(1))
4326 self.fake_gerrit.addEvent(E.getPatchsetCreatedEvent(1))
4327 self.fake_gerrit.addEvent(F.getPatchsetCreatedEvent(1))
4328 self.waitUntilSettled()
4329
4330 # We should be disabled now
4331 self.assertEqual(
4332 3, self.sched.layout.pipelines['check']._consecutive_failures)
4333 self.assertTrue(self.sched.layout.pipelines['check']._disabled)
4334
4335 # We need to wait between each of these patches to make sure the
4336 # smtp messages come back in an expected order
4337 self.fake_gerrit.addEvent(G.getPatchsetCreatedEvent(1))
4338 self.waitUntilSettled()
4339 self.fake_gerrit.addEvent(H.getPatchsetCreatedEvent(1))
4340 self.waitUntilSettled()
4341 self.fake_gerrit.addEvent(I.getPatchsetCreatedEvent(1))
4342 self.waitUntilSettled()
4343
4344 # The first 6 (ABCDEF) jobs should have reported back to gerrt thus
4345 # leaving a message on each change
4346 self.assertEqual(1, len(A.messages))
4347 self.assertIn('Build failed.', A.messages[0])
4348 self.assertEqual(1, len(B.messages))
4349 self.assertIn('Build failed.', B.messages[0])
4350 self.assertEqual(1, len(C.messages))
4351 self.assertIn('Build succeeded.', C.messages[0])
4352 self.assertEqual(1, len(D.messages))
4353 self.assertIn('Build failed.', D.messages[0])
4354 self.assertEqual(1, len(E.messages))
4355 self.assertIn('Build failed.', E.messages[0])
4356 self.assertEqual(1, len(F.messages))
4357 self.assertIn('Build failed.', F.messages[0])
4358
4359 # The last 3 (GHI) would have only reported via smtp.
4360 self.assertEqual(3, len(self.smtp_messages))
4361 self.assertEqual(0, len(G.messages))
4362 self.assertIn('Build failed.', self.smtp_messages[0]['body'])
4363 self.assertIn('/7/1/check', self.smtp_messages[0]['body'])
4364 self.assertEqual(0, len(H.messages))
4365 self.assertIn('Build failed.', self.smtp_messages[1]['body'])
4366 self.assertIn('/8/1/check', self.smtp_messages[1]['body'])
4367 self.assertEqual(0, len(I.messages))
4368 self.assertIn('Build succeeded.', self.smtp_messages[2]['body'])
4369 self.assertIn('/9/1/check', self.smtp_messages[2]['body'])
4370
4371 # Now reload the configuration (simulate a HUP) to check the pipeline
4372 # comes out of disabled
4373 self.sched.reconfigure(self.config)
4374
4375 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4376 self.assertEqual(
4377 0, self.sched.layout.pipelines['check']._consecutive_failures)
4378 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4379
4380 self.fake_gerrit.addEvent(J.getPatchsetCreatedEvent(1))
4381 self.fake_gerrit.addEvent(K.getPatchsetCreatedEvent(1))
4382 self.waitUntilSettled()
4383
4384 self.assertEqual(
4385 2, self.sched.layout.pipelines['check']._consecutive_failures)
4386 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4387
4388 # J and K went back to gerrit
4389 self.assertEqual(1, len(J.messages))
4390 self.assertIn('Build failed.', J.messages[0])
4391 self.assertEqual(1, len(K.messages))
4392 self.assertIn('Build failed.', K.messages[0])
4393 # No more messages reported via smtp
4394 self.assertEqual(3, len(self.smtp_messages))
Joshua Heskethd6dbd682015-12-22 10:06:54 +11004395
4396 def test_success_pattern(self):
4397 "Ensure bad build params are ignored"
4398
4399 # Use SMTP reporter to grab the result message easier
4400 self.init_repo("org/docs")
4401 self.config.set('zuul', 'layout_config',
4402 'tests/fixtures/layout-success-pattern.yaml')
4403 self.sched.reconfigure(self.config)
4404 self.worker.hold_jobs_in_build = True
4405 self.registerJobs()
4406
4407 A = self.fake_gerrit.addFakeChange('org/docs', 'master', 'A')
4408 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4409 self.waitUntilSettled()
4410
4411 # Grab build id
4412 self.assertEqual(len(self.builds), 1)
4413 uuid = self.builds[0].unique[:7]
4414
4415 self.worker.hold_jobs_in_build = False
4416 self.worker.release()
4417 self.waitUntilSettled()
4418
4419 self.assertEqual(len(self.smtp_messages), 1)
4420 body = self.smtp_messages[0]['body'].splitlines()
4421 self.assertEqual('Build succeeded.', body[0])
4422
4423 self.assertIn(
4424 '- docs-draft-test http://docs-draft.example.org/1/1/1/check/'
4425 'docs-draft-test/%s/publish-docs/' % uuid,
4426 body[2])
4427 self.assertIn(
4428 '- docs-draft-test2 https://server/job/docs-draft-test2/1/',
4429 body[3])