Index: third_party/twisted_8_1/twisted/conch/test/test_cftp.py |
diff --git a/third_party/twisted_8_1/twisted/conch/test/test_cftp.py b/third_party/twisted_8_1/twisted/conch/test/test_cftp.py |
deleted file mode 100644 |
index ea973224928579bf471c3f81be7c0c48c9dde319..0000000000000000000000000000000000000000 |
--- a/third_party/twisted_8_1/twisted/conch/test/test_cftp.py |
+++ /dev/null |
@@ -1,705 +0,0 @@ |
-# -*- test-case-name: twisted.conch.test.test_cftp -*- |
-# Copyright (c) 2001-2008 Twisted Matrix Laboratories. |
-# See LICENSE file for details. |
- |
-import sys, os |
- |
-try: |
- import Crypto |
-except ImportError: |
- Crypto = None |
- |
-try: |
- from twisted.conch import unix |
- from twisted.conch.scripts import cftp |
- from twisted.conch.client import connect, default, options |
- from twisted.conch.test.test_filetransfer import FileTransferForTestAvatar |
-except ImportError: |
- unix = None |
- try: |
- del sys.modules['twisted.conch.unix'] # remove the bad import |
- except KeyError: |
- # In Python 2.4, the bad import has already been cleaned up for us. |
- pass |
- |
-from twisted.cred import portal |
-from twisted.internet import reactor, protocol, interfaces, defer, error |
-from twisted.internet.utils import getProcessOutputAndValue |
-from twisted.python import log |
- |
-from twisted.conch.test import test_ssh, test_conch |
-from twisted.conch.test.test_filetransfer import SFTPTestBase |
-from twisted.conch.test.test_filetransfer import FileTransferTestAvatar |
- |
- |
-class FileTransferTestRealm: |
- def __init__(self, testDir): |
- self.testDir = testDir |
- |
- def requestAvatar(self, avatarID, mind, *interfaces): |
- a = FileTransferTestAvatar(self.testDir) |
- return interfaces[0], a, lambda: None |
- |
- |
-class SFTPTestProcess(protocol.ProcessProtocol): |
- """ |
- Protocol for testing cftp. Provides an interface between Python (where all |
- the tests are) and the cftp client process (which does the work that is |
- being tested). |
- """ |
- |
- def __init__(self, onOutReceived): |
- """ |
- @param onOutReceived: A L{Deferred} to be fired as soon as data is |
- received from stdout. |
- """ |
- self.clearBuffer() |
- self.onOutReceived = onOutReceived |
- self.onProcessEnd = None |
- self._expectingCommand = None |
- self._processEnded = False |
- |
- def clearBuffer(self): |
- """ |
- Clear any buffered data received from stdout. Should be private. |
- """ |
- self.buffer = '' |
- self._linesReceived = [] |
- self._lineBuffer = '' |
- |
- def outReceived(self, data): |
- """ |
- Called by Twisted when the cftp client prints data to stdout. |
- """ |
- log.msg('got %s' % data) |
- lines = (self._lineBuffer + data).split('\n') |
- self._lineBuffer = lines.pop(-1) |
- self._linesReceived.extend(lines) |
- # XXX - not strictly correct. |
- # We really want onOutReceived to fire after the first 'cftp>' prompt |
- # has been received. (See use in TestOurServerCmdLineClient.setUp) |
- if self.onOutReceived is not None: |
- d, self.onOutReceived = self.onOutReceived, None |
- d.callback(data) |
- self.buffer += data |
- self._checkForCommand() |
- |
- def _checkForCommand(self): |
- prompt = 'cftp> ' |
- if self._expectingCommand and self._lineBuffer == prompt: |
- buf = '\n'.join(self._linesReceived) |
- if buf.startswith(prompt): |
- buf = buf[len(prompt):] |
- self.clearBuffer() |
- d, self._expectingCommand = self._expectingCommand, None |
- d.callback(buf) |
- |
- def errReceived(self, data): |
- """ |
- Called by Twisted when the cftp client prints data to stderr. |
- """ |
- log.msg('err: %s' % data) |
- |
- def getBuffer(self): |
- """ |
- Return the contents of the buffer of data received from stdout. |
- """ |
- return self.buffer |
- |
- def runCommand(self, command): |
- """ |
- Issue the given command via the cftp client. Return a C{Deferred} that |
- fires when the server returns a result. Note that the C{Deferred} will |
- callback even if the server returns some kind of error. |
- |
- @param command: A string containing an sftp command. |
- |
- @return: A C{Deferred} that fires when the sftp server returns a |
- result. The payload is the server's response string. |
- """ |
- self._expectingCommand = defer.Deferred() |
- self.clearBuffer() |
- self.transport.write(command + '\n') |
- return self._expectingCommand |
- |
- def runScript(self, commands): |
- """ |
- Run each command in sequence and return a Deferred that fires when all |
- commands are completed. |
- |
- @param commands: A list of strings containing sftp commands. |
- |
- @return: A C{Deferred} that fires when all commands are completed. The |
- payload is a list of response strings from the server, in the same |
- order as the commands. |
- """ |
- sem = defer.DeferredSemaphore(1) |
- dl = [sem.run(self.runCommand, command) for command in commands] |
- return defer.gatherResults(dl) |
- |
- def killProcess(self): |
- """ |
- Kill the process if it is still running. |
- |
- If the process is still running, sends a KILL signal to the transport |
- and returns a C{Deferred} which fires when L{processEnded} is called. |
- |
- @return: a C{Deferred}. |
- """ |
- if self._processEnded: |
- return defer.succeed(None) |
- self.onProcessEnd = defer.Deferred() |
- self.transport.signalProcess('KILL') |
- return self.onProcessEnd |
- |
- def processEnded(self, reason): |
- """ |
- Called by Twisted when the cftp client process ends. |
- """ |
- self._processEnded = True |
- if self.onProcessEnd: |
- d, self.onProcessEnd = self.onProcessEnd, None |
- d.callback(None) |
- |
- |
-class CFTPClientTestBase(SFTPTestBase): |
- def setUp(self): |
- f = open('dsa_test.pub','w') |
- f.write(test_ssh.publicDSA_openssh) |
- f.close() |
- f = open('dsa_test','w') |
- f.write(test_ssh.privateDSA_openssh) |
- f.close() |
- os.chmod('dsa_test', 33152) |
- f = open('kh_test','w') |
- f.write('127.0.0.1 ' + test_ssh.publicRSA_openssh) |
- f.close() |
- return SFTPTestBase.setUp(self) |
- |
- def startServer(self): |
- realm = FileTransferTestRealm(self.testDir) |
- p = portal.Portal(realm) |
- p.registerChecker(test_ssh.ConchTestPublicKeyChecker()) |
- fac = test_ssh.ConchTestServerFactory() |
- fac.portal = p |
- self.server = reactor.listenTCP(0, fac, interface="127.0.0.1") |
- |
- def stopServer(self): |
- if not hasattr(self.server.factory, 'proto'): |
- return self._cbStopServer(None) |
- self.server.factory.proto.expectedLoseConnection = 1 |
- d = defer.maybeDeferred( |
- self.server.factory.proto.transport.loseConnection) |
- d.addCallback(self._cbStopServer) |
- return d |
- |
- def _cbStopServer(self, ignored): |
- return defer.maybeDeferred(self.server.stopListening) |
- |
- def tearDown(self): |
- for f in ['dsa_test.pub', 'dsa_test', 'kh_test']: |
- try: |
- os.remove(f) |
- except: |
- pass |
- return SFTPTestBase.tearDown(self) |
- |
- |
- |
-class TestOurServerCmdLineClient(CFTPClientTestBase): |
- |
- def setUp(self): |
- CFTPClientTestBase.setUp(self) |
- |
- self.startServer() |
- cmds = ('-p %i -l testuser ' |
- '--known-hosts kh_test ' |
- '--user-authentications publickey ' |
- '--host-key-algorithms ssh-rsa ' |
- '-K direct ' |
- '-i dsa_test ' |
- '-a --nocache ' |
- '-v ' |
- '127.0.0.1') |
- port = self.server.getHost().port |
- cmds = test_conch._makeArgs((cmds % port).split(), mod='cftp') |
- log.msg('running %s %s' % (sys.executable, cmds)) |
- d = defer.Deferred() |
- self.processProtocol = SFTPTestProcess(d) |
- d.addCallback(lambda _: self.processProtocol.clearBuffer()) |
- env = os.environ.copy() |
- env['PYTHONPATH'] = os.pathsep.join(sys.path) |
- reactor.spawnProcess(self.processProtocol, sys.executable, cmds, |
- env=env) |
- return d |
- |
- def tearDown(self): |
- d = self.stopServer() |
- d.addCallback(lambda _: self.processProtocol.killProcess()) |
- return d |
- |
- def _killProcess(self, ignored): |
- try: |
- self.processProtocol.transport.signalProcess('KILL') |
- except error.ProcessExitedAlready: |
- pass |
- |
- def runCommand(self, command): |
- """ |
- Run the given command with the cftp client. Return a C{Deferred} that |
- fires when the command is complete. Payload is the server's output for |
- that command. |
- """ |
- return self.processProtocol.runCommand(command) |
- |
- def runScript(self, *commands): |
- """ |
- Run the given commands with the cftp client. Returns a C{Deferred} |
- that fires when the commands are all complete. The C{Deferred}'s |
- payload is a list of output for each command. |
- """ |
- return self.processProtocol.runScript(commands) |
- |
- def testCdPwd(self): |
- """ |
- Test that 'pwd' reports the current remote directory, that 'lpwd' |
- reports the current local directory, and that changing to a |
- subdirectory then changing to its parent leaves you in the original |
- remote directory. |
- """ |
- # XXX - not actually a unit test, see docstring. |
- homeDir = os.path.join(os.getcwd(), self.testDir) |
- d = self.runScript('pwd', 'lpwd', 'cd testDirectory', 'cd ..', 'pwd') |
- d.addCallback(lambda xs: xs[:3] + xs[4:]) |
- d.addCallback(self.assertEqual, |
- [homeDir, os.getcwd(), '', homeDir]) |
- return d |
- |
- def testChAttrs(self): |
- """ |
- Check that 'ls -l' output includes the access permissions and that |
- this output changes appropriately with 'chmod'. |
- """ |
- def _check(results): |
- self.flushLoggedErrors() |
- self.assertTrue(results[0].startswith('-rw-r--r--')) |
- self.assertEqual(results[1], '') |
- self.assertTrue(results[2].startswith('----------'), results[2]) |
- self.assertEqual(results[3], '') |
- |
- d = self.runScript('ls -l testfile1', 'chmod 0 testfile1', |
- 'ls -l testfile1', 'chmod 644 testfile1') |
- return d.addCallback(_check) |
- # XXX test chgrp/own |
- |
- |
- def testList(self): |
- """ |
- Check 'ls' works as expected. Checks for wildcards, hidden files, |
- listing directories and listing empty directories. |
- """ |
- def _check(results): |
- self.assertEqual(results[0], ['testDirectory', 'testRemoveFile', |
- 'testRenameFile', 'testfile1']) |
- self.assertEqual(results[1], ['testDirectory', 'testRemoveFile', |
- 'testRenameFile', 'testfile1']) |
- self.assertEqual(results[2], ['testRemoveFile', 'testRenameFile']) |
- self.assertEqual(results[3], ['.testHiddenFile', 'testRemoveFile', |
- 'testRenameFile']) |
- self.assertEqual(results[4], ['']) |
- d = self.runScript('ls', 'ls ../' + os.path.basename(self.testDir), |
- 'ls *File', 'ls -a *File', 'ls -l testDirectory') |
- d.addCallback(lambda xs: [x.split('\n') for x in xs]) |
- return d.addCallback(_check) |
- |
- def testHelp(self): |
- """ |
- Check that running the '?' command returns help. |
- """ |
- d = self.runCommand('?') |
- d.addCallback(self.assertEqual, |
- cftp.StdioClient(None).cmd_HELP('').strip()) |
- return d |
- |
- def assertFilesEqual(self, name1, name2, msg=None): |
- """ |
- Assert that the files at C{name1} and C{name2} contain exactly the |
- same data. |
- """ |
- f1 = file(name1).read() |
- f2 = file(name2).read() |
- self.failUnlessEqual(f1, f2, msg) |
- |
- |
- def testGet(self): |
- """ |
- Test that 'get' saves the remote file to the correct local location, |
- that the output of 'get' is correct and that 'rm' actually removes |
- the file. |
- """ |
- # XXX - not actually a unit test |
- expectedOutput = ("Transferred %s/%s/testfile1 to %s/test file2" |
- % (os.getcwd(), self.testDir, self.testDir)) |
- def _checkGet(result): |
- self.assertTrue(result.endswith(expectedOutput)) |
- self.assertFilesEqual(self.testDir + '/testfile1', |
- self.testDir + '/test file2', |
- "get failed") |
- return self.runCommand('rm "test file2"') |
- |
- d = self.runCommand('get testfile1 "%s/test file2"' % (self.testDir,)) |
- d.addCallback(_checkGet) |
- d.addCallback(lambda _: self.failIf( |
- os.path.exists(self.testDir + '/test file2'))) |
- return d |
- |
- |
- def testWildcardGet(self): |
- """ |
- Test that 'get' works correctly when given wildcard parameters. |
- """ |
- def _check(ignored): |
- self.assertFilesEqual(self.testDir + '/testRemoveFile', |
- 'testRemoveFile', |
- 'testRemoveFile get failed') |
- self.assertFilesEqual(self.testDir + '/testRenameFile', |
- 'testRenameFile', |
- 'testRenameFile get failed') |
- |
- d = self.runCommand('get testR*') |
- return d.addCallback(_check) |
- |
- |
- def testPut(self): |
- """ |
- Check that 'put' uploads files correctly and that they can be |
- successfully removed. Also check the output of the put command. |
- """ |
- # XXX - not actually a unit test |
- expectedOutput = ('Transferred %s/testfile1 to %s/%s/test"file2' |
- % (self.testDir, os.getcwd(), self.testDir)) |
- def _checkPut(result): |
- self.assertFilesEqual(self.testDir + '/testfile1', |
- self.testDir + '/test"file2') |
- self.failUnless(result.endswith(expectedOutput)) |
- return self.runCommand('rm "test\\"file2"') |
- |
- d = self.runCommand('put %s/testfile1 "test\\"file2"' |
- % (self.testDir,)) |
- d.addCallback(_checkPut) |
- d.addCallback(lambda _: self.failIf( |
- os.path.exists(self.testDir + '/test"file2'))) |
- return d |
- |
- |
- def testWildcardPut(self): |
- """ |
- What happens if you issue a 'put' command and include a wildcard (i.e. |
- '*') in parameter? Check that all files matching the wildcard are |
- uploaded to the correct directory. |
- """ |
- def check(results): |
- self.assertEqual(results[0], '') |
- self.assertEqual(results[2], '') |
- self.assertFilesEqual(self.testDir + '/testRemoveFile', |
- self.testDir + '/../testRemoveFile', |
- 'testRemoveFile get failed') |
- self.assertFilesEqual(self.testDir + '/testRenameFile', |
- self.testDir + '/../testRenameFile', |
- 'testRenameFile get failed') |
- |
- d = self.runScript('cd ..', |
- 'put %s/testR*' % (self.testDir,), |
- 'cd %s' % os.path.basename(self.testDir)) |
- d.addCallback(check) |
- return d |
- |
- |
- def testLink(self): |
- """ |
- Test that 'ln' creates a file which appears as a link in the output of |
- 'ls'. Check that removing the new file succeeds without output. |
- """ |
- def _check(results): |
- self.flushLoggedErrors() |
- self.assertEqual(results[0], '') |
- self.assertTrue(results[1].startswith('l'), 'link failed') |
- return self.runCommand('rm testLink') |
- |
- d = self.runScript('ln testLink testfile1', 'ls -l testLink') |
- d.addCallback(_check) |
- d.addCallback(self.assertEqual, '') |
- return d |
- |
- |
- def testRemoteDirectory(self): |
- """ |
- Test that we can create and remove directories with the cftp client. |
- """ |
- def _check(results): |
- self.assertEqual(results[0], '') |
- self.assertTrue(results[1].startswith('d')) |
- return self.runCommand('rmdir testMakeDirectory') |
- |
- d = self.runScript('mkdir testMakeDirectory', |
- 'ls -l testMakeDirector?') |
- d.addCallback(_check) |
- d.addCallback(self.assertEqual, '') |
- return d |
- |
- |
- def testLocalDirectory(self): |
- """ |
- Test that we can create a directory locally and remove it with the |
- cftp client. This test works because the 'remote' server is running |
- out of a local directory. |
- """ |
- d = self.runCommand('lmkdir %s/testLocalDirectory' % (self.testDir,)) |
- d.addCallback(self.assertEqual, '') |
- d.addCallback(lambda _: self.runCommand('rmdir testLocalDirectory')) |
- d.addCallback(self.assertEqual, '') |
- return d |
- |
- |
- def testRename(self): |
- """ |
- Test that we can rename a file. |
- """ |
- def _check(results): |
- self.assertEqual(results[0], '') |
- self.assertEqual(results[1], 'testfile2') |
- return self.runCommand('rename testfile2 testfile1') |
- |
- d = self.runScript('rename testfile1 testfile2', 'ls testfile?') |
- d.addCallback(_check) |
- d.addCallback(self.assertEqual, '') |
- return d |
- |
- |
- def testCommand(self): |
- d = self.runCommand('!echo hello') |
- return d.addCallback(self.assertEqual, 'hello') |
- |
- |
-class TestOurServerBatchFile(CFTPClientTestBase): |
- def setUp(self): |
- CFTPClientTestBase.setUp(self) |
- self.startServer() |
- |
- def tearDown(self): |
- CFTPClientTestBase.tearDown(self) |
- return self.stopServer() |
- |
- def _getBatchOutput(self, f): |
- fn = self.mktemp() |
- open(fn, 'w').write(f) |
- l = [] |
- port = self.server.getHost().port |
- cmds = ('-p %i -l testuser ' |
- '--known-hosts kh_test ' |
- '--user-authentications publickey ' |
- '--host-key-algorithms ssh-rsa ' |
- '-K direct ' |
- '-i dsa_test ' |
- '-a --nocache ' |
- '-v -b %s 127.0.0.1') % (port, fn) |
- cmds = test_conch._makeArgs(cmds.split(), mod='cftp')[1:] |
- log.msg('running %s %s' % (sys.executable, cmds)) |
- env = os.environ.copy() |
- env['PYTHONPATH'] = os.pathsep.join(sys.path) |
- |
- self.server.factory.expectedLoseConnection = 1 |
- |
- d = getProcessOutputAndValue(sys.executable, cmds, env=env) |
- |
- def _cleanup(res): |
- os.remove(fn) |
- return res |
- |
- d.addCallback(lambda res: res[0]) |
- d.addBoth(_cleanup) |
- |
- return d |
- |
- def testBatchFile(self): |
- """Test whether batch file function of cftp ('cftp -b batchfile'). |
- This works by treating the file as a list of commands to be run. |
- """ |
- cmds = """pwd |
-ls |
-exit |
-""" |
- def _cbCheckResult(res): |
- res = res.split('\n') |
- log.msg('RES %s' % str(res)) |
- self.failUnless(res[1].find(self.testDir) != -1, repr(res)) |
- self.failUnlessEqual(res[3:-2], ['testDirectory', 'testRemoveFile', |
- 'testRenameFile', 'testfile1']) |
- |
- d = self._getBatchOutput(cmds) |
- d.addCallback(_cbCheckResult) |
- return d |
- |
- def testError(self): |
- """Test that an error in the batch file stops running the batch. |
- """ |
- cmds = """chown 0 missingFile |
-pwd |
-exit |
-""" |
- def _cbCheckResult(res): |
- self.failIf(res.find(self.testDir) != -1) |
- |
- d = self._getBatchOutput(cmds) |
- d.addCallback(_cbCheckResult) |
- return d |
- |
- def testIgnoredError(self): |
- """Test that a minus sign '-' at the front of a line ignores |
- any errors. |
- """ |
- cmds = """-chown 0 missingFile |
-pwd |
-exit |
-""" |
- def _cbCheckResult(res): |
- self.failIf(res.find(self.testDir) == -1) |
- |
- d = self._getBatchOutput(cmds) |
- d.addCallback(_cbCheckResult) |
- return d |
- |
- |
-class TestOurServerUnixClient(test_conch._UnixFixHome, CFTPClientTestBase): |
- |
- def setUp(self): |
- test_conch._UnixFixHome.setUp(self) |
- CFTPClientTestBase.setUp(self) |
- self.startServer() |
- cmd1 = ('-p %i -l testuser ' |
- '--known-hosts kh_test ' |
- '--host-key-algorithms ssh-rsa ' |
- '-a ' |
- '-K direct ' |
- '-i dsa_test ' |
- '127.0.0.1' |
- ) |
- port = self.server.getHost().port |
- cmds1 = (cmd1 % port).split() |
- o = options.ConchOptions() |
- def _(host, *args): |
- o['host'] = host |
- o.parseArgs = _ |
- o.parseOptions(cmds1) |
- vhk = default.verifyHostKey |
- self.conn = conn = test_conch.SSHTestConnectionForUnix(None) |
- uao = default.SSHUserAuthClient(o['user'], o, conn) |
- return connect.connect(o['host'], int(o['port']), o, vhk, uao) |
- |
- def tearDown(self): |
- CFTPClientTestBase.tearDown(self) |
- d = defer.maybeDeferred(self.conn.transport.loseConnection) |
- d.addCallback(lambda x : self.stopServer()) |
- def clean(ign): |
- test_conch._UnixFixHome.tearDown(self) |
- return ign |
- return defer.gatherResults([d, self.conn.stopDeferred]).addBoth(clean) |
- |
- def _getBatchOutput(self, f): |
- fn = self.mktemp() |
- open(fn, 'w').write(f) |
- port = self.server.getHost().port |
- cmds = ('-p %i -l testuser ' |
- '-K unix ' |
- '-a ' |
- '-v -b %s 127.0.0.1') % (port, fn) |
- cmds = test_conch._makeArgs(cmds.split(), mod='cftp')[1:] |
- log.msg('running %s %s' % (sys.executable, cmds)) |
- env = os.environ.copy() |
- env['PYTHONPATH'] = os.pathsep.join(sys.path) |
- |
- self.server.factory.expectedLoseConnection = 1 |
- |
- d = getProcessOutputAndValue(sys.executable, cmds, env=env) |
- |
- def _cleanup(res): |
- os.remove(fn) |
- return res |
- |
- d.addCallback(lambda res: res[0]) |
- d.addBoth(_cleanup) |
- |
- return d |
- |
- def testBatchFile(self): |
- """Test that the client works even over a UNIX connection. |
- """ |
- cmds = """pwd |
-exit |
-""" |
- d = self._getBatchOutput(cmds) |
- d.addCallback( |
- lambda res : self.failIf(res.find(self.testDir) == -1, |
- "%s not in %r" % (self.testDir, res))) |
- return d |
- |
- |
- |
-class TestOurServerSftpClient(CFTPClientTestBase): |
- """ |
- Test the sftp server against sftp command line client. |
- """ |
- |
- def setUp(self): |
- CFTPClientTestBase.setUp(self) |
- return self.startServer() |
- |
- |
- def tearDown(self): |
- return self.stopServer() |
- |
- |
- def test_extendedAttributes(self): |
- """ |
- Test the return of extended attributes by the server: the sftp client |
- should ignore them, but still be able to parse the response correctly. |
- |
- This test is mainly here to check that |
- L{filetransfer.FILEXFER_ATTR_EXTENDED} has the correct value. |
- """ |
- fn = self.mktemp() |
- open(fn, 'w').write("ls .\nexit") |
- port = self.server.getHost().port |
- |
- oldGetAttr = FileTransferForTestAvatar._getAttrs |
- def _getAttrs(self, s): |
- attrs = oldGetAttr(self, s) |
- attrs["ext_foo"] = "bar" |
- return attrs |
- |
- self.patch(FileTransferForTestAvatar, "_getAttrs", _getAttrs) |
- |
- self.server.factory.expectedLoseConnection = True |
- cmds = ('-o', 'IdentityFile=dsa_test', |
- '-o', 'UserKnownHostsFile=kh_test', |
- '-o', 'HostKeyAlgorithms=ssh-rsa', |
- '-o', 'Port=%i' % (port,), '-b', fn, 'testuser@127.0.0.1') |
- d = getProcessOutputAndValue("sftp", cmds) |
- def check(result): |
- self.assertEquals(result[2], 0) |
- for i in ['testDirectory', 'testRemoveFile', |
- 'testRenameFile', 'testfile1']: |
- self.assertIn(i, result[0]) |
- return d.addCallback(check) |
- |
- |
- |
-if not unix or not Crypto or not interfaces.IReactorProcess(reactor, None): |
- TestOurServerCmdLineClient.skip = "don't run w/o spawnprocess or PyCrypto" |
- TestOurServerBatchFile.skip = "don't run w/o spawnProcess or PyCrypto" |
- TestOurServerUnixClient.skip = "don't run w/o spawnProcess or PyCrypto" |
- TestOurServerSftpClient.skip = "don't run w/o spawnProcess or PyCrypto" |
-else: |
- from twisted.python.procutils import which |
- if not which('sftp'): |
- TestOurServerSftpClient.skip = "no sftp command-line client available" |