| Index: third_party/buildbot_7_12/buildbot/test/runutils.py
|
| diff --git a/third_party/buildbot_7_12/buildbot/test/runutils.py b/third_party/buildbot_7_12/buildbot/test/runutils.py
|
| deleted file mode 100644
|
| index 8af50471e8b821551e7164c1d2ea0bd297c59332..0000000000000000000000000000000000000000
|
| --- a/third_party/buildbot_7_12/buildbot/test/runutils.py
|
| +++ /dev/null
|
| @@ -1,511 +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 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():
|
| - slave.stopService()
|
| - dl.append(slave.waitUntilDisconnected())
|
| - 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, slavename="bot1", buildername="dummy"):
|
| - # 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[slavename].bf.continueTrying = 0
|
| - bot = self.slaves[slavename].getServiceNamed("bot")
|
| - broker = bot.builders[buildername].remote.broker
|
| - broker.transport.loseConnection()
|
| - del self.slaves[slavename]
|
| -
|
| - 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", 'slavebuilddir': "slavebuilddir", '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 setUpSignalHandler(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 tearDownSignalHandler(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 setUp(self):
|
| - self.setUpSignalHandler()
|
| -
|
| - def tearDown(self):
|
| - self.tearDownSignalHandler()
|
| -
|
| - 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)
|
|
|