blob: 15d33c8aadcc7257dad6cc6d69c0ba51e95f307f [file] [log] [blame]
James E. Blairb0fcae42012-07-17 11:12:10 -07001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
James E. Blairb0fcae42012-07-17 11:12:10 -070017import json
Monty Taylorbc758832013-06-17 17:22:42 -040018import logging
19import os
James E. Blairb0fcae42012-07-17 11:12:10 -070020import re
James E. Blair4886cc12012-07-18 15:39:41 -070021import shutil
Monty Taylorbc758832013-06-17 17:22:42 -040022import time
James E. Blair1843a552013-07-03 14:19:52 -070023import urllib
Monty Taylorbc758832013-06-17 17:22:42 -040024import urllib2
Maru Newby3fe5f852015-01-13 04:22:14 +000025import yaml
Monty Taylorbc758832013-06-17 17:22:42 -040026
James E. Blair4886cc12012-07-18 15:39:41 -070027import git
Monty Taylorbc758832013-06-17 17:22:42 -040028import testtools
James E. Blairb0fcae42012-07-17 11:12:10 -070029
Maru Newby3fe5f852015-01-13 04:22:14 +000030import zuul.change_matcher
James E. Blairb0fcae42012-07-17 11:12:10 -070031import zuul.scheduler
James E. Blairad28e912013-11-27 10:43:22 -080032import zuul.rpcclient
Joshua Hesketh1879cf72013-08-19 14:13:15 +100033import zuul.reporter.gerrit
Joshua Hesketh5fea8672013-08-19 17:32:01 +100034import zuul.reporter.smtp
James E. Blairb0fcae42012-07-17 11:12:10 -070035
Maru Newby3fe5f852015-01-13 04:22:14 +000036from tests.base import (
Maru Newby3fe5f852015-01-13 04:22:14 +000037 ZuulTestCase,
38 repack_repo,
39)
James E. Blairb0fcae42012-07-17 11:12:10 -070040
James E. Blair1f4c2bb2013-04-26 08:40:46 -070041logging.basicConfig(level=logging.DEBUG,
42 format='%(asctime)s %(name)-32s '
43 '%(levelname)-8s %(message)s')
James E. Blairb0fcae42012-07-17 11:12:10 -070044
45
Clark Boylanb640e052014-04-03 16:41:46 -070046class TestScheduler(ZuulTestCase):
Antoine Mussobd86a312014-01-08 14:51:33 +010047
James E. Blairb0fcae42012-07-17 11:12:10 -070048 def test_jobs_launched(self):
49 "Test that jobs are launched and a change is merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -070050
James E. Blairb0fcae42012-07-17 11:12:10 -070051 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair8c803f82012-07-31 16:25:42 -070052 A.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070053 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
54 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -040055 self.assertEqual(self.getJobFromHistory('project-merge').result,
56 'SUCCESS')
57 self.assertEqual(self.getJobFromHistory('project-test1').result,
58 'SUCCESS')
59 self.assertEqual(self.getJobFromHistory('project-test2').result,
60 'SUCCESS')
61 self.assertEqual(A.data['status'], 'MERGED')
62 self.assertEqual(A.reported, 2)
James E. Blairb0fcae42012-07-17 11:12:10 -070063
James E. Blair66eeebf2013-07-27 17:44:32 -070064 self.assertReportedStat('gerrit.event.comment-added', value='1|c')
65 self.assertReportedStat('zuul.pipeline.gate.current_changes',
66 value='1|g')
67 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
68 kind='ms')
69 self.assertReportedStat('zuul.pipeline.gate.job.project-merge.SUCCESS',
70 value='1|c')
71 self.assertReportedStat('zuul.pipeline.gate.resident_time', kind='ms')
72 self.assertReportedStat('zuul.pipeline.gate.total_changes',
73 value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -070074 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -070075 'zuul.pipeline.gate.org.project.resident_time', kind='ms')
James E. Blair412e5582013-04-22 15:50:12 -070076 self.assertReportedStat(
James E. Blair66eeebf2013-07-27 17:44:32 -070077 'zuul.pipeline.gate.org.project.total_changes', value='1|c')
James E. Blair412e5582013-04-22 15:50:12 -070078
James E. Blair5821bd92015-09-16 08:48:15 -070079 for build in self.builds:
80 self.assertEqual(build.parameters['ZUUL_VOTING'], '1')
81
James E. Blair3cb10702013-08-24 08:56:03 -070082 def test_initial_pipeline_gauges(self):
83 "Test that each pipeline reported its length on start"
84 pipeline_names = self.sched.layout.pipelines.keys()
85 self.assertNotEqual(len(pipeline_names), 0)
86 for name in pipeline_names:
87 self.assertReportedStat('zuul.pipeline.%s.current_changes' % name,
88 value='0|g')
89
James E. Blair42f74822013-05-14 15:18:03 -070090 def test_duplicate_pipelines(self):
91 "Test that a change matching multiple pipelines works"
James E. Blair1b4d9722013-05-21 10:32:04 -070092
James E. Blair42f74822013-05-14 15:18:03 -070093 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
94 self.fake_gerrit.addEvent(A.getChangeRestoredEvent())
95 self.waitUntilSettled()
James E. Blair42f74822013-05-14 15:18:03 -070096
Monty Taylor98f0f3e2013-07-06 16:02:31 -040097 self.assertEqual(len(self.history), 2)
Monty Taylor6bef8ef2013-06-02 08:17:12 -040098 self.history[0].name == 'project-test1'
99 self.history[1].name == 'project-test1'
James E. Blair42f74822013-05-14 15:18:03 -0700100
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400101 self.assertEqual(len(A.messages), 2)
James E. Blair42f74822013-05-14 15:18:03 -0700102 if 'dup1/project-test1' in A.messages[0]:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400103 self.assertIn('dup1/project-test1', A.messages[0])
104 self.assertNotIn('dup2/project-test1', A.messages[0])
105 self.assertNotIn('dup1/project-test1', A.messages[1])
106 self.assertIn('dup2/project-test1', A.messages[1])
James E. Blair42f74822013-05-14 15:18:03 -0700107 else:
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400108 self.assertIn('dup1/project-test1', A.messages[1])
109 self.assertNotIn('dup2/project-test1', A.messages[1])
110 self.assertNotIn('dup1/project-test1', A.messages[0])
111 self.assertIn('dup2/project-test1', A.messages[0])
James E. Blair42f74822013-05-14 15:18:03 -0700112
James E. Blairb0fcae42012-07-17 11:12:10 -0700113 def test_parallel_changes(self):
114 "Test that changes are tested in parallel and merged in series"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700115
116 self.worker.hold_jobs_in_build = True
James E. Blairb0fcae42012-07-17 11:12:10 -0700117 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
118 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
119 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700120 A.addApproval('CRVW', 2)
121 B.addApproval('CRVW', 2)
122 C.addApproval('CRVW', 2)
James E. Blairb0fcae42012-07-17 11:12:10 -0700123
124 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
125 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
126 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
127
128 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400129 self.assertEqual(len(self.builds), 1)
130 self.assertEqual(self.builds[0].name, 'project-merge')
131 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700132
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700133 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700134 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400135 self.assertEqual(len(self.builds), 3)
136 self.assertEqual(self.builds[0].name, 'project-test1')
137 self.assertTrue(self.job_has_changes(self.builds[0], A))
138 self.assertEqual(self.builds[1].name, 'project-test2')
139 self.assertTrue(self.job_has_changes(self.builds[1], A))
140 self.assertEqual(self.builds[2].name, 'project-merge')
141 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700142
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700143 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700144 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400145 self.assertEqual(len(self.builds), 5)
146 self.assertEqual(self.builds[0].name, 'project-test1')
147 self.assertTrue(self.job_has_changes(self.builds[0], A))
148 self.assertEqual(self.builds[1].name, 'project-test2')
149 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700150
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400151 self.assertEqual(self.builds[2].name, 'project-test1')
152 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
153 self.assertEqual(self.builds[3].name, 'project-test2')
154 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700155
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400156 self.assertEqual(self.builds[4].name, 'project-merge')
157 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700158
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700159 self.worker.release('.*-merge')
James E. Blairb0fcae42012-07-17 11:12:10 -0700160 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400161 self.assertEqual(len(self.builds), 6)
162 self.assertEqual(self.builds[0].name, 'project-test1')
163 self.assertTrue(self.job_has_changes(self.builds[0], A))
164 self.assertEqual(self.builds[1].name, 'project-test2')
165 self.assertTrue(self.job_has_changes(self.builds[1], A))
James E. Blairb0fcae42012-07-17 11:12:10 -0700166
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400167 self.assertEqual(self.builds[2].name, 'project-test1')
168 self.assertTrue(self.job_has_changes(self.builds[2], A, B))
169 self.assertEqual(self.builds[3].name, 'project-test2')
170 self.assertTrue(self.job_has_changes(self.builds[3], A, B))
James E. Blairb0fcae42012-07-17 11:12:10 -0700171
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400172 self.assertEqual(self.builds[4].name, 'project-test1')
173 self.assertTrue(self.job_has_changes(self.builds[4], A, B, C))
174 self.assertEqual(self.builds[5].name, 'project-test2')
175 self.assertTrue(self.job_has_changes(self.builds[5], A, B, C))
James E. Blairb0fcae42012-07-17 11:12:10 -0700176
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700177 self.worker.hold_jobs_in_build = False
178 self.worker.release()
James E. Blairb0fcae42012-07-17 11:12:10 -0700179 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400180 self.assertEqual(len(self.builds), 0)
James E. Blairb0fcae42012-07-17 11:12:10 -0700181
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400182 self.assertEqual(len(self.history), 9)
183 self.assertEqual(A.data['status'], 'MERGED')
184 self.assertEqual(B.data['status'], 'MERGED')
185 self.assertEqual(C.data['status'], 'MERGED')
186 self.assertEqual(A.reported, 2)
187 self.assertEqual(B.reported, 2)
188 self.assertEqual(C.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700189
190 def test_failed_changes(self):
191 "Test that a change behind a failed change is retested"
James E. Blaire2819012013-06-28 17:17:26 -0400192 self.worker.hold_jobs_in_build = True
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700193
James E. Blairb02a3bb2012-07-30 17:49:55 -0700194 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
195 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
James E. Blair8c803f82012-07-31 16:25:42 -0700196 A.addApproval('CRVW', 2)
197 B.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700198
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700199 self.worker.addFailTest('project-test1', A)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700200
James E. Blaire2819012013-06-28 17:17:26 -0400201 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
202 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700203 self.waitUntilSettled()
James E. Blaire2819012013-06-28 17:17:26 -0400204
205 self.worker.release('.*-merge')
206 self.waitUntilSettled()
207
208 self.worker.hold_jobs_in_build = False
209 self.worker.release()
210
211 self.waitUntilSettled()
212 # It's certain that the merge job for change 2 will run, but
213 # the test1 and test2 jobs may or may not run.
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400214 self.assertTrue(len(self.history) > 6)
215 self.assertEqual(A.data['status'], 'NEW')
216 self.assertEqual(B.data['status'], 'MERGED')
217 self.assertEqual(A.reported, 2)
218 self.assertEqual(B.reported, 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700219
220 def test_independent_queues(self):
221 "Test that changes end up in the right queues"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700222
223 self.worker.hold_jobs_in_build = True
Zhongyue Luo5d556072012-09-21 02:00:47 +0900224 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700225 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
226 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700227 A.addApproval('CRVW', 2)
228 B.addApproval('CRVW', 2)
229 C.addApproval('CRVW', 2)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700230
231 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
232 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
233 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
234
James E. Blairb02a3bb2012-07-30 17:49:55 -0700235 self.waitUntilSettled()
236
237 # There should be one merge job at the head of each queue running
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400238 self.assertEqual(len(self.builds), 2)
239 self.assertEqual(self.builds[0].name, 'project-merge')
240 self.assertTrue(self.job_has_changes(self.builds[0], A))
241 self.assertEqual(self.builds[1].name, 'project1-merge')
242 self.assertTrue(self.job_has_changes(self.builds[1], B))
James E. Blairb02a3bb2012-07-30 17:49:55 -0700243
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700244 # Release the current merge builds
245 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700246 self.waitUntilSettled()
247 # Release the merge job for project2 which is behind project1
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700248 self.worker.release('.*-merge')
James E. Blairb02a3bb2012-07-30 17:49:55 -0700249 self.waitUntilSettled()
250
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700251 # All the test builds should be running:
James E. Blairb02a3bb2012-07-30 17:49:55 -0700252 # project1 (3) + project2 (3) + project (2) = 8
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400253 self.assertEqual(len(self.builds), 8)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700254
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700255 self.worker.release()
James E. Blairb02a3bb2012-07-30 17:49:55 -0700256 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400257 self.assertEqual(len(self.builds), 0)
James E. Blairb02a3bb2012-07-30 17:49:55 -0700258
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400259 self.assertEqual(len(self.history), 11)
260 self.assertEqual(A.data['status'], 'MERGED')
261 self.assertEqual(B.data['status'], 'MERGED')
262 self.assertEqual(C.data['status'], 'MERGED')
263 self.assertEqual(A.reported, 2)
264 self.assertEqual(B.reported, 2)
265 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700266
267 def test_failed_change_at_head(self):
268 "Test that if a change at the head fails, jobs behind it are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700269
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700270 self.worker.hold_jobs_in_build = True
James E. Blaird466dc42012-07-31 10:42:56 -0700271 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
272 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
273 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700274 A.addApproval('CRVW', 2)
275 B.addApproval('CRVW', 2)
276 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700277
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700278 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700279
280 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
281 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
282 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
283
284 self.waitUntilSettled()
James E. Blaird466dc42012-07-31 10:42:56 -0700285
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400286 self.assertEqual(len(self.builds), 1)
287 self.assertEqual(self.builds[0].name, 'project-merge')
288 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700289
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700290 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700291 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700292 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700293 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700294 self.worker.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700295 self.waitUntilSettled()
296
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400297 self.assertEqual(len(self.builds), 6)
298 self.assertEqual(self.builds[0].name, 'project-test1')
299 self.assertEqual(self.builds[1].name, 'project-test2')
300 self.assertEqual(self.builds[2].name, 'project-test1')
301 self.assertEqual(self.builds[3].name, 'project-test2')
302 self.assertEqual(self.builds[4].name, 'project-test1')
303 self.assertEqual(self.builds[5].name, 'project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700304
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400305 self.release(self.builds[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700306 self.waitUntilSettled()
307
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400308 # project-test2, project-merge for B
309 self.assertEqual(len(self.builds), 2)
310 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 4)
James E. Blaird466dc42012-07-31 10:42:56 -0700311
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700312 self.worker.hold_jobs_in_build = False
313 self.worker.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700314 self.waitUntilSettled()
315
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400316 self.assertEqual(len(self.builds), 0)
317 self.assertEqual(len(self.history), 15)
318 self.assertEqual(A.data['status'], 'NEW')
319 self.assertEqual(B.data['status'], 'MERGED')
320 self.assertEqual(C.data['status'], 'MERGED')
321 self.assertEqual(A.reported, 2)
322 self.assertEqual(B.reported, 2)
323 self.assertEqual(C.reported, 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700324
James E. Blair0aac4872013-08-23 14:02:38 -0700325 def test_failed_change_in_middle(self):
326 "Test a failed change in the middle of the queue"
327
328 self.worker.hold_jobs_in_build = True
329 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
330 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
331 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
332 A.addApproval('CRVW', 2)
333 B.addApproval('CRVW', 2)
334 C.addApproval('CRVW', 2)
335
336 self.worker.addFailTest('project-test1', B)
337
338 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
339 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
340 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
341
342 self.waitUntilSettled()
343
344 self.worker.release('.*-merge')
345 self.waitUntilSettled()
346 self.worker.release('.*-merge')
347 self.waitUntilSettled()
348 self.worker.release('.*-merge')
349 self.waitUntilSettled()
350
351 self.assertEqual(len(self.builds), 6)
352 self.assertEqual(self.builds[0].name, 'project-test1')
353 self.assertEqual(self.builds[1].name, 'project-test2')
354 self.assertEqual(self.builds[2].name, 'project-test1')
355 self.assertEqual(self.builds[3].name, 'project-test2')
356 self.assertEqual(self.builds[4].name, 'project-test1')
357 self.assertEqual(self.builds[5].name, 'project-test2')
358
359 self.release(self.builds[2])
360 self.waitUntilSettled()
361
James E. Blair972e3c72013-08-29 12:04:55 -0700362 # project-test1 and project-test2 for A
363 # project-test2 for B
364 # project-merge for C (without B)
365 self.assertEqual(len(self.builds), 4)
James E. Blair0aac4872013-08-23 14:02:38 -0700366 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 2)
367
James E. Blair972e3c72013-08-29 12:04:55 -0700368 self.worker.release('.*-merge')
369 self.waitUntilSettled()
370
371 # project-test1 and project-test2 for A
372 # project-test2 for B
373 # project-test1 and project-test2 for C
374 self.assertEqual(len(self.builds), 5)
375
James E. Blair0aac4872013-08-23 14:02:38 -0700376 items = self.sched.layout.pipelines['gate'].getAllItems()
377 builds = items[0].current_build_set.getBuilds()
378 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
379 self.assertEqual(self.countJobResults(builds, None), 2)
380 builds = items[1].current_build_set.getBuilds()
381 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
382 self.assertEqual(self.countJobResults(builds, 'FAILURE'), 1)
383 self.assertEqual(self.countJobResults(builds, None), 1)
384 builds = items[2].current_build_set.getBuilds()
385 self.assertEqual(self.countJobResults(builds, 'SUCCESS'), 1)
James E. Blair972e3c72013-08-29 12:04:55 -0700386 self.assertEqual(self.countJobResults(builds, None), 2)
James E. Blair0aac4872013-08-23 14:02:38 -0700387
388 self.worker.hold_jobs_in_build = False
389 self.worker.release()
390 self.waitUntilSettled()
391
392 self.assertEqual(len(self.builds), 0)
393 self.assertEqual(len(self.history), 12)
394 self.assertEqual(A.data['status'], 'MERGED')
395 self.assertEqual(B.data['status'], 'NEW')
396 self.assertEqual(C.data['status'], 'MERGED')
397 self.assertEqual(A.reported, 2)
398 self.assertEqual(B.reported, 2)
399 self.assertEqual(C.reported, 2)
400
James E. Blaird466dc42012-07-31 10:42:56 -0700401 def test_failed_change_at_head_with_queue(self):
402 "Test that if a change at the head fails, queued jobs are canceled"
James E. Blaird466dc42012-07-31 10:42:56 -0700403
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700404 self.gearman_server.hold_jobs_in_queue = True
James E. Blaird466dc42012-07-31 10:42:56 -0700405 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
406 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
407 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
James E. Blair8c803f82012-07-31 16:25:42 -0700408 A.addApproval('CRVW', 2)
409 B.addApproval('CRVW', 2)
410 C.addApproval('CRVW', 2)
James E. Blaird466dc42012-07-31 10:42:56 -0700411
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700412 self.worker.addFailTest('project-test1', A)
James E. Blaird466dc42012-07-31 10:42:56 -0700413
414 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
415 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
416 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
417
418 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700419 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400420 self.assertEqual(len(self.builds), 0)
421 self.assertEqual(len(queue), 1)
422 self.assertEqual(queue[0].name, 'build:project-merge')
423 self.assertTrue(self.job_has_changes(queue[0], A))
James E. Blaird466dc42012-07-31 10:42:56 -0700424
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700425 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700426 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700427 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700428 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700429 self.gearman_server.release('.*-merge')
James E. Blaird466dc42012-07-31 10:42:56 -0700430 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700431 queue = self.gearman_server.getQueue()
James E. Blaird466dc42012-07-31 10:42:56 -0700432
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400433 self.assertEqual(len(self.builds), 0)
434 self.assertEqual(len(queue), 6)
435 self.assertEqual(queue[0].name, 'build:project-test1')
436 self.assertEqual(queue[1].name, 'build:project-test2')
437 self.assertEqual(queue[2].name, 'build:project-test1')
438 self.assertEqual(queue[3].name, 'build:project-test2')
439 self.assertEqual(queue[4].name, 'build:project-test1')
440 self.assertEqual(queue[5].name, 'build:project-test2')
James E. Blaird466dc42012-07-31 10:42:56 -0700441
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700442 self.release(queue[0])
James E. Blaird466dc42012-07-31 10:42:56 -0700443 self.waitUntilSettled()
444
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400445 self.assertEqual(len(self.builds), 0)
James E. Blair701c5b42013-06-06 09:34:59 -0700446 queue = self.gearman_server.getQueue()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400447 self.assertEqual(len(queue), 2) # project-test2, project-merge for B
448 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 0)
James E. Blaird466dc42012-07-31 10:42:56 -0700449
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700450 self.gearman_server.hold_jobs_in_queue = False
451 self.gearman_server.release()
James E. Blaird466dc42012-07-31 10:42:56 -0700452 self.waitUntilSettled()
453
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400454 self.assertEqual(len(self.builds), 0)
455 self.assertEqual(len(self.history), 11)
456 self.assertEqual(A.data['status'], 'NEW')
457 self.assertEqual(B.data['status'], 'MERGED')
458 self.assertEqual(C.data['status'], 'MERGED')
459 self.assertEqual(A.reported, 2)
460 self.assertEqual(B.reported, 2)
461 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700462
James E. Blairce8a2132016-05-19 15:21:52 -0700463 def _test_time_database(self, iteration):
464 self.worker.hold_jobs_in_build = True
465 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
466 A.addApproval('CRVW', 2)
467 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
468 self.waitUntilSettled()
469 time.sleep(2)
470
471 data = json.loads(self.sched.formatStatusJSON())
472 found_job = None
473 for pipeline in data['pipelines']:
474 if pipeline['name'] != 'gate':
475 continue
476 for queue in pipeline['change_queues']:
477 for head in queue['heads']:
478 for item in head:
479 for job in item['jobs']:
480 if job['name'] == 'project-merge':
481 found_job = job
482 break
483
484 self.assertIsNotNone(found_job)
485 if iteration == 1:
486 self.assertIsNotNone(found_job['estimated_time'])
487 self.assertIsNone(found_job['remaining_time'])
488 else:
489 self.assertIsNotNone(found_job['estimated_time'])
490 self.assertTrue(found_job['estimated_time'] >= 2)
491 self.assertIsNotNone(found_job['remaining_time'])
492
493 self.worker.hold_jobs_in_build = False
494 self.worker.release()
495 self.waitUntilSettled()
496
497 def test_time_database(self):
498 "Test the time database"
499
500 self._test_time_database(1)
501 self._test_time_database(2)
502
James E. Blairfef71632013-09-23 11:15:47 -0700503 def test_two_failed_changes_at_head(self):
504 "Test that changes are reparented correctly if 2 fail at head"
505
506 self.worker.hold_jobs_in_build = True
507 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
508 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
509 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
510 A.addApproval('CRVW', 2)
511 B.addApproval('CRVW', 2)
512 C.addApproval('CRVW', 2)
513
514 self.worker.addFailTest('project-test1', A)
515 self.worker.addFailTest('project-test1', B)
516
517 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
518 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
519 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
520 self.waitUntilSettled()
521
522 self.worker.release('.*-merge')
523 self.waitUntilSettled()
524 self.worker.release('.*-merge')
525 self.waitUntilSettled()
526 self.worker.release('.*-merge')
527 self.waitUntilSettled()
528
529 self.assertEqual(len(self.builds), 6)
530 self.assertEqual(self.builds[0].name, 'project-test1')
531 self.assertEqual(self.builds[1].name, 'project-test2')
532 self.assertEqual(self.builds[2].name, 'project-test1')
533 self.assertEqual(self.builds[3].name, 'project-test2')
534 self.assertEqual(self.builds[4].name, 'project-test1')
535 self.assertEqual(self.builds[5].name, 'project-test2')
536
537 self.assertTrue(self.job_has_changes(self.builds[0], A))
538 self.assertTrue(self.job_has_changes(self.builds[2], A))
539 self.assertTrue(self.job_has_changes(self.builds[2], B))
540 self.assertTrue(self.job_has_changes(self.builds[4], A))
541 self.assertTrue(self.job_has_changes(self.builds[4], B))
542 self.assertTrue(self.job_has_changes(self.builds[4], C))
543
544 # Fail change B first
545 self.release(self.builds[2])
546 self.waitUntilSettled()
547
548 # restart of C after B failure
549 self.worker.release('.*-merge')
550 self.waitUntilSettled()
551
552 self.assertEqual(len(self.builds), 5)
553 self.assertEqual(self.builds[0].name, 'project-test1')
554 self.assertEqual(self.builds[1].name, 'project-test2')
555 self.assertEqual(self.builds[2].name, 'project-test2')
556 self.assertEqual(self.builds[3].name, 'project-test1')
557 self.assertEqual(self.builds[4].name, 'project-test2')
558
559 self.assertTrue(self.job_has_changes(self.builds[1], A))
560 self.assertTrue(self.job_has_changes(self.builds[2], A))
561 self.assertTrue(self.job_has_changes(self.builds[2], B))
562 self.assertTrue(self.job_has_changes(self.builds[4], A))
563 self.assertFalse(self.job_has_changes(self.builds[4], B))
564 self.assertTrue(self.job_has_changes(self.builds[4], C))
565
566 # Finish running all passing jobs for change A
567 self.release(self.builds[1])
568 self.waitUntilSettled()
569 # Fail and report change A
570 self.release(self.builds[0])
571 self.waitUntilSettled()
572
573 # restart of B,C after A failure
574 self.worker.release('.*-merge')
575 self.waitUntilSettled()
576 self.worker.release('.*-merge')
577 self.waitUntilSettled()
578
579 self.assertEqual(len(self.builds), 4)
580 self.assertEqual(self.builds[0].name, 'project-test1') # B
581 self.assertEqual(self.builds[1].name, 'project-test2') # B
582 self.assertEqual(self.builds[2].name, 'project-test1') # C
583 self.assertEqual(self.builds[3].name, 'project-test2') # C
584
585 self.assertFalse(self.job_has_changes(self.builds[1], A))
586 self.assertTrue(self.job_has_changes(self.builds[1], B))
587 self.assertFalse(self.job_has_changes(self.builds[1], C))
588
589 self.assertFalse(self.job_has_changes(self.builds[2], A))
590 # After A failed and B and C restarted, B should be back in
591 # C's tests because it has not failed yet.
592 self.assertTrue(self.job_has_changes(self.builds[2], B))
593 self.assertTrue(self.job_has_changes(self.builds[2], C))
594
595 self.worker.hold_jobs_in_build = False
596 self.worker.release()
597 self.waitUntilSettled()
598
599 self.assertEqual(len(self.builds), 0)
600 self.assertEqual(len(self.history), 21)
601 self.assertEqual(A.data['status'], 'NEW')
602 self.assertEqual(B.data['status'], 'NEW')
603 self.assertEqual(C.data['status'], 'MERGED')
604 self.assertEqual(A.reported, 2)
605 self.assertEqual(B.reported, 2)
606 self.assertEqual(C.reported, 2)
607
James E. Blairce8a2132016-05-19 15:21:52 -0700608 def test_parse_skip_if(self):
609 job_yaml = """
610jobs:
611 - name: job_name
612 skip-if:
613 - project: ^project_name$
614 branch: ^stable/icehouse$
615 all-files-match-any:
616 - ^filename$
617 - project: ^project2_name$
618 all-files-match-any:
619 - ^filename2$
620 """.strip()
621 data = yaml.load(job_yaml)
622 config_job = data.get('jobs')[0]
623 cm = zuul.change_matcher
624 expected = cm.MatchAny([
625 cm.MatchAll([
626 cm.ProjectMatcher('^project_name$'),
627 cm.BranchMatcher('^stable/icehouse$'),
628 cm.MatchAllFiles([cm.FileMatcher('^filename$')]),
629 ]),
630 cm.MatchAll([
631 cm.ProjectMatcher('^project2_name$'),
632 cm.MatchAllFiles([cm.FileMatcher('^filename2$')]),
633 ]),
634 ])
635 matcher = self.sched._parseSkipIf(config_job)
636 self.assertEqual(expected, matcher)
637
James E. Blair8c803f82012-07-31 16:25:42 -0700638 def test_patch_order(self):
639 "Test that dependent patches are tested in the right order"
640 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
641 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
642 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
643 A.addApproval('CRVW', 2)
644 B.addApproval('CRVW', 2)
645 C.addApproval('CRVW', 2)
646
647 M2 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M2')
648 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
649 M2.setMerged()
650 M1.setMerged()
651
652 # C -> B -> A -> M1 -> M2
653 # M2 is here to make sure it is never queried. If it is, it
654 # means zuul is walking down the entire history of merged
655 # changes.
656
657 C.setDependsOn(B, 1)
658 B.setDependsOn(A, 1)
659 A.setDependsOn(M1, 1)
660 M1.setDependsOn(M2, 1)
661
662 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
663
664 self.waitUntilSettled()
665
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400666 self.assertEqual(A.data['status'], 'NEW')
667 self.assertEqual(B.data['status'], 'NEW')
668 self.assertEqual(C.data['status'], 'NEW')
James E. Blair8c803f82012-07-31 16:25:42 -0700669
670 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
671 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
672
673 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400674 self.assertEqual(M2.queried, 0)
675 self.assertEqual(A.data['status'], 'MERGED')
676 self.assertEqual(B.data['status'], 'MERGED')
677 self.assertEqual(C.data['status'], 'MERGED')
678 self.assertEqual(A.reported, 2)
679 self.assertEqual(B.reported, 2)
680 self.assertEqual(C.reported, 2)
James E. Blair8c803f82012-07-31 16:25:42 -0700681
James E. Blair063672f2015-01-29 13:09:12 -0800682 def test_needed_changes_enqueue(self):
683 "Test that a needed change is enqueued ahead"
684 # A Given a git tree like this, if we enqueue
685 # / \ change C, we should walk up and down the tree
686 # B G and enqueue changes in the order ABCDEFG.
687 # /|\ This is also the order that you would get if
688 # *C E F you enqueued changes in the order ABCDEFG, so
689 # / the ordering is stable across re-enqueue events.
690 # D
691
692 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
693 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
694 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
695 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
696 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
697 F = self.fake_gerrit.addFakeChange('org/project', 'master', 'F')
698 G = self.fake_gerrit.addFakeChange('org/project', 'master', 'G')
699 B.setDependsOn(A, 1)
700 C.setDependsOn(B, 1)
701 D.setDependsOn(C, 1)
702 E.setDependsOn(B, 1)
703 F.setDependsOn(B, 1)
704 G.setDependsOn(A, 1)
705
706 A.addApproval('CRVW', 2)
707 B.addApproval('CRVW', 2)
708 C.addApproval('CRVW', 2)
709 D.addApproval('CRVW', 2)
710 E.addApproval('CRVW', 2)
711 F.addApproval('CRVW', 2)
712 G.addApproval('CRVW', 2)
713 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
714
715 self.waitUntilSettled()
716
717 self.assertEqual(A.data['status'], 'NEW')
718 self.assertEqual(B.data['status'], 'NEW')
719 self.assertEqual(C.data['status'], 'NEW')
720 self.assertEqual(D.data['status'], 'NEW')
721 self.assertEqual(E.data['status'], 'NEW')
722 self.assertEqual(F.data['status'], 'NEW')
723 self.assertEqual(G.data['status'], 'NEW')
724
725 # We're about to add approvals to changes without adding the
726 # triggering events to Zuul, so that we can be sure that it is
727 # enqueing the changes based on dependencies, not because of
728 # triggering events. Since it will have the changes cached
729 # already (without approvals), we need to clear the cache
730 # first.
Joshua Hesketh4bd7da32016-02-17 20:58:47 +1100731 for connection in self.connections.values():
732 connection.maintainCache([])
James E. Blair063672f2015-01-29 13:09:12 -0800733
734 self.worker.hold_jobs_in_build = True
735 A.addApproval('APRV', 1)
736 B.addApproval('APRV', 1)
737 D.addApproval('APRV', 1)
738 E.addApproval('APRV', 1)
739 F.addApproval('APRV', 1)
740 G.addApproval('APRV', 1)
741 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
742
743 for x in range(8):
744 self.worker.release('.*-merge')
745 self.waitUntilSettled()
746 self.worker.hold_jobs_in_build = False
747 self.worker.release()
748 self.waitUntilSettled()
749
750 self.assertEqual(A.data['status'], 'MERGED')
751 self.assertEqual(B.data['status'], 'MERGED')
752 self.assertEqual(C.data['status'], 'MERGED')
753 self.assertEqual(D.data['status'], 'MERGED')
754 self.assertEqual(E.data['status'], 'MERGED')
755 self.assertEqual(F.data['status'], 'MERGED')
756 self.assertEqual(G.data['status'], 'MERGED')
757 self.assertEqual(A.reported, 2)
758 self.assertEqual(B.reported, 2)
759 self.assertEqual(C.reported, 2)
760 self.assertEqual(D.reported, 2)
761 self.assertEqual(E.reported, 2)
762 self.assertEqual(F.reported, 2)
763 self.assertEqual(G.reported, 2)
764 self.assertEqual(self.history[6].changes,
765 '1,1 2,1 3,1 4,1 5,1 6,1 7,1')
766
Joshua Hesketh850ccb62014-11-27 11:31:02 +1100767 def test_source_cache(self):
768 "Test that the source cache operates correctly"
James E. Blair0e933c52013-07-11 10:18:52 -0700769 self.worker.hold_jobs_in_build = True
770
771 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
772 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
773 X = self.fake_gerrit.addFakeChange('org/project', 'master', 'X')
774 A.addApproval('CRVW', 2)
775 B.addApproval('CRVW', 2)
776
777 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
778 M1.setMerged()
779
780 B.setDependsOn(A, 1)
781 A.setDependsOn(M1, 1)
782
783 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
784 self.fake_gerrit.addEvent(X.getPatchsetCreatedEvent(1))
785
786 self.waitUntilSettled()
787
788 for build in self.builds:
789 if build.parameters['ZUUL_PIPELINE'] == 'check':
790 build.release()
791 self.waitUntilSettled()
792 for build in self.builds:
793 if build.parameters['ZUUL_PIPELINE'] == 'check':
794 build.release()
795 self.waitUntilSettled()
796
797 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
798 self.waitUntilSettled()
799
Joshua Hesketh352264b2015-08-11 23:42:08 +1000800 self.log.debug("len %s" % self.fake_gerrit._change_cache.keys())
James E. Blair0e933c52013-07-11 10:18:52 -0700801 # there should still be changes in the cache
Joshua Hesketh352264b2015-08-11 23:42:08 +1000802 self.assertNotEqual(len(self.fake_gerrit._change_cache.keys()), 0)
James E. Blair0e933c52013-07-11 10:18:52 -0700803
804 self.worker.hold_jobs_in_build = False
805 self.worker.release()
806 self.waitUntilSettled()
807
808 self.assertEqual(A.data['status'], 'MERGED')
809 self.assertEqual(B.data['status'], 'MERGED')
810 self.assertEqual(A.queried, 2) # Initial and isMerged
811 self.assertEqual(B.queried, 3) # Initial A, refresh from B, isMerged
812
James E. Blair8c803f82012-07-31 16:25:42 -0700813 def test_can_merge(self):
James E. Blair4886cc12012-07-18 15:39:41 -0700814 "Test whether a change is ready to merge"
James E. Blair8c803f82012-07-31 16:25:42 -0700815 # TODO: move to test_gerrit (this is a unit test!)
816 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairc0dedf82014-08-06 09:37:52 -0700817 source = self.sched.layout.pipelines['gate'].source
818 a = source._getChange(1, 2)
James E. Blaireff88162013-07-01 12:44:14 -0400819 mgr = self.sched.layout.pipelines['gate'].manager
James E. Blairc0dedf82014-08-06 09:37:52 -0700820 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700821
822 A.addApproval('CRVW', 2)
James E. Blairc0dedf82014-08-06 09:37:52 -0700823 a = source._getChange(1, 2, refresh=True)
824 self.assertFalse(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair8c803f82012-07-31 16:25:42 -0700825
826 A.addApproval('APRV', 1)
James E. Blairc0dedf82014-08-06 09:37:52 -0700827 a = source._getChange(1, 2, refresh=True)
828 self.assertTrue(source.canMerge(a, mgr.getSubmitAllowNeeds()))
James E. Blair4886cc12012-07-18 15:39:41 -0700829
830 def test_build_configuration(self):
831 "Test that zuul merges the right commits for testing"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700832
833 self.gearman_server.hold_jobs_in_queue = True
James E. Blair4886cc12012-07-18 15:39:41 -0700834 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
835 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
836 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
837 A.addApproval('CRVW', 2)
838 B.addApproval('CRVW', 2)
839 C.addApproval('CRVW', 2)
840 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
841 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
842 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
843 self.waitUntilSettled()
844
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700845 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700846 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700847 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700848 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700849 self.gearman_server.release('.*-merge')
James E. Blair4886cc12012-07-18 15:39:41 -0700850 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -0700851 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700852 ref = self.getParameter(queue[-1], 'ZUUL_REF')
853 self.gearman_server.hold_jobs_in_queue = False
854 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700855 self.waitUntilSettled()
James E. Blair4886cc12012-07-18 15:39:41 -0700856
Monty Taylorbc758832013-06-17 17:22:42 -0400857 path = os.path.join(self.git_root, "org/project")
James E. Blair4886cc12012-07-18 15:39:41 -0700858 repo = git.Repo(path)
859 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
860 repo_messages.reverse()
James E. Blair4886cc12012-07-18 15:39:41 -0700861 correct_messages = ['initial commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400862 self.assertEqual(repo_messages, correct_messages)
James E. Blair973721f2012-08-15 10:19:43 -0700863
864 def test_build_configuration_conflict(self):
865 "Test that merge conflicts are handled"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700866
867 self.gearman_server.hold_jobs_in_queue = True
James E. Blair6736beb2013-07-11 15:18:15 -0700868 A = self.fake_gerrit.addFakeChange('org/conflict-project',
869 'master', 'A')
James E. Blair973721f2012-08-15 10:19:43 -0700870 A.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700871 B = self.fake_gerrit.addFakeChange('org/conflict-project',
872 'master', 'B')
James E. Blair973721f2012-08-15 10:19:43 -0700873 B.addPatchset(['conflict'])
James E. Blair6736beb2013-07-11 15:18:15 -0700874 C = self.fake_gerrit.addFakeChange('org/conflict-project',
875 'master', 'C')
James E. Blair973721f2012-08-15 10:19:43 -0700876 A.addApproval('CRVW', 2)
877 B.addApproval('CRVW', 2)
878 C.addApproval('CRVW', 2)
879 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
880 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
881 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
882 self.waitUntilSettled()
883
James E. Blair6736beb2013-07-11 15:18:15 -0700884 self.assertEqual(A.reported, 1)
885 self.assertEqual(B.reported, 1)
886 self.assertEqual(C.reported, 1)
887
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700888 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700889 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700890 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700891 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700892 self.gearman_server.release('.*-merge')
James E. Blair973721f2012-08-15 10:19:43 -0700893 self.waitUntilSettled()
James E. Blair972e3c72013-08-29 12:04:55 -0700894
895 self.assertEqual(len(self.history), 2) # A and C merge jobs
896
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700897 self.gearman_server.hold_jobs_in_queue = False
898 self.gearman_server.release()
James E. Blair973721f2012-08-15 10:19:43 -0700899 self.waitUntilSettled()
900
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400901 self.assertEqual(A.data['status'], 'MERGED')
902 self.assertEqual(B.data['status'], 'NEW')
903 self.assertEqual(C.data['status'], 'MERGED')
904 self.assertEqual(A.reported, 2)
905 self.assertEqual(B.reported, 2)
906 self.assertEqual(C.reported, 2)
James E. Blair972e3c72013-08-29 12:04:55 -0700907 self.assertEqual(len(self.history), 6)
James E. Blair6736beb2013-07-11 15:18:15 -0700908
James E. Blairdaabed22012-08-15 15:38:57 -0700909 def test_post(self):
910 "Test that post jobs run"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700911
Zhongyue Luo5d556072012-09-21 02:00:47 +0900912 e = {
913 "type": "ref-updated",
914 "submitter": {
915 "name": "User Name",
916 },
917 "refUpdate": {
918 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
919 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
920 "refName": "master",
921 "project": "org/project",
922 }
923 }
James E. Blairdaabed22012-08-15 15:38:57 -0700924 self.fake_gerrit.addEvent(e)
925 self.waitUntilSettled()
926
Monty Taylor6bef8ef2013-06-02 08:17:12 -0400927 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -0400928 self.assertEqual(len(self.history), 1)
929 self.assertIn('project-post', job_names)
James E. Blairc6294a52012-08-17 10:19:48 -0700930
K Jonathan Harkerf95e7232015-04-29 13:33:16 -0700931 def test_post_ignore_deletes(self):
932 "Test that deleting refs does not trigger post jobs"
933
934 e = {
935 "type": "ref-updated",
936 "submitter": {
937 "name": "User Name",
938 },
939 "refUpdate": {
940 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
941 "newRev": "0000000000000000000000000000000000000000",
942 "refName": "master",
943 "project": "org/project",
944 }
945 }
946 self.fake_gerrit.addEvent(e)
947 self.waitUntilSettled()
948
949 job_names = [x.name for x in self.history]
950 self.assertEqual(len(self.history), 0)
951 self.assertNotIn('project-post', job_names)
952
953 def test_post_ignore_deletes_negative(self):
954 "Test that deleting refs does trigger post jobs"
955
956 self.config.set('zuul', 'layout_config',
957 'tests/fixtures/layout-dont-ignore-deletes.yaml')
958 self.sched.reconfigure(self.config)
959
960 e = {
961 "type": "ref-updated",
962 "submitter": {
963 "name": "User Name",
964 },
965 "refUpdate": {
966 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
967 "newRev": "0000000000000000000000000000000000000000",
968 "refName": "master",
969 "project": "org/project",
970 }
971 }
972 self.fake_gerrit.addEvent(e)
973 self.waitUntilSettled()
974
975 job_names = [x.name for x in self.history]
976 self.assertEqual(len(self.history), 1)
977 self.assertIn('project-post', job_names)
978
James E. Blairc6294a52012-08-17 10:19:48 -0700979 def test_build_configuration_branch(self):
980 "Test that the right commits are on alternate branches"
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700981
982 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -0700983 A = self.fake_gerrit.addFakeChange('org/project', 'mp', 'A')
984 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
985 C = self.fake_gerrit.addFakeChange('org/project', 'mp', 'C')
986 A.addApproval('CRVW', 2)
987 B.addApproval('CRVW', 2)
988 C.addApproval('CRVW', 2)
989 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
990 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
991 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
992 self.waitUntilSettled()
993
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700994 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700995 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700996 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700997 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -0700998 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -0700999 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001000 queue = self.gearman_server.getQueue()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001001 ref = self.getParameter(queue[-1], 'ZUUL_REF')
1002 self.gearman_server.hold_jobs_in_queue = False
1003 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001004 self.waitUntilSettled()
1005
Monty Taylorbc758832013-06-17 17:22:42 -04001006 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001007 repo = git.Repo(path)
1008 repo_messages = [c.message.strip() for c in repo.iter_commits(ref)]
1009 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001010 correct_messages = ['initial commit', 'mp commit', 'A-1', 'B-1', 'C-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001011 self.assertEqual(repo_messages, correct_messages)
James E. Blairc6294a52012-08-17 10:19:48 -07001012
1013 def test_build_configuration_branch_interaction(self):
1014 "Test that switching between branches works"
1015 self.test_build_configuration()
1016 self.test_build_configuration_branch()
1017 # C has been merged, undo that
Monty Taylorbc758832013-06-17 17:22:42 -04001018 path = os.path.join(self.upstream_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001019 repo = git.Repo(path)
1020 repo.heads.master.commit = repo.commit('init')
1021 self.test_build_configuration()
1022
1023 def test_build_configuration_multi_branch(self):
1024 "Test that dependent changes on multiple branches are merged"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001025
1026 self.gearman_server.hold_jobs_in_queue = True
James E. Blairc6294a52012-08-17 10:19:48 -07001027 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1028 B = self.fake_gerrit.addFakeChange('org/project', 'mp', 'B')
1029 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1030 A.addApproval('CRVW', 2)
1031 B.addApproval('CRVW', 2)
1032 C.addApproval('CRVW', 2)
1033 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1034 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1035 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1036 self.waitUntilSettled()
James E. Blairbb1fe502014-03-04 10:15:06 -08001037 queue = self.gearman_server.getQueue()
1038 job_A = None
1039 for job in queue:
1040 if 'project-merge' in job.name:
1041 job_A = job
1042 ref_A = self.getParameter(job_A, 'ZUUL_REF')
1043 commit_A = self.getParameter(job_A, 'ZUUL_COMMIT')
1044 self.log.debug("Got Zuul ref for change A: %s" % ref_A)
1045 self.log.debug("Got Zuul commit for change A: %s" % commit_A)
James E. Blairc6294a52012-08-17 10:19:48 -07001046
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001047 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001048 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001049 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001050 job_B = None
1051 for job in queue:
1052 if 'project-merge' in job.name:
1053 job_B = job
1054 ref_B = self.getParameter(job_B, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001055 commit_B = self.getParameter(job_B, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001056 self.log.debug("Got Zuul ref for change B: %s" % ref_B)
James E. Blairbb1fe502014-03-04 10:15:06 -08001057 self.log.debug("Got Zuul commit for change B: %s" % commit_B)
1058
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001059 self.gearman_server.release('.*-merge')
James E. Blairc6294a52012-08-17 10:19:48 -07001060 self.waitUntilSettled()
James E. Blair701c5b42013-06-06 09:34:59 -07001061 queue = self.gearman_server.getQueue()
James E. Blaird320d7e2013-07-30 16:36:20 -07001062 for job in queue:
1063 if 'project-merge' in job.name:
1064 job_C = job
1065 ref_C = self.getParameter(job_C, 'ZUUL_REF')
James E. Blairbb1fe502014-03-04 10:15:06 -08001066 commit_C = self.getParameter(job_C, 'ZUUL_COMMIT')
James E. Blairf750aa02013-07-15 14:11:24 -07001067 self.log.debug("Got Zuul ref for change C: %s" % ref_C)
James E. Blairbb1fe502014-03-04 10:15:06 -08001068 self.log.debug("Got Zuul commit for change C: %s" % commit_C)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001069 self.gearman_server.hold_jobs_in_queue = False
1070 self.gearman_server.release()
James E. Blairc6294a52012-08-17 10:19:48 -07001071 self.waitUntilSettled()
1072
Monty Taylorbc758832013-06-17 17:22:42 -04001073 path = os.path.join(self.git_root, "org/project")
James E. Blairc6294a52012-08-17 10:19:48 -07001074 repo = git.Repo(path)
1075
1076 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001077 for c in repo.iter_commits(ref_C)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001078 repo_shas = [c.hexsha for c in repo.iter_commits(ref_C)]
James E. Blairc6294a52012-08-17 10:19:48 -07001079 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001080 correct_messages = ['initial commit', 'A-1', 'C-1']
James E. Blairbb1fe502014-03-04 10:15:06 -08001081 # Ensure the right commits are in the history for this ref
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001082 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001083 # Ensure ZUUL_REF -> ZUUL_COMMIT
1084 self.assertEqual(repo_shas[0], commit_C)
James E. Blairc6294a52012-08-17 10:19:48 -07001085
1086 repo_messages = [c.message.strip()
James E. Blairf750aa02013-07-15 14:11:24 -07001087 for c in repo.iter_commits(ref_B)]
James E. Blairbb1fe502014-03-04 10:15:06 -08001088 repo_shas = [c.hexsha for c in repo.iter_commits(ref_B)]
James E. Blairc6294a52012-08-17 10:19:48 -07001089 repo_messages.reverse()
James E. Blairc6294a52012-08-17 10:19:48 -07001090 correct_messages = ['initial commit', 'mp commit', 'B-1']
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001091 self.assertEqual(repo_messages, correct_messages)
James E. Blairbb1fe502014-03-04 10:15:06 -08001092 self.assertEqual(repo_shas[0], commit_B)
1093
1094 repo_messages = [c.message.strip()
1095 for c in repo.iter_commits(ref_A)]
1096 repo_shas = [c.hexsha for c in repo.iter_commits(ref_A)]
1097 repo_messages.reverse()
1098 correct_messages = ['initial commit', 'A-1']
1099 self.assertEqual(repo_messages, correct_messages)
1100 self.assertEqual(repo_shas[0], commit_A)
1101
1102 self.assertNotEqual(ref_A, ref_B, ref_C)
1103 self.assertNotEqual(commit_A, commit_B, commit_C)
James E. Blair7f71c802012-08-22 13:04:32 -07001104
1105 def test_one_job_project(self):
1106 "Test that queueing works with one job"
1107 A = self.fake_gerrit.addFakeChange('org/one-job-project',
1108 'master', 'A')
1109 B = self.fake_gerrit.addFakeChange('org/one-job-project',
1110 'master', 'B')
1111 A.addApproval('CRVW', 2)
1112 B.addApproval('CRVW', 2)
1113 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1114 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1115 self.waitUntilSettled()
1116
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001117 self.assertEqual(A.data['status'], 'MERGED')
1118 self.assertEqual(A.reported, 2)
1119 self.assertEqual(B.data['status'], 'MERGED')
1120 self.assertEqual(B.reported, 2)
James E. Blaircaec0c52012-08-22 14:52:22 -07001121
Antoine Musso80edd5a2013-02-13 15:37:53 +01001122 def test_job_from_templates_launched(self):
1123 "Test whether a job generated via a template can be launched"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001124
Antoine Musso80edd5a2013-02-13 15:37:53 +01001125 A = self.fake_gerrit.addFakeChange(
1126 'org/templated-project', 'master', 'A')
1127 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1128 self.waitUntilSettled()
Antoine Musso80edd5a2013-02-13 15:37:53 +01001129
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001130 self.assertEqual(self.getJobFromHistory('project-test1').result,
1131 'SUCCESS')
1132 self.assertEqual(self.getJobFromHistory('project-test2').result,
1133 'SUCCESS')
Antoine Musso80edd5a2013-02-13 15:37:53 +01001134
James E. Blair3e98c022013-12-16 15:25:38 -08001135 def test_layered_templates(self):
1136 "Test whether a job generated via a template can be launched"
1137
1138 A = self.fake_gerrit.addFakeChange(
1139 'org/layered-project', 'master', 'A')
1140 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1141 self.waitUntilSettled()
1142
1143 self.assertEqual(self.getJobFromHistory('project-test1').result,
1144 'SUCCESS')
1145 self.assertEqual(self.getJobFromHistory('project-test2').result,
1146 'SUCCESS')
James E. Blairaea6cf62013-12-16 15:38:12 -08001147 self.assertEqual(self.getJobFromHistory('layered-project-test3'
1148 ).result, 'SUCCESS')
1149 self.assertEqual(self.getJobFromHistory('layered-project-test4'
1150 ).result, 'SUCCESS')
James E. Blair12a92b12014-03-26 11:54:53 -07001151 self.assertEqual(self.getJobFromHistory('layered-project-foo-test5'
1152 ).result, 'SUCCESS')
James E. Blair3e98c022013-12-16 15:25:38 -08001153 self.assertEqual(self.getJobFromHistory('project-test6').result,
1154 'SUCCESS')
1155
James E. Blaircaec0c52012-08-22 14:52:22 -07001156 def test_dependent_changes_dequeue(self):
1157 "Test that dependent patches are not needlessly tested"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001158
James E. Blaircaec0c52012-08-22 14:52:22 -07001159 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1160 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1161 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1162 A.addApproval('CRVW', 2)
1163 B.addApproval('CRVW', 2)
1164 C.addApproval('CRVW', 2)
1165
1166 M1 = self.fake_gerrit.addFakeChange('org/project', 'master', 'M1')
1167 M1.setMerged()
1168
1169 # C -> B -> A -> M1
1170
1171 C.setDependsOn(B, 1)
1172 B.setDependsOn(A, 1)
1173 A.setDependsOn(M1, 1)
1174
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001175 self.worker.addFailTest('project-merge', A)
James E. Blaircaec0c52012-08-22 14:52:22 -07001176
1177 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1178 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1179 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1180
1181 self.waitUntilSettled()
1182
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001183 self.assertEqual(A.data['status'], 'NEW')
1184 self.assertEqual(A.reported, 2)
1185 self.assertEqual(B.data['status'], 'NEW')
1186 self.assertEqual(B.reported, 2)
1187 self.assertEqual(C.data['status'], 'NEW')
1188 self.assertEqual(C.reported, 2)
1189 self.assertEqual(len(self.history), 1)
James E. Blairec590122012-08-22 15:19:31 -07001190
James E. Blair972e3c72013-08-29 12:04:55 -07001191 def test_failing_dependent_changes(self):
1192 "Test that failing dependent patches are taken out of stream"
1193 self.worker.hold_jobs_in_build = True
1194 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1195 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1196 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1197 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1198 E = self.fake_gerrit.addFakeChange('org/project', 'master', 'E')
1199 A.addApproval('CRVW', 2)
1200 B.addApproval('CRVW', 2)
1201 C.addApproval('CRVW', 2)
1202 D.addApproval('CRVW', 2)
1203 E.addApproval('CRVW', 2)
1204
1205 # E, D -> C -> B, A
1206
1207 D.setDependsOn(C, 1)
1208 C.setDependsOn(B, 1)
1209
1210 self.worker.addFailTest('project-test1', B)
1211
1212 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1213 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1214 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1215 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1216 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1217
1218 self.waitUntilSettled()
1219 self.worker.release('.*-merge')
1220 self.waitUntilSettled()
1221 self.worker.release('.*-merge')
1222 self.waitUntilSettled()
1223 self.worker.release('.*-merge')
1224 self.waitUntilSettled()
1225 self.worker.release('.*-merge')
1226 self.waitUntilSettled()
1227 self.worker.release('.*-merge')
1228 self.waitUntilSettled()
1229
1230 self.worker.hold_jobs_in_build = False
1231 for build in self.builds:
1232 if build.parameters['ZUUL_CHANGE'] != '1':
1233 build.release()
1234 self.waitUntilSettled()
1235
1236 self.worker.release()
1237 self.waitUntilSettled()
1238
1239 self.assertEqual(A.data['status'], 'MERGED')
1240 self.assertEqual(A.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001241 self.assertIn('Build succeeded', A.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001242 self.assertEqual(B.data['status'], 'NEW')
1243 self.assertEqual(B.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001244 self.assertIn('Build failed', B.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001245 self.assertEqual(C.data['status'], 'NEW')
1246 self.assertEqual(C.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001247 self.assertIn('depends on a change', C.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001248 self.assertEqual(D.data['status'], 'NEW')
1249 self.assertEqual(D.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001250 self.assertIn('depends on a change', D.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001251 self.assertEqual(E.data['status'], 'MERGED')
1252 self.assertEqual(E.reported, 2)
Jeremy Stanley10837132014-08-02 16:10:56 +00001253 self.assertIn('Build succeeded', E.messages[1])
James E. Blair972e3c72013-08-29 12:04:55 -07001254 self.assertEqual(len(self.history), 18)
1255
James E. Blairec590122012-08-22 15:19:31 -07001256 def test_head_is_dequeued_once(self):
James E. Blair2fa50962013-01-30 21:50:41 -08001257 "Test that if a change at the head fails it is dequeued only once"
James E. Blairec590122012-08-22 15:19:31 -07001258 # If it's dequeued more than once, we should see extra
1259 # aborted jobs.
James E. Blairec590122012-08-22 15:19:31 -07001260
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001261 self.worker.hold_jobs_in_build = True
James E. Blairec590122012-08-22 15:19:31 -07001262 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1263 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1264 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
1265 A.addApproval('CRVW', 2)
1266 B.addApproval('CRVW', 2)
1267 C.addApproval('CRVW', 2)
1268
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001269 self.worker.addFailTest('project1-test1', A)
1270 self.worker.addFailTest('project1-test2', A)
1271 self.worker.addFailTest('project1-project2-integration', A)
James E. Blairec590122012-08-22 15:19:31 -07001272
1273 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1274 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1275 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1276
1277 self.waitUntilSettled()
James E. Blairec590122012-08-22 15:19:31 -07001278
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001279 self.assertEqual(len(self.builds), 1)
1280 self.assertEqual(self.builds[0].name, 'project1-merge')
1281 self.assertTrue(self.job_has_changes(self.builds[0], A))
James E. Blairec590122012-08-22 15:19:31 -07001282
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001283 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001284 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001285 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001286 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001287 self.worker.release('.*-merge')
James E. Blairec590122012-08-22 15:19:31 -07001288 self.waitUntilSettled()
1289
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001290 self.assertEqual(len(self.builds), 9)
1291 self.assertEqual(self.builds[0].name, 'project1-test1')
1292 self.assertEqual(self.builds[1].name, 'project1-test2')
1293 self.assertEqual(self.builds[2].name, 'project1-project2-integration')
1294 self.assertEqual(self.builds[3].name, 'project1-test1')
1295 self.assertEqual(self.builds[4].name, 'project1-test2')
1296 self.assertEqual(self.builds[5].name, 'project1-project2-integration')
1297 self.assertEqual(self.builds[6].name, 'project1-test1')
1298 self.assertEqual(self.builds[7].name, 'project1-test2')
1299 self.assertEqual(self.builds[8].name, 'project1-project2-integration')
James E. Blairec590122012-08-22 15:19:31 -07001300
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001301 self.release(self.builds[0])
James E. Blairec590122012-08-22 15:19:31 -07001302 self.waitUntilSettled()
1303
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001304 self.assertEqual(len(self.builds), 3) # test2,integration, merge for B
1305 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 6)
James E. Blairec590122012-08-22 15:19:31 -07001306
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001307 self.worker.hold_jobs_in_build = False
1308 self.worker.release()
James E. Blairec590122012-08-22 15:19:31 -07001309 self.waitUntilSettled()
1310
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001311 self.assertEqual(len(self.builds), 0)
1312 self.assertEqual(len(self.history), 20)
James E. Blaircaec0c52012-08-22 14:52:22 -07001313
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001314 self.assertEqual(A.data['status'], 'NEW')
1315 self.assertEqual(B.data['status'], 'MERGED')
1316 self.assertEqual(C.data['status'], 'MERGED')
1317 self.assertEqual(A.reported, 2)
1318 self.assertEqual(B.reported, 2)
1319 self.assertEqual(C.reported, 2)
James E. Blair4ec821f2012-08-23 15:28:28 -07001320
1321 def test_nonvoting_job(self):
1322 "Test that non-voting jobs don't vote."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001323
James E. Blair4ec821f2012-08-23 15:28:28 -07001324 A = self.fake_gerrit.addFakeChange('org/nonvoting-project',
1325 'master', 'A')
1326 A.addApproval('CRVW', 2)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001327 self.worker.addFailTest('nonvoting-project-test2', A)
James E. Blair4ec821f2012-08-23 15:28:28 -07001328 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1329
1330 self.waitUntilSettled()
James E. Blair4ec821f2012-08-23 15:28:28 -07001331
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001332 self.assertEqual(A.data['status'], 'MERGED')
1333 self.assertEqual(A.reported, 2)
1334 self.assertEqual(
1335 self.getJobFromHistory('nonvoting-project-merge').result,
1336 'SUCCESS')
1337 self.assertEqual(
1338 self.getJobFromHistory('nonvoting-project-test1').result,
1339 'SUCCESS')
1340 self.assertEqual(
1341 self.getJobFromHistory('nonvoting-project-test2').result,
1342 'FAILURE')
James E. Blaire0487072012-08-29 17:38:31 -07001343
James E. Blair5821bd92015-09-16 08:48:15 -07001344 for build in self.builds:
1345 self.assertEqual(build.parameters['ZUUL_VOTING'], '0')
1346
James E. Blaire0487072012-08-29 17:38:31 -07001347 def test_check_queue_success(self):
1348 "Test successful check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001349
James E. Blaire0487072012-08-29 17:38:31 -07001350 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1351 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1352
1353 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001354
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001355 self.assertEqual(A.data['status'], 'NEW')
1356 self.assertEqual(A.reported, 1)
1357 self.assertEqual(self.getJobFromHistory('project-merge').result,
1358 'SUCCESS')
1359 self.assertEqual(self.getJobFromHistory('project-test1').result,
1360 'SUCCESS')
1361 self.assertEqual(self.getJobFromHistory('project-test2').result,
1362 'SUCCESS')
James E. Blaire0487072012-08-29 17:38:31 -07001363
1364 def test_check_queue_failure(self):
1365 "Test failed check queue jobs."
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001366
James E. Blaire0487072012-08-29 17:38:31 -07001367 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001368 self.worker.addFailTest('project-test2', A)
James E. Blaire0487072012-08-29 17:38:31 -07001369 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1370
1371 self.waitUntilSettled()
James E. Blaire0487072012-08-29 17:38:31 -07001372
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001373 self.assertEqual(A.data['status'], 'NEW')
1374 self.assertEqual(A.reported, 1)
1375 self.assertEqual(self.getJobFromHistory('project-merge').result,
James E. Blair78e31b32013-07-09 09:11:34 -07001376 'SUCCESS')
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001377 self.assertEqual(self.getJobFromHistory('project-test1').result,
1378 'SUCCESS')
1379 self.assertEqual(self.getJobFromHistory('project-test2').result,
1380 'FAILURE')
James E. Blair127bc182012-08-28 15:55:15 -07001381
1382 def test_dependent_behind_dequeue(self):
1383 "test that dependent changes behind dequeued changes work"
1384 # This complicated test is a reproduction of a real life bug
1385 self.sched.reconfigure(self.config)
James E. Blair127bc182012-08-28 15:55:15 -07001386
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001387 self.worker.hold_jobs_in_build = True
James E. Blair127bc182012-08-28 15:55:15 -07001388 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1389 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1390 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1391 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1392 E = self.fake_gerrit.addFakeChange('org/project2', 'master', 'E')
1393 F = self.fake_gerrit.addFakeChange('org/project3', 'master', 'F')
1394 D.setDependsOn(C, 1)
1395 E.setDependsOn(D, 1)
1396 A.addApproval('CRVW', 2)
1397 B.addApproval('CRVW', 2)
1398 C.addApproval('CRVW', 2)
1399 D.addApproval('CRVW', 2)
1400 E.addApproval('CRVW', 2)
1401 F.addApproval('CRVW', 2)
1402
1403 A.fail_merge = True
James E. Blair127bc182012-08-28 15:55:15 -07001404
1405 # Change object re-use in the gerrit trigger is hidden if
1406 # changes are added in quick succession; waiting makes it more
1407 # like real life.
1408 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1409 self.waitUntilSettled()
1410 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1411 self.waitUntilSettled()
1412
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001413 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001414 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001415 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001416 self.waitUntilSettled()
1417
1418 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1419 self.waitUntilSettled()
1420 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1421 self.waitUntilSettled()
1422 self.fake_gerrit.addEvent(E.addApproval('APRV', 1))
1423 self.waitUntilSettled()
1424 self.fake_gerrit.addEvent(F.addApproval('APRV', 1))
1425 self.waitUntilSettled()
1426
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001427 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001428 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001429 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001430 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001431 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001432 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001433 self.worker.release('.*-merge')
James E. Blair127bc182012-08-28 15:55:15 -07001434 self.waitUntilSettled()
1435
1436 # all jobs running
James E. Blaire955e062012-10-08 09:49:03 -07001437
1438 # Grab pointers to the jobs we want to release before
1439 # releasing any, because list indexes may change as
1440 # the jobs complete.
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001441 a, b, c = self.builds[:3]
James E. Blaire955e062012-10-08 09:49:03 -07001442 a.release()
1443 b.release()
1444 c.release()
James E. Blair127bc182012-08-28 15:55:15 -07001445 self.waitUntilSettled()
1446
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001447 self.worker.hold_jobs_in_build = False
1448 self.worker.release()
James E. Blair127bc182012-08-28 15:55:15 -07001449 self.waitUntilSettled()
1450
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001451 self.assertEqual(A.data['status'], 'NEW')
1452 self.assertEqual(B.data['status'], 'MERGED')
1453 self.assertEqual(C.data['status'], 'MERGED')
1454 self.assertEqual(D.data['status'], 'MERGED')
1455 self.assertEqual(E.data['status'], 'MERGED')
1456 self.assertEqual(F.data['status'], 'MERGED')
James E. Blair127bc182012-08-28 15:55:15 -07001457
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001458 self.assertEqual(A.reported, 2)
1459 self.assertEqual(B.reported, 2)
1460 self.assertEqual(C.reported, 2)
1461 self.assertEqual(D.reported, 2)
1462 self.assertEqual(E.reported, 2)
1463 self.assertEqual(F.reported, 2)
James E. Blair127bc182012-08-28 15:55:15 -07001464
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001465 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 15)
1466 self.assertEqual(len(self.history), 44)
James E. Blair05fed602012-09-07 12:45:24 -07001467
1468 def test_merger_repack(self):
1469 "Test that the merger works after a repack"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001470
James E. Blair05fed602012-09-07 12:45:24 -07001471 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1472 A.addApproval('CRVW', 2)
1473 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1474 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001475 self.assertEqual(self.getJobFromHistory('project-merge').result,
1476 'SUCCESS')
1477 self.assertEqual(self.getJobFromHistory('project-test1').result,
1478 'SUCCESS')
1479 self.assertEqual(self.getJobFromHistory('project-test2').result,
1480 'SUCCESS')
1481 self.assertEqual(A.data['status'], 'MERGED')
1482 self.assertEqual(A.reported, 2)
James E. Blair05fed602012-09-07 12:45:24 -07001483 self.assertEmptyQueues()
James E. Blair4ca985f2013-05-30 12:27:43 -07001484 self.worker.build_history = []
James E. Blair05fed602012-09-07 12:45:24 -07001485
Monty Taylorbc758832013-06-17 17:22:42 -04001486 path = os.path.join(self.git_root, "org/project")
1487 print repack_repo(path)
James E. Blair05fed602012-09-07 12:45:24 -07001488
1489 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1490 A.addApproval('CRVW', 2)
1491 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1492 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001493 self.assertEqual(self.getJobFromHistory('project-merge').result,
1494 'SUCCESS')
1495 self.assertEqual(self.getJobFromHistory('project-test1').result,
1496 'SUCCESS')
1497 self.assertEqual(self.getJobFromHistory('project-test2').result,
1498 'SUCCESS')
1499 self.assertEqual(A.data['status'], 'MERGED')
1500 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001501
James E. Blair4886f282012-11-15 09:27:33 -08001502 def test_merger_repack_large_change(self):
1503 "Test that the merger works with large changes after a repack"
1504 # https://bugs.launchpad.net/zuul/+bug/1078946
James E. Blairac2c3242014-01-24 13:38:51 -08001505 # This test assumes the repo is already cloned; make sure it is
Joshua Hesketh352264b2015-08-11 23:42:08 +10001506 url = self.fake_gerrit.getGitUrl(
James E. Blairac2c3242014-01-24 13:38:51 -08001507 self.sched.layout.projects['org/project1'])
James E. Blair4076e2b2014-01-28 12:42:20 -08001508 self.merge_server.merger.addProject('org/project1', url)
James E. Blair4886f282012-11-15 09:27:33 -08001509 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1510 A.addPatchset(large=True)
Monty Taylorbc758832013-06-17 17:22:42 -04001511 path = os.path.join(self.upstream_root, "org/project1")
1512 print repack_repo(path)
1513 path = os.path.join(self.git_root, "org/project1")
1514 print repack_repo(path)
James E. Blair4886f282012-11-15 09:27:33 -08001515
1516 A.addApproval('CRVW', 2)
1517 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1518 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001519 self.assertEqual(self.getJobFromHistory('project1-merge').result,
1520 'SUCCESS')
1521 self.assertEqual(self.getJobFromHistory('project1-test1').result,
1522 'SUCCESS')
1523 self.assertEqual(self.getJobFromHistory('project1-test2').result,
1524 'SUCCESS')
1525 self.assertEqual(A.data['status'], 'MERGED')
1526 self.assertEqual(A.reported, 2)
James E. Blair4886f282012-11-15 09:27:33 -08001527
James E. Blair7ee88a22012-09-12 18:59:31 +02001528 def test_nonexistent_job(self):
1529 "Test launching a job that doesn't exist"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001530 # Set to the state immediately after a restart
1531 self.resetGearmanServer()
1532 self.launcher.negative_function_cache_ttl = 0
James E. Blair7ee88a22012-09-12 18:59:31 +02001533
1534 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1535 A.addApproval('CRVW', 2)
1536 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1537 # There may be a thread about to report a lost change
1538 while A.reported < 2:
1539 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04001540 job_names = [x.name for x in self.history]
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001541 self.assertFalse(job_names)
1542 self.assertEqual(A.data['status'], 'NEW')
1543 self.assertEqual(A.reported, 2)
James E. Blair7ee88a22012-09-12 18:59:31 +02001544 self.assertEmptyQueues()
1545
1546 # Make sure things still work:
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001547 self.registerJobs()
James E. Blair7ee88a22012-09-12 18:59:31 +02001548 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1549 A.addApproval('CRVW', 2)
1550 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1551 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001552 self.assertEqual(self.getJobFromHistory('project-merge').result,
1553 'SUCCESS')
1554 self.assertEqual(self.getJobFromHistory('project-test1').result,
1555 'SUCCESS')
1556 self.assertEqual(self.getJobFromHistory('project-test2').result,
1557 'SUCCESS')
1558 self.assertEqual(A.data['status'], 'MERGED')
1559 self.assertEqual(A.reported, 2)
James E. Blairf62d4282012-12-31 17:01:50 -08001560
1561 def test_single_nonexistent_post_job(self):
1562 "Test launching a single post job that doesn't exist"
James E. Blairf62d4282012-12-31 17:01:50 -08001563 e = {
1564 "type": "ref-updated",
1565 "submitter": {
1566 "name": "User Name",
1567 },
1568 "refUpdate": {
1569 "oldRev": "90f173846e3af9154517b88543ffbd1691f31366",
1570 "newRev": "d479a0bfcb34da57a31adb2a595c0cf687812543",
1571 "refName": "master",
1572 "project": "org/project",
1573 }
1574 }
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001575 # Set to the state immediately after a restart
1576 self.resetGearmanServer()
1577 self.launcher.negative_function_cache_ttl = 0
1578
James E. Blairf62d4282012-12-31 17:01:50 -08001579 self.fake_gerrit.addEvent(e)
1580 self.waitUntilSettled()
1581
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001582 self.assertEqual(len(self.history), 0)
James E. Blair2fa50962013-01-30 21:50:41 -08001583
1584 def test_new_patchset_dequeues_old(self):
1585 "Test that a new patchset causes the old to be dequeued"
1586 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001587 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001588 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1589 M.setMerged()
1590
1591 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1592 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1593 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1594 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1595 A.addApproval('CRVW', 2)
1596 B.addApproval('CRVW', 2)
1597 C.addApproval('CRVW', 2)
1598 D.addApproval('CRVW', 2)
1599
1600 C.setDependsOn(B, 1)
1601 B.setDependsOn(A, 1)
1602 A.setDependsOn(M, 1)
1603
1604 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1605 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1606 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1607 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1608 self.waitUntilSettled()
1609
1610 B.addPatchset()
1611 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1612 self.waitUntilSettled()
1613
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001614 self.worker.hold_jobs_in_build = False
1615 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001616 self.waitUntilSettled()
1617
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001618 self.assertEqual(A.data['status'], 'MERGED')
1619 self.assertEqual(A.reported, 2)
1620 self.assertEqual(B.data['status'], 'NEW')
1621 self.assertEqual(B.reported, 2)
1622 self.assertEqual(C.data['status'], 'NEW')
1623 self.assertEqual(C.reported, 2)
1624 self.assertEqual(D.data['status'], 'MERGED')
1625 self.assertEqual(D.reported, 2)
1626 self.assertEqual(len(self.history), 9) # 3 each for A, B, D.
James E. Blair2fa50962013-01-30 21:50:41 -08001627
James E. Blairba437362015-02-07 11:41:52 -08001628 def test_new_patchset_check(self):
1629 "Test a new patchset in check"
Antoine Mussobd86a312014-01-08 14:51:33 +01001630
1631 self.worker.hold_jobs_in_build = True
1632
1633 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
James E. Blairba437362015-02-07 11:41:52 -08001634 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1635 check_pipeline = self.sched.layout.pipelines['check']
1636
1637 # Add two git-dependent changes
1638 B.setDependsOn(A, 1)
1639 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1640 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001641 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1642 self.waitUntilSettled()
James E. Blairba437362015-02-07 11:41:52 -08001643
1644 # A live item, and a non-live/live pair
1645 items = check_pipeline.getAllItems()
1646 self.assertEqual(len(items), 3)
1647
1648 self.assertEqual(items[0].change.number, '1')
1649 self.assertEqual(items[0].change.patchset, '1')
1650 self.assertFalse(items[0].live)
1651
1652 self.assertEqual(items[1].change.number, '2')
1653 self.assertEqual(items[1].change.patchset, '1')
1654 self.assertTrue(items[1].live)
1655
1656 self.assertEqual(items[2].change.number, '1')
1657 self.assertEqual(items[2].change.patchset, '1')
1658 self.assertTrue(items[2].live)
1659
1660 # Add a new patchset to A
1661 A.addPatchset()
1662 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1663 self.waitUntilSettled()
1664
1665 # The live copy of A,1 should be gone, but the non-live and B
1666 # should continue, and we should have a new A,2
1667 items = check_pipeline.getAllItems()
1668 self.assertEqual(len(items), 3)
1669
1670 self.assertEqual(items[0].change.number, '1')
1671 self.assertEqual(items[0].change.patchset, '1')
1672 self.assertFalse(items[0].live)
1673
1674 self.assertEqual(items[1].change.number, '2')
1675 self.assertEqual(items[1].change.patchset, '1')
1676 self.assertTrue(items[1].live)
1677
1678 self.assertEqual(items[2].change.number, '1')
1679 self.assertEqual(items[2].change.patchset, '2')
1680 self.assertTrue(items[2].live)
1681
1682 # Add a new patchset to B
1683 B.addPatchset()
1684 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1685 self.waitUntilSettled()
1686
1687 # The live copy of B,1 should be gone, and it's non-live copy of A,1
1688 # but we should have a new B,2 (still based on A,1)
1689 items = check_pipeline.getAllItems()
1690 self.assertEqual(len(items), 3)
1691
1692 self.assertEqual(items[0].change.number, '1')
1693 self.assertEqual(items[0].change.patchset, '2')
1694 self.assertTrue(items[0].live)
1695
1696 self.assertEqual(items[1].change.number, '1')
1697 self.assertEqual(items[1].change.patchset, '1')
1698 self.assertFalse(items[1].live)
1699
1700 self.assertEqual(items[2].change.number, '2')
1701 self.assertEqual(items[2].change.patchset, '2')
1702 self.assertTrue(items[2].live)
1703
1704 self.builds[0].release()
1705 self.waitUntilSettled()
1706 self.builds[0].release()
1707 self.waitUntilSettled()
1708 self.worker.hold_jobs_in_build = False
1709 self.worker.release()
1710 self.waitUntilSettled()
1711
1712 self.assertEqual(A.reported, 1)
1713 self.assertEqual(B.reported, 1)
1714 self.assertEqual(self.history[0].result, 'ABORTED')
1715 self.assertEqual(self.history[0].changes, '1,1')
1716 self.assertEqual(self.history[1].result, 'ABORTED')
1717 self.assertEqual(self.history[1].changes, '1,1 2,1')
1718 self.assertEqual(self.history[2].result, 'SUCCESS')
1719 self.assertEqual(self.history[2].changes, '1,2')
1720 self.assertEqual(self.history[3].result, 'SUCCESS')
1721 self.assertEqual(self.history[3].changes, '1,1 2,2')
1722
1723 def test_abandoned_gate(self):
1724 "Test that an abandoned change is dequeued from gate"
1725
1726 self.worker.hold_jobs_in_build = True
1727
1728 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1729 A.addApproval('CRVW', 2)
1730 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1731 self.waitUntilSettled()
Antoine Mussobd86a312014-01-08 14:51:33 +01001732 self.assertEqual(len(self.builds), 1, "One job being built (on hold)")
1733 self.assertEqual(self.builds[0].name, 'project-merge')
1734
1735 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1736 self.waitUntilSettled()
1737
Antoine Mussobd86a312014-01-08 14:51:33 +01001738 self.worker.release('.*-merge')
1739 self.waitUntilSettled()
1740
1741 self.assertEqual(len(self.builds), 0, "No job running")
Antoine Mussobd86a312014-01-08 14:51:33 +01001742 self.assertEqual(len(self.history), 1, "Only one build in history")
1743 self.assertEqual(self.history[0].result, 'ABORTED',
James E. Blairba437362015-02-07 11:41:52 -08001744 "Build should have been aborted")
1745 self.assertEqual(A.reported, 1,
1746 "Abandoned gate change should report only start")
1747
1748 def test_abandoned_check(self):
1749 "Test that an abandoned change is dequeued from check"
1750
1751 self.worker.hold_jobs_in_build = True
1752
1753 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1754 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1755 check_pipeline = self.sched.layout.pipelines['check']
1756
1757 # Add two git-dependent changes
1758 B.setDependsOn(A, 1)
1759 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1760 self.waitUntilSettled()
1761 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1762 self.waitUntilSettled()
1763 # A live item, and a non-live/live pair
1764 items = check_pipeline.getAllItems()
1765 self.assertEqual(len(items), 3)
1766
1767 self.assertEqual(items[0].change.number, '1')
1768 self.assertFalse(items[0].live)
1769
1770 self.assertEqual(items[1].change.number, '2')
1771 self.assertTrue(items[1].live)
1772
1773 self.assertEqual(items[2].change.number, '1')
1774 self.assertTrue(items[2].live)
1775
1776 # Abandon A
1777 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1778 self.waitUntilSettled()
1779
1780 # The live copy of A should be gone, but the non-live and B
1781 # should continue
1782 items = check_pipeline.getAllItems()
1783 self.assertEqual(len(items), 2)
1784
1785 self.assertEqual(items[0].change.number, '1')
1786 self.assertFalse(items[0].live)
1787
1788 self.assertEqual(items[1].change.number, '2')
1789 self.assertTrue(items[1].live)
1790
1791 self.worker.hold_jobs_in_build = False
1792 self.worker.release()
1793 self.waitUntilSettled()
1794
1795 self.assertEqual(len(self.history), 4)
1796 self.assertEqual(self.history[0].result, 'ABORTED',
Antoine Mussobd86a312014-01-08 14:51:33 +01001797 'Build should have been aborted')
1798 self.assertEqual(A.reported, 0, "Abandoned change should not report")
James E. Blairba437362015-02-07 11:41:52 -08001799 self.assertEqual(B.reported, 1, "Change should report")
Antoine Mussobd86a312014-01-08 14:51:33 +01001800
Steve Varnau7b78b312015-04-03 14:49:46 -07001801 def test_abandoned_not_timer(self):
1802 "Test that an abandoned change does not cancel timer jobs"
1803
1804 self.worker.hold_jobs_in_build = True
1805
1806 # Start timer trigger - also org/project
1807 self.config.set('zuul', 'layout_config',
1808 'tests/fixtures/layout-idle.yaml')
1809 self.sched.reconfigure(self.config)
1810 self.registerJobs()
1811 # The pipeline triggers every second, so we should have seen
1812 # several by now.
1813 time.sleep(5)
1814 self.waitUntilSettled()
1815 # Stop queuing timer triggered jobs so that the assertions
1816 # below don't race against more jobs being queued.
1817 self.config.set('zuul', 'layout_config',
1818 'tests/fixtures/layout-no-timer.yaml')
1819 self.sched.reconfigure(self.config)
1820 self.registerJobs()
1821 self.assertEqual(len(self.builds), 2, "Two timer jobs")
1822
1823 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1824 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1825 self.waitUntilSettled()
1826 self.assertEqual(len(self.builds), 3, "One change plus two timer jobs")
1827
1828 self.fake_gerrit.addEvent(A.getChangeAbandonedEvent())
1829 self.waitUntilSettled()
1830
1831 self.assertEqual(len(self.builds), 2, "Two timer jobs remain")
1832
1833 self.worker.release()
1834 self.waitUntilSettled()
1835
Arx Cruzb1b010d2013-10-28 19:49:59 -02001836 def test_zuul_url_return(self):
1837 "Test if ZUUL_URL is returning when zuul_url is set in zuul.conf"
James E. Blair4076e2b2014-01-28 12:42:20 -08001838 self.assertTrue(self.sched.config.has_option('merger', 'zuul_url'))
Arx Cruzb1b010d2013-10-28 19:49:59 -02001839 self.worker.hold_jobs_in_build = True
1840
1841 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1842 A.addApproval('CRVW', 2)
1843 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1844 self.waitUntilSettled()
1845
1846 self.assertEqual(len(self.builds), 1)
1847 for build in self.builds:
1848 self.assertTrue('ZUUL_URL' in build.parameters)
1849
1850 self.worker.hold_jobs_in_build = False
1851 self.worker.release()
1852 self.waitUntilSettled()
1853
James E. Blair2fa50962013-01-30 21:50:41 -08001854 def test_new_patchset_dequeues_old_on_head(self):
1855 "Test that a new patchset causes the old to be dequeued (at head)"
1856 # D -> C (depends on B) -> B (depends on A) -> A -> M
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001857 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001858 M = self.fake_gerrit.addFakeChange('org/project', 'master', 'M')
1859 M.setMerged()
1860 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1861 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1862 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1863 D = self.fake_gerrit.addFakeChange('org/project', 'master', 'D')
1864 A.addApproval('CRVW', 2)
1865 B.addApproval('CRVW', 2)
1866 C.addApproval('CRVW', 2)
1867 D.addApproval('CRVW', 2)
1868
1869 C.setDependsOn(B, 1)
1870 B.setDependsOn(A, 1)
1871 A.setDependsOn(M, 1)
1872
1873 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1874 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1875 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1876 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
1877 self.waitUntilSettled()
1878
1879 A.addPatchset()
1880 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
1881 self.waitUntilSettled()
1882
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001883 self.worker.hold_jobs_in_build = False
1884 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001885 self.waitUntilSettled()
1886
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001887 self.assertEqual(A.data['status'], 'NEW')
1888 self.assertEqual(A.reported, 2)
1889 self.assertEqual(B.data['status'], 'NEW')
1890 self.assertEqual(B.reported, 2)
1891 self.assertEqual(C.data['status'], 'NEW')
1892 self.assertEqual(C.reported, 2)
1893 self.assertEqual(D.data['status'], 'MERGED')
1894 self.assertEqual(D.reported, 2)
1895 self.assertEqual(len(self.history), 7)
James E. Blair2fa50962013-01-30 21:50:41 -08001896
1897 def test_new_patchset_dequeues_old_without_dependents(self):
1898 "Test that a new patchset causes only the old to be dequeued"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001899 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001900 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1901 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1902 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1903 A.addApproval('CRVW', 2)
1904 B.addApproval('CRVW', 2)
1905 C.addApproval('CRVW', 2)
1906
1907 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
1908 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
1909 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1910 self.waitUntilSettled()
1911
1912 B.addPatchset()
1913 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1914 self.waitUntilSettled()
1915
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001916 self.worker.hold_jobs_in_build = False
1917 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001918 self.waitUntilSettled()
1919
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001920 self.assertEqual(A.data['status'], 'MERGED')
1921 self.assertEqual(A.reported, 2)
1922 self.assertEqual(B.data['status'], 'NEW')
1923 self.assertEqual(B.reported, 2)
1924 self.assertEqual(C.data['status'], 'MERGED')
1925 self.assertEqual(C.reported, 2)
1926 self.assertEqual(len(self.history), 9)
James E. Blair2fa50962013-01-30 21:50:41 -08001927
1928 def test_new_patchset_dequeues_old_independent_queue(self):
1929 "Test that a new patchset causes the old to be dequeued (independent)"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001930 self.worker.hold_jobs_in_build = True
James E. Blair2fa50962013-01-30 21:50:41 -08001931 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
1932 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
1933 C = self.fake_gerrit.addFakeChange('org/project', 'master', 'C')
1934 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1935 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
1936 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
1937 self.waitUntilSettled()
1938
1939 B.addPatchset()
1940 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(2))
1941 self.waitUntilSettled()
1942
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001943 self.worker.hold_jobs_in_build = False
1944 self.worker.release()
James E. Blair2fa50962013-01-30 21:50:41 -08001945 self.waitUntilSettled()
1946
Monty Taylor98f0f3e2013-07-06 16:02:31 -04001947 self.assertEqual(A.data['status'], 'NEW')
1948 self.assertEqual(A.reported, 1)
1949 self.assertEqual(B.data['status'], 'NEW')
1950 self.assertEqual(B.reported, 1)
1951 self.assertEqual(C.data['status'], 'NEW')
1952 self.assertEqual(C.reported, 1)
1953 self.assertEqual(len(self.history), 10)
1954 self.assertEqual(self.countJobResults(self.history, 'ABORTED'), 1)
James E. Blair7d0dedc2013-02-21 17:26:09 -08001955
James E. Blair18c64442014-03-18 10:14:45 -07001956 def test_noop_job(self):
1957 "Test that the internal noop job works"
1958 A = self.fake_gerrit.addFakeChange('org/noop-project', 'master', 'A')
1959 A.addApproval('CRVW', 2)
1960 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
1961 self.waitUntilSettled()
1962
1963 self.assertEqual(len(self.gearman_server.getQueue()), 0)
1964 self.assertTrue(self.sched._areAllBuildsComplete())
1965 self.assertEqual(len(self.history), 0)
1966 self.assertEqual(A.data['status'], 'MERGED')
1967 self.assertEqual(A.reported, 2)
1968
Evgeny Antyshevd6e546c2015-06-11 15:13:57 +00001969 def test_no_job_project(self):
1970 "Test that reports with no jobs don't get sent"
1971 A = self.fake_gerrit.addFakeChange('org/no-jobs-project',
1972 'master', 'A')
1973 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
1974 self.waitUntilSettled()
1975
1976 # Change wasn't reported to
1977 self.assertEqual(A.reported, False)
1978
1979 # Check queue is empty afterwards
1980 check_pipeline = self.sched.layout.pipelines['check']
1981 items = check_pipeline.getAllItems()
1982 self.assertEqual(len(items), 0)
1983
1984 self.assertEqual(len(self.history), 0)
1985
James E. Blair7d0dedc2013-02-21 17:26:09 -08001986 def test_zuul_refs(self):
1987 "Test that zuul refs exist and have the right changes"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07001988 self.worker.hold_jobs_in_build = True
James E. Blair7d0dedc2013-02-21 17:26:09 -08001989 M1 = self.fake_gerrit.addFakeChange('org/project1', 'master', 'M1')
1990 M1.setMerged()
1991 M2 = self.fake_gerrit.addFakeChange('org/project2', 'master', 'M2')
1992 M2.setMerged()
1993
1994 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
1995 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
1996 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
1997 D = self.fake_gerrit.addFakeChange('org/project2', 'master', 'D')
1998 A.addApproval('CRVW', 2)
1999 B.addApproval('CRVW', 2)
2000 C.addApproval('CRVW', 2)
2001 D.addApproval('CRVW', 2)
2002 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2003 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2004 self.fake_gerrit.addEvent(C.addApproval('APRV', 1))
2005 self.fake_gerrit.addEvent(D.addApproval('APRV', 1))
2006
2007 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002008 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002009 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002010 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002011 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002012 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002013 self.waitUntilSettled()
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002014 self.worker.release('.*-merge')
James E. Blair7d0dedc2013-02-21 17:26:09 -08002015 self.waitUntilSettled()
2016
James E. Blair7d0dedc2013-02-21 17:26:09 -08002017 a_zref = b_zref = c_zref = d_zref = None
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002018 for x in self.builds:
James E. Blair7d0dedc2013-02-21 17:26:09 -08002019 if x.parameters['ZUUL_CHANGE'] == '3':
2020 a_zref = x.parameters['ZUUL_REF']
2021 if x.parameters['ZUUL_CHANGE'] == '4':
2022 b_zref = x.parameters['ZUUL_REF']
2023 if x.parameters['ZUUL_CHANGE'] == '5':
2024 c_zref = x.parameters['ZUUL_REF']
2025 if x.parameters['ZUUL_CHANGE'] == '6':
2026 d_zref = x.parameters['ZUUL_REF']
2027
2028 # There are... four... refs.
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002029 self.assertIsNotNone(a_zref)
2030 self.assertIsNotNone(b_zref)
2031 self.assertIsNotNone(c_zref)
2032 self.assertIsNotNone(d_zref)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002033
2034 # And they should all be different
2035 refs = set([a_zref, b_zref, c_zref, d_zref])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002036 self.assertEqual(len(refs), 4)
James E. Blair7d0dedc2013-02-21 17:26:09 -08002037
2038 # a ref should have a, not b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002039 self.assertTrue(self.ref_has_change(a_zref, A))
2040 self.assertFalse(self.ref_has_change(a_zref, B))
2041 self.assertFalse(self.ref_has_change(a_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002042
2043 # b ref should have a and b, and should not be in project2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002044 self.assertTrue(self.ref_has_change(b_zref, A))
2045 self.assertTrue(self.ref_has_change(b_zref, B))
2046 self.assertFalse(self.ref_has_change(b_zref, M2))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002047
2048 # c ref should have a and b in 1, c in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002049 self.assertTrue(self.ref_has_change(c_zref, A))
2050 self.assertTrue(self.ref_has_change(c_zref, B))
2051 self.assertTrue(self.ref_has_change(c_zref, C))
2052 self.assertFalse(self.ref_has_change(c_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002053
2054 # d ref should have a and b in 1, c and d in 2
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002055 self.assertTrue(self.ref_has_change(d_zref, A))
2056 self.assertTrue(self.ref_has_change(d_zref, B))
2057 self.assertTrue(self.ref_has_change(d_zref, C))
2058 self.assertTrue(self.ref_has_change(d_zref, D))
James E. Blair7d0dedc2013-02-21 17:26:09 -08002059
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002060 self.worker.hold_jobs_in_build = False
2061 self.worker.release()
James E. Blair7d0dedc2013-02-21 17:26:09 -08002062 self.waitUntilSettled()
2063
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002064 self.assertEqual(A.data['status'], 'MERGED')
2065 self.assertEqual(A.reported, 2)
2066 self.assertEqual(B.data['status'], 'MERGED')
2067 self.assertEqual(B.reported, 2)
2068 self.assertEqual(C.data['status'], 'MERGED')
2069 self.assertEqual(C.reported, 2)
2070 self.assertEqual(D.data['status'], 'MERGED')
2071 self.assertEqual(D.reported, 2)
James E. Blair70c71582013-03-06 08:50:50 -08002072
James E. Blair4a28a882013-08-23 15:17:33 -07002073 def test_rerun_on_error(self):
2074 "Test that if a worker fails to run a job, it is run again"
2075 self.worker.hold_jobs_in_build = True
2076 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2077 A.addApproval('CRVW', 2)
2078 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2079 self.waitUntilSettled()
2080
2081 self.builds[0].run_error = True
2082 self.worker.hold_jobs_in_build = False
2083 self.worker.release()
2084 self.waitUntilSettled()
2085 self.assertEqual(self.countJobResults(self.history, 'RUN_ERROR'), 1)
2086 self.assertEqual(self.countJobResults(self.history, 'SUCCESS'), 3)
2087
James E. Blair412e5582013-04-22 15:50:12 -07002088 def test_statsd(self):
2089 "Test each of the statsd methods used in the scheduler"
2090 import extras
2091 statsd = extras.try_import('statsd.statsd')
2092 statsd.incr('test-incr')
2093 statsd.timing('test-timing', 3)
Alex Gaynor813d39b2014-05-17 16:17:16 -07002094 statsd.gauge('test-gauge', 12)
James E. Blair412e5582013-04-22 15:50:12 -07002095 self.assertReportedStat('test-incr', '1|c')
2096 self.assertReportedStat('test-timing', '3|ms')
Alex Gaynor813d39b2014-05-17 16:17:16 -07002097 self.assertReportedStat('test-gauge', '12|g')
James E. Blair412e5582013-04-22 15:50:12 -07002098
James E. Blairdad52252014-02-07 16:59:17 -08002099 def test_stuck_job_cleanup(self):
2100 "Test that pending jobs are cleaned up if removed from layout"
James E. Blair18c64442014-03-18 10:14:45 -07002101 # This job won't be registered at startup because it is not in
2102 # the standard layout, but we need it to already be registerd
2103 # for when we reconfigure, as that is when Zuul will attempt
2104 # to run the new job.
2105 self.worker.registerFunction('build:gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002106 self.gearman_server.hold_jobs_in_queue = True
2107 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2108 A.addApproval('CRVW', 2)
2109 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2110 self.waitUntilSettled()
2111 self.assertEqual(len(self.gearman_server.getQueue()), 1)
2112
2113 self.config.set('zuul', 'layout_config',
2114 'tests/fixtures/layout-no-jobs.yaml')
2115 self.sched.reconfigure(self.config)
2116 self.waitUntilSettled()
2117
James E. Blair18c64442014-03-18 10:14:45 -07002118 self.gearman_server.release('gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002119 self.waitUntilSettled()
2120 self.assertEqual(len(self.gearman_server.getQueue()), 0)
2121 self.assertTrue(self.sched._areAllBuildsComplete())
2122
2123 self.assertEqual(len(self.history), 1)
James E. Blair18c64442014-03-18 10:14:45 -07002124 self.assertEqual(self.history[0].name, 'gate-noop')
James E. Blairdad52252014-02-07 16:59:17 -08002125 self.assertEqual(self.history[0].result, 'SUCCESS')
2126
James E. Blair879dafb2015-07-17 14:04:49 -07002127 def test_file_head(self):
2128 # This is a regression test for an observed bug. A change
2129 # with a file named "HEAD" in the root directory of the repo
2130 # was processed by a merger. It then was unable to reset the
2131 # repo because of:
2132 # GitCommandError: 'git reset --hard HEAD' returned
2133 # with exit code 128
2134 # stderr: 'fatal: ambiguous argument 'HEAD': both revision
2135 # and filename
2136 # Use '--' to separate filenames from revisions'
2137
2138 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2139 A.addPatchset(['HEAD'])
2140 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2141
2142 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(2))
2143 self.waitUntilSettled()
2144
2145 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2146 self.waitUntilSettled()
2147
2148 self.assertIn('Build succeeded', A.messages[0])
2149 self.assertIn('Build succeeded', B.messages[0])
2150
James E. Blair70c71582013-03-06 08:50:50 -08002151 def test_file_jobs(self):
2152 "Test that file jobs run only when appropriate"
2153 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2154 A.addPatchset(['pip-requires'])
2155 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2156 A.addApproval('CRVW', 2)
2157 B.addApproval('CRVW', 2)
2158 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2159 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2160 self.waitUntilSettled()
2161
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002162 testfile_jobs = [x for x in self.history
James E. Blair70c71582013-03-06 08:50:50 -08002163 if x.name == 'project-testfile']
2164
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002165 self.assertEqual(len(testfile_jobs), 1)
2166 self.assertEqual(testfile_jobs[0].changes, '1,2')
2167 self.assertEqual(A.data['status'], 'MERGED')
2168 self.assertEqual(A.reported, 2)
2169 self.assertEqual(B.data['status'], 'MERGED')
2170 self.assertEqual(B.reported, 2)
James E. Blair3c5e5b52013-04-26 11:17:03 -07002171
Maru Newby3fe5f852015-01-13 04:22:14 +00002172 def _test_skip_if_jobs(self, branch, should_skip):
2173 "Test that jobs with a skip-if filter run only when appropriate"
2174 self.config.set('zuul', 'layout_config',
2175 'tests/fixtures/layout-skip-if.yaml')
2176 self.sched.reconfigure(self.config)
2177 self.registerJobs()
2178
2179 change = self.fake_gerrit.addFakeChange('org/project',
2180 branch,
2181 'test skip-if')
2182 self.fake_gerrit.addEvent(change.getPatchsetCreatedEvent(1))
2183 self.waitUntilSettled()
2184
2185 tested_change_ids = [x.changes[0] for x in self.history
2186 if x.name == 'project-test-skip-if']
2187
2188 if should_skip:
2189 self.assertEqual([], tested_change_ids)
2190 else:
2191 self.assertIn(change.data['number'], tested_change_ids)
2192
2193 def test_skip_if_match_skips_job(self):
2194 self._test_skip_if_jobs(branch='master', should_skip=True)
2195
2196 def test_skip_if_no_match_runs_job(self):
2197 self._test_skip_if_jobs(branch='mp', should_skip=False)
2198
James E. Blair3c5e5b52013-04-26 11:17:03 -07002199 def test_test_config(self):
2200 "Test that we can test the config"
Joshua Hesketh352264b2015-08-11 23:42:08 +10002201 self.sched.testConfig(self.config.get('zuul', 'layout_config'),
2202 self.connections)
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002203
2204 def test_build_description(self):
2205 "Test that build descriptions update"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002206 self.worker.registerFunction('set_description:' +
2207 self.worker.worker_id)
2208
2209 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2210 A.addApproval('CRVW', 2)
2211 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2212 self.waitUntilSettled()
Monty Taylor6bef8ef2013-06-02 08:17:12 -04002213 desc = self.history[0].description
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002214 self.log.debug("Description: %s" % desc)
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002215 self.assertTrue(re.search("Branch.*master", desc))
2216 self.assertTrue(re.search("Pipeline.*gate", desc))
2217 self.assertTrue(re.search("project-merge.*SUCCESS", desc))
2218 self.assertTrue(re.search("project-test1.*SUCCESS", desc))
2219 self.assertTrue(re.search("project-test2.*SUCCESS", desc))
2220 self.assertTrue(re.search("Reported result.*SUCCESS", desc))
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002221
James E. Blairc8a1e052014-02-25 09:29:26 -08002222 def test_queue_names(self):
2223 "Test shared change queue names"
2224 project1 = self.sched.layout.projects['org/project1']
2225 project2 = self.sched.layout.projects['org/project2']
2226 q1 = self.sched.layout.pipelines['gate'].getQueue(project1)
2227 q2 = self.sched.layout.pipelines['gate'].getQueue(project2)
2228 self.assertEqual(q1.name, 'integration')
2229 self.assertEqual(q2.name, 'integration')
2230
2231 self.config.set('zuul', 'layout_config',
2232 'tests/fixtures/layout-bad-queue.yaml')
2233 with testtools.ExpectedException(
2234 Exception, "More than one name assigned to change queue"):
2235 self.sched.reconfigure(self.config)
2236
James E. Blair64ed6f22013-07-10 14:07:23 -07002237 def test_queue_precedence(self):
2238 "Test that queue precedence works"
2239
2240 self.gearman_server.hold_jobs_in_queue = True
James E. Blair8de58bd2013-07-18 16:23:33 -07002241 self.worker.hold_jobs_in_build = True
James E. Blair64ed6f22013-07-10 14:07:23 -07002242 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2243 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2244 A.addApproval('CRVW', 2)
2245 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2246
2247 self.waitUntilSettled()
2248 self.gearman_server.hold_jobs_in_queue = False
2249 self.gearman_server.release()
2250 self.waitUntilSettled()
2251
James E. Blair8de58bd2013-07-18 16:23:33 -07002252 # Run one build at a time to ensure non-race order:
James E. Blairb8c16472015-05-05 14:55:26 -07002253 self.orderedRelease()
James E. Blair8de58bd2013-07-18 16:23:33 -07002254 self.worker.hold_jobs_in_build = False
2255 self.waitUntilSettled()
2256
James E. Blair64ed6f22013-07-10 14:07:23 -07002257 self.log.debug(self.history)
2258 self.assertEqual(self.history[0].pipeline, 'gate')
2259 self.assertEqual(self.history[1].pipeline, 'check')
2260 self.assertEqual(self.history[2].pipeline, 'gate')
2261 self.assertEqual(self.history[3].pipeline, 'gate')
2262 self.assertEqual(self.history[4].pipeline, 'check')
2263 self.assertEqual(self.history[5].pipeline, 'check')
2264
Clark Boylana5edbe42014-06-03 16:39:10 -07002265 def test_json_status(self):
James E. Blair1843a552013-07-03 14:19:52 -07002266 "Test that we can retrieve JSON status info"
2267 self.worker.hold_jobs_in_build = True
2268 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2269 A.addApproval('CRVW', 2)
2270 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2271 self.waitUntilSettled()
2272
James E. Blairb7273ef2016-04-19 08:58:51 -07002273 self.worker.release('project-merge')
2274 self.waitUntilSettled()
2275
James E. Blair1843a552013-07-03 14:19:52 -07002276 port = self.webapp.server.socket.getsockname()[1]
2277
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002278 req = urllib2.Request("http://localhost:%s/status.json" % port)
Yuriy Taradaya6d452f2014-04-16 12:36:20 +04002279 f = urllib2.urlopen(req)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002280 headers = f.info()
2281 self.assertIn('Content-Length', headers)
2282 self.assertIn('Content-Type', headers)
Sachi Kingdc963fc2016-03-23 16:00:33 +11002283 self.assertIsNotNone(re.match('^application/json(; charset=UTF-8)?$',
2284 headers['Content-Type']))
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002285 self.assertIn('Access-Control-Allow-Origin', headers)
2286 self.assertIn('Cache-Control', headers)
Clark Boylanaa4f2e72014-06-03 21:22:40 -07002287 self.assertIn('Last-Modified', headers)
Timo Tijhof0ebd2932015-04-02 12:11:21 +01002288 self.assertIn('Expires', headers)
James E. Blair1843a552013-07-03 14:19:52 -07002289 data = f.read()
2290
2291 self.worker.hold_jobs_in_build = False
2292 self.worker.release()
2293 self.waitUntilSettled()
2294
2295 data = json.loads(data)
James E. Blairb7273ef2016-04-19 08:58:51 -07002296 status_jobs = []
James E. Blair1843a552013-07-03 14:19:52 -07002297 for p in data['pipelines']:
2298 for q in p['change_queues']:
James E. Blairbfb8e042014-12-30 17:01:44 -08002299 if p['name'] in ['gate', 'conflict']:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002300 self.assertEqual(q['window'], 20)
2301 else:
2302 self.assertEqual(q['window'], 0)
James E. Blair1843a552013-07-03 14:19:52 -07002303 for head in q['heads']:
2304 for change in head:
Clark Boylanaf2476f2014-01-23 14:47:36 -08002305 self.assertTrue(change['active'])
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002306 self.assertEqual(change['id'], '1,1')
James E. Blair1843a552013-07-03 14:19:52 -07002307 for job in change['jobs']:
James E. Blairb7273ef2016-04-19 08:58:51 -07002308 status_jobs.append(job)
2309 self.assertEqual('project-merge', status_jobs[0]['name'])
2310 self.assertEqual('https://server/job/project-merge/0/',
2311 status_jobs[0]['url'])
2312 self.assertEqual('http://logs.example.com/1/1/gate/project-merge/0',
2313 status_jobs[0]['report_url'])
2314
2315 self.assertEqual('project-test1', status_jobs[1]['name'])
2316 self.assertEqual('https://server/job/project-test1/1/',
2317 status_jobs[1]['url'])
2318 self.assertEqual('http://logs.example.com/1/1/gate/project-test1/1',
2319 status_jobs[1]['report_url'])
2320
2321 self.assertEqual('project-test2', status_jobs[2]['name'])
2322 self.assertEqual('https://server/job/project-test2/2/',
2323 status_jobs[2]['url'])
2324 self.assertEqual('http://logs.example.com/1/1/gate/project-test2/2',
2325 status_jobs[2]['report_url'])
James E. Blair1843a552013-07-03 14:19:52 -07002326
James E. Blairc3d428e2013-12-03 15:06:48 -08002327 def test_merging_queues(self):
2328 "Test that transitively-connected change queues are merged"
2329 self.config.set('zuul', 'layout_config',
2330 'tests/fixtures/layout-merge-queues.yaml')
2331 self.sched.reconfigure(self.config)
2332 self.assertEqual(len(self.sched.layout.pipelines['gate'].queues), 1)
2333
James E. Blairaf17a972016-02-03 15:07:18 -08002334 def test_mutex(self):
2335 "Test job mutexes"
2336 self.config.set('zuul', 'layout_config',
2337 'tests/fixtures/layout-mutex.yaml')
2338 self.sched.reconfigure(self.config)
2339
2340 self.worker.hold_jobs_in_build = True
2341 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2342 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2343 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2344
2345 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2346 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2347 self.waitUntilSettled()
2348 self.assertEqual(len(self.builds), 3)
2349 self.assertEqual(self.builds[0].name, 'project-test1')
2350 self.assertEqual(self.builds[1].name, 'mutex-one')
2351 self.assertEqual(self.builds[2].name, 'project-test1')
2352
2353 self.worker.release('mutex-one')
2354 self.waitUntilSettled()
2355
2356 self.assertEqual(len(self.builds), 3)
2357 self.assertEqual(self.builds[0].name, 'project-test1')
2358 self.assertEqual(self.builds[1].name, 'project-test1')
2359 self.assertEqual(self.builds[2].name, 'mutex-two')
2360 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2361
2362 self.worker.release('mutex-two')
2363 self.waitUntilSettled()
2364
2365 self.assertEqual(len(self.builds), 3)
2366 self.assertEqual(self.builds[0].name, 'project-test1')
2367 self.assertEqual(self.builds[1].name, 'project-test1')
2368 self.assertEqual(self.builds[2].name, 'mutex-one')
2369 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2370
2371 self.worker.release('mutex-one')
2372 self.waitUntilSettled()
2373
2374 self.assertEqual(len(self.builds), 3)
2375 self.assertEqual(self.builds[0].name, 'project-test1')
2376 self.assertEqual(self.builds[1].name, 'project-test1')
2377 self.assertEqual(self.builds[2].name, 'mutex-two')
2378 self.assertTrue('test-mutex' in self.sched.mutex.mutexes)
2379
2380 self.worker.release('mutex-two')
2381 self.waitUntilSettled()
2382
2383 self.assertEqual(len(self.builds), 2)
2384 self.assertEqual(self.builds[0].name, 'project-test1')
2385 self.assertEqual(self.builds[1].name, 'project-test1')
2386 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2387
2388 self.worker.hold_jobs_in_build = False
2389 self.worker.release()
2390
2391 self.waitUntilSettled()
2392 self.assertEqual(len(self.builds), 0)
2393
2394 self.assertEqual(A.reported, 1)
2395 self.assertEqual(B.reported, 1)
2396 self.assertFalse('test-mutex' in self.sched.mutex.mutexes)
2397
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002398 def test_node_label(self):
2399 "Test that a job runs on a specific node label"
James E. Blair1f4c2bb2013-04-26 08:40:46 -07002400 self.worker.registerFunction('build:node-project-test1:debian')
2401
2402 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2403 A.addApproval('CRVW', 2)
2404 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2405 self.waitUntilSettled()
James E. Blair4ca985f2013-05-30 12:27:43 -07002406
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002407 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2408 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2409 'debian')
2410 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
James E. Blaircdccd972013-07-01 12:10:22 -07002411
2412 def test_live_reconfiguration(self):
2413 "Test that live reconfiguration works"
2414 self.worker.hold_jobs_in_build = True
2415 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2416 A.addApproval('CRVW', 2)
2417 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2418 self.waitUntilSettled()
2419
2420 self.sched.reconfigure(self.config)
2421
2422 self.worker.hold_jobs_in_build = False
2423 self.worker.release()
2424 self.waitUntilSettled()
Monty Taylor98f0f3e2013-07-06 16:02:31 -04002425 self.assertEqual(self.getJobFromHistory('project-merge').result,
2426 'SUCCESS')
2427 self.assertEqual(self.getJobFromHistory('project-test1').result,
2428 'SUCCESS')
2429 self.assertEqual(self.getJobFromHistory('project-test2').result,
2430 'SUCCESS')
2431 self.assertEqual(A.data['status'], 'MERGED')
2432 self.assertEqual(A.reported, 2)
James E. Blair287c06d2013-07-24 10:39:30 -07002433
James E. Blair6bc782d2015-07-17 16:20:21 -07002434 def test_live_reconfiguration_merge_conflict(self):
2435 # A real-world bug: a change in a gate queue has a merge
2436 # conflict and a job is added to its project while it's
2437 # sitting in the queue. The job gets added to the change and
2438 # enqueued and the change gets stuck.
2439 self.worker.registerFunction('build:project-test3')
2440 self.worker.hold_jobs_in_build = True
2441
2442 # This change is fine. It's here to stop the queue long
2443 # enough for the next change to be subject to the
2444 # reconfiguration, as well as to provide a conflict for the
2445 # next change. This change will succeed and merge.
2446 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2447 A.addPatchset(['conflict'])
2448 A.addApproval('CRVW', 2)
James E. Blair6bc782d2015-07-17 16:20:21 -07002449
2450 # This change will be in merge conflict. During the
2451 # reconfiguration, we will add a job. We want to make sure
2452 # that doesn't cause it to get stuck.
2453 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2454 B.addPatchset(['conflict'])
2455 B.addApproval('CRVW', 2)
James E. Blair4eb21fa2015-07-27 14:56:47 -07002456
2457 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
James E. Blair6bc782d2015-07-17 16:20:21 -07002458 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2459
2460 self.waitUntilSettled()
2461
2462 # No jobs have run yet
2463 self.assertEqual(A.data['status'], 'NEW')
2464 self.assertEqual(A.reported, 1)
2465 self.assertEqual(B.data['status'], 'NEW')
2466 self.assertEqual(B.reported, 1)
2467 self.assertEqual(len(self.history), 0)
2468
2469 # Add the "project-test3" job.
2470 self.config.set('zuul', 'layout_config',
2471 'tests/fixtures/layout-live-'
2472 'reconfiguration-add-job.yaml')
2473 self.sched.reconfigure(self.config)
2474 self.waitUntilSettled()
2475
2476 self.worker.hold_jobs_in_build = False
2477 self.worker.release()
2478 self.waitUntilSettled()
2479
2480 self.assertEqual(A.data['status'], 'MERGED')
2481 self.assertEqual(A.reported, 2)
2482 self.assertEqual(B.data['status'], 'NEW')
2483 self.assertEqual(B.reported, 2)
2484 self.assertEqual(self.getJobFromHistory('project-merge').result,
2485 'SUCCESS')
2486 self.assertEqual(self.getJobFromHistory('project-test1').result,
2487 'SUCCESS')
2488 self.assertEqual(self.getJobFromHistory('project-test2').result,
2489 'SUCCESS')
2490 self.assertEqual(self.getJobFromHistory('project-test3').result,
2491 'SUCCESS')
2492 self.assertEqual(len(self.history), 4)
2493
James E. Blair400e8fd2015-07-30 17:44:45 -07002494 def test_live_reconfiguration_failed_root(self):
James E. Blair6bc782d2015-07-17 16:20:21 -07002495 # An extrapolation of test_live_reconfiguration_merge_conflict
2496 # that tests a job added to a job tree with a failed root does
2497 # not run.
2498 self.worker.registerFunction('build:project-test3')
2499 self.worker.hold_jobs_in_build = True
2500
2501 # This change is fine. It's here to stop the queue long
2502 # enough for the next change to be subject to the
2503 # reconfiguration. This change will succeed and merge.
2504 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2505 A.addPatchset(['conflict'])
2506 A.addApproval('CRVW', 2)
2507 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2508 self.waitUntilSettled()
2509 self.worker.release('.*-merge')
2510 self.waitUntilSettled()
2511
2512 B = self.fake_gerrit.addFakeChange('org/project', 'master', 'B')
2513 self.worker.addFailTest('project-merge', B)
2514 B.addApproval('CRVW', 2)
2515 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2516 self.waitUntilSettled()
2517
2518 self.worker.release('.*-merge')
2519 self.waitUntilSettled()
2520
2521 # Both -merge jobs have run, but no others.
2522 self.assertEqual(A.data['status'], 'NEW')
2523 self.assertEqual(A.reported, 1)
2524 self.assertEqual(B.data['status'], 'NEW')
2525 self.assertEqual(B.reported, 1)
2526 self.assertEqual(self.history[0].result, 'SUCCESS')
2527 self.assertEqual(self.history[0].name, 'project-merge')
2528 self.assertEqual(self.history[1].result, 'FAILURE')
2529 self.assertEqual(self.history[1].name, 'project-merge')
2530 self.assertEqual(len(self.history), 2)
2531
2532 # Add the "project-test3" job.
2533 self.config.set('zuul', 'layout_config',
2534 'tests/fixtures/layout-live-'
2535 'reconfiguration-add-job.yaml')
2536 self.sched.reconfigure(self.config)
2537 self.waitUntilSettled()
2538
2539 self.worker.hold_jobs_in_build = False
2540 self.worker.release()
2541 self.waitUntilSettled()
2542
2543 self.assertEqual(A.data['status'], 'MERGED')
2544 self.assertEqual(A.reported, 2)
2545 self.assertEqual(B.data['status'], 'NEW')
2546 self.assertEqual(B.reported, 2)
2547 self.assertEqual(self.history[0].result, 'SUCCESS')
2548 self.assertEqual(self.history[0].name, 'project-merge')
2549 self.assertEqual(self.history[1].result, 'FAILURE')
2550 self.assertEqual(self.history[1].name, 'project-merge')
2551 self.assertEqual(self.history[2].result, 'SUCCESS')
2552 self.assertEqual(self.history[3].result, 'SUCCESS')
2553 self.assertEqual(self.history[4].result, 'SUCCESS')
2554 self.assertEqual(len(self.history), 5)
2555
James E. Blair400e8fd2015-07-30 17:44:45 -07002556 def test_live_reconfiguration_failed_job(self):
2557 # Test that a change with a removed failing job does not
2558 # disrupt reconfiguration. If a change has a failed job and
2559 # that job is removed during a reconfiguration, we observed a
2560 # bug where the code to re-set build statuses would run on
2561 # that build and raise an exception because the job no longer
2562 # existed.
2563 self.worker.hold_jobs_in_build = True
2564
2565 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2566
2567 # This change will fail and later be removed by the reconfiguration.
2568 self.worker.addFailTest('project-test1', A)
2569
2570 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2571 self.waitUntilSettled()
2572 self.worker.release('.*-merge')
2573 self.waitUntilSettled()
2574 self.worker.release('project-test1')
2575 self.waitUntilSettled()
2576
2577 self.assertEqual(A.data['status'], 'NEW')
2578 self.assertEqual(A.reported, 0)
2579
2580 self.assertEqual(self.getJobFromHistory('project-merge').result,
2581 'SUCCESS')
2582 self.assertEqual(self.getJobFromHistory('project-test1').result,
2583 'FAILURE')
2584 self.assertEqual(len(self.history), 2)
2585
2586 # Remove the test1 job.
2587 self.config.set('zuul', 'layout_config',
2588 'tests/fixtures/layout-live-'
2589 'reconfiguration-failed-job.yaml')
2590 self.sched.reconfigure(self.config)
2591 self.waitUntilSettled()
2592
2593 self.worker.hold_jobs_in_build = False
2594 self.worker.release()
2595 self.waitUntilSettled()
2596
2597 self.assertEqual(self.getJobFromHistory('project-test2').result,
2598 'SUCCESS')
2599 self.assertEqual(self.getJobFromHistory('project-testfile').result,
2600 'SUCCESS')
2601 self.assertEqual(len(self.history), 4)
2602
2603 self.assertEqual(A.data['status'], 'NEW')
2604 self.assertEqual(A.reported, 1)
2605 self.assertIn('Build succeeded', A.messages[0])
2606 # Ensure the removed job was not included in the report.
2607 self.assertNotIn('project-test1', A.messages[0])
2608
James E. Blairfe707d12015-08-05 15:18:15 -07002609 def test_live_reconfiguration_shared_queue(self):
2610 # Test that a change with a failing job which was removed from
2611 # this project but otherwise still exists in the system does
2612 # not disrupt reconfiguration.
2613
2614 self.worker.hold_jobs_in_build = True
2615
2616 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2617
2618 self.worker.addFailTest('project1-project2-integration', A)
2619
2620 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2621 self.waitUntilSettled()
2622 self.worker.release('.*-merge')
2623 self.waitUntilSettled()
2624 self.worker.release('project1-project2-integration')
2625 self.waitUntilSettled()
2626
2627 self.assertEqual(A.data['status'], 'NEW')
2628 self.assertEqual(A.reported, 0)
2629
2630 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2631 'SUCCESS')
2632 self.assertEqual(self.getJobFromHistory(
2633 'project1-project2-integration').result, 'FAILURE')
2634 self.assertEqual(len(self.history), 2)
2635
2636 # Remove the integration job.
2637 self.config.set('zuul', 'layout_config',
2638 'tests/fixtures/layout-live-'
2639 'reconfiguration-shared-queue.yaml')
2640 self.sched.reconfigure(self.config)
2641 self.waitUntilSettled()
2642
2643 self.worker.hold_jobs_in_build = False
2644 self.worker.release()
2645 self.waitUntilSettled()
2646
2647 self.assertEqual(self.getJobFromHistory('project1-merge').result,
2648 'SUCCESS')
2649 self.assertEqual(self.getJobFromHistory('project1-test1').result,
2650 'SUCCESS')
2651 self.assertEqual(self.getJobFromHistory('project1-test2').result,
2652 'SUCCESS')
2653 self.assertEqual(self.getJobFromHistory(
2654 'project1-project2-integration').result, 'FAILURE')
2655 self.assertEqual(len(self.history), 4)
2656
2657 self.assertEqual(A.data['status'], 'NEW')
2658 self.assertEqual(A.reported, 1)
2659 self.assertIn('Build succeeded', A.messages[0])
2660 # Ensure the removed job was not included in the report.
2661 self.assertNotIn('project1-project2-integration', A.messages[0])
2662
Joshua Hesketh4bd7da32016-02-17 20:58:47 +11002663 def test_double_live_reconfiguration_shared_queue(self):
2664 # This was a real-world regression. A change is added to
2665 # gate; a reconfigure happens, a second change which depends
2666 # on the first is added, and a second reconfiguration happens.
2667 # Ensure that both changes merge.
2668
2669 # A failure may indicate incorrect caching or cleaning up of
2670 # references during a reconfiguration.
2671 self.worker.hold_jobs_in_build = True
2672
2673 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2674 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2675 B.setDependsOn(A, 1)
2676 A.addApproval('CRVW', 2)
2677 B.addApproval('CRVW', 2)
2678
2679 # Add the parent change.
2680 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2681 self.waitUntilSettled()
2682 self.worker.release('.*-merge')
2683 self.waitUntilSettled()
2684
2685 # Reconfigure (with only one change in the pipeline).
2686 self.sched.reconfigure(self.config)
2687 self.waitUntilSettled()
2688
2689 # Add the child change.
2690 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2691 self.waitUntilSettled()
2692 self.worker.release('.*-merge')
2693 self.waitUntilSettled()
2694
2695 # Reconfigure (with both in the pipeline).
2696 self.sched.reconfigure(self.config)
2697 self.waitUntilSettled()
2698
2699 self.worker.hold_jobs_in_build = False
2700 self.worker.release()
2701 self.waitUntilSettled()
2702
2703 self.assertEqual(len(self.history), 8)
2704
2705 self.assertEqual(A.data['status'], 'MERGED')
2706 self.assertEqual(A.reported, 2)
2707 self.assertEqual(B.data['status'], 'MERGED')
2708 self.assertEqual(B.reported, 2)
2709
Evgeny Antyshev0deaaad2015-08-03 20:22:56 +00002710 def test_live_reconfiguration_del_project(self):
2711 # Test project deletion from layout
2712 # while changes are enqueued
2713
2714 self.worker.hold_jobs_in_build = True
2715 A = self.fake_gerrit.addFakeChange('org/project', 'master', 'A')
2716 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
2717 C = self.fake_gerrit.addFakeChange('org/project1', 'master', 'C')
2718
2719 # A Depends-On: B
2720 A.data['commitMessage'] = '%s\n\nDepends-On: %s\n' % (
2721 A.subject, B.data['id'])
2722 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2723
2724 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2725 self.fake_gerrit.addEvent(C.getPatchsetCreatedEvent(1))
2726 self.waitUntilSettled()
2727 self.worker.release('.*-merge')
2728 self.waitUntilSettled()
2729 self.assertEqual(len(self.builds), 5)
2730
2731 # This layout defines only org/project, not org/project1
2732 self.config.set('zuul', 'layout_config',
2733 'tests/fixtures/layout-live-'
2734 'reconfiguration-del-project.yaml')
2735 self.sched.reconfigure(self.config)
2736 self.waitUntilSettled()
2737
2738 # Builds for C aborted, builds for A succeed,
2739 # and have change B applied ahead
2740 job_c = self.getJobFromHistory('project1-test1')
2741 self.assertEqual(job_c.changes, '3,1')
2742 self.assertEqual(job_c.result, 'ABORTED')
2743
2744 self.worker.hold_jobs_in_build = False
2745 self.worker.release()
2746 self.waitUntilSettled()
2747
2748 self.assertEqual(self.getJobFromHistory('project-test1').changes,
2749 '2,1 1,1')
2750
2751 self.assertEqual(A.data['status'], 'NEW')
2752 self.assertEqual(B.data['status'], 'NEW')
2753 self.assertEqual(C.data['status'], 'NEW')
2754 self.assertEqual(A.reported, 1)
2755 self.assertEqual(B.reported, 0)
2756 self.assertEqual(C.reported, 0)
2757
2758 self.assertEqual(len(self.sched.layout.pipelines['check'].queues), 0)
2759 self.assertIn('Build succeeded', A.messages[0])
2760
James E. Blaire712d9f2013-07-31 11:40:11 -07002761 def test_live_reconfiguration_functions(self):
2762 "Test live reconfiguration with a custom function"
2763 self.worker.registerFunction('build:node-project-test1:debian')
2764 self.worker.registerFunction('build:node-project-test1:wheezy')
2765 A = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'A')
2766 A.addApproval('CRVW', 2)
2767 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2768 self.waitUntilSettled()
2769
2770 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2771 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2772 'debian')
2773 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2774
2775 self.config.set('zuul', 'layout_config',
2776 'tests/fixtures/layout-live-'
2777 'reconfiguration-functions.yaml')
2778 self.sched.reconfigure(self.config)
2779 self.worker.build_history = []
2780
2781 B = self.fake_gerrit.addFakeChange('org/node-project', 'master', 'B')
2782 B.addApproval('CRVW', 2)
2783 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2784 self.waitUntilSettled()
2785
2786 self.assertIsNone(self.getJobFromHistory('node-project-merge').node)
2787 self.assertEqual(self.getJobFromHistory('node-project-test1').node,
2788 'wheezy')
2789 self.assertIsNone(self.getJobFromHistory('node-project-test2').node)
2790
James E. Blair287c06d2013-07-24 10:39:30 -07002791 def test_delayed_repo_init(self):
2792 self.config.set('zuul', 'layout_config',
2793 'tests/fixtures/layout-delayed-repo-init.yaml')
2794 self.sched.reconfigure(self.config)
2795
2796 self.init_repo("org/new-project")
2797 A = self.fake_gerrit.addFakeChange('org/new-project', 'master', 'A')
2798
2799 A.addApproval('CRVW', 2)
2800 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2801 self.waitUntilSettled()
2802 self.assertEqual(self.getJobFromHistory('project-merge').result,
2803 'SUCCESS')
2804 self.assertEqual(self.getJobFromHistory('project-test1').result,
2805 'SUCCESS')
2806 self.assertEqual(self.getJobFromHistory('project-test2').result,
2807 'SUCCESS')
2808 self.assertEqual(A.data['status'], 'MERGED')
2809 self.assertEqual(A.reported, 2)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002810
Clark Boylan6dbbc482013-10-18 10:57:31 -07002811 def test_repo_deleted(self):
2812 self.config.set('zuul', 'layout_config',
2813 'tests/fixtures/layout-repo-deleted.yaml')
2814 self.sched.reconfigure(self.config)
2815
2816 self.init_repo("org/delete-project")
2817 A = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'A')
2818
2819 A.addApproval('CRVW', 2)
2820 self.fake_gerrit.addEvent(A.addApproval('APRV', 1))
2821 self.waitUntilSettled()
2822 self.assertEqual(self.getJobFromHistory('project-merge').result,
2823 'SUCCESS')
2824 self.assertEqual(self.getJobFromHistory('project-test1').result,
2825 'SUCCESS')
2826 self.assertEqual(self.getJobFromHistory('project-test2').result,
2827 'SUCCESS')
2828 self.assertEqual(A.data['status'], 'MERGED')
2829 self.assertEqual(A.reported, 2)
2830
2831 # Delete org/new-project zuul repo. Should be recloned.
2832 shutil.rmtree(os.path.join(self.git_root, "org/delete-project"))
2833
2834 B = self.fake_gerrit.addFakeChange('org/delete-project', 'master', 'B')
2835
2836 B.addApproval('CRVW', 2)
2837 self.fake_gerrit.addEvent(B.addApproval('APRV', 1))
2838 self.waitUntilSettled()
2839 self.assertEqual(self.getJobFromHistory('project-merge').result,
2840 'SUCCESS')
2841 self.assertEqual(self.getJobFromHistory('project-test1').result,
2842 'SUCCESS')
2843 self.assertEqual(self.getJobFromHistory('project-test2').result,
2844 'SUCCESS')
2845 self.assertEqual(B.data['status'], 'MERGED')
2846 self.assertEqual(B.reported, 2)
2847
James E. Blair456f2fb2016-02-09 09:29:33 -08002848 def test_tags(self):
2849 "Test job tags"
2850 self.config.set('zuul', 'layout_config',
2851 'tests/fixtures/layout-tags.yaml')
2852 self.sched.reconfigure(self.config)
2853
2854 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
2855 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
2856 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
2857 self.fake_gerrit.addEvent(B.getPatchsetCreatedEvent(1))
2858 self.waitUntilSettled()
2859
2860 results = {'project1-merge': 'extratag merge project1',
2861 'project2-merge': 'merge'}
2862
2863 for build in self.history:
2864 self.assertEqual(results.get(build.name, ''),
2865 build.parameters.get('BUILD_TAGS'))
2866
James E. Blair63bb0ef2013-07-29 17:14:51 -07002867 def test_timer(self):
2868 "Test that a periodic job is triggered"
2869 self.worker.hold_jobs_in_build = True
2870 self.config.set('zuul', 'layout_config',
2871 'tests/fixtures/layout-timer.yaml')
2872 self.sched.reconfigure(self.config)
2873 self.registerJobs()
2874
Clark Boylan3ee090a2014-04-03 20:55:09 -07002875 # The pipeline triggers every second, so we should have seen
2876 # several by now.
2877 time.sleep(5)
James E. Blair63bb0ef2013-07-29 17:14:51 -07002878 self.waitUntilSettled()
Clark Boylan3ee090a2014-04-03 20:55:09 -07002879
2880 self.assertEqual(len(self.builds), 2)
2881
James E. Blair63bb0ef2013-07-29 17:14:51 -07002882 port = self.webapp.server.socket.getsockname()[1]
2883
2884 f = urllib.urlopen("http://localhost:%s/status.json" % port)
2885 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))