Index: tests/s3/test_resumable_downloads.py |
diff --git a/boto/tests/test_resumable_downloads.py b/tests/s3/test_resumable_downloads.py |
similarity index 91% |
rename from boto/tests/test_resumable_downloads.py |
rename to tests/s3/test_resumable_downloads.py |
index d7ced7f33ab041d1cd09952c49f6dfad04167236..4e3e6bacf15c05a8eebb9e24f07c9fb62e8537aa 100755 |
--- a/boto/tests/test_resumable_downloads.py |
+++ b/tests/s3/test_resumable_downloads.py |
@@ -45,7 +45,16 @@ from boto.s3.resumable_download_handler import ResumableDownloadHandler |
from boto.exception import ResumableTransferDisposition |
from boto.exception import ResumableDownloadException |
from boto.exception import StorageResponseError |
-from boto.tests.cb_test_harnass import CallbackTestHarnass |
+from cb_test_harnass import CallbackTestHarnass |
+ |
+# We don't use the OAuth2 authentication plugin directly; importing it here |
+# ensures that it's loaded and available by default. |
+try: |
+ from oauth2_plugin import oauth2_plugin |
+except ImportError: |
+ # Do nothing - if user doesn't have OAuth2 configured it doesn't matter; |
+ # and if they do, the tests will fail (as they should in that case). |
+ pass |
class ResumableDownloadTests(unittest.TestCase): |
@@ -113,9 +122,9 @@ class ResumableDownloadTests(unittest.TestCase): |
# Create the test bucket. |
hostname = socket.gethostname().split('.')[0] |
- uri_base_str = 'gs://res_download_test_%s_%s_%s' % ( |
+ uri_base_str = 'gs://res-download-test-%s-%s-%s' % ( |
hostname, os.getpid(), int(time.time())) |
- cls.src_bucket_uri = storage_uri('%s_dst' % uri_base_str) |
+ cls.src_bucket_uri = storage_uri('%s-dst' % uri_base_str) |
cls.src_bucket_uri.create_bucket() |
# Create test source objects. |
@@ -212,7 +221,8 @@ class ResumableDownloadTests(unittest.TestCase): |
# We'll get a ResumableDownloadException at this point because |
# of CallbackTestHarnass (above). Check that the tracker file was |
# created correctly. |
- self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
+ self.assertEqual(e.disposition, |
+ ResumableTransferDisposition.ABORT_CUR_PROCESS) |
self.assertTrue(os.path.exists(self.tracker_file_name)) |
f = open(self.tracker_file_name) |
etag_line = f.readline() |
@@ -237,6 +247,22 @@ class ResumableDownloadTests(unittest.TestCase): |
self.assertEqual(self.small_src_key_as_string, |
self.small_src_key.get_contents_as_string()) |
+ def test_broken_pipe_recovery(self): |
+ """ |
+ Tests handling of a Broken Pipe (which interacts with an httplib bug) |
+ """ |
+ exception = IOError(errno.EPIPE, "Broken pipe") |
+ harnass = CallbackTestHarnass(exception=exception) |
+ res_download_handler = ResumableDownloadHandler(num_retries=1) |
+ self.small_src_key.get_contents_to_file( |
+ self.dst_fp, cb=harnass.call, |
+ res_download_handler=res_download_handler) |
+ # Ensure downloaded object has correct content. |
+ self.assertEqual(self.small_src_key_size, |
+ get_cur_file_size(self.dst_fp)) |
+ self.assertEqual(self.small_src_key_as_string, |
+ self.small_src_key.get_contents_as_string()) |
+ |
def test_non_retryable_exception_handling(self): |
""" |
Tests resumable download that fails with a non-retryable exception |
@@ -303,7 +329,8 @@ class ResumableDownloadTests(unittest.TestCase): |
res_download_handler=res_download_handler) |
self.fail('Did not get expected ResumableDownloadException') |
except ResumableDownloadException, e: |
- self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
+ self.assertEqual(e.disposition, |
+ ResumableTransferDisposition.ABORT_CUR_PROCESS) |
# Ensure a tracker file survived. |
self.assertTrue(os.path.exists(self.tracker_file_name)) |
# Try it one more time; this time should succeed. |
@@ -370,7 +397,9 @@ class ResumableDownloadTests(unittest.TestCase): |
res_download_handler=res_download_handler) |
self.fail('Did not get expected ResumableDownloadException') |
except ResumableDownloadException, e: |
- self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
+ # First abort (from harnass-forced failure) should be |
+ # ABORT_CUR_PROCESS. |
+ self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT_CUR_PROCESS) |
# Ensure a tracker file survived. |
self.assertTrue(os.path.exists(self.tracker_file_name)) |
# Try it again, this time with different src key (simulating an |
@@ -380,6 +409,8 @@ class ResumableDownloadTests(unittest.TestCase): |
self.dst_fp, res_download_handler=res_download_handler) |
self.fail('Did not get expected ResumableDownloadException') |
except ResumableDownloadException, e: |
+ # This abort should be a hard abort (object size changing during |
+ # transfer). |
self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
self.assertNotEqual( |
e.message.find('md5 signature doesn\'t match etag'), -1) |
@@ -403,7 +434,10 @@ class ResumableDownloadTests(unittest.TestCase): |
res_download_handler=res_download_handler) |
self.fail('Did not get expected ResumableDownloadException') |
except ResumableDownloadException, e: |
- self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
+ # First abort (from harnass-forced failure) should be |
+ # ABORT_CUR_PROCESS. |
+ self.assertEqual(e.disposition, |
+ ResumableTransferDisposition.ABORT_CUR_PROCESS) |
# Ensure a tracker file survived. |
self.assertTrue(os.path.exists(self.tracker_file_name)) |
# Before trying again change the first byte of the file fragment |
@@ -419,6 +453,8 @@ class ResumableDownloadTests(unittest.TestCase): |
res_download_handler=res_download_handler) |
self.fail('Did not get expected ResumableDownloadException') |
except ResumableDownloadException, e: |
+ # This abort should be a hard abort (file content changing during |
+ # transfer). |
self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) |
self.assertNotEqual( |
e.message.find('md5 signature doesn\'t match etag'), -1) |