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 |