| 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)
|
|
|