diff options
Diffstat (limited to 'buildbot/buildbot/test/test_run.py')
-rw-r--r-- | buildbot/buildbot/test/test_run.py | 1199 |
1 files changed, 0 insertions, 1199 deletions
diff --git a/buildbot/buildbot/test/test_run.py b/buildbot/buildbot/test/test_run.py deleted file mode 100644 index a04ea5b..0000000 --- a/buildbot/buildbot/test/test_run.py +++ /dev/null @@ -1,1199 +0,0 @@ -# -*- test-case-name: buildbot.test.test_run -*- - -from twisted.trial import unittest -from twisted.internet import reactor, defer -import os - -from buildbot import master, interfaces -from buildbot.sourcestamp import SourceStamp -from buildbot.changes import changes -from buildbot.status import builder -from buildbot.process.base import BuildRequest - -from buildbot.test.runutils import RunMixin, TestFlagMixin, rmtree - -config_base = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -f1 = factory.QuickBuildFactory('fakerep', 'cvsmodule', configure=None) - -f2 = factory.BuildFactory([ - dummy.Dummy(timeout=1), - dummy.RemoteDummy(timeout=2), - ]) - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit')] -c['schedulers'] = [] -c['builders'] = [] -c['builders'].append({'name':'quick', 'slavename':'bot1', - 'builddir': 'quickdir', 'factory': f1}) -c['slavePortnum'] = 0 -""" - -config_run = config_base + """ -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('quick', None, 120, ['quick'])] -""" - -config_can_build = config_base + """ -from buildbot.buildslave import BuildSlave -c['slaves'] = [ BuildSlave('bot1', 'sekrit') ] - -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy'])] - -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy1', 'factory': f2}] -""" - -config_cant_build = config_can_build + """ -class MyBuildSlave(BuildSlave): - def canStartBuild(self): return False -c['slaves'] = [ MyBuildSlave('bot1', 'sekrit') ] -""" - -config_concurrency = config_base + """ -from buildbot.buildslave import BuildSlave -c['slaves'] = [ BuildSlave('bot1', 'sekrit', max_builds=1) ] - -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy', 'dummy2'])] - -c['builders'].append({'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f2}) -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2}) -""" - -config_2 = config_base + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy1', 'factory': f2}, - {'name': 'testdummy', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2, 'category': 'test'}] -""" - -config_3 = config_2 + """ -c['builders'].append({'name': 'adummy', 'slavename': 'bot1', - 'builddir': 'adummy3', 'factory': f2}) -c['builders'].append({'name': 'bdummy', 'slavename': 'bot1', - 'builddir': 'adummy4', 'factory': f2, - 'category': 'test'}) -""" - -config_4 = config_base + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f2}] -""" - -config_4_newbasedir = config_4 + """ -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2}] -""" - -config_4_newbuilder = config_4_newbasedir + """ -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'builddir': 'dummy23', 'factory': f2}) -""" - -class Run(unittest.TestCase): - def rmtree(self, d): - rmtree(d) - - def testMaster(self): - self.rmtree("basedir") - os.mkdir("basedir") - m = master.BuildMaster("basedir") - m.loadConfig(config_run) - m.readConfig = True - m.startService() - cm = m.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - cm.addChange(c) - # verify that the Scheduler is now waiting - s = m.allSchedulers()[0] - self.failUnless(s.timer) - # halting the service will also stop the timer - d = defer.maybeDeferred(m.stopService) - return d - -class CanStartBuild(RunMixin, unittest.TestCase): - def rmtree(self, d): - rmtree(d) - - def testCanStartBuild(self): - return self.do_test(config_can_build, True) - - def testCantStartBuild(self): - return self.do_test(config_cant_build, False) - - def do_test(self, config, builder_should_run): - self.master.loadConfig(config) - self.master.readConfig = True - self.master.startService() - d = self.connectSlave() - - # send a change - cm = self.master.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - cm.addChange(c) - - d.addCallback(self._do_test1, builder_should_run) - - return d - - def _do_test1(self, res, builder_should_run): - # delay a little bit. Note that relying upon timers is a bit fragile, - # in this case we're hoping that our 0.5 second timer will land us - # somewhere in the middle of the [0.1s, 3.1s] window (after the 0.1 - # second Scheduler fires, then during the 3-second build), so that - # when we sample BuildSlave.state, we'll see BUILDING (or IDLE if the - # slave was told to be unavailable). On a heavily loaded system, our - # 0.5 second timer might not actually fire until after the build has - # completed. In the long run, it would be good to change this test to - # pass under those circumstances too. - d = defer.Deferred() - reactor.callLater(.5, d.callback, builder_should_run) - d.addCallback(self._do_test2) - return d - - def _do_test2(self, builder_should_run): - b = self.master.botmaster.builders['dummy'] - self.failUnless(len(b.slaves) == 1) - - bs = b.slaves[0] - from buildbot.process.builder import IDLE, BUILDING - if builder_should_run: - self.failUnlessEqual(bs.state, BUILDING) - else: - self.failUnlessEqual(bs.state, IDLE) - - -class ConcurrencyLimit(RunMixin, unittest.TestCase): - - def testConcurrencyLimit(self): - d = self.master.loadConfig(config_concurrency) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectSlave()) - - def _send(res): - # send a change. This will trigger both builders at the same - # time, but since they share a slave, the max_builds=1 setting - # will insure that only one of the two builds gets to run. - cm = self.master.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], - "changed stuff") - cm.addChange(c) - d.addCallback(_send) - - def _delay(res): - d1 = defer.Deferred() - reactor.callLater(1, d1.callback, None) - # this test depends upon this 1s delay landing us in the middle - # of one of the builds. - return d1 - d.addCallback(_delay) - - def _check(res): - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - for builder in builders: - self.failUnless(len(builder.slaves) == 1) - - from buildbot.process.builder import BUILDING - building_bs = [ builder - for builder in builders - if builder.slaves[0].state == BUILDING ] - # assert that only one build is running right now. If the - # max_builds= weren't in effect, this would be 2. - self.failUnlessEqual(len(building_bs), 1) - d.addCallback(_check) - - return d - - -class Ping(RunMixin, unittest.TestCase): - def testPing(self): - self.master.loadConfig(config_2) - self.master.readConfig = True - self.master.startService() - - d = self.connectSlave() - d.addCallback(self._testPing_1) - return d - - def _testPing_1(self, res): - d = interfaces.IControl(self.master).getBuilder("dummy").ping(1) - d.addCallback(self._testPing_2) - return d - - def _testPing_2(self, res): - pass - -class BuilderNames(unittest.TestCase): - - def testGetBuilderNames(self): - os.mkdir("bnames") - m = master.BuildMaster("bnames") - s = m.getStatus() - - m.loadConfig(config_3) - m.readConfig = True - - self.failUnlessEqual(s.getBuilderNames(), - ["dummy", "testdummy", "adummy", "bdummy"]) - self.failUnlessEqual(s.getBuilderNames(categories=['test']), - ["testdummy", "bdummy"]) - -class Disconnect(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - - # verify that disconnecting the slave during a build properly - # terminates the build - m = self.master - s = self.status - c = self.control - - m.loadConfig(config_2) - m.readConfig = True - m.startService() - - self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"]) - self.s1 = s1 = s.getBuilder("dummy") - self.failUnlessEqual(s1.getName(), "dummy") - self.failUnlessEqual(s1.getState(), ("offline", [])) - self.failUnlessEqual(s1.getCurrentBuilds(), []) - self.failUnlessEqual(s1.getLastFinishedBuild(), None) - self.failUnlessEqual(s1.getBuild(-1), None) - - d = self.connectSlave() - d.addCallback(self._disconnectSetup_1) - return d - - def _disconnectSetup_1(self, res): - self.failUnlessEqual(self.s1.getState(), ("idle", [])) - - - def verifyDisconnect(self, bs): - self.failUnless(bs.isFinished()) - - step1 = bs.getSteps()[0] - self.failUnlessEqual(step1.getText(), ["delay", "interrupted"]) - self.failUnlessEqual(step1.getResults()[0], builder.FAILURE) - - self.failUnlessEqual(bs.getResults(), builder.FAILURE) - - def verifyDisconnect2(self, bs): - self.failUnless(bs.isFinished()) - - step1 = bs.getSteps()[1] - self.failUnlessEqual(step1.getText(), ["remote", "delay", "2 secs", - "failed", "slave", "lost"]) - self.failUnlessEqual(step1.getResults()[0], builder.FAILURE) - - self.failUnlessEqual(bs.getResults(), builder.FAILURE) - - def submitBuild(self): - ss = SourceStamp() - br = BuildRequest("forced build", ss, "dummy") - self.control.getBuilder("dummy").requestBuild(br) - d = defer.Deferred() - def _started(bc): - br.unsubscribe(_started) - d.callback(bc) - br.subscribe(_started) - return d - - def testIdle2(self): - # now suppose the slave goes missing - self.disappearSlave(allowReconnect=False) - - # forcing a build will work: the build detect that the slave is no - # longer available and will be re-queued. Wait 5 seconds, then check - # to make sure the build is still in the 'waiting for a slave' queue. - self.control.getBuilder("dummy").original.START_BUILD_TIMEOUT = 1 - req = BuildRequest("forced build", SourceStamp(), "test_builder") - self.failUnlessEqual(req.startCount, 0) - self.control.getBuilder("dummy").requestBuild(req) - # this should ping the slave, which doesn't respond, and then give up - # after a second. The BuildRequest will be re-queued, and its - # .startCount will be incremented. - d = defer.Deferred() - d.addCallback(self._testIdle2_1, req) - reactor.callLater(3, d.callback, None) - return d - testIdle2.timeout = 5 - - def _testIdle2_1(self, res, req): - self.failUnlessEqual(req.startCount, 1) - cancelled = req.cancel() - self.failUnless(cancelled) - - - def testBuild1(self): - # this next sequence is timing-dependent. The dummy build takes at - # least 3 seconds to complete, and this batch of commands must - # complete within that time. - # - d = self.submitBuild() - d.addCallback(self._testBuild1_1) - return d - - def _testBuild1_1(self, bc): - bs = bc.getStatus() - # now kill the slave before it gets to start the first step - d = self.shutdownAllSlaves() # dies before it gets started - d.addCallback(self._testBuild1_2, bs) - return d # TODO: this used to have a 5-second timeout - - def _testBuild1_2(self, res, bs): - # now examine the just-stopped build and make sure it is really - # stopped. This is checking for bugs in which the slave-detach gets - # missed or causes an exception which prevents the build from being - # marked as "finished due to an error". - d = bs.waitUntilFinished() - d2 = self.master.botmaster.waitUntilBuilderDetached("dummy") - dl = defer.DeferredList([d, d2]) - dl.addCallback(self._testBuild1_3, bs) - return dl # TODO: this had a 5-second timeout too - - def _testBuild1_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild2(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild2_1) - return d - testBuild2.timeout = 30 - - def _testBuild2_1(self, bc): - bs = bc.getStatus() - # shutdown the slave while it's running the first step - reactor.callLater(0.5, self.shutdownAllSlaves) - - d = bs.waitUntilFinished() - d.addCallback(self._testBuild2_2, bs) - return d - - def _testBuild2_2(self, res, bs): - # we hit here when the build has finished. The builder is still being - # torn down, however, so spin for another second to allow the - # callLater(0) in Builder.detached to fire. - d = defer.Deferred() - reactor.callLater(1, d.callback, None) - d.addCallback(self._testBuild2_3, bs) - return d - - def _testBuild2_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild3(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild3_1) - return d - testBuild3.timeout = 30 - - def _testBuild3_1(self, bc): - bs = bc.getStatus() - # kill the slave while it's running the first step - reactor.callLater(0.5, self.killSlave) - d = bs.waitUntilFinished() - d.addCallback(self._testBuild3_2, bs) - return d - - def _testBuild3_2(self, res, bs): - # the builder is still being torn down, so give it another second - d = defer.Deferred() - reactor.callLater(1, d.callback, None) - d.addCallback(self._testBuild3_3, bs) - return d - - def _testBuild3_3(self, res, bs): - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect(bs) - - - def testBuild4(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testBuild4_1) - return d - testBuild4.timeout = 30 - - def _testBuild4_1(self, bc): - bs = bc.getStatus() - # kill the slave while it's running the second (remote) step - reactor.callLater(1.5, self.killSlave) - d = bs.waitUntilFinished() - d.addCallback(self._testBuild4_2, bs) - return d - - def _testBuild4_2(self, res, bs): - # at this point, the slave is in the process of being removed, so it - # could either be 'idle' or 'offline'. I think there is a - # reactor.callLater(0) standing between here and the offline state. - #reactor.iterate() # TODO: remove the need for this - - self.failUnlessEqual(self.s1.getState()[0], "offline") - self.verifyDisconnect2(bs) - - - def testInterrupt(self): - # this next sequence is timing-dependent - d = self.submitBuild() - d.addCallback(self._testInterrupt_1) - return d - testInterrupt.timeout = 30 - - def _testInterrupt_1(self, bc): - bs = bc.getStatus() - # halt the build while it's running the first step - reactor.callLater(0.5, bc.stopBuild, "bang go splat") - d = bs.waitUntilFinished() - d.addCallback(self._testInterrupt_2, bs) - return d - - def _testInterrupt_2(self, res, bs): - self.verifyDisconnect(bs) - - - def testDisappear(self): - bc = self.control.getBuilder("dummy") - - # ping should succeed - d = bc.ping(1) - d.addCallback(self._testDisappear_1, bc) - return d - - def _testDisappear_1(self, res, bc): - self.failUnlessEqual(res, True) - - # now, before any build is run, make the slave disappear - self.disappearSlave(allowReconnect=False) - - # at this point, a ping to the slave should timeout - d = bc.ping(1) - d.addCallback(self. _testDisappear_2) - return d - def _testDisappear_2(self, res): - self.failUnlessEqual(res, False) - - def testDuplicate(self): - bc = self.control.getBuilder("dummy") - bs = self.status.getBuilder("dummy") - ss = bs.getSlaves()[0] - - self.failUnless(ss.isConnected()) - self.failUnlessEqual(ss.getAdmin(), "one") - - # now, before any build is run, make the first slave disappear - self.disappearSlave(allowReconnect=False) - - d = self.master.botmaster.waitUntilBuilderDetached("dummy") - # now let the new slave take over - self.connectSlave2() - d.addCallback(self._testDuplicate_1, ss) - return d - testDuplicate.timeout = 5 - - def _testDuplicate_1(self, res, ss): - d = self.master.botmaster.waitUntilBuilderAttached("dummy") - d.addCallback(self._testDuplicate_2, ss) - return d - - def _testDuplicate_2(self, res, ss): - self.failUnless(ss.isConnected()) - self.failUnlessEqual(ss.getAdmin(), "two") - - -class Disconnect2(RunMixin, unittest.TestCase): - - def setUp(self): - RunMixin.setUp(self) - # verify that disconnecting the slave during a build properly - # terminates the build - m = self.master - s = self.status - c = self.control - - m.loadConfig(config_2) - m.readConfig = True - m.startService() - - self.failUnlessEqual(s.getBuilderNames(), ["dummy", "testdummy"]) - self.s1 = s1 = s.getBuilder("dummy") - self.failUnlessEqual(s1.getName(), "dummy") - self.failUnlessEqual(s1.getState(), ("offline", [])) - self.failUnlessEqual(s1.getCurrentBuilds(), []) - self.failUnlessEqual(s1.getLastFinishedBuild(), None) - self.failUnlessEqual(s1.getBuild(-1), None) - - d = self.connectSlaveFastTimeout() - d.addCallback(self._setup_disconnect2_1) - return d - - def _setup_disconnect2_1(self, res): - self.failUnlessEqual(self.s1.getState(), ("idle", [])) - - - def testSlaveTimeout(self): - # now suppose the slave goes missing. We want to find out when it - # creates a new Broker, so we reach inside and mark it with the - # well-known sigil of impending messy death. - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - broker = bd.remote.broker - broker.redshirt = 1 - - # make sure the keepalives will keep the connection up - d = defer.Deferred() - reactor.callLater(5, d.callback, None) - d.addCallback(self._testSlaveTimeout_1) - return d - testSlaveTimeout.timeout = 20 - - def _testSlaveTimeout_1(self, res): - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - if not bd.remote or not hasattr(bd.remote.broker, "redshirt"): - self.fail("slave disconnected when it shouldn't have") - - d = self.master.botmaster.waitUntilBuilderDetached("dummy") - # whoops! how careless of me. - self.disappearSlave(allowReconnect=True) - # the slave will realize the connection is lost within 2 seconds, and - # reconnect. - d.addCallback(self._testSlaveTimeout_2) - return d - - def _testSlaveTimeout_2(self, res): - # the ReconnectingPBClientFactory will attempt a reconnect in two - # seconds. - d = self.master.botmaster.waitUntilBuilderAttached("dummy") - d.addCallback(self._testSlaveTimeout_3) - return d - - def _testSlaveTimeout_3(self, res): - # make sure it is a new connection (i.e. a new Broker) - bd = self.slaves['bot1'].getServiceNamed("bot").builders["dummy"] - self.failUnless(bd.remote, "hey, slave isn't really connected") - self.failIf(hasattr(bd.remote.broker, "redshirt"), - "hey, slave's Broker is still marked for death") - - -class Basedir(RunMixin, unittest.TestCase): - def testChangeBuilddir(self): - m = self.master - m.loadConfig(config_4) - m.readConfig = True - m.startService() - - d = self.connectSlave() - d.addCallback(self._testChangeBuilddir_1) - return d - - def _testChangeBuilddir_1(self, res): - self.bot = bot = self.slaves['bot1'].bot - self.builder = builder = bot.builders.get("dummy") - self.failUnless(builder) - self.failUnlessEqual(builder.builddir, "dummy") - self.failUnlessEqual(builder.basedir, - os.path.join("slavebase-bot1", "dummy")) - - d = self.master.loadConfig(config_4_newbasedir) - d.addCallback(self._testChangeBuilddir_2) - return d - - def _testChangeBuilddir_2(self, res): - bot = self.bot - # this does NOT cause the builder to be replaced - builder = bot.builders.get("dummy") - self.failUnless(builder) - self.failUnlessIdentical(self.builder, builder) - # the basedir should be updated - self.failUnlessEqual(builder.builddir, "dummy2") - self.failUnlessEqual(builder.basedir, - os.path.join("slavebase-bot1", "dummy2")) - - # add a new builder, which causes the basedir list to be reloaded - d = self.master.loadConfig(config_4_newbuilder) - return d - -class Triggers(RunMixin, TestFlagMixin, unittest.TestCase): - config_trigger = config_base + """ -from buildbot.scheduler import Triggerable, Scheduler -from buildbot.steps.trigger import Trigger -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -c['schedulers'] = [ - Scheduler('triggerer', None, 0.1, ['triggerer']), - Triggerable('triggeree', ['triggeree']) -] -triggerer = factory.BuildFactory() -triggerer.addSteps([ - SetTestFlagStep(flagname='triggerer_started'), - Trigger(flunkOnFailure=True, @ARGS@), - SetTestFlagStep(flagname='triggerer_finished'), - ]) -triggeree = factory.BuildFactory([ - s(SetTestFlagStep, flagname='triggeree_started'), - s(@DUMMYCLASS@), - s(SetTestFlagStep, flagname='triggeree_finished'), - ]) -c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1', - 'builddir': 'triggerer', 'factory': triggerer}, - {'name': 'triggeree', 'slavename': 'bot1', - 'builddir': 'triggeree', 'factory': triggeree}] -""" - - def mkConfig(self, args, dummyclass="Dummy"): - return self.config_trigger.replace("@ARGS@", args).replace("@DUMMYCLASS@", dummyclass) - - def setupTest(self, args, dummyclass, checkFn): - self.clearFlags() - m = self.master - m.loadConfig(self.mkConfig(args, dummyclass)) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave(builders=['triggerer', 'triggeree']) - d.addCallback(self.startTimer, 0.5, checkFn) - return d - - def startTimer(self, res, time, next_fn): - d = defer.Deferred() - reactor.callLater(time, d.callback, None) - d.addCallback(next_fn) - return d - - def testTriggerBuild(self): - return self.setupTest("schedulerNames=['triggeree']", - "Dummy", - self._checkTriggerBuild) - - def _checkTriggerBuild(self, res): - self.failIfFlagNotSet('triggerer_started') - self.failIfFlagNotSet('triggeree_started') - self.failIfFlagSet('triggeree_finished') - self.failIfFlagNotSet('triggerer_finished') - - def testTriggerBuildWait(self): - return self.setupTest("schedulerNames=['triggeree'], waitForFinish=1", - "Dummy", - self._checkTriggerBuildWait) - - def _checkTriggerBuildWait(self, res): - self.failIfFlagNotSet('triggerer_started') - self.failIfFlagNotSet('triggeree_started') - self.failIfFlagSet('triggeree_finished') - self.failIfFlagSet('triggerer_finished') - -class PropertyPropagation(RunMixin, TestFlagMixin, unittest.TestCase): - def setupTest(self, config, builders, checkFn): - self.clearFlags() - m = self.master - m.loadConfig(config) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave(builders=builders) - d.addCallback(self.startTimer, 0.5, checkFn) - return d - - def startTimer(self, res, time, next_fn): - d = defer.Deferred() - reactor.callLater(time, d.callback, None) - d.addCallback(next_fn) - return d - - config_schprop = config_base + """ -from buildbot.scheduler import Scheduler -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('mysched', None, 0.1, ['flagcolor'], properties={'color':'red'}), -] -factory = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('color=%(color)s sched=%(scheduler)s')), - ]) -c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1', - 'builddir': 'test', 'factory': factory}, - ] -""" - - def testScheduler(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'color=red sched=mysched') - return self.setupTest(self.config_schprop, ['flagcolor'], _check) - - config_slaveprop = config_base + """ -from buildbot.scheduler import Scheduler -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('mysched', None, 0.1, ['flagcolor']) -] -c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'color':'orange'})] -factory = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('color=%(color)s slavename=%(slavename)s')), - ]) -c['builders'] = [{'name': 'flagcolor', 'slavename': 'bot1', - 'builddir': 'test', 'factory': factory}, - ] -""" - def testSlave(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'color=orange slavename=bot1') - return self.setupTest(self.config_slaveprop, ['flagcolor'], _check) - - config_trigger = config_base + """ -from buildbot.scheduler import Triggerable, Scheduler -from buildbot.steps.trigger import Trigger -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import SetTestFlagStep -from buildbot.process.properties import WithProperties -c['schedulers'] = [ - Scheduler('triggerer', None, 0.1, ['triggerer'], - properties={'color':'mauve', 'pls_trigger':'triggeree'}), - Triggerable('triggeree', ['triggeree'], properties={'color':'invisible'}) -] -triggerer = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', value='wrongone'), - s(Trigger, flunkOnFailure=True, - schedulerNames=[WithProperties('%(pls_trigger)s')], - set_properties={'color' : WithProperties('%(color)s')}), - s(SetTestFlagStep, flagname='testresult', value='triggered'), - ]) -triggeree = factory.BuildFactory([ - s(SetTestFlagStep, flagname='testresult', - value=WithProperties('sched=%(scheduler)s color=%(color)s')), - ]) -c['builders'] = [{'name': 'triggerer', 'slavename': 'bot1', - 'builddir': 'triggerer', 'factory': triggerer}, - {'name': 'triggeree', 'slavename': 'bot1', - 'builddir': 'triggeree', 'factory': triggeree}] -""" - def testTrigger(self): - def _check(res): - self.failUnlessEqual(self.getFlag('testresult'), - 'sched=triggeree color=mauve') - return self.setupTest(self.config_trigger, - ['triggerer', 'triggeree'], _check) - - -config_test_flag = config_base + """ -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('quick', None, 0.1, ['dummy'])] - -from buildbot.test.runutils import SetTestFlagStep -f3 = factory.BuildFactory([ - s(SetTestFlagStep, flagname='foo', value='bar'), - ]) - -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f3}] -""" - -class TestFlag(RunMixin, TestFlagMixin, unittest.TestCase): - """Test for the TestFlag functionality in runutils""" - def testTestFlag(self): - m = self.master - m.loadConfig(config_test_flag) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave() - d.addCallback(self._testTestFlag_1) - return d - - def _testTestFlag_1(self, res): - d = defer.Deferred() - reactor.callLater(0.5, d.callback, None) - d.addCallback(self._testTestFlag_2) - return d - - def _testTestFlag_2(self, res): - self.failUnlessEqual(self.getFlag('foo'), 'bar') - -# TODO: test everything, from Change submission to Scheduler to Build to -# Status. Use all the status types. Specifically I want to catch recurrences -# of the bug where I forgot to make Waterfall inherit from StatusReceiver -# such that buildSetSubmitted failed. - -config_test_builder = config_base + """ -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('quick', 'dummy', 0.1, ['dummy']), - Scheduler('quick2', 'dummy2', 0.1, ['dummy2']), - Scheduler('quick3', 'dummy3', 0.1, ['dummy3'])] - -from buildbot.steps.shell import ShellCommand -f3 = factory.BuildFactory([ - s(ShellCommand, command="sleep 3", env={'blah':'blah'}) - ]) - -c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', 'env': {'foo':'bar'}, - 'builddir': 'dummy', 'factory': f3}] - -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'env': {'blah':'bar'}, 'builddir': 'dummy2', - 'factory': f3}) - -f4 = factory.BuildFactory([ - s(ShellCommand, command="sleep 3") - ]) - -c['builders'].append({'name': 'dummy3', 'slavename': 'bot1', - 'env': {'blah':'bar'}, 'builddir': 'dummy3', - 'factory': f4}) -""" - -class TestBuilder(RunMixin, unittest.TestCase): - def setUp(self): - RunMixin.setUp(self) - self.master.loadConfig(config_test_builder) - self.master.readConfig = True - self.master.startService() - self.connectSlave(builders=["dummy", "dummy2", "dummy3"]) - - def doBuilderEnvTest(self, branch, cb): - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed", - branch=branch) - self.master.change_svc.addChange(c) - - d = defer.Deferred() - reactor.callLater(0.5, d.callback, None) - d.addCallback(cb) - - return d - - def testBuilderEnv(self): - return self.doBuilderEnvTest("dummy", self._testBuilderEnv1) - - def _testBuilderEnv1(self, res): - b = self.master.botmaster.builders['dummy'] - build = b.building[0] - s = build.currentStep - self.failUnless('foo' in s.cmd.args['env']) - self.failUnlessEqual('bar', s.cmd.args['env']['foo']) - self.failUnless('blah' in s.cmd.args['env']) - self.failUnlessEqual('blah', s.cmd.args['env']['blah']) - - def testBuilderEnvOverride(self): - return self.doBuilderEnvTest("dummy2", self._testBuilderEnvOverride1) - - def _testBuilderEnvOverride1(self, res): - b = self.master.botmaster.builders['dummy2'] - build = b.building[0] - s = build.currentStep - self.failUnless('blah' in s.cmd.args['env']) - self.failUnlessEqual('blah', s.cmd.args['env']['blah']) - - def testBuilderNoStepEnv(self): - return self.doBuilderEnvTest("dummy3", self._testBuilderNoStepEnv1) - - def _testBuilderNoStepEnv1(self, res): - b = self.master.botmaster.builders['dummy3'] - build = b.building[0] - s = build.currentStep - self.failUnless('blah' in s.cmd.args['env']) - self.failUnlessEqual('bar', s.cmd.args['env']['blah']) - -class SchedulerWatchers(RunMixin, TestFlagMixin, unittest.TestCase): - config_watchable = config_base + """ -from buildbot.scheduler import AnyBranchScheduler -from buildbot.steps.dummy import Dummy -from buildbot.test.runutils import setTestFlag, SetTestFlagStep -s = AnyBranchScheduler( - name='abs', - branches=None, - treeStableTimer=0, - builderNames=['a', 'b']) -c['schedulers'] = [ s ] - -# count the number of times a success watcher is called -numCalls = [ 0 ] -def watcher(ss): - numCalls[0] += 1 - setTestFlag("numCalls", numCalls[0]) -s.subscribeToSuccessfulBuilds(watcher) - -f = factory.BuildFactory() -f.addStep(Dummy(timeout=0)) -c['builders'] = [{'name': 'a', 'slavename': 'bot1', - 'builddir': 'a', 'factory': f}, - {'name': 'b', 'slavename': 'bot1', - 'builddir': 'b', 'factory': f}] -""" - - def testWatchers(self): - self.clearFlags() - m = self.master - m.loadConfig(self.config_watchable) - m.readConfig = True - m.startService() - - c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed stuff") - m.change_svc.addChange(c) - - d = self.connectSlave(builders=['a', 'b']) - - def pause(res): - d = defer.Deferred() - reactor.callLater(1, d.callback, res) - return d - d.addCallback(pause) - - def checkFn(res): - self.failUnlessEqual(self.getFlag('numCalls'), 1) - d.addCallback(checkFn) - return d - -config_priority = """ -from buildbot.process import factory -from buildbot.steps import dummy -from buildbot.buildslave import BuildSlave -s = factory.s - -from buildbot.steps.shell import ShellCommand -f1 = factory.BuildFactory([ - s(ShellCommand, command="sleep 3", env={'blah':'blah'}) - ]) - -BuildmasterConfig = c = {} -c['slaves'] = [BuildSlave('bot1', 'sekrit', max_builds=1)] -c['schedulers'] = [] -c['builders'] = [] -c['builders'].append({'name':'quick1', 'slavename':'bot1', 'builddir': 'quickdir1', 'factory': f1}) -c['builders'].append({'name':'quick2', 'slavename':'bot1', 'builddir': 'quickdir2', 'factory': f1}) -c['slavePortnum'] = 0 -""" - -class BuildPrioritization(RunMixin, unittest.TestCase): - def rmtree(self, d): - rmtree(d) - - def testPriority(self): - self.rmtree("basedir") - os.mkdir("basedir") - self.master.loadConfig(config_priority) - self.master.readConfig = True - self.master.startService() - - d = self.connectSlave(builders=['quick1', 'quick2']) - d.addCallback(self._connected) - - return d - - def _connected(self, *args): - # Our fake source stamp - # we override canBeMergedWith so that our requests don't get merged together - ss = SourceStamp() - ss.canBeMergedWith = lambda x: False - - # Send one request to tie up the slave before sending future requests - req0 = BuildRequest("reason", ss, "test_builder") - self.master.botmaster.builders['quick1'].submitBuildRequest(req0) - - # Send 10 requests to alternating builders - # We fudge the submittedAt field after submitting since they're all - # getting submitted so close together according to time.time() - # and all we care about is what order they're run in. - reqs = [] - self.finish_order = [] - for i in range(10): - req = BuildRequest(str(i), ss, "test_builder") - j = i % 2 + 1 - self.master.botmaster.builders['quick%i' % j].submitBuildRequest(req) - req.submittedAt = i - # Keep track of what order the builds finished in - def append(item, arg): - self.finish_order.append(item) - req.waitUntilFinished().addCallback(append, req) - reqs.append(req.waitUntilFinished()) - - dl = defer.DeferredList(reqs) - dl.addCallback(self._all_finished) - - # After our first build finishes, we should wait for the rest to finish - d = req0.waitUntilFinished() - d.addCallback(lambda x: dl) - return d - - def _all_finished(self, *args): - # The builds should have finished in proper order - self.failUnlessEqual([int(b.reason) for b in self.finish_order], range(10)) - -# Test graceful shutdown when no builds are active, as well as -# canStartBuild after graceful shutdown is initiated -config_graceful_shutdown_idle = config_base -class GracefulShutdownIdle(RunMixin, unittest.TestCase): - def testShutdown(self): - self.rmtree("basedir") - os.mkdir("basedir") - self.master.loadConfig(config_graceful_shutdown_idle) - self.master.readConfig = True - self.master.startService() - d = self.connectSlave(builders=['quick']) - d.addCallback(self._do_shutdown) - return d - - def _do_shutdown(self, res): - bs = self.master.botmaster.builders['quick'].slaves[0] - # Check that the slave is accepting builds once it's connected - self.assertEquals(bs.slave.canStartBuild(), True) - - # Monkeypatch the slave's shutdown routine since the real shutdown - # interrupts the test harness - self.did_shutdown = False - def _shutdown(): - self.did_shutdown = True - bs.slave.shutdown = _shutdown - - # Start a graceful shutdown - bs.slave.slave_status.setGraceful(True) - # Check that the slave isn't accepting builds any more - self.assertEquals(bs.slave.canStartBuild(), False) - - # Wait a little bit and then check that we (pretended to) shut down - d = defer.Deferred() - d.addCallback(self._check_shutdown) - reactor.callLater(0.5, d.callback, None) - return d - - def _check_shutdown(self, res): - self.assertEquals(self.did_shutdown, True) - -# Test graceful shutdown when two builds are active -config_graceful_shutdown_busy = config_base + """ -from buildbot.buildslave import BuildSlave -c['slaves'] = [ BuildSlave('bot1', 'sekrit', max_builds=2) ] - -from buildbot.scheduler import Scheduler -c['schedulers'] = [Scheduler('dummy', None, 0.1, ['dummy', 'dummy2'])] - -c['builders'].append({'name': 'dummy', 'slavename': 'bot1', - 'builddir': 'dummy', 'factory': f2}) -c['builders'].append({'name': 'dummy2', 'slavename': 'bot1', - 'builddir': 'dummy2', 'factory': f2}) -""" -class GracefulShutdownBusy(RunMixin, unittest.TestCase): - def testShutdown(self): - self.rmtree("basedir") - os.mkdir("basedir") - d = self.master.loadConfig(config_graceful_shutdown_busy) - d.addCallback(lambda res: self.master.startService()) - d.addCallback(lambda res: self.connectSlave()) - - def _send(res): - # send a change. This will trigger both builders at the same - # time, but since they share a slave, the max_builds=1 setting - # will insure that only one of the two builds gets to run. - cm = self.master.change_svc - c = changes.Change("bob", ["Makefile", "foo/bar.c"], - "changed stuff") - cm.addChange(c) - d.addCallback(_send) - - def _delay(res): - d1 = defer.Deferred() - reactor.callLater(0.5, d1.callback, None) - # this test depends upon this 0.5s delay landing us in the middle - # of one of the builds. - return d1 - d.addCallback(_delay) - - # Start a graceful shutdown. We should be in the middle of two builds - def _shutdown(res): - bs = self.master.botmaster.builders['dummy'].slaves[0] - # Monkeypatch the slave's shutdown routine since the real shutdown - # interrupts the test harness - self.did_shutdown = False - def _shutdown(): - self.did_shutdown = True - return defer.succeed(None) - bs.slave.shutdown = _shutdown - # Start a graceful shutdown - bs.slave.slave_status.setGraceful(True) - - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - for builder in builders: - self.failUnless(len(builder.slaves) == 1) - from buildbot.process.builder import BUILDING - building_bs = [ builder - for builder in builders - if builder.slaves[0].state == BUILDING ] - # assert that both builds are running right now. - self.failUnlessEqual(len(building_bs), 2) - - d.addCallback(_shutdown) - - # Wait a little bit again, and then make sure that we are still running - # the two builds, and haven't shutdown yet - d.addCallback(_delay) - def _check(res): - self.assertEquals(self.did_shutdown, False) - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - for builder in builders: - self.failUnless(len(builder.slaves) == 1) - from buildbot.process.builder import BUILDING - building_bs = [ builder - for builder in builders - if builder.slaves[0].state == BUILDING ] - # assert that both builds are running right now. - self.failUnlessEqual(len(building_bs), 2) - d.addCallback(_check) - - # Wait for all the builds to finish - def _wait_finish(res): - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - builds = [] - for builder in builders: - builds.append(builder.builder_status.currentBuilds[0].waitUntilFinished()) - dl = defer.DeferredList(builds) - return dl - d.addCallback(_wait_finish) - - # Wait a little bit after the builds finish, and then - # check that the slave has shutdown - d.addCallback(_delay) - def _check_shutdown(res): - # assert that we shutdown the slave - self.assertEquals(self.did_shutdown, True) - builders = [ self.master.botmaster.builders[bn] - for bn in ('dummy', 'dummy2') ] - from buildbot.process.builder import BUILDING - building_bs = [ builder - for builder in builders - if builder.slaves[0].state == BUILDING ] - # assert that no builds are running right now. - self.failUnlessEqual(len(building_bs), 0) - d.addCallback(_check_shutdown) - - return d |