Skip to content

Commit c60c6af

Browse files
committed
Update s3transfer tests to account for using IfNoneMatch
Removes the tests for 0 length files and moves some tests to the TestNonMultipartCopy, since CopyObject accepts IfNoneMatch and no longer needs to force multipart copying.
1 parent 931308c commit c60c6af

File tree

1 file changed

+64
-129
lines changed

1 file changed

+64
-129
lines changed

tests/functional/s3transfer/test_copy.py

Lines changed: 64 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,69 @@ def test_copy_with_extra_args(self):
255255
future.result()
256256
self.stubber.assert_no_pending_responses()
257257

258+
def test_copy_with_ifnonematch_when_object_not_exists_at_target(self):
259+
self.extra_args['IfNoneMatch'] = '*'
260+
261+
expected_head_params = {
262+
'Bucket': 'mysourcebucket',
263+
'Key': 'mysourcekey',
264+
}
265+
266+
expected_copy_object = {
267+
'Bucket': 'mybucket',
268+
'Key': 'mykey',
269+
'CopySource': {
270+
'Bucket': 'mysourcebucket',
271+
'Key': 'mysourcekey',
272+
},
273+
"IfNoneMatch": "*"
274+
}
275+
276+
self.add_head_object_response(expected_params=expected_head_params)
277+
self.add_successful_copy_responses(
278+
expected_copy_params=expected_copy_object
279+
)
280+
281+
call_kwargs = self.create_call_kwargs()
282+
call_kwargs['extra_args'] = self.extra_args
283+
future = self.manager.copy(**call_kwargs)
284+
future.result()
285+
self.stubber.assert_no_pending_responses()
286+
287+
def test_copy_with_ifnonematch_when_object_exists_at_target(self):
288+
self.extra_args['IfNoneMatch'] = '*'
289+
290+
expected_head_params = {
291+
'Bucket': 'mysourcebucket',
292+
'Key': 'mysourcekey',
293+
}
294+
295+
self.add_head_object_response(expected_params=expected_head_params)
296+
297+
# Mock a PreconditionFailed error for copy_object
298+
self.stubber.add_client_error(
299+
method='copy_object',
300+
service_error_code='PreconditionFailed',
301+
service_message='The condition specified in the conditional header(s) was not met',
302+
http_status_code=412,
303+
expected_params={
304+
'Bucket': self.bucket,
305+
'Key': self.key,
306+
'CopySource': self.copy_source,
307+
'IfNoneMatch': '*',
308+
},
309+
)
310+
311+
call_kwargs = self.create_call_kwargs()
312+
call_kwargs['extra_args'] = self.extra_args
313+
future = self.manager.copy(**call_kwargs)
314+
with self.assertRaises(ClientError) as context:
315+
future.result()
316+
self.assertEqual(
317+
context.exception.response['Error']['Code'], 'PreconditionFailed'
318+
)
319+
self.stubber.assert_no_pending_responses()
320+
258321
def test_copy_maps_extra_args_to_head_object(self):
259322
self.extra_args['CopySourceSSECustomerAlgorithm'] = 'AES256'
260323

@@ -719,135 +782,6 @@ def test_mp_copy_with_tagging_directive(self):
719782
future.result()
720783
self.stubber.assert_no_pending_responses()
721784

722-
def test_copy_with_no_overwrite_flag_when_small_object_exists_at_target(
723-
self,
724-
):
725-
# Set up IfNoneMatch in extra_args
726-
self.extra_args['IfNoneMatch'] = '*'
727-
# Setting up the size of object
728-
small_content_size = 5
729-
self.content = b'0' * small_content_size
730-
# Add head object response with small content size
731-
head_response = self.create_stubbed_responses()[0]
732-
head_response['service_response'] = {
733-
'ContentLength': small_content_size
734-
}
735-
self.stubber.add_response(**head_response)
736-
# Should use multipart upload
737-
# Add create_multipart_upload response
738-
self.stubber.add_response(
739-
'create_multipart_upload',
740-
service_response={'UploadId': self.multipart_id},
741-
expected_params={
742-
'Bucket': self.bucket,
743-
'Key': self.key,
744-
},
745-
)
746-
# Add upload_part_copy response
747-
self.stubber.add_response(
748-
'upload_part_copy',
749-
{'CopyPartResult': {'ETag': 'etag-1'}},
750-
{
751-
'Bucket': self.bucket,
752-
'Key': self.key,
753-
'CopySource': self.copy_source,
754-
'UploadId': self.multipart_id,
755-
'PartNumber': 1,
756-
'CopySourceRange': f'bytes=0-{small_content_size-1}',
757-
},
758-
)
759-
# Mock a PreconditionFailed error for complete_multipart_upload
760-
self.stubber.add_client_error(
761-
method='complete_multipart_upload',
762-
service_error_code='PreconditionFailed',
763-
service_message='The condition specified in the conditional header(s) was not met',
764-
http_status_code=412,
765-
expected_params={
766-
'Bucket': self.bucket,
767-
'Key': self.key,
768-
'UploadId': self.multipart_id,
769-
'MultipartUpload': {
770-
'Parts': [{'ETag': 'etag-1', 'PartNumber': 1}]
771-
},
772-
'IfNoneMatch': '*',
773-
},
774-
)
775-
# Add abort_multipart_upload response
776-
self.stubber.add_response(
777-
'abort_multipart_upload',
778-
service_response={},
779-
expected_params={
780-
'Bucket': self.bucket,
781-
'Key': self.key,
782-
'UploadId': self.multipart_id,
783-
},
784-
)
785-
call_kwargs = self.create_call_kwargs()
786-
call_kwargs['extra_args'] = self.extra_args
787-
future = self.manager.copy(**call_kwargs)
788-
with self.assertRaises(ClientError) as context:
789-
future.result()
790-
self.assertEqual(
791-
context.exception.response['Error']['Code'], 'PreconditionFailed'
792-
)
793-
self.stubber.assert_no_pending_responses()
794-
795-
def test_copy_with_no_overwrite_flag_when_small_object_not_exists_at_target(
796-
self,
797-
):
798-
# Set up IfNoneMatch in extra_args
799-
self.extra_args['IfNoneMatch'] = '*'
800-
# Setting up the size of object
801-
small_content_size = 5
802-
self.content = b'0' * small_content_size
803-
# Add head object response with small content size
804-
head_response = self.create_stubbed_responses()[0]
805-
head_response['service_response'] = {
806-
'ContentLength': small_content_size
807-
}
808-
self.stubber.add_response(**head_response)
809-
# Should use multipart copy
810-
# Add create_multipart_upload response
811-
self.stubber.add_response(
812-
'create_multipart_upload',
813-
service_response={'UploadId': self.multipart_id},
814-
expected_params={
815-
'Bucket': self.bucket,
816-
'Key': self.key,
817-
},
818-
)
819-
# Add upload_part_copy response
820-
self.stubber.add_response(
821-
'upload_part_copy',
822-
{'CopyPartResult': {'ETag': 'etag-1'}},
823-
{
824-
'Bucket': self.bucket,
825-
'Key': self.key,
826-
'CopySource': self.copy_source,
827-
'UploadId': self.multipart_id,
828-
'PartNumber': 1,
829-
'CopySourceRange': f'bytes=0-{small_content_size-1}',
830-
},
831-
)
832-
self.stubber.add_response(
833-
'complete_multipart_upload',
834-
service_response={},
835-
expected_params={
836-
'Bucket': self.bucket,
837-
'Key': self.key,
838-
'UploadId': self.multipart_id,
839-
'MultipartUpload': {
840-
'Parts': [{'ETag': 'etag-1', 'PartNumber': 1}]
841-
},
842-
'IfNoneMatch': '*',
843-
},
844-
)
845-
call_kwargs = self.create_call_kwargs()
846-
call_kwargs['extra_args'] = self.extra_args
847-
future = self.manager.copy(**call_kwargs)
848-
future.result()
849-
self.stubber.assert_no_pending_responses()
850-
851785
def test_copy_with_no_overwrite_flag_when_large_object_exists_at_target(
852786
self,
853787
):
@@ -931,6 +865,7 @@ def test_copy_with_no_overwrite_flag_when_large_object_not_exists_at_target(
931865
future = self.manager.copy(**call_kwargs)
932866
future.result()
933867
self.stubber.assert_no_pending_responses()
868+
934869
def test_copy_fails_if_etag_validation_fails(self):
935870
expected_params = {
936871
'Bucket': 'mybucket',

0 commit comments

Comments
 (0)