| OLD | NEW |
| (Empty) |
| 1 | |
| 2 | |
| 3 # test step.ShellCommand and the slave-side commands.ShellCommand | |
| 4 | |
| 5 import sys, time, os | |
| 6 from twisted.trial import unittest | |
| 7 from twisted.internet import reactor, defer | |
| 8 from twisted.python import util | |
| 9 from buildbot.slave.commands import SlaveShellCommand | |
| 10 from buildbot.test.runutils import SlaveCommandTestBase | |
| 11 | |
| 12 class SlaveSide(SlaveCommandTestBase, unittest.TestCase): | |
| 13 def testOne(self): | |
| 14 self.setUpBuilder("test_shell.testOne") | |
| 15 emitcmd = util.sibpath(__file__, "emit.py") | |
| 16 args = { | |
| 17 'command': [sys.executable, emitcmd, "0"], | |
| 18 'workdir': ".", | |
| 19 } | |
| 20 d = self.startCommand(SlaveShellCommand, args) | |
| 21 d.addCallback(self.collectUpdates) | |
| 22 def _check(logs): | |
| 23 self.failUnlessEqual(logs['stdout'], "this is stdout\n") | |
| 24 self.failUnlessEqual(logs['stderr'], "this is stderr\n") | |
| 25 d.addCallback(_check) | |
| 26 return d | |
| 27 | |
| 28 # TODO: move test_slavecommand.Shell and .ShellPTY over here | |
| 29 | |
| 30 def _generateText(self, filename): | |
| 31 lines = [] | |
| 32 for i in range(3): | |
| 33 lines.append("this is %s %d\n" % (filename, i)) | |
| 34 return "".join(lines) | |
| 35 | |
| 36 def testLogFiles_0(self): | |
| 37 return self._testLogFiles(0) | |
| 38 | |
| 39 def testLogFiles_1(self): | |
| 40 return self._testLogFiles(1) | |
| 41 | |
| 42 def testLogFiles_2(self): | |
| 43 return self._testLogFiles(2) | |
| 44 | |
| 45 def testLogFiles_3(self): | |
| 46 return self._testLogFiles(3) | |
| 47 | |
| 48 def _testLogFiles(self, mode): | |
| 49 basedir = "test_shell.testLogFiles" | |
| 50 self.setUpBuilder(basedir) | |
| 51 # emitlogs.py writes two lines to stdout and two logfiles, one second | |
| 52 # apart. Then it waits for us to write something to stdin, then it | |
| 53 # writes one more line. | |
| 54 | |
| 55 if mode != 3: | |
| 56 # we write something to the log file first, to exercise the logic | |
| 57 # that distinguishes between the old file and the one as modified | |
| 58 # by the ShellCommand. We set the timestamp back 5 seconds so | |
| 59 # that timestamps can be used to distinguish old from new. | |
| 60 log2file = os.path.join(basedir, "log2.out") | |
| 61 f = open(log2file, "w") | |
| 62 f.write("dummy text\n") | |
| 63 f.close() | |
| 64 earlier = time.time() - 5 | |
| 65 os.utime(log2file, (earlier, earlier)) | |
| 66 | |
| 67 if mode == 3: | |
| 68 # mode=3 doesn't create the old logfiles in the first place, but | |
| 69 # then behaves like mode=1 (where the command pauses before | |
| 70 # creating them). | |
| 71 mode = 1 | |
| 72 | |
| 73 # mode=1 will cause emitlogs.py to delete the old logfiles first, and | |
| 74 # then wait two seconds before creating the new files. mode=0 does | |
| 75 # not do this. | |
| 76 args = { | |
| 77 'command': [sys.executable, | |
| 78 util.sibpath(__file__, "emitlogs.py"), | |
| 79 "%s" % mode], | |
| 80 'workdir': ".", | |
| 81 'logfiles': {"log2": "log2.out", | |
| 82 "log3": "log3.out"}, | |
| 83 'keep_stdin_open': True, | |
| 84 } | |
| 85 finishd = self.startCommand(SlaveShellCommand, args) | |
| 86 # The first batch of lines is written immediately. The second is | |
| 87 # written after a pause of one second. We poll once per second until | |
| 88 # we see both batches. | |
| 89 | |
| 90 self._check_timeout = 10 | |
| 91 d = self._check_and_wait() | |
| 92 def _wait_for_finish(res, finishd): | |
| 93 return finishd | |
| 94 d.addCallback(_wait_for_finish, finishd) | |
| 95 d.addCallback(self.collectUpdates) | |
| 96 def _check(logs): | |
| 97 self.failUnlessEqual(logs['stdout'], self._generateText("stdout")) | |
| 98 if mode == 2: | |
| 99 self.failIf(('log','log2') in logs) | |
| 100 self.failIf(('log','log3') in logs) | |
| 101 else: | |
| 102 self.failUnlessEqual(logs[('log','log2')], | |
| 103 self._generateText("log2")) | |
| 104 self.failUnlessEqual(logs[('log','log3')], | |
| 105 self._generateText("log3")) | |
| 106 d.addCallback(_check) | |
| 107 d.addBoth(self._maybePrintError) | |
| 108 return d | |
| 109 | |
| 110 def _check_and_wait(self, res=None): | |
| 111 self._check_timeout -= 1 | |
| 112 if self._check_timeout <= 0: | |
| 113 raise defer.TimeoutError("gave up on command") | |
| 114 logs = self.collectUpdates() | |
| 115 if logs.get('stdout') == "this is stdout 0\nthis is stdout 1\n": | |
| 116 # the emitlogs.py process is now waiting for something to arrive | |
| 117 # on stdin | |
| 118 self.cmd.command.pp.transport.write("poke\n") | |
| 119 return | |
| 120 if not self.cmd.running: | |
| 121 self.fail("command finished too early") | |
| 122 spin = defer.Deferred() | |
| 123 spin.addCallback(self._check_and_wait) | |
| 124 reactor.callLater(1, spin.callback, None) | |
| 125 return spin | |
| 126 | |
| 127 def _maybePrintError(self, res): | |
| 128 rc = self.findRC() | |
| 129 if rc != 0: | |
| 130 print "Command ended with rc=%s" % rc | |
| 131 print "STDERR:" | |
| 132 self.printStderr() | |
| 133 return res | |
| 134 | |
| 135 # MAYBE TODO: a command which appends to an existing logfile should | |
| 136 # result in only the new text being sent up to the master. I need to | |
| 137 # think about this more first. | |
| 138 | |
| OLD | NEW |