def testSendBuffered(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand("hello"), self.basedir) s._addToBuffers("stdout", "hello ") s._addToBuffers("stdout", "world") s._sendBuffers() self.failUnlessEqual(b.updates, [{"stdout": "hello world"}], b.show())
def testSendBuffered(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir) s._addToBuffers('stdout', 'hello ') s._addToBuffers('stdout', 'world') s._sendBuffers() self.failUnlessEqual(b.updates, [{'stdout': 'hello world'}], b.show())
def testEnvironExpandVar(self): b = FakeSlaveBuilder(False, self.basedir) environ = { "EXPND": "-${PATH}-", "DOESNT_EXPAND": "-${---}-", "DOESNT_FIND": "-${DOESNT_EXISTS}-" } s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ=environ) d = s.start() def check(ign): headers = "".join([ update.values()[0] for update in b.updates if update.keys() == ["header"] ]) self.failUnless("EXPND=-$" not in headers, "got:\n" + headers) self.failUnless("DOESNT_FIND=--" in headers, "got:\n" + headers) self.failUnless("DOESNT_EXPAND=-${---}-" in headers, "got:\n" + headers) d.addCallback(check) return d
def testCommandEncodingObfuscated(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, [bsutil.Obfuscated(u'abcd', u'ABCD')], self.basedir) self.assertIsInstance(s.command[0], str) self.assertIsInstance(s.fake_command[0], str)
def testSendChunked(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir) data = "x" * (runprocess.RunProcess.CHUNK_LIMIT * 3 / 2) s._addToBuffers('stdout', data) s._sendBuffers() self.failUnlessEqual(len(b.updates), 2)
def test_simple(self, interruptSignal=None): # test a simple process that just sleeps waiting to die pidfile = self.newPidfile() self.pid = None b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, scriptCommand('write_pidfile_and_sleep', pidfile), self.basedir) if interruptSignal is not None: s.interruptSignal = interruptSignal runproc_d = s.start() pidfile_d = self.waitForPidfile(pidfile) def check_alive(pid): self.pid = pid # for use in check_dead # test that the process is still alive self.assertAlive(pid) # and tell the RunProcess object to kill it s.kill("diaf") pidfile_d.addCallback(check_alive) def check_dead(_): self.assertDead(self.pid) runproc_d.addCallback(check_dead) return defer.gatherResults([pidfile_d, runproc_d])
def testObfuscatedCommand(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, [('obfuscated', 'abcd', 'ABCD')], self.basedir) self.assertEqual(s.command, ['abcd']) self.assertEqual(s.fake_command, ['ABCD'])
def testEnvironInt(self): b = FakeSlaveBuilder(False, self.basedir) self.assertRaises( RuntimeError, lambda: runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ={"BUILD_NUMBER": 13}))
def testStderr(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stderrCommand("hello"), self.basedir) d = s.start() def check(ign): self.failIf({'stderr': nl('hello\n')} not in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testNoStdout(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, sendStdout=False) d = s.start() def check(ign): self.failIf({'stdout': nl('hello\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testUnsetEnvironVar(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ={"PATH":None}) d = s.start() def check(ign): headers = "".join([update.values()[0] for update in b.updates if update.keys() == ["header"] ]) self.failUnless(not re.match('\bPATH=',headers), "got:\n" + headers) d.addCallback(check) return d
def testStringCommand(self): b = FakeSlaveBuilder(False, self.basedir) # careful! This command must execute the same on windows and UNIX s = runprocess.RunProcess(b, 'echo hello', self.basedir) d = s.start() def check(ign): self.failUnless({'stdout': nl('hello\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testNoLogEnviron(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ={"FOO": "BAR"}, logEnviron=False) d = s.start() def check(ign): headers = "".join([update.values()[0] for update in b.updates if update.keys() == ["header"] ]) self.failUnless("FOO=BAR" not in headers, "got:\n" + headers) d.addCallback(check) return d
def testPipeEmbedded(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, ['echo', 'escaped|pipe'], self.basedir) d = s.start() def check(ign): self.failUnless({'stdout': nl('escaped|pipe\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testInitialStdinUnicode(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess( b, catCommand(), self.basedir, initialStdin=u'hello') d = s.start() def check(ign): self.failUnless({'stdout': nl('hello')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def test_stdin_closed(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, scriptCommand('assert_stdin_closed'), self.basedir, usePTY=False, # if usePTY=True, stdin is never closed logEnviron=False) d = s.start() def check(ign): self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testSendBufferedInterleaved(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir) s._addToBuffers('stdout', 'hello ') s._addToBuffers('stderr', 'DIEEEEEEE') s._addToBuffers('stdout', 'world') s._sendBuffers() self.failUnlessEqual(b.updates, [ {'stdout': 'hello '}, {'stderr': 'DIEEEEEEE'}, {'stdout': 'world'}, ])
def testEnvironArray(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ={"FOO":['a', 'b']}) d = s.start() def check(ign): headers = "".join([update.values()[0] for update in b.updates if update.keys() == ["header"] ]) self.failUnless(not re.match('\bFOO=a%sb\b' % (os.pathsep),headers), "got:\n" + headers) d.addCallback(check) return d
def testCommandMaxTime(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, sleepCommand(10), self.basedir, maxTime=5) clock = task.Clock() s._reactor = clock d = s.start() def check(ign): self.failUnless({'stdout': nl('hello\n')} not in b.updates, b.show()) self.failUnless({'rc': FATAL_RC} in b.updates, b.show()) d.addCallback(check) clock.advance(6) # should knock out maxTime return d
def testPipeString(self): b = FakeSlaveBuilder(False, self.basedir) #this is highly contrived, but it proves the point. cmd = sys.executable + ' -c "import sys; sys.stdout.write(\'b\\na\\n\')" | sort' s = runprocess.RunProcess(b, cmd, self.basedir) d = s.start() def check(ign): self.failUnless({'stdout': nl('a\nb\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testEnvironPythonPath(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir, environ={"PYTHONPATH": 'a'}) d = s.start() def check(ign): headers = "".join([list(update.values())[0] for update in b.updates if list(update) == ["header"]]) self.failUnless(not re.match('\bPYTHONPATH=a%s' % (os.pathsep), headers), "got:\n" + headers) d.addCallback(check) return d
def testMultiWordStringCommand(self): b = FakeSlaveBuilder(False, self.basedir) # careful! This command must execute the same on windows and UNIX s = runprocess.RunProcess(b, 'echo Happy Days and Jubilation', self.basedir) # no quoting occurs exp = nl('Happy Days and Jubilation\n') d = s.start() def check(ign): self.failUnless({'stdout': exp} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testPipeAlone(self): b = FakeSlaveBuilder(False, self.basedir) #this is highly contrived, but it proves the point. cmd = stdoutCommand("b\\na") cmd[0] = cmd[0].replace(".exe","") cmd.extend(['|','sort']) s = runprocess.RunProcess(b, cmd, self.basedir) d = s.start() def check(ign): self.failUnless({'stdout': nl('a\nb\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def do_test_double_fork(self, usePTY, useProcGroup=True, expectChildSurvival=False): # when a spawned process spawns another process, and then dies itself # (either intentionally or accidentally), we should be able to clean up # the child. parent_pidfile = self.newPidfile() self.parent_pid = None child_pidfile = self.newPidfile() self.child_pid = None b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, scriptCommand('double_fork', parent_pidfile, child_pidfile), self.basedir, usePTY=usePTY, useProcGroup=useProcGroup) runproc_d = s.start() # wait for both processes to start up, then call s.kill parent_pidfile_d = self.waitForPidfile(parent_pidfile) child_pidfile_d = self.waitForPidfile(child_pidfile) pidfiles_d = defer.gatherResults([parent_pidfile_d, child_pidfile_d]) def got_pids(pids): self.parent_pid, self.child_pid = pids pidfiles_d.addCallback(got_pids) def kill(_): s.kill("diaf") pidfiles_d.addCallback(kill) # check that both processes are dead after RunProcess is done d = defer.gatherResults([pidfiles_d, runproc_d]) def check_dead(_): self.assertDead(self.parent_pid) if expectChildSurvival: self.assertAlive(self.child_pid) else: self.assertDead(self.child_pid) d.addCallback(check_dead) return d
def do_test_pgroup(self, usePTY, useProcGroup=True, expectChildSurvival=False): # test that a process group gets killed parent_pidfile = self.newPidfile() self.parent_pid = None child_pidfile = self.newPidfile() self.child_pid = None b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, scriptCommand('spawn_child', parent_pidfile, child_pidfile), self.basedir, usePTY=usePTY, useProcGroup=useProcGroup) runproc_d = s.start() # wait for both processes to start up, then call s.kill parent_pidfile_d = self.waitForPidfile(parent_pidfile) child_pidfile_d = self.waitForPidfile(child_pidfile) pidfiles_d = defer.gatherResults([parent_pidfile_d, child_pidfile_d]) def got_pids(pids): self.parent_pid, self.child_pid = pids pidfiles_d.addCallback(got_pids) def kill(_): s.kill("diaf") pidfiles_d.addCallback(kill) # check that both processes are dead after RunProcess is done d = defer.gatherResults([pidfiles_d, runproc_d]) def check_dead(_): self.assertDead(self.parent_pid) if expectChildSurvival: self.assertAlive(self.child_pid) else: self.assertDead(self.child_pid) d.addCallback(check_dead) return d
def test_sigterm(self, interruptSignal=None): # Tests that the process will receive SIGTERM if sigtermTimeout # is not None pidfile = self.newPidfile() self.pid = None b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, scriptCommand('write_pidfile_and_sleep', pidfile), self.basedir, sigtermTime=1) runproc_d = s.start() pidfile_d = self.waitForPidfile(pidfile) self.receivedSIGTERM = False def check_alive(pid): # Create a mock process that will check if we recieve SIGTERM mock_process = Mock(wraps=s.process) mock_process.pgid = None # Skips over group SIGTERM mock_process.pid = pid process = s.process def _mock_signalProcess(sig): if sig == "TERM": self.receivedSIGTERM = True process.signalProcess(sig) mock_process.signalProcess = _mock_signalProcess s.process = mock_process self.pid = pid # for use in check_dead # test that the process is still alive self.assertAlive(pid) # and tell the RunProcess object to kill it s.kill("diaf") pidfile_d.addCallback(check_alive) def check_dead(_): self.failUnlessEqual(self.receivedSIGTERM, True) self.assertDead(self.pid) runproc_d.addCallback(check_dead) return defer.gatherResults([pidfile_d, runproc_d])
def testMultiWordStringCommandQuotes(self): b = FakeSlaveBuilder(False, self.basedir) # careful! This command must execute the same on windows and UNIX s = runprocess.RunProcess(b, 'echo "Happy Days and Jubilation"', self.basedir) if runtime.platformType == "win32": # echo doesn't parse out the quotes, so they come through in the # output exp = nl('"Happy Days and Jubilation"\n') else: exp = nl('Happy Days and Jubilation\n') d = s.start() def check(ign): self.failUnless({'stdout': exp} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testBadCommand(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, ['command_that_doesnt_exist.exe'], self.basedir) s.workdir = 1 # cause an exception d = s.start() def check(err): err.trap(AbandonChain) stderr = [] # Here we're checking that the exception starting up the command # actually gets propogated back to the master. for u in b.updates: if 'stderr' in u: stderr.append(u['stderr']) stderr = "".join(stderr) self.failUnless("TypeError" in stderr, stderr) d.addBoth(check) d.addBoth(lambda _ : self.flushLoggedErrors()) return d
def testMultiWordCommand(self): b = FakeSlaveBuilder(False, self.basedir) # careful! This command must execute the same on windows and UNIX s = runprocess.RunProcess(b, ['echo', 'Happy Days and Jubilation'], self.basedir) if runtime.platformType == "win32": # Twisted adds quotes to all arguments, and echo doesn't remove # them, so they appear in the output. exp = nl('"Happy Days and Jubilation"\n') else: exp = nl('Happy Days and Jubilation\n') d = s.start() def check(ign): self.failUnless({'stdout': exp} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testUserParameter(self): """ Test that setting the 'user' parameter causes RunProcess to wrap the command using 'sudo'. """ user = '******' cmd = ['whatever'] b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, cmd, self.basedir, user=user) # Override the '_spawnProcess' method so that we can verify # that the command is run using 'sudo', as we expect. def _spawnProcess(*args, **kwargs): executable = args[1] args = args[2] self.assertEqual(executable, 'sudo') self.assertEqual(args, ['sudo', '-u', user, '-H'] + cmd) s._spawnProcess = _spawnProcess s.start() return s.finished(None, 0)
def testPunctuation(self): # make sure special characters make it through unscathed b = FakeSlaveBuilder(False, self.basedir) punct = r'''!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~''' s = runprocess.RunProcess(b, ['echo', punct, '%PATH%'], self.basedir) d = s.start() if runtime.platformType == "win32": # Windows echo doesn't parse arguments, so they remain # quoted/escaped out_punct = '"' + punct.replace('"', r'\"') + '"' else: out_punct = punct def check(ign): self.failUnless({'stdout': nl(out_punct + ' %PATH%\n')} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testTrickyArguments(self): # make sure non-trivial arguments are passed verbatim b = FakeSlaveBuilder(False, self.basedir) args = [ 'Happy Days and Jubilation', # spaces r'''!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~''', # special characters '%PATH%', # Windows variable expansions # Expansions get an argument of their own, because the Windows # shell doesn't treat % as special unless it surrounds a # variable name. ] s = runprocess.RunProcess(b, printArgsCommand() + args, self.basedir) d = s.start() def check(ign): self.failUnless({'stdout': nl(repr(args))} in b.updates, b.show()) self.failUnless({'rc': 0} in b.updates, b.show()) d.addCallback(check) return d
def testSendStatus(self): b = FakeSlaveBuilder(False, self.basedir) s = runprocess.RunProcess(b, stdoutCommand('hello'), self.basedir) s.sendStatus({'stdout': nl('hello\n')}) self.failUnlessEqual(b.updates, [{'stdout': nl('hello\n')}], b.show())