Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(289)

Side by Side Diff: third_party/buildbot_7_12/buildbot/test/test_run.py

Issue 12207158: Bye bye buildbot 0.7.12. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: buildbot.test.test_run -*-
2
3 from twisted.trial import unittest
4 from twisted.internet import reactor, defer
5 import os
6
7 from buildbot import master, interfaces
8 from buildbot.sourcestamp import SourceStamp
9 from buildbot.changes import changes
10 from buildbot.status import builder
11 from buildbot.process.base import BuildRequest
12
13 from buildbot.test.runutils import RunMixin, TestFlagMixin, rmtree
14
15 config_base = """
16 from buildbot.process import factory
17 from buildbot.steps import dummy
18 from buildbot.buildslave import BuildSlave
19 from buildbot.config import BuilderConfig
20 s = factory.s
21
22 f1 = factory.QuickBuildFactory('fakerep', 'cvsmodule', configure=None)
23
24 f2 = factory.BuildFactory([
25 dummy.Dummy(timeout=1),
26 dummy.RemoteDummy(timeout=2),
27 ])
28
29 BuildmasterConfig = c = {}
30 c['slaves'] = [BuildSlave('bot1', 'sekrit')]
31 c['schedulers'] = []
32 c['builders'] = [
33 BuilderConfig(name='quick', slavename='bot1', factory=f1,
34 builddir='quickdir', slavebuilddir='slavequickdir'),
35 ]
36 c['slavePortnum'] = 0
37 """
38
39 config_run = config_base + """
40 from buildbot.scheduler import Scheduler
41 c['schedulers'] = [Scheduler('quick', None, 120, ['quick'])]
42 """
43
44 config_can_build = config_base + """
45 from buildbot.buildslave import BuildSlave
46 c['slaves'] = [ BuildSlave('bot1', 'sekrit') ]
47
48 from buildbot.scheduler import Scheduler
49 c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy'])]
50
51 c['builders'] = [
52 BuilderConfig(name='dummy', slavename='bot1',
53 factory=f2, builddir='dummy1'),
54 ]
55 """
56
57 config_cant_build = config_can_build + """
58 class MyBuildSlave(BuildSlave):
59 def canStartBuild(self): return False
60 c['slaves'] = [ MyBuildSlave('bot1', 'sekrit') ]
61 """
62
63 config_concurrency = config_base + """
64 from buildbot.buildslave import BuildSlave
65 c['slaves'] = [ BuildSlave('bot1', 'sekrit', max_builds=1) ]
66
67 from buildbot.scheduler import Scheduler
68 c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy', 'dummy2'])]
69
70 c['builders'] = c['builders'] + [
71 BuilderConfig(name='dummy', slavename='bot1', factory=f2),
72 BuilderConfig(name='dummy2', slavename='bot1', factory=f2),
73 ]
74 """
75
76 config_2 = config_base + """
77 c['builders'] = [
78 BuilderConfig(name='dummy', slavename='bot1',
79 builddir='dummy1', factory=f2),
80 BuilderConfig(name='test dummy', slavename='bot1',
81 factory=f2, category='test'),
82 ]
83 """
84
85 config_3 = config_2 + """
86 c['builders'] = c['builders'] + [
87 BuilderConfig(name='adummy', slavename='bot1',
88 builddir='adummy3', factory=f2),
89 BuilderConfig(name='bdummy', slavename='bot1',
90 builddir='adummy4', factory=f2,
91 category='test'),
92 ]
93 """
94
95 config_4 = config_base + """
96 c['builders'] = [
97 BuilderConfig(name='dummy', slavename='bot1',
98 slavebuilddir='sdummy', factory=f2),
99 ]
100 """
101
102 config_4_newbasedir = config_4 + """
103 c['builders'] = [
104 BuilderConfig(name='dummy', slavename='bot1',
105 builddir='dummy2', factory=f2),
106 ]
107 """
108
109 config_4_newbuilder = config_4_newbasedir + """
110 c['builders'] = c['builders'] + [
111 BuilderConfig(name='dummy2', slavename='bot1',
112 builddir='dummy23', factory=f2),
113 ]
114 """
115
116 class Run(unittest.TestCase):
117 def rmtree(self, d):
118 rmtree(d)
119
120 def testMaster(self):
121 self.rmtree("basedir")
122 os.mkdir("basedir")
123 m = master.BuildMaster("basedir")
124 m.loadConfig(config_run)
125 m.readConfig = True
126 m.startService()
127 cm = m.change_svc
128 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
129 cm.addChange(c)
130 # verify that the Scheduler is now waiting
131 s = m.allSchedulers()[0]
132 self.failUnless(s.timer)
133 # halting the service will also stop the timer
134 d = defer.maybeDeferred(m.stopService)
135 return d
136
137 class CanStartBuild(RunMixin, unittest.TestCase):
138 def rmtree(self, d):
139 rmtree(d)
140
141 def testCanStartBuild(self):
142 return self.do_test(config_can_build, True)
143
144 def testCantStartBuild(self):
145 return self.do_test(config_cant_build, False)
146
147 def do_test(self, config, builder_should_run):
148 self.master.loadConfig(config)
149 self.master.readConfig = True
150 self.master.startService()
151 d = self.connectSlave()
152
153 # send a change
154 cm = self.master.change_svc
155 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
156 cm.addChange(c)
157
158 d.addCallback(self._do_test1, builder_should_run)
159
160 return d
161
162 def _do_test1(self, res, builder_should_run):
163 # delay a little bit. Note that relying upon timers is a bit fragile,
164 # in this case we're hoping that our 0.5 second timer will land us
165 # somewhere in the middle of the [0.1s, 3.1s] window (after the 0.1
166 # second Scheduler fires, then during the 3-second build), so that
167 # when we sample BuildSlave.state, we'll see BUILDING (or IDLE if the
168 # slave was told to be unavailable). On a heavily loaded system, our
169 # 0.5 second timer might not actually fire until after the build has
170 # completed. In the long run, it would be good to change this test to
171 # pass under those circumstances too.
172 d = defer.Deferred()
173 reactor.callLater(.5, d.callback, builder_should_run)
174 d.addCallback(self._do_test2)
175 return d
176
177 def _do_test2(self, builder_should_run):
178 b = self.master.botmaster.builders['dummy']
179 self.failUnless(len(b.slaves) == 1)
180
181 bs = b.slaves[0]
182 from buildbot.process.builder import IDLE, BUILDING
183 if builder_should_run:
184 self.failUnlessEqual(bs.state, BUILDING)
185 else:
186 self.failUnlessEqual(bs.state, IDLE)
187
188
189 class ConcurrencyLimit(RunMixin, unittest.TestCase):
190
191 def testConcurrencyLimit(self):
192 d = self.master.loadConfig(config_concurrency)
193 d.addCallback(lambda res: self.master.startService())
194 d.addCallback(lambda res: self.connectSlave())
195
196 def _send(res):
197 # send a change. This will trigger both builders at the same
198 # time, but since they share a slave, the max_builds=1 setting
199 # will insure that only one of the two builds gets to run.
200 cm = self.master.change_svc
201 c = changes.Change("bob", ["Makefile", "foo/bar.c"],
202 "changed stuff")
203 cm.addChange(c)
204 d.addCallback(_send)
205
206 def _delay(res):
207 d1 = defer.Deferred()
208 reactor.callLater(1, d1.callback, None)
209 # this test depends upon this 1s delay landing us in the middle
210 # of one of the builds.
211 return d1
212 d.addCallback(_delay)
213
214 def _check(res):
215 builders = [ self.master.botmaster.builders[bn]
216 for bn in ('dummy', 'dummy2') ]
217 for builder in builders:
218 self.failUnless(len(builder.slaves) == 1)
219
220 from buildbot.process.builder import BUILDING
221 building_bs = [ builder
222 for builder in builders
223 if builder.slaves[0].state == BUILDING ]
224 # assert that only one build is running right now. If the
225 # max_builds= weren't in effect, this would be 2.
226 self.failUnlessEqual(len(building_bs), 1)
227 d.addCallback(_check)
228
229 return d
230
231
232 class Ping(RunMixin, unittest.TestCase):
233 def testPing(self):
234 self.master.loadConfig(config_2)
235 self.master.readConfig = True
236 self.master.startService()
237
238 d = self.connectSlave()
239 d.addCallback(self._testPing_1)
240 return d
241
242 def _testPing_1(self, res):
243 d = interfaces.IControl(self.master).getBuilder("dummy").ping()
244 d.addCallback(self._testPing_2)
245 return d
246
247 def _testPing_2(self, res):
248 pass
249
250 class BuilderNames(unittest.TestCase):
251
252 def testGetBuilderNames(self):
253 os.mkdir("bnames")
254 m = master.BuildMaster("bnames")
255 s = m.getStatus()
256
257 m.loadConfig(config_3)
258 m.readConfig = True
259
260 self.failUnlessEqual(s.getBuilderNames(),
261 ["dummy", "test dummy", "adummy", "bdummy"])
262 self.failUnlessEqual(s.getBuilderNames(categories=['test']),
263 ["test dummy", "bdummy"])
264
265 class Disconnect(RunMixin, unittest.TestCase):
266
267 def setUp(self):
268 RunMixin.setUp(self)
269
270 # verify that disconnecting the slave during a build properly
271 # terminates the build
272 m = self.master
273 s = self.status
274 c = self.control
275
276 m.loadConfig(config_2)
277 m.readConfig = True
278 m.startService()
279
280 self.failUnlessEqual(s.getBuilderNames(), ["dummy", "test dummy"])
281 self.s1 = s1 = s.getBuilder("dummy")
282 self.failUnlessEqual(s1.getName(), "dummy")
283 self.failUnlessEqual(s1.getState(), ("offline", []))
284 self.failUnlessEqual(s1.getCurrentBuilds(), [])
285 self.failUnlessEqual(s1.getLastFinishedBuild(), None)
286 self.failUnlessEqual(s1.getBuild(-1), None)
287
288 d = self.connectSlave()
289 d.addCallback(self._disconnectSetup_1)
290 return d
291
292 def _disconnectSetup_1(self, res):
293 self.failUnlessEqual(self.s1.getState(), ("idle", []))
294
295
296 def verifyDisconnect(self, bs):
297 self.failUnless(bs.isFinished())
298
299 step1 = bs.getSteps()[0]
300 self.failUnlessEqual(step1.getText(), ["delay", "interrupted"])
301 self.failUnlessEqual(step1.getResults()[0], builder.FAILURE)
302
303 self.failUnlessEqual(bs.getResults(), builder.FAILURE)
304
305 def verifyDisconnect2(self, bs):
306 self.failUnless(bs.isFinished())
307
308 step1 = bs.getSteps()[1]
309 self.failUnlessEqual(step1.getText(), ["remote", "delay", "2 secs",
310 "failed", "slave", "lost"])
311 self.failUnlessEqual(step1.getResults()[0], builder.EXCEPTION)
312
313 self.failUnlessEqual(bs.getResults(), builder.EXCEPTION)
314
315 def submitBuild(self):
316 ss = SourceStamp()
317 br = BuildRequest("forced build", ss, "dummy")
318 self.control.getBuilder("dummy").requestBuild(br)
319 d = defer.Deferred()
320 def _started(bc):
321 br.unsubscribe(_started)
322 d.callback(bc)
323 br.subscribe(_started)
324 return d
325
326 def testIdle2(self):
327 # now suppose the slave goes missing
328 self.disappearSlave(allowReconnect=False)
329
330 # forcing a build will work: the build detect that the slave is no
331 # longer available and will be re-queued. Wait 5 seconds, then check
332 # to make sure the build is still in the 'waiting for a slave' queue.
333 req = BuildRequest("forced build", SourceStamp(), "test_builder")
334 self.failUnlessEqual(req.startCount, 0)
335 self.control.getBuilder("dummy").requestBuild(req)
336 # this should ping the slave, which doesn't respond (and eventually
337 # times out). The BuildRequest will be re-queued, and its .startCount
338 # will be incremented.
339 self.killSlave()
340 d = defer.Deferred()
341 d.addCallback(self._testIdle2_1, req)
342 reactor.callLater(3, d.callback, None)
343 return d
344 testIdle2.timeout = 5
345
346 def _testIdle2_1(self, res, req):
347 self.failUnlessEqual(req.startCount, 1)
348 cancelled = req.cancel()
349 self.failUnless(cancelled)
350
351
352 def testBuild1(self):
353 # this next sequence is timing-dependent. The dummy build takes at
354 # least 3 seconds to complete, and this batch of commands must
355 # complete within that time.
356 #
357 d = self.submitBuild()
358 d.addCallback(self._testBuild1_1)
359 return d
360
361 def _testBuild1_1(self, bc):
362 bs = bc.getStatus()
363 # now kill the slave before it gets to start the first step
364 d = self.shutdownAllSlaves() # dies before it gets started
365 d.addCallback(self._testBuild1_2, bs)
366 return d # TODO: this used to have a 5-second timeout
367
368 def _testBuild1_2(self, res, bs):
369 # now examine the just-stopped build and make sure it is really
370 # stopped. This is checking for bugs in which the slave-detach gets
371 # missed or causes an exception which prevents the build from being
372 # marked as "finished due to an error".
373 d = bs.waitUntilFinished()
374 d2 = self.master.botmaster.waitUntilBuilderDetached("dummy")
375 dl = defer.DeferredList([d, d2])
376 dl.addCallback(self._testBuild1_3, bs)
377 return dl # TODO: this had a 5-second timeout too
378
379 def _testBuild1_3(self, res, bs):
380 self.failUnlessEqual(self.s1.getState()[0], "offline")
381 self.verifyDisconnect(bs)
382
383
384 def testBuild2(self):
385 # this next sequence is timing-dependent
386 d = self.submitBuild()
387 d.addCallback(self._testBuild2_1)
388 return d
389 testBuild2.timeout = 30
390
391 def _testBuild2_1(self, bc):
392 bs = bc.getStatus()
393 # shutdown the slave while it's running the first step
394 reactor.callLater(0.5, self.shutdownAllSlaves)
395
396 d = bs.waitUntilFinished()
397 d.addCallback(self._testBuild2_2, bs)
398 return d
399
400 def _testBuild2_2(self, res, bs):
401 # we hit here when the build has finished. The builder is still being
402 # torn down, however, so spin for another second to allow the
403 # callLater(0) in Builder.detached to fire.
404 d = defer.Deferred()
405 reactor.callLater(1, d.callback, None)
406 d.addCallback(self._testBuild2_3, bs)
407 return d
408
409 def _testBuild2_3(self, res, bs):
410 self.failUnlessEqual(self.s1.getState()[0], "offline")
411 self.verifyDisconnect(bs)
412
413
414 def testBuild3(self):
415 # this next sequence is timing-dependent
416 d = self.submitBuild()
417 d.addCallback(self._testBuild3_1)
418 return d
419 testBuild3.timeout = 30
420
421 def _testBuild3_1(self, bc):
422 bs = bc.getStatus()
423 # kill the slave while it's running the first step
424 reactor.callLater(0.5, self.killSlave)
425 d = bs.waitUntilFinished()
426 d.addCallback(self._testBuild3_2, bs)
427 return d
428
429 def _testBuild3_2(self, res, bs):
430 # the builder is still being torn down, so give it another second
431 d = defer.Deferred()
432 reactor.callLater(1, d.callback, None)
433 d.addCallback(self._testBuild3_3, bs)
434 return d
435
436 def _testBuild3_3(self, res, bs):
437 self.failUnlessEqual(self.s1.getState()[0], "offline")
438 self.verifyDisconnect(bs)
439
440
441 def testBuild4(self):
442 # this next sequence is timing-dependent
443 d = self.submitBuild()
444 d.addCallback(self._testBuild4_1)
445 return d
446 testBuild4.timeout = 30
447
448 def _testBuild4_1(self, bc):
449 bs = bc.getStatus()
450 # kill the slave while it's running the second (remote) step
451 reactor.callLater(1.5, self.killSlave)
452 d = bs.waitUntilFinished()
453 d.addCallback(self._testBuild4_2, bs)
454 return d
455
456 def _testBuild4_2(self, res, bs):
457 # at this point, the slave is in the process of being removed, so it
458 # could either be 'idle' or 'offline'. I think there is a
459 # reactor.callLater(0) standing between here and the offline state.
460 #reactor.iterate() # TODO: remove the need for this
461
462 self.failUnlessEqual(self.s1.getState()[0], "offline")
463 self.verifyDisconnect2(bs)
464
465
466 def testInterrupt(self):
467 # this next sequence is timing-dependent
468 d = self.submitBuild()
469 d.addCallback(self._testInterrupt_1)
470 return d
471 testInterrupt.timeout = 30
472
473 def _testInterrupt_1(self, bc):
474 bs = bc.getStatus()
475 # halt the build while it's running the first step
476 reactor.callLater(0.5, bc.stopBuild, "bang go splat")
477 d = bs.waitUntilFinished()
478 d.addCallback(self._testInterrupt_2, bs)
479 return d
480
481 def _testInterrupt_2(self, res, bs):
482 self.verifyDisconnect(bs)
483
484
485 def testDisappear(self):
486 bc = self.control.getBuilder("dummy")
487
488 # ping should succeed
489 d = bc.ping()
490 d.addCallback(self._testDisappear_1, bc)
491 return d
492
493 def _testDisappear_1(self, res, bc):
494 self.failUnlessEqual(res, True)
495
496 # now, before any build is run, make the slave disappear
497 self.disappearSlave(allowReconnect=False)
498
499 # initiate the ping and then kill the slave, to simulate a disconnect.
500 d = bc.ping()
501 self.killSlave()
502 d.addCallback(self. _testDisappear_2)
503 return d
504 def _testDisappear_2(self, res):
505 self.failUnlessEqual(res, False)
506
507 def testDuplicate(self):
508 bc = self.control.getBuilder("dummy")
509 bs = self.status.getBuilder("dummy")
510 ss = bs.getSlaves()[0]
511
512 self.failUnless(ss.isConnected())
513 self.failUnlessEqual(ss.getAdmin(), "one")
514
515 # now, before any build is run, make the first slave disappear
516 self.disappearSlave(allowReconnect=False)
517
518 d = self.master.botmaster.waitUntilBuilderDetached("dummy")
519 # now let the new slave take over
520 self.connectSlave2()
521 d.addCallback(self._testDuplicate_1, ss)
522 return d
523 testDuplicate.timeout = 5
524
525 def _testDuplicate_1(self, res, ss):
526 d = self.master.botmaster.waitUntilBuilderAttached("dummy")
527 d.addCallback(self._testDuplicate_2, ss)
528 return d
529
530 def _testDuplicate_2(self, res, ss):
531 self.failUnless(ss.isConnected())
532 self.failUnlessEqual(ss.getAdmin(), "two")
533
534
535 class Disconnect2(RunMixin, unittest.TestCase):
536
537 def setUp(self):
538 RunMixin.setUp(self)
539 # verify that disconnecting the slave during a build properly
540 # terminates the build
541 m = self.master
542 s = self.status
543 c = self.control
544
545 m.loadConfig(config_2)
546 m.readConfig = True
547 m.startService()
548
549 self.failUnlessEqual(s.getBuilderNames(), ["dummy", "test dummy"])
550 self.s1 = s1 = s.getBuilder("dummy")
551 self.failUnlessEqual(s1.getName(), "dummy")
552 self.failUnlessEqual(s1.getState(), ("offline", []))
553 self.failUnlessEqual(s1.getCurrentBuilds(), [])
554 self.failUnlessEqual(s1.getLastFinishedBuild(), None)
555 self.failUnlessEqual(s1.getBuild(-1), None)
556
557 d = self.connectSlaveFastTimeout()
558 d.addCallback(self._setup_disconnect2_1)
559 return d
560
561 def _setup_disconnect2_1(self, res):
562 self.failUnlessEqual(self.s1.getState(), ("idle", []))
563
564
565 def testSlaveTimeout(self):
566 # now suppose the slave goes missing. We want to find out when it
567 # creates a new Broker, so we reach inside and mark it with the
568 # well-known sigil of impending messy death.
569 bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"]
570 broker = bd.remote.broker
571 broker.redshirt = 1
572
573 # make sure the keepalives will keep the connection up
574 d = defer.Deferred()
575 reactor.callLater(5, d.callback, None)
576 d.addCallback(self._testSlaveTimeout_1)
577 return d
578 testSlaveTimeout.timeout = 20
579
580 def _testSlaveTimeout_1(self, res):
581 bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"]
582 if not bd.remote or not hasattr(bd.remote.broker, "redshirt"):
583 self.fail("slave disconnected when it shouldn't have")
584
585 d = self.master.botmaster.waitUntilBuilderDetached("dummy")
586 # whoops! how careless of me.
587 self.disappearSlave(allowReconnect=True)
588 # the slave will realize the connection is lost within 2 seconds, and
589 # reconnect.
590 d.addCallback(self._testSlaveTimeout_2)
591 return d
592
593 def _testSlaveTimeout_2(self, res):
594 # the ReconnectingPBClientFactory will attempt a reconnect in two
595 # seconds.
596 d = self.master.botmaster.waitUntilBuilderAttached("dummy")
597 d.addCallback(self._testSlaveTimeout_3)
598 return d
599
600 def _testSlaveTimeout_3(self, res):
601 # make sure it is a new connection (i.e. a new Broker)
602 bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"]
603 self.failUnless(bd.remote, "hey, slave isn't really connected")
604 self.failIf(hasattr(bd.remote.broker, "redshirt"),
605 "hey, slave's Broker is still marked for death")
606
607
608 class Basedir(RunMixin, unittest.TestCase):
609 def testChangeBuilddir(self):
610 m = self.master
611 m.loadConfig(config_4)
612 m.readConfig = True
613 m.startService()
614
615 d = self.connectSlave()
616 d.addCallback(self._testChangeBuilddir_1)
617 return d
618
619 def _testChangeBuilddir_1(self, res):
620 self.bot = bot = self.slaves['bot1'].bot
621 self.builder = builder = bot.builders.get("dummy")
622 self.failUnless(builder)
623 # slavebuilddir value.
624 self.failUnlessEqual(builder.builddir, "sdummy")
625 self.failUnlessEqual(builder.basedir,
626 os.path.join("slavebase-bot1", "sdummy"))
627
628 d = self.master.loadConfig(config_4_newbasedir)
629 d.addCallback(self._testChangeBuilddir_2)
630 return d
631
632 def _testChangeBuilddir_2(self, res):
633 bot = self.bot
634 # this does NOT cause the builder to be replaced
635 builder = bot.builders.get("dummy")
636 self.failUnless(builder)
637 self.failUnlessIdentical(self.builder, builder)
638 # the basedir should be updated
639 self.failUnlessEqual(builder.builddir, "dummy2")
640 self.failUnlessEqual(builder.basedir,
641 os.path.join("slavebase-bot1", "dummy2"))
642
643 # add a new builder, which causes the basedir list to be reloaded
644 d = self.master.loadConfig(config_4_newbuilder)
645 return d
646
647 class Triggers(RunMixin, TestFlagMixin, unittest.TestCase):
648 config_trigger = config_base + """
649 from buildbot.scheduler import Triggerable, Scheduler
650 from buildbot.steps.trigger import Trigger
651 from buildbot.steps.dummy import Dummy
652 from buildbot.test.runutils import SetTestFlagStep
653 from buildbot.process.properties import WithProperties
654 c['schedulers'] = [
655 Scheduler('triggerer', None, 0.1, ['triggerer'], properties={'dyn':'dyn'}),
656 Triggerable('triggeree', ['triggeree'])
657 ]
658 triggerer = factory.BuildFactory()
659 triggerer.addSteps([
660 SetTestFlagStep(flagname='triggerer_started'),
661 Trigger(flunkOnFailure=True, @ARGS@),
662 SetTestFlagStep(flagname='triggerer_finished'),
663 ])
664 triggeree = factory.BuildFactory([
665 s(SetTestFlagStep, flagname='triggeree_started'),
666 s(@DUMMYCLASS@),
667 s(SetTestFlagStep, flagname='triggeree_finished'),
668 ])
669 c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1',
670 'builddir': 'triggerer', 'factory': triggerer},
671 {'name': 'triggeree', 'slavename': 'bot1',
672 'builddir': 'triggeree', 'factory': triggeree}]
673 """
674
675 def mkConfig(self, args, dummyclass="Dummy"):
676 return self.config_trigger.replace("@ARGS@", args).replace("@DUMMYCLASS@ ", dummyclass)
677
678 def setupTest(self, args, dummyclass, checkFn):
679 self.clearFlags()
680 m = self.master
681 m.loadConfig(self.mkConfig(args, dummyclass))
682 m.readConfig = True
683 m.startService()
684
685 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
686 m.change_svc.addChange(c)
687
688 d = self.connectSlave(builders=['triggerer', 'triggeree'])
689 d.addCallback(self.startTimer, 0.5, checkFn)
690 return d
691
692 def startTimer(self, res, time, next_fn):
693 d = defer.Deferred()
694 reactor.callLater(time, d.callback, None)
695 d.addCallback(next_fn)
696 return d
697
698 def testTriggerBuild(self):
699 return self.setupTest("schedulerNames=['triggeree']",
700 "Dummy",
701 self._checkTriggerBuild)
702
703 def _checkTriggerBuild(self, res):
704 self.failIfFlagNotSet('triggerer_started')
705 self.failIfFlagNotSet('triggeree_started')
706 self.failIfFlagSet('triggeree_finished')
707 self.failIfFlagNotSet('triggerer_finished')
708
709 def testTriggerBuildWait(self):
710 return self.setupTest("schedulerNames=['triggeree'], waitForFinish=1",
711 "Dummy",
712 self._checkTriggerBuildWait)
713
714 def _checkTriggerBuildWait(self, res):
715 self.failIfFlagNotSet('triggerer_started')
716 self.failIfFlagNotSet('triggeree_started')
717 self.failIfFlagSet('triggeree_finished')
718 self.failIfFlagSet('triggerer_finished')
719
720 def testProperties(self):
721 return self.setupTest("""
722 schedulerNames=['triggeree'],
723 set_properties={'lit' : 'lit'},
724 copy_properties=['dyn']
725 """, """
726 SetTestFlagStep, flagname='props',
727 value=WithProperties('%(lit:-MISSING)s:%(dyn:-MISSING)s')
728 """,
729 self._checkProperties)
730
731 def _checkProperties(self, res):
732 self.assertEqual(self.getFlag("props"), "lit:dyn")
733
734 class PropertyPropagation(RunMixin, TestFlagMixin, unittest.TestCase):
735 def setupTest(self, config, builders, checkFn, changeProps={}):
736 self.clearFlags()
737 m = self.master
738 m.loadConfig(config)
739 m.readConfig = True
740 m.startService()
741
742 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff",
743 properties=changeProps)
744 m.change_svc.addChange(c)
745
746 d = self.connectSlave(builders=builders)
747 d.addCallback(self.startTimer, 0.5, checkFn)
748 return d
749
750 def startTimer(self, res, time, next_fn):
751 d = defer.Deferred()
752 reactor.callLater(time, d.callback, None)
753 d.addCallback(next_fn)
754 return d
755
756 config_schprop = config_base + """
757 from buildbot.scheduler import Scheduler
758 from buildbot.steps.dummy import Dummy
759 from buildbot.test.runutils import SetTestFlagStep
760 from buildbot.process.properties import WithProperties
761 c['schedulers'] = [
762 Scheduler('mysched', None, 0.1, ['flagcolor'], properties={'color':'red'}),
763 ]
764 factory = factory.BuildFactory([
765 s(SetTestFlagStep, flagname='testresult',
766 value=WithProperties('color=%(color)s sched=%(scheduler)s')),
767 ])
768 c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1',
769 'builddir': 'test', 'factory': factory},
770 ]
771 """
772
773 def testScheduler(self):
774 def _check(res):
775 self.failUnlessEqual(self.getFlag('testresult'),
776 'color=red sched=mysched')
777 return self.setupTest(self.config_schprop, ['flagcolor'], _check)
778
779 config_changeprop = config_base + """
780 from buildbot.scheduler import Scheduler
781 from buildbot.steps.dummy import Dummy
782 from buildbot.test.runutils import SetTestFlagStep
783 from buildbot.process.properties import WithProperties
784 c['schedulers'] = [
785 Scheduler('mysched', None, 0.1, ['flagcolor'], properties={'color':'red'}),
786 ]
787 factory = factory.BuildFactory([
788 s(SetTestFlagStep, flagname='testresult',
789 value=WithProperties('color=%(color)s sched=%(scheduler)s prop1=%(prop1)s' )),
790 ])
791 c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1',
792 'builddir': 'test', 'factory': factory},
793 ]
794 """
795
796 def testChangeProp(self):
797 def _check(res):
798 self.failUnlessEqual(self.getFlag('testresult'),
799 'color=blue sched=mysched prop1=prop1')
800 return self.setupTest(self.config_changeprop, ['flagcolor'], _check,
801 changeProps={'color': 'blue', 'prop1': 'prop1'})
802
803 config_slaveprop = config_base + """
804 from buildbot.scheduler import Scheduler
805 from buildbot.steps.dummy import Dummy
806 from buildbot.test.runutils import SetTestFlagStep
807 from buildbot.process.properties import WithProperties
808 c['schedulers'] = [
809 Scheduler('mysched', None, 0.1, ['flagcolor'])
810 ]
811 c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'color':'orange'})]
812 factory = factory.BuildFactory([
813 s(SetTestFlagStep, flagname='testresult',
814 value=WithProperties('color=%(color)s slavename=%(slavename)s')),
815 ])
816 c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1',
817 'builddir': 'test', 'factory': factory},
818 ]
819 """
820 def testSlave(self):
821 def _check(res):
822 self.failUnlessEqual(self.getFlag('testresult'),
823 'color=orange slavename=bot1')
824 return self.setupTest(self.config_slaveprop, ['flagcolor'], _check)
825
826 config_trigger = config_base + """
827 from buildbot.scheduler import Triggerable, Scheduler
828 from buildbot.steps.trigger import Trigger
829 from buildbot.steps.dummy import Dummy
830 from buildbot.test.runutils import SetTestFlagStep
831 from buildbot.process.properties import WithProperties
832 c['schedulers'] = [
833 Scheduler('triggerer', None, 0.1, ['triggerer'],
834 properties={'color':'mauve', 'pls_trigger':'triggeree'}),
835 Triggerable('triggeree', ['triggeree'], properties={'color':'invisible'})
836 ]
837 triggerer = factory.BuildFactory([
838 s(SetTestFlagStep, flagname='testresult', value='wrongone'),
839 s(Trigger, flunkOnFailure=True,
840 schedulerNames=[WithProperties('%(pls_trigger)s')],
841 set_properties={'color' : WithProperties('%(color)s')}),
842 s(SetTestFlagStep, flagname='testresult', value='triggered'),
843 ])
844 triggeree = factory.BuildFactory([
845 s(SetTestFlagStep, flagname='testresult',
846 value=WithProperties('sched=%(scheduler)s color=%(color)s')),
847 ])
848 c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1',
849 'builddir': 'triggerer', 'factory': triggerer},
850 {'name': 'triggeree', 'slavename': 'bot1',
851 'builddir': 'triggeree', 'factory': triggeree}]
852 """
853 def testTrigger(self):
854 def _check(res):
855 self.failUnlessEqual(self.getFlag('testresult'),
856 'sched=triggeree color=mauve')
857 return self.setupTest(self.config_trigger,
858 ['triggerer', 'triggeree'], _check)
859
860
861 config_test_flag = config_base + """
862 from buildbot.scheduler import Scheduler
863 c['schedulers'] = [Scheduler('quick', None, 0.1, ['dummy'])]
864
865 from buildbot.test.runutils import SetTestFlagStep
866 f3 = factory.BuildFactory([
867 s(SetTestFlagStep, flagname='foo', value='bar'),
868 ])
869
870 c['builders'] = [{'name': 'dummy', 'slavename': 'bot1',
871 'builddir': 'dummy', 'factory': f3}]
872 """
873
874 class TestFlag(RunMixin, TestFlagMixin, unittest.TestCase):
875 """Test for the TestFlag functionality in runutils"""
876 def testTestFlag(self):
877 m = self.master
878 m.loadConfig(config_test_flag)
879 m.readConfig = True
880 m.startService()
881
882 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
883 m.change_svc.addChange(c)
884
885 d = self.connectSlave()
886 d.addCallback(self._testTestFlag_1)
887 return d
888
889 def _testTestFlag_1(self, res):
890 d = defer.Deferred()
891 reactor.callLater(0.5, d.callback, None)
892 d.addCallback(self._testTestFlag_2)
893 return d
894
895 def _testTestFlag_2(self, res):
896 self.failUnlessEqual(self.getFlag('foo'), 'bar')
897
898 # TODO: test everything, from Change submission to Scheduler to Build to
899 # Status. Use all the status types. Specifically I want to catch recurrences
900 # of the bug where I forgot to make Waterfall inherit from StatusReceiver
901 # such that buildSetSubmitted failed.
902
903 config_test_builder = config_base + """
904 from buildbot.scheduler import Scheduler
905 c['schedulers'] = [Scheduler('quick', 'dummy', 0.1, ['dummy']),
906 Scheduler('quick2', 'dummy2', 0.1, ['dummy2']),
907 Scheduler('quick3', 'dummy3', 0.1, ['dummy3'])]
908
909 from buildbot.steps.shell import ShellCommand
910 f3 = factory.BuildFactory([
911 s(ShellCommand, command="sleep 3", env={'blah':'blah'})
912 ])
913
914 c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', 'env': {'foo':'bar'},
915 'builddir': 'dummy', 'factory': f3}]
916
917 c['builders'].append({'name': 'dummy2', 'slavename': 'bot1',
918 'env': {'blah':'bar'}, 'builddir': 'dummy2',
919 'factory': f3})
920
921 f4 = factory.BuildFactory([
922 s(ShellCommand, command="sleep 3")
923 ])
924
925 c['builders'].append({'name': 'dummy3', 'slavename': 'bot1',
926 'env': {'blah':'bar'}, 'builddir': 'dummy3',
927 'factory': f4})
928 """
929
930 class TestBuilder(RunMixin, unittest.TestCase):
931 def setUp(self):
932 RunMixin.setUp(self)
933 self.master.loadConfig(config_test_builder)
934 self.master.readConfig = True
935 self.master.startService()
936 self.connectSlave(builders=["dummy", "dummy2", "dummy3"])
937
938 def doBuilderEnvTest(self, branch, cb):
939 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed",
940 branch=branch)
941 self.master.change_svc.addChange(c)
942
943 d = defer.Deferred()
944 reactor.callLater(0.5, d.callback, None)
945 d.addCallback(cb)
946
947 return d
948
949 def testBuilderEnv(self):
950 return self.doBuilderEnvTest("dummy", self._testBuilderEnv1)
951
952 def _testBuilderEnv1(self, res):
953 b = self.master.botmaster.builders['dummy']
954 build = b.building[0]
955 s = build.currentStep
956 self.failUnless('foo' in s.cmd.args['env'])
957 self.failUnlessEqual('bar', s.cmd.args['env']['foo'])
958 self.failUnless('blah' in s.cmd.args['env'])
959 self.failUnlessEqual('blah', s.cmd.args['env']['blah'])
960
961 def testBuilderEnvOverride(self):
962 return self.doBuilderEnvTest("dummy2", self._testBuilderEnvOverride1)
963
964 def _testBuilderEnvOverride1(self, res):
965 b = self.master.botmaster.builders['dummy2']
966 build = b.building[0]
967 s = build.currentStep
968 self.failUnless('blah' in s.cmd.args['env'])
969 self.failUnlessEqual('blah', s.cmd.args['env']['blah'])
970
971 def testBuilderNoStepEnv(self):
972 return self.doBuilderEnvTest("dummy3", self._testBuilderNoStepEnv1)
973
974 def _testBuilderNoStepEnv1(self, res):
975 b = self.master.botmaster.builders['dummy3']
976 build = b.building[0]
977 s = build.currentStep
978 self.failUnless('blah' in s.cmd.args['env'])
979 self.failUnlessEqual('bar', s.cmd.args['env']['blah'])
980
981 class SchedulerWatchers(RunMixin, TestFlagMixin, unittest.TestCase):
982 config_watchable = config_base + """
983 from buildbot.scheduler import AnyBranchScheduler
984 from buildbot.steps.dummy import Dummy
985 from buildbot.test.runutils import setTestFlag, SetTestFlagStep
986 s = AnyBranchScheduler(
987 name='abs',
988 branches=None,
989 treeStableTimer=0,
990 builderNames=['a', 'b'])
991 c['schedulers'] = [ s ]
992
993 # count the number of times a success watcher is called
994 numCalls = [ 0 ]
995 def watcher(ss):
996 numCalls[0] += 1
997 setTestFlag("numCalls", numCalls[0])
998 s.subscribeToSuccessfulBuilds(watcher)
999
1000 f = factory.BuildFactory()
1001 f.addStep(Dummy(timeout=0))
1002 c['builders'] = [{'name': 'a', 'slavename': 'bot1',
1003 'builddir': 'a', 'factory': f},
1004 {'name': 'b', 'slavename': 'bot1',
1005 'builddir': 'b', 'factory': f}]
1006 """
1007
1008 def testWatchers(self):
1009 self.clearFlags()
1010 m = self.master
1011 m.loadConfig(self.config_watchable)
1012 m.readConfig = True
1013 m.startService()
1014
1015 c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff")
1016 m.change_svc.addChange(c)
1017
1018 d = self.connectSlave(builders=['a', 'b'])
1019
1020 def pause(res):
1021 d = defer.Deferred()
1022 reactor.callLater(1, d.callback, res)
1023 return d
1024 d.addCallback(pause)
1025
1026 def checkFn(res):
1027 self.failUnlessEqual(self.getFlag('numCalls'), 1)
1028 d.addCallback(checkFn)
1029 return d
1030
1031 config_priority = """
1032 from buildbot.process import factory
1033 from buildbot.steps import dummy
1034 from buildbot.buildslave import BuildSlave
1035 s = factory.s
1036
1037 from buildbot.steps.shell import ShellCommand
1038 f1 = factory.BuildFactory([
1039 s(ShellCommand, command="sleep 1", env={'blah':'blah'})
1040 ])
1041
1042 BuildmasterConfig = c = {}
1043 slavenames = ['bot%i' % i for i in range(5)]
1044 c['slaves'] = [BuildSlave(name, 'sekrit', max_builds=1) for name in slavenames]
1045 c['schedulers'] = []
1046 c['builders'] = []
1047 c['builders'].append({'name':'quick1', 'slavenames':slavenames, 'builddir': 'qui ckdir1', 'factory': f1})
1048 c['builders'].append({'name':'quick2', 'slavenames':slavenames, 'builddir': 'qui ckdir2', 'factory': f1})
1049 c['slavePortnum'] = 0
1050 """
1051
1052 class BuildPrioritization(RunMixin, unittest.TestCase):
1053 def rmtree(self, d):
1054 rmtree(d)
1055
1056 def testPriority(self):
1057 self.rmtree("basedir")
1058 os.mkdir("basedir")
1059 self.master.loadConfig(config_priority)
1060 self.master.readConfig = True
1061 self.master.startService()
1062
1063 # Our fake source stamp
1064 # we override canBeMergedWith so that our requests don't get merged toge ther
1065 ss = SourceStamp()
1066 ss.canBeMergedWith = lambda x: False
1067
1068 # Send 10 requests to alternating builders
1069 # We fudge the submittedAt field after submitting since they're all
1070 # getting submitted so close together according to time.time()
1071 # and all we care about is what order they're run in.
1072 reqs = []
1073 self.start_order = []
1074 for i in range(10):
1075 req = BuildRequest(str(i), ss, "test_builder")
1076 j = i % 2 + 1
1077 self.master.botmaster.builders['quick%i' % j].submitBuildRequest(req )
1078 req.submittedAt = i
1079 # Keep track of what order the builds start in
1080 def append(build):
1081 self.start_order.append(int(build.reason))
1082 req.subscribe(append)
1083 reqs.append(req.waitUntilFinished())
1084
1085 dl = defer.DeferredList(reqs)
1086 dl.addCallback(self._all_finished)
1087
1088 def _delay(res):
1089 d1 = defer.Deferred()
1090 reactor.callLater(0.5, d1.callback, None)
1091 # this test depends upon this 0.5s delay landing us in the middle
1092 # of one of the builds.
1093 return d1
1094
1095 def _connect(res, i):
1096 return self.connectSlave(slavename="bot%i" % i, builders=["quick1", "quick2"])
1097
1098 # Now add the slaves
1099 d = self.connectSlave(slavename="bot0", builders=["quick1", "quick2"])
1100 for i in range(1,5):
1101 d.addCallback(_delay)
1102 d.addCallback(_connect, i)
1103
1104 d.addCallback(lambda x: dl)
1105
1106 return d
1107
1108 def _all_finished(self, *args):
1109 # The builds should have finished in proper order
1110 self.failUnlessEqual(self.start_order, range(10))
1111
1112 # Test graceful shutdown when no builds are active, as well as
1113 # canStartBuild after graceful shutdown is initiated
1114 config_graceful_shutdown_idle = config_base
1115 class GracefulShutdownIdle(RunMixin, unittest.TestCase):
1116 def testShutdown(self):
1117 self.rmtree("basedir")
1118 os.mkdir("basedir")
1119 self.master.loadConfig(config_graceful_shutdown_idle)
1120 self.master.readConfig = True
1121 self.master.startService()
1122 d = self.connectSlave(builders=['quick'])
1123 d.addCallback(self._do_shutdown)
1124 return d
1125
1126 def _do_shutdown(self, res):
1127 bs = self.master.botmaster.builders['quick'].slaves[0]
1128 # Check that the slave is accepting builds once it's connected
1129 self.assertEquals(bs.slave.canStartBuild(), True)
1130
1131 # Monkeypatch the slave's shutdown routine since the real shutdown
1132 # interrupts the test harness
1133 self.did_shutdown = False
1134 def _shutdown():
1135 self.did_shutdown = True
1136 bs.slave.shutdown = _shutdown
1137
1138 # Start a graceful shutdown
1139 bs.slave.slave_status.setGraceful(True)
1140 # Check that the slave isn't accepting builds any more
1141 self.assertEquals(bs.slave.canStartBuild(), False)
1142
1143 # Wait a little bit and then check that we (pretended to) shut down
1144 d = defer.Deferred()
1145 d.addCallback(self._check_shutdown)
1146 reactor.callLater(0.5, d.callback, None)
1147 return d
1148
1149 def _check_shutdown(self, res):
1150 self.assertEquals(self.did_shutdown, True)
1151
1152 # Test graceful shutdown when two builds are active
1153 config_graceful_shutdown_busy = config_base + """
1154 from buildbot.buildslave import BuildSlave
1155 c['slaves'] = [ BuildSlave('bot1', 'sekrit', max_builds=2) ]
1156
1157 from buildbot.scheduler import Scheduler
1158 c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy', 'dummy2'])]
1159
1160 c['builders'].append({'name': 'dummy', 'slavename': 'bot1',
1161 'builddir': 'dummy', 'factory': f2})
1162 c['builders'].append({'name': 'dummy2', 'slavename': 'bot1',
1163 'builddir': 'dummy2', 'factory': f2})
1164 """
1165 class GracefulShutdownBusy(RunMixin, unittest.TestCase):
1166 def testShutdown(self):
1167 self.rmtree("basedir")
1168 os.mkdir("basedir")
1169 d = self.master.loadConfig(config_graceful_shutdown_busy)
1170 d.addCallback(lambda res: self.master.startService())
1171 d.addCallback(lambda res: self.connectSlave())
1172
1173 def _send(res):
1174 # send a change. This will trigger both builders at the same
1175 # time, but since they share a slave, the max_builds=1 setting
1176 # will insure that only one of the two builds gets to run.
1177 cm = self.master.change_svc
1178 c = changes.Change("bob", ["Makefile", "foo/bar.c"],
1179 "changed stuff")
1180 cm.addChange(c)
1181 d.addCallback(_send)
1182
1183 def _delay(res):
1184 d1 = defer.Deferred()
1185 reactor.callLater(0.5, d1.callback, None)
1186 # this test depends upon this 0.5s delay landing us in the middle
1187 # of one of the builds.
1188 return d1
1189 d.addCallback(_delay)
1190
1191 # Start a graceful shutdown. We should be in the middle of two builds
1192 def _shutdown(res):
1193 bs = self.master.botmaster.builders['dummy'].slaves[0]
1194 # Monkeypatch the slave's shutdown routine since the real shutdown
1195 # interrupts the test harness
1196 self.did_shutdown = False
1197 def _shutdown():
1198 self.did_shutdown = True
1199 return defer.succeed(None)
1200 bs.slave.shutdown = _shutdown
1201 # Start a graceful shutdown
1202 bs.slave.slave_status.setGraceful(True)
1203
1204 builders = [ self.master.botmaster.builders[bn]
1205 for bn in ('dummy', 'dummy2') ]
1206 for builder in builders:
1207 self.failUnless(len(builder.slaves) == 1)
1208 from buildbot.process.builder import BUILDING
1209 building_bs = [ builder
1210 for builder in builders
1211 if builder.slaves[0].state == BUILDING ]
1212 # assert that both builds are running right now.
1213 self.failUnlessEqual(len(building_bs), 2)
1214
1215 d.addCallback(_shutdown)
1216
1217 # Wait a little bit again, and then make sure that we are still running
1218 # the two builds, and haven't shutdown yet
1219 d.addCallback(_delay)
1220 def _check(res):
1221 self.assertEquals(self.did_shutdown, False)
1222 builders = [ self.master.botmaster.builders[bn]
1223 for bn in ('dummy', 'dummy2') ]
1224 for builder in builders:
1225 self.failUnless(len(builder.slaves) == 1)
1226 from buildbot.process.builder import BUILDING
1227 building_bs = [ builder
1228 for builder in builders
1229 if builder.slaves[0].state == BUILDING ]
1230 # assert that both builds are running right now.
1231 self.failUnlessEqual(len(building_bs), 2)
1232 d.addCallback(_check)
1233
1234 # Wait for all the builds to finish
1235 def _wait_finish(res):
1236 builders = [ self.master.botmaster.builders[bn]
1237 for bn in ('dummy', 'dummy2') ]
1238 builds = []
1239 for builder in builders:
1240 builds.append(builder.builder_status.currentBuilds[0].waitUntilF inished())
1241 dl = defer.DeferredList(builds)
1242 return dl
1243 d.addCallback(_wait_finish)
1244
1245 # Wait a little bit after the builds finish, and then
1246 # check that the slave has shutdown
1247 d.addCallback(_delay)
1248 def _check_shutdown(res):
1249 # assert that we shutdown the slave
1250 self.assertEquals(self.did_shutdown, True)
1251 builders = [ self.master.botmaster.builders[bn]
1252 for bn in ('dummy', 'dummy2') ]
1253 from buildbot.process.builder import BUILDING
1254 building_bs = [ builder
1255 for builder in builders
1256 if builder.slaves[0].state == BUILDING ]
1257 # assert that no builds are running right now.
1258 self.failUnlessEqual(len(building_bs), 0)
1259 d.addCallback(_check_shutdown)
1260
1261 return d
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/test/test_reconfig.py ('k') | third_party/buildbot_7_12/buildbot/test/test_runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698