diff options
Diffstat (limited to 'buildbot/buildbot/test/test_properties.py')
-rw-r--r-- | buildbot/buildbot/test/test_properties.py | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/buildbot/buildbot/test/test_properties.py b/buildbot/buildbot/test/test_properties.py new file mode 100644 index 0000000..a8973dd --- /dev/null +++ b/buildbot/buildbot/test/test_properties.py @@ -0,0 +1,274 @@ +# -*- test-case-name: buildbot.test.test_properties -*- + +import os + +from twisted.trial import unittest + +from buildbot.sourcestamp import SourceStamp +from buildbot.process import base +from buildbot.process.properties import WithProperties, Properties +from buildbot.status import builder +from buildbot.slave.commands import rmdirRecursive +from buildbot.test.runutils import RunMixin + + +class FakeBuild: + pass +class FakeBuildMaster: + properties = Properties(masterprop="master") +class FakeBotMaster: + parent = FakeBuildMaster() +class FakeBuilder: + statusbag = None + name = "fakebuilder" + botmaster = FakeBotMaster() +class FakeSlave: + slavename = "bot12" + properties = Properties(slavename="bot12") +class FakeSlaveBuilder: + slave = FakeSlave() + def getSlaveCommandVersion(self, command, oldversion=None): + return "1.10" +class FakeScheduler: + name = "fakescheduler" + +class TestProperties(unittest.TestCase): + def setUp(self): + self.props = Properties() + + def testDictBehavior(self): + self.props.setProperty("do-tests", 1, "scheduler") + self.props.setProperty("do-install", 2, "scheduler") + + self.assert_(self.props.has_key('do-tests')) + self.failUnlessEqual(self.props['do-tests'], 1) + self.failUnlessEqual(self.props['do-install'], 2) + self.assertRaises(KeyError, lambda : self.props['do-nothing']) + self.failUnlessEqual(self.props.getProperty('do-install'), 2) + + def testUpdate(self): + self.props.setProperty("x", 24, "old") + newprops = { 'a' : 1, 'b' : 2 } + self.props.update(newprops, "new") + + self.failUnlessEqual(self.props.getProperty('x'), 24) + self.failUnlessEqual(self.props.getPropertySource('x'), 'old') + self.failUnlessEqual(self.props.getProperty('a'), 1) + self.failUnlessEqual(self.props.getPropertySource('a'), 'new') + + def testUpdateFromProperties(self): + self.props.setProperty("x", 24, "old") + newprops = Properties() + newprops.setProperty('a', 1, "new") + newprops.setProperty('b', 2, "new") + self.props.updateFromProperties(newprops) + + self.failUnlessEqual(self.props.getProperty('x'), 24) + self.failUnlessEqual(self.props.getPropertySource('x'), 'old') + self.failUnlessEqual(self.props.getProperty('a'), 1) + self.failUnlessEqual(self.props.getPropertySource('a'), 'new') + + # render() is pretty well tested by TestWithProperties + +class TestWithProperties(unittest.TestCase): + def setUp(self): + self.props = Properties() + + def testBasic(self): + # test basic substitution with WithProperties + self.props.setProperty("revision", "47", "test") + command = WithProperties("build-%s.tar.gz", "revision") + self.failUnlessEqual(self.props.render(command), + "build-47.tar.gz") + + def testDict(self): + # test dict-style substitution with WithProperties + self.props.setProperty("other", "foo", "test") + command = WithProperties("build-%(other)s.tar.gz") + self.failUnlessEqual(self.props.render(command), + "build-foo.tar.gz") + + def testDictColonMinus(self): + # test dict-style substitution with WithProperties + self.props.setProperty("prop1", "foo", "test") + command = WithProperties("build-%(prop1:-empty)s-%(prop2:-empty)s.tar.gz") + self.failUnlessEqual(self.props.render(command), + "build-foo-empty.tar.gz") + + def testDictColonPlus(self): + # test dict-style substitution with WithProperties + self.props.setProperty("prop1", "foo", "test") + command = WithProperties("build-%(prop1:+exists)s-%(prop2:+exists)s.tar.gz") + self.failUnlessEqual(self.props.render(command), + "build-exists-.tar.gz") + + def testEmpty(self): + # None should render as '' + self.props.setProperty("empty", None, "test") + command = WithProperties("build-%(empty)s.tar.gz") + self.failUnlessEqual(self.props.render(command), + "build-.tar.gz") + + def testRecursiveList(self): + self.props.setProperty("x", 10, "test") + self.props.setProperty("y", 20, "test") + command = [ WithProperties("%(x)s %(y)s"), "and", + WithProperties("%(y)s %(x)s") ] + self.failUnlessEqual(self.props.render(command), + ["10 20", "and", "20 10"]) + + def testRecursiveTuple(self): + self.props.setProperty("x", 10, "test") + self.props.setProperty("y", 20, "test") + command = ( WithProperties("%(x)s %(y)s"), "and", + WithProperties("%(y)s %(x)s") ) + self.failUnlessEqual(self.props.render(command), + ("10 20", "and", "20 10")) + + def testRecursiveDict(self): + self.props.setProperty("x", 10, "test") + self.props.setProperty("y", 20, "test") + command = { WithProperties("%(x)s %(y)s") : + WithProperties("%(y)s %(x)s") } + self.failUnlessEqual(self.props.render(command), + {"10 20" : "20 10"}) + +class BuildProperties(unittest.TestCase): + """Test the properties that a build should have.""" + def setUp(self): + self.builder = FakeBuilder() + self.builder_status = builder.BuilderStatus("fakebuilder") + self.builder_status.basedir = "test_properties" + self.builder_status.nextBuildNumber = 5 + rmdirRecursive(self.builder_status.basedir) + os.mkdir(self.builder_status.basedir) + self.build_status = self.builder_status.newBuild() + req = base.BuildRequest("reason", + SourceStamp(branch="branch2", revision="1234"), + 'test_builder', + properties=Properties(scheduler="fakescheduler")) + self.build = base.Build([req]) + self.build.build_status = self.build_status + self.build.setBuilder(self.builder) + self.build.setupProperties() + self.build.setupSlaveBuilder(FakeSlaveBuilder()) + + def testProperties(self): + self.failUnlessEqual(self.build.getProperty("scheduler"), "fakescheduler") + self.failUnlessEqual(self.build.getProperty("branch"), "branch2") + self.failUnlessEqual(self.build.getProperty("revision"), "1234") + self.failUnlessEqual(self.build.getProperty("slavename"), "bot12") + self.failUnlessEqual(self.build.getProperty("buildnumber"), 5) + self.failUnlessEqual(self.build.getProperty("buildername"), "fakebuilder") + self.failUnlessEqual(self.build.getProperty("masterprop"), "master") + +run_config = """ +from buildbot.process import factory +from buildbot.steps.shell import ShellCommand, WithProperties +from buildbot.buildslave import BuildSlave +s = factory.s + +BuildmasterConfig = c = {} +c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'slprop':'slprop'})] +c['schedulers'] = [] +c['slavePortnum'] = 0 +c['properties'] = { 'global' : 'global' } + +# Note: when run against twisted-1.3.0, this locks up about 5% of the time. I +# suspect that a command with no output that finishes quickly triggers a race +# condition in 1.3.0's process-reaping code. The 'touch' process becomes a +# zombie and the step never completes. To keep this from messing up the unit +# tests too badly, this step runs with a reduced timeout. + +f1 = factory.BuildFactory([s(ShellCommand, + flunkOnFailure=True, + command=['touch', + WithProperties('%s-%s-%s', + 'slavename', 'global', 'slprop'), + ], + workdir='.', + timeout=10, + )]) + +b1 = {'name': 'full1', 'slavename': 'bot1', 'builddir': 'bd1', 'factory': f1} +c['builders'] = [b1] + +""" + +class Run(RunMixin, unittest.TestCase): + def testInterpolate(self): + # run an actual build with a step that interpolates a build property + d = self.master.loadConfig(run_config) + d.addCallback(lambda res: self.master.startService()) + d.addCallback(lambda res: self.connectOneSlave("bot1")) + d.addCallback(lambda res: self.requestBuild("full1")) + d.addCallback(self.failUnlessBuildSucceeded) + def _check_touch(res): + f = os.path.join("slavebase-bot1", "bd1", "bot1-global-slprop") + self.failUnless(os.path.exists(f)) + return res + d.addCallback(_check_touch) + return d + + SetProperty_base_config = """ +from buildbot.process import factory +from buildbot.steps.shell import ShellCommand, SetProperty, WithProperties +from buildbot.buildslave import BuildSlave +s = factory.s + +BuildmasterConfig = c = {} +c['slaves'] = [BuildSlave('bot1', 'sekrit')] +c['schedulers'] = [] +c['slavePortnum'] = 0 + +f1 = factory.BuildFactory([ +##STEPS## +]) + +b1 = {'name': 'full1', 'slavename': 'bot1', 'builddir': 'bd1', 'factory': f1} +c['builders'] = [b1] +""" + + SetPropertySimple_config = SetProperty_base_config.replace("##STEPS##", """ + SetProperty(property='foo', command="echo foo"), + SetProperty(property=WithProperties('wp'), command="echo wp"), + SetProperty(property='bar', command="echo bar", strip=False), + """) + + def testSetPropertySimple(self): + d = self.master.loadConfig(self.SetPropertySimple_config) + d.addCallback(lambda res: self.master.startService()) + d.addCallback(lambda res: self.connectOneSlave("bot1")) + d.addCallback(lambda res: self.requestBuild("full1")) + d.addCallback(self.failUnlessBuildSucceeded) + def _check_props(bs): + self.failUnlessEqual(bs.getProperty("foo"), "foo") + self.failUnlessEqual(bs.getProperty("wp"), "wp") + # (will this fail on some platforms, due to newline differences?) + self.failUnlessEqual(bs.getProperty("bar"), "bar\n") + return bs + d.addCallback(_check_props) + return d + + SetPropertyExtractFn_config = SetProperty_base_config.replace("##STEPS##", """ + SetProperty( + extract_fn=lambda rc,stdout,stderr : { + 'foo' : stdout.strip(), + 'bar' : stderr.strip() }, + command="echo foo; echo bar >&2"), + """) + + def testSetPropertyExtractFn(self): + d = self.master.loadConfig(self.SetPropertyExtractFn_config) + d.addCallback(lambda res: self.master.startService()) + d.addCallback(lambda res: self.connectOneSlave("bot1")) + d.addCallback(lambda res: self.requestBuild("full1")) + d.addCallback(self.failUnlessBuildSucceeded) + def _check_props(bs): + self.failUnlessEqual(bs.getProperty("foo"), "foo") + self.failUnlessEqual(bs.getProperty("bar"), "bar") + return bs + d.addCallback(_check_props) + return d + +# we test got_revision in test_vc |