Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: tests/s3/test_resumable_uploads.py

Issue 8386013: Merging in latest boto. (Closed) Base URL: svn://svn.chromium.org/boto
Patch Set: Redoing vendor drop by deleting and then merging. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tests/s3/test_resumable_downloads.py ('k') | tests/s3/test_versioning.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2010 Google Inc. 3 # Copyright 2010 Google Inc.
4 # 4 #
5 # Permission is hereby granted, free of charge, to any person obtaining a 5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the 6 # copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including 7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish, dis- 8 # without limitation the rights to use, copy, modify, merge, publish, dis-
9 # tribute, sublicense, and/or sell copies of the Software, and to permit 9 # tribute, sublicense, and/or sell copies of the Software, and to permit
10 # persons to whom the Software is furnished to do so, subject to the fol- 10 # persons to whom the Software is furnished to do so, subject to the fol-
11 # lowing conditions: 11 # lowing conditions:
12 # 12 #
13 # The above copyright notice and this permission notice shall be included 13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software. 14 # in all copies or substantial portions of the Software.
15 # 15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
18 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 18 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 # IN THE SOFTWARE. 22 # IN THE SOFTWARE.
23 23
24 """ 24 """
25 Tests of resumable uploads. 25 Tests of Google Cloud Storage resumable uploads.
26 """ 26 """
27 27
28 import errno 28 import errno
29 import getopt 29 import getopt
30 import os 30 import os
31 import random 31 import random
32 import re 32 import re
33 import shutil 33 import shutil
34 import socket 34 import socket
35 import StringIO 35 import StringIO
36 import sys 36 import sys
37 import tempfile 37 import tempfile
38 import time 38 import time
39 import unittest 39 import unittest
40 40
41 import boto 41 import boto
42 from boto.exception import GSResponseError 42 from boto.exception import GSResponseError
43 from boto.gs.resumable_upload_handler import ResumableUploadHandler 43 from boto.gs.resumable_upload_handler import ResumableUploadHandler
44 from boto.exception import InvalidUriError
44 from boto.exception import ResumableTransferDisposition 45 from boto.exception import ResumableTransferDisposition
45 from boto.exception import ResumableUploadException 46 from boto.exception import ResumableUploadException
46 from boto.exception import StorageResponseError 47 from boto.exception import StorageResponseError
47 from boto.tests.cb_test_harnass import CallbackTestHarnass 48 from cb_test_harnass import CallbackTestHarnass
49
50 # We don't use the OAuth2 authentication plugin directly; importing it here
51 # ensures that it's loaded and available by default.
52 try:
53 from oauth2_plugin import oauth2_plugin
54 except ImportError:
55 # Do nothing - if user doesn't have OAuth2 configured it doesn't matter;
56 # and if they do, the tests will fail (as they should in that case).
57 pass
48 58
49 59
50 class ResumableUploadTests(unittest.TestCase): 60 class ResumableUploadTests(unittest.TestCase):
51 """ 61 """
52 Resumable upload test suite. 62 Resumable upload test suite.
53 """ 63 """
54 64
55 def get_suite_description(self): 65 def get_suite_description(self):
56 return 'Resumable upload test suite' 66 return 'Resumable upload test suite'
57 67
58 @classmethod 68 def setUp(self):
59 def setUp(cls):
60 """ 69 """
61 Creates dst_key needed by all tests. 70 Creates dst_key needed by all tests.
62 71
63 This method's namingCase is required by the unittest framework. 72 This method's namingCase is required by the unittest framework.
64 """ 73 """
65 cls.dst_key = cls.dst_key_uri.new_key(validate=False) 74 self.dst_key = self.dst_key_uri.new_key(validate=False)
66 75
67 @classmethod 76 def tearDown(self):
68 def tearDown(cls):
69 """ 77 """
70 Deletes any objects or files created by last test run. 78 Deletes any objects or files created by last test run.
71 79
72 This method's namingCase is required by the unittest framework. 80 This method's namingCase is required by the unittest framework.
73 """ 81 """
74 try: 82 try:
75 cls.dst_key_uri.delete_key() 83 self.dst_key_uri.delete_key()
76 except GSResponseError: 84 except GSResponseError:
77 # Ignore possible not-found error. 85 # Ignore possible not-found error.
78 pass 86 pass
79 # Recursively delete dst dir and then re-create it, so in effect we 87 # Recursively delete dst dir and then re-create it, so in effect we
80 # remove all dirs and files under that directory. 88 # remove all dirs and files under that directory.
81 shutil.rmtree(cls.tmp_dir) 89 shutil.rmtree(self.tmp_dir)
82 os.mkdir(cls.tmp_dir) 90 os.mkdir(self.tmp_dir)
83 91
84 @staticmethod 92 @staticmethod
85 def build_test_input_file(size): 93 def build_test_input_file(size):
86 buf = [] 94 buf = []
87 # I manually construct the random data here instead of calling 95 # I manually construct the random data here instead of calling
88 # os.urandom() because I want to constrain the range of data (in 96 # os.urandom() because I want to constrain the range of data (in
89 # this case to 0'..'9') so the test 97 # this case to 0'..'9') so the test
90 # code can easily overwrite part of the StringIO file with 98 # code can easily overwrite part of the StringIO file with
91 # known-to-be-different values. 99 # known-to-be-different values.
92 for i in range(size): 100 for i in range(size):
93 buf.append(str(random.randint(0, 9))) 101 buf.append(str(random.randint(0, 9)))
94 file_as_string = ''.join(buf) 102 file_as_string = ''.join(buf)
95 return (file_as_string, StringIO.StringIO(file_as_string)) 103 return (file_as_string, StringIO.StringIO(file_as_string))
96 104
97 @classmethod 105 @classmethod
106 def get_dst_bucket_uri(cls, debug):
107 """A unique bucket to test."""
108 hostname = socket.gethostname().split('.')[0]
109 uri_base_str = 'gs://res-upload-test-%s-%s-%s' % (
110 hostname, os.getpid(), int(time.time()))
111 return boto.storage_uri('%s-dst' % uri_base_str, debug=debug)
112
113 @classmethod
114 def get_dst_key_uri(cls):
115 """A key to test."""
116 return cls.dst_bucket_uri.clone_replace_name('obj')
117
118 @classmethod
119 def get_staged_host(cls):
120 """URL of an existing bucket."""
121 return 'pub.commondatastorage.googleapis.com'
122
123 @classmethod
124 def get_invalid_upload_id(cls):
125 return (
126 'http://%s/?upload_id='
127 'AyzB2Uo74W4EYxyi5dp_-r68jz8rtbvshsv4TX7srJVkJ57CxTY5Dw2' % (
128 cls.get_staged_host()))
129
130 @classmethod
98 def set_up_class(cls, debug): 131 def set_up_class(cls, debug):
99 """ 132 """
100 Initializes test suite. 133 Initializes test suite.
101 """ 134 """
102 135
103 # Use a designated tmpdir prefix to make it easy to find the end of 136 # Use a designated tmpdir prefix to make it easy to find the end of
104 # the tmp path. 137 # the tmp path.
105 cls.tmpdir_prefix = 'tmp_resumable_upload_test' 138 cls.tmpdir_prefix = 'tmp_resumable_upload_test'
106 139
107 # Create test source file data. 140 # Create test source file data.
108 cls.empty_src_file_size = 0 141 cls.empty_src_file_size = 0
109 (cls.empty_src_file_as_string, cls.empty_src_file) = ( 142 (cls.empty_src_file_as_string, cls.empty_src_file) = (
110 cls.build_test_input_file(cls.empty_src_file_size)) 143 cls.build_test_input_file(cls.empty_src_file_size))
111 cls.small_src_file_size = 2 * 1024 # 2 KB. 144 cls.small_src_file_size = 2 * 1024 # 2 KB.
112 (cls.small_src_file_as_string, cls.small_src_file) = ( 145 (cls.small_src_file_as_string, cls.small_src_file) = (
113 cls.build_test_input_file(cls.small_src_file_size)) 146 cls.build_test_input_file(cls.small_src_file_size))
114 cls.larger_src_file_size = 500 * 1024 # 500 KB. 147 cls.larger_src_file_size = 500 * 1024 # 500 KB.
115 (cls.larger_src_file_as_string, cls.larger_src_file) = ( 148 (cls.larger_src_file_as_string, cls.larger_src_file) = (
116 cls.build_test_input_file(cls.larger_src_file_size)) 149 cls.build_test_input_file(cls.larger_src_file_size))
117 cls.largest_src_file_size = 1024 * 1024 # 1 MB. 150 cls.largest_src_file_size = 1024 * 1024 # 1 MB.
118 (cls.largest_src_file_as_string, cls.largest_src_file) = ( 151 (cls.largest_src_file_as_string, cls.largest_src_file) = (
119 cls.build_test_input_file(cls.largest_src_file_size)) 152 cls.build_test_input_file(cls.largest_src_file_size))
120 153
121 # Create temp dir. 154 # Create temp dir.
122 cls.tmp_dir = tempfile.mkdtemp(prefix=cls.tmpdir_prefix) 155 cls.tmp_dir = tempfile.mkdtemp(prefix=cls.tmpdir_prefix)
123 156
124 # Create the test bucket. 157 # Create the test bucket.
125 hostname = socket.gethostname().split('.')[0] 158 cls.dst_bucket_uri = cls.get_dst_bucket_uri(debug)
126 cls.uri_base_str = 'gs://res_upload_test_%s_%s_%s' % (
127 hostname, os.getpid(), int(time.time()))
128 cls.dst_bucket_uri = boto.storage_uri('%s_dst' %
129 cls.uri_base_str, debug=debug)
130 cls.dst_bucket_uri.create_bucket() 159 cls.dst_bucket_uri.create_bucket()
131 cls.dst_key_uri = cls.dst_bucket_uri.clone_replace_name('obj') 160 cls.dst_key_uri = cls.get_dst_key_uri()
132 161
133 cls.tracker_file_name = '%s%suri_tracker' % (cls.tmp_dir, os.sep) 162 cls.tracker_file_name = '%s%suri_tracker' % (cls.tmp_dir, os.sep)
134 163
135 cls.syntactically_invalid_tracker_file_name = ( 164 cls.syntactically_invalid_tracker_file_name = (
136 '%s%ssynt_invalid_uri_tracker' % (cls.tmp_dir, os.sep)) 165 '%s%ssynt_invalid_uri_tracker' % (cls.tmp_dir, os.sep))
137 f = open(cls.syntactically_invalid_tracker_file_name, 'w') 166 f = open(cls.syntactically_invalid_tracker_file_name, 'w')
138 f.write('ftp://example.com') 167 f.write('ftp://example.com')
139 f.close() 168 f.close()
140 169
141 cls.invalid_upload_id = ( 170 cls.invalid_upload_id = cls.get_invalid_upload_id()
142 'http://pub.commondatastorage.googleapis.com/?upload_id='
143 'AyzB2Uo74W4EYxyi5dp_-r68jz8rtbvshsv4TX7srJVkJ57CxTY5Dw2')
144 cls.invalid_upload_id_tracker_file_name = ( 171 cls.invalid_upload_id_tracker_file_name = (
145 '%s%sinvalid_upload_id_tracker' % (cls.tmp_dir, os.sep)) 172 '%s%sinvalid_upload_id_tracker' % (cls.tmp_dir, os.sep))
146 f = open(cls.invalid_upload_id_tracker_file_name, 'w') 173 f = open(cls.invalid_upload_id_tracker_file_name, 'w')
147 f.write(cls.invalid_upload_id) 174 f.write(cls.invalid_upload_id)
148 f.close() 175 f.close()
149 176
150 cls.created_test_data = True 177 cls.created_test_data = True
151 178
152 @classmethod 179 @classmethod
153 def tear_down_class(cls): 180 def tear_down_class(cls):
154 """ 181 """
155 Deletes bucket and tmp dir created by set_up_class. 182 Deletes bucket and tmp dir created by set_up_class.
156 """ 183 """
157 if not hasattr(cls, 'created_test_data'): 184 if not hasattr(cls, 'created_test_data'):
158 return 185 return
159 # Call cls.tearDown() in case the tests got interrupted, to ensure
160 # dst objects get deleted.
161 cls.tearDown()
162 186
163 # Retry (for up to 2 minutes) the bucket gets deleted (it may not 187 # Retry (for up to 2 minutes) the bucket gets deleted (it may not
164 # the first time round, due to eventual consistency of bucket delete 188 # the first time round, due to eventual consistency of bucket delete
165 # operations). 189 # operations).
166 for i in range(60): 190 for i in range(60):
167 try: 191 try:
168 cls.dst_bucket_uri.delete_bucket() 192 cls.dst_bucket_uri.delete_bucket()
169 break 193 break
170 except StorageResponseError: 194 except StorageResponseError:
171 print 'Test bucket (%s) not yet deleted, still trying' % ( 195 print 'Test bucket (%s) not yet deleted, still trying' % (
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 tracker_file_name=self.tracker_file_name, num_retries=0) 227 tracker_file_name=self.tracker_file_name, num_retries=0)
204 try: 228 try:
205 self.dst_key.set_contents_from_file( 229 self.dst_key.set_contents_from_file(
206 self.small_src_file, cb=harnass.call, 230 self.small_src_file, cb=harnass.call,
207 res_upload_handler=res_upload_handler) 231 res_upload_handler=res_upload_handler)
208 self.fail('Did not get expected ResumableUploadException') 232 self.fail('Did not get expected ResumableUploadException')
209 except ResumableUploadException, e: 233 except ResumableUploadException, e:
210 # We'll get a ResumableUploadException at this point because 234 # We'll get a ResumableUploadException at this point because
211 # of CallbackTestHarnass (above). Check that the tracker file was 235 # of CallbackTestHarnass (above). Check that the tracker file was
212 # created correctly. 236 # created correctly.
213 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) 237 self.assertEqual(e.disposition,
238 ResumableTransferDisposition.ABORT_CUR_PROCESS)
214 self.assertTrue(os.path.exists(self.tracker_file_name)) 239 self.assertTrue(os.path.exists(self.tracker_file_name))
215 f = open(self.tracker_file_name) 240 f = open(self.tracker_file_name)
216 uri_from_file = f.readline().strip() 241 uri_from_file = f.readline().strip()
217 f.close() 242 f.close()
218 self.assertEqual(uri_from_file, 243 self.assertEqual(uri_from_file,
219 res_upload_handler.get_tracker_uri()) 244 res_upload_handler.get_tracker_uri())
220 245
221 def test_retryable_exception_recovery(self): 246 def test_retryable_exception_recovery(self):
222 """ 247 """
223 Tests handling of a retryable exception 248 Tests handling of a retryable exception
224 """ 249 """
225 # Test one of the RETRYABLE_EXCEPTIONS. 250 # Test one of the RETRYABLE_EXCEPTIONS.
226 exception = ResumableUploadHandler.RETRYABLE_EXCEPTIONS[0] 251 exception = ResumableUploadHandler.RETRYABLE_EXCEPTIONS[0]
227 harnass = CallbackTestHarnass(exception=exception) 252 harnass = CallbackTestHarnass(exception=exception)
228 res_upload_handler = ResumableUploadHandler(num_retries=1) 253 res_upload_handler = ResumableUploadHandler(num_retries=1)
229 self.dst_key.set_contents_from_file( 254 self.dst_key.set_contents_from_file(
230 self.small_src_file, cb=harnass.call, 255 self.small_src_file, cb=harnass.call,
231 res_upload_handler=res_upload_handler) 256 res_upload_handler=res_upload_handler)
232 # Ensure uploaded object has correct content. 257 # Ensure uploaded object has correct content.
233 self.assertEqual(self.small_src_file_size, self.dst_key.size) 258 self.assertEqual(self.small_src_file_size, self.dst_key.size)
234 self.assertEqual(self.small_src_file_as_string, 259 self.assertEqual(self.small_src_file_as_string,
235 self.dst_key.get_contents_as_string()) 260 self.dst_key.get_contents_as_string())
236 261
262 def test_broken_pipe_recovery(self):
263 """
264 Tests handling of a Broken Pipe (which interacts with an httplib bug)
265 """
266 exception = IOError(errno.EPIPE, "Broken pipe")
267 harnass = CallbackTestHarnass(exception=exception)
268 res_upload_handler = ResumableUploadHandler(num_retries=1)
269 self.dst_key.set_contents_from_file(
270 self.small_src_file, cb=harnass.call,
271 res_upload_handler=res_upload_handler)
272 # Ensure uploaded object has correct content.
273 self.assertEqual(self.small_src_file_size, self.dst_key.size)
274 self.assertEqual(self.small_src_file_as_string,
275 self.dst_key.get_contents_as_string())
276
237 def test_non_retryable_exception_handling(self): 277 def test_non_retryable_exception_handling(self):
238 """ 278 """
239 Tests a resumable upload that fails with a non-retryable exception 279 Tests a resumable upload that fails with a non-retryable exception
240 """ 280 """
241 harnass = CallbackTestHarnass( 281 harnass = CallbackTestHarnass(
242 exception=OSError(errno.EACCES, 'Permission denied')) 282 exception=OSError(errno.EACCES, 'Permission denied'))
243 res_upload_handler = ResumableUploadHandler(num_retries=1) 283 res_upload_handler = ResumableUploadHandler(num_retries=1)
244 try: 284 try:
245 self.dst_key.set_contents_from_file( 285 self.dst_key.set_contents_from_file(
246 self.small_src_file, cb=harnass.call, 286 self.small_src_file, cb=harnass.call,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 harnass = CallbackTestHarnass( 331 harnass = CallbackTestHarnass(
292 fail_after_n_bytes=self.larger_src_file_size/2, num_times_to_fail=2) 332 fail_after_n_bytes=self.larger_src_file_size/2, num_times_to_fail=2)
293 res_upload_handler = ResumableUploadHandler( 333 res_upload_handler = ResumableUploadHandler(
294 tracker_file_name=self.tracker_file_name, num_retries=1) 334 tracker_file_name=self.tracker_file_name, num_retries=1)
295 try: 335 try:
296 self.dst_key.set_contents_from_file( 336 self.dst_key.set_contents_from_file(
297 self.larger_src_file, cb=harnass.call, 337 self.larger_src_file, cb=harnass.call,
298 res_upload_handler=res_upload_handler) 338 res_upload_handler=res_upload_handler)
299 self.fail('Did not get expected ResumableUploadException') 339 self.fail('Did not get expected ResumableUploadException')
300 except ResumableUploadException, e: 340 except ResumableUploadException, e:
301 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) 341 self.assertEqual(e.disposition,
342 ResumableTransferDisposition.ABORT_CUR_PROCESS)
302 # Ensure a tracker file survived. 343 # Ensure a tracker file survived.
303 self.assertTrue(os.path.exists(self.tracker_file_name)) 344 self.assertTrue(os.path.exists(self.tracker_file_name))
304 # Try it one more time; this time should succeed. 345 # Try it one more time; this time should succeed.
305 self.dst_key.set_contents_from_file( 346 self.dst_key.set_contents_from_file(
306 self.larger_src_file, cb=harnass.call, 347 self.larger_src_file, cb=harnass.call,
307 res_upload_handler=res_upload_handler) 348 res_upload_handler=res_upload_handler)
308 self.assertEqual(self.larger_src_file_size, self.dst_key.size) 349 self.assertEqual(self.larger_src_file_size, self.dst_key.size)
309 self.assertEqual(self.larger_src_file_as_string, 350 self.assertEqual(self.larger_src_file_as_string,
310 self.dst_key.get_contents_as_string()) 351 self.dst_key.get_contents_as_string())
311 self.assertFalse(os.path.exists(self.tracker_file_name)) 352 self.assertFalse(os.path.exists(self.tracker_file_name))
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 # retries (initial upload request will establish expected size to 422 # retries (initial upload request will establish expected size to
382 # upload server). 423 # upload server).
383 res_upload_handler = ResumableUploadHandler( 424 res_upload_handler = ResumableUploadHandler(
384 tracker_file_name=self.tracker_file_name, num_retries=0) 425 tracker_file_name=self.tracker_file_name, num_retries=0)
385 try: 426 try:
386 self.dst_key.set_contents_from_file( 427 self.dst_key.set_contents_from_file(
387 self.larger_src_file, cb=harnass.call, 428 self.larger_src_file, cb=harnass.call,
388 res_upload_handler=res_upload_handler) 429 res_upload_handler=res_upload_handler)
389 self.fail('Did not get expected ResumableUploadException') 430 self.fail('Did not get expected ResumableUploadException')
390 except ResumableUploadException, e: 431 except ResumableUploadException, e:
391 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) 432 # First abort (from harnass-forced failure) should be
433 # ABORT_CUR_PROCESS.
434 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT_C UR_PROCESS)
392 # Ensure a tracker file survived. 435 # Ensure a tracker file survived.
393 self.assertTrue(os.path.exists(self.tracker_file_name)) 436 self.assertTrue(os.path.exists(self.tracker_file_name))
394 # Try it again, this time with different size source file. 437 # Try it again, this time with different size source file.
395 # Wait 1 second between retry attempts, to give upload server a 438 # Wait 1 second between retry attempts, to give upload server a
396 # chance to save state so it can respond to changed file size with 439 # chance to save state so it can respond to changed file size with
397 # 500 response in the next attempt. 440 # 500 response in the next attempt.
398 time.sleep(1) 441 time.sleep(1)
399 try: 442 try:
400 self.dst_key.set_contents_from_file( 443 self.dst_key.set_contents_from_file(
401 self.largest_src_file, res_upload_handler=res_upload_handler) 444 self.largest_src_file, res_upload_handler=res_upload_handler)
402 self.fail('Did not get expected ResumableUploadException') 445 self.fail('Did not get expected ResumableUploadException')
403 except ResumableUploadException, e: 446 except ResumableUploadException, e:
447 # This abort should be a hard abort (file size changing during
448 # transfer).
404 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) 449 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT)
405 self.assertNotEqual( 450 self.assertNotEqual(e.message.find('file size changed'), -1, e.messa ge)
406 e.message.find('attempt to upload a different size file'), -1)
407 451
408 def test_upload_with_file_size_change_during_upload(self): 452 def test_upload_with_file_size_change_during_upload(self):
409 """ 453 """
410 Tests resumable upload on a file that changes sizes while upload 454 Tests resumable upload on a file that changes sizes while upload
411 in progress 455 in progress
412 """ 456 """
413 # Create a file we can change during the upload. 457 # Create a file we can change during the upload.
414 test_file_size = 500 * 1024 # 500 KB. 458 test_file_size = 500 * 1024 # 500 KB.
415 test_file = self.build_test_input_file(test_file_size)[1] 459 test_file = self.build_test_input_file(test_file_size)[1]
416 harnass = CallbackTestHarnass(fp_to_change=test_file, 460 harnass = CallbackTestHarnass(fp_to_change=test_file,
(...skipping 29 matching lines...) Expand all
446 res_upload_handler=res_upload_handler) 490 res_upload_handler=res_upload_handler)
447 self.fail('Did not get expected ResumableUploadException') 491 self.fail('Did not get expected ResumableUploadException')
448 except ResumableUploadException, e: 492 except ResumableUploadException, e:
449 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT) 493 self.assertEqual(e.disposition, ResumableTransferDisposition.ABORT)
450 # Ensure the file size didn't change. 494 # Ensure the file size didn't change.
451 test_file.seek(0, os.SEEK_END) 495 test_file.seek(0, os.SEEK_END)
452 self.assertEqual(test_file_size, test_file.tell()) 496 self.assertEqual(test_file_size, test_file.tell())
453 self.assertNotEqual( 497 self.assertNotEqual(
454 e.message.find('md5 signature doesn\'t match etag'), -1) 498 e.message.find('md5 signature doesn\'t match etag'), -1)
455 # Ensure the bad data wasn't left around. 499 # Ensure the bad data wasn't left around.
456 all_keys = self.dst_key_uri.get_all_keys() 500 try:
457 self.assertEqual(0, len(all_keys)) 501 self.dst_key_uri.get_key()
502 self.fail('Did not get expected InvalidUriError')
503 except InvalidUriError, e:
504 pass
458 505
459 def test_upload_with_content_length_header_set(self): 506 def test_upload_with_content_length_header_set(self):
460 """ 507 """
461 Tests resumable upload on a file when the user supplies a 508 Tests resumable upload on a file when the user supplies a
462 Content-Length header. This is used by gsutil, for example, 509 Content-Length header. This is used by gsutil, for example,
463 to set the content length when gzipping a file. 510 to set the content length when gzipping a file.
464 """ 511 """
465 res_upload_handler = ResumableUploadHandler() 512 res_upload_handler = ResumableUploadHandler()
466 try: 513 try:
467 self.dst_key.set_contents_from_file( 514 self.dst_key.set_contents_from_file(
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 # that do it, with camelCase versions of these names). 589 # that do it, with camelCase versions of these names).
543 try: 590 try:
544 print 'Setting up %s...' % test_class.get_suite_description() 591 print 'Setting up %s...' % test_class.get_suite_description()
545 test_class.set_up_class(debug) 592 test_class.set_up_class(debug)
546 print 'Running %s...' % test_class.get_suite_description() 593 print 'Running %s...' % test_class.get_suite_description()
547 unittest.TextTestRunner(verbosity=2).run(suite) 594 unittest.TextTestRunner(verbosity=2).run(suite)
548 finally: 595 finally:
549 print 'Cleaning up after %s...' % test_class.get_suite_description() 596 print 'Cleaning up after %s...' % test_class.get_suite_description()
550 test_class.tear_down_class() 597 test_class.tear_down_class()
551 print '' 598 print ''
OLDNEW
« no previous file with comments | « tests/s3/test_resumable_downloads.py ('k') | tests/s3/test_versioning.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698