launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #25661
[Merge] ~cjwatson/launchpad:sftp-inlineCallbacks into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:sftp-inlineCallbacks into launchpad:master.
Commit message:
Convert lp.codehosting.sftp and its tests to inlineCallbacks
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/393769
This is more compact and easier to follow.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:sftp-inlineCallbacks into launchpad:master.
diff --git a/lib/lp/codehosting/sftp.py b/lib/lp/codehosting/sftp.py
index d99dcc6..614f847 100644
--- a/lib/lp/codehosting/sftp.py
+++ b/lib/lp/codehosting/sftp.py
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""An SFTP server that backs on to a special kind of Bazaar Transport.
@@ -166,6 +166,7 @@ class TransportSFTPFile:
return self.transport.put_bytes(self._escaped_path, b'')
@with_sftp_error
+ @defer.inlineCallbacks
def writeChunk(self, offset, data):
"""See `ISFTPFile`."""
if not self._shouldWrite():
@@ -173,43 +174,30 @@ class TransportSFTPFile:
filetransfer.FX_PERMISSION_DENIED,
"%r was opened read-only." % self._unescaped_relpath)
if self._shouldTruncate():
- deferred = self._truncateFile()
- else:
- deferred = defer.succeed(None)
+ yield self._truncateFile()
self._written = True
if self._shouldAppend():
- deferred.addCallback(
- lambda ignored:
- self.transport.append_bytes(self._escaped_path, data))
+ yield self.transport.append_bytes(self._escaped_path, data)
else:
- deferred.addCallback(
- lambda ignored:
- self.transport.writeChunk(self._escaped_path, offset, data))
- return deferred
+ yield self.transport.writeChunk(self._escaped_path, offset, data)
@with_sftp_error
+ @defer.inlineCallbacks
def readChunk(self, offset, length):
"""See `ISFTPFile`."""
- deferred = self.transport.readv(
- self._escaped_path, [(offset, length)])
-
- def get_first_chunk(read_things):
- return next(read_things)[1]
-
- def handle_short_read(failure):
- """Handle short reads by reading what was available.
-
- Doing things this way around, by trying to read all the data
- requested and then handling the short read error, might be a bit
- inefficient, but the breezy sftp transport doesn't read past the
- end of files, so we don't need to worry too much about performance
- here.
- """
- failure.trap(bzr_errors.ShortReadvError)
- return self.readChunk(failure.value.offset, failure.value.actual)
-
- deferred.addCallback(get_first_chunk)
- return deferred.addErrback(handle_short_read)
+ try:
+ read_things = yield self.transport.readv(
+ self._escaped_path, [(offset, length)])
+ chunk = next(read_things)[1]
+ except bzr_errors.ShortReadvError as e:
+ # Handle short reads by reading what was available.
+ # Doing things this way around, by trying to read all the data
+ # requested and then handling the short read error, might be a
+ # bit inefficient, but the breezy sftp transport doesn't read
+ # past the end of files, so we don't need to worry too much
+ # about performance here.
+ chunk = yield self.readChunk(e.offset, e.actual)
+ defer.returnValue(chunk)
def setAttrs(self, attrs):
"""See `ISFTPFile`.
@@ -225,21 +213,19 @@ class TransportSFTPFile:
"""See `ISFTPFile`."""
return self._server.getAttrs(self._unescaped_relpath, False)
+ @defer.inlineCallbacks
def close(self):
"""See `ISFTPFile`."""
if self._written or not self._shouldCreate():
- return defer.succeed(None)
+ return
if self._shouldTruncate():
- return self._truncateFile()
-
- deferred = self.transport.has(self._escaped_path)
-
- def maybe_create_file(already_exists):
- if not already_exists:
- return self._truncateFile()
+ yield self._truncateFile()
+ return
- return deferred.addCallback(maybe_create_file)
+ already_exists = yield self.transport.has(self._escaped_path)
+ if not already_exists:
+ yield self._truncateFile()
def _get_transport_for_dir(directory):
@@ -311,48 +297,38 @@ class TransportSFTPServer:
yield (shortname, longname, attr_dict)
@with_sftp_error
+ @defer.inlineCallbacks
def openDirectory(self, path):
"""See `ISFTPServer`."""
escaped_path = urlutils.escape(path)
- deferred = self.transport.list_dir(escaped_path)
-
- def produce_entries_from_file_list(file_list):
- stats_deferred = self._stat_files_in_list(file_list, escaped_path)
- stats_deferred.addCallback(
- self._format_directory_entries, file_list)
- return stats_deferred
-
- return deferred.addCallback(
- produce_entries_from_file_list).addCallback(DirectoryListing)
+ file_list = yield self.transport.list_dir(escaped_path)
+ stat_results = yield self._stat_files_in_list(file_list, escaped_path)
+ entries = self._format_directory_entries(stat_results, file_list)
+ defer.returnValue(DirectoryListing(entries))
@with_sftp_error
+ @defer.inlineCallbacks
def openFile(self, path, flags, attrs):
"""See `ISFTPServer`."""
directory = os.path.dirname(path)
- deferred = self.transport.stat(directory)
-
- def open_file(stat_result):
- if stat.S_ISDIR(stat_result.st_mode):
- return TransportSFTPFile(self.transport, path, flags, self)
- else:
- raise filetransfer.SFTPError(
- filetransfer.FX_NO_SUCH_FILE, directory)
-
- return deferred.addCallback(open_file)
+ stat_result = yield self.transport.stat(directory)
+ if stat.S_ISDIR(stat_result.st_mode):
+ defer.returnValue(
+ TransportSFTPFile(self.transport, path, flags, self))
+ else:
+ raise filetransfer.SFTPError(
+ filetransfer.FX_NO_SUCH_FILE, directory)
def readLink(self, path):
"""See `ISFTPServer`."""
raise NotImplementedError()
+ @defer.inlineCallbacks
def realPath(self, relpath):
"""See `ISFTPServer`."""
- deferred = self.transport.local_realPath(urlutils.escape(relpath))
-
- def unescape_path(path):
- unescaped_path = urlutils.unescape(path)
- return unescaped_path.encode('utf-8')
-
- return deferred.addCallback(unescape_path)
+ path = yield self.transport.local_realPath(urlutils.escape(relpath))
+ unescaped_path = urlutils.unescape(path)
+ defer.returnValue(unescaped_path.encode('utf-8'))
def setAttrs(self, path, attrs):
"""See `ISFTPServer`.
@@ -378,13 +354,14 @@ class TransportSFTPServer:
}
@with_sftp_error
+ @defer.inlineCallbacks
def getAttrs(self, path, followLinks):
"""See `ISFTPServer`.
This just delegates to TransportSFTPFile's implementation.
"""
- deferred = self.transport.stat(urlutils.escape(path))
- return deferred.addCallback(self._translate_stat)
+ stat_result = yield self.transport.stat(urlutils.escape(path))
+ defer.returnValue(self._translate_stat(stat_result))
def gotVersion(self, otherVersion, extensionData):
"""See `ISFTPServer`."""
diff --git a/lib/lp/codehosting/tests/test_sftp.py b/lib/lp/codehosting/tests/test_sftp.py
index d827421..794fb47 100644
--- a/lib/lp/codehosting/tests/test_sftp.py
+++ b/lib/lp/codehosting/tests/test_sftp.py
@@ -1,4 +1,4 @@
-# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2020 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for the transport-backed SFTP server implementation."""
@@ -16,10 +16,9 @@ from breezy.tests import TestCaseInTempDir
from breezy.transport import get_transport
from breezy.transport.memory import MemoryTransport
from lazr.sshserver.sftp import FileIsADirectory
-from testtools.twistedsupport import (
- assert_fails_with,
- AsynchronousDeferredRunTest,
- )
+from testtools.matchers import MatchesStructure
+from testtools.testcase import ExpectedException
+from testtools.twistedsupport import AsynchronousDeferredRunTest
from twisted.conch.interfaces import ISFTPServer
from twisted.conch.ls import lsLine
from twisted.conch.ssh import filetransfer
@@ -184,16 +183,13 @@ class TestSFTPFile(TestCaseInTempDir, SFTPTestMixin):
FatLocalTransport(urlutils.local_path_to_url('.')))
self._sftp_server = TransportSFTPServer(transport)
+ @defer.inlineCallbacks
def assertSFTPError(self, sftp_code, function, *args, **kwargs):
"""Assert that calling functions fails with `sftp_code`."""
- deferred = defer.maybeDeferred(function, *args, **kwargs)
- deferred = assert_fails_with(deferred, filetransfer.SFTPError)
-
- def check_sftp_code(exception):
- self.assertEqual(sftp_code, exception.code)
- return exception
-
- return deferred.addCallback(check_sftp_code)
+ with ExpectedException(
+ filetransfer.SFTPError,
+ MatchesStructure.byEquality(code=sftp_code)):
+ yield function(*args, **kwargs)
def openFile(self, path, flags, attrs):
return self._sftp_server.openFile(path, flags, attrs)
@@ -218,213 +214,183 @@ class TestSFTPFile(TestCaseInTempDir, SFTPTestMixin):
self.openFile,
'%s/%s' % (nondirectory, self.getPathSegment()), 0, {})
+ @defer.inlineCallbacks
def test_createEmptyFile(self):
# Opening a file with create flags and then closing it will create a
# new, empty file.
filename = self.getPathSegment()
- deferred = self.openFile(filename, filetransfer.FXF_CREAT, {})
- return deferred.addCallback(
- self._test_createEmptyFile_callback, filename)
-
- def _test_createEmptyFile_callback(self, handle, filename):
- deferred = handle.close()
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('', filename))
+ handle = yield self.openFile(filename, filetransfer.FXF_CREAT, {})
+ yield handle.close()
+ self.assertFileEqual('', filename)
+ @defer.inlineCallbacks
def test_createFileWithData(self):
# writeChunk writes data to the file.
filename = self.getPathSegment()
- deferred = self.openFile(
+ handle = yield self.openFile(
filename, filetransfer.FXF_CREAT | filetransfer.FXF_WRITE, {})
- return deferred.addCallback(
- self._test_createFileWithData_callback, filename)
-
- def _test_createFileWithData_callback(self, handle, filename):
- deferred = handle.writeChunk(0, 'bar')
- deferred.addCallback(lambda ignored: handle.close())
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('bar', filename))
+ yield handle.writeChunk(0, 'bar')
+ yield handle.close()
+ self.assertFileEqual('bar', filename)
+ @defer.inlineCallbacks
def test_writeChunkToFile(self):
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'contents')])
- deferred = self.openFile(filename, filetransfer.FXF_WRITE, {})
- return deferred.addCallback(
- self._test_writeChunkToFile_callback, filename)
-
- def _test_writeChunkToFile_callback(self, handle, filename):
- deferred = handle.writeChunk(1, 'qux')
- deferred.addCallback(lambda ignored: handle.close())
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('cquxents', filename))
+ handle = yield self.openFile(filename, filetransfer.FXF_WRITE, {})
+ yield handle.writeChunk(1, 'qux')
+ yield handle.close()
+ self.assertFileEqual('cquxents', filename)
+ @defer.inlineCallbacks
def test_writeTwoChunks(self):
# We can write one chunk after another.
filename = self.getPathSegment()
- deferred = self.openFile(
+ handle = yield self.openFile(
filename, filetransfer.FXF_WRITE | filetransfer.FXF_TRUNC, {})
+ yield handle.writeChunk(1, 'a')
+ yield handle.writeChunk(2, 'a')
+ yield handle.close()
+ self.assertFileEqual(chr(0) + 'aa', filename)
- def write_chunks(handle):
- deferred = handle.writeChunk(1, 'a')
- deferred.addCallback(lambda ignored: handle.writeChunk(2, 'a'))
- deferred.addCallback(lambda ignored: handle.close())
-
- deferred.addCallback(write_chunks)
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual(chr(0) + 'aa', filename))
-
+ @defer.inlineCallbacks
def test_writeChunkToNonexistentFile(self):
# Writing a chunk of data to a non-existent file creates the file even
# if the create flag is not set. NOTE: This behaviour is unspecified
# in the SFTP drafts at
# http://tools.ietf.org/wg/secsh/draft-ietf-secsh-filexfer/
filename = self.getPathSegment()
- deferred = self.openFile(filename, filetransfer.FXF_WRITE, {})
- return deferred.addCallback(
- self._test_writeChunkToNonexistentFile_callback, filename)
-
- def _test_writeChunkToNonexistentFile_callback(self, handle, filename):
- deferred = handle.writeChunk(1, 'qux')
- deferred.addCallback(lambda ignored: handle.close())
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual(chr(0) + 'qux', filename))
+ handle = yield self.openFile(filename, filetransfer.FXF_WRITE, {})
+ yield handle.writeChunk(1, 'qux')
+ yield handle.close()
+ self.assertFileEqual(chr(0) + 'qux', filename)
+ @defer.inlineCallbacks
def test_writeToReadOpenedFile(self):
# writeChunk raises an error if we try to write to a file that has
# been opened only for reading.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, filetransfer.FXF_READ, {})
- return deferred.addCallback(
- self._test_writeToReadOpenedFile_callback)
-
- def _test_writeToReadOpenedFile_callback(self, handle):
- return self.assertSFTPError(
+ handle = yield self.openFile(filename, filetransfer.FXF_READ, {})
+ yield self.assertSFTPError(
filetransfer.FX_PERMISSION_DENIED,
handle.writeChunk, 0, 'new content')
+ @defer.inlineCallbacks
def test_overwriteFile(self):
# writeChunk overwrites a file if write, create and trunk flags are
# set.
self.build_tree_contents([('foo', 'contents')])
- deferred = self.openFile(
+ handle = yield self.openFile(
'foo', filetransfer.FXF_CREAT | filetransfer.FXF_TRUNC |
filetransfer.FXF_WRITE, {})
- return deferred.addCallback(self._test_overwriteFile_callback)
-
- def _test_overwriteFile_callback(self, handle):
- deferred = handle.writeChunk(0, 'bar')
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('bar', 'foo'))
+ yield handle.writeChunk(0, 'bar')
+ self.assertFileEqual('bar', 'foo')
+ @defer.inlineCallbacks
def test_writeToAppendingFileIgnoresOffset(self):
# If a file is opened with the 'append' flag, writeChunk ignores its
# offset parameter.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, filetransfer.FXF_APPEND, {})
- return deferred.addCallback(
- self._test_writeToAppendingFileIgnoresOffset_cb, filename)
-
- def _test_writeToAppendingFileIgnoresOffset_cb(self, handle, filename):
- deferred = handle.writeChunk(0, 'baz')
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('barbaz', filename))
+ handle = yield self.openFile(filename, filetransfer.FXF_APPEND, {})
+ yield handle.writeChunk(0, 'baz')
+ self.assertFileEqual('barbaz', filename)
+ @defer.inlineCallbacks
def test_openAndCloseExistingFileLeavesUnchanged(self):
# If we open a file with the 'create' flag and without the 'truncate'
# flag, the file remains unchanged.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, filetransfer.FXF_CREAT, {})
- return deferred.addCallback(
- self._test_openAndCloseExistingFileUnchanged_cb, filename)
-
- def _test_openAndCloseExistingFileUnchanged_cb(self, handle, filename):
- deferred = handle.close()
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('bar', filename))
+ handle = yield self.openFile(filename, filetransfer.FXF_CREAT, {})
+ yield handle.close()
+ self.assertFileEqual('bar', filename)
+ @defer.inlineCallbacks
def test_openAndCloseExistingFileTruncation(self):
# If we open a file with the 'create' flag and the 'truncate' flag,
# the file is reset to empty.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(
+ handle = yield self.openFile(
filename, filetransfer.FXF_TRUNC | filetransfer.FXF_CREAT, {})
- return deferred.addCallback(
- self._test_openAndCloseExistingFileTruncation_cb, filename)
-
- def _test_openAndCloseExistingFileTruncation_cb(self, handle, filename):
- deferred = handle.close()
- return deferred.addCallback(
- lambda ignored: self.assertFileEqual('', filename))
+ yield handle.close()
+ self.assertFileEqual('', filename)
+ @defer.inlineCallbacks
def test_writeChunkOnDirectory(self):
# Errors in writeChunk are translated to SFTPErrors.
directory = self.getPathSegment()
os.mkdir(directory)
- deferred = self.openFile(directory, filetransfer.FXF_WRITE, {})
- deferred.addCallback(lambda handle: handle.writeChunk(0, 'bar'))
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ handle = yield self.openFile(directory, filetransfer.FXF_WRITE, {})
+ with ExpectedException(filetransfer.SFTPError):
+ yield handle.writeChunk(0, 'bar')
+ @defer.inlineCallbacks
def test_readChunk(self):
# readChunk reads a chunk of data from the file.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.readChunk(1, 2))
- return deferred.addCallback(self.assertEqual, 'ar')
+ handle = yield self.openFile(filename, 0, {})
+ chunk = yield handle.readChunk(1, 2)
+ self.assertEqual('ar', chunk)
+ @defer.inlineCallbacks
def test_readChunkPastEndOfFile(self):
# readChunk returns the rest of the file if it is asked to read past
# the end of the file.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.readChunk(2, 10))
- return deferred.addCallback(self.assertEqual, 'r')
+ handle = yield self.openFile(filename, 0, {})
+ chunk = yield handle.readChunk(2, 10)
+ self.assertEqual('r', chunk)
+ @defer.inlineCallbacks
def test_readChunkEOF(self):
# readChunk returns the empty string if it encounters end-of-file
# before reading any data.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.readChunk(3, 10))
- return deferred.addCallback(self.assertEqual, '')
+ handle = yield self.openFile(filename, 0, {})
+ chunk = yield handle.readChunk(3, 10)
+ self.assertEqual('', chunk)
+ @defer.inlineCallbacks
def test_readChunkError(self):
# Errors in readChunk are translated to SFTPErrors.
filename = self.getPathSegment()
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.readChunk(1, 2))
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ handle = yield self.openFile(filename, 0, {})
+ with ExpectedException(filetransfer.SFTPError):
+ yield handle.readChunk(1, 2)
+ @defer.inlineCallbacks
def test_setAttrs(self):
# setAttrs on TransportSFTPFile does nothing.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.openFile(filename, 0, {})
- return deferred.addCallback(lambda handle: handle.setAttrs({}))
+ handle = yield self.openFile(filename, 0, {})
+ yield handle.setAttrs({})
+ @defer.inlineCallbacks
def test_getAttrs(self):
# getAttrs on TransportSFTPFile returns a dictionary consistent
# with the results of os.stat.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
stat_value = os.stat(filename)
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.getAttrs())
- return deferred.addCallback(self.checkAttrs, stat_value)
+ handle = yield self.openFile(filename, 0, {})
+ attrs = yield handle.getAttrs()
+ self.checkAttrs(attrs, stat_value)
+ @defer.inlineCallbacks
def test_getAttrsError(self):
# Errors in getAttrs on TransportSFTPFile are translated into
# SFTPErrors.
filename = self.getPathSegment()
- deferred = self.openFile(filename, 0, {})
- deferred.addCallback(lambda handle: handle.getAttrs())
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ handle = yield self.openFile(filename, 0, {})
+ with ExpectedException(filetransfer.SFTPError):
+ yield handle.getAttrs()
class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
@@ -439,109 +405,104 @@ class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
FatLocalTransport(urlutils.local_path_to_url('.')))
self.sftp_server = TransportSFTPServer(transport)
+ @defer.inlineCallbacks
def test_serverSetAttrs(self):
# setAttrs on the TransportSFTPServer doesn't do anything either.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- self.sftp_server.setAttrs(filename, {})
+ yield self.sftp_server.setAttrs(filename, {})
+ @defer.inlineCallbacks
def test_serverGetAttrs(self):
# getAttrs on the TransportSFTPServer also returns a dictionary
# consistent with the results of os.stat.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
stat_value = os.stat(filename)
- deferred = self.sftp_server.getAttrs(filename, False)
- return deferred.addCallback(self.checkAttrs, stat_value)
+ attrs = yield self.sftp_server.getAttrs(filename, False)
+ self.checkAttrs(attrs, stat_value)
+ @defer.inlineCallbacks
def test_serverGetAttrsError(self):
# Errors in getAttrs on the TransportSFTPServer are translated into
# SFTPErrors.
nonexistent_file = self.getPathSegment()
- deferred = self.sftp_server.getAttrs(nonexistent_file, False)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.getAttrs(nonexistent_file, False)
+ @defer.inlineCallbacks
def test_removeFile(self):
# removeFile removes the file.
filename = self.getPathSegment()
self.build_tree_contents([(filename, 'bar')])
- deferred = self.sftp_server.removeFile(filename)
-
- def assertFileRemoved(ignored):
- self.assertFalse(file_exists(filename))
-
- return deferred.addCallback(assertFileRemoved)
+ yield self.sftp_server.removeFile(filename)
+ self.assertFalse(file_exists(filename))
+ @defer.inlineCallbacks
def test_removeFileError(self):
# Errors in removeFile are translated into SFTPErrors.
filename = self.getPathSegment()
- deferred = self.sftp_server.removeFile(filename)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.removeFile(filename)
+ @defer.inlineCallbacks
def test_removeFile_directory(self):
# Errors in removeFile are translated into SFTPErrors.
filename = self.getPathSegment()
self.build_tree_contents([(filename + '/',)])
- deferred = self.sftp_server.removeFile(filename)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.removeFile(filename)
+ @defer.inlineCallbacks
def test_renameFile(self):
# renameFile renames the file.
orig_filename = self.getPathSegment()
new_filename = self.getPathSegment()
self.build_tree_contents([(orig_filename, 'bar')])
- deferred = self.sftp_server.renameFile(orig_filename, new_filename)
-
- def assertFileRenamed(ignored):
- self.assertFalse(file_exists(orig_filename))
- self.assertTrue(file_exists(new_filename))
-
- return deferred.addCallback(assertFileRenamed)
+ yield self.sftp_server.renameFile(orig_filename, new_filename)
+ self.assertFalse(file_exists(orig_filename))
+ self.assertTrue(file_exists(new_filename))
+ @defer.inlineCallbacks
def test_renameFileError(self):
# Errors in renameFile are translated into SFTPErrors.
orig_filename = self.getPathSegment()
new_filename = self.getPathSegment()
- deferred = self.sftp_server.renameFile(orig_filename, new_filename)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.renameFile(orig_filename, new_filename)
+ @defer.inlineCallbacks
def test_makeDirectory(self):
# makeDirectory makes the directory.
directory = self.getPathSegment()
- deferred = self.sftp_server.makeDirectory(
- directory, {'permissions': 0o777})
-
- def assertDirectoryExists(ignored):
- self.assertTrue(
- os.path.isdir(directory), '%r is not a directory' % directory)
- self.assertEqual(0o40777, os.stat(directory).st_mode)
-
- return deferred.addCallback(assertDirectoryExists)
+ yield self.sftp_server.makeDirectory(directory, {'permissions': 0o777})
+ self.assertTrue(
+ os.path.isdir(directory), '%r is not a directory' % directory)
+ self.assertEqual(0o40777, os.stat(directory).st_mode)
+ @defer.inlineCallbacks
def test_makeDirectoryError(self):
# Errors in makeDirectory are translated into SFTPErrors.
nonexistent = self.getPathSegment()
nonexistent_child = '%s/%s' % (nonexistent, self.getPathSegment())
- deferred = self.sftp_server.makeDirectory(
- nonexistent_child, {'permissions': 0o777})
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.makeDirectory(
+ nonexistent_child, {'permissions': 0o777})
+ @defer.inlineCallbacks
def test_removeDirectory(self):
# removeDirectory removes the directory.
directory = self.getPathSegment()
os.mkdir(directory)
- deferred = self.sftp_server.removeDirectory(directory)
-
- def assertDirectoryRemoved(ignored):
- self.assertFalse(file_exists(directory))
-
- return deferred.addCallback(assertDirectoryRemoved)
+ yield self.sftp_server.removeDirectory(directory)
+ self.assertFalse(file_exists(directory))
+ @defer.inlineCallbacks
def test_removeDirectoryError(self):
# Errors in removeDirectory are translated into SFTPErrors.
directory = self.getPathSegment()
- deferred = self.sftp_server.removeDirectory(directory)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.removeDirectory(directory)
def test_gotVersion(self):
# gotVersion returns an empty dictionary.
@@ -554,12 +515,13 @@ class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
NotImplementedError, self.sftp_server.extendedRequest,
'foo', 'bar')
+ @defer.inlineCallbacks
def test_realPath(self):
# realPath returns the absolute path of the file.
src, dst = self.getPathSegment(), self.getPathSegment()
os.symlink(src, dst)
- deferred = self.sftp_server.realPath(dst)
- return deferred.addCallback(self.assertEqual, os.path.abspath(src))
+ path = yield self.sftp_server.realPath(dst)
+ self.assertEqual(os.path.abspath(src), path)
def test_makeLink(self):
# makeLink is not supported.
@@ -573,6 +535,7 @@ class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
NotImplementedError, self.sftp_server.readLink,
self.getPathSegment())
+ @defer.inlineCallbacks
def test_openDirectory(self):
# openDirectory returns an iterator that iterates over the contents of
# the directory.
@@ -583,7 +546,11 @@ class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
parent_dir + '/',
'%s/%s/' % (parent_dir, child_dir),
'%s/%s' % (parent_dir, child_file)])
- deferred = self.sftp_server.openDirectory(parent_dir)
+ directory = yield self.sftp_server.openDirectory(parent_dir)
+ entries = list(directory)
+ directory.close()
+ names = [entry[0] for entry in entries]
+ self.assertEqual(set(names), set([child_dir, child_file]))
def check_entry(entries, filename):
t = get_transport('.')
@@ -595,35 +562,26 @@ class TestSFTPServer(TestCaseInTempDir, SFTPTestMixin):
self.assertEqual(lsLine(name, stat), longname)
self.assertEqual(self.sftp_server._translate_stat(stat), attrs)
- def check_open_directory(directory):
- entries = list(directory)
- directory.close()
- names = [entry[0] for entry in entries]
- self.assertEqual(set(names), set([child_dir, child_file]))
- check_entry(entries, child_dir)
- check_entry(entries, child_file)
-
- return deferred.addCallback(check_open_directory)
+ check_entry(entries, child_dir)
+ check_entry(entries, child_file)
+ @defer.inlineCallbacks
def test_openDirectoryError(self):
# Errors in openDirectory are translated into SFTPErrors.
nonexistent = self.getPathSegment()
- deferred = self.sftp_server.openDirectory(nonexistent)
- return assert_fails_with(deferred, filetransfer.SFTPError)
+ with ExpectedException(filetransfer.SFTPError):
+ yield self.sftp_server.openDirectory(nonexistent)
+ @defer.inlineCallbacks
def test_openDirectoryMemory(self):
"""openDirectory works on MemoryTransport."""
transport = MemoryTransport()
transport.put_bytes('hello', b'hello')
sftp_server = TransportSFTPServer(AsyncTransport(transport))
- deferred = sftp_server.openDirectory('.')
-
- def check_directory(directory):
- with closing(directory):
- names = [entry[0] for entry in directory]
- self.assertEqual(['hello'], names)
-
- return deferred.addCallback(check_directory)
+ directory = yield sftp_server.openDirectory('.')
+ with closing(directory):
+ names = [entry[0] for entry in directory]
+ self.assertEqual(['hello'], names)
def test__format_directory_entries_with_MemoryStat(self):
"""format_directory_entries works with MemoryStat.