| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: buildbot.test.test_steps -*- | |
| 2 | |
| 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. | |
| 9 | |
| 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. | |
| 13 | |
| 14 # todo: test batched updates, by invoking remote_update(updates) instead of | |
| 15 # statusUpdate(update). Also involves interrupted builds. | |
| 16 | |
| 17 import sys | |
| 18 import os | |
| 19 | |
| 20 from twisted.trial import unittest | |
| 21 from twisted.internet import reactor, defer | |
| 22 | |
| 23 from buildbot.sourcestamp import SourceStamp | |
| 24 from buildbot.process import buildstep, base, factory | |
| 25 from buildbot.process.properties import Properties, WithProperties | |
| 26 from buildbot.buildslave import BuildSlave | |
| 27 from buildbot.steps import shell, source, python, master | |
| 28 from buildbot.status import builder | |
| 29 from buildbot.status.builder import SUCCESS, WARNINGS, FAILURE, SKIPPED | |
| 30 from buildbot.test.runutils import RunMixin, rmtree | |
| 31 from buildbot.test.runutils import makeBuildStep, StepTester | |
| 32 from buildbot.slave import commands, registry | |
| 33 | |
| 34 | |
| 35 class MyShellCommand(shell.ShellCommand): | |
| 36 started = False | |
| 37 def runCommand(self, c): | |
| 38 self.started = True | |
| 39 self.rc = c | |
| 40 return shell.ShellCommand.runCommand(self, c) | |
| 41 | |
| 42 class FakeBuild: | |
| 43 pass | |
| 44 class FakeBuilder: | |
| 45 statusbag = None | |
| 46 name = "fakebuilder" | |
| 47 class FakeSlaveBuilder: | |
| 48 def getSlaveCommandVersion(self, command, oldversion=None): | |
| 49 return "1.10" | |
| 50 | |
| 51 class FakeRemote: | |
| 52 def __init__(self): | |
| 53 self.events = [] | |
| 54 self.remoteCalls = 0 | |
| 55 #self.callRemoteNotifier = None | |
| 56 def callRemote(self, methname, *args): | |
| 57 event = ["callRemote", methname, args] | |
| 58 self.events.append(event) | |
| 59 ## if self.callRemoteNotifier: | |
| 60 ## reactor.callLater(0, self.callRemoteNotifier, event) | |
| 61 self.remoteCalls += 1 | |
| 62 self.deferred = defer.Deferred() | |
| 63 return self.deferred | |
| 64 def notifyOnDisconnect(self, callback): | |
| 65 pass | |
| 66 def dontNotifyOnDisconnect(self, callback): | |
| 67 pass | |
| 68 | |
| 69 | |
| 70 class BuildStep(unittest.TestCase): | |
| 71 | |
| 72 def setUp(self): | |
| 73 rmtree("test_steps") | |
| 74 self.builder = FakeBuilder() | |
| 75 self.builder_status = builder.BuilderStatus("fakebuilder") | |
| 76 self.builder_status.basedir = "test_steps" | |
| 77 self.builder_status.nextBuildNumber = 0 | |
| 78 os.mkdir(self.builder_status.basedir) | |
| 79 self.build_status = self.builder_status.newBuild() | |
| 80 req = base.BuildRequest("reason", SourceStamp(), 'test_builder') | |
| 81 self.build = base.Build([req]) | |
| 82 self.build.build_status = self.build_status # fake it | |
| 83 self.build.builder = self.builder | |
| 84 self.build.slavebuilder = FakeSlaveBuilder() | |
| 85 self.remote = FakeRemote() | |
| 86 self.finished = 0 | |
| 87 | |
| 88 def callback(self, results): | |
| 89 self.failed = 0 | |
| 90 self.failure = None | |
| 91 self.results = results | |
| 92 self.finished = 1 | |
| 93 def errback(self, failure): | |
| 94 self.failed = 1 | |
| 95 self.failure = failure | |
| 96 self.results = None | |
| 97 self.finished = 1 | |
| 98 | |
| 99 def testShellCommand1(self): | |
| 100 cmd = "argle bargle" | |
| 101 dir = "murkle" | |
| 102 self.expectedEvents = [] | |
| 103 buildstep.RemoteCommand.commandCounter[0] = 3 | |
| 104 c = MyShellCommand(workdir=dir, command=cmd, timeout=10) | |
| 105 c.setBuild(self.build) | |
| 106 c.setBuildSlave(BuildSlave("name", "password")) | |
| 107 self.assertEqual(self.remote.events, self.expectedEvents) | |
| 108 c.step_status = self.build_status.addStepWithName("myshellcommand") | |
| 109 d = c.startStep(self.remote) | |
| 110 self.failUnless(c.started) | |
| 111 d.addCallbacks(self.callback, self.errback) | |
| 112 d2 = self.poll() | |
| 113 d2.addCallback(self._testShellCommand1_2, c) | |
| 114 return d2 | |
| 115 testShellCommand1.timeout = 10 | |
| 116 | |
| 117 def poll(self, ignored=None): | |
| 118 # TODO: This is gross, but at least it's no longer using | |
| 119 # reactor.iterate() . Still, get rid of this some day soon. | |
| 120 if self.remote.remoteCalls == 0: | |
| 121 d = defer.Deferred() | |
| 122 d.addCallback(self.poll) | |
| 123 reactor.callLater(0.1, d.callback, None) | |
| 124 return d | |
| 125 return defer.succeed(None) | |
| 126 | |
| 127 def _testShellCommand1_2(self, res, c): | |
| 128 rc = c.rc | |
| 129 self.expectedEvents.append(["callRemote", "startCommand", | |
| 130 (rc, "3", | |
| 131 "shell", | |
| 132 {'command': "argle bargle", | |
| 133 'workdir': "murkle", | |
| 134 'logEnviron' : True, | |
| 135 'want_stdout': 1, | |
| 136 'want_stderr': 1, | |
| 137 'logfiles': {}, | |
| 138 'timeout': 10, | |
| 139 'maxTime': None, | |
| 140 'usePTY': 'slave-config', | |
| 141 'env': None}) ] ) | |
| 142 self.assertEqual(self.remote.events, self.expectedEvents) | |
| 143 | |
| 144 # we could do self.remote.deferred.errback(UnknownCommand) here. We | |
| 145 # could also do .callback(), but generally the master end silently | |
| 146 # ignores the slave's ack | |
| 147 | |
| 148 logs = c.step_status.getLogs() | |
| 149 for log in logs: | |
| 150 if log.getName() == "log": | |
| 151 break | |
| 152 | |
| 153 rc.remoteUpdate({'header': | |
| 154 "command 'argle bargle' in dir 'murkle'\n\n"}) | |
| 155 rc.remoteUpdate({'stdout': "foo\n"}) | |
| 156 self.assertEqual(log.getText(), "foo\n") | |
| 157 self.assertEqual(log.getTextWithHeaders(), | |
| 158 "command 'argle bargle' in dir 'murkle'\n\n" | |
| 159 "foo\n") | |
| 160 rc.remoteUpdate({'stderr': "bar\n"}) | |
| 161 self.assertEqual(log.getText(), "foo\nbar\n") | |
| 162 self.assertEqual(log.getTextWithHeaders(), | |
| 163 "command 'argle bargle' in dir 'murkle'\n\n" | |
| 164 "foo\nbar\n") | |
| 165 rc.remoteUpdate({'rc': 0}) | |
| 166 self.assertEqual(rc.rc, 0) | |
| 167 | |
| 168 rc.remote_complete() | |
| 169 # that should fire the Deferred | |
| 170 d = self.poll2() | |
| 171 d.addCallback(self._testShellCommand1_3) | |
| 172 return d | |
| 173 | |
| 174 def poll2(self, ignored=None): | |
| 175 if not self.finished: | |
| 176 d = defer.Deferred() | |
| 177 d.addCallback(self.poll2) | |
| 178 reactor.callLater(0.1, d.callback, None) | |
| 179 return d | |
| 180 return defer.succeed(None) | |
| 181 | |
| 182 def _testShellCommand1_3(self, res): | |
| 183 self.assertEqual(self.failed, 0) | |
| 184 self.assertEqual(self.results, 0) | |
| 185 | |
| 186 | |
| 187 class MyObserver(buildstep.LogObserver): | |
| 188 out = "" | |
| 189 def outReceived(self, data): | |
| 190 self.out = self.out + data | |
| 191 | |
| 192 class Steps(unittest.TestCase): | |
| 193 def testMultipleStepInstances(self): | |
| 194 steps = [ | |
| 195 (source.CVS, {'cvsroot': "root", 'cvsmodule': "module"}), | |
| 196 (shell.Configure, {'command': "./configure"}), | |
| 197 (shell.Compile, {'command': "make"}), | |
| 198 (shell.Compile, {'command': "make more"}), | |
| 199 (shell.Compile, {'command': "make evenmore"}), | |
| 200 (shell.Test, {'command': "make test"}), | |
| 201 (shell.Test, {'command': "make testharder"}), | |
| 202 ] | |
| 203 f = factory.ConfigurableBuildFactory(steps) | |
| 204 req = base.BuildRequest("reason", SourceStamp(), 'test_builder') | |
| 205 b = f.newBuild([req]) | |
| 206 #for s in b.steps: print s.name | |
| 207 | |
| 208 def failUnlessClones(self, s1, attrnames): | |
| 209 f1 = s1.getStepFactory() | |
| 210 f,args = f1 | |
| 211 s2 = f(**args) | |
| 212 for name in attrnames: | |
| 213 self.failUnlessEqual(getattr(s1, name), getattr(s2, name)) | |
| 214 | |
| 215 def clone(self, s1): | |
| 216 f1 = s1.getStepFactory() | |
| 217 f,args = f1 | |
| 218 s2 = f(**args) | |
| 219 return s2 | |
| 220 | |
| 221 def testClone(self): | |
| 222 s1 = shell.ShellCommand(command=["make", "test"], | |
| 223 timeout=1234, | |
| 224 workdir="here", | |
| 225 description="yo", | |
| 226 descriptionDone="yoyo", | |
| 227 env={'key': 'value'}, | |
| 228 want_stdout=False, | |
| 229 want_stderr=False, | |
| 230 logfiles={"name": "filename"}, | |
| 231 ) | |
| 232 shellparms = (buildstep.BuildStep.parms + | |
| 233 ("remote_kwargs description descriptionDone " | |
| 234 "command logfiles").split() ) | |
| 235 self.failUnlessClones(s1, shellparms) | |
| 236 | |
| 237 | |
| 238 # test the various methods available to buildsteps | |
| 239 | |
| 240 def test_getProperty(self): | |
| 241 s = makeBuildStep("test_steps.Steps.test_getProperty") | |
| 242 bs = s.step_status.getBuild() | |
| 243 | |
| 244 s.setProperty("prop1", "value1", "test") | |
| 245 s.setProperty("prop2", "value2", "test") | |
| 246 self.failUnlessEqual(s.getProperty("prop1"), "value1") | |
| 247 self.failUnlessEqual(bs.getProperty("prop1"), "value1") | |
| 248 self.failUnlessEqual(s.getProperty("prop2"), "value2") | |
| 249 self.failUnlessEqual(bs.getProperty("prop2"), "value2") | |
| 250 s.setProperty("prop1", "value1a", "test") | |
| 251 self.failUnlessEqual(s.getProperty("prop1"), "value1a") | |
| 252 self.failUnlessEqual(bs.getProperty("prop1"), "value1a") | |
| 253 | |
| 254 | |
| 255 def test_addURL(self): | |
| 256 s = makeBuildStep("test_steps.Steps.test_addURL") | |
| 257 s.addURL("coverage", "http://coverage.example.org/target") | |
| 258 s.addURL("icon", "http://coverage.example.org/icon.png") | |
| 259 bs = s.step_status | |
| 260 links = bs.getURLs() | |
| 261 expected = {"coverage": "http://coverage.example.org/target", | |
| 262 "icon": "http://coverage.example.org/icon.png", | |
| 263 } | |
| 264 self.failUnlessEqual(links, expected) | |
| 265 | |
| 266 def test_addLog(self): | |
| 267 s = makeBuildStep("test_steps.Steps.test_addLog") | |
| 268 l = s.addLog("newlog") | |
| 269 l.addStdout("some stdout here") | |
| 270 l.finish() | |
| 271 bs = s.step_status | |
| 272 logs = bs.getLogs() | |
| 273 self.failUnlessEqual(len(logs), 1) | |
| 274 l1 = logs[0] | |
| 275 self.failUnlessEqual(l1.getText(), "some stdout here") | |
| 276 l1a = s.getLog("newlog") | |
| 277 self.failUnlessEqual(l1a.getText(), "some stdout here") | |
| 278 | |
| 279 def test_addHTMLLog(self): | |
| 280 s = makeBuildStep("test_steps.Steps.test_addHTMLLog") | |
| 281 l = s.addHTMLLog("newlog", "some html here") | |
| 282 bs = s.step_status | |
| 283 logs = bs.getLogs() | |
| 284 self.failUnlessEqual(len(logs), 1) | |
| 285 l1 = logs[0] | |
| 286 self.failUnless(isinstance(l1, builder.HTMLLogFile)) | |
| 287 self.failUnlessEqual(l1.getText(), "some html here") | |
| 288 | |
| 289 def test_addCompleteLog(self): | |
| 290 s = makeBuildStep("test_steps.Steps.test_addCompleteLog") | |
| 291 l = s.addCompleteLog("newlog", "some stdout here") | |
| 292 bs = s.step_status | |
| 293 logs = bs.getLogs() | |
| 294 self.failUnlessEqual(len(logs), 1) | |
| 295 l1 = logs[0] | |
| 296 self.failUnlessEqual(l1.getText(), "some stdout here") | |
| 297 l1a = s.getLog("newlog") | |
| 298 self.failUnlessEqual(l1a.getText(), "some stdout here") | |
| 299 | |
| 300 def test_addLogObserver(self): | |
| 301 s = makeBuildStep("test_steps.Steps.test_addLogObserver") | |
| 302 bss = s.step_status | |
| 303 o1,o2,o3 = MyObserver(), MyObserver(), MyObserver() | |
| 304 | |
| 305 # add the log before the observer | |
| 306 l1 = s.addLog("one") | |
| 307 l1.addStdout("onestuff") | |
| 308 s.addLogObserver("one", o1) | |
| 309 self.failUnlessEqual(o1.out, "onestuff") | |
| 310 l1.addStdout(" morestuff") | |
| 311 self.failUnlessEqual(o1.out, "onestuff morestuff") | |
| 312 | |
| 313 # add the observer before the log | |
| 314 s.addLogObserver("two", o2) | |
| 315 l2 = s.addLog("two") | |
| 316 l2.addStdout("twostuff") | |
| 317 self.failUnlessEqual(o2.out, "twostuff") | |
| 318 | |
| 319 # test more stuff about ShellCommands | |
| 320 | |
| 321 def test_description(self): | |
| 322 s = makeBuildStep("test_steps.Steps.test_description.1", | |
| 323 step_class=shell.ShellCommand, | |
| 324 workdir="dummy", | |
| 325 description=["list", "of", "strings"], | |
| 326 descriptionDone=["another", "list"]) | |
| 327 self.failUnlessEqual(s.description, ["list", "of", "strings"]) | |
| 328 self.failUnlessEqual(s.descriptionDone, ["another", "list"]) | |
| 329 | |
| 330 s = makeBuildStep("test_steps.Steps.test_description.2", | |
| 331 step_class=shell.ShellCommand, | |
| 332 workdir="dummy", | |
| 333 description="single string", | |
| 334 descriptionDone="another string") | |
| 335 self.failUnlessEqual(s.description, ["single string"]) | |
| 336 self.failUnlessEqual(s.descriptionDone, ["another string"]) | |
| 337 | |
| 338 class VersionCheckingStep(buildstep.BuildStep): | |
| 339 def start(self): | |
| 340 # give our test a chance to run. It is non-trivial for a buildstep to | |
| 341 # claw its way back out to the test case which is currently running. | |
| 342 master = self.build.builder.botmaster.parent | |
| 343 checker = master._checker | |
| 344 checker(self) | |
| 345 # then complete | |
| 346 self.finished(buildstep.SUCCESS) | |
| 347 | |
| 348 version_config = """ | |
| 349 from buildbot.process import factory | |
| 350 from buildbot.test.test_steps import VersionCheckingStep | |
| 351 from buildbot.buildslave import BuildSlave | |
| 352 from buildbot.config import BuilderConfig | |
| 353 BuildmasterConfig = c = {} | |
| 354 f1 = factory.BuildFactory([ | |
| 355 factory.s(VersionCheckingStep), | |
| 356 ]) | |
| 357 c['slaves'] = [BuildSlave('bot1', 'sekrit')] | |
| 358 c['schedulers'] = [] | |
| 359 c['builders'] = [ | |
| 360 BuilderConfig(name='quick', slavename='bot1', factory=f1, | |
| 361 builddir='quickdir', slavebuilddir='quickslavedir'), | |
| 362 ] | |
| 363 c['slavePortnum'] = 0 | |
| 364 """ | |
| 365 | |
| 366 class SlaveVersion(RunMixin, unittest.TestCase): | |
| 367 def setUp(self): | |
| 368 RunMixin.setUp(self) | |
| 369 self.master.loadConfig(version_config) | |
| 370 self.master.startService() | |
| 371 d = self.connectSlave(["quick"]) | |
| 372 return d | |
| 373 | |
| 374 def doBuild(self, buildername): | |
| 375 br = base.BuildRequest("forced", SourceStamp(), 'test_builder') | |
| 376 d = br.waitUntilFinished() | |
| 377 self.control.getBuilder(buildername).requestBuild(br) | |
| 378 return d | |
| 379 | |
| 380 | |
| 381 def checkCompare(self, s): | |
| 382 cver = commands.command_version | |
| 383 v = s.slaveVersion("svn", None) | |
| 384 # this insures that we are getting the version correctly | |
| 385 self.failUnlessEqual(s.slaveVersion("svn", None), cver) | |
| 386 # and that non-existent commands do not provide a version | |
| 387 self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND"), None) | |
| 388 # TODO: verify that a <=0.5.0 buildslave (which does not implement | |
| 389 # remote_getCommands) handles oldversion= properly. This requires a | |
| 390 # mutant slave which does not offer that method. | |
| 391 #self.failUnlessEqual(s.slaveVersion("NOSUCHCOMMAND", "old"), "old") | |
| 392 | |
| 393 # now check the comparison functions | |
| 394 self.failIf(s.slaveVersionIsOlderThan("svn", cver)) | |
| 395 self.failIf(s.slaveVersionIsOlderThan("svn", "1.1")) | |
| 396 self.failUnless(s.slaveVersionIsOlderThan("svn", cver + ".1")) | |
| 397 | |
| 398 self.failUnlessEqual(s.getSlaveName(), "bot1") | |
| 399 | |
| 400 def testCompare(self): | |
| 401 self.master._checker = self.checkCompare | |
| 402 d = self.doBuild("quick") | |
| 403 return d | |
| 404 | |
| 405 | |
| 406 class _SimpleBuildStep(buildstep.BuildStep): | |
| 407 def start(self): | |
| 408 args = {"arg1": "value"} | |
| 409 cmd = buildstep.RemoteCommand("simple", args) | |
| 410 d = self.runCommand(cmd) | |
| 411 d.addCallback(lambda res: self.finished(SUCCESS)) | |
| 412 | |
| 413 class _SimpleCommand(commands.Command): | |
| 414 def start(self): | |
| 415 self.builder.flag = True | |
| 416 self.builder.flag_args = self.args | |
| 417 return defer.succeed(None) | |
| 418 | |
| 419 class CheckStepTester(StepTester, unittest.TestCase): | |
| 420 def testSimple(self): | |
| 421 self.slavebase = "testSimple.slave" | |
| 422 self.masterbase = "testSimple.master" | |
| 423 sb = self.makeSlaveBuilder() | |
| 424 sb.flag = False | |
| 425 registry.registerSlaveCommand("simple", _SimpleCommand, "1") | |
| 426 step = self.makeStep(_SimpleBuildStep) | |
| 427 d = self.runStep(step) | |
| 428 def _checkSimple(results): | |
| 429 self.failUnless(sb.flag) | |
| 430 self.failUnlessEqual(sb.flag_args, {"arg1": "value"}) | |
| 431 d.addCallback(_checkSimple) | |
| 432 return d | |
| 433 | |
| 434 class Python(StepTester, unittest.TestCase): | |
| 435 def testPyFlakes1(self): | |
| 436 self.masterbase = "Python.testPyFlakes1" | |
| 437 step = self.makeStep(python.PyFlakes) | |
| 438 output = \ | |
| 439 """pyflakes buildbot | |
| 440 buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused | |
| 441 buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 | |
| 442 buildbot/clients/debug.py:9: 'gnome' imported but unused | |
| 443 buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 | |
| 444 buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 | |
| 445 buildbot/scripts/imaginary.py:12: undefined name 'size' | |
| 446 buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detec
t undefined names | |
| 447 """ | |
| 448 log = step.addLog("stdio") | |
| 449 log.addStdout(output) | |
| 450 log.finish() | |
| 451 step.createSummary(log) | |
| 452 desc = step.descriptionDone | |
| 453 self.failUnless("unused=2" in desc) | |
| 454 self.failUnless("undefined=1" in desc) | |
| 455 self.failUnless("redefs=3" in desc) | |
| 456 self.failUnless("import*=1" in desc) | |
| 457 self.failIf("misc=" in desc) | |
| 458 | |
| 459 self.failUnlessEqual(step.getProperty("pyflakes-unused"), 2) | |
| 460 self.failUnlessEqual(step.getProperty("pyflakes-undefined"), 1) | |
| 461 self.failUnlessEqual(step.getProperty("pyflakes-redefs"), 3) | |
| 462 self.failUnlessEqual(step.getProperty("pyflakes-import*"), 1) | |
| 463 self.failUnlessEqual(step.getProperty("pyflakes-misc"), 0) | |
| 464 self.failUnlessEqual(step.getProperty("pyflakes-total"), 7) | |
| 465 | |
| 466 logs = {} | |
| 467 for log in step.step_status.getLogs(): | |
| 468 logs[log.getName()] = log | |
| 469 | |
| 470 for name in ["unused", "undefined", "redefs", "import*"]: | |
| 471 self.failUnless(name in logs) | |
| 472 self.failIf("misc" in logs) | |
| 473 lines = logs["unused"].readlines() | |
| 474 self.failUnlessEqual(len(lines), 2) | |
| 475 self.failUnlessEqual(lines[0], "buildbot/changes/freshcvsmail.py:5: 'FCM
aildirSource' imported but unused\n") | |
| 476 | |
| 477 cmd = buildstep.RemoteCommand(None, {}) | |
| 478 cmd.rc = 0 | |
| 479 results = step.evaluateCommand(cmd) | |
| 480 self.failUnlessEqual(results, FAILURE) # because of the 'undefined' | |
| 481 | |
| 482 def testPyFlakes2(self): | |
| 483 self.masterbase = "Python.testPyFlakes2" | |
| 484 step = self.makeStep(python.PyFlakes) | |
| 485 output = \ | |
| 486 """pyflakes buildbot | |
| 487 some more text here that should be ignored | |
| 488 buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused | |
| 489 buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 | |
| 490 buildbot/clients/debug.py:9: 'gnome' imported but unused | |
| 491 buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 | |
| 492 buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 | |
| 493 buildbot/scripts/imaginary.py:12: undefined name 'size' | |
| 494 could not compile 'blah/blah.py':3: | |
| 495 pretend there was an invalid line here | |
| 496 buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detec
t undefined names | |
| 497 """ | |
| 498 log = step.addLog("stdio") | |
| 499 log.addStdout(output) | |
| 500 log.finish() | |
| 501 step.createSummary(log) | |
| 502 desc = step.descriptionDone | |
| 503 self.failUnless("unused=2" in desc) | |
| 504 self.failUnless("undefined=1" in desc) | |
| 505 self.failUnless("redefs=3" in desc) | |
| 506 self.failUnless("import*=1" in desc) | |
| 507 self.failUnless("misc=2" in desc) | |
| 508 | |
| 509 | |
| 510 def testPyFlakes3(self): | |
| 511 self.masterbase = "Python.testPyFlakes3" | |
| 512 step = self.makeStep(python.PyFlakes) | |
| 513 output = \ | |
| 514 """buildbot/changes/freshcvsmail.py:5: 'FCMaildirSource' imported but unused | |
| 515 buildbot/clients/debug.py:9: redefinition of unused 'gtk' from line 9 | |
| 516 buildbot/clients/debug.py:9: 'gnome' imported but unused | |
| 517 buildbot/scripts/runner.py:323: redefinition of unused 'run' from line 321 | |
| 518 buildbot/scripts/runner.py:325: redefinition of unused 'run' from line 323 | |
| 519 buildbot/scripts/imaginary.py:12: undefined name 'size' | |
| 520 buildbot/scripts/imaginary.py:18: 'from buildbot import *' used; unable to detec
t undefined names | |
| 521 """ | |
| 522 log = step.addLog("stdio") | |
| 523 log.addStdout(output) | |
| 524 log.finish() | |
| 525 step.createSummary(log) | |
| 526 desc = step.descriptionDone | |
| 527 self.failUnless("unused=2" in desc) | |
| 528 self.failUnless("undefined=1" in desc) | |
| 529 self.failUnless("redefs=3" in desc) | |
| 530 self.failUnless("import*=1" in desc) | |
| 531 self.failIf("misc" in desc) | |
| 532 | |
| 533 | |
| 534 class OrdinaryCompile(shell.Compile): | |
| 535 warningPattern = "ordinary line" | |
| 536 | |
| 537 class Warnings(StepTester, unittest.TestCase): | |
| 538 def testCompile1(self): | |
| 539 self.masterbase = "Warnings.testCompile1" | |
| 540 step = self.makeStep(shell.Compile) | |
| 541 output = \ | |
| 542 """Compile started | |
| 543 normal line | |
| 544 warning: oh noes! | |
| 545 ordinary line | |
| 546 error (but we aren't looking for errors now, are we) | |
| 547 line 23: warning: we are now on line 23 | |
| 548 ending line | |
| 549 """ | |
| 550 log = step.addLog("stdio") | |
| 551 log.addStdout(output) | |
| 552 log.finish() | |
| 553 step.createSummary(log) | |
| 554 self.failUnlessEqual(step.getProperty("warnings-count"), 2) | |
| 555 logs = {} | |
| 556 for log in step.step_status.getLogs(): | |
| 557 logs[log.getName()] = log | |
| 558 self.failUnless("warnings" in logs) | |
| 559 lines = logs["warnings"].readlines() | |
| 560 self.failUnlessEqual(len(lines), 2) | |
| 561 self.failUnlessEqual(lines[0], "warning: oh noes!\n") | |
| 562 self.failUnlessEqual(lines[1], | |
| 563 "line 23: warning: we are now on line 23\n") | |
| 564 | |
| 565 cmd = buildstep.RemoteCommand(None, {}) | |
| 566 cmd.rc = 0 | |
| 567 results = step.evaluateCommand(cmd) | |
| 568 self.failUnlessEqual(results, WARNINGS) | |
| 569 | |
| 570 def testCompile2(self): | |
| 571 self.masterbase = "Warnings.testCompile2" | |
| 572 step = self.makeStep(shell.Compile, warningPattern="ordinary line") | |
| 573 output = \ | |
| 574 """Compile started | |
| 575 normal line | |
| 576 warning: oh noes! | |
| 577 ordinary line | |
| 578 error (but we aren't looking for errors now, are we) | |
| 579 line 23: warning: we are now on line 23 | |
| 580 ending line | |
| 581 """ | |
| 582 log = step.addLog("stdio") | |
| 583 log.addStdout(output) | |
| 584 log.finish() | |
| 585 step.createSummary(log) | |
| 586 self.failUnlessEqual(step.getProperty("warnings-count"), 1) | |
| 587 logs = {} | |
| 588 for log in step.step_status.getLogs(): | |
| 589 logs[log.getName()] = log | |
| 590 self.failUnless("warnings" in logs) | |
| 591 lines = logs["warnings"].readlines() | |
| 592 self.failUnlessEqual(len(lines), 1) | |
| 593 self.failUnlessEqual(lines[0], "ordinary line\n") | |
| 594 | |
| 595 cmd = buildstep.RemoteCommand(None, {}) | |
| 596 cmd.rc = 0 | |
| 597 results = step.evaluateCommand(cmd) | |
| 598 self.failUnlessEqual(results, WARNINGS) | |
| 599 | |
| 600 def testCompile3(self): | |
| 601 self.masterbase = "Warnings.testCompile3" | |
| 602 step = self.makeStep(OrdinaryCompile) | |
| 603 output = \ | |
| 604 """Compile started | |
| 605 normal line | |
| 606 warning: oh noes! | |
| 607 ordinary line | |
| 608 error (but we aren't looking for errors now, are we) | |
| 609 line 23: warning: we are now on line 23 | |
| 610 ending line | |
| 611 """ | |
| 612 step.setProperty("warnings-count", 10, "test") | |
| 613 log = step.addLog("stdio") | |
| 614 log.addStdout(output) | |
| 615 log.finish() | |
| 616 step.createSummary(log) | |
| 617 self.failUnlessEqual(step.getProperty("warnings-count"), 11) | |
| 618 logs = {} | |
| 619 for log in step.step_status.getLogs(): | |
| 620 logs[log.getName()] = log | |
| 621 self.failUnless("warnings" in logs) | |
| 622 lines = logs["warnings"].readlines() | |
| 623 self.failUnlessEqual(len(lines), 1) | |
| 624 self.failUnlessEqual(lines[0], "ordinary line\n") | |
| 625 | |
| 626 cmd = buildstep.RemoteCommand(None, {}) | |
| 627 cmd.rc = 0 | |
| 628 results = step.evaluateCommand(cmd) | |
| 629 self.failUnlessEqual(results, WARNINGS) | |
| 630 | |
| 631 def testCompile4(self): | |
| 632 # Test suppression of warnings. | |
| 633 self.masterbase = "Warnings.testCompile4" | |
| 634 step = self.makeStep(shell.Compile, | |
| 635 warningPattern="^(.*?):([0-9]+): [Ww]arning: (.*)$"
, | |
| 636 warningExtractor=shell.Compile.warnExtractFromRegex
pGroups, | |
| 637 directoryEnterPattern="make.*: Entering directory [
\"`'](.*)['`\"]", | |
| 638 directoryLeavePattern="make.*: Leaving directory") | |
| 639 step.addSuppression([(r"/subdir/", r"xyzzy", None, None), | |
| 640 (r"foo.c", r".*", None, 20), | |
| 641 (r"foo.c", r".*", 200, None), | |
| 642 (r"foo.c", r".*", 50, 50), | |
| 643 (r"xxx", r".*", None, None), | |
| 644 ]) | |
| 645 log = step.addLog("stdio") | |
| 646 output = \ | |
| 647 """Making all in . | |
| 648 make[1]: Entering directory `/abs/path/build' | |
| 649 foo.c:10: warning: `bar' defined but not used | |
| 650 foo.c:50: warning: `bar' defined but not used | |
| 651 make[2]: Entering directory `/abs/path/build/subdir' | |
| 652 baz.c:33: warning: `xyzzy' defined but not used | |
| 653 baz.c:34: warning: `magic' defined but not used | |
| 654 make[2]: Leaving directory `/abs/path/build/subdir' | |
| 655 foo.c:100: warning: `xyzzy' defined but not used | |
| 656 foo.c:200: warning: `bar' defined but not used | |
| 657 make[2]: Leaving directory `/abs/path/build' | |
| 658 """ | |
| 659 log.addStdout(output) | |
| 660 log.finish() | |
| 661 step.createSummary(log) | |
| 662 self.failUnlessEqual(step.getProperty("warnings-count"), 2) | |
| 663 logs = {} | |
| 664 for log in step.step_status.getLogs(): | |
| 665 logs[log.getName()] = log | |
| 666 self.failUnless("warnings" in logs) | |
| 667 lines = logs["warnings"].readlines() | |
| 668 self.failUnlessEqual(len(lines), 2) | |
| 669 self.failUnlessEqual(lines[0], "baz.c:34: warning: `magic' defined but n
ot used\n") | |
| 670 self.failUnlessEqual(lines[1], "foo.c:100: warning: `xyzzy' defined but
not used\n") | |
| 671 | |
| 672 cmd = buildstep.RemoteCommand(None, {}) | |
| 673 cmd.rc = 0 | |
| 674 results = step.evaluateCommand(cmd) | |
| 675 self.failUnlessEqual(results, WARNINGS) | |
| 676 | |
| 677 def filterArgs(self, args): | |
| 678 if "writer" in args: | |
| 679 args["writer"] = self.wrap(args["writer"]) | |
| 680 return args | |
| 681 | |
| 682 suppressionFileData = """ | |
| 683 # Sample suppressions file for testing | |
| 684 | |
| 685 /subdir/ : xyzzy | |
| 686 foo.c: .* : 0-20 | |
| 687 foo.c: .*: 200-10000 | |
| 688 foo.c :.*: 50 | |
| 689 xxx : .* | |
| 690 """ | |
| 691 def testCompile5(self): | |
| 692 # Test downloading warning suppression file from slave. | |
| 693 self.slavebase = "Warnings.testCompile5.slave" | |
| 694 self.masterbase = "Warnings.testCompile5.master" | |
| 695 sb = self.makeSlaveBuilder() | |
| 696 os.mkdir(os.path.join(self.slavebase, self.slavebuilderbase, | |
| 697 "build")) | |
| 698 output = \ | |
| 699 """Making all in . | |
| 700 make[1]: Entering directory `/abs/path/build' | |
| 701 foo.c:10: warning: `bar' defined but not used | |
| 702 foo.c:50: warning: `bar' defined but not used | |
| 703 make[2]: Entering directory `/abs/path/build/subdir' | |
| 704 baz.c:33: warning: `xyzzy' defined but not used | |
| 705 baz.c:34: warning: `magic' defined but not used | |
| 706 make[2]: Leaving directory `/abs/path/build/subdir' | |
| 707 foo.c:100: warning: `xyzzy' defined but not used | |
| 708 foo.c:200: warning: `bar' defined but not used | |
| 709 make[2]: Leaving directory `/abs/path/build' | |
| 710 """ | |
| 711 printStatement = ('print """%s"""' % output) | |
| 712 step = self.makeStep(shell.Compile, | |
| 713 warningPattern="^(.*?):([0-9]+): [Ww]arning: (.*)$"
, | |
| 714 warningExtractor=shell.Compile.warnExtractFromRegex
pGroups, | |
| 715 suppressionFile="warnings.supp", | |
| 716 command=[sys.executable, "-c", printStatement]) | |
| 717 self.failUnlessEqual(step.step_status.getText(), ['compiling']) | |
| 718 slavesrc = os.path.join(self.slavebase, | |
| 719 self.slavebuilderbase, | |
| 720 "build", | |
| 721 "warnings.supp") | |
| 722 open(slavesrc, "w").write(self.suppressionFileData) | |
| 723 | |
| 724 d = self.runStep(step) | |
| 725 def _checkResult(result): | |
| 726 self.failUnlessEqual(step.getProperty("warnings-count"), 2) | |
| 727 logs = {} | |
| 728 for log in step.step_status.getLogs(): | |
| 729 logs[log.getName()] = log | |
| 730 self.failUnless("warnings" in logs) | |
| 731 lines = logs["warnings"].readlines() | |
| 732 self.failUnlessEqual(len(lines), 2) | |
| 733 self.failUnlessEqual(lines[0], "baz.c:34: warning: `magic' defined b
ut not used\n") | |
| 734 self.failUnlessEqual(lines[1], "foo.c:100: warning: `xyzzy' defined
but not used\n") | |
| 735 self.failUnlessEqual(step.step_status.getText(), ['compile', | |
| 736 'warnings']) | |
| 737 | |
| 738 d.addCallback(_checkResult) | |
| 739 return d | |
| 740 | |
| 741 class TreeSize(StepTester, unittest.TestCase): | |
| 742 def testTreeSize(self): | |
| 743 self.slavebase = "TreeSize.testTreeSize.slave" | |
| 744 self.masterbase = "TreeSize.testTreeSize.master" | |
| 745 | |
| 746 sb = self.makeSlaveBuilder() | |
| 747 step = self.makeStep(shell.TreeSize) | |
| 748 d = self.runStep(step) | |
| 749 def _check(results): | |
| 750 self.failUnlessEqual(results, SUCCESS) | |
| 751 kib = step.getProperty("tree-size-KiB") | |
| 752 self.failUnless(isinstance(kib, int)) | |
| 753 self.failUnless(kib < 100) # should be empty, I get '4' | |
| 754 s = step.step_status | |
| 755 self.failUnlessEqual(" ".join(s.getText()), | |
| 756 "treesize %d KiB" % kib) | |
| 757 d.addCallback(_check) | |
| 758 return d | |
| 759 | |
| 760 class FakeCommand: | |
| 761 def __init__(self, rc): | |
| 762 self.rc = rc | |
| 763 | |
| 764 class PerlModuleTest(StepTester, unittest.TestCase): | |
| 765 def testAllTestsPassed(self): | |
| 766 self.masterbase = "PMT.testAllTestsPassed" | |
| 767 step = self.makeStep(shell.PerlModuleTest) | |
| 768 output = \ | |
| 769 """ok 1 | |
| 770 ok 2 | |
| 771 All tests successful | |
| 772 Files=1, Tests=123, other stuff | |
| 773 """ | |
| 774 log = step.addLog("stdio") | |
| 775 log.addStdout(output) | |
| 776 log.finish() | |
| 777 rc = step.evaluateCommand(FakeCommand(rc=241)) | |
| 778 self.failUnlessEqual(rc, SUCCESS) | |
| 779 ss = step.step_status | |
| 780 self.failUnlessEqual(ss.getStatistic('tests-failed'), 0) | |
| 781 self.failUnlessEqual(ss.getStatistic('tests-total'), 123) | |
| 782 self.failUnlessEqual(ss.getStatistic('tests-passed'), 123) | |
| 783 | |
| 784 def testFailures_OldTestHarness(self): | |
| 785 self.masterbase = "PMT.testFailures_OldTestHarness" | |
| 786 step = self.makeStep(shell.PerlModuleTest) | |
| 787 output = \ | |
| 788 """ | |
| 789 ok 1 | |
| 790 ok 2 | |
| 791 3/7 subtests failed | |
| 792 """ | |
| 793 log = step.addLog("stdio") | |
| 794 log.addStdout(output) | |
| 795 log.finish() | |
| 796 rc = step.evaluateCommand(FakeCommand(rc = 123)) | |
| 797 self.failUnlessEqual(rc, FAILURE) | |
| 798 ss = step.step_status | |
| 799 self.failUnlessEqual(ss.getStatistic('tests-failed'), 3) | |
| 800 self.failUnlessEqual(ss.getStatistic('tests-total'), 7) | |
| 801 self.failUnlessEqual(ss.getStatistic('tests-passed'), 4) | |
| 802 | |
| 803 def testFailures_UnparseableStdio(self): | |
| 804 self.masterbase = "PMT.testFailures_UnparseableStdio" | |
| 805 step = self.makeStep(shell.PerlModuleTest) | |
| 806 output = \ | |
| 807 """ | |
| 808 just some random stuff, you know | |
| 809 """ | |
| 810 log = step.addLog("stdio") | |
| 811 log.addStdout(output) | |
| 812 log.finish() | |
| 813 rc = step.evaluateCommand(FakeCommand(rc = 243)) | |
| 814 self.failUnlessEqual(rc, 243) | |
| 815 ss = step.step_status | |
| 816 self.failUnlessEqual(ss.getStatistic('tests-failed'), None) | |
| 817 self.failUnlessEqual(ss.getStatistic('tests-total'), None) | |
| 818 self.failUnlessEqual(ss.getStatistic('tests-passed'), None) | |
| 819 | |
| 820 def testFailures_NewTestHarness(self): | |
| 821 self.masterbase = "PMT.testFailures_NewTestHarness" | |
| 822 step = self.makeStep(shell.PerlModuleTest) | |
| 823 output = \ | |
| 824 """ | |
| 825 # Looks like you failed 15 tests of 18. | |
| 826 tests/services.......................... Failed 265/30904 subtests | |
| 827 (less 16 skipped subtests: 30623 okay) | |
| 828 tests/simple_query_backend..............ok | |
| 829 tests/simple_query_middleware...........ok | |
| 830 tests/soap_globalcollect................ok | |
| 831 tests/three_d_me........................ok | |
| 832 tests/three_d_me_callback...............ok | |
| 833 tests/transaction_create................ok | |
| 834 tests/unique_txid.......................ok | |
| 835 | |
| 836 Test Summary Report | |
| 837 ------------------- | |
| 838 tests/000policies (Wstat: 5632 Tests: 9078 Failed: 22) | |
| 839 Failed tests: 2409, 2896-2897, 2900-2901, 2940-2941, 2944-2945 | |
| 840 2961-2962, 2965-2966, 2969-2970, 2997-2998 | |
| 841 3262, 3281-3282, 3288-3289 | |
| 842 Non-zero exit status: 22 | |
| 843 tests/services (Wstat: 0 Tests: 30904 Failed: 265) | |
| 844 Failed tests: 14, 16-21, 64-69, 71-96, 98, 30157, 30159 | |
| 845 30310, 30316, 30439-30543, 30564, 30566-30577 | |
| 846 30602, 30604-30607, 30609-30612, 30655 | |
| 847 30657-30668, 30675, 30697-30716, 30718-30720 | |
| 848 30722-30736, 30773-30774, 30776-30777, 30786 | |
| 849 30791, 30795, 30797, 30801, 30822-30827 | |
| 850 30830-30831, 30848-30855, 30858-30859, 30888-30899 | |
| 851 30901, 30903-30904 | |
| 852 Files=68, Tests=264809, 1944 wallclock secs (17.59 usr 0.63 sys + 470.04 cusr 1
31.40 csys = 619.66 CPU) | |
| 853 Result: FAIL | |
| 854 """ | |
| 855 log = step.addLog("stdio") | |
| 856 log.addStdout(output) | |
| 857 log.finish() | |
| 858 rc = step.evaluateCommand(FakeCommand(rc=87)) | |
| 859 self.failUnlessEqual(rc, FAILURE) | |
| 860 ss = step.step_status | |
| 861 self.failUnlessEqual(ss.getStatistic('tests-failed'), 287) | |
| 862 self.failUnlessEqual(ss.getStatistic('tests-total'), 264809) | |
| 863 self.failUnlessEqual(ss.getStatistic('tests-passed'), 264522) | |
| 864 | |
| 865 class MasterShellCommand(StepTester, unittest.TestCase): | |
| 866 def testMasterShellCommand(self): | |
| 867 self.slavebase = "testMasterShellCommand.slave" | |
| 868 self.masterbase = "testMasterShellCommand.master" | |
| 869 sb = self.makeSlaveBuilder() | |
| 870 step = self.makeStep(master.MasterShellCommand, command=['echo', | |
| 871 WithProperties("hi build-%(other)s.tar.gz")]) | |
| 872 step.build.setProperty("other", "foo", "test") | |
| 873 | |
| 874 # we can't invoke runStep until the reactor is started .. hence this | |
| 875 # little dance | |
| 876 d = defer.Deferred() | |
| 877 def _dotest(_): | |
| 878 return self.runStep(step) | |
| 879 d.addCallback(_dotest) | |
| 880 | |
| 881 def _check(results): | |
| 882 self.failUnlessEqual(results, SUCCESS) | |
| 883 logtxt = step.getLog("stdio").getText() | |
| 884 self.failUnlessEqual(logtxt.strip(), "hi build-foo.tar.gz") | |
| 885 d.addCallback(_check) | |
| 886 reactor.callLater(0, d.callback, None) | |
| 887 return d | |
| 888 | |
| 889 def testMasterShellCommand_badexit(self): | |
| 890 self.slavebase = "testMasterShellCommand_badexit.slave" | |
| 891 self.masterbase = "testMasterShellCommand_badexit.master" | |
| 892 sb = self.makeSlaveBuilder() | |
| 893 step = self.makeStep(master.MasterShellCommand, command="exit 1") | |
| 894 | |
| 895 # we can't invoke runStep until the reactor is started .. hence this | |
| 896 # little dance | |
| 897 d = defer.Deferred() | |
| 898 def _dotest(_): | |
| 899 return self.runStep(step) | |
| 900 d.addCallback(_dotest) | |
| 901 | |
| 902 def _check(results): | |
| 903 self.failUnlessEqual(results, FAILURE) | |
| 904 d.addCallback(_check) | |
| 905 reactor.callLater(0, d.callback, None) | |
| 906 return d | |
| 907 | |
| 908 class SuccessStep(buildstep.BuildStep): | |
| 909 def start(self): | |
| 910 self.finished(buildstep.SUCCESS) | |
| 911 | |
| 912 class ConditionalStepTest(StepTester, unittest.TestCase): | |
| 913 def testNotSkipped(self): | |
| 914 self.slavebase = "testNotSkipped.slave" | |
| 915 self.masterbase = "testNotSkipped.master" | |
| 916 sb = self.makeSlaveBuilder() | |
| 917 step = self.makeStep(SuccessStep) | |
| 918 d = self.runStep(step) | |
| 919 def _checkResults(results): | |
| 920 self.failUnlessEqual(SUCCESS, results) | |
| 921 d.addCallback(_checkResults) | |
| 922 return d | |
| 923 | |
| 924 def testSkipped(self): | |
| 925 self.slavebase = "testSkipped.slave" | |
| 926 self.masterbase = "testSkipped.master" | |
| 927 sb = self.makeSlaveBuilder() | |
| 928 step = self.makeStep(SuccessStep, doStepIf=False) | |
| 929 d = self.runStep(step) | |
| 930 def _checkResults(results): | |
| 931 self.failUnlessEqual(SKIPPED, results) | |
| 932 d.addCallback(_checkResults) | |
| 933 return d | |
| 934 | |
| 935 def testNotSkippedFunc(self): | |
| 936 self.slavebase = "testNotSkippedFunc.slave" | |
| 937 self.masterbase = "testNotSkippedFunc.master" | |
| 938 sb = self.makeSlaveBuilder() | |
| 939 step = self.makeStep(SuccessStep, doStepIf=lambda s: True) | |
| 940 d = self.runStep(step) | |
| 941 def _checkResults(results): | |
| 942 self.failUnlessEqual(SUCCESS, results) | |
| 943 d.addCallback(_checkResults) | |
| 944 return d | |
| 945 | |
| 946 def testSkippedFunc(self): | |
| 947 self.slavebase = "testSkippedFunc.slave" | |
| 948 self.masterbase = "testSkippedFunc.master" | |
| 949 sb = self.makeSlaveBuilder() | |
| 950 step = self.makeStep(SuccessStep, doStepIf=lambda s: False) | |
| 951 d = self.runStep(step) | |
| 952 def _checkResults(results): | |
| 953 self.failUnlessEqual(SKIPPED, results) | |
| 954 d.addCallback(_checkResults) | |
| 955 return d | |
| OLD | NEW |