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
10 # sometimes, .callRemote should raise an exception because of a stale
11 # reference. Sometimes it should errBack with an UnknownCommand failure.
14 # todo: test batched updates, by invoking remote_update(updates) instead of
15 # statusUpdate(update). Also involves interrupted builds.
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
28 from buildbot
.twcompat
import maybeWait
29 from buildbot
.slave
import commands
31 from twisted
.python
import log
32 #log.startLogging(sys.stdout)
34 class MyShellCommand(ShellCommand
):
36 def runCommand(self
, c
):
39 return ShellCommand
.runCommand(self
, c
)
46 class FakeSlaveBuilder
:
47 def getSlaveCommandVersion(self
, command
, oldversion
=None):
54 #self.callRemoteNotifier = None
55 def callRemote(self
, methname
, *args
):
56 event
= ["callRemote", methname
, args
]
57 self
.events
.append(event
)
58 ## if self.callRemoteNotifier:
59 ## reactor.callLater(0, self.callRemoteNotifier, event)
61 self
.deferred
= Deferred()
63 def notifyOnDisconnect(self
, callback
):
65 def dontNotifyOnDisconnect(self
, callback
):
69 class BuildStep(unittest
.TestCase
):
71 self
.builder
= FakeBuilder()
72 self
.builder_status
= builder
.BuilderStatus("fakebuilder")
73 self
.builder_status
.basedir
= "test_steps"
74 self
.builder_status
.nextBuildNumber
= 0
75 os
.mkdir(self
.builder_status
.basedir
)
76 self
.build_status
= self
.builder_status
.newBuild()
77 req
= base
.BuildRequest("reason", SourceStamp())
78 self
.build
= base
.Build([req
])
79 self
.build
.build_status
= self
.build_status
# fake it
80 self
.build
.builder
= self
.builder
81 self
.build
.slavebuilder
= FakeSlaveBuilder()
82 self
.remote
= FakeRemote()
85 def callback(self
, results
):
88 self
.results
= results
90 def errback(self
, failure
):
92 self
.failure
= failure
96 def testShellCommand1(self
):
100 step
.RemoteCommand
.commandCounter
[0] = 3
101 c
= MyShellCommand(workdir
=dir, command
=cmd
, build
=self
.build
,
103 self
.assertEqual(self
.remote
.events
, expectedEvents
)
104 self
.build_status
.addStep(c
)
105 d
= c
.startStep(self
.remote
)
106 self
.failUnless(c
.started
)
108 d
.addCallbacks(self
.callback
, self
.errback
)
109 timeout
= time
.time() + 10
110 while self
.remote
.remoteCalls
== 0:
111 if time
.time() > timeout
:
113 reactor
.iterate(0.01)
114 expectedEvents
.append(["callRemote", "startCommand",
117 {'command': "argle bargle",
123 self
.assertEqual(self
.remote
.events
, expectedEvents
)
125 # we could do self.remote.deferred.errback(UnknownCommand) here. We
126 # could also do .callback(), but generally the master end silently
127 # ignores the slave's ack
129 logs
= c
.step_status
.getLogs()
131 if log
.getName() == "log":
134 rc
.remoteUpdate({'header':
135 "command 'argle bargle' in dir 'murkle'\n\n"})
136 rc
.remoteUpdate({'stdout': "foo\n"})
137 self
.assertEqual(log
.getText(), "foo\n")
138 self
.assertEqual(log
.getTextWithHeaders(),
139 "command 'argle bargle' in dir 'murkle'\n\n"
141 rc
.remoteUpdate({'stderr': "bar\n"})
142 self
.assertEqual(log
.getText(), "foo\nbar\n")
143 self
.assertEqual(log
.getTextWithHeaders(),
144 "command 'argle bargle' in dir 'murkle'\n\n"
146 rc
.remoteUpdate({'rc': 0})
147 self
.assertEqual(rc
.rc
, 0)
150 # that should fire the Deferred
151 timeout
= time
.time() + 10
152 while not self
.finished
:
153 if time
.time() > timeout
:
155 reactor
.iterate(0.01)
156 self
.assertEqual(self
.failed
, 0)
157 self
.assertEqual(self
.results
, 0)
159 class Steps(unittest
.TestCase
):
160 def testMultipleStepInstances(self
):
162 (step
.CVS
, {'cvsroot': "root", 'cvsmodule': "module"}),
163 (step
.Configure
, {'command': "./configure"}),
164 (step
.Compile
, {'command': "make"}),
165 (step
.Compile
, {'command': "make more"}),
166 (step
.Compile
, {'command': "make evenmore"}),
167 (step
.Test
, {'command': "make test"}),
168 (step
.Test
, {'command': "make testharder"}),
170 f
= factory
.ConfigurableBuildFactory(steps
)
171 req
= base
.BuildRequest("reason", SourceStamp())
172 b
= f
.newBuild([req
])
173 #for s in b.steps: print s.name
175 class VersionCheckingStep(step
.BuildStep
):
177 # give our test a chance to run. It is non-trivial for a buildstep to
178 # claw its way back out to the test case which is currently running.
179 master
= self
.build
.builder
.botmaster
.parent
180 checker
= master
._checker
183 self
.finished(step
.SUCCESS
)
186 from buildbot.process import factory, step
187 from buildbot.test.test_steps import VersionCheckingStep
188 BuildmasterConfig = c = {}
189 f1 = factory.BuildFactory([
190 factory.s(VersionCheckingStep),
192 c['bots'] = [['bot1', 'sekrit']]
195 c['builders'] = [{'name':'quick', 'slavename':'bot1',
196 'builddir': 'quickdir', 'factory': f1}]
197 c['slavePortnum'] = 0
200 class Version(RunMixin
, unittest
.TestCase
):
203 self
.master
.loadConfig(version_config
)
204 self
.master
.startService()
205 d
= self
.connectSlave(["quick"])
208 def doBuild(self
, buildername
):
209 br
= base
.BuildRequest("forced", SourceStamp())
210 d
= br
.waitUntilFinished()
211 self
.control
.getBuilder(buildername
).requestBuild(br
)
215 def checkCompare(self
, s
):
216 v
= s
.slaveVersion("svn", None)
217 # this insures that we are getting the version correctly
218 self
.failUnlessEqual(s
.slaveVersion("svn", None), commands
.cvs_ver
)
219 # and that non-existent commands do not provide a version
220 self
.failUnlessEqual(s
.slaveVersion("NOSUCHCOMMAND"), None)
221 # TODO: verify that a <=0.5.0 buildslave (which does not implement
222 # remote_getCommands) handles oldversion= properly. This requires a
223 # mutant slave which does not offer that method.
224 #self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND", "old"), "old")
226 # now check the comparison functions
227 self
.failIf(s
.slaveVersionIsOlderThan("svn", commands
.cvs_ver
))
228 self
.failIf(s
.slaveVersionIsOlderThan("svn", "1.1"))
229 self
.failUnless(s
.slaveVersionIsOlderThan("svn",
230 commands
.cvs_ver
+ ".1"))
232 def testCompare(self
):
233 self
.master
._checker
= self
.checkCompare
234 d
= self
.doBuild("quick")