remove a lot of unused imports, marked by pyflakes
[buildbot.git] / buildbot / test / test_steps.py
bloba294d0e7edd72af6d7c436ab00bdc3fd5faec517
1 # -*- test-case-name: buildbot.test.test_steps -*-
3 # create the BuildStep with a fake .remote instance that logs the
4 # .callRemote invocations and compares them against the expected calls. Then
5 # the test harness should send statusUpdate() messages in with assorted
6 # data, eventually calling remote_complete(). Then we can verify that the
7 # Step's rc was correct, and that the status it was supposed to return
8 # matches.
10 # sometimes, .callRemote should raise an exception because of a stale
11 # reference. Sometimes it should errBack with an UnknownCommand failure.
12 # Or other failure.
14 # todo: test batched updates, by invoking remote_update(updates) instead of
15 # statusUpdate(update). Also involves interrupted builds.
17 import os, time
19 from twisted.trial import unittest
20 from twisted.internet import reactor
21 from twisted.internet.defer import Deferred
23 from buildbot.sourcestamp import SourceStamp
24 from buildbot.process import step, base, factory
25 from buildbot.process.step import ShellCommand #, ShellCommands
26 from buildbot.status import builder
27 from buildbot.test.runutils import RunMixin, rmtree
28 from buildbot.test.runutils import makeBuildStep
29 from buildbot.twcompat import maybeWait
30 from buildbot.slave import commands
33 class MyShellCommand(ShellCommand):
34 started = False
35 def runCommand(self, c):
36 self.started = True
37 self.rc = c
38 return ShellCommand.runCommand(self, c)
40 class FakeBuild:
41 pass
42 class FakeBuilder:
43 statusbag = None
44 name = "fakebuilder"
45 class FakeSlaveBuilder:
46 def getSlaveCommandVersion(self, command, oldversion=None):
47 return "1.10"
49 class FakeRemote:
50 def __init__(self):
51 self.events = []
52 self.remoteCalls = 0
53 #self.callRemoteNotifier = None
54 def callRemote(self, methname, *args):
55 event = ["callRemote", methname, args]
56 self.events.append(event)
57 ## if self.callRemoteNotifier:
58 ## reactor.callLater(0, self.callRemoteNotifier, event)
59 self.remoteCalls += 1
60 self.deferred = Deferred()
61 return self.deferred
62 def notifyOnDisconnect(self, callback):
63 pass
64 def dontNotifyOnDisconnect(self, callback):
65 pass
68 class BuildStep(unittest.TestCase):
70 def setUp(self):
71 rmtree("test_steps")
72 self.builder = FakeBuilder()
73 self.builder_status = builder.BuilderStatus("fakebuilder")
74 self.builder_status.basedir = "test_steps"
75 self.builder_status.nextBuildNumber = 0
76 os.mkdir(self.builder_status.basedir)
77 self.build_status = self.builder_status.newBuild()
78 req = base.BuildRequest("reason", SourceStamp())
79 self.build = base.Build([req])
80 self.build.build_status = self.build_status # fake it
81 self.build.builder = self.builder
82 self.build.slavebuilder = FakeSlaveBuilder()
83 self.remote = FakeRemote()
84 self.finished = 0
86 def callback(self, results):
87 self.failed = 0
88 self.failure = None
89 self.results = results
90 self.finished = 1
91 def errback(self, failure):
92 self.failed = 1
93 self.failure = failure
94 self.results = None
95 self.finished = 1
97 def testShellCommand1(self):
98 cmd = "argle bargle"
99 dir = "murkle"
100 expectedEvents = []
101 step.RemoteCommand.commandCounter[0] = 3
102 c = MyShellCommand(workdir=dir, command=cmd, build=self.build,
103 timeout=10)
104 self.assertEqual(self.remote.events, expectedEvents)
105 c.step_status = self.build_status.addStepWithName("myshellcommand")
106 d = c.startStep(self.remote)
107 self.failUnless(c.started)
108 rc = c.rc
109 d.addCallbacks(self.callback, self.errback)
110 timeout = time.time() + 10
111 while self.remote.remoteCalls == 0:
112 if time.time() > timeout:
113 self.fail("timeout")
114 reactor.iterate(0.01)
115 expectedEvents.append(["callRemote", "startCommand",
116 (rc, "3",
117 "shell",
118 {'command': "argle bargle",
119 'workdir': "murkle",
120 'want_stdout': 1,
121 'want_stderr': 1,
122 'logfiles': {},
123 'timeout': 10,
124 'env': None}) ] )
125 self.assertEqual(self.remote.events, expectedEvents)
127 # we could do self.remote.deferred.errback(UnknownCommand) here. We
128 # could also do .callback(), but generally the master end silently
129 # ignores the slave's ack
131 logs = c.step_status.getLogs()
132 for log in logs:
133 if log.getName() == "log":
134 break
136 rc.remoteUpdate({'header':
137 "command 'argle bargle' in dir 'murkle'\n\n"})
138 rc.remoteUpdate({'stdout': "foo\n"})
139 self.assertEqual(log.getText(), "foo\n")
140 self.assertEqual(log.getTextWithHeaders(),
141 "command 'argle bargle' in dir 'murkle'\n\n"
142 "foo\n")
143 rc.remoteUpdate({'stderr': "bar\n"})
144 self.assertEqual(log.getText(), "foo\nbar\n")
145 self.assertEqual(log.getTextWithHeaders(),
146 "command 'argle bargle' in dir 'murkle'\n\n"
147 "foo\nbar\n")
148 rc.remoteUpdate({'rc': 0})
149 self.assertEqual(rc.rc, 0)
151 rc.remote_complete()
152 # that should fire the Deferred
153 timeout = time.time() + 10
154 while not self.finished:
155 if time.time() > timeout:
156 self.fail("timeout")
157 reactor.iterate(0.01)
158 self.assertEqual(self.failed, 0)
159 self.assertEqual(self.results, 0)
162 class MyObserver(step.LogObserver):
163 out = ""
164 def outReceived(self, data):
165 self.out = self.out + data
167 class Steps(unittest.TestCase):
168 def testMultipleStepInstances(self):
169 steps = [
170 (step.CVS, {'cvsroot': "root", 'cvsmodule': "module"}),
171 (step.Configure, {'command': "./configure"}),
172 (step.Compile, {'command': "make"}),
173 (step.Compile, {'command': "make more"}),
174 (step.Compile, {'command': "make evenmore"}),
175 (step.Test, {'command': "make test"}),
176 (step.Test, {'command': "make testharder"}),
178 f = factory.ConfigurableBuildFactory(steps)
179 req = base.BuildRequest("reason", SourceStamp())
180 b = f.newBuild([req])
181 #for s in b.steps: print s.name
183 # test the various methods available to buildsteps
185 def test_getProperty(self):
186 s = makeBuildStep("test_steps.Steps.test_getProperty")
187 bs = s.step_status.getBuild()
189 s.setProperty("prop1", "value1")
190 s.setProperty("prop2", "value2")
191 self.failUnlessEqual(s.getProperty("prop1"), "value1")
192 self.failUnlessEqual(bs.getProperty("prop1"), "value1")
193 self.failUnlessEqual(s.getProperty("prop2"), "value2")
194 self.failUnlessEqual(bs.getProperty("prop2"), "value2")
195 s.setProperty("prop1", "value1a")
196 self.failUnlessEqual(s.getProperty("prop1"), "value1a")
197 self.failUnlessEqual(bs.getProperty("prop1"), "value1a")
200 def test_addURL(self):
201 s = makeBuildStep("test_steps.Steps.test_addURL")
202 s.addURL("coverage", "http://coverage.example.org/target")
203 s.addURL("icon", "http://coverage.example.org/icon.png")
204 bs = s.step_status
205 links = bs.getURLs()
206 expected = {"coverage": "http://coverage.example.org/target",
207 "icon": "http://coverage.example.org/icon.png",
209 self.failUnlessEqual(links, expected)
211 def test_addLog(self):
212 s = makeBuildStep("test_steps.Steps.test_addLog")
213 l = s.addLog("newlog")
214 l.addStdout("some stdout here")
215 l.finish()
216 bs = s.step_status
217 logs = bs.getLogs()
218 self.failUnlessEqual(len(logs), 1)
219 l1 = logs[0]
220 self.failUnlessEqual(l1.getText(), "some stdout here")
222 def test_addHTMLLog(self):
223 s = makeBuildStep("test_steps.Steps.test_addHTMLLog")
224 l = s.addHTMLLog("newlog", "some html here")
225 bs = s.step_status
226 logs = bs.getLogs()
227 self.failUnlessEqual(len(logs), 1)
228 l1 = logs[0]
229 self.failUnless(isinstance(l1, builder.HTMLLogFile))
230 self.failUnlessEqual(l1.getText(), "some html here")
232 def test_addCompleteLog(self):
233 s = makeBuildStep("test_steps.Steps.test_addCompleteLog")
234 l = s.addCompleteLog("newlog", "some stdout here")
235 bs = s.step_status
236 logs = bs.getLogs()
237 self.failUnlessEqual(len(logs), 1)
238 l1 = logs[0]
239 self.failUnlessEqual(l1.getText(), "some stdout here")
241 def test_addLogObserver(self):
242 s = makeBuildStep("test_steps.Steps.test_addLogObserver")
243 bss = s.step_status
244 o1,o2,o3 = MyObserver(), MyObserver(), MyObserver()
246 # add the log before the observer
247 l1 = s.addLog("one")
248 l1.addStdout("onestuff")
249 s.addLogObserver("one", o1)
250 self.failUnlessEqual(o1.out, "onestuff")
251 l1.addStdout(" morestuff")
252 self.failUnlessEqual(o1.out, "onestuff morestuff")
254 # add the observer before the log
255 s.addLogObserver("two", o2)
256 l2 = s.addLog("two")
257 l2.addStdout("twostuff")
258 self.failUnlessEqual(o2.out, "twostuff")
260 # test more stuff about ShellCommands
262 def test_description(self):
263 s = makeBuildStep("test_steps.Steps.test_description.1",
264 step_class=ShellCommand,
265 workdir="dummy",
266 description=["list", "of", "strings"],
267 descriptionDone=["another", "list"])
268 self.failUnlessEqual(s.description, ["list", "of", "strings"])
269 self.failUnlessEqual(s.descriptionDone, ["another", "list"])
271 s = makeBuildStep("test_steps.Steps.test_description.2",
272 step_class=ShellCommand,
273 workdir="dummy",
274 description="single string",
275 descriptionDone="another string")
276 self.failUnlessEqual(s.description, ["single string"])
277 self.failUnlessEqual(s.descriptionDone, ["another string"])
279 class VersionCheckingStep(step.BuildStep):
280 def start(self):
281 # give our test a chance to run. It is non-trivial for a buildstep to
282 # claw its way back out to the test case which is currently running.
283 master = self.build.builder.botmaster.parent
284 checker = master._checker
285 checker(self)
286 # then complete
287 self.finished(step.SUCCESS)
289 version_config = """
290 from buildbot.process import factory, step
291 from buildbot.test.test_steps import VersionCheckingStep
292 BuildmasterConfig = c = {}
293 f1 = factory.BuildFactory([
294 factory.s(VersionCheckingStep),
296 c['bots'] = [['bot1', 'sekrit']]
297 c['sources'] = []
298 c['schedulers'] = []
299 c['builders'] = [{'name':'quick', 'slavename':'bot1',
300 'builddir': 'quickdir', 'factory': f1}]
301 c['slavePortnum'] = 0
304 class SlaveVersion(RunMixin, unittest.TestCase):
305 def setUp(self):
306 RunMixin.setUp(self)
307 self.master.loadConfig(version_config)
308 self.master.startService()
309 d = self.connectSlave(["quick"])
310 return maybeWait(d)
312 def doBuild(self, buildername):
313 br = base.BuildRequest("forced", SourceStamp())
314 d = br.waitUntilFinished()
315 self.control.getBuilder(buildername).requestBuild(br)
316 return d
319 def checkCompare(self, s):
320 cver = commands.command_version
321 v = s.slaveVersion("svn", None)
322 # this insures that we are getting the version correctly
323 self.failUnlessEqual(s.slaveVersion("svn", None), cver)
324 # and that non-existent commands do not provide a version
325 self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND"), None)
326 # TODO: verify that a <=0.5.0 buildslave (which does not implement
327 # remote_getCommands) handles oldversion= properly. This requires a
328 # mutant slave which does not offer that method.
329 #self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND", "old"), "old")
331 # now check the comparison functions
332 self.failIf(s.slaveVersionIsOlderThan("svn", cver))
333 self.failIf(s.slaveVersionIsOlderThan("svn", "1.1"))
334 self.failUnless(s.slaveVersionIsOlderThan("svn", cver + ".1"))
336 self.failUnlessEqual(s.getSlaveName(), "bot1")
338 def testCompare(self):
339 self.master._checker = self.checkCompare
340 d = self.doBuild("quick")
341 return maybeWait(d)