| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: buildbot.test.test_properties -*- | |
| 2 | |
| 3 import os | |
| 4 | |
| 5 from twisted.trial import unittest | |
| 6 | |
| 7 from buildbot.sourcestamp import SourceStamp | |
| 8 from buildbot.process import base | |
| 9 from buildbot.process.properties import WithProperties, Properties | |
| 10 from buildbot.status import builder | |
| 11 from buildbot.slave.commands import rmdirRecursive | |
| 12 from buildbot.test.runutils import RunMixin | |
| 13 | |
| 14 | |
| 15 class FakeBuild: | |
| 16 pass | |
| 17 class FakeBuildMaster: | |
| 18 properties = Properties(masterprop="master") | |
| 19 class FakeBotMaster: | |
| 20 parent = FakeBuildMaster() | |
| 21 class FakeBuilder: | |
| 22 statusbag = None | |
| 23 name = "fakebuilder" | |
| 24 botmaster = FakeBotMaster() | |
| 25 class FakeSlave: | |
| 26 slavename = "bot12" | |
| 27 properties = Properties(slavename="bot12") | |
| 28 class FakeSlaveBuilder: | |
| 29 slave = FakeSlave() | |
| 30 def getSlaveCommandVersion(self, command, oldversion=None): | |
| 31 return "1.10" | |
| 32 class FakeScheduler: | |
| 33 name = "fakescheduler" | |
| 34 | |
| 35 class TestProperties(unittest.TestCase): | |
| 36 def setUp(self): | |
| 37 self.props = Properties() | |
| 38 | |
| 39 def testDictBehavior(self): | |
| 40 self.props.setProperty("do-tests", 1, "scheduler") | |
| 41 self.props.setProperty("do-install", 2, "scheduler") | |
| 42 | |
| 43 self.assert_(self.props.has_key('do-tests')) | |
| 44 self.failUnlessEqual(self.props['do-tests'], 1) | |
| 45 self.failUnlessEqual(self.props['do-install'], 2) | |
| 46 self.assertRaises(KeyError, lambda : self.props['do-nothing']) | |
| 47 self.failUnlessEqual(self.props.getProperty('do-install'), 2) | |
| 48 | |
| 49 def testUpdate(self): | |
| 50 self.props.setProperty("x", 24, "old") | |
| 51 newprops = { 'a' : 1, 'b' : 2 } | |
| 52 self.props.update(newprops, "new") | |
| 53 | |
| 54 self.failUnlessEqual(self.props.getProperty('x'), 24) | |
| 55 self.failUnlessEqual(self.props.getPropertySource('x'), 'old') | |
| 56 self.failUnlessEqual(self.props.getProperty('a'), 1) | |
| 57 self.failUnlessEqual(self.props.getPropertySource('a'), 'new') | |
| 58 | |
| 59 def testUpdateFromProperties(self): | |
| 60 self.props.setProperty("x", 24, "old") | |
| 61 newprops = Properties() | |
| 62 newprops.setProperty('a', 1, "new") | |
| 63 newprops.setProperty('b', 2, "new") | |
| 64 self.props.updateFromProperties(newprops) | |
| 65 | |
| 66 self.failUnlessEqual(self.props.getProperty('x'), 24) | |
| 67 self.failUnlessEqual(self.props.getPropertySource('x'), 'old') | |
| 68 self.failUnlessEqual(self.props.getProperty('a'), 1) | |
| 69 self.failUnlessEqual(self.props.getPropertySource('a'), 'new') | |
| 70 | |
| 71 # render() is pretty well tested by TestWithProperties | |
| 72 | |
| 73 class TestWithProperties(unittest.TestCase): | |
| 74 def setUp(self): | |
| 75 self.props = Properties() | |
| 76 | |
| 77 def testBasic(self): | |
| 78 # test basic substitution with WithProperties | |
| 79 self.props.setProperty("revision", "47", "test") | |
| 80 command = WithProperties("build-%s.tar.gz", "revision") | |
| 81 self.failUnlessEqual(self.props.render(command), | |
| 82 "build-47.tar.gz") | |
| 83 | |
| 84 def testDict(self): | |
| 85 # test dict-style substitution with WithProperties | |
| 86 self.props.setProperty("other", "foo", "test") | |
| 87 command = WithProperties("build-%(other)s.tar.gz") | |
| 88 self.failUnlessEqual(self.props.render(command), | |
| 89 "build-foo.tar.gz") | |
| 90 | |
| 91 def testDictColonMinus(self): | |
| 92 # test dict-style substitution with WithProperties | |
| 93 self.props.setProperty("prop1", "foo", "test") | |
| 94 command = WithProperties("build-%(prop1:-empty)s-%(prop2:-empty)s.tar.gz
") | |
| 95 self.failUnlessEqual(self.props.render(command), | |
| 96 "build-foo-empty.tar.gz") | |
| 97 | |
| 98 def testDictColonPlus(self): | |
| 99 # test dict-style substitution with WithProperties | |
| 100 self.props.setProperty("prop1", "foo", "test") | |
| 101 command = WithProperties("build-%(prop1:+exists)s-%(prop2:+exists)s.tar.
gz") | |
| 102 self.failUnlessEqual(self.props.render(command), | |
| 103 "build-exists-.tar.gz") | |
| 104 | |
| 105 def testEmpty(self): | |
| 106 # None should render as '' | |
| 107 self.props.setProperty("empty", None, "test") | |
| 108 command = WithProperties("build-%(empty)s.tar.gz") | |
| 109 self.failUnlessEqual(self.props.render(command), | |
| 110 "build-.tar.gz") | |
| 111 | |
| 112 def testRecursiveList(self): | |
| 113 self.props.setProperty("x", 10, "test") | |
| 114 self.props.setProperty("y", 20, "test") | |
| 115 command = [ WithProperties("%(x)s %(y)s"), "and", | |
| 116 WithProperties("%(y)s %(x)s") ] | |
| 117 self.failUnlessEqual(self.props.render(command), | |
| 118 ["10 20", "and", "20 10"]) | |
| 119 | |
| 120 def testRecursiveTuple(self): | |
| 121 self.props.setProperty("x", 10, "test") | |
| 122 self.props.setProperty("y", 20, "test") | |
| 123 command = ( WithProperties("%(x)s %(y)s"), "and", | |
| 124 WithProperties("%(y)s %(x)s") ) | |
| 125 self.failUnlessEqual(self.props.render(command), | |
| 126 ("10 20", "and", "20 10")) | |
| 127 | |
| 128 def testRecursiveDict(self): | |
| 129 self.props.setProperty("x", 10, "test") | |
| 130 self.props.setProperty("y", 20, "test") | |
| 131 command = { WithProperties("%(x)s %(y)s") : | |
| 132 WithProperties("%(y)s %(x)s") } | |
| 133 self.failUnlessEqual(self.props.render(command), | |
| 134 {"10 20" : "20 10"}) | |
| 135 | |
| 136 class BuildProperties(unittest.TestCase): | |
| 137 """Test the properties that a build should have.""" | |
| 138 def setUp(self): | |
| 139 self.builder = FakeBuilder() | |
| 140 self.builder_status = builder.BuilderStatus("fakebuilder") | |
| 141 self.builder_status.basedir = "test_properties" | |
| 142 self.builder_status.nextBuildNumber = 5 | |
| 143 rmdirRecursive(self.builder_status.basedir) | |
| 144 os.mkdir(self.builder_status.basedir) | |
| 145 self.build_status = self.builder_status.newBuild() | |
| 146 req = base.BuildRequest("reason", | |
| 147 SourceStamp(branch="branch2", revision="1234"), | |
| 148 'test_builder', | |
| 149 properties=Properties(scheduler="fakescheduler")) | |
| 150 self.build = base.Build([req]) | |
| 151 self.build.build_status = self.build_status | |
| 152 self.build.setBuilder(self.builder) | |
| 153 self.build.setupProperties() | |
| 154 self.build.setupSlaveBuilder(FakeSlaveBuilder()) | |
| 155 | |
| 156 def testProperties(self): | |
| 157 self.failUnlessEqual(self.build.getProperty("scheduler"), "fakescheduler
") | |
| 158 self.failUnlessEqual(self.build.getProperty("branch"), "branch2") | |
| 159 self.failUnlessEqual(self.build.getProperty("revision"), "1234") | |
| 160 self.failUnlessEqual(self.build.getProperty("slavename"), "bot12") | |
| 161 self.failUnlessEqual(self.build.getProperty("buildnumber"), 5) | |
| 162 self.failUnlessEqual(self.build.getProperty("buildername"), "fakebuilder
") | |
| 163 self.failUnlessEqual(self.build.getProperty("masterprop"), "master") | |
| 164 | |
| 165 run_config = """ | |
| 166 from buildbot.process import factory | |
| 167 from buildbot.steps.shell import ShellCommand, WithProperties | |
| 168 from buildbot.buildslave import BuildSlave | |
| 169 from buildbot.config import BuilderConfig | |
| 170 s = factory.s | |
| 171 | |
| 172 BuildmasterConfig = c = {} | |
| 173 c['slaves'] = [BuildSlave('bot1', 'sekrit', properties={'slprop':'slprop'})] | |
| 174 c['schedulers'] = [] | |
| 175 c['slavePortnum'] = 0 | |
| 176 c['properties'] = { 'global' : 'global' } | |
| 177 | |
| 178 # Note: when run against twisted-1.3.0, this locks up about 5% of the time. I | |
| 179 # suspect that a command with no output that finishes quickly triggers a race | |
| 180 # condition in 1.3.0's process-reaping code. The 'touch' process becomes a | |
| 181 # zombie and the step never completes. To keep this from messing up the unit | |
| 182 # tests too badly, this step runs with a reduced timeout. | |
| 183 | |
| 184 f1 = factory.BuildFactory([s(ShellCommand, | |
| 185 flunkOnFailure=True, | |
| 186 command=['touch', | |
| 187 WithProperties('%s-%s-%s', | |
| 188 'slavename', 'global', 'slprop'), | |
| 189 ], | |
| 190 workdir='.', | |
| 191 timeout=10, | |
| 192 )]) | |
| 193 | |
| 194 c['builders'] = [ | |
| 195 BuilderConfig(name='full1', slavename='bot1', factory=f1, builddir='bd1'), | |
| 196 ] | |
| 197 | |
| 198 """ | |
| 199 | |
| 200 class Run(RunMixin, unittest.TestCase): | |
| 201 def testInterpolate(self): | |
| 202 # run an actual build with a step that interpolates a build property | |
| 203 d = self.master.loadConfig(run_config) | |
| 204 d.addCallback(lambda res: self.master.startService()) | |
| 205 d.addCallback(lambda res: self.connectOneSlave("bot1")) | |
| 206 d.addCallback(lambda res: self.requestBuild("full1")) | |
| 207 d.addCallback(self.failUnlessBuildSucceeded) | |
| 208 def _check_touch(res): | |
| 209 f = os.path.join("slavebase-bot1", "bd1", "bot1-global-slprop") | |
| 210 self.failUnless(os.path.exists(f)) | |
| 211 return res | |
| 212 d.addCallback(_check_touch) | |
| 213 return d | |
| 214 | |
| 215 SetProperty_base_config = """ | |
| 216 from buildbot.process import factory | |
| 217 from buildbot.steps.shell import ShellCommand, SetProperty, WithProperties | |
| 218 from buildbot.buildslave import BuildSlave | |
| 219 from buildbot.config import BuilderConfig | |
| 220 s = factory.s | |
| 221 | |
| 222 BuildmasterConfig = c = {} | |
| 223 c['slaves'] = [BuildSlave('bot1', 'sekrit')] | |
| 224 c['schedulers'] = [] | |
| 225 c['slavePortnum'] = 0 | |
| 226 | |
| 227 f1 = factory.BuildFactory([ | |
| 228 ##STEPS## | |
| 229 ]) | |
| 230 | |
| 231 c['builders'] = [ | |
| 232 BuilderConfig(name='full1', slavename='bot1', factory=f1, builddir='bd1'), | |
| 233 ] | |
| 234 """ | |
| 235 | |
| 236 SetPropertySimple_config = SetProperty_base_config.replace("##STEPS##", """ | |
| 237 SetProperty(property='foo', command="echo foo"), | |
| 238 SetProperty(property=WithProperties('wp'), command="echo wp"), | |
| 239 SetProperty(property='bar', command="echo bar", strip=False), | |
| 240 """) | |
| 241 | |
| 242 def testSetPropertySimple(self): | |
| 243 d = self.master.loadConfig(self.SetPropertySimple_config) | |
| 244 d.addCallback(lambda res: self.master.startService()) | |
| 245 d.addCallback(lambda res: self.connectOneSlave("bot1")) | |
| 246 d.addCallback(lambda res: self.requestBuild("full1")) | |
| 247 d.addCallback(self.failUnlessBuildSucceeded) | |
| 248 def _check_props(bs): | |
| 249 self.failUnlessEqual(bs.getProperty("foo"), "foo") | |
| 250 self.failUnlessEqual(bs.getProperty("wp"), "wp") | |
| 251 # (will this fail on some platforms, due to newline differences?) | |
| 252 self.failUnlessEqual(bs.getProperty("bar"), "bar\n") | |
| 253 return bs | |
| 254 d.addCallback(_check_props) | |
| 255 return d | |
| 256 | |
| 257 SetPropertyExtractFn_config = SetProperty_base_config.replace("##STEPS##", "
"" | |
| 258 SetProperty( | |
| 259 extract_fn=lambda rc,stdout,stderr : { | |
| 260 'foo' : stdout.strip(), | |
| 261 'bar' : stderr.strip() }, | |
| 262 command="echo foo; echo bar >&2"), | |
| 263 """) | |
| 264 | |
| 265 def testSetPropertyExtractFn(self): | |
| 266 d = self.master.loadConfig(self.SetPropertyExtractFn_config) | |
| 267 d.addCallback(lambda res: self.master.startService()) | |
| 268 d.addCallback(lambda res: self.connectOneSlave("bot1")) | |
| 269 d.addCallback(lambda res: self.requestBuild("full1")) | |
| 270 d.addCallback(self.failUnlessBuildSucceeded) | |
| 271 def _check_props(bs): | |
| 272 self.failUnlessEqual(bs.getProperty("foo"), "foo") | |
| 273 self.failUnlessEqual(bs.getProperty("bar"), "bar") | |
| 274 return bs | |
| 275 d.addCallback(_check_props) | |
| 276 return d | |
| 277 | |
| 278 # we test got_revision in test_vc | |
| OLD | NEW |