blob: 46e1d995d9de50e6f897318fe123fe94d78611a2 [file] [log] [blame]
Antoine Musso45dd2cb2014-01-29 17:17:43 +01001#!/usr/bin/env python
2
3# Copyright 2012 Hewlett-Packard Development Company, L.P.
4# Copyright 2014 Wikimedia Foundation Inc.
5#
6# Licensed under the Apache License, Version 2.0 (the "License"); you may
7# not use this file except in compliance with the License. You may obtain
8# a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15# License for the specific language governing permissions and limitations
16# under the License.
17
James E. Blairdf37ad22018-02-01 13:59:48 -080018try:
19 from unittest import mock
20except ImportError:
21 import mock
22
Antoine Musso45dd2cb2014-01-29 17:17:43 +010023import logging
James E. Blair217b10d2015-01-08 16:25:28 -080024import time
Antoine Musso45dd2cb2014-01-29 17:17:43 +010025
Tristan Cacqueray80954402017-05-28 00:33:55 +000026import zuul.executor.server
27import zuul.model
28
James E. Blaird8af5422017-05-24 13:59:40 -070029from tests.base import ZuulTestCase, simple_layout
Antoine Musso45dd2cb2014-01-29 17:17:43 +010030
Antoine Musso45dd2cb2014-01-29 17:17:43 +010031
James E. Blairb3b5b382017-06-02 11:29:57 -070032class TestExecutorRepos(ZuulTestCase):
James E. Blaird8af5422017-05-24 13:59:40 -070033 tenant_config_file = 'config/single-tenant/main.yaml'
Antoine Musso45dd2cb2014-01-29 17:17:43 +010034
James E. Blairb3b5b382017-06-02 11:29:57 -070035 log = logging.getLogger("zuul.test.executor")
Antoine Musso45dd2cb2014-01-29 17:17:43 +010036
James E. Blairaf3d01e2017-05-26 14:30:18 -070037 def assertRepoState(self, repo, state, project, build, number):
James E. Blairbcaa2d42017-05-26 15:44:23 -070038 if 'branch' in state:
39 self.assertFalse(repo.head.is_detached,
40 'Project %s commit for build %s #%s should '
41 'not have a detached HEAD' % (
42 project, build, number))
zhangyangyangc3e786f2017-09-13 10:47:52 +080043 self.assertEqual(repo.active_branch.name,
44 state['branch'],
45 'Project %s commit for build %s #%s should '
46 'be on the correct branch' % (
47 project, build, number))
James E. Blairbcaa2d42017-05-26 15:44:23 -070048 if 'commit' in state:
zhangyangyangc3e786f2017-09-13 10:47:52 +080049 self.assertEqual(state['commit'],
50 str(repo.commit('HEAD')),
51 'Project %s commit for build %s #%s should '
52 'be correct' % (
53 project, build, number))
James E. Blairbcaa2d42017-05-26 15:44:23 -070054 ref = repo.commit('HEAD')
55 repo_messages = set(
56 [c.message.strip() for c in repo.iter_commits(ref)])
57 if 'present' in state:
58 for change in state['present']:
James E. Blairaf3d01e2017-05-26 14:30:18 -070059 msg = '%s-1' % change.subject
60 self.assertTrue(msg in repo_messages,
61 'Project %s for build %s #%s should '
62 'have change %s' % (
63 project, build, number, change.subject))
James E. Blairbcaa2d42017-05-26 15:44:23 -070064 if 'absent' in state:
65 for change in state['absent']:
James E. Blairaf3d01e2017-05-26 14:30:18 -070066 msg = '%s-1' % change.subject
67 self.assertTrue(msg not in repo_messages,
68 'Project %s for build %s #%s should '
69 'not have change %s' % (
70 project, build, number, change.subject))
71
James E. Blair987855f2017-06-06 14:41:58 -070072 def assertBuildStates(self, states, projects):
73 for number, build in enumerate(self.builds):
74 work = build.getWorkspaceRepos(projects)
75 state = states[number]
76
77 for project in projects:
78 self.assertRepoState(work[project], state[project],
79 project, build, number)
80
81 self.executor_server.hold_jobs_in_build = False
82 self.executor_server.release()
83 self.waitUntilSettled()
84
James E. Blaird8af5422017-05-24 13:59:40 -070085 @simple_layout('layouts/repo-checkout-two-project.yaml')
James E. Blair97d902e2014-08-21 13:25:56 -070086 def test_one_branch(self):
James E. Blaird8af5422017-05-24 13:59:40 -070087 self.executor_server.hold_jobs_in_build = True
Antoine Musso45dd2cb2014-01-29 17:17:43 +010088
James E. Blaird8af5422017-05-24 13:59:40 -070089 p1 = 'review.example.com/org/project1'
90 p2 = 'review.example.com/org/project2'
91 projects = [p1, p2]
Antoine Musso45dd2cb2014-01-29 17:17:43 +010092 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
93 B = self.fake_gerrit.addFakeChange('org/project2', 'master', 'B')
Tobias Henkelbf24fd12017-07-27 06:13:07 +020094 A.addApproval('Code-Review', 2)
95 B.addApproval('Code-Review', 2)
96 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
97 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
Antoine Musso45dd2cb2014-01-29 17:17:43 +010098
99 self.waitUntilSettled()
100
zhangyangyangc3e786f2017-09-13 10:47:52 +0800101 self.assertEqual(2, len(self.builds), "Two builds are running")
Antoine Musso45dd2cb2014-01-29 17:17:43 +0100102
James E. Blair97d902e2014-08-21 13:25:56 -0700103 upstream = self.getUpstreamRepos(projects)
104 states = [
James E. Blairbcaa2d42017-05-26 15:44:23 -0700105 {p1: dict(present=[A], absent=[B], branch='master'),
106 p2: dict(commit=str(upstream[p2].commit('master')),
107 branch='master'),
James E. Blair97d902e2014-08-21 13:25:56 -0700108 },
James E. Blairbcaa2d42017-05-26 15:44:23 -0700109 {p1: dict(present=[A], absent=[B], branch='master'),
110 p2: dict(present=[B], absent=[A], branch='master'),
James E. Blair97d902e2014-08-21 13:25:56 -0700111 },
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000112 ]
James E. Blair97d902e2014-08-21 13:25:56 -0700113
James E. Blair987855f2017-06-06 14:41:58 -0700114 self.assertBuildStates(states, projects)
James E. Blair97d902e2014-08-21 13:25:56 -0700115
James E. Blairaf3d01e2017-05-26 14:30:18 -0700116 @simple_layout('layouts/repo-checkout-four-project.yaml')
James E. Blair97d902e2014-08-21 13:25:56 -0700117 def test_multi_branch(self):
James E. Blairaf3d01e2017-05-26 14:30:18 -0700118 self.executor_server.hold_jobs_in_build = True
119
120 p1 = 'review.example.com/org/project1'
121 p2 = 'review.example.com/org/project2'
122 p3 = 'review.example.com/org/project3'
123 p4 = 'review.example.com/org/project4'
124 projects = [p1, p2, p3, p4]
James E. Blair97d902e2014-08-21 13:25:56 -0700125
126 self.create_branch('org/project2', 'stable/havana')
127 self.create_branch('org/project4', 'stable/havana')
128 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000129 B = self.fake_gerrit.addFakeChange('org/project2', 'stable/havana',
130 'B')
James E. Blair97d902e2014-08-21 13:25:56 -0700131 C = self.fake_gerrit.addFakeChange('org/project3', 'master', 'C')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200132 A.addApproval('Code-Review', 2)
133 B.addApproval('Code-Review', 2)
134 C.addApproval('Code-Review', 2)
135 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
136 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
137 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
James E. Blair97d902e2014-08-21 13:25:56 -0700138
139 self.waitUntilSettled()
140
zhangyangyangc3e786f2017-09-13 10:47:52 +0800141 self.assertEqual(3, len(self.builds), "Three builds are running")
James E. Blair97d902e2014-08-21 13:25:56 -0700142
143 upstream = self.getUpstreamRepos(projects)
144 states = [
James E. Blairbcaa2d42017-05-26 15:44:23 -0700145 {p1: dict(present=[A], absent=[B, C], branch='master'),
146 p2: dict(commit=str(upstream[p2].commit('master')),
147 branch='master'),
148 p3: dict(commit=str(upstream[p3].commit('master')),
149 branch='master'),
150 p4: dict(commit=str(upstream[p4].commit('master')),
151 branch='master'),
James E. Blair97d902e2014-08-21 13:25:56 -0700152 },
James E. Blairbcaa2d42017-05-26 15:44:23 -0700153 {p1: dict(present=[A], absent=[B, C], branch='master'),
154 p2: dict(present=[B], absent=[A, C], branch='stable/havana'),
155 p3: dict(commit=str(upstream[p3].commit('master')),
156 branch='master'),
157 p4: dict(commit=str(upstream[p4].commit('stable/havana')),
158 branch='stable/havana'),
James E. Blair97d902e2014-08-21 13:25:56 -0700159 },
James E. Blairbcaa2d42017-05-26 15:44:23 -0700160 {p1: dict(present=[A], absent=[B, C], branch='master'),
161 p2: dict(commit=str(upstream[p2].commit('master')),
162 branch='master'),
163 p3: dict(present=[C], absent=[A, B], branch='master'),
164 p4: dict(commit=str(upstream[p4].commit('master')),
165 branch='master'),
James E. Blair97d902e2014-08-21 13:25:56 -0700166 },
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000167 ]
James E. Blair97d902e2014-08-21 13:25:56 -0700168
James E. Blair987855f2017-06-06 14:41:58 -0700169 self.assertBuildStates(states, projects)
James E. Blairbce35e12014-08-21 14:31:17 -0700170
James E. Blair4de8d9e2017-06-01 15:41:40 -0700171 @simple_layout('layouts/repo-checkout-six-project.yaml')
James E. Blairf0420222014-08-21 16:02:17 -0700172 def test_project_override(self):
James E. Blair4de8d9e2017-06-01 15:41:40 -0700173 self.executor_server.hold_jobs_in_build = True
174
175 p1 = 'review.example.com/org/project1'
176 p2 = 'review.example.com/org/project2'
177 p3 = 'review.example.com/org/project3'
178 p4 = 'review.example.com/org/project4'
179 p5 = 'review.example.com/org/project5'
180 p6 = 'review.example.com/org/project6'
181 projects = [p1, p2, p3, p4, p5, p6]
James E. Blairf0420222014-08-21 16:02:17 -0700182
183 self.create_branch('org/project3', 'stable/havana')
184 self.create_branch('org/project4', 'stable/havana')
185 self.create_branch('org/project6', 'stable/havana')
186 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
187 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B')
188 C = self.fake_gerrit.addFakeChange('org/project2', 'master', 'C')
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000189 D = self.fake_gerrit.addFakeChange('org/project3', 'stable/havana',
190 'D')
Tobias Henkelbf24fd12017-07-27 06:13:07 +0200191 A.addApproval('Code-Review', 2)
192 B.addApproval('Code-Review', 2)
193 C.addApproval('Code-Review', 2)
194 D.addApproval('Code-Review', 2)
195 self.fake_gerrit.addEvent(A.addApproval('Approved', 1))
196 self.fake_gerrit.addEvent(B.addApproval('Approved', 1))
197 self.fake_gerrit.addEvent(C.addApproval('Approved', 1))
198 self.fake_gerrit.addEvent(D.addApproval('Approved', 1))
James E. Blairf0420222014-08-21 16:02:17 -0700199
200 self.waitUntilSettled()
201
zhangyangyangc3e786f2017-09-13 10:47:52 +0800202 self.assertEqual(4, len(self.builds), "Four builds are running")
James E. Blairf0420222014-08-21 16:02:17 -0700203
204 upstream = self.getUpstreamRepos(projects)
205 states = [
James E. Blair4de8d9e2017-06-01 15:41:40 -0700206 {p1: dict(present=[A], absent=[B, C, D], branch='master'),
207 p2: dict(commit=str(upstream[p2].commit('master')),
208 branch='master'),
209 p3: dict(commit=str(upstream[p3].commit('master')),
210 branch='master'),
211 p4: dict(commit=str(upstream[p4].commit('master')),
212 branch='master'),
213 p5: dict(commit=str(upstream[p5].commit('master')),
214 branch='master'),
215 p6: dict(commit=str(upstream[p6].commit('master')),
216 branch='master'),
James E. Blairf0420222014-08-21 16:02:17 -0700217 },
James E. Blair4de8d9e2017-06-01 15:41:40 -0700218 {p1: dict(present=[A, B], absent=[C, D], branch='master'),
219 p2: dict(commit=str(upstream[p2].commit('master')),
220 branch='master'),
221 p3: dict(commit=str(upstream[p3].commit('master')),
222 branch='master'),
223 p4: dict(commit=str(upstream[p4].commit('master')),
224 branch='master'),
225 p5: dict(commit=str(upstream[p5].commit('master')),
226 branch='master'),
227 p6: dict(commit=str(upstream[p6].commit('master')),
228 branch='master'),
James E. Blairf0420222014-08-21 16:02:17 -0700229 },
James E. Blair4de8d9e2017-06-01 15:41:40 -0700230 {p1: dict(present=[A, B], absent=[C, D], branch='master'),
231 p2: dict(present=[C], absent=[A, B, D], branch='master'),
232 p3: dict(commit=str(upstream[p3].commit('master')),
233 branch='master'),
234 p4: dict(commit=str(upstream[p4].commit('master')),
235 branch='master'),
236 p5: dict(commit=str(upstream[p5].commit('master')),
237 branch='master'),
238 p6: dict(commit=str(upstream[p6].commit('master')),
239 branch='master'),
James E. Blairf0420222014-08-21 16:02:17 -0700240 },
James E. Blair4de8d9e2017-06-01 15:41:40 -0700241 {p1: dict(present=[A, B], absent=[C, D], branch='master'),
242 p2: dict(present=[C], absent=[A, B, D], branch='master'),
243 p3: dict(present=[D], absent=[A, B, C],
244 branch='stable/havana'),
245 p4: dict(commit=str(upstream[p4].commit('master')),
246 branch='master'),
247 p5: dict(commit=str(upstream[p5].commit('master')),
248 branch='master'),
249 p6: dict(commit=str(upstream[p6].commit('stable/havana')),
250 branch='stable/havana'),
James E. Blairf0420222014-08-21 16:02:17 -0700251 },
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000252 ]
James E. Blairf0420222014-08-21 16:02:17 -0700253
James E. Blair987855f2017-06-06 14:41:58 -0700254 self.assertBuildStates(states, projects)
James E. Blair217b10d2015-01-08 16:25:28 -0800255
James E. Blair21037782017-07-19 11:56:55 -0700256 def test_periodic_override(self):
257 # This test can not use simple_layout because it must start
258 # with a configuration which does not include a
259 # timer-triggered job so that we have an opportunity to set
260 # the hold flag before the first job.
261
262 # This tests that we can override the branch in a timer
263 # trigger (mostly to ensure backwards compatability for jobs).
264 self.executor_server.hold_jobs_in_build = True
265 # Start timer trigger - also org/project
266 self.commitConfigUpdate('common-config',
267 'layouts/repo-checkout-timer-override.yaml')
268 self.sched.reconfigure(self.config)
269
270 p1 = 'review.example.com/org/project1'
271 projects = [p1]
272 self.create_branch('org/project1', 'stable/havana')
273
274 # The pipeline triggers every second, so we should have seen
275 # several by now.
276 time.sleep(5)
277 self.waitUntilSettled()
278
279 # Stop queuing timer triggered jobs so that the assertions
280 # below don't race against more jobs being queued.
281 self.commitConfigUpdate('common-config',
James E. Blair0b137b42017-07-27 08:51:25 -0700282 'layouts/repo-checkout-no-timer-override.yaml')
James E. Blair21037782017-07-19 11:56:55 -0700283 self.sched.reconfigure(self.config)
James E. Blair0b137b42017-07-27 08:51:25 -0700284 self.waitUntilSettled()
James E. Blair78ae4782017-08-02 14:19:10 -0700285 # If APScheduler is in mid-event when we remove the job, we
286 # can end up with one more event firing, so give it an extra
287 # second to settle.
288 time.sleep(1)
289 self.waitUntilSettled()
James E. Blair21037782017-07-19 11:56:55 -0700290
zhangyangyangc3e786f2017-09-13 10:47:52 +0800291 self.assertEqual(1, len(self.builds), "One build is running")
James E. Blair21037782017-07-19 11:56:55 -0700292
293 upstream = self.getUpstreamRepos(projects)
294 states = [
295 {p1: dict(commit=str(upstream[p1].commit('stable/havana')),
296 branch='stable/havana'),
297 },
298 ]
299
300 self.assertBuildStates(states, projects)
301
James E. Blair217b10d2015-01-08 16:25:28 -0800302 def test_periodic(self):
James E. Blair95ae4fc2017-06-01 15:54:53 -0700303 # This test can not use simple_layout because it must start
304 # with a configuration which does not include a
305 # timer-triggered job so that we have an opportunity to set
306 # the hold flag before the first job.
307 self.executor_server.hold_jobs_in_build = True
308 # Start timer trigger - also org/project
309 self.commitConfigUpdate('common-config',
310 'layouts/repo-checkout-timer.yaml')
James E. Blair217b10d2015-01-08 16:25:28 -0800311 self.sched.reconfigure(self.config)
James E. Blair95ae4fc2017-06-01 15:54:53 -0700312
313 p1 = 'review.example.com/org/project1'
314 projects = [p1]
315 self.create_branch('org/project1', 'stable/havana')
James E. Blair217b10d2015-01-08 16:25:28 -0800316
317 # The pipeline triggers every second, so we should have seen
318 # several by now.
319 time.sleep(5)
320 self.waitUntilSettled()
321
James E. Blair217b10d2015-01-08 16:25:28 -0800322 # Stop queuing timer triggered jobs so that the assertions
323 # below don't race against more jobs being queued.
James E. Blair95ae4fc2017-06-01 15:54:53 -0700324 self.commitConfigUpdate('common-config',
325 'layouts/repo-checkout-no-timer.yaml')
James E. Blair217b10d2015-01-08 16:25:28 -0800326 self.sched.reconfigure(self.config)
James E. Blair0b137b42017-07-27 08:51:25 -0700327 self.waitUntilSettled()
James E. Blair78ae4782017-08-02 14:19:10 -0700328 # If APScheduler is in mid-event when we remove the job, we
329 # can end up with one more event firing, so give it an extra
330 # second to settle.
331 time.sleep(1)
332 self.waitUntilSettled()
James E. Blair217b10d2015-01-08 16:25:28 -0800333
zhangyangyangc3e786f2017-09-13 10:47:52 +0800334 self.assertEqual(2, len(self.builds), "Two builds are running")
James E. Blair217b10d2015-01-08 16:25:28 -0800335
336 upstream = self.getUpstreamRepos(projects)
337 states = [
James E. Blair95ae4fc2017-06-01 15:54:53 -0700338 {p1: dict(commit=str(upstream[p1].commit('stable/havana')),
339 branch='stable/havana'),
James E. Blair217b10d2015-01-08 16:25:28 -0800340 },
James E. Blair21037782017-07-19 11:56:55 -0700341 {p1: dict(commit=str(upstream[p1].commit('master')),
342 branch='master'),
343 },
Joshua Hesketh29d99b72014-08-19 16:27:42 +1000344 ]
James E. Blair21037782017-07-19 11:56:55 -0700345 if self.builds[0].parameters['zuul']['ref'] == 'refs/heads/master':
346 states = list(reversed(states))
James E. Blair217b10d2015-01-08 16:25:28 -0800347
James E. Blair987855f2017-06-06 14:41:58 -0700348 self.assertBuildStates(states, projects)
Sachi King9f16d522016-03-16 12:20:45 +1100349
James E. Blairbbe811e2017-06-02 10:47:44 -0700350 @simple_layout('layouts/repo-checkout-post.yaml')
Sachi King9f16d522016-03-16 12:20:45 +1100351 def test_post_and_master_checkout(self):
James E. Blair1de2e492017-06-02 11:04:42 -0700352 self.executor_server.hold_jobs_in_build = True
353 p1 = "review.example.com/org/project1"
354 p2 = "review.example.com/org/project2"
355 projects = [p1, p2]
James E. Blair289f5932017-07-27 15:02:29 -0700356 upstream = self.getUpstreamRepos(projects)
James E. Blair8cce42e2016-10-18 08:18:36 -0700357
James E. Blair1de2e492017-06-02 11:04:42 -0700358 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
James E. Blair8cce42e2016-10-18 08:18:36 -0700359 event = A.getRefUpdatedEvent()
360 A.setMerged()
James E. Blair289f5932017-07-27 15:02:29 -0700361 A_commit = str(upstream[p1].commit('master'))
362 self.log.debug("A commit: %s" % A_commit)
363
364 # Add another commit to the repo that merged right after this
365 # one to make sure that our post job runs with the one that we
366 # intended rather than simply the current repo state.
367 B = self.fake_gerrit.addFakeChange('org/project1', 'master', 'B',
368 parent='refs/changes/1/1/1')
369 B.setMerged()
370 B_commit = str(upstream[p1].commit('master'))
371 self.log.debug("B commit: %s" % B_commit)
372
James E. Blair8cce42e2016-10-18 08:18:36 -0700373 self.fake_gerrit.addEvent(event)
374 self.waitUntilSettled()
375
James E. Blair1de2e492017-06-02 11:04:42 -0700376 states = [
James E. Blair289f5932017-07-27 15:02:29 -0700377 {p1: dict(commit=A_commit,
378 present=[A], absent=[B], branch='master'),
James E. Blair1de2e492017-06-02 11:04:42 -0700379 p2: dict(commit=str(upstream[p2].commit('master')),
James E. Blair289f5932017-07-27 15:02:29 -0700380 absent=[A, B], branch='master'),
James E. Blair1de2e492017-06-02 11:04:42 -0700381 },
382 ]
James E. Blair8cce42e2016-10-18 08:18:36 -0700383
James E. Blair987855f2017-06-06 14:41:58 -0700384 self.assertBuildStates(states, projects)
Tristan Cacqueray80954402017-05-28 00:33:55 +0000385
James E. Blairedff2c22017-10-30 14:04:48 -0700386 @simple_layout('layouts/repo-checkout-tag.yaml')
387 def test_tag_checkout(self):
388 self.executor_server.hold_jobs_in_build = True
389 p1 = "review.example.com/org/project1"
390 p2 = "review.example.com/org/project2"
391 projects = [p1, p2]
392 upstream = self.getUpstreamRepos(projects)
393
394 self.create_branch('org/project2', 'stable/havana')
395 files = {'README': 'tagged readme'}
396 self.addCommitToRepo('org/project2', 'tagged commit',
397 files, branch='stable/havana', tag='test-tag')
398
399 A = self.fake_gerrit.addFakeChange('org/project1', 'master', 'A')
400 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
401 self.waitUntilSettled()
402
403 states = [
404 {p1: dict(present=[A], branch='master'),
405 p2: dict(commit=str(upstream[p2].commit('test-tag')),
406 absent=[A]),
407 },
408 ]
409
410 self.assertBuildStates(states, projects)
411
Tristan Cacqueray80954402017-05-28 00:33:55 +0000412
413class TestAnsibleJob(ZuulTestCase):
414 tenant_config_file = 'config/ansible/main.yaml'
415
416 def setUp(self):
417 super(TestAnsibleJob, self).setUp()
418 job = zuul.model.Job('test')
419 job.unique = 'test'
420 self.test_job = zuul.executor.server.AnsibleJob(self.executor_server,
421 job)
422
423 def test_getHostList_host_keys(self):
Tobias Henkelaea43442017-09-05 14:36:33 +0200424 # Test without connection_port set
Tristan Cacqueray80954402017-05-28 00:33:55 +0000425 node = {'name': 'fake-host',
426 'host_keys': ['fake-host-key'],
427 'interface_ip': 'localhost'}
428 keys = self.test_job.getHostList({'nodes': [node]})[0]['host_keys']
429 self.assertEqual(keys[0], 'localhost fake-host-key')
430
Tobias Henkelaea43442017-09-05 14:36:33 +0200431 # Test with custom connection_port set
432 node['connection_port'] = 22022
Tristan Cacqueray80954402017-05-28 00:33:55 +0000433 keys = self.test_job.getHostList({'nodes': [node]})[0]['host_keys']
434 self.assertEqual(keys[0], '[localhost]:22022 fake-host-key')
Tobias Henkel055cda32017-10-17 13:08:18 +0200435
436
437class TestExecutorHostname(ZuulTestCase):
438 config_file = 'zuul-executor-hostname.conf'
439 tenant_config_file = 'config/single-tenant/main.yaml'
440
441 def test_executor_hostname(self):
Tobias Henkele2d35662017-10-19 19:01:03 +0200442 self.assertEqual('test-executor-hostname.example.com',
Tobias Henkel055cda32017-10-17 13:08:18 +0200443 self.executor_server.hostname)
James E. Blairdf37ad22018-02-01 13:59:48 -0800444
445
446class TestGovernor(ZuulTestCase):
447 tenant_config_file = 'config/governor/main.yaml'
448
449 @mock.patch('os.getloadavg')
450 @mock.patch('psutil.virtual_memory')
451 def test_load_governor(self, vm_mock, loadavg_mock):
452 class Dummy(object):
453 pass
454 ram = Dummy()
455 ram.percent = 20.0 # 20% used
456 vm_mock.return_value = ram
457 loadavg_mock.return_value = (0.0, 0.0, 0.0)
458 self.executor_server.manageLoad()
459 self.assertTrue(self.executor_server.accepting_work)
460 ram.percent = 99.0 # 99% used
461 loadavg_mock.return_value = (100.0, 100.0, 100.0)
462 self.executor_server.manageLoad()
463 self.assertFalse(self.executor_server.accepting_work)
464
465 def waitForExecutorBuild(self, jobname):
466 timeout = time.time() + 30
467 build = None
468 while (time.time() < timeout and not build):
469 for b in self.builds:
470 if b.name == jobname:
471 build = b
472 break
473 time.sleep(0.1)
474 build_id = build.uuid
475 while (time.time() < timeout and
476 build_id not in self.executor_server.job_workers):
477 time.sleep(0.1)
478 worker = self.executor_server.job_workers[build_id]
479 while (time.time() < timeout and
480 not worker.started):
481 time.sleep(0.1)
482 return build
483
484 def waitForWorkerCompletion(self, build):
485 timeout = time.time() + 30
486 while (time.time() < timeout and
487 build.uuid in self.executor_server.job_workers):
488 time.sleep(0.1)
489
490 def test_slow_start(self):
491 self.executor_server.hold_jobs_in_build = True
492 self.executor_server.max_starting_builds = 1
James E. Blairacb632d2018-02-05 10:36:36 -0800493 self.executor_server.min_starting_builds = 1
James E. Blairdf37ad22018-02-01 13:59:48 -0800494 self.executor_server.manageLoad()
495 self.assertTrue(self.executor_server.accepting_work)
496 A = self.fake_gerrit.addFakeChange('common-config', 'master', 'A')
497 self.fake_gerrit.addEvent(A.getPatchsetCreatedEvent(1))
498
499 build1 = self.waitForExecutorBuild('test1')
500 # With one job (test1) being started, we should no longer
501 # be accepting new work
502 self.assertFalse(self.executor_server.accepting_work)
503 self.assertEqual(len(self.executor_server.job_workers), 1)
504 # Allow enough starting builds for the test to complete.
505 self.executor_server.max_starting_builds = 3
506 build1.release()
507 self.waitForWorkerCompletion(build1)
508 self.executor_server.manageLoad()
509
510 self.waitForExecutorBuild('test2')
511 self.waitForExecutorBuild('test3')
512 self.assertFalse(self.executor_server.accepting_work)
513
514 self.executor_server.hold_jobs_in_build = False
515 self.executor_server.release()
516 self.waitUntilSettled()
517 self.executor_server.manageLoad()
518 self.assertTrue(self.executor_server.accepting_work)