Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/buildbot/buildbot/test/test_config.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildbot/buildbot/test/test_config.py')
-rw-r--r--buildbot/buildbot/test/test_config.py1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/buildbot/buildbot/test/test_config.py b/buildbot/buildbot/test/test_config.py
new file mode 100644
index 0000000..900dcad
--- /dev/null
+++ b/buildbot/buildbot/test/test_config.py
@@ -0,0 +1,1277 @@
+# -*- test-case-name: buildbot.test.test_config -*-
+
+import os, warnings, exceptions
+
+from twisted.trial import unittest
+from twisted.python import failure
+from twisted.internet import defer
+
+from buildbot.master import BuildMaster
+from buildbot import scheduler
+from twisted.application import service, internet
+from twisted.spread import pb
+from twisted.web.server import Site
+from twisted.web.distrib import ResourcePublisher
+from buildbot.process.builder import Builder
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.changes.pb import PBChangeSource
+from buildbot.changes.mail import SyncmailMaildirSource
+from buildbot.steps.source import CVS, Darcs
+from buildbot.steps.shell import Compile, Test, ShellCommand
+from buildbot.status import base
+from buildbot.steps import dummy, maxq, python, python_twisted, shell, \
+ source, transfer
+words = None
+try:
+ from buildbot.status import words
+except ImportError:
+ pass
+
+emptyCfg = \
+"""
+from buildbot.buildslave import BuildSlave
+BuildmasterConfig = c = {}
+c['slaves'] = []
+c['schedulers'] = []
+c['builders'] = []
+c['slavePortnum'] = 9999
+c['projectName'] = 'dummy project'
+c['projectURL'] = 'http://dummy.example.com'
+c['buildbotURL'] = 'http://dummy.example.com/buildbot'
+"""
+
+buildersCfg = \
+"""
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.buildslave import BuildSlave
+BuildmasterConfig = c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+c['slavePortnum'] = 9999
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+c['builders'] = [{'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir', 'factory':f1}]
+"""
+
+buildersCfg2 = buildersCfg + \
+"""
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule2')
+c['builders'] = [{'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir', 'factory':f1}]
+"""
+
+buildersCfg3 = buildersCfg2 + \
+"""
+c['builders'].append({'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 })
+"""
+
+buildersCfg4 = buildersCfg2 + \
+"""
+c['builders'] = [{ 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'newworkdir', 'factory': f1 },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 }]
+"""
+
+wpCfg1 = buildersCfg + \
+"""
+from buildbot.steps import shell
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+f1.addStep(shell.ShellCommand, command=[shell.WithProperties('echo')])
+c['builders'] = [{'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir1', 'factory': f1}]
+"""
+
+wpCfg2 = buildersCfg + \
+"""
+from buildbot.steps import shell
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+f1.addStep(shell.ShellCommand,
+ command=[shell.WithProperties('echo %s', 'revision')])
+c['builders'] = [{'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir1', 'factory': f1}]
+"""
+
+
+
+ircCfg1 = emptyCfg + \
+"""
+from buildbot.status import words
+c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted'])]
+"""
+
+ircCfg2 = emptyCfg + \
+"""
+from buildbot.status import words
+c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['twisted']),
+ words.IRC('irc.example.com', 'otherbot', ['chan1', 'chan2'])]
+"""
+
+ircCfg3 = emptyCfg + \
+"""
+from buildbot.status import words
+c['status'] = [words.IRC('irc.us.freenode.net', 'buildbot', ['knotted'])]
+"""
+
+webCfg1 = emptyCfg + \
+"""
+from buildbot.status import html
+c['status'] = [html.Waterfall(http_port=9980)]
+"""
+
+webCfg2 = emptyCfg + \
+"""
+from buildbot.status import html
+c['status'] = [html.Waterfall(http_port=9981)]
+"""
+
+webCfg3 = emptyCfg + \
+"""
+from buildbot.status import html
+c['status'] = [html.Waterfall(http_port='tcp:9981:interface=127.0.0.1')]
+"""
+
+webNameCfg1 = emptyCfg + \
+"""
+from buildbot.status import html
+c['status'] = [html.Waterfall(distrib_port='~/.twistd-web-pb')]
+"""
+
+webNameCfg2 = emptyCfg + \
+"""
+from buildbot.status import html
+c['status'] = [html.Waterfall(distrib_port='./bar.socket')]
+"""
+
+debugPasswordCfg = emptyCfg + \
+"""
+c['debugPassword'] = 'sekrit'
+"""
+
+interlockCfgBad = \
+"""
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1 },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+# interlocks have been removed
+c['interlocks'] = [('lock1', ['builder1'], ['builder2', 'builder3']),
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfgBad1 = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock1') # duplicate lock name
+f1 = BuildFactory([s(Dummy, locks=[])])
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfgBad2 = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock, SlaveLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = SlaveLock('lock1') # duplicate lock name
+f1 = BuildFactory([s(Dummy, locks=[])])
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfgBad3 = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock1') # duplicate lock name
+f1 = BuildFactory([s(Dummy, locks=[l2])])
+f2 = BuildFactory([s(Dummy)])
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f2, 'locks': [l1] },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfg1a = \
+"""
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock2')
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1, 'locks': [l1, l2] },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfg1b = \
+"""
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock2')
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1, 'locks': [l1] },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f1 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+# test out step Locks
+lockCfg2a = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock2')
+f1 = BuildFactory([s(Dummy, locks=[l1,l2])])
+f2 = BuildFactory([s(Dummy)])
+
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1 },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f2 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfg2b = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock2')
+f1 = BuildFactory([s(Dummy, locks=[l1])])
+f2 = BuildFactory([s(Dummy)])
+
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1 },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f2 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+lockCfg2c = \
+"""
+from buildbot.steps.dummy import Dummy
+from buildbot.process.factory import BuildFactory, s
+from buildbot.locks import MasterLock
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+l1 = MasterLock('lock1')
+l2 = MasterLock('lock2')
+f1 = BuildFactory([s(Dummy)])
+f2 = BuildFactory([s(Dummy)])
+
+c['builders'] = [
+ { 'name': 'builder1', 'slavename': 'bot1',
+ 'builddir': 'workdir', 'factory': f1 },
+ { 'name': 'builder2', 'slavename': 'bot1',
+ 'builddir': 'workdir2', 'factory': f2 },
+ ]
+c['slavePortnum'] = 9999
+BuildmasterConfig = c
+"""
+
+schedulersCfg = \
+"""
+from buildbot.scheduler import Scheduler, Dependent
+from buildbot.process.factory import BasicBuildFactory
+from buildbot.buildslave import BuildSlave
+c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+f1 = BasicBuildFactory('cvsroot', 'cvsmodule')
+b1 = {'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir', 'factory':f1}
+c['builders'] = [b1]
+c['schedulers'] = [Scheduler('full', None, 60, ['builder1'])]
+c['slavePortnum'] = 9999
+c['projectName'] = 'dummy project'
+c['projectURL'] = 'http://dummy.example.com'
+c['buildbotURL'] = 'http://dummy.example.com/buildbot'
+BuildmasterConfig = c
+"""
+
+class ConfigTest(unittest.TestCase):
+ def setUp(self):
+ # this class generates several deprecation warnings, which the user
+ # doesn't need to see.
+ warnings.simplefilter('ignore', exceptions.DeprecationWarning)
+ self.buildmaster = BuildMaster(".")
+
+ def failUnlessListsEquivalent(self, list1, list2):
+ l1 = list1[:]
+ l1.sort()
+ l2 = list2[:]
+ l2.sort()
+ self.failUnlessEqual(l1, l2)
+
+ def servers(self, s, types):
+ # perform a recursive search of s.services, looking for instances of
+ # twisted.application.internet.TCPServer, then extract their .args
+ # values to find the TCP ports they want to listen on
+ for child in s:
+ if service.IServiceCollection.providedBy(child):
+ for gc in self.servers(child, types):
+ yield gc
+ if isinstance(child, types):
+ yield child
+
+ def TCPports(self, s):
+ return list(self.servers(s, internet.TCPServer))
+ def UNIXports(self, s):
+ return list(self.servers(s, internet.UNIXServer))
+ def TCPclients(self, s):
+ return list(self.servers(s, internet.TCPClient))
+
+ def checkPorts(self, svc, expected):
+ """Verify that the TCPServer and UNIXServer children of the given
+ service have the expected portnum/pathname and factory classes. As a
+ side-effect, return a list of servers in the same order as the
+ 'expected' list. This can be used to verify properties of the
+ factories contained therein."""
+
+ expTCP = [e for e in expected if type(e[0]) == int]
+ expUNIX = [e for e in expected if type(e[0]) == str]
+ haveTCP = [(p.args[0], p.args[1].__class__)
+ for p in self.TCPports(svc)]
+ haveUNIX = [(p.args[0], p.args[1].__class__)
+ for p in self.UNIXports(svc)]
+ self.failUnlessListsEquivalent(expTCP, haveTCP)
+ self.failUnlessListsEquivalent(expUNIX, haveUNIX)
+ ret = []
+ for e in expected:
+ for have in self.TCPports(svc) + self.UNIXports(svc):
+ if have.args[0] == e[0]:
+ ret.append(have)
+ continue
+ assert(len(ret) == len(expected))
+ return ret
+
+ def testEmpty(self):
+ self.failUnlessRaises(KeyError, self.buildmaster.loadConfig, "")
+
+ def testSimple(self):
+ # covers slavePortnum, base checker passwords
+ master = self.buildmaster
+ master.loadChanges()
+
+ master.loadConfig(emptyCfg)
+ # note: this doesn't actually start listening, because the app
+ # hasn't been started running
+ self.failUnlessEqual(master.slavePortnum, "tcp:9999")
+ self.checkPorts(master, [(9999, pb.PBServerFactory)])
+ self.failUnlessEqual(list(master.change_svc), [])
+ self.failUnlessEqual(master.botmaster.builders, {})
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw"})
+ self.failUnlessEqual(master.projectName, "dummy project")
+ self.failUnlessEqual(master.projectURL, "http://dummy.example.com")
+ self.failUnlessEqual(master.buildbotURL,
+ "http://dummy.example.com/buildbot")
+
+ def testSlavePortnum(self):
+ master = self.buildmaster
+ master.loadChanges()
+
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.slavePortnum, "tcp:9999")
+ ports = self.checkPorts(master, [(9999, pb.PBServerFactory)])
+ p = ports[0]
+
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.slavePortnum, "tcp:9999")
+ ports = self.checkPorts(master, [(9999, pb.PBServerFactory)])
+ self.failUnlessIdentical(p, ports[0],
+ "the slave port was changed even " + \
+ "though the configuration was not")
+
+ master.loadConfig(emptyCfg + "c['slavePortnum'] = 9000\n")
+ self.failUnlessEqual(master.slavePortnum, "tcp:9000")
+ ports = self.checkPorts(master, [(9000, pb.PBServerFactory)])
+ self.failIf(p is ports[0],
+ "slave port was unchanged but configuration was changed")
+
+ def testSlaves(self):
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.botmaster.builders, {})
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw"})
+ # 'botsCfg' is testing backwards compatibility, for 0.7.5 config
+ # files that have not yet been updated to 0.7.6 . This compatibility
+ # (and this test) is scheduled for removal in 0.8.0 .
+ botsCfg = (emptyCfg +
+ "c['bots'] = [('bot1', 'pw1'), ('bot2', 'pw2')]\n")
+ master.loadConfig(botsCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw",
+ "bot1": "pw1",
+ "bot2": "pw2"})
+ master.loadConfig(botsCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw",
+ "bot1": "pw1",
+ "bot2": "pw2"})
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw"})
+ slavesCfg = (emptyCfg +
+ "from buildbot.buildslave import BuildSlave\n"
+ "c['slaves'] = [BuildSlave('bot1','pw1'), "
+ "BuildSlave('bot2','pw2')]\n")
+ master.loadConfig(slavesCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw",
+ "bot1": "pw1",
+ "bot2": "pw2"})
+
+
+ def testChangeSource(self):
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(list(master.change_svc), [])
+
+ sourcesCfg = emptyCfg + \
+"""
+from buildbot.changes.pb import PBChangeSource
+c['change_source'] = PBChangeSource()
+"""
+
+ d = master.loadConfig(sourcesCfg)
+ def _check1(res):
+ self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
+ s1 = list(self.buildmaster.change_svc)[0]
+ self.failUnless(isinstance(s1, PBChangeSource))
+ self.failUnlessEqual(s1, list(self.buildmaster.change_svc)[0])
+ self.failUnless(s1.parent)
+
+ # verify that unchanged sources are not interrupted
+ d1 = self.buildmaster.loadConfig(sourcesCfg)
+
+ def _check2(res):
+ self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
+ s2 = list(self.buildmaster.change_svc)[0]
+ self.failUnlessIdentical(s1, s2)
+ self.failUnless(s1.parent)
+ d1.addCallback(_check2)
+ return d1
+ d.addCallback(_check1)
+
+ # make sure we can get rid of the sources too
+ d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
+
+ def _check3(res):
+ self.failUnlessEqual(list(self.buildmaster.change_svc), [])
+ d.addCallback(_check3)
+
+ return d
+
+ def testChangeSources(self):
+ # make sure we can accept a list
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(list(master.change_svc), [])
+
+ sourcesCfg = emptyCfg + \
+"""
+from buildbot.changes.pb import PBChangeSource
+from buildbot.changes.mail import SyncmailMaildirSource
+c['change_source'] = [PBChangeSource(),
+ SyncmailMaildirSource('.'),
+ ]
+"""
+
+ d = master.loadConfig(sourcesCfg)
+ def _check1(res):
+ self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 2)
+ s1,s2 = list(self.buildmaster.change_svc)
+ if isinstance(s2, PBChangeSource):
+ s1,s2 = s2,s1
+ self.failUnless(isinstance(s1, PBChangeSource))
+ self.failUnless(s1.parent)
+ self.failUnless(isinstance(s2, SyncmailMaildirSource))
+ self.failUnless(s2.parent)
+ d.addCallback(_check1)
+ return d
+
+ def testSources(self):
+ # test backwards compatibility. c['sources'] is deprecated.
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(list(master.change_svc), [])
+
+ sourcesCfg = emptyCfg + \
+"""
+from buildbot.changes.pb import PBChangeSource
+c['sources'] = [PBChangeSource()]
+"""
+
+ d = master.loadConfig(sourcesCfg)
+ def _check1(res):
+ self.failUnlessEqual(len(list(self.buildmaster.change_svc)), 1)
+ s1 = list(self.buildmaster.change_svc)[0]
+ self.failUnless(isinstance(s1, PBChangeSource))
+ self.failUnless(s1.parent)
+ d.addCallback(_check1)
+ return d
+
+ def shouldBeFailure(self, res, *expected):
+ self.failUnless(isinstance(res, failure.Failure),
+ "we expected this to fail, not produce %s" % (res,))
+ res.trap(*expected)
+ return None # all is good
+
+ def testSchedulerErrors(self):
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.allSchedulers(), [])
+
+ def _shouldBeFailure(res, hint=None):
+ self.shouldBeFailure(res, AssertionError, ValueError)
+ if hint:
+ self.failUnless(str(res).find(hint) != -1)
+
+ def _loadConfig(res, newcfg):
+ return self.buildmaster.loadConfig(newcfg)
+ d = defer.succeed(None)
+
+ # c['schedulers'] must be a list
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = Scheduler('full', None, 60, ['builder1'])
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure,
+ "c['schedulers'] must be a list of Scheduler instances")
+
+ # c['schedulers'] must be a list of IScheduler objects
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = ['oops', 'problem']
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure,
+ "c['schedulers'] must be a list of Scheduler instances")
+
+ # c['schedulers'] must point at real builders
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = [Scheduler('full', None, 60, ['builder-bogus'])]
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure, "uses unknown builder")
+
+ # builderNames= must be a list
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = [Scheduler('full', None, 60, 'builder1')]
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure,
+ "must be a list of Builder description names")
+
+ # builderNames= must be a list of strings, not dicts
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = [Scheduler('full', None, 60, [b1])]
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure,
+ "must be a list of Builder description names")
+
+ # builderNames= must be a list of strings, not a dict
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = [Scheduler('full', None, 60, b1)]
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure,
+ "must be a list of Builder description names")
+
+ # each Scheduler must have a unique name
+ badcfg = schedulersCfg + \
+"""
+c['schedulers'] = [Scheduler('dup', None, 60, []),
+ Scheduler('dup', None, 60, [])]
+"""
+ d.addCallback(_loadConfig, badcfg)
+ d.addBoth(_shouldBeFailure, "Schedulers must have unique names")
+
+ return d
+
+ def testSchedulers(self):
+ master = self.buildmaster
+ master.loadChanges()
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.allSchedulers(), [])
+
+ d = self.buildmaster.loadConfig(schedulersCfg)
+ d.addCallback(self._testSchedulers_1)
+ return d
+
+ def _testSchedulers_1(self, res):
+ sch = self.buildmaster.allSchedulers()
+ self.failUnlessEqual(len(sch), 1)
+ s = sch[0]
+ self.failUnless(isinstance(s, scheduler.Scheduler))
+ self.failUnlessEqual(s.name, "full")
+ self.failUnlessEqual(s.branch, None)
+ self.failUnlessEqual(s.treeStableTimer, 60)
+ self.failUnlessEqual(s.builderNames, ['builder1'])
+
+ newcfg = schedulersCfg + \
+"""
+s1 = Scheduler('full', None, 60, ['builder1'])
+c['schedulers'] = [s1, Dependent('downstream', s1, ['builder1'])]
+"""
+ d = self.buildmaster.loadConfig(newcfg)
+ d.addCallback(self._testSchedulers_2, newcfg)
+ return d
+ def _testSchedulers_2(self, res, newcfg):
+ sch = self.buildmaster.allSchedulers()
+ self.failUnlessEqual(len(sch), 2)
+ s = sch[0]
+ self.failUnless(isinstance(s, scheduler.Scheduler))
+ s = sch[1]
+ self.failUnless(isinstance(s, scheduler.Dependent))
+ self.failUnlessEqual(s.name, "downstream")
+ self.failUnlessEqual(s.builderNames, ['builder1'])
+
+ # reloading the same config file should leave the schedulers in place
+ d = self.buildmaster.loadConfig(newcfg)
+ d.addCallback(self._testSchedulers_3, sch)
+ return d
+ def _testSchedulers_3(self, res, sch1):
+ sch2 = self.buildmaster.allSchedulers()
+ self.failUnlessEqual(len(sch2), 2)
+ sch1.sort()
+ sch2.sort()
+ self.failUnlessEqual(sch1, sch2)
+ self.failUnlessIdentical(sch1[0], sch2[0])
+ self.failUnlessIdentical(sch1[1], sch2[1])
+ self.failUnlessIdentical(sch1[0].parent, self.buildmaster)
+ self.failUnlessIdentical(sch1[1].parent, self.buildmaster)
+
+
+
+ def testBuilders(self):
+ master = self.buildmaster
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.botmaster.builders, {})
+
+ master.loadConfig(buildersCfg)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
+ self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
+ b = master.botmaster.builders["builder1"]
+ self.failUnless(isinstance(b, Builder))
+ self.failUnlessEqual(b.name, "builder1")
+ self.failUnlessEqual(b.slavenames, ["bot1"])
+ self.failUnlessEqual(b.builddir, "workdir")
+ f1 = b.buildFactory
+ self.failUnless(isinstance(f1, BasicBuildFactory))
+ steps = f1.steps
+ self.failUnlessEqual(len(steps), 3)
+ self.failUnlessEqual(steps[0], (CVS,
+ {'cvsroot': 'cvsroot',
+ 'cvsmodule': 'cvsmodule',
+ 'mode': 'clobber'}))
+ self.failUnlessEqual(steps[1], (Compile,
+ {'command': 'make all'}))
+ self.failUnlessEqual(steps[2], (Test,
+ {'command': 'make check'}))
+
+
+ # make sure a reload of the same data doesn't interrupt the Builder
+ master.loadConfig(buildersCfg)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
+ self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
+ b2 = master.botmaster.builders["builder1"]
+ self.failUnlessIdentical(b, b2)
+ # TODO: test that the BuilderStatus object doesn't change
+ #statusbag2 = master.client_svc.statusbags["builder1"]
+ #self.failUnlessIdentical(statusbag, statusbag2)
+
+ # but changing something should result in a new Builder
+ master.loadConfig(buildersCfg2)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
+ self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
+ b3 = master.botmaster.builders["builder1"]
+ self.failIf(b is b3)
+ # the statusbag remains the same TODO
+ #statusbag3 = master.client_svc.statusbags["builder1"]
+ #self.failUnlessIdentical(statusbag, statusbag3)
+
+ # adding new builder
+ master.loadConfig(buildersCfg3)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1",
+ "builder2"])
+ self.failUnlessListsEquivalent(master.botmaster.builders.keys(),
+ ["builder1", "builder2"])
+ b4 = master.botmaster.builders["builder1"]
+ self.failUnlessIdentical(b3, b4)
+
+ # changing first builder should leave it at the same place in the list
+ master.loadConfig(buildersCfg4)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1",
+ "builder2"])
+ self.failUnlessListsEquivalent(master.botmaster.builders.keys(),
+ ["builder1", "builder2"])
+ b5 = master.botmaster.builders["builder1"]
+ self.failIf(b4 is b5)
+
+ # and removing it should make the Builder go away
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.botmaster.builderNames, [])
+ self.failUnlessEqual(master.botmaster.builders, {})
+ #self.failUnlessEqual(master.client_svc.statusbags, {}) # TODO
+
+ def testWithProperties(self):
+ master = self.buildmaster
+ master.loadConfig(wpCfg1)
+ self.failUnlessEqual(master.botmaster.builderNames, ["builder1"])
+ self.failUnlessEqual(master.botmaster.builders.keys(), ["builder1"])
+ b1 = master.botmaster.builders["builder1"]
+
+ # reloading the same config should leave the builder unchanged
+ master.loadConfig(wpCfg1)
+ b2 = master.botmaster.builders["builder1"]
+ self.failUnlessIdentical(b1, b2)
+
+ # but changing the parameters of the WithProperties should change it
+ master.loadConfig(wpCfg2)
+ b3 = master.botmaster.builders["builder1"]
+ self.failIf(b1 is b3)
+
+ # again, reloading same config should leave the builder unchanged
+ master.loadConfig(wpCfg2)
+ b4 = master.botmaster.builders["builder1"]
+ self.failUnlessIdentical(b3, b4)
+
+ def checkIRC(self, m, expected):
+ ircs = {}
+ for irc in self.servers(m, words.IRC):
+ ircs[irc.host] = (irc.nick, irc.channels)
+ self.failUnlessEqual(ircs, expected)
+
+ def testIRC(self):
+ if not words:
+ raise unittest.SkipTest("Twisted Words package is not installed")
+ master = self.buildmaster
+ master.loadChanges()
+ d = master.loadConfig(emptyCfg)
+ e1 = {}
+ d.addCallback(lambda res: self.checkIRC(master, e1))
+ d.addCallback(lambda res: master.loadConfig(ircCfg1))
+ e2 = {'irc.us.freenode.net': ('buildbot', ['twisted'])}
+ d.addCallback(lambda res: self.checkIRC(master, e2))
+ d.addCallback(lambda res: master.loadConfig(ircCfg2))
+ e3 = {'irc.us.freenode.net': ('buildbot', ['twisted']),
+ 'irc.example.com': ('otherbot', ['chan1', 'chan2'])}
+ d.addCallback(lambda res: self.checkIRC(master, e3))
+ d.addCallback(lambda res: master.loadConfig(ircCfg3))
+ e4 = {'irc.us.freenode.net': ('buildbot', ['knotted'])}
+ d.addCallback(lambda res: self.checkIRC(master, e4))
+ d.addCallback(lambda res: master.loadConfig(ircCfg1))
+ e5 = {'irc.us.freenode.net': ('buildbot', ['twisted'])}
+ d.addCallback(lambda res: self.checkIRC(master, e5))
+ return d
+
+ def testWebPortnum(self):
+ master = self.buildmaster
+ master.loadChanges()
+
+ d = master.loadConfig(webCfg1)
+ def _check1(res):
+ ports = self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory), (9980, Site)])
+ p = ports[1]
+ self.p = p
+ # nothing should be changed
+ d.addCallback(_check1)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg1))
+ def _check2(res):
+ ports = self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory), (9980, Site)])
+ self.failUnlessIdentical(self.p, ports[1],
+ "web port was changed even though "
+ "configuration was not")
+ # WebStatus is no longer a ComparableMixin, so it will be
+ # rebuilt on each reconfig
+ #d.addCallback(_check2)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg2))
+ # changes port to 9981
+ def _check3(p):
+ ports = self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory), (9981, Site)])
+ self.failIf(self.p is ports[1],
+ "configuration was changed but web port was unchanged")
+ d.addCallback(_check3)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(webCfg3))
+ # make 9981 on only localhost
+ def _check4(p):
+ ports = self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory), (9981, Site)])
+ self.failUnlessEqual(ports[1].kwargs['interface'], "127.0.0.1")
+ d.addCallback(_check4)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
+ d.addCallback(lambda res:
+ self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory)]))
+ return d
+
+ def testWebPathname(self):
+ master = self.buildmaster
+ master.loadChanges()
+
+ d = master.loadConfig(webNameCfg1)
+ def _check1(res):
+ self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory),
+ ('~/.twistd-web-pb', pb.PBServerFactory)])
+ unixports = self.UNIXports(self.buildmaster)
+ self.f = f = unixports[0].args[1]
+ self.failUnless(isinstance(f.root, ResourcePublisher))
+ d.addCallback(_check1)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg1))
+ # nothing should be changed
+ def _check2(res):
+ self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory),
+ ('~/.twistd-web-pb', pb.PBServerFactory)])
+ newf = self.UNIXports(self.buildmaster)[0].args[1]
+ self.failUnlessIdentical(self.f, newf,
+ "web factory was changed even though "
+ "configuration was not")
+ # WebStatus is no longer a ComparableMixin, so it will be
+ # rebuilt on each reconfig
+ #d.addCallback(_check2)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(webNameCfg2))
+ def _check3(res):
+ self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory),
+ ('./bar.socket', pb.PBServerFactory)])
+ newf = self.UNIXports(self.buildmaster)[0].args[1],
+ self.failIf(self.f is newf,
+ "web factory was unchanged but "
+ "configuration was changed")
+ d.addCallback(_check3)
+
+ d.addCallback(lambda res: self.buildmaster.loadConfig(emptyCfg))
+ d.addCallback(lambda res:
+ self.checkPorts(self.buildmaster,
+ [(9999, pb.PBServerFactory)]))
+ return d
+
+ def testDebugPassword(self):
+ master = self.buildmaster
+
+ master.loadConfig(debugPasswordCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw",
+ "debug": "sekrit"})
+
+ master.loadConfig(debugPasswordCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw",
+ "debug": "sekrit"})
+
+ master.loadConfig(emptyCfg)
+ self.failUnlessEqual(master.checker.users,
+ {"change": "changepw"})
+
+ def testLocks(self):
+ master = self.buildmaster
+ botmaster = master.botmaster
+
+ # make sure that c['interlocks'] is rejected properly
+ self.failUnlessRaises(KeyError, master.loadConfig, interlockCfgBad)
+ # and that duplicate-named Locks are caught
+ self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad1)
+ self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad2)
+ self.failUnlessRaises(ValueError, master.loadConfig, lockCfgBad3)
+
+ # create a Builder that uses Locks
+ master.loadConfig(lockCfg1a)
+ b1 = master.botmaster.builders["builder1"]
+ self.failUnlessEqual(len(b1.locks), 2)
+
+ # reloading the same config should not change the Builder
+ master.loadConfig(lockCfg1a)
+ self.failUnlessIdentical(b1, master.botmaster.builders["builder1"])
+ # but changing the set of locks used should change it
+ master.loadConfig(lockCfg1b)
+ self.failIfIdentical(b1, master.botmaster.builders["builder1"])
+ b1 = master.botmaster.builders["builder1"]
+ self.failUnlessEqual(len(b1.locks), 1)
+
+ # similar test with step-scoped locks
+ master.loadConfig(lockCfg2a)
+ b1 = master.botmaster.builders["builder1"]
+ # reloading the same config should not change the Builder
+ master.loadConfig(lockCfg2a)
+ self.failUnlessIdentical(b1, master.botmaster.builders["builder1"])
+ # but changing the set of locks used should change it
+ master.loadConfig(lockCfg2b)
+ self.failIfIdentical(b1, master.botmaster.builders["builder1"])
+ b1 = master.botmaster.builders["builder1"]
+ # remove the locks entirely
+ master.loadConfig(lockCfg2c)
+ self.failIfIdentical(b1, master.botmaster.builders["builder1"])
+
+class ConfigElements(unittest.TestCase):
+ # verify that ComparableMixin is working
+ def testSchedulers(self):
+ s1 = scheduler.Scheduler(name='quick', branch=None,
+ treeStableTimer=30,
+ builderNames=['quick'])
+ s2 = scheduler.Scheduler(name="all", branch=None,
+ treeStableTimer=5*60,
+ builderNames=["a", "b"])
+ s3 = scheduler.Try_Userpass("try", ["a","b"], port=9989,
+ userpass=[("foo","bar")])
+ s1a = scheduler.Scheduler(name='quick', branch=None,
+ treeStableTimer=30,
+ builderNames=['quick'])
+ s2a = scheduler.Scheduler(name="all", branch=None,
+ treeStableTimer=5*60,
+ builderNames=["a", "b"])
+ s3a = scheduler.Try_Userpass("try", ["a","b"], port=9989,
+ userpass=[("foo","bar")])
+ self.failUnless(s1 == s1)
+ self.failUnless(s1 == s1a)
+ self.failUnless(s1a in [s1, s2, s3])
+ self.failUnless(s2a in [s1, s2, s3])
+ self.failUnless(s3a in [s1, s2, s3])
+
+
+
+class ConfigFileTest(unittest.TestCase):
+
+ def testFindConfigFile(self):
+ os.mkdir("test_cf")
+ open(os.path.join("test_cf", "master.cfg"), "w").write(emptyCfg)
+ slaveportCfg = emptyCfg + "c['slavePortnum'] = 9000\n"
+ open(os.path.join("test_cf", "alternate.cfg"), "w").write(slaveportCfg)
+
+ m = BuildMaster("test_cf")
+ m.loadTheConfigFile()
+ self.failUnlessEqual(m.slavePortnum, "tcp:9999")
+
+ m = BuildMaster("test_cf", "alternate.cfg")
+ m.loadTheConfigFile()
+ self.failUnlessEqual(m.slavePortnum, "tcp:9000")
+
+
+class MyTarget(base.StatusReceiverMultiService):
+ def __init__(self, name):
+ self.name = name
+ base.StatusReceiverMultiService.__init__(self)
+ def startService(self):
+ # make a note in a list stashed in the BuildMaster
+ self.parent.targetevents.append(("start", self.name))
+ return base.StatusReceiverMultiService.startService(self)
+ def stopService(self):
+ self.parent.targetevents.append(("stop", self.name))
+ return base.StatusReceiverMultiService.stopService(self)
+
+class MySlowTarget(MyTarget):
+ def stopService(self):
+ from twisted.internet import reactor
+ d = base.StatusReceiverMultiService.stopService(self)
+ def stall(res):
+ d2 = defer.Deferred()
+ reactor.callLater(0.1, d2.callback, res)
+ return d2
+ d.addCallback(stall)
+ m = self.parent
+ def finishedStalling(res):
+ m.targetevents.append(("stop", self.name))
+ return res
+ d.addCallback(finishedStalling)
+ return d
+
+# we can't actually startService a buildmaster with a config that uses a
+# fixed slavePortnum like 9999, so instead this makes it possible to pass '0'
+# for the first time, and then substitute back in the allocated port number
+# on subsequent passes.
+startableEmptyCfg = emptyCfg + \
+"""
+c['slavePortnum'] = %d
+"""
+
+targetCfg1 = startableEmptyCfg + \
+"""
+from buildbot.test.test_config import MyTarget
+c['status'] = [MyTarget('a')]
+"""
+
+targetCfg2 = startableEmptyCfg + \
+"""
+from buildbot.test.test_config import MySlowTarget
+c['status'] = [MySlowTarget('b')]
+"""
+
+class StartService(unittest.TestCase):
+ def tearDown(self):
+ return self.master.stopService()
+
+ def testStartService(self):
+ os.mkdir("test_ss")
+ self.master = m = BuildMaster("test_ss")
+ # inhibit the usual read-config-on-startup behavior
+ m.readConfig = True
+ m.startService()
+ d = m.loadConfig(startableEmptyCfg % 0)
+ d.addCallback(self._testStartService_0)
+ return d
+
+ def _testStartService_0(self, res):
+ m = self.master
+ m.targetevents = []
+ # figure out what port got allocated
+ self.portnum = m.slavePort._port.getHost().port
+ d = m.loadConfig(targetCfg1 % self.portnum)
+ d.addCallback(self._testStartService_1)
+ return d
+
+ def _testStartService_1(self, res):
+ self.failUnlessEqual(len(self.master.statusTargets), 1)
+ self.failUnless(isinstance(self.master.statusTargets[0], MyTarget))
+ self.failUnlessEqual(self.master.targetevents,
+ [('start', 'a')])
+ self.master.targetevents = []
+ # reloading the same config should not start or stop the target
+ d = self.master.loadConfig(targetCfg1 % self.portnum)
+ d.addCallback(self._testStartService_2)
+ return d
+
+ def _testStartService_2(self, res):
+ self.failUnlessEqual(self.master.targetevents, [])
+ # but loading a new config file should stop the old one, then
+ # start the new one
+ d = self.master.loadConfig(targetCfg2 % self.portnum)
+ d.addCallback(self._testStartService_3)
+ return d
+
+ def _testStartService_3(self, res):
+ self.failUnlessEqual(self.master.targetevents,
+ [('stop', 'a'), ('start', 'b')])
+ self.master.targetevents = []
+ # and going back to the old one should do the same, in the same
+ # order, even though the current MySlowTarget takes a moment to shut
+ # down
+ d = self.master.loadConfig(targetCfg1 % self.portnum)
+ d.addCallback(self._testStartService_4)
+ return d
+
+ def _testStartService_4(self, res):
+ self.failUnlessEqual(self.master.targetevents,
+ [('stop', 'b'), ('start', 'a')])
+
+cfg1 = \
+"""
+from buildbot.process.factory import BuildFactory, s
+from buildbot.steps.shell import ShellCommand
+from buildbot.steps.source import Darcs
+from buildbot.buildslave import BuildSlave
+BuildmasterConfig = c = {}
+c['slaves'] = [BuildSlave('bot1', 'pw1')]
+c['schedulers'] = []
+c['slavePortnum'] = 9999
+f1 = BuildFactory([ShellCommand(command='echo yes'),
+ s(ShellCommand, command='old-style'),
+ ])
+f1.addStep(Darcs(repourl='http://buildbot.net/repos/trunk'))
+f1.addStep(ShellCommand, command='echo old-style')
+c['builders'] = [{'name':'builder1', 'slavename':'bot1',
+ 'builddir':'workdir', 'factory':f1}]
+"""
+
+class Factories(unittest.TestCase):
+
+ def failUnlessExpectedShell(self, factory, defaults=True, **kwargs):
+ shell_args = {}
+ if defaults:
+ shell_args.update({'descriptionDone': None,
+ 'description': None,
+ 'workdir': None,
+ 'logfiles': {},
+ 'usePTY': "slave-config",
+ })
+ shell_args.update(kwargs)
+ self.failUnlessIdentical(factory[0], ShellCommand)
+ if factory[1] != shell_args:
+ print
+ print "factory had:"
+ for k in sorted(factory[1].keys()):
+ print k
+ print "but we were expecting:"
+ for k in sorted(shell_args.keys()):
+ print k
+ self.failUnlessEqual(factory[1], shell_args)
+
+ def failUnlessExpectedDarcs(self, factory, **kwargs):
+ darcs_args = {'workdir': None,
+ 'alwaysUseLatest': False,
+ 'mode': 'update',
+ 'timeout': 1200,
+ 'retry': None,
+ 'baseURL': None,
+ 'defaultBranch': None,
+ 'logfiles': {},
+ }
+ darcs_args.update(kwargs)
+ self.failUnlessIdentical(factory[0], Darcs)
+ if factory[1] != darcs_args:
+ print
+ print "factory had:"
+ for k in sorted(factory[1].keys()):
+ print k
+ print "but we were expecting:"
+ for k in sorted(darcs_args.keys()):
+ print k
+ self.failUnlessEqual(factory[1], darcs_args)
+
+ def testSteps(self):
+ m = BuildMaster(".")
+ m.loadConfig(cfg1)
+ b = m.botmaster.builders["builder1"]
+ steps = b.buildFactory.steps
+ self.failUnlessEqual(len(steps), 4)
+
+ self.failUnlessExpectedShell(steps[0], command="echo yes")
+ self.failUnlessExpectedShell(steps[1], defaults=False,
+ command="old-style")
+ self.failUnlessExpectedDarcs(steps[2],
+ repourl="http://buildbot.net/repos/trunk")
+ self.failUnlessExpectedShell(steps[3], defaults=False,
+ command="echo old-style")
+
+ def _loop(self, orig):
+ step_class, kwargs = orig.getStepFactory()
+ newstep = step_class(**kwargs)
+ return newstep
+
+ def testAllSteps(self):
+ # make sure that steps can be created from the factories that they
+ # return
+ for s in ( dummy.Dummy(), dummy.FailingDummy(), dummy.RemoteDummy(),
+ maxq.MaxQ("testdir"),
+ python.BuildEPYDoc(), python.PyFlakes(),
+ python_twisted.HLint(),
+ python_twisted.Trial(testpath=None, tests="tests"),
+ python_twisted.ProcessDocs(), python_twisted.BuildDebs(),
+ python_twisted.RemovePYCs(),
+ shell.ShellCommand(), shell.TreeSize(),
+ shell.Configure(), shell.Compile(), shell.Test(),
+ source.CVS("cvsroot", "module"),
+ source.SVN("svnurl"), source.Darcs("repourl"),
+ source.Git("repourl"),
+ source.Arch("url", "version"),
+ source.Bazaar("url", "version", "archive"),
+ source.Bzr("repourl"),
+ source.Mercurial("repourl"),
+ source.P4("p4base"),
+ source.P4Sync(1234, "p4user", "passwd", "client",
+ mode="copy"),
+ source.Monotone("server", "branch"),
+ transfer.FileUpload("src", "dest"),
+ transfer.FileDownload("src", "dest"),
+ ):
+ try:
+ self._loop(s)
+ except:
+ print "error checking %s" % s
+ raise
+