[Buildbot-commits] buildbot/buildbot/test sleep.py,NONE,1.1 test_slavecommand.py,1.14,1.15
Brian Warner
warner at users.sourceforge.net
Tue Jul 19 01:55:23 UTC 2005
Update of /cvsroot/buildbot/buildbot/buildbot/test
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10106/buildbot/test
Modified Files:
test_slavecommand.py
Added Files:
sleep.py
Log Message:
Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-234
Creator: Brian Warner <warner at monolith.lothar.com>
overhaul ShellCommand timeout/interrupt/cleanup, add tests
* buildbot/slave/commands.py (ShellCommand): overhaul
error-handling code, to try and make timeout/interrupt work
properly, and make win32 happier
* buildbot/test/test_slavecommand.py: clean up, stop using
reactor.iterate, add tests for timeout and interrupt
* buildbot/test/sleep.py: utility for a new timeout test
* buildbot/twcompat.py: copy over twisted 1.3/2.0 compatibility
code from the local-usebranches branch
--- NEW FILE: sleep.py ---
#! /usr/bin/python
import sys, time
delay = int(sys.argv[1])
sys.stdout.write("sleeping for %d seconds\n" % delay)
time.sleep(delay)
sys.stdout.write("woke up\n")
sys.exit(0)
Index: test_slavecommand.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_slavecommand.py,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- test_slavecommand.py 16 May 2005 08:50:23 -0000 1.14
+++ test_slavecommand.py 19 Jul 2005 01:55:20 -0000 1.15
@@ -1,8 +1,9 @@
# -*- test-case-name: buildbot.test.test_slavecommand -*-
from twisted.trial import unittest
-from twisted.internet import reactor, defer
-from twisted.python import util, runtime
+from twisted.internet import reactor
+from twisted.python import util, runtime, failure
+from buildbot.twcompat import maybeWait
noisy = False
if noisy:
@@ -10,10 +11,11 @@
import sys
startLogging(sys.stdout)
-import os, re, time, sys
+import os, re, sys
import signal
-from buildbot.slave.commands import SlaveShellCommand
+from buildbot.slave import commands
+SlaveShellCommand = commands.SlaveShellCommand
# test slavecommand.py by running the various commands with a fake
# SlaveBuilder object that logs the calls to sendUpdate()
@@ -21,28 +23,13 @@
def findDir():
# the same directory that holds this script
return util.sibpath(__file__, ".")
-
-class FakeSlaveBuild:
- pass
class FakeSlaveBuilder:
- def __init__(self, d, usePTY):
+ def __init__(self, usePTY):
self.updates = []
- self.failure = None
- self.deferred = d
self.basedir = findDir()
self.usePTY = usePTY
- def startBuild(self):
- self.build = FakeSlaveBuild()
- def commandComplete(self, dummy):
- if noisy: print "FakeSlaveBuilder.commandComplete"
- self.completed = 1
- self.deferred.callback(0)
- def commandFailed(self, failure):
- if noisy: print "FakeSlaveBuilder.commandFailed", failure
- self.failure = failure
- self.deferred.callback(1)
def sendUpdate(self, data):
if noisy: print "FakeSlaveBuilder.sendUpdate", data
self.updates.append(data)
@@ -64,40 +51,14 @@
signal.signal(signal.SIGCHLD, self.sigchldHandler)
-class Shell(SignalMixin, unittest.TestCase):
- usePTY = False
+class ShellBase(SignalMixin):
def setUp(self):
- d = defer.Deferred()
- self.builder = FakeSlaveBuilder(d, self.usePTY)
- d.addCallback(self.callback)
- self.failed = None
- self.results = None
-
- def callback(self, failed):
- self.failed = failed
- self.results = self.builder.updates
-
- def doTest(self, commandfactory, args):
- builder = self.builder
- builder.startBuild()
- stepId = None
- cmd = commandfactory(builder, stepId, args)
- d = cmd.start()
- d.addCallbacks(builder.commandComplete, builder.commandFailed)
-
- timeout = time.time() + 2
- while not (self.results or self.failed) and time.time() < timeout:
- reactor.iterate(0.01)
- if not (self.results or self.failed):
- self.fail("timeout")
- if self.failed:
- print self.builder.failure
- return self.failed
+ self.builder = FakeSlaveBuilder(self.usePTY)
def getfile(self, which):
got = ""
- for r in self.results:
+ for r in self.builder.updates:
if r.has_key(which):
got += r[which]
return got
@@ -126,8 +87,8 @@
self.assertEquals(got, contents)
def getrc(self):
- self.failUnless(self.results[-1].has_key('rc'))
- got = self.results[-1]['rc']
+ self.failUnless(self.builder.updates[-1].has_key('rc'))
+ got = self.builder.updates[-1]['rc']
return got
def checkrc(self, expected):
got = self.getrc()
@@ -136,48 +97,69 @@
def testShell1(self):
cmd = sys.executable + " emit.py 0"
args = {'command': cmd, 'workdir': '.', 'timeout': 60}
- failed = self.doTest(SlaveShellCommand, args)
- self.failIf(failed)
- self.checkOutput([('stdout', "this is stdout\n"),
- ('stderr', "this is stderr\n")])
- self.checkrc(0)
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ expected = [('stdout', "this is stdout\n"),
+ ('stderr', "this is stderr\n")]
+ d.addCallback(self._checkPass, expected, 0)
+ return maybeWait(d)
+
+ def _checkPass(self, res, expected, rc):
+ self.checkOutput(expected)
+ self.checkrc(rc)
def testShell2(self):
- cmd = sys.executable + " emit.py 1"
+ cmd = [sys.executable, "emit.py", "0"]
args = {'command': cmd, 'workdir': '.', 'timeout': 60}
- failed = self.doTest(SlaveShellCommand, args)
- self.failIf(failed)
- self.checkOutput([('stdout', "this is stdout\n"),
- ('stderr', "this is stderr\n")])
- self.checkrc(1)
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ expected = [('stdout', "this is stdout\n"),
+ ('stderr', "this is stderr\n")]
+ d.addCallback(self._checkPass, expected, 0)
+ return maybeWait(d)
- def testShell3(self):
+ def testShellRC(self):
+ cmd = [sys.executable, "emit.py", "1"]
+ args = {'command': cmd, 'workdir': '.', 'timeout': 60}
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ expected = [('stdout', "this is stdout\n"),
+ ('stderr', "this is stderr\n")]
+ d.addCallback(self._checkPass, expected, 1)
+ return maybeWait(d)
+
+ def testShellEnv(self):
cmd = sys.executable + " emit.py 0"
args = {'command': cmd, 'workdir': '.',
'env': {'EMIT_TEST': "envtest"}, 'timeout': 60}
- failed = self.doTest(SlaveShellCommand, args)
- self.failIf(failed)
- self.checkOutput([('stdout', "this is stdout\n"),
- ('stderr', "this is stderr\n"),
- ('stdout', "EMIT_TEST: envtest\n"),
- ])
- self.checkrc(0)
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ expected = [('stdout', "this is stdout\n"),
+ ('stderr', "this is stderr\n"),
+ ('stdout', "EMIT_TEST: envtest\n"),
+ ]
+ d.addCallback(self._checkPass, expected, 0)
+ return maybeWait(d)
- def testShell4(self):
+ def testShellSubdir(self):
cmd = sys.executable + " emit.py 0"
args = {'command': cmd, 'workdir': "subdir", 'timeout': 60}
- failed = self.doTest(SlaveShellCommand, args)
- self.failIf(failed)
- self.checkOutput([('stdout', "this is stdout in subdir\n"),
- ('stderr', "this is stderr\n")])
- self.checkrc(0)
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ expected = [('stdout', "this is stdout in subdir\n"),
+ ('stderr', "this is stderr\n")]
+ d.addCallback(self._checkPass, expected, 0)
+ return maybeWait(d)
- def testShellZ(self):
+ def testShellMissingCommand(self):
args = {'command': "/bin/EndWorldHungerAndMakePigsFly",
'workdir': '.', 'timeout': 10}
- failed = self.doTest(SlaveShellCommand, args)
- self.failIf(failed)
- self.failUnless(self.getrc() != 0)
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ d.addCallback(self._testShellMissingCommand_1)
+ return maybeWait(d)
+ def _testShellMissingCommand_1(self, res):
+ self.failIfEqual(self.getrc(), 0)
got = self.getfile('stdout') + self.getfile('stderr')
self.failUnless(re.search(r'no such file', got, re.I) # unix
or re.search(r'cannot find the path specified',
@@ -188,12 +170,89 @@
"message, got '%s'" % got
)
- # todo: interrupt(), kill process
+ def testTimeout(self):
+ args = {'command': [sys.executable, "sleep.py", "10"],
+ 'workdir': '.', 'timeout': 2}
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ d.addCallback(self._testTimeout_1)
+ return maybeWait(d)
+ def _testTimeout_1(self, res):
+ self.failIfEqual(self.getrc(), 0)
+ got = self.getfile('header')
+ self.failUnlessIn("command timed out: 2 seconds without output", got)
+ if runtime.platformType == "posix":
+ # the "killing pid" message is not present in windows
+ self.failUnlessIn("killing pid", got)
+ # but the process *ought* to be killed somehow
+ self.failUnlessIn("process killed by signal", got)
+ #print got
+ if runtime.platformType != 'posix':
+ testTimeout.todo = "timeout doesn't appear to work under windows"
+
+ def testInterrupt1(self):
+ args = {'command': [sys.executable, "sleep.py", "10"],
+ 'workdir': '.', 'timeout': 20}
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ reactor.callLater(1, c.interrupt)
+ d.addCallback(self._testInterrupt1_1)
+ return maybeWait(d)
+ def _testInterrupt1_1(self, res):
+ self.failIfEqual(self.getrc(), 0)
+ got = self.getfile('header')
+ self.failUnlessIn("command interrupted", got)
+ if runtime.platformType == "posix":
+ self.failUnlessIn("process killed by signal", got)
+
# todo: twisted-specific command tests
+class Shell(ShellBase, unittest.TestCase):
+ usePTY = False
+
+ def testInterrupt2(self):
+ # test the backup timeout. This doesn't work under a PTY, because the
+ # transport.loseConnection we do in the timeout handler actually
+ # *does* kill the process.
+ args = {'command': [sys.executable, "sleep.py", "5"],
+ 'workdir': '.', 'timeout': 20}
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ c.command.BACKUP_TIMEOUT = 1
+ # make it unable to kill the child, by changing the signal it uses
+ # from SIGKILL to the do-nothing signal 0.
+ c.command.KILL = None
+ reactor.callLater(1, c.interrupt)
+ d.addBoth(self._testInterrupt2_1)
+ return maybeWait(d)
+ def _testInterrupt2_1(self, res):
+ # the slave should raise a TimeoutError exception. In a normal build
+ # process (i.e. one that uses step.RemoteShellCommand), this
+ # exception will be handed to the Step, which will acquire an ERROR
+ # status. In our test environment, it isn't such a big deal.
+ self.failUnless(isinstance(res, failure.Failure),
+ "res is not a Failure: %s" % (res,))
+ self.failUnless(res.check(commands.TimeoutError))
+ self.checkrc(-1)
+ return
+ # the command is still actually running. Start another command, to
+ # make sure that a) the old command's output doesn't interfere with
+ # the new one, and b) the old command's actual termination doesn't
+ # break anything
+ args = {'command': [sys.executable, "sleep.py", "5"],
+ 'workdir': '.', 'timeout': 20}
+ c = SlaveShellCommand(self.builder, None, args)
+ d = c.start()
+ d.addCallback(self._testInterrupt2_2)
+ return d
+ def _testInterrupt2_2(self, res):
+ self.checkrc(0)
+ # N.B.: under windows, the trial process hangs out for another few
+ # seconds. I assume that the win32eventreactor is waiting for one of
+ # the lingering child processes to really finish.
if runtime.platformType == 'posix':
# test with PTYs also
- class ShellPTY(Shell):
+ class ShellPTY(ShellBase, unittest.TestCase):
usePTY = True
More information about the Commits
mailing list