def test_childConnectionLost(self): """ L{IProcessProtocol.childConnectionLost} is called each time a file descriptor associated with a child process is closed. """ connected = Deferred() lost = {0: Deferred(), 1: Deferred(), 2: Deferred()} class Closer(ProcessProtocol): def makeConnection(self, transport): connected.callback(transport) def childConnectionLost(self, childFD): lost[childFD].callback(None) source = ("import os, sys\n" "while 1:\n" " line = sys.stdin.readline().strip()\n" " if not line:\n" " break\n" " os.close(int(line))\n") reactor = self.buildReactor() reactor.callWhenRunning(reactor.spawnProcess, Closer(), sys.executable, [sys.executable, "-c", source], usePTY=self.usePTY) def cbConnected(transport): transport.write('2\n') return lost[2].addCallback(lambda ign: transport) connected.addCallback(cbConnected) def lostSecond(transport): transport.write('1\n') return lost[1].addCallback(lambda ign: transport) connected.addCallback(lostSecond) def lostFirst(transport): transport.write('\n') connected.addCallback(lostFirst) connected.addErrback(err) def cbEnded(ignored): reactor.stop() connected.addCallback(cbEnded) self.runReactor(reactor)
def test_processExited(self): """ L{IProcessProtocol.processExited} is called when the child process exits, even if file descriptors associated with the child are still open. """ exited = Deferred() allLost = Deferred() lost = [] class Waiter(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) def childConnectionLost(self, childFD): msg('childConnectionLost(%d)' % (childFD, )) lost.append(childFD) if len(lost) == 3: allLost.callback(None) def processExited(self, reason): msg('processExited(%r)' % (reason, )) # See test_processExitedWithSignal exited.callback([reason]) self.transport.loseConnection() reactor = self.buildReactor() reactor.callWhenRunning(reactor.spawnProcess, Waiter(), sys.executable, [ sys.executable, self.keepStdioOpenProgram, "child", self.keepStdioOpenArg ], usePTY=self.usePTY) def cbExited((failure, )): failure.trap(ProcessDone) msg('cbExited; lost = %s' % (lost, )) self.assertEqual(lost, []) return allLost exited.addCallback(cbExited) def cbAllLost(ignored): self.assertEqual(set(lost), set([0, 1, 2])) exited.addCallback(cbAllLost) exited.addErrback(err) exited.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)
def test_processExited(self): """ L{IProcessProtocol.processExited} is called when the child process exits, even if file descriptors associated with the child are still open. """ exited = Deferred() allLost = Deferred() lost = [] class Waiter(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) def childConnectionLost(self, childFD): msg('childConnectionLost(%d)' % (childFD,)) lost.append(childFD) if len(lost) == 3: allLost.callback(None) def processExited(self, reason): msg('processExited(%r)' % (reason,)) # See test_processExitedWithSignal exited.callback([reason]) self.transport.loseConnection() reactor = self.buildReactor() reactor.callWhenRunning( reactor.spawnProcess, Waiter(), sys.executable, [sys.executable, self.keepStdioOpenProgram, "child", self.keepStdioOpenArg], usePTY=self.usePTY) def cbExited((failure,)): failure.trap(ProcessDone) msg('cbExited; lost = %s' % (lost,)) self.assertEqual(lost, []) return allLost exited.addCallback(cbExited) def cbAllLost(ignored): self.assertEqual(set(lost), set([0, 1, 2])) exited.addCallback(cbAllLost) exited.addErrback(err) exited.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)
def test_childConnectionLost(self): """ L{IProcessProtocol.childConnectionLost} is called each time a file descriptor associated with a child process is closed. """ connected = Deferred() lost = {0: Deferred(), 1: Deferred(), 2: Deferred()} class Closer(ProcessProtocol): def makeConnection(self, transport): connected.callback(transport) def childConnectionLost(self, childFD): lost[childFD].callback(None) source = ( "import os, sys\n" "while 1:\n" " line = sys.stdin.readline().strip()\n" " if not line:\n" " break\n" " os.close(int(line))\n") reactor = self.buildReactor() reactor.callWhenRunning( reactor.spawnProcess, Closer(), sys.executable, [sys.executable, "-c", source], usePTY=self.usePTY) def cbConnected(transport): transport.write('2\n') return lost[2].addCallback(lambda ign: transport) connected.addCallback(cbConnected) def lostSecond(transport): transport.write('1\n') return lost[1].addCallback(lambda ign: transport) connected.addCallback(lostSecond) def lostFirst(transport): transport.write('\n') connected.addCallback(lostFirst) connected.addErrback(err) def cbEnded(ignored): reactor.stop() connected.addCallback(cbEnded) self.runReactor(reactor)
def test_processEnded(self): """ L{IProcessProtocol.processEnded} is called after the child process exits and L{IProcessProtocol.childConnectionLost} is called for each of its file descriptors. """ ended = Deferred() lost = [] class Ender(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) self.transport.loseConnection() def childConnectionLost(self, childFD): msg('childConnectionLost(%d)' % (childFD, )) lost.append(childFD) def processExited(self, reason): msg('processExited(%r)' % (reason, )) def processEnded(self, reason): msg('processEnded(%r)' % (reason, )) ended.callback([reason]) reactor = self.buildReactor() reactor.callWhenRunning(reactor.spawnProcess, Ender(), sys.executable, [ sys.executable, self.keepStdioOpenProgram, "child", self.keepStdioOpenArg ], usePTY=self.usePTY) def cbEnded((failure, )): failure.trap(ProcessDone) self.assertEqual(set(lost), set([0, 1, 2])) ended.addCallback(cbEnded) ended.addErrback(err) ended.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)
def test_processEnded(self): """ L{IProcessProtocol.processEnded} is called after the child process exits and L{IProcessProtocol.childConnectionLost} is called for each of its file descriptors. """ ended = Deferred() lost = [] class Ender(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) self.transport.loseConnection() def childConnectionLost(self, childFD): msg('childConnectionLost(%d)' % (childFD,)) lost.append(childFD) def processExited(self, reason): msg('processExited(%r)' % (reason,)) def processEnded(self, reason): msg('processEnded(%r)' % (reason,)) ended.callback([reason]) reactor = self.buildReactor() reactor.callWhenRunning( reactor.spawnProcess, Ender(), sys.executable, [sys.executable, self.keepStdioOpenProgram, "child", self.keepStdioOpenArg], usePTY=self.usePTY) def cbEnded((failure,)): failure.trap(ProcessDone) self.assertEqual(set(lost), set([0, 1, 2])) ended.addCallback(cbEnded) ended.addErrback(err) ended.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)
class PassportTests(unittest.TestCase): def setUp(self): self.result = [] self.deferred = Deferred() self.deferred.addCallback(lambda r: self.result.append(r)) self.deferred.addErrback(printError) def test_nexus(self): """ When L{msn.PassportNexus} receives enough information to identify the address of the login server, it fires the L{Deferred} passed to its initializer with that address. """ protocol = msn.PassportNexus(self.deferred, 'https://foobar.com/somepage.quux') headers = { 'Content-Length': '0', 'Content-Type': 'text/html', 'PassportURLs': 'DARealm=Passport.Net,DALogin=login.myserver.com/,DAReg=reg.myserver.com' } transport = StringTransport() protocol.makeConnection(transport) protocol.dataReceived('HTTP/1.0 200 OK\r\n') for (h, v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h, v)) protocol.dataReceived('\r\n') self.assertEquals(self.result[0], "https://login.myserver.com/") def _doLoginTest(self, response, headers): protocol = msn.PassportLogin(self.deferred, '*****@*****.**', 'testpass', 'https://foo.com/', 'a') protocol.makeConnection(StringTransport()) protocol.dataReceived(response) for (h, v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h, v)) protocol.dataReceived('\r\n') def testPassportLoginSuccess(self): headers = { 'Content-Length': '0', 'Content-Type': 'text/html', 'Authentication-Info': "Passport1.4 da-status=success,tname=MSPAuth," + "tname=MSPProf,tname=MSPSec,from-PP='somekey'," + "ru=http://messenger.msn.com" } self._doLoginTest('HTTP/1.1 200 OK\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_SUCCESS, 'somekey')) def testPassportLoginFailure(self): headers = { 'Content-Type': 'text/html', 'WWW-Authenticate': 'Passport1.4 da-status=failed,' + 'srealm=Passport.NET,ts=-3,prompt,cburl=http://host.com,' + 'cbtxt=the%20error%20message' } self._doLoginTest('HTTP/1.1 401 Unauthorized\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_FAILURE, 'the error message')) def testPassportLoginRedirect(self): headers = { 'Content-Type': 'text/html', 'Authentication-Info': 'Passport1.4 da-status=redir', 'Location': 'https://newlogin.host.com/' } self._doLoginTest('HTTP/1.1 302 Found\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_REDIRECT, 'https://newlogin.host.com/', 'a'))
def test_processExitedWithSignal(self): """ The C{reason} argument passed to L{IProcessProtocol.processExited} is a L{ProcessTerminated} instance if the child process exits with a signal. """ sigName = 'TERM' sigNum = getattr(signal, 'SIG' + sigName) exited = Deferred() source = ( "import sys\n" # Talk so the parent process knows the process is running. This is # necessary because ProcessProtocol.makeConnection may be called # before this process is exec'd. It would be unfortunate if we # SIGTERM'd the Twisted process while it was on its way to doing # the exec. "sys.stdout.write('x')\n" "sys.stdout.flush()\n" "sys.stdin.read()\n") class Exiter(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) self.transport.signalProcess(sigName) def childConnectionLost(self, fd): msg('childConnectionLost(%d)' % (fd, )) def processExited(self, reason): msg('processExited(%r)' % (reason, )) # Protect the Deferred from the failure so that it follows # the callback chain. This doesn't use the errback chain # because it wants to make sure reason is a Failure. An # Exception would also make an errback-based test pass, and # that would be wrong. exited.callback([reason]) def processEnded(self, reason): msg('processEnded(%r)' % (reason, )) reactor = self.buildReactor() reactor.callWhenRunning(reactor.spawnProcess, Exiter(), sys.executable, [sys.executable, "-c", source], usePTY=self.usePTY) def cbExited((failure, )): # Trapping implicitly verifies that it's a Failure (rather than # an exception) and explicitly makes sure it's the right type. failure.trap(ProcessTerminated) err = failure.value if platform.isWindows(): # Windows can't really /have/ signals, so it certainly can't # report them as the reason for termination. Maybe there's # something better we could be doing here, anyway? Hard to # say. Anyway, this inconsistency between different platforms # is extremely unfortunate and I would remove it if I # could. -exarkun self.assertIdentical(err.signal, None) self.assertEqual(err.exitCode, 1) else: self.assertEqual(err.signal, sigNum) self.assertIdentical(err.exitCode, None) exited.addCallback(cbExited) exited.addErrback(err) exited.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)
class PassportTests(unittest.TestCase): def setUp(self): self.result = [] self.deferred = Deferred() self.deferred.addCallback(lambda r: self.result.append(r)) self.deferred.addErrback(printError) def test_nexus(self): """ When L{msn.PassportNexus} receives enough information to identify the address of the login server, it fires the L{Deferred} passed to its initializer with that address. """ protocol = msn.PassportNexus(self.deferred, 'https://foobar.com/somepage.quux') headers = { 'Content-Length' : '0', 'Content-Type' : 'text/html', 'PassportURLs' : 'DARealm=Passport.Net,DALogin=login.myserver.com/,DAReg=reg.myserver.com' } transport = StringTransport() protocol.makeConnection(transport) protocol.dataReceived('HTTP/1.0 200 OK\r\n') for (h, v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) protocol.dataReceived('\r\n') self.assertEquals(self.result[0], "https://login.myserver.com/") def _doLoginTest(self, response, headers): protocol = msn.PassportLogin(self.deferred,'*****@*****.**','testpass','https://foo.com/', 'a') protocol.makeConnection(StringTransport()) protocol.dataReceived(response) for (h,v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) protocol.dataReceived('\r\n') def testPassportLoginSuccess(self): headers = { 'Content-Length' : '0', 'Content-Type' : 'text/html', 'Authentication-Info' : "Passport1.4 da-status=success,tname=MSPAuth," + "tname=MSPProf,tname=MSPSec,from-PP='somekey'," + "ru=http://messenger.msn.com" } self._doLoginTest('HTTP/1.1 200 OK\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_SUCCESS, 'somekey')) def testPassportLoginFailure(self): headers = { 'Content-Type' : 'text/html', 'WWW-Authenticate' : 'Passport1.4 da-status=failed,' + 'srealm=Passport.NET,ts=-3,prompt,cburl=http://host.com,' + 'cbtxt=the%20error%20message' } self._doLoginTest('HTTP/1.1 401 Unauthorized\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_FAILURE, 'the error message')) def testPassportLoginRedirect(self): headers = { 'Content-Type' : 'text/html', 'Authentication-Info' : 'Passport1.4 da-status=redir', 'Location' : 'https://newlogin.host.com/' } self._doLoginTest('HTTP/1.1 302 Found\r\n', headers) self.failUnless(self.result[0] == (msn.LOGIN_REDIRECT, 'https://newlogin.host.com/', 'a'))
def test_processExitedWithSignal(self): """ The C{reason} argument passed to L{IProcessProtocol.processExited} is a L{ProcessTerminated} instance if the child process exits with a signal. """ sigName = 'TERM' sigNum = getattr(signal, 'SIG' + sigName) exited = Deferred() source = ( "import sys\n" # Talk so the parent process knows the process is running. This is # necessary because ProcessProtocol.makeConnection may be called # before this process is exec'd. It would be unfortunate if we # SIGTERM'd the Twisted process while it was on its way to doing # the exec. "sys.stdout.write('x')\n" "sys.stdout.flush()\n" "sys.stdin.read()\n") class Exiter(ProcessProtocol): def childDataReceived(self, fd, data): msg('childDataReceived(%d, %r)' % (fd, data)) self.transport.signalProcess(sigName) def childConnectionLost(self, fd): msg('childConnectionLost(%d)' % (fd,)) def processExited(self, reason): msg('processExited(%r)' % (reason,)) # Protect the Deferred from the failure so that it follows # the callback chain. This doesn't use the errback chain # because it wants to make sure reason is a Failure. An # Exception would also make an errback-based test pass, and # that would be wrong. exited.callback([reason]) def processEnded(self, reason): msg('processEnded(%r)' % (reason,)) reactor = self.buildReactor() reactor.callWhenRunning( reactor.spawnProcess, Exiter(), sys.executable, [sys.executable, "-c", source], usePTY=self.usePTY) def cbExited((failure,)): # Trapping implicitly verifies that it's a Failure (rather than # an exception) and explicitly makes sure it's the right type. failure.trap(ProcessTerminated) err = failure.value if platform.isWindows(): # Windows can't really /have/ signals, so it certainly can't # report them as the reason for termination. Maybe there's # something better we could be doing here, anyway? Hard to # say. Anyway, this inconsistency between different platforms # is extremely unfortunate and I would remove it if I # could. -exarkun self.assertIdentical(err.signal, None) self.assertEqual(err.exitCode, 1) else: self.assertEqual(err.signal, sigNum) self.assertIdentical(err.exitCode, None) exited.addCallback(cbExited) exited.addErrback(err) exited.addCallback(lambda ign: reactor.stop()) self.runReactor(reactor)