blob: ea512a2dbc83287430478f1e1a9067329ef3351d [file] [log] [blame]
James E. Blairb0fcae42012-07-17 11:12:10 -07001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
James E. Blairb0fcae42012-07-17 11:12:10 -070017import json
Monty Taylorbc758832013-06-17 17:22:42 -040018import logging
19import os
James E. Blairb0fcae42012-07-17 11:12:10 -070020import re
James E. Blair4886cc12012-07-18 15:39:41 -070021import shutil
Monty Taylorbc758832013-06-17 17:22:42 -040022import time
Maru Newby3fe5f852015-01-13 04:22:14 +000023import yaml
Monty Taylorbc758832013-06-17 17:22:42 -040024
James E. Blair4886cc12012-07-18 15:39:41 -070025import git
Morgan Fainberg293f7f82016-05-30 14:01:22 -070026from six.moves import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040027import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070028
Maru Newby3fe5f852015-01-13 04:22:14 +000029import zuul.change_matcher
James E. Blairb0fcae42012-07-17 11:12:10 -070030import zuul.scheduler
James E. Blairad28e912013-11-27 10:43:22 -080031import zuul.rpcclient
Joshua Hesketh1879cf72013-08-19 14:13:15 +100032import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100033import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070034
Maru Newby3fe5f852015-01-13 04:22:14 +000035from tests.base import (
Maru Newby3fe5f852015-01-13 04:22:14 +000036 ZuulTestCase,
37 repack_repo,
38)
James E. Blairb0fcae42012-07-17 11:12:10 -070039
James E. Blair1f4c2bb2013-04-26 08:40:46 -070040logging.basicConfig(level=logging.DEBUG,
41 format='%(asctime)s %(name)-32s '
42 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070043
44
Clark Boylanb640e052014-04-03 16:41:46 -070045class TestScheduler(ZuulTestCase):
Antoine Mussobd86a312014-01-08 14:51:33 +010046
James E. Blairb0fcae42012-07-17 11:12:10 -070047 def test_jobs_launched(self):
48 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -070049
James E. Blairb0fcae42012-07-17 11:12:10 -070050 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -070051 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070052 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
53 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -040054 self.assertEqual(self.getJobFromHistory('project-merge').result,
55 'SUCCESS')
56 self.assertEqual(self.getJobFromHistory('project-test1').result,
57 'SUCCESS')
58 self.assertEqual(self.getJobFromHistory('project-test2').result,
59 'SUCCESS')
60 self.assertEqual(A.data['status'], 'MERGED')
61 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070062
James E. Blair66eeebf2013-07-27 17:44:32 -070063 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
64 self.assertReportedStat('zuul.pipeline.gate.current_changes',
65 value='1|g')
66 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
67 kind='ms')
68 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
69 value='1|c')
70 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
71 self.assertReportedStat('zuul.pipeline.gate.total_changes',
72 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -070073 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -070074 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -070075 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -070076 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -070077
James E. Blair5821bd92015-09-16 08:48:15 -070078 for build in self.builds:
79 self.assertEqual(build.parameters['ZUUL_VOTING'], '1')
80
James E. Blair3cb10702013-08-24 08:56:03 -070081 def test_initial_pipeline_gauges(self):
82 "Test that each pipeline reported its length on start"
83 pipeline_names = self.sched.layout.pipelines.keys()
84 self.assertNotEqual(len(pipeline_names), 0)
85 for name in pipeline_names:
86 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
87 value='0|g')
88
James E. Blair42f74822013-05-14 15:18:03 -070089 def test_duplicate_pipelines(self):
90 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -070091
James E. Blair42f74822013-05-14 15:18:03 -070092 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
93 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
94 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -070095
Monty Taylor98f0f3e2013-07-06 16:02:31 -040096 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -040097 self.history[0].name == 'project-test1'
98 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -070099
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400100 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -0700101 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400102 self.assertIn('dup1/project-test1', A.messages[0])
103 self.assertNotIn('dup2/project-test1', A.messages[0])
104 self.assertNotIn('dup1/project-test1', A.messages[1])
105 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -0700106 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400107 self.assertIn('dup1/project-test1', A.messages[1])
108 self.assertNotIn('dup2/project-test1', A.messages[1])
109 self.assertNotIn('dup1/project-test1', A.messages[0])
110 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -0700111
James E. Blairb0fcae42012-07-17 11:12:10 -0700112 def test_parallel_changes(self):
113 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700114
115 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700116 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
117 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
118 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700119 A.addApproval('CRVW', 2)
120 B.addApproval('CRVW', 2)
121 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700122
123 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
124 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
125 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
126
127 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400128 self.assertEqual(len(self.builds), 1)
129 self.assertEqual(self.builds[0].name, 'project-merge')
130 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700131
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700132 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700133 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400134 self.assertEqual(len(self.builds), 3)
135 self.assertEqual(self.builds[0].name, 'project-test1')
136 self.assertTrue(self.job_has_changes(self.builds[0], A))
137 self.assertEqual(self.builds[1].name, 'project-test2')
138 self.assertTrue(self.job_has_changes(self.builds[1], A))
139 self.assertEqual(self.builds[2].name, 'project-merge')
140 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700141
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700142 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700143 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400144 self.assertEqual(len(self.builds), 5)
145 self.assertEqual(self.builds[0].name, 'project-test1')
146 self.assertTrue(self.job_has_changes(self.builds[0], A))
147 self.assertEqual(self.builds[1].name, 'project-test2')
148 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700149
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400150 self.assertEqual(self.builds[2].name, 'project-test1')
151 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
152 self.assertEqual(self.builds[3].name, 'project-test2')
153 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700154
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400155 self.assertEqual(self.builds[4].name, 'project-merge')
156 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700157
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700158 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700159 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400160 self.assertEqual(len(self.builds), 6)
161 self.assertEqual(self.builds[0].name, 'project-test1')
162 self.assertTrue(self.job_has_changes(self.builds[0], A))
163 self.assertEqual(self.builds[1].name, 'project-test2')
164 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700165
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400166 self.assertEqual(self.builds[2].name, 'project-test1')
167 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
168 self.assertEqual(self.builds[3].name, 'project-test2')
169 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700170
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400171 self.assertEqual(self.builds[4].name, 'project-test1')
172 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
173 self.assertEqual(self.builds[5].name, 'project-test2')
174 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700175
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700176 self.worker.hold_jobs_in_build = False
177 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700178 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400179 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -0700180
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400181 self.assertEqual(len(self.history), 9)
182 self.assertEqual(A.data['status'], 'MERGED')
183 self.assertEqual(B.data['status'], 'MERGED')
184 self.assertEqual(C.data['status'], 'MERGED')
185 self.assertEqual(A.reported, 2)
186 self.assertEqual(B.reported, 2)
187 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700188
189 def test_failed_changes(self):
190 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -0400191 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700192
James E. Blairb02a3bb2012-07-30 17:49:55 -0700193 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
194 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700195 A.addApproval('CRVW', 2)
196 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700197
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700198 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700199
James E. Blaire2819012013-06-28 17:17:26 -0400200 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
201 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700202 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -0400203
204 self.worker.release('.*-merge')
205 self.waitUntilSettled()
206
207 self.worker.hold_jobs_in_build = False
208 self.worker.release()
209
210 self.waitUntilSettled()
211 # It's certain that the merge job for change 2 will run, but
212 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400213 self.assertTrue(len(self.history) > 6)
214 self.assertEqual(A.data['status'], 'NEW')
215 self.assertEqual(B.data['status'], 'MERGED')
216 self.assertEqual(A.reported, 2)
217 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700218
219 def test_independent_queues(self):
220 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700221
222 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900223 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700224 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
225 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700226 A.addApproval('CRVW', 2)
227 B.addApproval('CRVW', 2)
228 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700229
230 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
231 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
232 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
233
James E. Blairb02a3bb2012-07-30 17:49:55 -0700234 self.waitUntilSettled()
235
236 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400237 self.assertEqual(len(self.builds), 2)
238 self.assertEqual(self.builds[0].name, 'project-merge')
239 self.assertTrue(self.job_has_changes(self.builds[0], A))
240 self.assertEqual(self.builds[1].name, 'project1-merge')
241 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700242
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700243 # Release the current merge builds
244 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700245 self.waitUntilSettled()
246 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700247 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700248 self.waitUntilSettled()
249
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700250 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -0700251 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400252 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700253
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700254 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700255 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400256 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700257
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400258 self.assertEqual(len(self.history), 11)
259 self.assertEqual(A.data['status'], 'MERGED')
260 self.assertEqual(B.data['status'], 'MERGED')
261 self.assertEqual(C.data['status'], 'MERGED')
262 self.assertEqual(A.reported, 2)
263 self.assertEqual(B.reported, 2)
264 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700265
266 def test_failed_change_at_head(self):
267 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700268
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700269 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -0700270 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
271 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
272 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700273 A.addApproval('CRVW', 2)
274 B.addApproval('CRVW', 2)
275 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700276
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700277 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700278
279 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
280 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
281 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
282
283 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -0700284
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400285 self.assertEqual(len(self.builds), 1)
286 self.assertEqual(self.builds[0].name, 'project-merge')
287 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700288
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700289 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700290 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700291 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700292 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700293 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700294 self.waitUntilSettled()
295
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400296 self.assertEqual(len(self.builds), 6)
297 self.assertEqual(self.builds[0].name, 'project-test1')
298 self.assertEqual(self.builds[1].name, 'project-test2')
299 self.assertEqual(self.builds[2].name, 'project-test1')
300 self.assertEqual(self.builds[3].name, 'project-test2')
301 self.assertEqual(self.builds[4].name, 'project-test1')
302 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700303
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400304 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700305 self.waitUntilSettled()
306
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400307 # project-test2, project-merge for B
308 self.assertEqual(len(self.builds), 2)
309 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -0700310
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700311 self.worker.hold_jobs_in_build = False
312 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700313 self.waitUntilSettled()
314
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400315 self.assertEqual(len(self.builds), 0)
316 self.assertEqual(len(self.history), 15)
317 self.assertEqual(A.data['status'], 'NEW')
318 self.assertEqual(B.data['status'], 'MERGED')
319 self.assertEqual(C.data['status'], 'MERGED')
320 self.assertEqual(A.reported, 2)
321 self.assertEqual(B.reported, 2)
322 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700323
James E. Blair0aac4872013-08-23 14:02:38 -0700324 def test_failed_change_in_middle(self):
325 "Test a failed change in the middle of the queue"
326
327 self.worker.hold_jobs_in_build = True
328 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
329 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
330 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
331 A.addApproval('CRVW', 2)
332 B.addApproval('CRVW', 2)
333 C.addApproval('CRVW', 2)
334
335 self.worker.addFailTest('project-test1', B)
336
337 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
338 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
339 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
340
341 self.waitUntilSettled()
342
343 self.worker.release('.*-merge')
344 self.waitUntilSettled()
345 self.worker.release('.*-merge')
346 self.waitUntilSettled()
347 self.worker.release('.*-merge')
348 self.waitUntilSettled()
349
350 self.assertEqual(len(self.builds), 6)
351 self.assertEqual(self.builds[0].name, 'project-test1')
352 self.assertEqual(self.builds[1].name, 'project-test2')
353 self.assertEqual(self.builds[2].name, 'project-test1')
354 self.assertEqual(self.builds[3].name, 'project-test2')
355 self.assertEqual(self.builds[4].name, 'project-test1')
356 self.assertEqual(self.builds[5].name, 'project-test2')
357
358 self.release(self.builds[2])
359 self.waitUntilSettled()
360
James E. Blair972e3c72013-08-29 12:04:55 -0700361 # project-test1 and project-test2 for A
362 # project-test2 for B
363 # project-merge for C (without B)
364 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -0700365 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
366
James E. Blair972e3c72013-08-29 12:04:55 -0700367 self.worker.release('.*-merge')
368 self.waitUntilSettled()
369
370 # project-test1 and project-test2 for A
371 # project-test2 for B
372 # project-test1 and project-test2 for C
373 self.assertEqual(len(self.builds), 5)
374
James E. Blair0aac4872013-08-23 14:02:38 -0700375 items = self.sched.layout.pipelines['gate'].getAllItems()
376 builds = items[0].current_build_set.getBuilds()
377 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
378 self.assertEqual(self.countJobResults(builds, None), 2)
379 builds = items[1].current_build_set.getBuilds()
380 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
381 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
382 self.assertEqual(self.countJobResults(builds, None), 1)
383 builds = items[2].current_build_set.getBuilds()
384 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -0700385 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -0700386
387 self.worker.hold_jobs_in_build = False
388 self.worker.release()
389 self.waitUntilSettled()
390
391 self.assertEqual(len(self.builds), 0)
392 self.assertEqual(len(self.history), 12)
393 self.assertEqual(A.data['status'], 'MERGED')
394 self.assertEqual(B.data['status'], 'NEW')
395 self.assertEqual(C.data['status'], 'MERGED')
396 self.assertEqual(A.reported, 2)
397 self.assertEqual(B.reported, 2)
398 self.assertEqual(C.reported, 2)
399
James E. Blaird466dc42012-07-31 10:42:56 -0700400 def test_failed_change_at_head_with_queue(self):
401 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700402
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700403 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -0700404 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
405 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
406 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700407 A.addApproval('CRVW', 2)
408 B.addApproval('CRVW', 2)
409 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700410
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700411 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700412
413 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
414 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
415 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
416
417 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700418 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400419 self.assertEqual(len(self.builds), 0)
420 self.assertEqual(len(queue), 1)
421 self.assertEqual(queue[0].name, 'build:project-merge')
422 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700423
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700424 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700425 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700426 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700427 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700428 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700429 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700430 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -0700431
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400432 self.assertEqual(len(self.builds), 0)
433 self.assertEqual(len(queue), 6)
434 self.assertEqual(queue[0].name, 'build:project-test1')
435 self.assertEqual(queue[1].name, 'build:project-test2')
436 self.assertEqual(queue[2].name, 'build:project-test1')
437 self.assertEqual(queue[3].name, 'build:project-test2')
438 self.assertEqual(queue[4].name, 'build:project-test1')
439 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700440
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700441 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700442 self.waitUntilSettled()
443
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400444 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -0700445 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400446 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
447 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -0700448
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700449 self.gearman_server.hold_jobs_in_queue = False
450 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700451 self.waitUntilSettled()
452
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400453 self.assertEqual(len(self.builds), 0)
454 self.assertEqual(len(self.history), 11)
455 self.assertEqual(A.data['status'], 'NEW')
456 self.assertEqual(B.data['status'], 'MERGED')
457 self.assertEqual(C.data['status'], 'MERGED')
458 self.assertEqual(A.reported, 2)
459 self.assertEqual(B.reported, 2)
460 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700461
James E. Blairce8a2132016-05-19 15:21:52 -0700462 def _test_time_database(self, iteration):
463 self.worker.hold_jobs_in_build = True
464 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
465 A.addApproval('CRVW', 2)
466 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
467 self.waitUntilSettled()
468 time.sleep(2)
469
470 data = json.loads(self.sched.formatStatusJSON())
471 found_job = None
472 for pipeline in data['pipelines']:
473 if pipeline['name'] != 'gate':
474 continue
475 for queue in pipeline['change_queues']:
476 for head in queue['heads']:
477 for item in head:
478 for job in item['jobs']:
479 if job['name'] == 'project-merge':
480 found_job = job
481 break
482
483 self.assertIsNotNone(found_job)
484 if iteration == 1:
485 self.assertIsNotNone(found_job['estimated_time'])
486 self.assertIsNone(found_job['remaining_time'])
487 else:
488 self.assertIsNotNone(found_job['estimated_time'])
489 self.assertTrue(found_job['estimated_time'] >= 2)
490 self.assertIsNotNone(found_job['remaining_time'])
491
492 self.worker.hold_jobs_in_build = False
493 self.worker.release()
494 self.waitUntilSettled()
495
496 def test_time_database(self):
497 "Test the time database"
498
499 self._test_time_database(1)
500 self._test_time_database(2)
501
James E. Blairfef71632013-09-23 11:15:47 -0700502 def test_two_failed_changes_at_head(self):
503 "Test that changes are reparented correctly if 2 fail at head"
504
505 self.worker.hold_jobs_in_build = True
506 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
507 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
508 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
509 A.addApproval('CRVW', 2)
510 B.addApproval('CRVW', 2)
511 C.addApproval('CRVW', 2)
512
513 self.worker.addFailTest('project-test1', A)
514 self.worker.addFailTest('project-test1', B)
515
516 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
517 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
518 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
519 self.waitUntilSettled()
520
521 self.worker.release('.*-merge')
522 self.waitUntilSettled()
523 self.worker.release('.*-merge')
524 self.waitUntilSettled()
525 self.worker.release('.*-merge')
526 self.waitUntilSettled()
527
528 self.assertEqual(len(self.builds), 6)
529 self.assertEqual(self.builds[0].name, 'project-test1')
530 self.assertEqual(self.builds[1].name, 'project-test2')
531 self.assertEqual(self.builds[2].name, 'project-test1')
532 self.assertEqual(self.builds[3].name, 'project-test2')
533 self.assertEqual(self.builds[4].name, 'project-test1')
534 self.assertEqual(self.builds[5].name, 'project-test2')
535
536 self.assertTrue(self.job_has_changes(self.builds[0], A))
537 self.assertTrue(self.job_has_changes(self.builds[2], A))
538 self.assertTrue(self.job_has_changes(self.builds[2], B))
539 self.assertTrue(self.job_has_changes(self.builds[4], A))
540 self.assertTrue(self.job_has_changes(self.builds[4], B))
541 self.assertTrue(self.job_has_changes(self.builds[4], C))
542
543 # Fail change B first
544 self.release(self.builds[2])
545 self.waitUntilSettled()
546
547 # restart of C after B failure
548 self.worker.release('.*-merge')
549 self.waitUntilSettled()
550
551 self.assertEqual(len(self.builds), 5)
552 self.assertEqual(self.builds[0].name, 'project-test1')
553 self.assertEqual(self.builds[1].name, 'project-test2')
554 self.assertEqual(self.builds[2].name, 'project-test2')
555 self.assertEqual(self.builds[3].name, 'project-test1')
556 self.assertEqual(self.builds[4].name, 'project-test2')
557
558 self.assertTrue(self.job_has_changes(self.builds[1], A))
559 self.assertTrue(self.job_has_changes(self.builds[2], A))
560 self.assertTrue(self.job_has_changes(self.builds[2], B))
561 self.assertTrue(self.job_has_changes(self.builds[4], A))
562 self.assertFalse(self.job_has_changes(self.builds[4], B))
563 self.assertTrue(self.job_has_changes(self.builds[4], C))
564
565 # Finish running all passing jobs for change A
566 self.release(self.builds[1])
567 self.waitUntilSettled()
568 # Fail and report change A
569 self.release(self.builds[0])
570 self.waitUntilSettled()
571
572 # restart of B,C after A failure
573 self.worker.release('.*-merge')
574 self.waitUntilSettled()
575 self.worker.release('.*-merge')
576 self.waitUntilSettled()
577
578 self.assertEqual(len(self.builds), 4)
579 self.assertEqual(self.builds[0].name, 'project-test1') # B
580 self.assertEqual(self.builds[1].name, 'project-test2') # B
581 self.assertEqual(self.builds[2].name, 'project-test1') # C
582 self.assertEqual(self.builds[3].name, 'project-test2') # C
583
584 self.assertFalse(self.job_has_changes(self.builds[1], A))
585 self.assertTrue(self.job_has_changes(self.builds[1], B))
586 self.assertFalse(self.job_has_changes(self.builds[1], C))
587
588 self.assertFalse(self.job_has_changes(self.builds[2], A))
589 # After A failed and B and C restarted, B should be back in
590 # C's tests because it has not failed yet.
591 self.assertTrue(self.job_has_changes(self.builds[2], B))
592 self.assertTrue(self.job_has_changes(self.builds[2], C))
593
594 self.worker.hold_jobs_in_build = False
595 self.worker.release()
596 self.waitUntilSettled()
597
598 self.assertEqual(len(self.builds), 0)
599 self.assertEqual(len(self.history), 21)
600 self.assertEqual(A.data['status'], 'NEW')
601 self.assertEqual(B.data['status'], 'NEW')
602 self.assertEqual(C.data['status'], 'MERGED')
603 self.assertEqual(A.reported, 2)
604 self.assertEqual(B.reported, 2)
605 self.assertEqual(C.reported, 2)
606
James E. Blairce8a2132016-05-19 15:21:52 -0700607 def test_parse_skip_if(self):
608 job_yaml = """
609jobs:
610 - name: job_name
611 skip-if:
612 - project: ^project_name$
613 branch: ^stable/icehouse$
614 all-files-match-any:
615 - ^filename$
616 - project: ^project2_name$
617 all-files-match-any:
618 - ^filename2$
619 """.strip()
620 data = yaml.load(job_yaml)
621 config_job = data.get('jobs')[0]
622 cm = zuul.change_matcher
623 expected = cm.MatchAny([
624 cm.MatchAll([
625 cm.ProjectMatcher('^project_name$'),
626 cm.BranchMatcher('^stable/icehouse$'),
627 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
628 ]),
629 cm.MatchAll([
630 cm.ProjectMatcher('^project2_name$'),
631 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
632 ]),
633 ])
634 matcher = self.sched._parseSkipIf(config_job)
635 self.assertEqual(expected, matcher)
636
James E. Blair8c803f82012-07-31 16:25:42 -0700637 def test_patch_order(self):
638 "Test that dependent patches are tested in the right order"
639 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
640 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
641 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
642 A.addApproval('CRVW', 2)
643 B.addApproval('CRVW', 2)
644 C.addApproval('CRVW', 2)
645
646 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
647 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
648 M2.setMerged()
649 M1.setMerged()
650
651 # C -> B -> A -> M1 -> M2
652 # M2 is here to make sure it is never queried. If it is, it
653 # means zuul is walking down the entire history of merged
654 # changes.
655
656 C.setDependsOn(B, 1)
657 B.setDependsOn(A, 1)
658 A.setDependsOn(M1, 1)
659 M1.setDependsOn(M2, 1)
660
661 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
662
663 self.waitUntilSettled()
664
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400665 self.assertEqual(A.data['status'], 'NEW')
666 self.assertEqual(B.data['status'], 'NEW')
667 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -0700668
669 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
670 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
671
672 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400673 self.assertEqual(M2.queried, 0)
674 self.assertEqual(A.data['status'], 'MERGED')
675 self.assertEqual(B.data['status'], 'MERGED')
676 self.assertEqual(C.data['status'], 'MERGED')
677 self.assertEqual(A.reported, 2)
678 self.assertEqual(B.reported, 2)
679 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700680
James E. Blair063672f2015-01-29 13:09:12 -0800681 def test_needed_changes_enqueue(self):
682 "Test that a needed change is enqueued ahead"
683 # A Given a git tree like this, if we enqueue
684 # / \ change C, we should walk up and down the tree
685 # B G and enqueue changes in the order ABCDEFG.
686 # /|\ This is also the order that you would get if
687 # *C E F you enqueued changes in the order ABCDEFG, so
688 # / the ordering is stable across re-enqueue events.
689 # D
690
691 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
692 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
693 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
694 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
695 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
696 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
697 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
698 B.setDependsOn(A, 1)
699 C.setDependsOn(B, 1)
700 D.setDependsOn(C, 1)
701 E.setDependsOn(B, 1)
702 F.setDependsOn(B, 1)
703 G.setDependsOn(A, 1)
704
705 A.addApproval('CRVW', 2)
706 B.addApproval('CRVW', 2)
707 C.addApproval('CRVW', 2)
708 D.addApproval('CRVW', 2)
709 E.addApproval('CRVW', 2)
710 F.addApproval('CRVW', 2)
711 G.addApproval('CRVW', 2)
712 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
713
714 self.waitUntilSettled()
715
716 self.assertEqual(A.data['status'], 'NEW')
717 self.assertEqual(B.data['status'], 'NEW')
718 self.assertEqual(C.data['status'], 'NEW')
719 self.assertEqual(D.data['status'], 'NEW')
720 self.assertEqual(E.data['status'], 'NEW')
721 self.assertEqual(F.data['status'], 'NEW')
722 self.assertEqual(G.data['status'], 'NEW')
723
724 # We're about to add approvals to changes without adding the
725 # triggering events to Zuul, so that we can be sure that it is
726 # enqueing the changes based on dependencies, not because of
727 # triggering events. Since it will have the changes cached
728 # already (without approvals), we need to clear the cache
729 # first.
Joshua Hesketh4bd7da32016-02-17 20:58:47 +1100730 for connection in self.connections.values():
731 connection.maintainCache([])
James E. Blair063672f2015-01-29 13:09:12 -0800732
733 self.worker.hold_jobs_in_build = True
734 A.addApproval('APRV', 1)
735 B.addApproval('APRV', 1)
736 D.addApproval('APRV', 1)
737 E.addApproval('APRV', 1)
738 F.addApproval('APRV', 1)
739 G.addApproval('APRV', 1)
740 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
741
742 for x in range(8):
743 self.worker.release('.*-merge')
744 self.waitUntilSettled()
745 self.worker.hold_jobs_in_build = False
746 self.worker.release()
747 self.waitUntilSettled()
748
749 self.assertEqual(A.data['status'], 'MERGED')
750 self.assertEqual(B.data['status'], 'MERGED')
751 self.assertEqual(C.data['status'], 'MERGED')
752 self.assertEqual(D.data['status'], 'MERGED')
753 self.assertEqual(E.data['status'], 'MERGED')
754 self.assertEqual(F.data['status'], 'MERGED')
755 self.assertEqual(G.data['status'], 'MERGED')
756 self.assertEqual(A.reported, 2)
757 self.assertEqual(B.reported, 2)
758 self.assertEqual(C.reported, 2)
759 self.assertEqual(D.reported, 2)
760 self.assertEqual(E.reported, 2)
761 self.assertEqual(F.reported, 2)
762 self.assertEqual(G.reported, 2)
763 self.assertEqual(self.history[6].changes,
764 '1,1 2,1 3,1 4,1 5,1 6,1 7,1')
765
Joshua Hesketh850ccb62014-11-27 11:31:02 +1100766 def test_source_cache(self):
767 "Test that the source cache operates correctly"
James E. Blair0e933c52013-07-11 10:18:52 -0700768 self.worker.hold_jobs_in_build = True
769
770 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
771 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
772 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
773 A.addApproval('CRVW', 2)
774 B.addApproval('CRVW', 2)
775
776 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
777 M1.setMerged()
778
779 B.setDependsOn(A, 1)
780 A.setDependsOn(M1, 1)
781
782 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
783 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
784
785 self.waitUntilSettled()
786
787 for build in self.builds:
788 if build.parameters['ZUUL_PIPELINE'] == 'check':
789 build.release()
790 self.waitUntilSettled()
791 for build in self.builds:
792 if build.parameters['ZUUL_PIPELINE'] == 'check':
793 build.release()
794 self.waitUntilSettled()
795
796 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
797 self.waitUntilSettled()
798
Joshua Hesketh352264b2015-08-11 23:42:08 +1000799 self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -0700800 # there should still be changes in the cache
Joshua Hesketh352264b2015-08-11 23:42:08 +1000801 self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -0700802
803 self.worker.hold_jobs_in_build = False
804 self.worker.release()
805 self.waitUntilSettled()
806
807 self.assertEqual(A.data['status'], 'MERGED')
808 self.assertEqual(B.data['status'], 'MERGED')
809 self.assertEqual(A.queried, 2) # Initial and isMerged
810 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
811
James E. Blair8c803f82012-07-31 16:25:42 -0700812 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -0700813 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -0700814 # TODO: move to test_gerrit (this is a unit test!)
815 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairc0dedf82014-08-06 09:37:52 -0700816 source = self.sched.layout.pipelines['gate'].source
817 a = source._getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -0400818 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blairc0dedf82014-08-06 09:37:52 -0700819 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700820
821 A.addApproval('CRVW', 2)
James E. Blairc0dedf82014-08-06 09:37:52 -0700822 a = source._getChange(1, 2, refresh=True)
823 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700824
825 A.addApproval('APRV', 1)
James E. Blairc0dedf82014-08-06 09:37:52 -0700826 a = source._getChange(1, 2, refresh=True)
827 self.assertTrue(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair4886cc12012-07-18 15:39:41 -0700828
829 def test_build_configuration(self):
830 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700831
832 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -0700833 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
834 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
835 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
836 A.addApproval('CRVW', 2)
837 B.addApproval('CRVW', 2)
838 C.addApproval('CRVW', 2)
839 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
840 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
841 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
842 self.waitUntilSettled()
843
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700844 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700845 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700846 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700847 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700848 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700849 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700850 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700851 ref = self.getParameter(queue[-1], 'ZUUL_REF')
852 self.gearman_server.hold_jobs_in_queue = False
853 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700854 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -0700855
Monty Taylorbc758832013-06-17 17:22:42 -0400856 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -0700857 repo = git.Repo(path)
858 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
859 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -0700860 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400861 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -0700862
863 def test_build_configuration_conflict(self):
864 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700865
866 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -0700867 A = self.fake_gerrit.addFakeChange('org/conflict-project',
868 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -0700869 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700870 B = self.fake_gerrit.addFakeChange('org/conflict-project',
871 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -0700872 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700873 C = self.fake_gerrit.addFakeChange('org/conflict-project',
874 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -0700875 A.addApproval('CRVW', 2)
876 B.addApproval('CRVW', 2)
877 C.addApproval('CRVW', 2)
878 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
879 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
880 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
881 self.waitUntilSettled()
882
James E. Blair6736beb2013-07-11 15:18:15 -0700883 self.assertEqual(A.reported, 1)
884 self.assertEqual(B.reported, 1)
885 self.assertEqual(C.reported, 1)
886
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700887 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700888 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700889 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700890 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700891 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700892 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -0700893
894 self.assertEqual(len(self.history), 2) # A and C merge jobs
895
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700896 self.gearman_server.hold_jobs_in_queue = False
897 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700898 self.waitUntilSettled()
899
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400900 self.assertEqual(A.data['status'], 'MERGED')
901 self.assertEqual(B.data['status'], 'NEW')
902 self.assertEqual(C.data['status'], 'MERGED')
903 self.assertEqual(A.reported, 2)
904 self.assertEqual(B.reported, 2)
905 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -0700906 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -0700907
James E. Blairdaabed22012-08-15 15:38:57 -0700908 def test_post(self):
909 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700910
Zhongyue Luo5d556072012-09-21 02:00:47 +0900911 e = {
912 "type": "ref-updated",
913 "submitter": {
914 "name": "User Name",
915 },
916 "refUpdate": {
917 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
918 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
919 "refName": "master",
920 "project": "org/project",
921 }
922 }
James E. Blairdaabed22012-08-15 15:38:57 -0700923 self.fake_gerrit.addEvent(e)
924 self.waitUntilSettled()
925
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400926 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400927 self.assertEqual(len(self.history), 1)
928 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -0700929
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700930 def test_post_ignore_deletes(self):
931 "Test that deleting refs does not trigger post jobs"
932
933 e = {
934 "type": "ref-updated",
935 "submitter": {
936 "name": "User Name",
937 },
938 "refUpdate": {
939 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
940 "newRev": "0000000000000000000000000000000000000000",
941 "refName": "master",
942 "project": "org/project",
943 }
944 }
945 self.fake_gerrit.addEvent(e)
946 self.waitUntilSettled()
947
948 job_names = [x.name for x in self.history]
949 self.assertEqual(len(self.history), 0)
950 self.assertNotIn('project-post', job_names)
951
952 def test_post_ignore_deletes_negative(self):
953 "Test that deleting refs does trigger post jobs"
954
955 self.config.set('zuul', 'layout_config',
956 'tests/fixtures/layout-dont-ignore-deletes.yaml')
957 self.sched.reconfigure(self.config)
958
959 e = {
960 "type": "ref-updated",
961 "submitter": {
962 "name": "User Name",
963 },
964 "refUpdate": {
965 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
966 "newRev": "0000000000000000000000000000000000000000",
967 "refName": "master",
968 "project": "org/project",
969 }
970 }
971 self.fake_gerrit.addEvent(e)
972 self.waitUntilSettled()
973
974 job_names = [x.name for x in self.history]
975 self.assertEqual(len(self.history), 1)
976 self.assertIn('project-post', job_names)
977
James E. Blairc6294a52012-08-17 10:19:48 -0700978 def test_build_configuration_branch(self):
979 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700980
981 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700982 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
983 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
984 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
985 A.addApproval('CRVW', 2)
986 B.addApproval('CRVW', 2)
987 C.addApproval('CRVW', 2)
988 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
989 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
990 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
991 self.waitUntilSettled()
992
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700993 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700994 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700995 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700996 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700997 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700998 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700999 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001000 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1001 self.gearman_server.hold_jobs_in_queue = False
1002 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001003 self.waitUntilSettled()
1004
Monty Taylorbc758832013-06-17 17:22:42 -04001005 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001006 repo = git.Repo(path)
1007 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1008 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001009 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001010 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001011
1012 def test_build_configuration_branch_interaction(self):
1013 "Test that switching between branches works"
1014 self.test_build_configuration()
1015 self.test_build_configuration_branch()
1016 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001017 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001018 repo = git.Repo(path)
1019 repo.heads.master.commit = repo.commit('init')
1020 self.test_build_configuration()
1021
1022 def test_build_configuration_multi_branch(self):
1023 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001024
1025 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001026 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1027 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1028 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1029 A.addApproval('CRVW', 2)
1030 B.addApproval('CRVW', 2)
1031 C.addApproval('CRVW', 2)
1032 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1033 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1034 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1035 self.waitUntilSettled()
James E. Blairbb1fe502014-03-04 10:15:06 -08001036 queue = self.gearman_server.getQueue()
1037 job_A = None
1038 for job in queue:
1039 if 'project-merge' in job.name:
1040 job_A = job
1041 ref_A = self.getParameter(job_A, 'ZUUL_REF')
1042 commit_A = self.getParameter(job_A, 'ZUUL_COMMIT')
1043 self.log.debug("Got Zuul ref for change A: %s" % ref_A)
1044 self.log.debug("Got Zuul commit for change A: %s" % commit_A)
James E. Blairc6294a52012-08-17 10:19:48 -07001045
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001046 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001047 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001048 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001049 job_B = None
1050 for job in queue:
1051 if 'project-merge' in job.name:
1052 job_B = job
1053 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001054 commit_B = self.getParameter(job_B, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001055 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blairbb1fe502014-03-04 10:15:06 -08001056 self.log.debug("Got Zuul commit for change B: %s" % commit_B)
1057
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001058 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001059 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001060 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001061 for job in queue:
1062 if 'project-merge' in job.name:
1063 job_C = job
1064 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001065 commit_C = self.getParameter(job_C, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001066 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blairbb1fe502014-03-04 10:15:06 -08001067 self.log.debug("Got Zuul commit for change C: %s" % commit_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001068 self.gearman_server.hold_jobs_in_queue = False
1069 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001070 self.waitUntilSettled()
1071
Monty Taylorbc758832013-06-17 17:22:42 -04001072 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001073 repo = git.Repo(path)
1074
1075 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001076 for c in repo.iter_commits(ref_C)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001077 repo_shas = [c.hexsha for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001078 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001079 correct_messages = ['initial commit', 'A-1', 'C-1']
James E. Blairbb1fe502014-03-04 10:15:06 -08001080 # Ensure the right commits are in the history for this ref
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001081 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001082 # Ensure ZUUL_REF -> ZUUL_COMMIT
1083 self.assertEqual(repo_shas[0], commit_C)
James E. Blairc6294a52012-08-17 10:19:48 -07001084
1085 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001086 for c in repo.iter_commits(ref_B)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001087 repo_shas = [c.hexsha for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001088 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001089 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001090 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001091 self.assertEqual(repo_shas[0], commit_B)
1092
1093 repo_messages = [c.message.strip()
1094 for c in repo.iter_commits(ref_A)]
1095 repo_shas = [c.hexsha for c in repo.iter_commits(ref_A)]
1096 repo_messages.reverse()
1097 correct_messages = ['initial commit', 'A-1']
1098 self.assertEqual(repo_messages, correct_messages)
1099 self.assertEqual(repo_shas[0], commit_A)
1100
1101 self.assertNotEqual(ref_A, ref_B, ref_C)
1102 self.assertNotEqual(commit_A, commit_B, commit_C)
James E. Blair7f71c802012-08-22 13:04:32 -07001103
1104 def test_one_job_project(self):
1105 "Test that queueing works with one job"
1106 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1107 'master', 'A')
1108 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1109 'master', 'B')
1110 A.addApproval('CRVW', 2)
1111 B.addApproval('CRVW', 2)
1112 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1113 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1114 self.waitUntilSettled()
1115
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001116 self.assertEqual(A.data['status'], 'MERGED')
1117 self.assertEqual(A.reported, 2)
1118 self.assertEqual(B.data['status'], 'MERGED')
1119 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001120
Antoine Musso80edd5a2013-02-13 15:37:53 +01001121 def test_job_from_templates_launched(self):
1122 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001123
Antoine Musso80edd5a2013-02-13 15:37:53 +01001124 A = self.fake_gerrit.addFakeChange(
1125 'org/templated-project', 'master', 'A')
1126 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1127 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001128
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001129 self.assertEqual(self.getJobFromHistory('project-test1').result,
1130 'SUCCESS')
1131 self.assertEqual(self.getJobFromHistory('project-test2').result,
1132 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001133
James E. Blair3e98c022013-12-16 15:25:38 -08001134 def test_layered_templates(self):
1135 "Test whether a job generated via a template can be launched"
1136
1137 A = self.fake_gerrit.addFakeChange(
1138 'org/layered-project', 'master', 'A')
1139 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1140 self.waitUntilSettled()
1141
1142 self.assertEqual(self.getJobFromHistory('project-test1').result,
1143 'SUCCESS')
1144 self.assertEqual(self.getJobFromHistory('project-test2').result,
1145 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001146 self.assertEqual(self.getJobFromHistory('layered-project-test3'
1147 ).result, 'SUCCESS')
1148 self.assertEqual(self.getJobFromHistory('layered-project-test4'
1149 ).result, 'SUCCESS')
James E. Blair12a92b12014-03-26 11:54:53 -07001150 self.assertEqual(self.getJobFromHistory('layered-project-foo-test5'
1151 ).result, 'SUCCESS')
James E. Blair3e98c022013-12-16 15:25:38 -08001152 self.assertEqual(self.getJobFromHistory('project-test6').result,
1153 'SUCCESS')
1154
James E. Blaircaec0c52012-08-22 14:52:22 -07001155 def test_dependent_changes_dequeue(self):
1156 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001157
James E. Blaircaec0c52012-08-22 14:52:22 -07001158 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1159 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1160 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1161 A.addApproval('CRVW', 2)
1162 B.addApproval('CRVW', 2)
1163 C.addApproval('CRVW', 2)
1164
1165 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1166 M1.setMerged()
1167
1168 # C -> B -> A -> M1
1169
1170 C.setDependsOn(B, 1)
1171 B.setDependsOn(A, 1)
1172 A.setDependsOn(M1, 1)
1173
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001174 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001175
1176 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1177 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1178 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1179
1180 self.waitUntilSettled()
1181
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001182 self.assertEqual(A.data['status'], 'NEW')
1183 self.assertEqual(A.reported, 2)
1184 self.assertEqual(B.data['status'], 'NEW')
1185 self.assertEqual(B.reported, 2)
1186 self.assertEqual(C.data['status'], 'NEW')
1187 self.assertEqual(C.reported, 2)
1188 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001189
James E. Blair972e3c72013-08-29 12:04:55 -07001190 def test_failing_dependent_changes(self):
1191 "Test that failing dependent patches are taken out of stream"
1192 self.worker.hold_jobs_in_build = True
1193 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1194 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1195 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1196 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1197 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1198 A.addApproval('CRVW', 2)
1199 B.addApproval('CRVW', 2)
1200 C.addApproval('CRVW', 2)
1201 D.addApproval('CRVW', 2)
1202 E.addApproval('CRVW', 2)
1203
1204 # E, D -> C -> B, A
1205
1206 D.setDependsOn(C, 1)
1207 C.setDependsOn(B, 1)
1208
1209 self.worker.addFailTest('project-test1', B)
1210
1211 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1212 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1213 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1214 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1215 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1216
1217 self.waitUntilSettled()
1218 self.worker.release('.*-merge')
1219 self.waitUntilSettled()
1220 self.worker.release('.*-merge')
1221 self.waitUntilSettled()
1222 self.worker.release('.*-merge')
1223 self.waitUntilSettled()
1224 self.worker.release('.*-merge')
1225 self.waitUntilSettled()
1226 self.worker.release('.*-merge')
1227 self.waitUntilSettled()
1228
1229 self.worker.hold_jobs_in_build = False
1230 for build in self.builds:
1231 if build.parameters['ZUUL_CHANGE'] != '1':
1232 build.release()
1233 self.waitUntilSettled()
1234
1235 self.worker.release()
1236 self.waitUntilSettled()
1237
1238 self.assertEqual(A.data['status'], 'MERGED')
1239 self.assertEqual(A.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001240 self.assertIn('Build succeeded', A.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001241 self.assertEqual(B.data['status'], 'NEW')
1242 self.assertEqual(B.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001243 self.assertIn('Build failed', B.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001244 self.assertEqual(C.data['status'], 'NEW')
1245 self.assertEqual(C.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001246 self.assertIn('depends on a change', C.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001247 self.assertEqual(D.data['status'], 'NEW')
1248 self.assertEqual(D.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001249 self.assertIn('depends on a change', D.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001250 self.assertEqual(E.data['status'], 'MERGED')
1251 self.assertEqual(E.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001252 self.assertIn('Build succeeded', E.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001253 self.assertEqual(len(self.history), 18)
1254
James E. Blairec590122012-08-22 15:19:31 -07001255 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001256 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001257 # If it's dequeued more than once, we should see extra
1258 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001259
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001260 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001261 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1262 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1263 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1264 A.addApproval('CRVW', 2)
1265 B.addApproval('CRVW', 2)
1266 C.addApproval('CRVW', 2)
1267
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001268 self.worker.addFailTest('project1-test1', A)
1269 self.worker.addFailTest('project1-test2', A)
1270 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001271
1272 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1273 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1274 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1275
1276 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001277
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001278 self.assertEqual(len(self.builds), 1)
1279 self.assertEqual(self.builds[0].name, 'project1-merge')
1280 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001281
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001282 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001283 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001284 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001285 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001286 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001287 self.waitUntilSettled()
1288
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001289 self.assertEqual(len(self.builds), 9)
1290 self.assertEqual(self.builds[0].name, 'project1-test1')
1291 self.assertEqual(self.builds[1].name, 'project1-test2')
1292 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1293 self.assertEqual(self.builds[3].name, 'project1-test1')
1294 self.assertEqual(self.builds[4].name, 'project1-test2')
1295 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1296 self.assertEqual(self.builds[6].name, 'project1-test1')
1297 self.assertEqual(self.builds[7].name, 'project1-test2')
1298 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001299
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001300 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001301 self.waitUntilSettled()
1302
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001303 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1304 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001305
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001306 self.worker.hold_jobs_in_build = False
1307 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001308 self.waitUntilSettled()
1309
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001310 self.assertEqual(len(self.builds), 0)
1311 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001312
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001313 self.assertEqual(A.data['status'], 'NEW')
1314 self.assertEqual(B.data['status'], 'MERGED')
1315 self.assertEqual(C.data['status'], 'MERGED')
1316 self.assertEqual(A.reported, 2)
1317 self.assertEqual(B.reported, 2)
1318 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001319
1320 def test_nonvoting_job(self):
1321 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001322
James E. Blair4ec821f2012-08-23 15:28:28 -07001323 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1324 'master', 'A')
1325 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001326 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001327 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1328
1329 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001330
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001331 self.assertEqual(A.data['status'], 'MERGED')
1332 self.assertEqual(A.reported, 2)
1333 self.assertEqual(
1334 self.getJobFromHistory('nonvoting-project-merge').result,
1335 'SUCCESS')
1336 self.assertEqual(
1337 self.getJobFromHistory('nonvoting-project-test1').result,
1338 'SUCCESS')
1339 self.assertEqual(
1340 self.getJobFromHistory('nonvoting-project-test2').result,
1341 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001342
James E. Blair5821bd92015-09-16 08:48:15 -07001343 for build in self.builds:
1344 self.assertEqual(build.parameters['ZUUL_VOTING'], '0')
1345
James E. Blaire0487072012-08-29 17:38:31 -07001346 def test_check_queue_success(self):
1347 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001348
James E. Blaire0487072012-08-29 17:38:31 -07001349 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1350 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1351
1352 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001353
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001354 self.assertEqual(A.data['status'], 'NEW')
1355 self.assertEqual(A.reported, 1)
1356 self.assertEqual(self.getJobFromHistory('project-merge').result,
1357 'SUCCESS')
1358 self.assertEqual(self.getJobFromHistory('project-test1').result,
1359 'SUCCESS')
1360 self.assertEqual(self.getJobFromHistory('project-test2').result,
1361 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001362
1363 def test_check_queue_failure(self):
1364 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001365
James E. Blaire0487072012-08-29 17:38:31 -07001366 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001367 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001368 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1369
1370 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001371
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001372 self.assertEqual(A.data['status'], 'NEW')
1373 self.assertEqual(A.reported, 1)
1374 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001375 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001376 self.assertEqual(self.getJobFromHistory('project-test1').result,
1377 'SUCCESS')
1378 self.assertEqual(self.getJobFromHistory('project-test2').result,
1379 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001380
1381 def test_dependent_behind_dequeue(self):
1382 "test that dependent changes behind dequeued changes work"
1383 # This complicated test is a reproduction of a real life bug
1384 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001385
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001386 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001387 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1388 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1389 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1390 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1391 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1392 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1393 D.setDependsOn(C, 1)
1394 E.setDependsOn(D, 1)
1395 A.addApproval('CRVW', 2)
1396 B.addApproval('CRVW', 2)
1397 C.addApproval('CRVW', 2)
1398 D.addApproval('CRVW', 2)
1399 E.addApproval('CRVW', 2)
1400 F.addApproval('CRVW', 2)
1401
1402 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001403
1404 # Change object re-use in the gerrit trigger is hidden if
1405 # changes are added in quick succession; waiting makes it more
1406 # like real life.
1407 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1408 self.waitUntilSettled()
1409 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1410 self.waitUntilSettled()
1411
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001412 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001413 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001414 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001415 self.waitUntilSettled()
1416
1417 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1418 self.waitUntilSettled()
1419 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1420 self.waitUntilSettled()
1421 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1422 self.waitUntilSettled()
1423 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1424 self.waitUntilSettled()
1425
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001426 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001427 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001428 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001429 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001430 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001431 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001432 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001433 self.waitUntilSettled()
1434
1435 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001436
1437 # Grab pointers to the jobs we want to release before
1438 # releasing any, because list indexes may change as
1439 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001440 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001441 a.release()
1442 b.release()
1443 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001444 self.waitUntilSettled()
1445
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001446 self.worker.hold_jobs_in_build = False
1447 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001448 self.waitUntilSettled()
1449
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001450 self.assertEqual(A.data['status'], 'NEW')
1451 self.assertEqual(B.data['status'], 'MERGED')
1452 self.assertEqual(C.data['status'], 'MERGED')
1453 self.assertEqual(D.data['status'], 'MERGED')
1454 self.assertEqual(E.data['status'], 'MERGED')
1455 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07001456
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001457 self.assertEqual(A.reported, 2)
1458 self.assertEqual(B.reported, 2)
1459 self.assertEqual(C.reported, 2)
1460 self.assertEqual(D.reported, 2)
1461 self.assertEqual(E.reported, 2)
1462 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07001463
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001464 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
1465 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07001466
1467 def test_merger_repack(self):
1468 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001469
James E. Blair05fed602012-09-07 12:45:24 -07001470 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1471 A.addApproval('CRVW', 2)
1472 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1473 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001474 self.assertEqual(self.getJobFromHistory('project-merge').result,
1475 'SUCCESS')
1476 self.assertEqual(self.getJobFromHistory('project-test1').result,
1477 'SUCCESS')
1478 self.assertEqual(self.getJobFromHistory('project-test2').result,
1479 'SUCCESS')
1480 self.assertEqual(A.data['status'], 'MERGED')
1481 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07001482 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001483 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001484
Monty Taylorbc758832013-06-17 17:22:42 -04001485 path = os.path.join(self.git_root, "org/project")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001486 print(repack_repo(path))
James E. Blair05fed602012-09-07 12:45:24 -07001487
1488 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1489 A.addApproval('CRVW', 2)
1490 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1491 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001492 self.assertEqual(self.getJobFromHistory('project-merge').result,
1493 'SUCCESS')
1494 self.assertEqual(self.getJobFromHistory('project-test1').result,
1495 'SUCCESS')
1496 self.assertEqual(self.getJobFromHistory('project-test2').result,
1497 'SUCCESS')
1498 self.assertEqual(A.data['status'], 'MERGED')
1499 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001500
James E. Blair4886f282012-11-15 09:27:33 -08001501 def test_merger_repack_large_change(self):
1502 "Test that the merger works with large changes after a repack"
1503 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08001504 # This test assumes the repo is already cloned; make sure it is
Joshua Hesketh352264b2015-08-11 23:42:08 +10001505 url = self.fake_gerrit.getGitUrl(
James E. Blairac2c3242014-01-24 13:38:51 -08001506 self.sched.layout.projects['org/project1'])
James E. Blair4076e2b2014-01-28 12:42:20 -08001507 self.merge_server.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08001508 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1509 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001510 path = os.path.join(self.upstream_root, "org/project1")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001511 print(repack_repo(path))
Monty Taylorbc758832013-06-17 17:22:42 -04001512 path = os.path.join(self.git_root, "org/project1")
Morgan Fainberg4c6a7742016-05-27 08:42:17 -07001513 print(repack_repo(path))
James E. Blair4886f282012-11-15 09:27:33 -08001514
1515 A.addApproval('CRVW', 2)
1516 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1517 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001518 self.assertEqual(self.getJobFromHistory('project1-merge').result,
1519 'SUCCESS')
1520 self.assertEqual(self.getJobFromHistory('project1-test1').result,
1521 'SUCCESS')
1522 self.assertEqual(self.getJobFromHistory('project1-test2').result,
1523 'SUCCESS')
1524 self.assertEqual(A.data['status'], 'MERGED')
1525 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08001526
James E. Blair7ee88a22012-09-12 18:59:31 +02001527 def test_nonexistent_job(self):
1528 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001529 # Set to the state immediately after a restart
1530 self.resetGearmanServer()
1531 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001532
1533 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1534 A.addApproval('CRVW', 2)
1535 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1536 # There may be a thread about to report a lost change
1537 while A.reported < 2:
1538 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001539 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001540 self.assertFalse(job_names)
1541 self.assertEqual(A.data['status'], 'NEW')
1542 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001543 self.assertEmptyQueues()
1544
1545 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001546 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001547 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1548 A.addApproval('CRVW', 2)
1549 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1550 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001551 self.assertEqual(self.getJobFromHistory('project-merge').result,
1552 'SUCCESS')
1553 self.assertEqual(self.getJobFromHistory('project-test1').result,
1554 'SUCCESS')
1555 self.assertEqual(self.getJobFromHistory('project-test2').result,
1556 'SUCCESS')
1557 self.assertEqual(A.data['status'], 'MERGED')
1558 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08001559
1560 def test_single_nonexistent_post_job(self):
1561 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001562 e = {
1563 "type": "ref-updated",
1564 "submitter": {
1565 "name": "User Name",
1566 },
1567 "refUpdate": {
1568 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1569 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1570 "refName": "master",
1571 "project": "org/project",
1572 }
1573 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001574 # Set to the state immediately after a restart
1575 self.resetGearmanServer()
1576 self.launcher.negative_function_cache_ttl = 0
1577
James E. Blairf62d4282012-12-31 17:01:50 -08001578 self.fake_gerrit.addEvent(e)
1579 self.waitUntilSettled()
1580
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001581 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08001582
1583 def test_new_patchset_dequeues_old(self):
1584 "Test that a new patchset causes the old to be dequeued"
1585 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001586 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001587 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1588 M.setMerged()
1589
1590 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1591 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1592 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1593 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1594 A.addApproval('CRVW', 2)
1595 B.addApproval('CRVW', 2)
1596 C.addApproval('CRVW', 2)
1597 D.addApproval('CRVW', 2)
1598
1599 C.setDependsOn(B, 1)
1600 B.setDependsOn(A, 1)
1601 A.setDependsOn(M, 1)
1602
1603 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1604 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1605 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1606 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1607 self.waitUntilSettled()
1608
1609 B.addPatchset()
1610 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1611 self.waitUntilSettled()
1612
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001613 self.worker.hold_jobs_in_build = False
1614 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001615 self.waitUntilSettled()
1616
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001617 self.assertEqual(A.data['status'], 'MERGED')
1618 self.assertEqual(A.reported, 2)
1619 self.assertEqual(B.data['status'], 'NEW')
1620 self.assertEqual(B.reported, 2)
1621 self.assertEqual(C.data['status'], 'NEW')
1622 self.assertEqual(C.reported, 2)
1623 self.assertEqual(D.data['status'], 'MERGED')
1624 self.assertEqual(D.reported, 2)
1625 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001626
James E. Blairba437362015-02-07 11:41:52 -08001627 def test_new_patchset_check(self):
1628 "Test a new patchset in check"
Antoine Mussobd86a312014-01-08 14:51:33 +01001629
1630 self.worker.hold_jobs_in_build = True
1631
1632 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairba437362015-02-07 11:41:52 -08001633 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1634 check_pipeline = self.sched.layout.pipelines['check']
1635
1636 # Add two git-dependent changes
1637 B.setDependsOn(A, 1)
1638 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1639 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001640 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1641 self.waitUntilSettled()
James E. Blairba437362015-02-07 11:41:52 -08001642
1643 # A live item, and a non-live/live pair
1644 items = check_pipeline.getAllItems()
1645 self.assertEqual(len(items), 3)
1646
1647 self.assertEqual(items[0].change.number, '1')
1648 self.assertEqual(items[0].change.patchset, '1')
1649 self.assertFalse(items[0].live)
1650
1651 self.assertEqual(items[1].change.number, '2')
1652 self.assertEqual(items[1].change.patchset, '1')
1653 self.assertTrue(items[1].live)
1654
1655 self.assertEqual(items[2].change.number, '1')
1656 self.assertEqual(items[2].change.patchset, '1')
1657 self.assertTrue(items[2].live)
1658
1659 # Add a new patchset to A
1660 A.addPatchset()
1661 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1662 self.waitUntilSettled()
1663
1664 # The live copy of A,1 should be gone, but the non-live and B
1665 # should continue, and we should have a new A,2
1666 items = check_pipeline.getAllItems()
1667 self.assertEqual(len(items), 3)
1668
1669 self.assertEqual(items[0].change.number, '1')
1670 self.assertEqual(items[0].change.patchset, '1')
1671 self.assertFalse(items[0].live)
1672
1673 self.assertEqual(items[1].change.number, '2')
1674 self.assertEqual(items[1].change.patchset, '1')
1675 self.assertTrue(items[1].live)
1676
1677 self.assertEqual(items[2].change.number, '1')
1678 self.assertEqual(items[2].change.patchset, '2')
1679 self.assertTrue(items[2].live)
1680
1681 # Add a new patchset to B
1682 B.addPatchset()
1683 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1684 self.waitUntilSettled()
1685
1686 # The live copy of B,1 should be gone, and it's non-live copy of A,1
1687 # but we should have a new B,2 (still based on A,1)
1688 items = check_pipeline.getAllItems()
1689 self.assertEqual(len(items), 3)
1690
1691 self.assertEqual(items[0].change.number, '1')
1692 self.assertEqual(items[0].change.patchset, '2')
1693 self.assertTrue(items[0].live)
1694
1695 self.assertEqual(items[1].change.number, '1')
1696 self.assertEqual(items[1].change.patchset, '1')
1697 self.assertFalse(items[1].live)
1698
1699 self.assertEqual(items[2].change.number, '2')
1700 self.assertEqual(items[2].change.patchset, '2')
1701 self.assertTrue(items[2].live)
1702
1703 self.builds[0].release()
1704 self.waitUntilSettled()
1705 self.builds[0].release()
1706 self.waitUntilSettled()
1707 self.worker.hold_jobs_in_build = False
1708 self.worker.release()
1709 self.waitUntilSettled()
1710
1711 self.assertEqual(A.reported, 1)
1712 self.assertEqual(B.reported, 1)
1713 self.assertEqual(self.history[0].result, 'ABORTED')
1714 self.assertEqual(self.history[0].changes, '1,1')
1715 self.assertEqual(self.history[1].result, 'ABORTED')
1716 self.assertEqual(self.history[1].changes, '1,1 2,1')
1717 self.assertEqual(self.history[2].result, 'SUCCESS')
1718 self.assertEqual(self.history[2].changes, '1,2')
1719 self.assertEqual(self.history[3].result, 'SUCCESS')
1720 self.assertEqual(self.history[3].changes, '1,1 2,2')
1721
1722 def test_abandoned_gate(self):
1723 "Test that an abandoned change is dequeued from gate"
1724
1725 self.worker.hold_jobs_in_build = True
1726
1727 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1728 A.addApproval('CRVW', 2)
1729 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1730 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001731 self.assertEqual(len(self.builds), 1, "One job being built (on hold)")
1732 self.assertEqual(self.builds[0].name, 'project-merge')
1733
1734 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1735 self.waitUntilSettled()
1736
Antoine Mussobd86a312014-01-08 14:51:33 +01001737 self.worker.release('.*-merge')
1738 self.waitUntilSettled()
1739
1740 self.assertEqual(len(self.builds), 0, "No job running")
Antoine Mussobd86a312014-01-08 14:51:33 +01001741 self.assertEqual(len(self.history), 1, "Only one build in history")
1742 self.assertEqual(self.history[0].result, 'ABORTED',
James E. Blairba437362015-02-07 11:41:52 -08001743 "Build should have been aborted")
1744 self.assertEqual(A.reported, 1,
1745 "Abandoned gate change should report only start")
1746
1747 def test_abandoned_check(self):
1748 "Test that an abandoned change is dequeued from check"
1749
1750 self.worker.hold_jobs_in_build = True
1751
1752 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1753 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1754 check_pipeline = self.sched.layout.pipelines['check']
1755
1756 # Add two git-dependent changes
1757 B.setDependsOn(A, 1)
1758 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1759 self.waitUntilSettled()
1760 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1761 self.waitUntilSettled()
1762 # A live item, and a non-live/live pair
1763 items = check_pipeline.getAllItems()
1764 self.assertEqual(len(items), 3)
1765
1766 self.assertEqual(items[0].change.number, '1')
1767 self.assertFalse(items[0].live)
1768
1769 self.assertEqual(items[1].change.number, '2')
1770 self.assertTrue(items[1].live)
1771
1772 self.assertEqual(items[2].change.number, '1')
1773 self.assertTrue(items[2].live)
1774
1775 # Abandon A
1776 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1777 self.waitUntilSettled()
1778
1779 # The live copy of A should be gone, but the non-live and B
1780 # should continue
1781 items = check_pipeline.getAllItems()
1782 self.assertEqual(len(items), 2)
1783
1784 self.assertEqual(items[0].change.number, '1')
1785 self.assertFalse(items[0].live)
1786
1787 self.assertEqual(items[1].change.number, '2')
1788 self.assertTrue(items[1].live)
1789
1790 self.worker.hold_jobs_in_build = False
1791 self.worker.release()
1792 self.waitUntilSettled()
1793
1794 self.assertEqual(len(self.history), 4)
1795 self.assertEqual(self.history[0].result, 'ABORTED',
Antoine Mussobd86a312014-01-08 14:51:33 +01001796 'Build should have been aborted')
1797 self.assertEqual(A.reported, 0, "Abandoned change should not report")
James E. Blairba437362015-02-07 11:41:52 -08001798 self.assertEqual(B.reported, 1, "Change should report")
Antoine Mussobd86a312014-01-08 14:51:33 +01001799
Steve Varnau7b78b312015-04-03 14:49:46 -07001800 def test_abandoned_not_timer(self):
1801 "Test that an abandoned change does not cancel timer jobs"
1802
1803 self.worker.hold_jobs_in_build = True
1804
1805 # Start timer trigger - also org/project
1806 self.config.set('zuul', 'layout_config',
1807 'tests/fixtures/layout-idle.yaml')
1808 self.sched.reconfigure(self.config)
1809 self.registerJobs()
1810 # The pipeline triggers every second, so we should have seen
1811 # several by now.
1812 time.sleep(5)
1813 self.waitUntilSettled()
1814 # Stop queuing timer triggered jobs so that the assertions
1815 # below don't race against more jobs being queued.
1816 self.config.set('zuul', 'layout_config',
1817 'tests/fixtures/layout-no-timer.yaml')
1818 self.sched.reconfigure(self.config)
1819 self.registerJobs()
1820 self.assertEqual(len(self.builds), 2, "Two timer jobs")
1821
1822 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1823 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1824 self.waitUntilSettled()
1825 self.assertEqual(len(self.builds), 3, "One change plus two timer jobs")
1826
1827 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1828 self.waitUntilSettled()
1829
1830 self.assertEqual(len(self.builds), 2, "Two timer jobs remain")
1831
1832 self.worker.release()
1833 self.waitUntilSettled()
1834
Arx Cruzb1b010d2013-10-28 19:49:59 -02001835 def test_zuul_url_return(self):
1836 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
James E. Blair4076e2b2014-01-28 12:42:20 -08001837 self.assertTrue(self.sched.config.has_option('merger', 'zuul_url'))
Arx Cruzb1b010d2013-10-28 19:49:59 -02001838 self.worker.hold_jobs_in_build = True
1839
1840 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1841 A.addApproval('CRVW', 2)
1842 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1843 self.waitUntilSettled()
1844
1845 self.assertEqual(len(self.builds), 1)
1846 for build in self.builds:
1847 self.assertTrue('ZUUL_URL' in build.parameters)
1848
1849 self.worker.hold_jobs_in_build = False
1850 self.worker.release()
1851 self.waitUntilSettled()
1852
James E. Blair2fa50962013-01-30 21:50:41 -08001853 def test_new_patchset_dequeues_old_on_head(self):
1854 "Test that a new patchset causes the old to be dequeued (at head)"
1855 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001856 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001857 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1858 M.setMerged()
1859 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1860 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1861 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1862 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1863 A.addApproval('CRVW', 2)
1864 B.addApproval('CRVW', 2)
1865 C.addApproval('CRVW', 2)
1866 D.addApproval('CRVW', 2)
1867
1868 C.setDependsOn(B, 1)
1869 B.setDependsOn(A, 1)
1870 A.setDependsOn(M, 1)
1871
1872 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1873 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1874 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1875 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1876 self.waitUntilSettled()
1877
1878 A.addPatchset()
1879 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1880 self.waitUntilSettled()
1881
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001882 self.worker.hold_jobs_in_build = False
1883 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001884 self.waitUntilSettled()
1885
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001886 self.assertEqual(A.data['status'], 'NEW')
1887 self.assertEqual(A.reported, 2)
1888 self.assertEqual(B.data['status'], 'NEW')
1889 self.assertEqual(B.reported, 2)
1890 self.assertEqual(C.data['status'], 'NEW')
1891 self.assertEqual(C.reported, 2)
1892 self.assertEqual(D.data['status'], 'MERGED')
1893 self.assertEqual(D.reported, 2)
1894 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08001895
1896 def test_new_patchset_dequeues_old_without_dependents(self):
1897 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001898 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001899 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1900 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1901 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1902 A.addApproval('CRVW', 2)
1903 B.addApproval('CRVW', 2)
1904 C.addApproval('CRVW', 2)
1905
1906 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1907 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1908 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1909 self.waitUntilSettled()
1910
1911 B.addPatchset()
1912 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1913 self.waitUntilSettled()
1914
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001915 self.worker.hold_jobs_in_build = False
1916 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001917 self.waitUntilSettled()
1918
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001919 self.assertEqual(A.data['status'], 'MERGED')
1920 self.assertEqual(A.reported, 2)
1921 self.assertEqual(B.data['status'], 'NEW')
1922 self.assertEqual(B.reported, 2)
1923 self.assertEqual(C.data['status'], 'MERGED')
1924 self.assertEqual(C.reported, 2)
1925 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08001926
1927 def test_new_patchset_dequeues_old_independent_queue(self):
1928 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001929 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001930 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1931 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1932 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1933 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1934 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1935 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1936 self.waitUntilSettled()
1937
1938 B.addPatchset()
1939 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1940 self.waitUntilSettled()
1941
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001942 self.worker.hold_jobs_in_build = False
1943 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001944 self.waitUntilSettled()
1945
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001946 self.assertEqual(A.data['status'], 'NEW')
1947 self.assertEqual(A.reported, 1)
1948 self.assertEqual(B.data['status'], 'NEW')
1949 self.assertEqual(B.reported, 1)
1950 self.assertEqual(C.data['status'], 'NEW')
1951 self.assertEqual(C.reported, 1)
1952 self.assertEqual(len(self.history), 10)
1953 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001954
James E. Blair18c64442014-03-18 10:14:45 -07001955 def test_noop_job(self):
1956 "Test that the internal noop job works"
1957 A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A')
1958 A.addApproval('CRVW', 2)
1959 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1960 self.waitUntilSettled()
1961
1962 self.assertEqual(len(self.gearman_server.getQueue()), 0)
1963 self.assertTrue(self.sched._areAllBuildsComplete())
1964 self.assertEqual(len(self.history), 0)
1965 self.assertEqual(A.data['status'], 'MERGED')
1966 self.assertEqual(A.reported, 2)
1967
Evgeny Antyshevd6e546c2015-06-11 15:13:57 +00001968 def test_no_job_project(self):
1969 "Test that reports with no jobs don't get sent"
1970 A = self.fake_gerrit.addFakeChange('org/no-jobs-project',
1971 'master', 'A')
1972 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1973 self.waitUntilSettled()
1974
1975 # Change wasn't reported to
1976 self.assertEqual(A.reported, False)
1977
1978 # Check queue is empty afterwards
1979 check_pipeline = self.sched.layout.pipelines['check']
1980 items = check_pipeline.getAllItems()
1981 self.assertEqual(len(items), 0)
1982
1983 self.assertEqual(len(self.history), 0)
1984
James E. Blair7d0dedc2013-02-21 17:26:09 -08001985 def test_zuul_refs(self):
1986 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001987 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08001988 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1989 M1.setMerged()
1990 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1991 M2.setMerged()
1992
1993 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1994 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1995 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1996 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1997 A.addApproval('CRVW', 2)
1998 B.addApproval('CRVW', 2)
1999 C.addApproval('CRVW', 2)
2000 D.addApproval('CRVW', 2)
2001 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2002 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2003 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2004 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2005
2006 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002007 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002008 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002009 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002010 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002011 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002012 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002013 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002014 self.waitUntilSettled()
2015
James E. Blair7d0dedc2013-02-21 17:26:09 -08002016 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002017 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002018 if x.parameters['ZUUL_CHANGE'] == '3':
2019 a_zref = x.parameters['ZUUL_REF']
2020 if x.parameters['ZUUL_CHANGE'] == '4':
2021 b_zref = x.parameters['ZUUL_REF']
2022 if x.parameters['ZUUL_CHANGE'] == '5':
2023 c_zref = x.parameters['ZUUL_REF']
2024 if x.parameters['ZUUL_CHANGE'] == '6':
2025 d_zref = x.parameters['ZUUL_REF']
2026
2027 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002028 self.assertIsNotNone(a_zref)
2029 self.assertIsNotNone(b_zref)
2030 self.assertIsNotNone(c_zref)
2031 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002032
2033 # And they should all be different
2034 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002035 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002036
2037 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002038 self.assertTrue(self.ref_has_change(a_zref, A))
2039 self.assertFalse(self.ref_has_change(a_zref, B))
2040 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002041
2042 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002043 self.assertTrue(self.ref_has_change(b_zref, A))
2044 self.assertTrue(self.ref_has_change(b_zref, B))
2045 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002046
2047 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002048 self.assertTrue(self.ref_has_change(c_zref, A))
2049 self.assertTrue(self.ref_has_change(c_zref, B))
2050 self.assertTrue(self.ref_has_change(c_zref, C))
2051 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002052
2053 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002054 self.assertTrue(self.ref_has_change(d_zref, A))
2055 self.assertTrue(self.ref_has_change(d_zref, B))
2056 self.assertTrue(self.ref_has_change(d_zref, C))
2057 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002058
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002059 self.worker.hold_jobs_in_build = False
2060 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002061 self.waitUntilSettled()
2062
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002063 self.assertEqual(A.data['status'], 'MERGED')
2064 self.assertEqual(A.reported, 2)
2065 self.assertEqual(B.data['status'], 'MERGED')
2066 self.assertEqual(B.reported, 2)
2067 self.assertEqual(C.data['status'], 'MERGED')
2068 self.assertEqual(C.reported, 2)
2069 self.assertEqual(D.data['status'], 'MERGED')
2070 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002071
James E. Blair4a28a882013-08-23 15:17:33 -07002072 def test_rerun_on_error(self):
2073 "Test that if a worker fails to run a job, it is run again"
2074 self.worker.hold_jobs_in_build = True
2075 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2076 A.addApproval('CRVW', 2)
2077 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2078 self.waitUntilSettled()
2079
2080 self.builds[0].run_error = True
2081 self.worker.hold_jobs_in_build = False
2082 self.worker.release()
2083 self.waitUntilSettled()
2084 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2085 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2086
James E. Blair412e5582013-04-22 15:50:12 -07002087 def test_statsd(self):
2088 "Test each of the statsd methods used in the scheduler"
2089 import extras
2090 statsd = extras.try_import('statsd.statsd')
2091 statsd.incr('test-incr')
2092 statsd.timing('test-timing', 3)
Alex Gaynor813d39b2014-05-17 16:17:16 -07002093 statsd.gauge('test-gauge', 12)
James E. Blair412e5582013-04-22 15:50:12 -07002094 self.assertReportedStat('test-incr', '1|c')
2095 self.assertReportedStat('test-timing', '3|ms')
Alex Gaynor813d39b2014-05-17 16:17:16 -07002096 self.assertReportedStat('test-gauge', '12|g')
James E. Blair412e5582013-04-22 15:50:12 -07002097
James E. Blairdad52252014-02-07 16:59:17 -08002098 def test_stuck_job_cleanup(self):
2099 "Test that pending jobs are cleaned up if removed from layout"
James E. Blair18c64442014-03-18 10:14:45 -07002100 # This job won't be registered at startup because it is not in
2101 # the standard layout, but we need it to already be registerd
2102 # for when we reconfigure, as that is when Zuul will attempt
2103 # to run the new job.
2104 self.worker.registerFunction('build:gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002105 self.gearman_server.hold_jobs_in_queue = True
2106 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2107 A.addApproval('CRVW', 2)
2108 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2109 self.waitUntilSettled()
2110 self.assertEqual(len(self.gearman_server.getQueue()), 1)
2111
2112 self.config.set('zuul', 'layout_config',
2113 'tests/fixtures/layout-no-jobs.yaml')
2114 self.sched.reconfigure(self.config)
2115 self.waitUntilSettled()
2116
James E. Blair18c64442014-03-18 10:14:45 -07002117 self.gearman_server.release('gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002118 self.waitUntilSettled()
2119 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2120 self.assertTrue(self.sched._areAllBuildsComplete())
2121
2122 self.assertEqual(len(self.history), 1)
James E. Blair18c64442014-03-18 10:14:45 -07002123 self.assertEqual(self.history[0].name, 'gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002124 self.assertEqual(self.history[0].result, 'SUCCESS')
2125
James E. Blair879dafb2015-07-17 14:04:49 -07002126 def test_file_head(self):
2127 # This is a regression test for an observed bug. A change
2128 # with a file named "HEAD" in the root directory of the repo
2129 # was processed by a merger. It then was unable to reset the
2130 # repo because of:
2131 # GitCommandError: 'git reset --hard HEAD' returned
2132 # with exit code 128
2133 # stderr: 'fatal: ambiguous argument 'HEAD': both revision
2134 # and filename
2135 # Use '--' to separate filenames from revisions'
2136
2137 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2138 A.addPatchset(['HEAD'])
2139 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2140
2141 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2142 self.waitUntilSettled()
2143
2144 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2145 self.waitUntilSettled()
2146
2147 self.assertIn('Build succeeded', A.messages[0])
2148 self.assertIn('Build succeeded', B.messages[0])
2149
James E. Blair70c71582013-03-06 08:50:50 -08002150 def test_file_jobs(self):
2151 "Test that file jobs run only when appropriate"
2152 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2153 A.addPatchset(['pip-requires'])
2154 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2155 A.addApproval('CRVW', 2)
2156 B.addApproval('CRVW', 2)
2157 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2158 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2159 self.waitUntilSettled()
2160
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002161 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002162 if x.name == 'project-testfile']
2163
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002164 self.assertEqual(len(testfile_jobs), 1)
2165 self.assertEqual(testfile_jobs[0].changes, '1,2')
2166 self.assertEqual(A.data['status'], 'MERGED')
2167 self.assertEqual(A.reported, 2)
2168 self.assertEqual(B.data['status'], 'MERGED')
2169 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002170
Maru Newby3fe5f852015-01-13 04:22:14 +00002171 def _test_skip_if_jobs(self, branch, should_skip):
2172 "Test that jobs with a skip-if filter run only when appropriate"
2173 self.config.set('zuul', 'layout_config',
2174 'tests/fixtures/layout-skip-if.yaml')
2175 self.sched.reconfigure(self.config)
2176 self.registerJobs()
2177
2178 change = self.fake_gerrit.addFakeChange('org/project',
2179 branch,
2180 'test skip-if')
2181 self.fake_gerrit.addEvent(change.getPatchsetCreatedEvent(1))
2182 self.waitUntilSettled()
2183
2184 tested_change_ids = [x.changes[0] for x in self.history
2185 if x.name == 'project-test-skip-if']
2186
2187 if should_skip:
2188 self.assertEqual([], tested_change_ids)
2189 else:
2190 self.assertIn(change.data['number'], tested_change_ids)
2191
2192 def test_skip_if_match_skips_job(self):
2193 self._test_skip_if_jobs(branch='master', should_skip=True)
2194
2195 def test_skip_if_no_match_runs_job(self):
2196 self._test_skip_if_jobs(branch='mp', should_skip=False)
2197
James E. Blair3c5e5b52013-04-26 11:17:03 -07002198 def test_test_config(self):
2199 "Test that we can test the config"
Joshua Hesketh352264b2015-08-11 23:42:08 +10002200 self.sched.testConfig(self.config.get('zuul', 'layout_config'),
2201 self.connections)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002202
2203 def test_build_description(self):
2204 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002205 self.worker.registerFunction('set_description:' +
2206 self.worker.worker_id)
2207
2208 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2209 A.addApproval('CRVW', 2)
2210 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2211 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002212 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002213 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002214 self.assertTrue(re.search("Branch.*master", desc))
2215 self.assertTrue(re.search("Pipeline.*gate", desc))
2216 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2217 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2218 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2219 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002220
James E. Blairc8a1e052014-02-25 09:29:26 -08002221 def test_queue_names(self):
2222 "Test shared change queue names"
2223 project1 = self.sched.layout.projects['org/project1']
2224 project2 = self.sched.layout.projects['org/project2']
2225 q1 = self.sched.layout.pipelines['gate'].getQueue(project1)
2226 q2 = self.sched.layout.pipelines['gate'].getQueue(project2)
2227 self.assertEqual(q1.name, 'integration')
2228 self.assertEqual(q2.name, 'integration')
2229
2230 self.config.set('zuul', 'layout_config',
2231 'tests/fixtures/layout-bad-queue.yaml')
2232 with testtools.ExpectedException(
2233 Exception, "More than one name assigned to change queue"):
2234 self.sched.reconfigure(self.config)
2235
James E. Blair64ed6f22013-07-10 14:07:23 -07002236 def test_queue_precedence(self):
2237 "Test that queue precedence works"
2238
2239 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002240 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002241 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2242 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2243 A.addApproval('CRVW', 2)
2244 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2245
2246 self.waitUntilSettled()
2247 self.gearman_server.hold_jobs_in_queue = False
2248 self.gearman_server.release()
2249 self.waitUntilSettled()
2250
James E. Blair8de58bd2013-07-18 16:23:33 -07002251 # Run one build at a time to ensure non-race order:
James E. Blairb8c16472015-05-05 14:55:26 -07002252 self.orderedRelease()
James E. Blair8de58bd2013-07-18 16:23:33 -07002253 self.worker.hold_jobs_in_build = False
2254 self.waitUntilSettled()
2255
James E. Blair64ed6f22013-07-10 14:07:23 -07002256 self.log.debug(self.history)
2257 self.assertEqual(self.history[0].pipeline, 'gate')
2258 self.assertEqual(self.history[1].pipeline, 'check')
2259 self.assertEqual(self.history[2].pipeline, 'gate')
2260 self.assertEqual(self.history[3].pipeline, 'gate')
2261 self.assertEqual(self.history[4].pipeline, 'check')
2262 self.assertEqual(self.history[5].pipeline, 'check')
2263
Clark Boylana5edbe42014-06-03 16:39:10 -07002264 def test_json_status(self):
James E. Blair1843a552013-07-03 14:19:52 -07002265 "Test that we can retrieve JSON status info"
2266 self.worker.hold_jobs_in_build = True
2267 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2268 A.addApproval('CRVW', 2)
2269 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2270 self.waitUntilSettled()
2271
James E. Blairb7273ef2016-04-19 08:58:51 -07002272 self.worker.release('project-merge')
2273 self.waitUntilSettled()
2274
James E. Blair1843a552013-07-03 14:19:52 -07002275 port = self.webapp.server.socket.getsockname()[1]
2276
Morgan Fainberg293f7f82016-05-30 14:01:22 -07002277 req = urllib.request.Request("http://localhost:%s/status.json" % port)
2278 f = urllib.request.urlopen(req)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002279 headers = f.info()
2280 self.assertIn('Content-Length', headers)
2281 self.assertIn('Content-Type', headers)
Sachi Kingdc963fc2016-03-23 16:00:33 +11002282 self.assertIsNotNone(re.match('^application/json(; charset=UTF-8)?$',
2283 headers['Content-Type']))
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002284 self.assertIn('Access-Control-Allow-Origin', headers)
2285 self.assertIn('Cache-Control', headers)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002286 self.assertIn('Last-Modified', headers)
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002287 self.assertIn('Expires', headers)
James E. Blair1843a552013-07-03 14:19:52 -07002288 data = f.read()
2289
2290 self.worker.hold_jobs_in_build = False
2291 self.worker.release()
2292 self.waitUntilSettled()
2293
2294 data = json.loads(data)
James E. Blairb7273ef2016-04-19 08:58:51 -07002295 status_jobs = []
James E. Blair1843a552013-07-03 14:19:52 -07002296 for p in data['pipelines']:
2297 for q in p['change_queues']:
James E. Blairbfb8e042014-12-30 17:01:44 -08002298 if p['name'] in ['gate', 'conflict']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002299 self.assertEqual(q['window'], 20)
2300 else:
2301 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002302 for head in q['heads']:
2303 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002304 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002305 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002306 for job in change['jobs']:
James E. Blairb7273ef2016-04-19 08:58:51 -07002307 status_jobs.append(job)
2308 self.assertEqual('project-merge', status_jobs[0]['name'])
2309 self.assertEqual('https://server/job/project-merge/0/',
2310 status_jobs[0]['url'])
2311 self.assertEqual('http://logs.example.com/1/1/gate/project-merge/0',
2312 status_jobs[0]['report_url'])
2313
2314 self.assertEqual('project-test1', status_jobs[1]['name'])
2315 self.assertEqual('https://server/job/project-test1/1/',
2316 status_jobs[1]['url'])
2317 self.assertEqual('http://logs.example.com/1/1/gate/project-test1/1',
2318 status_jobs[1]['report_url'])
2319
2320 self.assertEqual('project-test2', status_jobs[2]['name'])
2321 self.assertEqual('https://server/job/project-test2/2/',
2322 status_jobs[2]['url'])
2323 self.assertEqual('http://logs.example.com/1/1/gate/project-test2/2',
2324 status_jobs[2]['report_url'])
James E. Blair1843a552013-07-03 14:19:52 -07002325
James E. Blairc3d428e2013-12-03 15:06:48 -08002326 def test_merging_queues(self):
2327 "Test that transitively-connected change queues are merged"
2328 self.config.set('zuul', 'layout_config',
2329 'tests/fixtures/layout-merge-queues.yaml')
2330 self.sched.reconfigure(self.config)
2331 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2332
James E. Blairaf17a972016-02-03 15:07:18 -08002333 def test_mutex(self):
2334 "Test job mutexes"
2335 self.config.set('zuul', 'layout_config',
2336 'tests/fixtures/layout-mutex.yaml')
2337 self.sched.reconfigure(self.config)
2338
2339 self.worker.hold_jobs_in_build = True
2340 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2341 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2342 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2343
2344 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2345 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2346 self.waitUntilSettled()
2347 self.assertEqual(len(self.builds), 3)
2348 self.assertEqual(self.builds[0].name, 'project-test1')
2349 self.assertEqual(self.builds[1].name, 'mutex-one')
2350 self.assertEqual(self.builds[2].name, 'project-test1')
2351
2352 self.worker.release('mutex-one')
2353 self.waitUntilSettled()
2354
2355 self.assertEqual(len(self.builds), 3)
2356 self.assertEqual(self.builds[0].name, 'project-test1')
2357 self.assertEqual(self.builds[1].name, 'project-test1')
2358 self.assertEqual(self.builds[2].name, 'mutex-two')
2359 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2360
2361 self.worker.release('mutex-two')
2362 self.waitUntilSettled()
2363
2364 self.assertEqual(len(self.builds), 3)
2365 self.assertEqual(self.builds[0].name, 'project-test1')
2366 self.assertEqual(self.builds[1].name, 'project-test1')
2367 self.assertEqual(self.builds[2].name, 'mutex-one')
2368 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2369
2370 self.worker.release('mutex-one')
2371 self.waitUntilSettled()
2372
2373 self.assertEqual(len(self.builds), 3)
2374 self.assertEqual(self.builds[0].name, 'project-test1')
2375 self.assertEqual(self.builds[1].name, 'project-test1')
2376 self.assertEqual(self.builds[2].name, 'mutex-two')
2377 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2378
2379 self.worker.release('mutex-two')
2380 self.waitUntilSettled()
2381
2382 self.assertEqual(len(self.builds), 2)
2383 self.assertEqual(self.builds[0].name, 'project-test1')
2384 self.assertEqual(self.builds[1].name, 'project-test1')
2385 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2386
2387 self.worker.hold_jobs_in_build = False
2388 self.worker.release()
2389
2390 self.waitUntilSettled()
2391 self.assertEqual(len(self.builds), 0)
2392
2393 self.assertEqual(A.reported, 1)
2394 self.assertEqual(B.reported, 1)
2395 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2396
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002397 def test_node_label(self):
2398 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002399 self.worker.registerFunction('build:node-project-test1:debian')
2400
2401 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2402 A.addApproval('CRVW', 2)
2403 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2404 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002405
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002406 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2407 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2408 'debian')
2409 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002410
2411 def test_live_reconfiguration(self):
2412 "Test that live reconfiguration works"
2413 self.worker.hold_jobs_in_build = True
2414 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2415 A.addApproval('CRVW', 2)
2416 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2417 self.waitUntilSettled()
2418
2419 self.sched.reconfigure(self.config)
2420
2421 self.worker.hold_jobs_in_build = False
2422 self.worker.release()
2423 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002424 self.assertEqual(self.getJobFromHistory('project-merge').result,
2425 'SUCCESS')
2426 self.assertEqual(self.getJobFromHistory('project-test1').result,
2427 'SUCCESS')
2428 self.assertEqual(self.getJobFromHistory('project-test2').result,
2429 'SUCCESS')
2430 self.assertEqual(A.data['status'], 'MERGED')
2431 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002432
James E. Blair6bc782d2015-07-17 16:20:21 -07002433 def test_live_reconfiguration_merge_conflict(self):
2434 # A real-world bug: a change in a gate queue has a merge
2435 # conflict and a job is added to its project while it's
2436 # sitting in the queue. The job gets added to the change and
2437 # enqueued and the change gets stuck.
2438 self.worker.registerFunction('build:project-test3')
2439 self.worker.hold_jobs_in_build = True
2440
2441 # This change is fine. It's here to stop the queue long
2442 # enough for the next change to be subject to the
2443 # reconfiguration, as well as to provide a conflict for the
2444 # next change. This change will succeed and merge.
2445 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2446 A.addPatchset(['conflict'])
2447 A.addApproval('CRVW', 2)
James E. Blair6bc782d2015-07-17 16:20:21 -07002448
2449 # This change will be in merge conflict. During the
2450 # reconfiguration, we will add a job. We want to make sure
2451 # that doesn't cause it to get stuck.
2452 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2453 B.addPatchset(['conflict'])
2454 B.addApproval('CRVW', 2)
James E. Blair4eb21fa2015-07-27 14:56:47 -07002455
2456 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
James E. Blair6bc782d2015-07-17 16:20:21 -07002457 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2458
2459 self.waitUntilSettled()
2460
2461 # No jobs have run yet
2462 self.assertEqual(A.data['status'], 'NEW')
2463 self.assertEqual(A.reported, 1)
2464 self.assertEqual(B.data['status'], 'NEW')
2465 self.assertEqual(B.reported, 1)
2466 self.assertEqual(len(self.history), 0)
2467
2468 # Add the "project-test3" job.
2469 self.config.set('zuul', 'layout_config',
2470 'tests/fixtures/layout-live-'
2471 'reconfiguration-add-job.yaml')
2472 self.sched.reconfigure(self.config)
2473 self.waitUntilSettled()
2474
2475 self.worker.hold_jobs_in_build = False
2476 self.worker.release()
2477 self.waitUntilSettled()
2478
2479 self.assertEqual(A.data['status'], 'MERGED')
2480 self.assertEqual(A.reported, 2)
2481 self.assertEqual(B.data['status'], 'NEW')
2482 self.assertEqual(B.reported, 2)
2483 self.assertEqual(self.getJobFromHistory('project-merge').result,
2484 'SUCCESS')
2485 self.assertEqual(self.getJobFromHistory('project-test1').result,
2486 'SUCCESS')
2487 self.assertEqual(self.getJobFromHistory('project-test2').result,
2488 'SUCCESS')
2489 self.assertEqual(self.getJobFromHistory('project-test3').result,
2490 'SUCCESS')
2491 self.assertEqual(len(self.history), 4)
2492
James E. Blair400e8fd2015-07-30 17:44:45 -07002493 def test_live_reconfiguration_failed_root(self):
James E. Blair6bc782d2015-07-17 16:20:21 -07002494 # An extrapolation of test_live_reconfiguration_merge_conflict
2495 # that tests a job added to a job tree with a failed root does
2496 # not run.
2497 self.worker.registerFunction('build:project-test3')
2498 self.worker.hold_jobs_in_build = True
2499
2500 # This change is fine. It's here to stop the queue long
2501 # enough for the next change to be subject to the
2502 # reconfiguration. This change will succeed and merge.
2503 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2504 A.addPatchset(['conflict'])
2505 A.addApproval('CRVW', 2)
2506 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2507 self.waitUntilSettled()
2508 self.worker.release('.*-merge')
2509 self.waitUntilSettled()
2510
2511 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2512 self.worker.addFailTest('project-merge', B)
2513 B.addApproval('CRVW', 2)
2514 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2515 self.waitUntilSettled()
2516
2517 self.worker.release('.*-merge')
2518 self.waitUntilSettled()
2519
2520 # Both -merge jobs have run, but no others.
2521 self.assertEqual(A.data['status'], 'NEW')
2522 self.assertEqual(A.reported, 1)
2523 self.assertEqual(B.data['status'], 'NEW')
2524 self.assertEqual(B.reported, 1)
2525 self.assertEqual(self.history[0].result, 'SUCCESS')
2526 self.assertEqual(self.history[0].name, 'project-merge')
2527 self.assertEqual(self.history[1].result, 'FAILURE')
2528 self.assertEqual(self.history[1].name, 'project-merge')
2529 self.assertEqual(len(self.history), 2)
2530
2531 # Add the "project-test3" job.
2532 self.config.set('zuul', 'layout_config',
2533 'tests/fixtures/layout-live-'
2534 'reconfiguration-add-job.yaml')
2535 self.sched.reconfigure(self.config)
2536 self.waitUntilSettled()
2537
2538 self.worker.hold_jobs_in_build = False
2539 self.worker.release()
2540 self.waitUntilSettled()
2541
2542 self.assertEqual(A.data['status'], 'MERGED')
2543 self.assertEqual(A.reported, 2)
2544 self.assertEqual(B.data['status'], 'NEW')
2545 self.assertEqual(B.reported, 2)
2546 self.assertEqual(self.history[0].result, 'SUCCESS')
2547 self.assertEqual(self.history[0].name, 'project-merge')
2548 self.assertEqual(self.history[1].result, 'FAILURE')
2549 self.assertEqual(self.history[1].name, 'project-merge')
2550 self.assertEqual(self.history[2].result, 'SUCCESS')
2551 self.assertEqual(self.history[3].result, 'SUCCESS')
2552 self.assertEqual(self.history[4].result, 'SUCCESS')
2553 self.assertEqual(len(self.history), 5)
2554
James E. Blair400e8fd2015-07-30 17:44:45 -07002555 def test_live_reconfiguration_failed_job(self):
2556 # Test that a change with a removed failing job does not
2557 # disrupt reconfiguration. If a change has a failed job and
2558 # that job is removed during a reconfiguration, we observed a
2559 # bug where the code to re-set build statuses would run on
2560 # that build and raise an exception because the job no longer
2561 # existed.
2562 self.worker.hold_jobs_in_build = True
2563
2564 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2565
2566 # This change will fail and later be removed by the reconfiguration.
2567 self.worker.addFailTest('project-test1', A)
2568
2569 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2570 self.waitUntilSettled()
2571 self.worker.release('.*-merge')
2572 self.waitUntilSettled()
2573 self.worker.release('project-test1')
2574 self.waitUntilSettled()
2575
2576 self.assertEqual(A.data['status'], 'NEW')
2577 self.assertEqual(A.reported, 0)
2578
2579 self.assertEqual(self.getJobFromHistory('project-merge').result,
2580 'SUCCESS')
2581 self.assertEqual(self.getJobFromHistory('project-test1').result,
2582 'FAILURE')
2583 self.assertEqual(len(self.history), 2)
2584
2585 # Remove the test1 job.
2586 self.config.set('zuul', 'layout_config',
2587 'tests/fixtures/layout-live-'
2588 'reconfiguration-failed-job.yaml')
2589 self.sched.reconfigure(self.config)
2590 self.waitUntilSettled()
2591
2592 self.worker.hold_jobs_in_build = False
2593 self.worker.release()
2594 self.waitUntilSettled()
2595
2596 self.assertEqual(self.getJobFromHistory('project-test2').result,
2597 'SUCCESS')
2598 self.assertEqual(self.getJobFromHistory('project-testfile').result,
2599 'SUCCESS')
2600 self.assertEqual(len(self.history), 4)
2601
2602 self.assertEqual(A.data['status'], 'NEW')
2603 self.assertEqual(A.reported, 1)
2604 self.assertIn('Build succeeded', A.messages[0])
2605 # Ensure the removed job was not included in the report.
2606 self.assertNotIn('project-test1', A.messages[0])
2607
James E. Blairfe707d12015-08-05 15:18:15 -07002608 def test_live_reconfiguration_shared_queue(self):
2609 # Test that a change with a failing job which was removed from
2610 # this project but otherwise still exists in the system does
2611 # not disrupt reconfiguration.
2612
2613 self.worker.hold_jobs_in_build = True
2614
2615 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2616
2617 self.worker.addFailTest('project1-project2-integration', A)
2618
2619 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2620 self.waitUntilSettled()
2621 self.worker.release('.*-merge')
2622 self.waitUntilSettled()
2623 self.worker.release('project1-project2-integration')
2624 self.waitUntilSettled()
2625
2626 self.assertEqual(A.data['status'], 'NEW')
2627 self.assertEqual(A.reported, 0)
2628
2629 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2630 'SUCCESS')
2631 self.assertEqual(self.getJobFromHistory(
2632 'project1-project2-integration').result, 'FAILURE')
2633 self.assertEqual(len(self.history), 2)
2634
2635 # Remove the integration job.
2636 self.config.set('zuul', 'layout_config',
2637 'tests/fixtures/layout-live-'
2638 'reconfiguration-shared-queue.yaml')
2639 self.sched.reconfigure(self.config)
2640 self.waitUntilSettled()
2641
2642 self.worker.hold_jobs_in_build = False
2643 self.worker.release()
2644 self.waitUntilSettled()
2645
2646 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2647 'SUCCESS')
2648 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2649 'SUCCESS')
2650 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2651 'SUCCESS')
2652 self.assertEqual(self.getJobFromHistory(
2653 'project1-project2-integration').result, 'FAILURE')
2654 self.assertEqual(len(self.history), 4)
2655
2656 self.assertEqual(A.data['status'], 'NEW')
2657 self.assertEqual(A.reported, 1)
2658 self.assertIn('Build succeeded', A.messages[0])
2659 # Ensure the removed job was not included in the report.
2660 self.assertNotIn('project1-project2-integration', A.messages[0])
2661
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11002662 def test_double_live_reconfiguration_shared_queue(self):
2663 # This was a real-world regression. A change is added to
2664 # gate; a reconfigure happens, a second change which depends
2665 # on the first is added, and a second reconfiguration happens.
2666 # Ensure that both changes merge.
2667
2668 # A failure may indicate incorrect caching or cleaning up of
2669 # references during a reconfiguration.
2670 self.worker.hold_jobs_in_build = True
2671
2672 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2673 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2674 B.setDependsOn(A, 1)
2675 A.addApproval('CRVW', 2)
2676 B.addApproval('CRVW', 2)
2677
2678 # Add the parent change.
2679 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2680 self.waitUntilSettled()
2681 self.worker.release('.*-merge')
2682 self.waitUntilSettled()
2683
2684 # Reconfigure (with only one change in the pipeline).
2685 self.sched.reconfigure(self.config)
2686 self.waitUntilSettled()
2687
2688 # Add the child change.
2689 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2690 self.waitUntilSettled()
2691 self.worker.release('.*-merge')
2692 self.waitUntilSettled()
2693
2694 # Reconfigure (with both in the pipeline).
2695 self.sched.reconfigure(self.config)
2696 self.waitUntilSettled()
2697
2698 self.worker.hold_jobs_in_build = False
2699 self.worker.release()
2700 self.waitUntilSettled()
2701
2702 self.assertEqual(len(self.history), 8)
2703
2704 self.assertEqual(A.data['status'], 'MERGED')
2705 self.assertEqual(A.reported, 2)
2706 self.assertEqual(B.data['status'], 'MERGED')
2707 self.assertEqual(B.reported, 2)
2708
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002709 def test_live_reconfiguration_del_project(self):
2710 # Test project deletion from layout
2711 # while changes are enqueued
2712
2713 self.worker.hold_jobs_in_build = True
2714 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2715 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2716 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2717
2718 # A Depends-On: B
2719 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2720 A.subject, B.data['id'])
2721 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2722
2723 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2724 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2725 self.waitUntilSettled()
2726 self.worker.release('.*-merge')
2727 self.waitUntilSettled()
2728 self.assertEqual(len(self.builds), 5)
2729
2730 # This layout defines only org/project, not org/project1
2731 self.config.set('zuul', 'layout_config',
2732 'tests/fixtures/layout-live-'
2733 'reconfiguration-del-project.yaml')
2734 self.sched.reconfigure(self.config)
2735 self.waitUntilSettled()
2736
2737 # Builds for C aborted, builds for A succeed,
2738 # and have change B applied ahead
2739 job_c = self.getJobFromHistory('project1-test1')
2740 self.assertEqual(job_c.changes, '3,1')
2741 self.assertEqual(job_c.result, 'ABORTED')
2742
2743 self.worker.hold_jobs_in_build = False
2744 self.worker.release()
2745 self.waitUntilSettled()
2746
2747 self.assertEqual(self.getJobFromHistory('project-test1').changes,
2748 '2,1 1,1')
2749
2750 self.assertEqual(A.data['status'], 'NEW')
2751 self.assertEqual(B.data['status'], 'NEW')
2752 self.assertEqual(C.data['status'], 'NEW')
2753 self.assertEqual(A.reported, 1)
2754 self.assertEqual(B.reported, 0)
2755 self.assertEqual(C.reported, 0)
2756
2757 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
2758 self.assertIn('Build succeeded', A.messages[0])
2759
James E. Blaire712d9f2013-07-31 11:40:11 -07002760 def test_live_reconfiguration_functions(self):
2761 "Test live reconfiguration with a custom function"
2762 self.worker.registerFunction('build:node-project-test1:debian')
2763 self.worker.registerFunction('build:node-project-test1:wheezy')
2764 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2765 A.addApproval('CRVW', 2)
2766 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2767 self.waitUntilSettled()
2768
2769 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2770 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2771 'debian')
2772 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2773
2774 self.config.set('zuul', 'layout_config',
2775 'tests/fixtures/layout-live-'
2776 'reconfiguration-functions.yaml')
2777 self.sched.reconfigure(self.config)
2778 self.worker.build_history = []
2779
2780 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2781 B.addApproval('CRVW', 2)
2782 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2783 self.waitUntilSettled()
2784
2785 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2786 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2787 'wheezy')
2788 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2789
James E. Blair287c06d2013-07-24 10:39:30 -07002790 def test_delayed_repo_init(self):
2791 self.config.set('zuul', 'layout_config',
2792 'tests/fixtures/layout-delayed-repo-init.yaml')
2793 self.sched.reconfigure(self.config)
2794
2795 self.init_repo("org/new-project")
2796 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2797
2798 A.addApproval('CRVW', 2)
2799 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2800 self.waitUntilSettled()
2801 self.assertEqual(self.getJobFromHistory('project-merge').result,
2802 'SUCCESS')
2803 self.assertEqual(self.getJobFromHistory('project-test1').result,
2804 'SUCCESS')
2805 self.assertEqual(self.getJobFromHistory('project-test2').result,
2806 'SUCCESS')
2807 self.assertEqual(A.data['status'], 'MERGED')
2808 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002809
Clark Boylan6dbbc482013-10-18 10:57:31 -07002810 def test_repo_deleted(self):
2811 self.config.set('zuul', 'layout_config',
2812 'tests/fixtures/layout-repo-deleted.yaml')
2813 self.sched.reconfigure(self.config)
2814
2815 self.init_repo("org/delete-project")
2816 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2817
2818 A.addApproval('CRVW', 2)
2819 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2820 self.waitUntilSettled()
2821 self.assertEqual(self.getJobFromHistory('project-merge').result,
2822 'SUCCESS')
2823 self.assertEqual(self.getJobFromHistory('project-test1').result,
2824 'SUCCESS')
2825 self.assertEqual(self.getJobFromHistory('project-test2').result,
2826 'SUCCESS')
2827 self.assertEqual(A.data['status'], 'MERGED')
2828 self.assertEqual(A.reported, 2)
2829
2830 # Delete org/new-project zuul repo. Should be recloned.
2831 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2832
2833 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2834
2835 B.addApproval('CRVW', 2)
2836 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2837 self.waitUntilSettled()
2838 self.assertEqual(self.getJobFromHistory('project-merge').result,
2839 'SUCCESS')
2840 self.assertEqual(self.getJobFromHistory('project-test1').result,
2841 'SUCCESS')
2842 self.assertEqual(self.getJobFromHistory('project-test2').result,
2843 'SUCCESS')
2844 self.assertEqual(B.data['status'], 'MERGED')
2845 self.assertEqual(B.reported, 2)
2846
James E. Blair456f2fb2016-02-09 09:29:33 -08002847 def test_tags(self):
2848 "Test job tags"
2849 self.config.set('zuul', 'layout_config',
2850 'tests/fixtures/layout-tags.yaml')
2851 self.sched.reconfigure(self.config)
2852
2853 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2854 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
2855 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2856 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2857 self.waitUntilSettled()
2858
2859 results = {'project1-merge': 'extratag merge project1',
2860 'project2-merge': 'merge'}
2861
2862 for build in self.history:
2863 self.assertEqual(results.get(build.name, ''),
2864 build.parameters.get('BUILD_TAGS'))
2865
James E. Blair63bb0ef2013-07-29 17:14:51 -07002866 def test_timer(self):
2867 "Test that a periodic job is triggered"
2868 self.worker.hold_jobs_in_build = True
2869 self.config.set('zuul', 'layout_config',
2870 'tests/fixtures/layout-timer.yaml')
2871 self.sched.reconfigure(self.config)
2872 self.registerJobs()
2873
Clark Boylan3ee090a2014-04-03 20:55:09 -07002874 # The pipeline triggers every second, so we should have seen
2875 # several by now.
2876 time.sleep(5)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002877 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002878
2879 self.assertEqual(len(self.builds), 2)
2880
James E. Blair63bb0ef2013-07-29 17:14:51 -07002881 port = self.webapp.server.socket.getsockname()[1]
2882
Morgan Fainberg293f7f82016-05-30 14:01:22 -07002883 req = urllib.request.Request("http://localhost:%s/status.json" % port)
2884 f = urllib.request.urlopen(req)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002885 data = f.read()
2886
2887 self.worker.hold_jobs_in_build = False
Clark Boylan3ee090a2014-04-03 20:55:09 -07002888 # Stop queuing timer triggered jobs so that the assertions
2889 # below don't race against more jobs being queued.
2890 self.config.set('zuul', 'layout_config',
2891 'tests/fixtures/layout-no-timer.yaml')
2892 self.sched.reconfigure(self.config)
2893 self.registerJobs()
James E. Blair63bb0ef2013-07-29 17:14:51 -07002894 self.worker.release()
2895 self.waitUntilSettled()
2896
2897 self.assertEqual(self.getJobFromHistory(
2898 'project-bitrot-stable-old').result, 'SUCCESS')
2899 self.assertEqual(self.getJobFromHistory(
2900 'project-bitrot-stable-older').result, 'SUCCESS')
2901
2902 data = json.loads(data)
2903 status_jobs = set()
2904 for p in data['pipelines']:
2905 for q in p['change_queues']:
2906 for head in q['heads']:
2907 for change in head:
Alex Gaynorddb9ef32013-09-16 21:04:58 -07002908 self.assertEqual(change['id'], None)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002909 for job in change['jobs']:
2910 status_jobs.add(job['name'])
2911 self.assertIn('project-bitrot-stable-old', status_jobs)
2912 self.assertIn('project-bitrot-stable-older', status_jobs)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002913
James E. Blair4f6033c2014-03-27 15:49:09 -07002914 def test_idle(self):
2915 "Test that frequent periodic jobs work"
2916 self.worker.hold_jobs_in_build = True
James E. Blair4f6033c2014-03-27 15:49:09 -07002917
Clark Boylan3ee090a2014-04-03 20:55:09 -07002918 for x in range(1, 3):
2919 # Test that timer triggers periodic jobs even across
2920 # layout config reloads.
2921 # Start timer trigger
2922 self.config.set('zuul', 'layout_config',
2923 'tests/fixtures/layout-idle.yaml')
2924 self.sched.reconfigure(self.config)
2925 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002926 self.waitUntilSettled()
James E. Blair4f6033c2014-03-27 15:49:09 -07002927
Clark Boylan3ee090a2014-04-03 20:55:09 -07002928 # The pipeline triggers every second, so we should have seen
2929 # several by now.
2930 time.sleep(5)
Clark Boylan3ee090a2014-04-03 20:55:09 -07002931
2932 # Stop queuing timer triggered jobs so that the assertions
2933 # below don't race against more jobs being queued.
2934 self.config.set('zuul', 'layout_config',
2935 'tests/fixtures/layout-no-timer.yaml')
2936 self.sched.reconfigure(self.config)
2937 self.registerJobs()
James E. Blair995fc0f2016-02-04 16:48:31 -08002938 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002939
2940 self.assertEqual(len(self.builds), 2)
2941 self.worker.release('.*')
2942 self.waitUntilSettled()
2943 self.assertEqual(len(self.builds), 0)
2944 self.assertEqual(len(self.history), x * 2)
James E. Blair4f6033c2014-03-27 15:49:09 -07002945
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002946 def test_check_smtp_pool(self):
2947 self.config.set('zuul', 'layout_config',
2948 'tests/fixtures/layout-smtp.yaml')
2949 self.sched.reconfigure(self.config)
2950
2951 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2952 self.waitUntilSettled()
2953
2954 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2955 self.waitUntilSettled()
2956
James E. Blairff80a2f2013-12-27 13:24:06 -08002957 self.assertEqual(len(self.smtp_messages), 2)
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002958
2959 # A.messages only holds what FakeGerrit places in it. Thus we
2960 # work on the knowledge of what the first message should be as
2961 # it is only configured to go to SMTP.
2962
2963 self.assertEqual('zuul@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002964 self.smtp_messages[0]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002965 self.assertEqual(['you@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002966 self.smtp_messages[0]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002967 self.assertEqual('Starting check jobs.',
James E. Blairff80a2f2013-12-27 13:24:06 -08002968 self.smtp_messages[0]['body'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002969
2970 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08002971 self.smtp_messages[1]['from_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002972 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08002973 self.smtp_messages[1]['to_email'])
Joshua Hesketh5fea8672013-08-19 17:32:01 +10002974 self.assertEqual(A.messages[0],
James E. Blairff80a2f2013-12-27 13:24:06 -08002975 self.smtp_messages[1]['body'])
James E. Blairad28e912013-11-27 10:43:22 -08002976
James E. Blaire5910202013-12-27 09:50:31 -08002977 def test_timer_smtp(self):
2978 "Test that a periodic job is triggered"
Clark Boylan3ee090a2014-04-03 20:55:09 -07002979 self.worker.hold_jobs_in_build = True
James E. Blaire5910202013-12-27 09:50:31 -08002980 self.config.set('zuul', 'layout_config',
2981 'tests/fixtures/layout-timer-smtp.yaml')
2982 self.sched.reconfigure(self.config)
2983 self.registerJobs()
2984
Clark Boylan3ee090a2014-04-03 20:55:09 -07002985 # The pipeline triggers every second, so we should have seen
2986 # several by now.
2987 time.sleep(5)
James E. Blaire5910202013-12-27 09:50:31 -08002988 self.waitUntilSettled()
2989
Clark Boylan3ee090a2014-04-03 20:55:09 -07002990 self.assertEqual(len(self.builds), 2)
2991 self.worker.release('.*')
2992 self.waitUntilSettled()
2993 self.assertEqual(len(self.history), 2)
2994
James E. Blaire5910202013-12-27 09:50:31 -08002995 self.assertEqual(self.getJobFromHistory(
2996 'project-bitrot-stable-old').result, 'SUCCESS')
2997 self.assertEqual(self.getJobFromHistory(
2998 'project-bitrot-stable-older').result, 'SUCCESS')
2999
James E. Blairff80a2f2013-12-27 13:24:06 -08003000 self.assertEqual(len(self.smtp_messages), 1)
James E. Blaire5910202013-12-27 09:50:31 -08003001
3002 # A.messages only holds what FakeGerrit places in it. Thus we
3003 # work on the knowledge of what the first message should be as
3004 # it is only configured to go to SMTP.
3005
3006 self.assertEqual('zuul_from@example.com',
James E. Blairff80a2f2013-12-27 13:24:06 -08003007 self.smtp_messages[0]['from_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003008 self.assertEqual(['alternative_me@example.com'],
James E. Blairff80a2f2013-12-27 13:24:06 -08003009 self.smtp_messages[0]['to_email'])
James E. Blaire5910202013-12-27 09:50:31 -08003010 self.assertIn('Subject: Periodic check for org/project succeeded',
James E. Blairff80a2f2013-12-27 13:24:06 -08003011 self.smtp_messages[0]['headers'])
James E. Blaire5910202013-12-27 09:50:31 -08003012
Clark Boylan3ee090a2014-04-03 20:55:09 -07003013 # Stop queuing timer triggered jobs and let any that may have
3014 # queued through so that end of test assertions pass.
3015 self.config.set('zuul', 'layout_config',
3016 'tests/fixtures/layout-no-timer.yaml')
3017 self.sched.reconfigure(self.config)
3018 self.registerJobs()
James E. Blairf8058972014-08-15 16:09:16 -07003019 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07003020 self.worker.release('.*')
3021 self.waitUntilSettled()
3022
James E. Blair91e34592015-07-31 16:45:59 -07003023 def test_client_enqueue_change(self):
James E. Blairad28e912013-11-27 10:43:22 -08003024 "Test that the RPC client can enqueue a change"
3025 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3026 A.addApproval('CRVW', 2)
3027 A.addApproval('APRV', 1)
3028
3029 client = zuul.rpcclient.RPCClient('127.0.0.1',
3030 self.gearman_server.port)
3031 r = client.enqueue(pipeline='gate',
3032 project='org/project',
3033 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003034 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003035 self.waitUntilSettled()
3036 self.assertEqual(self.getJobFromHistory('project-merge').result,
3037 'SUCCESS')
3038 self.assertEqual(self.getJobFromHistory('project-test1').result,
3039 'SUCCESS')
3040 self.assertEqual(self.getJobFromHistory('project-test2').result,
3041 'SUCCESS')
3042 self.assertEqual(A.data['status'], 'MERGED')
3043 self.assertEqual(A.reported, 2)
3044 self.assertEqual(r, True)
3045
James E. Blair91e34592015-07-31 16:45:59 -07003046 def test_client_enqueue_ref(self):
3047 "Test that the RPC client can enqueue a ref"
3048
3049 client = zuul.rpcclient.RPCClient('127.0.0.1',
3050 self.gearman_server.port)
3051 r = client.enqueue_ref(
3052 pipeline='post',
3053 project='org/project',
3054 trigger='gerrit',
3055 ref='master',
3056 oldrev='90f173846e3af9154517b88543ffbd1691f31366',
3057 newrev='d479a0bfcb34da57a31adb2a595c0cf687812543')
3058 self.waitUntilSettled()
3059 job_names = [x.name for x in self.history]
3060 self.assertEqual(len(self.history), 1)
3061 self.assertIn('project-post', job_names)
3062 self.assertEqual(r, True)
3063
James E. Blairad28e912013-11-27 10:43:22 -08003064 def test_client_enqueue_negative(self):
3065 "Test that the RPC client returns errors"
3066 client = zuul.rpcclient.RPCClient('127.0.0.1',
3067 self.gearman_server.port)
3068 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3069 "Invalid project"):
3070 r = client.enqueue(pipeline='gate',
3071 project='project-does-not-exist',
3072 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003073 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003074 client.shutdown()
3075 self.assertEqual(r, False)
3076
3077 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3078 "Invalid pipeline"):
3079 r = client.enqueue(pipeline='pipeline-does-not-exist',
3080 project='org/project',
3081 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003082 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003083 client.shutdown()
3084 self.assertEqual(r, False)
3085
3086 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3087 "Invalid trigger"):
3088 r = client.enqueue(pipeline='gate',
3089 project='org/project',
3090 trigger='trigger-does-not-exist',
James E. Blair36658cf2013-12-06 17:53:48 -08003091 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003092 client.shutdown()
3093 self.assertEqual(r, False)
3094
3095 with testtools.ExpectedException(zuul.rpcclient.RPCFailure,
3096 "Invalid change"):
3097 r = client.enqueue(pipeline='gate',
3098 project='org/project',
3099 trigger='gerrit',
James E. Blair36658cf2013-12-06 17:53:48 -08003100 change='1,1')
James E. Blairad28e912013-11-27 10:43:22 -08003101 client.shutdown()
3102 self.assertEqual(r, False)
3103
3104 self.waitUntilSettled()
3105 self.assertEqual(len(self.history), 0)
3106 self.assertEqual(len(self.builds), 0)
James E. Blair36658cf2013-12-06 17:53:48 -08003107
3108 def test_client_promote(self):
3109 "Test that the RPC client can promote a change"
3110 self.worker.hold_jobs_in_build = True
3111 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3112 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3113 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3114 A.addApproval('CRVW', 2)
3115 B.addApproval('CRVW', 2)
3116 C.addApproval('CRVW', 2)
3117
3118 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3119 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3120 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3121
3122 self.waitUntilSettled()
3123
Sean Daguef39b9ca2014-01-10 21:34:35 -05003124 items = self.sched.layout.pipelines['gate'].getAllItems()
3125 enqueue_times = {}
3126 for item in items:
3127 enqueue_times[str(item.change)] = item.enqueue_time
3128
James E. Blair36658cf2013-12-06 17:53:48 -08003129 client = zuul.rpcclient.RPCClient('127.0.0.1',
3130 self.gearman_server.port)
3131 r = client.promote(pipeline='gate',
3132 change_ids=['2,1', '3,1'])
3133
Sean Daguef39b9ca2014-01-10 21:34:35 -05003134 # ensure that enqueue times are durable
3135 items = self.sched.layout.pipelines['gate'].getAllItems()
3136 for item in items:
3137 self.assertEqual(
3138 enqueue_times[str(item.change)], item.enqueue_time)
3139
James E. Blair78acec92014-02-06 07:11:32 -08003140 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003141 self.worker.release('.*-merge')
3142 self.waitUntilSettled()
3143 self.worker.release('.*-merge')
3144 self.waitUntilSettled()
3145 self.worker.release('.*-merge')
3146 self.waitUntilSettled()
3147
3148 self.assertEqual(len(self.builds), 6)
3149 self.assertEqual(self.builds[0].name, 'project-test1')
3150 self.assertEqual(self.builds[1].name, 'project-test2')
3151 self.assertEqual(self.builds[2].name, 'project-test1')
3152 self.assertEqual(self.builds[3].name, 'project-test2')
3153 self.assertEqual(self.builds[4].name, 'project-test1')
3154 self.assertEqual(self.builds[5].name, 'project-test2')
3155
3156 self.assertTrue(self.job_has_changes(self.builds[0], B))
3157 self.assertFalse(self.job_has_changes(self.builds[0], A))
3158 self.assertFalse(self.job_has_changes(self.builds[0], C))
3159
3160 self.assertTrue(self.job_has_changes(self.builds[2], B))
3161 self.assertTrue(self.job_has_changes(self.builds[2], C))
3162 self.assertFalse(self.job_has_changes(self.builds[2], A))
3163
3164 self.assertTrue(self.job_has_changes(self.builds[4], B))
3165 self.assertTrue(self.job_has_changes(self.builds[4], C))
3166 self.assertTrue(self.job_has_changes(self.builds[4], A))
3167
3168 self.worker.release()
3169 self.waitUntilSettled()
3170
3171 self.assertEqual(A.data['status'], 'MERGED')
3172 self.assertEqual(A.reported, 2)
3173 self.assertEqual(B.data['status'], 'MERGED')
3174 self.assertEqual(B.reported, 2)
3175 self.assertEqual(C.data['status'], 'MERGED')
3176 self.assertEqual(C.reported, 2)
3177
3178 client.shutdown()
3179 self.assertEqual(r, True)
3180
3181 def test_client_promote_dependent(self):
3182 "Test that the RPC client can promote a dependent change"
3183 # C (depends on B) -> B -> A ; then promote C to get:
3184 # A -> C (depends on B) -> B
3185 self.worker.hold_jobs_in_build = True
3186 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3187 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3188 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3189
3190 C.setDependsOn(B, 1)
3191
3192 A.addApproval('CRVW', 2)
3193 B.addApproval('CRVW', 2)
3194 C.addApproval('CRVW', 2)
3195
3196 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3197 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3198 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3199
3200 self.waitUntilSettled()
3201
3202 client = zuul.rpcclient.RPCClient('127.0.0.1',
3203 self.gearman_server.port)
3204 r = client.promote(pipeline='gate',
3205 change_ids=['3,1'])
3206
James E. Blair78acec92014-02-06 07:11:32 -08003207 self.waitUntilSettled()
James E. Blair36658cf2013-12-06 17:53:48 -08003208 self.worker.release('.*-merge')
3209 self.waitUntilSettled()
3210 self.worker.release('.*-merge')
3211 self.waitUntilSettled()
3212 self.worker.release('.*-merge')
3213 self.waitUntilSettled()
3214
3215 self.assertEqual(len(self.builds), 6)
3216 self.assertEqual(self.builds[0].name, 'project-test1')
3217 self.assertEqual(self.builds[1].name, 'project-test2')
3218 self.assertEqual(self.builds[2].name, 'project-test1')
3219 self.assertEqual(self.builds[3].name, 'project-test2')
3220 self.assertEqual(self.builds[4].name, 'project-test1')
3221 self.assertEqual(self.builds[5].name, 'project-test2')
3222
3223 self.assertTrue(self.job_has_changes(self.builds[0], B))
3224 self.assertFalse(self.job_has_changes(self.builds[0], A))
3225 self.assertFalse(self.job_has_changes(self.builds[0], C))
3226
3227 self.assertTrue(self.job_has_changes(self.builds[2], B))
3228 self.assertTrue(self.job_has_changes(self.builds[2], C))
3229 self.assertFalse(self.job_has_changes(self.builds[2], A))
3230
3231 self.assertTrue(self.job_has_changes(self.builds[4], B))
3232 self.assertTrue(self.job_has_changes(self.builds[4], C))
3233 self.assertTrue(self.job_has_changes(self.builds[4], A))
3234
3235 self.worker.release()
3236 self.waitUntilSettled()
3237
3238 self.assertEqual(A.data['status'], 'MERGED')
3239 self.assertEqual(A.reported, 2)
3240 self.assertEqual(B.data['status'], 'MERGED')
3241 self.assertEqual(B.reported, 2)
3242 self.assertEqual(C.data['status'], 'MERGED')
3243 self.assertEqual(C.reported, 2)
3244
3245 client.shutdown()
3246 self.assertEqual(r, True)
3247
3248 def test_client_promote_negative(self):
3249 "Test that the RPC client returns errors for promotion"
3250 self.worker.hold_jobs_in_build = True
3251 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3252 A.addApproval('CRVW', 2)
3253 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3254 self.waitUntilSettled()
3255
3256 client = zuul.rpcclient.RPCClient('127.0.0.1',
3257 self.gearman_server.port)
3258
3259 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3260 r = client.promote(pipeline='nonexistent',
3261 change_ids=['2,1', '3,1'])
3262 client.shutdown()
3263 self.assertEqual(r, False)
3264
3265 with testtools.ExpectedException(zuul.rpcclient.RPCFailure):
3266 r = client.promote(pipeline='gate',
3267 change_ids=['4,1'])
3268 client.shutdown()
3269 self.assertEqual(r, False)
3270
3271 self.worker.hold_jobs_in_build = False
3272 self.worker.release()
3273 self.waitUntilSettled()
Clark Boylan7603a372014-01-21 11:43:20 -08003274
3275 def test_queue_rate_limiting(self):
3276 "Test that DependentPipelines are rate limited with dep across window"
3277 self.config.set('zuul', 'layout_config',
3278 'tests/fixtures/layout-rate-limit.yaml')
3279 self.sched.reconfigure(self.config)
3280 self.worker.hold_jobs_in_build = True
3281 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3282 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3283 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3284
3285 C.setDependsOn(B, 1)
3286 self.worker.addFailTest('project-test1', A)
3287
3288 A.addApproval('CRVW', 2)
3289 B.addApproval('CRVW', 2)
3290 C.addApproval('CRVW', 2)
3291
3292 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3293 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3294 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3295 self.waitUntilSettled()
3296
3297 # Only A and B will have their merge jobs queued because
3298 # window is 2.
3299 self.assertEqual(len(self.builds), 2)
3300 self.assertEqual(self.builds[0].name, 'project-merge')
3301 self.assertEqual(self.builds[1].name, 'project-merge')
3302
3303 self.worker.release('.*-merge')
3304 self.waitUntilSettled()
3305 self.worker.release('.*-merge')
3306 self.waitUntilSettled()
3307
3308 # Only A and B will have their test jobs queued because
3309 # window is 2.
3310 self.assertEqual(len(self.builds), 4)
3311 self.assertEqual(self.builds[0].name, 'project-test1')
3312 self.assertEqual(self.builds[1].name, 'project-test2')
3313 self.assertEqual(self.builds[2].name, 'project-test1')
3314 self.assertEqual(self.builds[3].name, 'project-test2')
3315
3316 self.worker.release('project-.*')
3317 self.waitUntilSettled()
3318
3319 queue = self.sched.layout.pipelines['gate'].queues[0]
3320 # A failed so window is reduced by 1 to 1.
3321 self.assertEqual(queue.window, 1)
3322 self.assertEqual(queue.window_floor, 1)
3323 self.assertEqual(A.data['status'], 'NEW')
3324
3325 # Gate is reset and only B's merge job is queued because
3326 # window shrunk to 1.
3327 self.assertEqual(len(self.builds), 1)
3328 self.assertEqual(self.builds[0].name, 'project-merge')
3329
3330 self.worker.release('.*-merge')
3331 self.waitUntilSettled()
3332
3333 # Only B's test jobs are queued because window is still 1.
3334 self.assertEqual(len(self.builds), 2)
3335 self.assertEqual(self.builds[0].name, 'project-test1')
3336 self.assertEqual(self.builds[1].name, 'project-test2')
3337
3338 self.worker.release('project-.*')
3339 self.waitUntilSettled()
3340
3341 # B was successfully merged so window is increased to 2.
3342 self.assertEqual(queue.window, 2)
3343 self.assertEqual(queue.window_floor, 1)
3344 self.assertEqual(B.data['status'], 'MERGED')
3345
3346 # Only C is left and its merge job is queued.
3347 self.assertEqual(len(self.builds), 1)
3348 self.assertEqual(self.builds[0].name, 'project-merge')
3349
3350 self.worker.release('.*-merge')
3351 self.waitUntilSettled()
3352
3353 # After successful merge job the test jobs for C are queued.
3354 self.assertEqual(len(self.builds), 2)
3355 self.assertEqual(self.builds[0].name, 'project-test1')
3356 self.assertEqual(self.builds[1].name, 'project-test2')
3357
3358 self.worker.release('project-.*')
3359 self.waitUntilSettled()
3360
3361 # C successfully merged so window is bumped to 3.
3362 self.assertEqual(queue.window, 3)
3363 self.assertEqual(queue.window_floor, 1)
3364 self.assertEqual(C.data['status'], 'MERGED')
3365
3366 def test_queue_rate_limiting_dependent(self):
3367 "Test that DependentPipelines are rate limited with dep in window"
3368 self.config.set('zuul', 'layout_config',
3369 'tests/fixtures/layout-rate-limit.yaml')
3370 self.sched.reconfigure(self.config)
3371 self.worker.hold_jobs_in_build = True
3372 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3373 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3374 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3375
3376 B.setDependsOn(A, 1)
3377
3378 self.worker.addFailTest('project-test1', A)
3379
3380 A.addApproval('CRVW', 2)
3381 B.addApproval('CRVW', 2)
3382 C.addApproval('CRVW', 2)
3383
3384 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3385 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3386 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3387 self.waitUntilSettled()
3388
3389 # Only A and B will have their merge jobs queued because
3390 # window is 2.
3391 self.assertEqual(len(self.builds), 2)
3392 self.assertEqual(self.builds[0].name, 'project-merge')
3393 self.assertEqual(self.builds[1].name, 'project-merge')
3394
3395 self.worker.release('.*-merge')
3396 self.waitUntilSettled()
3397 self.worker.release('.*-merge')
3398 self.waitUntilSettled()
3399
3400 # Only A and B will have their test jobs queued because
3401 # window is 2.
3402 self.assertEqual(len(self.builds), 4)
3403 self.assertEqual(self.builds[0].name, 'project-test1')
3404 self.assertEqual(self.builds[1].name, 'project-test2')
3405 self.assertEqual(self.builds[2].name, 'project-test1')
3406 self.assertEqual(self.builds[3].name, 'project-test2')
3407
3408 self.worker.release('project-.*')
3409 self.waitUntilSettled()
3410
3411 queue = self.sched.layout.pipelines['gate'].queues[0]
3412 # A failed so window is reduced by 1 to 1.
3413 self.assertEqual(queue.window, 1)
3414 self.assertEqual(queue.window_floor, 1)
3415 self.assertEqual(A.data['status'], 'NEW')
3416 self.assertEqual(B.data['status'], 'NEW')
3417
3418 # Gate is reset and only C's merge job is queued because
3419 # window shrunk to 1 and A and B were dequeued.
3420 self.assertEqual(len(self.builds), 1)
3421 self.assertEqual(self.builds[0].name, 'project-merge')
3422
3423 self.worker.release('.*-merge')
3424 self.waitUntilSettled()
3425
3426 # Only C's test jobs are queued because window is still 1.
3427 self.assertEqual(len(self.builds), 2)
3428 self.assertEqual(self.builds[0].name, 'project-test1')
3429 self.assertEqual(self.builds[1].name, 'project-test2')
3430
3431 self.worker.release('project-.*')
3432 self.waitUntilSettled()
3433
3434 # C was successfully merged so window is increased to 2.
3435 self.assertEqual(queue.window, 2)
3436 self.assertEqual(queue.window_floor, 1)
3437 self.assertEqual(C.data['status'], 'MERGED')
Joshua Heskethba8776a2014-01-12 14:35:40 +08003438
3439 def test_worker_update_metadata(self):
3440 "Test if a worker can send back metadata about itself"
3441 self.worker.hold_jobs_in_build = True
3442
3443 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3444 A.addApproval('CRVW', 2)
3445 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3446 self.waitUntilSettled()
3447
3448 self.assertEqual(len(self.launcher.builds), 1)
3449
3450 self.log.debug('Current builds:')
3451 self.log.debug(self.launcher.builds)
3452
3453 start = time.time()
3454 while True:
3455 if time.time() - start > 10:
3456 raise Exception("Timeout waiting for gearman server to report "
3457 + "back to the client")
3458 build = self.launcher.builds.values()[0]
3459 if build.worker.name == "My Worker":
3460 break
3461 else:
3462 time.sleep(0)
3463
3464 self.log.debug(build)
3465 self.assertEqual("My Worker", build.worker.name)
3466 self.assertEqual("localhost", build.worker.hostname)
3467 self.assertEqual(['127.0.0.1', '192.168.1.1'], build.worker.ips)
3468 self.assertEqual("zuul.example.org", build.worker.fqdn)
3469 self.assertEqual("FakeBuilder", build.worker.program)
3470 self.assertEqual("v1.1", build.worker.version)
3471 self.assertEqual({'something': 'else'}, build.worker.extra)
3472
3473 self.worker.hold_jobs_in_build = False
3474 self.worker.release()
3475 self.waitUntilSettled()
Joshua Hesketh3979e3e2014-03-04 11:21:10 +11003476
3477 def test_footer_message(self):
3478 "Test a pipeline's footer message is correctly added to the report."
3479 self.config.set('zuul', 'layout_config',
3480 'tests/fixtures/layout-footer-message.yaml')
3481 self.sched.reconfigure(self.config)
3482 self.registerJobs()
3483
3484 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3485 A.addApproval('CRVW', 2)
3486 self.worker.addFailTest('test1', A)
3487 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3488 self.waitUntilSettled()
3489
3490 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3491 B.addApproval('CRVW', 2)
3492 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3493 self.waitUntilSettled()
3494
3495 self.assertEqual(2, len(self.smtp_messages))
3496
3497 failure_body = """\
3498Build failed. For information on how to proceed, see \
3499http://wiki.example.org/Test_Failures
3500
3501- test1 http://logs.example.com/1/1/gate/test1/0 : FAILURE in 0s
3502- test2 http://logs.example.com/1/1/gate/test2/1 : SUCCESS in 0s
3503
3504For CI problems and help debugging, contact ci@example.org"""
3505
3506 success_body = """\
3507Build succeeded.
3508
3509- test1 http://logs.example.com/2/1/gate/test1/2 : SUCCESS in 0s
3510- test2 http://logs.example.com/2/1/gate/test2/3 : SUCCESS in 0s
3511
3512For CI problems and help debugging, contact ci@example.org"""
3513
3514 self.assertEqual(failure_body, self.smtp_messages[0]['body'])
3515 self.assertEqual(success_body, self.smtp_messages[1]['body'])
Joshua Heskethb7179772014-01-30 23:30:46 +11003516
3517 def test_merge_failure_reporters(self):
3518 """Check that the config is set up correctly"""
3519
3520 self.config.set('zuul', 'layout_config',
3521 'tests/fixtures/layout-merge-failure.yaml')
3522 self.sched.reconfigure(self.config)
3523 self.registerJobs()
3524
3525 self.assertEqual(
Jeremy Stanley1c2c3c22015-06-15 21:23:19 +00003526 "Merge Failed.\n\nThis change or one of its cross-repo "
3527 "dependencies was unable to be automatically merged with the "
3528 "current state of its repository. Please rebase the change and "
3529 "upload a new patchset.",
Joshua Heskethb7179772014-01-30 23:30:46 +11003530 self.sched.layout.pipelines['check'].merge_failure_message)
3531 self.assertEqual(
3532 "The merge failed! For more information...",
3533 self.sched.layout.pipelines['gate'].merge_failure_message)
3534
3535 self.assertEqual(
3536 len(self.sched.layout.pipelines['check'].merge_failure_actions), 1)
3537 self.assertEqual(
3538 len(self.sched.layout.pipelines['gate'].merge_failure_actions), 2)
3539
3540 self.assertTrue(isinstance(
Joshua Heskethde958652015-11-10 19:19:50 +11003541 self.sched.layout.pipelines['check'].merge_failure_actions[0],
3542 zuul.reporter.gerrit.GerritReporter))
Joshua Heskethb7179772014-01-30 23:30:46 +11003543
3544 self.assertTrue(
3545 (
3546 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003547 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003548 zuul.reporter.smtp.SMTPReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003549 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003550 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003551 zuul.reporter.gerrit.GerritReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003552 ) or (
3553 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003554 merge_failure_actions[0],
Joshua Heskethffe42062014-09-05 21:43:52 +10003555 zuul.reporter.gerrit.GerritReporter) and
Joshua Heskethb7179772014-01-30 23:30:46 +11003556 isinstance(self.sched.layout.pipelines['gate'].
Joshua Heskethde958652015-11-10 19:19:50 +11003557 merge_failure_actions[1],
Joshua Heskethffe42062014-09-05 21:43:52 +10003558 zuul.reporter.smtp.SMTPReporter)
Joshua Heskethb7179772014-01-30 23:30:46 +11003559 )
3560 )
3561
3562 def test_merge_failure_reports(self):
3563 """Check that when a change fails to merge the correct message is sent
3564 to the correct reporter"""
3565 self.config.set('zuul', 'layout_config',
3566 'tests/fixtures/layout-merge-failure.yaml')
3567 self.sched.reconfigure(self.config)
3568 self.registerJobs()
3569
3570 # Check a test failure isn't reported to SMTP
3571 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3572 A.addApproval('CRVW', 2)
3573 self.worker.addFailTest('project-test1', A)
3574 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3575 self.waitUntilSettled()
3576
3577 self.assertEqual(3, len(self.history)) # 3 jobs
3578 self.assertEqual(0, len(self.smtp_messages))
3579
3580 # Check a merge failure is reported to SMTP
3581 # B should be merged, but C will conflict with B
3582 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3583 B.addPatchset(['conflict'])
3584 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
3585 C.addPatchset(['conflict'])
3586 B.addApproval('CRVW', 2)
3587 C.addApproval('CRVW', 2)
3588 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3589 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
3590 self.waitUntilSettled()
3591
3592 self.assertEqual(6, len(self.history)) # A and B jobs
3593 self.assertEqual(1, len(self.smtp_messages))
3594 self.assertEqual('The merge failed! For more information...',
3595 self.smtp_messages[0]['body'])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003596
James E. Blairf760f0e2016-02-09 08:44:52 -08003597 def test_default_merge_failure_reports(self):
3598 """Check that the default merge failure reports are correct."""
3599
3600 # A should report success, B should report merge failure.
3601 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3602 A.addPatchset(['conflict'])
3603 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3604 B.addPatchset(['conflict'])
3605 A.addApproval('CRVW', 2)
3606 B.addApproval('CRVW', 2)
3607 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3608 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3609 self.waitUntilSettled()
3610
3611 self.assertEqual(3, len(self.history)) # A jobs
3612 self.assertEqual(A.reported, 2)
3613 self.assertEqual(B.reported, 2)
3614 self.assertEqual(A.data['status'], 'MERGED')
3615 self.assertEqual(B.data['status'], 'NEW')
3616 self.assertIn('Build succeeded', A.messages[1])
3617 self.assertIn('Merge Failed', B.messages[1])
3618 self.assertIn('automatically merged', B.messages[1])
3619 self.assertNotIn('logs.example.com', B.messages[1])
3620 self.assertNotIn('SKIPPED', B.messages[1])
3621
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003622 def test_swift_instructions(self):
3623 "Test that the correct swift instructions are sent to the workers"
3624 self.config.set('zuul', 'layout_config',
3625 'tests/fixtures/layout-swift.yaml')
3626 self.sched.reconfigure(self.config)
3627 self.registerJobs()
3628
3629 self.worker.hold_jobs_in_build = True
3630 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3631
3632 A.addApproval('CRVW', 2)
3633 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3634 self.waitUntilSettled()
3635
3636 self.assertEqual(
3637 "https://storage.example.org/V1/AUTH_account/merge_logs/1/1/1/"
3638 "gate/test-merge/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003639 self.builds[0].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003640 self.assertEqual(5,
3641 len(self.builds[0].parameters['SWIFT_logs_HMAC_BODY'].
3642 split('\n')))
3643 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[0].parameters)
3644
3645 self.assertEqual(
3646 "https://storage.example.org/V1/AUTH_account/logs/1/1/1/"
3647 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003648 self.builds[1].parameters['SWIFT_logs_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003649 self.assertEqual(5,
3650 len(self.builds[1].parameters['SWIFT_logs_HMAC_BODY'].
3651 split('\n')))
3652 self.assertIn('SWIFT_logs_SIGNATURE', self.builds[1].parameters)
3653
3654 self.assertEqual(
3655 "https://storage.example.org/V1/AUTH_account/stash/1/1/1/"
3656 "gate/test-test/",
Joshua Hesketh76dee532014-07-03 15:39:13 +10003657 self.builds[1].parameters['SWIFT_MOSTLY_URL'][:-7])
Joshua Hesketh36c3fa52014-01-22 11:40:52 +11003658 self.assertEqual(5,
3659 len(self.builds[1].
3660 parameters['SWIFT_MOSTLY_HMAC_BODY'].split('\n')))
3661 self.assertIn('SWIFT_MOSTLY_SIGNATURE', self.builds[1].parameters)
3662
3663 self.worker.hold_jobs_in_build = False
3664 self.worker.release()
3665 self.waitUntilSettled()
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003666
3667 def test_client_get_running_jobs(self):
3668 "Test that the RPC client can get a list of running jobs"
3669 self.worker.hold_jobs_in_build = True
3670 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3671 A.addApproval('CRVW', 2)
3672 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3673 self.waitUntilSettled()
3674
3675 client = zuul.rpcclient.RPCClient('127.0.0.1',
3676 self.gearman_server.port)
3677
3678 # Wait for gearman server to send the initial workData back to zuul
3679 start = time.time()
3680 while True:
3681 if time.time() - start > 10:
3682 raise Exception("Timeout waiting for gearman server to report "
3683 + "back to the client")
3684 build = self.launcher.builds.values()[0]
3685 if build.worker.name == "My Worker":
3686 break
3687 else:
3688 time.sleep(0)
3689
3690 running_items = client.get_running_jobs()
3691
3692 self.assertEqual(1, len(running_items))
3693 running_item = running_items[0]
3694 self.assertEqual([], running_item['failing_reasons'])
3695 self.assertEqual([], running_item['items_behind'])
3696 self.assertEqual('https://hostname/1', running_item['url'])
3697 self.assertEqual(None, running_item['item_ahead'])
3698 self.assertEqual('org/project', running_item['project'])
3699 self.assertEqual(None, running_item['remaining_time'])
3700 self.assertEqual(True, running_item['active'])
3701 self.assertEqual('1,1', running_item['id'])
3702
3703 self.assertEqual(3, len(running_item['jobs']))
3704 for job in running_item['jobs']:
3705 if job['name'] == 'project-merge':
3706 self.assertEqual('project-merge', job['name'])
3707 self.assertEqual('gate', job['pipeline'])
3708 self.assertEqual(False, job['retry'])
Joshua Hesketh85af4e92014-02-21 08:28:58 -08003709 self.assertEqual('https://server/job/project-merge/0/',
3710 job['url'])
3711 self.assertEqual(7, len(job['worker']))
3712 self.assertEqual(False, job['canceled'])
3713 self.assertEqual(True, job['voting'])
3714 self.assertEqual(None, job['result'])
3715 self.assertEqual('gate', job['pipeline'])
3716 break
3717
3718 self.worker.hold_jobs_in_build = False
3719 self.worker.release()
3720 self.waitUntilSettled()
3721
3722 running_items = client.get_running_jobs()
3723 self.assertEqual(0, len(running_items))
James E. Blairbadc1ad2014-04-28 13:55:14 -07003724
3725 def test_nonvoting_pipeline(self):
3726 "Test that a nonvoting pipeline (experimental) can still report"
3727
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003728 A = self.fake_gerrit.addFakeChange('org/experimental-project',
3729 'master', 'A')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003730 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
3731 self.waitUntilSettled()
Joshua Heskethcc017ea2014-04-30 19:55:25 +10003732 self.assertEqual(
3733 self.getJobFromHistory('experimental-project-test').result,
3734 'SUCCESS')
James E. Blairbadc1ad2014-04-28 13:55:14 -07003735 self.assertEqual(A.reported, 1)
James E. Blair5ee24252014-12-30 10:12:29 -08003736
3737 def test_crd_gate(self):
3738 "Test cross-repo dependencies"
3739 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3740 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3741 A.addApproval('CRVW', 2)
3742 B.addApproval('CRVW', 2)
3743
3744 AM2 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM2')
3745 AM1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'AM1')
3746 AM2.setMerged()
3747 AM1.setMerged()
3748
3749 BM2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM2')
3750 BM1 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'BM1')
3751 BM2.setMerged()
3752 BM1.setMerged()
3753
3754 # A -> AM1 -> AM2
3755 # B -> BM1 -> BM2
3756 # A Depends-On: B
3757 # M2 is here to make sure it is never queried. If it is, it
3758 # means zuul is walking down the entire history of merged
3759 # changes.
3760
3761 B.setDependsOn(BM1, 1)
3762 BM1.setDependsOn(BM2, 1)
3763
3764 A.setDependsOn(AM1, 1)
3765 AM1.setDependsOn(AM2, 1)
3766
3767 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3768 A.subject, B.data['id'])
3769
3770 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3771 self.waitUntilSettled()
3772
3773 self.assertEqual(A.data['status'], 'NEW')
3774 self.assertEqual(B.data['status'], 'NEW')
3775
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11003776 for connection in self.connections.values():
3777 connection.maintainCache([])
James E. Blair5ee24252014-12-30 10:12:29 -08003778
3779 self.worker.hold_jobs_in_build = True
3780 B.addApproval('APRV', 1)
3781 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3782 self.waitUntilSettled()
3783
3784 self.worker.release('.*-merge')
3785 self.waitUntilSettled()
3786 self.worker.release('.*-merge')
3787 self.waitUntilSettled()
3788 self.worker.hold_jobs_in_build = False
3789 self.worker.release()
3790 self.waitUntilSettled()
3791
3792 self.assertEqual(AM2.queried, 0)
3793 self.assertEqual(BM2.queried, 0)
3794 self.assertEqual(A.data['status'], 'MERGED')
3795 self.assertEqual(B.data['status'], 'MERGED')
3796 self.assertEqual(A.reported, 2)
3797 self.assertEqual(B.reported, 2)
3798
James E. Blair8f78d882015-02-05 08:51:37 -08003799 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3800 '2,1 1,1')
3801
3802 def test_crd_branch(self):
3803 "Test cross-repo dependencies in multiple branches"
3804 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3805 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3806 C = self.fake_gerrit.addFakeChange('org/project2', 'mp', 'C')
3807 C.data['id'] = B.data['id']
3808 A.addApproval('CRVW', 2)
3809 B.addApproval('CRVW', 2)
3810 C.addApproval('CRVW', 2)
3811
3812 # A Depends-On: B+C
3813 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3814 A.subject, B.data['id'])
3815
3816 self.worker.hold_jobs_in_build = True
3817 B.addApproval('APRV', 1)
3818 C.addApproval('APRV', 1)
3819 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3820 self.waitUntilSettled()
3821
3822 self.worker.release('.*-merge')
3823 self.waitUntilSettled()
3824 self.worker.release('.*-merge')
3825 self.waitUntilSettled()
3826 self.worker.release('.*-merge')
3827 self.waitUntilSettled()
3828 self.worker.hold_jobs_in_build = False
3829 self.worker.release()
3830 self.waitUntilSettled()
3831
3832 self.assertEqual(A.data['status'], 'MERGED')
3833 self.assertEqual(B.data['status'], 'MERGED')
3834 self.assertEqual(C.data['status'], 'MERGED')
3835 self.assertEqual(A.reported, 2)
3836 self.assertEqual(B.reported, 2)
3837 self.assertEqual(C.reported, 2)
3838
3839 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3840 '2,1 3,1 1,1')
3841
3842 def test_crd_multiline(self):
3843 "Test multiple depends-on lines in commit"
3844 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3845 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3846 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
3847 A.addApproval('CRVW', 2)
3848 B.addApproval('CRVW', 2)
3849 C.addApproval('CRVW', 2)
3850
3851 # A Depends-On: B+C
3852 A.data['commitMessage'] = '%s\n\nDepends-On: %s\nDepends-On: %s\n' % (
3853 A.subject, B.data['id'], C.data['id'])
3854
3855 self.worker.hold_jobs_in_build = True
3856 B.addApproval('APRV', 1)
3857 C.addApproval('APRV', 1)
3858 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3859 self.waitUntilSettled()
3860
3861 self.worker.release('.*-merge')
3862 self.waitUntilSettled()
3863 self.worker.release('.*-merge')
3864 self.waitUntilSettled()
3865 self.worker.release('.*-merge')
3866 self.waitUntilSettled()
3867 self.worker.hold_jobs_in_build = False
3868 self.worker.release()
3869 self.waitUntilSettled()
3870
3871 self.assertEqual(A.data['status'], 'MERGED')
3872 self.assertEqual(B.data['status'], 'MERGED')
3873 self.assertEqual(C.data['status'], 'MERGED')
3874 self.assertEqual(A.reported, 2)
3875 self.assertEqual(B.reported, 2)
3876 self.assertEqual(C.reported, 2)
3877
3878 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3879 '2,1 3,1 1,1')
James E. Blair5ee24252014-12-30 10:12:29 -08003880
3881 def test_crd_unshared_gate(self):
3882 "Test cross-repo dependencies in unshared gate queues"
3883 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3884 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
3885 A.addApproval('CRVW', 2)
3886 B.addApproval('CRVW', 2)
3887
3888 # A Depends-On: B
3889 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3890 A.subject, B.data['id'])
3891
3892 # A and B do not share a queue, make sure that A is unable to
3893 # enqueue B (and therefore, A is unable to be enqueued).
3894 B.addApproval('APRV', 1)
3895 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3896 self.waitUntilSettled()
3897
3898 self.assertEqual(A.data['status'], 'NEW')
3899 self.assertEqual(B.data['status'], 'NEW')
3900 self.assertEqual(A.reported, 0)
3901 self.assertEqual(B.reported, 0)
3902 self.assertEqual(len(self.history), 0)
3903
3904 # Enqueue and merge B alone.
3905 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3906 self.waitUntilSettled()
3907
3908 self.assertEqual(B.data['status'], 'MERGED')
3909 self.assertEqual(B.reported, 2)
3910
3911 # Now that B is merged, A should be able to be enqueued and
3912 # merged.
3913 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3914 self.waitUntilSettled()
3915
3916 self.assertEqual(A.data['status'], 'MERGED')
3917 self.assertEqual(A.reported, 2)
3918
James E. Blair96698e22015-04-02 07:48:21 -07003919 def test_crd_gate_reverse(self):
3920 "Test reverse cross-repo dependencies"
3921 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3922 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3923 A.addApproval('CRVW', 2)
3924 B.addApproval('CRVW', 2)
3925
3926 # A Depends-On: B
3927
3928 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3929 A.subject, B.data['id'])
3930
3931 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3932 self.waitUntilSettled()
3933
3934 self.assertEqual(A.data['status'], 'NEW')
3935 self.assertEqual(B.data['status'], 'NEW')
3936
3937 self.worker.hold_jobs_in_build = True
3938 A.addApproval('APRV', 1)
3939 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
3940 self.waitUntilSettled()
3941
3942 self.worker.release('.*-merge')
3943 self.waitUntilSettled()
3944 self.worker.release('.*-merge')
3945 self.waitUntilSettled()
3946 self.worker.hold_jobs_in_build = False
3947 self.worker.release()
3948 self.waitUntilSettled()
3949
3950 self.assertEqual(A.data['status'], 'MERGED')
3951 self.assertEqual(B.data['status'], 'MERGED')
3952 self.assertEqual(A.reported, 2)
3953 self.assertEqual(B.reported, 2)
3954
3955 self.assertEqual(self.getJobFromHistory('project1-merge').changes,
3956 '2,1 1,1')
3957
James E. Blair5ee24252014-12-30 10:12:29 -08003958 def test_crd_cycle(self):
3959 "Test cross-repo dependency cycles"
3960 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
3961 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
3962 A.addApproval('CRVW', 2)
3963 B.addApproval('CRVW', 2)
3964
3965 # A -> B -> A (via commit-depends)
3966
3967 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3968 A.subject, B.data['id'])
3969 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3970 B.subject, A.data['id'])
3971
3972 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3973 self.waitUntilSettled()
3974
3975 self.assertEqual(A.reported, 0)
3976 self.assertEqual(B.reported, 0)
3977 self.assertEqual(A.data['status'], 'NEW')
3978 self.assertEqual(B.data['status'], 'NEW')
James E. Blairbfb8e042014-12-30 17:01:44 -08003979
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00003980 def test_crd_gate_unknown(self):
3981 "Test unknown projects in dependent pipeline"
3982 self.init_repo("org/unknown")
3983 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
3984 B = self.fake_gerrit.addFakeChange('org/unknown', 'master', 'B')
3985 A.addApproval('CRVW', 2)
3986 B.addApproval('CRVW', 2)
3987
3988 # A Depends-On: B
3989 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
3990 A.subject, B.data['id'])
3991
3992 B.addApproval('APRV', 1)
3993 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
3994 self.waitUntilSettled()
3995
3996 # Unknown projects cannot share a queue with any other
3997 # since they don't have common jobs with any other (they have no jobs).
3998 # Changes which depend on unknown project changes
3999 # should not be processed in dependent pipeline
4000 self.assertEqual(A.data['status'], 'NEW')
4001 self.assertEqual(B.data['status'], 'NEW')
4002 self.assertEqual(A.reported, 0)
4003 self.assertEqual(B.reported, 0)
4004 self.assertEqual(len(self.history), 0)
4005
4006 # Simulate change B being gated outside this layout
4007 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
4008 B.setMerged()
4009 self.waitUntilSettled()
4010 self.assertEqual(len(self.history), 0)
4011
4012 # Now that B is merged, A should be able to be enqueued and
4013 # merged.
4014 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
4015 self.waitUntilSettled()
4016
4017 self.assertEqual(A.data['status'], 'MERGED')
4018 self.assertEqual(A.reported, 2)
4019 self.assertEqual(B.data['status'], 'MERGED')
4020 self.assertEqual(B.reported, 0)
4021
James E. Blairbfb8e042014-12-30 17:01:44 -08004022 def test_crd_check(self):
4023 "Test cross-repo dependencies in independent pipelines"
4024
4025 self.gearman_server.hold_jobs_in_queue = True
4026 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4027 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4028
4029 # A Depends-On: B
4030 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4031 A.subject, B.data['id'])
4032
4033 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4034 self.waitUntilSettled()
4035
4036 queue = self.gearman_server.getQueue()
4037 ref = self.getParameter(queue[-1], 'ZUUL_REF')
4038 self.gearman_server.hold_jobs_in_queue = False
4039 self.gearman_server.release()
4040 self.waitUntilSettled()
4041
4042 path = os.path.join(self.git_root, "org/project1")
4043 repo = git.Repo(path)
4044 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4045 repo_messages.reverse()
4046 correct_messages = ['initial commit', 'A-1']
4047 self.assertEqual(repo_messages, correct_messages)
4048
4049 path = os.path.join(self.git_root, "org/project2")
4050 repo = git.Repo(path)
4051 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
4052 repo_messages.reverse()
4053 correct_messages = ['initial commit', 'B-1']
4054 self.assertEqual(repo_messages, correct_messages)
4055
4056 self.assertEqual(A.data['status'], 'NEW')
4057 self.assertEqual(B.data['status'], 'NEW')
4058 self.assertEqual(A.reported, 1)
4059 self.assertEqual(B.reported, 0)
4060
4061 self.assertEqual(self.history[0].changes, '2,1 1,1')
4062 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair8f78d882015-02-05 08:51:37 -08004063
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004064 def test_crd_check_git_depends(self):
4065 "Test single-repo dependencies in independent pipelines"
James E. Blairb8c16472015-05-05 14:55:26 -07004066 self.gearman_server.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004067 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4068 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4069
4070 # Add two git-dependent changes and make sure they both report
4071 # success.
4072 B.setDependsOn(A, 1)
4073 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4074 self.waitUntilSettled()
4075 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4076 self.waitUntilSettled()
4077
James E. Blairb8c16472015-05-05 14:55:26 -07004078 self.orderedRelease()
4079 self.gearman_server.hold_jobs_in_build = False
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004080 self.waitUntilSettled()
4081
4082 self.assertEqual(A.data['status'], 'NEW')
4083 self.assertEqual(B.data['status'], 'NEW')
4084 self.assertEqual(A.reported, 1)
4085 self.assertEqual(B.reported, 1)
4086
4087 self.assertEqual(self.history[0].changes, '1,1')
4088 self.assertEqual(self.history[-1].changes, '1,1 2,1')
4089 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4090
4091 self.assertIn('Build succeeded', A.messages[0])
4092 self.assertIn('Build succeeded', B.messages[0])
4093
4094 def test_crd_check_duplicate(self):
4095 "Test duplicate check in independent pipelines"
James E. Blair1e263032015-05-07 14:35:34 -07004096 self.worker.hold_jobs_in_build = True
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004097 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4098 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4099 check_pipeline = self.sched.layout.pipelines['check']
4100
4101 # Add two git-dependent changes...
4102 B.setDependsOn(A, 1)
4103 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4104 self.waitUntilSettled()
4105 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4106
4107 # ...make sure the live one is not duplicated...
4108 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4109 self.waitUntilSettled()
4110 self.assertEqual(len(check_pipeline.getAllItems()), 2)
4111
4112 # ...but the non-live one is able to be.
4113 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4114 self.waitUntilSettled()
4115 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4116
Clark Boylandd849822015-03-02 12:38:14 -08004117 # Release jobs in order to avoid races with change A jobs
4118 # finishing before change B jobs.
James E. Blaird7650852015-05-07 15:47:37 -07004119 self.orderedRelease()
James E. Blair1e263032015-05-07 14:35:34 -07004120 self.worker.hold_jobs_in_build = False
4121 self.worker.release()
James E. Blairdbfe1cd2015-02-07 11:41:19 -08004122 self.waitUntilSettled()
4123
4124 self.assertEqual(A.data['status'], 'NEW')
4125 self.assertEqual(B.data['status'], 'NEW')
4126 self.assertEqual(A.reported, 1)
4127 self.assertEqual(B.reported, 1)
4128
4129 self.assertEqual(self.history[0].changes, '1,1 2,1')
4130 self.assertEqual(self.history[1].changes, '1,1')
4131 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
4132
4133 self.assertIn('Build succeeded', A.messages[0])
4134 self.assertIn('Build succeeded', B.messages[0])
4135
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004136 def _test_crd_check_reconfiguration(self, project1, project2):
James E. Blair8f78d882015-02-05 08:51:37 -08004137 "Test cross-repo dependencies re-enqueued in independent pipelines"
4138
4139 self.gearman_server.hold_jobs_in_queue = True
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004140 A = self.fake_gerrit.addFakeChange(project1, 'master', 'A')
4141 B = self.fake_gerrit.addFakeChange(project2, 'master', 'B')
James E. Blair8f78d882015-02-05 08:51:37 -08004142
4143 # A Depends-On: B
4144 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4145 A.subject, B.data['id'])
4146
4147 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4148 self.waitUntilSettled()
4149
4150 self.sched.reconfigure(self.config)
4151
4152 # Make sure the items still share a change queue, and the
4153 # first one is not live.
4154 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 1)
4155 queue = self.sched.layout.pipelines['check'].queues[0]
4156 first_item = queue.queue[0]
4157 for item in queue.queue:
4158 self.assertEqual(item.queue, first_item.queue)
4159 self.assertFalse(first_item.live)
4160 self.assertTrue(queue.queue[1].live)
4161
4162 self.gearman_server.hold_jobs_in_queue = False
4163 self.gearman_server.release()
4164 self.waitUntilSettled()
4165
4166 self.assertEqual(A.data['status'], 'NEW')
4167 self.assertEqual(B.data['status'], 'NEW')
4168 self.assertEqual(A.reported, 1)
4169 self.assertEqual(B.reported, 0)
4170
4171 self.assertEqual(self.history[0].changes, '2,1 1,1')
4172 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
James E. Blair17dd6772015-02-09 14:45:18 -08004173
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00004174 def test_crd_check_reconfiguration(self):
4175 self._test_crd_check_reconfiguration('org/project1', 'org/project2')
4176
4177 def test_crd_undefined_project(self):
4178 """Test that undefined projects in dependencies are handled for
4179 independent pipelines"""
4180 # It's a hack for fake gerrit,
4181 # as it implies repo creation upon the creation of any change
4182 self.init_repo("org/unknown")
4183 self._test_crd_check_reconfiguration('org/project1', 'org/unknown')
4184
James E. Blair17dd6772015-02-09 14:45:18 -08004185 def test_crd_check_ignore_dependencies(self):
4186 "Test cross-repo dependencies can be ignored"
4187 self.config.set('zuul', 'layout_config',
4188 'tests/fixtures/layout-ignore-dependencies.yaml')
4189 self.sched.reconfigure(self.config)
4190 self.registerJobs()
4191
4192 self.gearman_server.hold_jobs_in_queue = True
4193 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4194 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4195 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
4196
4197 # A Depends-On: B
4198 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4199 A.subject, B.data['id'])
4200 # C git-depends on B
4201 C.setDependsOn(B, 1)
4202 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4203 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4204 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4205 self.waitUntilSettled()
4206
4207 # Make sure none of the items share a change queue, and all
4208 # are live.
4209 check_pipeline = self.sched.layout.pipelines['check']
4210 self.assertEqual(len(check_pipeline.queues), 3)
4211 self.assertEqual(len(check_pipeline.getAllItems()), 3)
4212 for item in check_pipeline.getAllItems():
4213 self.assertTrue(item.live)
4214
4215 self.gearman_server.hold_jobs_in_queue = False
4216 self.gearman_server.release()
4217 self.waitUntilSettled()
4218
4219 self.assertEqual(A.data['status'], 'NEW')
4220 self.assertEqual(B.data['status'], 'NEW')
4221 self.assertEqual(C.data['status'], 'NEW')
4222 self.assertEqual(A.reported, 1)
4223 self.assertEqual(B.reported, 1)
4224 self.assertEqual(C.reported, 1)
4225
4226 # Each job should have tested exactly one change
4227 for job in self.history:
4228 self.assertEqual(len(job.changes.split()), 1)
James E. Blair96698e22015-04-02 07:48:21 -07004229
4230 def test_crd_check_transitive(self):
4231 "Test transitive cross-repo dependencies"
4232 # Specifically, if A -> B -> C, and C gets a new patchset and
4233 # A gets a new patchset, ensure the test of A,2 includes B,1
4234 # and C,2 (not C,1 which would indicate stale data in the
4235 # cache for B).
4236 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
4237 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
4238 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
4239
4240 # A Depends-On: B
4241 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4242 A.subject, B.data['id'])
4243
4244 # B Depends-On: C
4245 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4246 B.subject, C.data['id'])
4247
4248 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4249 self.waitUntilSettled()
4250 self.assertEqual(self.history[-1].changes, '3,1 2,1 1,1')
4251
4252 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4253 self.waitUntilSettled()
4254 self.assertEqual(self.history[-1].changes, '3,1 2,1')
4255
4256 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4257 self.waitUntilSettled()
4258 self.assertEqual(self.history[-1].changes, '3,1')
4259
4260 C.addPatchset()
4261 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(2))
4262 self.waitUntilSettled()
4263 self.assertEqual(self.history[-1].changes, '3,2')
4264
4265 A.addPatchset()
4266 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
4267 self.waitUntilSettled()
4268 self.assertEqual(self.history[-1].changes, '3,2 2,1 1,2')
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004269
James E. Blair92464a22016-04-05 10:21:26 -07004270 def test_crd_cycle_join(self):
4271 "Test an updated change creates a cycle"
4272 A = self.fake_gerrit.addFakeChange('org/project2', 'master', 'A')
4273
4274 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4275 self.waitUntilSettled()
4276
4277 # Create B->A
4278 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
4279 B.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4280 B.subject, A.data['id'])
4281 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4282 self.waitUntilSettled()
4283
4284 # Update A to add A->B (a cycle).
4285 A.addPatchset()
4286 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
4287 A.subject, B.data['id'])
4288 # Normally we would submit the patchset-created event for
4289 # processing here, however, we have no way of noting whether
4290 # the dependency cycle detection correctly raised an
4291 # exception, so instead, we reach into the source driver and
4292 # call the method that would ultimately be called by the event
4293 # processing.
4294
4295 source = self.sched.layout.pipelines['gate'].source
4296 with testtools.ExpectedException(
4297 Exception, "Dependency cycle detected"):
4298 source._getChange(u'1', u'2', True)
4299 self.log.debug("Got expected dependency cycle exception")
4300
4301 # Now if we update B to remove the depends-on, everything
4302 # should be okay. B; A->B
4303
4304 B.addPatchset()
4305 B.data['commitMessage'] = '%s\n' % (B.subject,)
4306 source._getChange(u'1', u'2', True)
4307 source._getChange(u'2', u'2', True)
4308
Joshua Hesketh89e829d2015-02-10 16:29:45 +11004309 def test_disable_at(self):
4310 "Test a pipeline will only report to the disabled trigger when failing"
4311
4312 self.config.set('zuul', 'layout_config',
4313 'tests/fixtures/layout-disable-at.yaml')
4314 self.sched.reconfigure(self.config)
4315
4316 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4317 self.assertEqual(
4318 0, self.sched.layout.pipelines['check']._consecutive_failures)
4319 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4320
4321 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
4322 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
4323 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
4324 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
4325 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
4326 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
4327 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
4328 H = self.fake_gerrit.addFakeChange('org/project', 'master', 'H')
4329 I = self.fake_gerrit.addFakeChange('org/project', 'master', 'I')
4330 J = self.fake_gerrit.addFakeChange('org/project', 'master', 'J')
4331 K = self.fake_gerrit.addFakeChange('org/project', 'master', 'K')
4332
4333 self.worker.addFailTest('project-test1', A)
4334 self.worker.addFailTest('project-test1', B)
4335 # Let C pass, resetting the counter
4336 self.worker.addFailTest('project-test1', D)
4337 self.worker.addFailTest('project-test1', E)
4338 self.worker.addFailTest('project-test1', F)
4339 self.worker.addFailTest('project-test1', G)
4340 self.worker.addFailTest('project-test1', H)
4341 # I also passes but should only report to the disabled reporters
4342 self.worker.addFailTest('project-test1', J)
4343 self.worker.addFailTest('project-test1', K)
4344
4345 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
4346 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
4347 self.waitUntilSettled()
4348
4349 self.assertEqual(
4350 2, self.sched.layout.pipelines['check']._consecutive_failures)
4351 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4352
4353 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
4354 self.waitUntilSettled()
4355
4356 self.assertEqual(
4357 0, self.sched.layout.pipelines['check']._consecutive_failures)
4358 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4359
4360 self.fake_gerrit.addEvent(D.getPatchsetCreatedEvent(1))
4361 self.fake_gerrit.addEvent(E.getPatchsetCreatedEvent(1))
4362 self.fake_gerrit.addEvent(F.getPatchsetCreatedEvent(1))
4363 self.waitUntilSettled()
4364
4365 # We should be disabled now
4366 self.assertEqual(
4367 3, self.sched.layout.pipelines['check']._consecutive_failures)
4368 self.assertTrue(self.sched.layout.pipelines['check']._disabled)
4369
4370 # We need to wait between each of these patches to make sure the
4371 # smtp messages come back in an expected order
4372 self.fake_gerrit.addEvent(G.getPatchsetCreatedEvent(1))
4373 self.waitUntilSettled()
4374 self.fake_gerrit.addEvent(H.getPatchsetCreatedEvent(1))
4375 self.waitUntilSettled()
4376 self.fake_gerrit.addEvent(I.getPatchsetCreatedEvent(1))
4377 self.waitUntilSettled()
4378
4379 # The first 6 (ABCDEF) jobs should have reported back to gerrt thus
4380 # leaving a message on each change
4381 self.assertEqual(1, len(A.messages))
4382 self.assertIn('Build failed.', A.messages[0])
4383 self.assertEqual(1, len(B.messages))
4384 self.assertIn('Build failed.', B.messages[0])
4385 self.assertEqual(1, len(C.messages))
4386 self.assertIn('Build succeeded.', C.messages[0])
4387 self.assertEqual(1, len(D.messages))
4388 self.assertIn('Build failed.', D.messages[0])
4389 self.assertEqual(1, len(E.messages))
4390 self.assertIn('Build failed.', E.messages[0])
4391 self.assertEqual(1, len(F.messages))
4392 self.assertIn('Build failed.', F.messages[0])
4393
4394 # The last 3 (GHI) would have only reported via smtp.
4395 self.assertEqual(3, len(self.smtp_messages))
4396 self.assertEqual(0, len(G.messages))
4397 self.assertIn('Build failed.', self.smtp_messages[0]['body'])
4398 self.assertIn('/7/1/check', self.smtp_messages[0]['body'])
4399 self.assertEqual(0, len(H.messages))
4400 self.assertIn('Build failed.', self.smtp_messages[1]['body'])
4401 self.assertIn('/8/1/check', self.smtp_messages[1]['body'])
4402 self.assertEqual(0, len(I.messages))
4403 self.assertIn('Build succeeded.', self.smtp_messages[2]['body'])
4404 self.assertIn('/9/1/check', self.smtp_messages[2]['body'])
4405
4406 # Now reload the configuration (simulate a HUP) to check the pipeline
4407 # comes out of disabled
4408 self.sched.reconfigure(self.config)
4409
4410 self.assertEqual(3, self.sched.layout.pipelines['check'].disable_at)
4411 self.assertEqual(
4412 0, self.sched.layout.pipelines['check']._consecutive_failures)
4413 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4414
4415 self.fake_gerrit.addEvent(J.getPatchsetCreatedEvent(1))
4416 self.fake_gerrit.addEvent(K.getPatchsetCreatedEvent(1))
4417 self.waitUntilSettled()
4418
4419 self.assertEqual(
4420 2, self.sched.layout.pipelines['check']._consecutive_failures)
4421 self.assertFalse(self.sched.layout.pipelines['check']._disabled)
4422
4423 # J and K went back to gerrit
4424 self.assertEqual(1, len(J.messages))
4425 self.assertIn('Build failed.', J.messages[0])
4426 self.assertEqual(1, len(K.messages))
4427 self.assertIn('Build failed.', K.messages[0])
4428 # No more messages reported via smtp
4429 self.assertEqual(3, len(self.smtp_messages))