Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/buildbot/buildbot/test/runutils.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildbot/buildbot/test/runutils.py')
-rw-r--r--buildbot/buildbot/test/runutils.py516
1 files changed, 0 insertions, 516 deletions
diff --git a/buildbot/buildbot/test/runutils.py b/buildbot/buildbot/test/runutils.py
deleted file mode 100644
index 2be85d6..0000000
--- a/buildbot/buildbot/test/runutils.py
+++ /dev/null
@@ -1,516 +0,0 @@
-
-import signal
-import shutil, os, errno
-from cStringIO import StringIO
-from twisted.internet import defer, reactor, protocol
-from twisted.python import log, util
-
-from buildbot import master, interfaces
-from buildbot.slave import bot
-from buildbot.buildslave import BuildSlave
-from buildbot.process.builder import Builder
-from buildbot.process.base import BuildRequest, Build
-from buildbot.process.buildstep import BuildStep
-from buildbot.sourcestamp import SourceStamp
-from buildbot.status import builder
-from buildbot.process.properties import Properties
-
-
-
-class _PutEverythingGetter(protocol.ProcessProtocol):
- def __init__(self, deferred, stdin):
- self.deferred = deferred
- self.outBuf = StringIO()
- self.errBuf = StringIO()
- self.outReceived = self.outBuf.write
- self.errReceived = self.errBuf.write
- self.stdin = stdin
-
- def connectionMade(self):
- if self.stdin is not None:
- self.transport.write(self.stdin)
- self.transport.closeStdin()
-
- def processEnded(self, reason):
- out = self.outBuf.getvalue()
- err = self.errBuf.getvalue()
- e = reason.value
- code = e.exitCode
- if e.signal:
- self.deferred.errback((out, err, e.signal))
- else:
- self.deferred.callback((out, err, code))
-
-def myGetProcessOutputAndValue(executable, args=(), env={}, path='.',
- _reactor_ignored=None, stdin=None):
- """Like twisted.internet.utils.getProcessOutputAndValue but takes
- stdin, too."""
- d = defer.Deferred()
- p = _PutEverythingGetter(d, stdin)
- reactor.spawnProcess(p, executable, (executable,)+tuple(args), env, path)
- return d
-
-
-class MyBot(bot.Bot):
- def remote_getSlaveInfo(self):
- return self.parent.info
-
-class MyBuildSlave(bot.BuildSlave):
- botClass = MyBot
-
-def rmtree(d):
- try:
- shutil.rmtree(d, ignore_errors=1)
- except OSError, e:
- # stupid 2.2 appears to ignore ignore_errors
- if e.errno != errno.ENOENT:
- raise
-
-class RunMixin:
- master = None
-
- def rmtree(self, d):
- rmtree(d)
-
- def setUp(self):
- self.slaves = {}
- self.rmtree("basedir")
- os.mkdir("basedir")
- self.master = master.BuildMaster("basedir")
- self.status = self.master.getStatus()
- self.control = interfaces.IControl(self.master)
-
- def connectOneSlave(self, slavename, opts={}):
- port = self.master.slavePort._port.getHost().port
- self.rmtree("slavebase-%s" % slavename)
- os.mkdir("slavebase-%s" % slavename)
- slave = MyBuildSlave("localhost", port, slavename, "sekrit",
- "slavebase-%s" % slavename,
- keepalive=0, usePTY=False, debugOpts=opts)
- slave.info = {"admin": "one"}
- self.slaves[slavename] = slave
- slave.startService()
-
- def connectSlave(self, builders=["dummy"], slavename="bot1",
- opts={}):
- # connect buildslave 'slavename' and wait for it to connect to all of
- # the given builders
- dl = []
- # initiate call for all of them, before waiting on result,
- # otherwise we might miss some
- for b in builders:
- dl.append(self.master.botmaster.waitUntilBuilderAttached(b))
- d = defer.DeferredList(dl)
- self.connectOneSlave(slavename, opts)
- return d
-
- def connectSlaves(self, slavenames, builders):
- dl = []
- # initiate call for all of them, before waiting on result,
- # otherwise we might miss some
- for b in builders:
- dl.append(self.master.botmaster.waitUntilBuilderAttached(b))
- d = defer.DeferredList(dl)
- for name in slavenames:
- self.connectOneSlave(name)
- return d
-
- def connectSlave2(self):
- # this takes over for bot1, so it has to share the slavename
- port = self.master.slavePort._port.getHost().port
- self.rmtree("slavebase-bot2")
- os.mkdir("slavebase-bot2")
- # this uses bot1, really
- slave = MyBuildSlave("localhost", port, "bot1", "sekrit",
- "slavebase-bot2", keepalive=0, usePTY=False)
- slave.info = {"admin": "two"}
- self.slaves['bot2'] = slave
- slave.startService()
-
- def connectSlaveFastTimeout(self):
- # this slave has a very fast keepalive timeout
- port = self.master.slavePort._port.getHost().port
- self.rmtree("slavebase-bot1")
- os.mkdir("slavebase-bot1")
- slave = MyBuildSlave("localhost", port, "bot1", "sekrit",
- "slavebase-bot1", keepalive=2, usePTY=False,
- keepaliveTimeout=1)
- slave.info = {"admin": "one"}
- self.slaves['bot1'] = slave
- slave.startService()
- d = self.master.botmaster.waitUntilBuilderAttached("dummy")
- return d
-
- # things to start builds
- def requestBuild(self, builder):
- # returns a Deferred that fires with an IBuildStatus object when the
- # build is finished
- req = BuildRequest("forced build", SourceStamp(), 'test_builder')
- self.control.getBuilder(builder).requestBuild(req)
- return req.waitUntilFinished()
-
- def failUnlessBuildSucceeded(self, bs):
- if bs.getResults() != builder.SUCCESS:
- log.msg("failUnlessBuildSucceeded noticed that the build failed")
- self.logBuildResults(bs)
- self.failUnlessEqual(bs.getResults(), builder.SUCCESS)
- return bs # useful for chaining
-
- def logBuildResults(self, bs):
- # emit the build status and the contents of all logs to test.log
- log.msg("logBuildResults starting")
- log.msg(" bs.getResults() == %s" % builder.Results[bs.getResults()])
- log.msg(" bs.isFinished() == %s" % bs.isFinished())
- for s in bs.getSteps():
- for l in s.getLogs():
- log.msg("--- START step %s / log %s ---" % (s.getName(),
- l.getName()))
- if not l.getName().endswith(".html"):
- log.msg(l.getTextWithHeaders())
- log.msg("--- STOP ---")
- log.msg("logBuildResults finished")
-
- def tearDown(self):
- log.msg("doing tearDown")
- d = self.shutdownAllSlaves()
- d.addCallback(self._tearDown_1)
- d.addCallback(self._tearDown_2)
- return d
- def _tearDown_1(self, res):
- if self.master:
- return defer.maybeDeferred(self.master.stopService)
- def _tearDown_2(self, res):
- self.master = None
- log.msg("tearDown done")
-
-
- # various forms of slave death
-
- def shutdownAllSlaves(self):
- # the slave has disconnected normally: they SIGINT'ed it, or it shut
- # down willingly. This will kill child processes and give them a
- # chance to finish up. We return a Deferred that will fire when
- # everything is finished shutting down.
-
- log.msg("doing shutdownAllSlaves")
- dl = []
- for slave in self.slaves.values():
- dl.append(slave.waitUntilDisconnected())
- dl.append(defer.maybeDeferred(slave.stopService))
- d = defer.DeferredList(dl)
- d.addCallback(self._shutdownAllSlavesDone)
- return d
- def _shutdownAllSlavesDone(self, res):
- for name in self.slaves.keys():
- del self.slaves[name]
- return self.master.botmaster.waitUntilBuilderFullyDetached("dummy")
-
- def shutdownSlave(self, slavename, buildername):
- # this slave has disconnected normally: they SIGINT'ed it, or it shut
- # down willingly. This will kill child processes and give them a
- # chance to finish up. We return a Deferred that will fire when
- # everything is finished shutting down, and the given Builder knows
- # that the slave has gone away.
-
- s = self.slaves[slavename]
- dl = [self.master.botmaster.waitUntilBuilderDetached(buildername),
- s.waitUntilDisconnected()]
- d = defer.DeferredList(dl)
- d.addCallback(self._shutdownSlave_done, slavename)
- s.stopService()
- return d
- def _shutdownSlave_done(self, res, slavename):
- del self.slaves[slavename]
-
- def killSlave(self):
- # the slave has died, its host sent a FIN. The .notifyOnDisconnect
- # callbacks will terminate the current step, so the build should be
- # flunked (no further steps should be started).
- self.slaves['bot1'].bf.continueTrying = 0
- bot = self.slaves['bot1'].getServiceNamed("bot")
- broker = bot.builders["dummy"].remote.broker
- broker.transport.loseConnection()
- del self.slaves['bot1']
-
- def disappearSlave(self, slavename="bot1", buildername="dummy",
- allowReconnect=False):
- # the slave's host has vanished off the net, leaving the connection
- # dangling. This will be detected quickly by app-level keepalives or
- # a ping, or slowly by TCP timeouts.
-
- # simulate this by replacing the slave Broker's .dataReceived method
- # with one that just throws away all data.
- def discard(data):
- pass
- bot = self.slaves[slavename].getServiceNamed("bot")
- broker = bot.builders[buildername].remote.broker
- broker.dataReceived = discard # seal its ears
- broker.transport.write = discard # and take away its voice
- if not allowReconnect:
- # also discourage it from reconnecting once the connection goes away
- assert self.slaves[slavename].bf.continueTrying
- self.slaves[slavename].bf.continueTrying = False
-
- def ghostSlave(self):
- # the slave thinks it has lost the connection, and initiated a
- # reconnect. The master doesn't yet realize it has lost the previous
- # connection, and sees two connections at once.
- raise NotImplementedError
-
-
-def setupBuildStepStatus(basedir):
- """Return a BuildStep with a suitable BuildStepStatus object, ready to
- use."""
- os.mkdir(basedir)
- botmaster = None
- s0 = builder.Status(botmaster, basedir)
- s1 = s0.builderAdded("buildername", "buildername")
- s2 = builder.BuildStatus(s1, 1)
- s3 = builder.BuildStepStatus(s2)
- s3.setName("foostep")
- s3.started = True
- s3.stepStarted()
- return s3
-
-def fake_slaveVersion(command, oldversion=None):
- from buildbot.slave.registry import commandRegistry
- return commandRegistry[command]
-
-class FakeBuildMaster:
- properties = Properties(masterprop="master")
-
-class FakeBotMaster:
- parent = FakeBuildMaster()
-
-def makeBuildStep(basedir, step_class=BuildStep, **kwargs):
- bss = setupBuildStepStatus(basedir)
-
- ss = SourceStamp()
- setup = {'name': "builder1", "slavename": "bot1",
- 'builddir': "builddir", 'factory': None}
- b0 = Builder(setup, bss.getBuild().getBuilder())
- b0.botmaster = FakeBotMaster()
- br = BuildRequest("reason", ss, 'test_builder')
- b = Build([br])
- b.setBuilder(b0)
- s = step_class(**kwargs)
- s.setBuild(b)
- s.setStepStatus(bss)
- b.build_status = bss.getBuild()
- b.setupProperties()
- s.slaveVersion = fake_slaveVersion
- return s
-
-
-def findDir():
- # the same directory that holds this script
- return util.sibpath(__file__, ".")
-
-class SignalMixin:
- sigchldHandler = None
-
- def setUpClass(self):
- # make sure SIGCHLD handler is installed, as it should be on
- # reactor.run(). problem is reactor may not have been run when this
- # test runs.
- if hasattr(reactor, "_handleSigchld") and hasattr(signal, "SIGCHLD"):
- self.sigchldHandler = signal.signal(signal.SIGCHLD,
- reactor._handleSigchld)
-
- def tearDownClass(self):
- if self.sigchldHandler:
- signal.signal(signal.SIGCHLD, self.sigchldHandler)
-
-# these classes are used to test SlaveCommands in isolation
-
-class FakeSlaveBuilder:
- debug = False
- def __init__(self, usePTY, basedir):
- self.updates = []
- self.basedir = basedir
- self.usePTY = usePTY
-
- def sendUpdate(self, data):
- if self.debug:
- print "FakeSlaveBuilder.sendUpdate", data
- self.updates.append(data)
-
-
-class SlaveCommandTestBase(SignalMixin):
- usePTY = False
-
- def setUpBuilder(self, basedir):
- if not os.path.exists(basedir):
- os.mkdir(basedir)
- self.builder = FakeSlaveBuilder(self.usePTY, basedir)
-
- def startCommand(self, cmdclass, args):
- stepId = 0
- self.cmd = c = cmdclass(self.builder, stepId, args)
- c.running = True
- d = c.doStart()
- return d
-
- def collectUpdates(self, res=None):
- logs = {}
- for u in self.builder.updates:
- for k in u.keys():
- if k == "log":
- logname,data = u[k]
- oldlog = logs.get(("log",logname), "")
- logs[("log",logname)] = oldlog + data
- elif k == "rc":
- pass
- else:
- logs[k] = logs.get(k, "") + u[k]
- return logs
-
- def findRC(self):
- for u in self.builder.updates:
- if "rc" in u:
- return u["rc"]
- return None
-
- def printStderr(self):
- for u in self.builder.updates:
- if "stderr" in u:
- print u["stderr"]
-
-# ----------------------------------------
-
-class LocalWrapper:
- # r = pb.Referenceable()
- # w = LocalWrapper(r)
- # now you can do things like w.callRemote()
- def __init__(self, target):
- self.target = target
-
- def callRemote(self, name, *args, **kwargs):
- # callRemote is not allowed to fire its Deferred in the same turn
- d = defer.Deferred()
- d.addCallback(self._callRemote, *args, **kwargs)
- reactor.callLater(0, d.callback, name)
- return d
-
- def _callRemote(self, name, *args, **kwargs):
- method = getattr(self.target, "remote_"+name)
- return method(*args, **kwargs)
-
- def notifyOnDisconnect(self, observer):
- pass
- def dontNotifyOnDisconnect(self, observer):
- pass
-
-
-class LocalSlaveBuilder(bot.SlaveBuilder):
- """I am object that behaves like a pb.RemoteReference, but in fact I
- invoke methods locally."""
- _arg_filter = None
-
- def setArgFilter(self, filter):
- self._arg_filter = filter
-
- def remote_startCommand(self, stepref, stepId, command, args):
- if self._arg_filter:
- args = self._arg_filter(args)
- # stepref should be a RemoteReference to the RemoteCommand
- return bot.SlaveBuilder.remote_startCommand(self,
- LocalWrapper(stepref),
- stepId, command, args)
-
-class StepTester:
- """Utility class to exercise BuildSteps and RemoteCommands, without
- really using a Build or a Bot. No networks are used.
-
- Use this as follows::
-
- class MyTest(StepTester, unittest.TestCase):
- def testOne(self):
- self.slavebase = 'testOne.slave'
- self.masterbase = 'testOne.master'
- sb = self.makeSlaveBuilder()
- step = self.makeStep(stepclass, **kwargs)
- d = self.runStep(step)
- d.addCallback(_checkResults)
- return d
- """
-
- #slavebase = "slavebase"
- slavebuilderbase = "slavebuilderbase"
- #masterbase = "masterbase"
-
- def makeSlaveBuilder(self):
- os.mkdir(self.slavebase)
- os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase))
- b = bot.Bot(self.slavebase, False)
- b.startService()
- sb = LocalSlaveBuilder("slavebuildername", False)
- sb.setArgFilter(self.filterArgs)
- sb.usePTY = False
- sb.setServiceParent(b)
- sb.setBuilddir(self.slavebuilderbase)
- self.remote = LocalWrapper(sb)
- return sb
-
- workdir = "build"
- def makeStep(self, factory, **kwargs):
- step = makeBuildStep(self.masterbase, factory, **kwargs)
- step.setBuildSlave(BuildSlave("name", "password"))
- step.setDefaultWorkdir(self.workdir)
- return step
-
- def runStep(self, step):
- d = defer.maybeDeferred(step.startStep, self.remote)
- return d
-
- def wrap(self, target):
- return LocalWrapper(target)
-
- def filterArgs(self, args):
- # this can be overridden
- return args
-
-# ----------------------------------------
-
-_flags = {}
-
-def setTestFlag(flagname, value):
- _flags[flagname] = value
-
-class SetTestFlagStep(BuildStep):
- """
- A special BuildStep to set a named flag; this can be used with the
- TestFlagMixin to monitor what has and has not run in a particular
- configuration.
- """
- def __init__(self, flagname='flag', value=1, **kwargs):
- BuildStep.__init__(self, **kwargs)
- self.addFactoryArguments(flagname=flagname, value=value)
-
- self.flagname = flagname
- self.value = value
-
- def start(self):
- properties = self.build.getProperties()
- _flags[self.flagname] = properties.render(self.value)
- self.finished(builder.SUCCESS)
-
-class TestFlagMixin:
- def clearFlags(self):
- """
- Set up for a test by clearing all flags; call this from your test
- function.
- """
- _flags.clear()
-
- def failIfFlagSet(self, flagname, msg=None):
- if not msg: msg = "flag '%s' is set" % flagname
- self.failIf(_flags.has_key(flagname), msg=msg)
-
- def failIfFlagNotSet(self, flagname, msg=None):
- if not msg: msg = "flag '%s' is not set" % flagname
- self.failUnless(_flags.has_key(flagname), msg=msg)
-
- def getFlag(self, flagname):
- self.failIfFlagNotSet(flagname, "flag '%s' not set" % flagname)
- return _flags.get(flagname)