@@ -335,7 +335,6 @@ def test_no_overwrite_flag_multipart_upload_when_object_not_exists_on_target(
335
335
# Create a large file that will trigger multipart upload
336
336
full_path = self .files .create_file ('foo.txt' , 'a' * 10 * (1024 ** 2 ))
337
337
cmdline = f'{ self .prefix } { full_path } s3://bucket --no-overwrite'
338
-
339
338
# Set up responses for multipart upload
340
339
self .parsed_responses = [
341
340
{'UploadId' : 'foo' }, # CreateMultipartUpload response
@@ -397,6 +396,160 @@ def test_no_overwrite_flag_multipart_upload_when_object_exists_on_target(
397
396
# Verify the IfNoneMatch condition was set in the CompleteMultipartUpload request
398
397
self .assertEqual (self .operations_called [3 ][1 ]['IfNoneMatch' ], '*' )
399
398
399
+ def test_no_overwrite_flag_on_copy_when_small_object_does_not_exist_on_target (
400
+ self ,
401
+ ):
402
+ cmdline = f'{ self .prefix } s3://bucket1/key.txt s3://bucket/key1.txt --no-overwrite'
403
+ # Set up responses for multipart copy (since no-overwrite always uses multipart)
404
+ self .parsed_responses = [
405
+ self .head_object_response (), # HeadObject to get source metadata
406
+ self .create_mpu_response ('foo' ), # CreateMultipartUpload response
407
+ self .upload_part_copy_response (), # UploadPartCopy response
408
+ {}, # CompleteMultipartUpload response
409
+ ]
410
+ self .run_cmd (cmdline , expected_rc = 0 )
411
+ # Verify all multipart operations were called
412
+ self .assertEqual (len (self .operations_called ), 4 )
413
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
414
+ self .assertEqual (
415
+ self .operations_called [1 ][0 ].name , 'CreateMultipartUpload'
416
+ )
417
+ self .assertEqual (self .operations_called [2 ][0 ].name , 'UploadPartCopy' )
418
+ self .assertEqual (
419
+ self .operations_called [3 ][0 ].name , 'CompleteMultipartUpload'
420
+ )
421
+ # Verify the IfNoneMatch condition was set in the CompleteMultipartUpload request
422
+ self .assertEqual (self .operations_called [3 ][1 ]['IfNoneMatch' ], '*' )
423
+
424
+ def test_no_overwrite_flag_on_copy_when_small_object_exists_on_target (
425
+ self ,
426
+ ):
427
+ cmdline = f'{ self .prefix } s3://bucket1/key.txt s3://bucket/key.txt --no-overwrite'
428
+ # Set up responses for multipart copy (since no-overwrite always uses multipart)
429
+ self .parsed_responses = [
430
+ self .head_object_response (), # HeadObject to get source metadata
431
+ self .create_mpu_response ('foo' ), # CreateMultipartUpload response
432
+ self .upload_part_copy_response (), # UploadPartCopy response
433
+ self .precondition_failed_error_response (), # CompleteMultipartUpload
434
+ {}, # AbortMultipartUpload response
435
+ ]
436
+ self .run_cmd (cmdline , expected_rc = 0 )
437
+ # Verify all multipart operations were called
438
+ self .assertEqual (len (self .operations_called ), 5 )
439
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
440
+ self .assertEqual (
441
+ self .operations_called [1 ][0 ].name , 'CreateMultipartUpload'
442
+ )
443
+ self .assertEqual (self .operations_called [2 ][0 ].name , 'UploadPartCopy' )
444
+ self .assertEqual (
445
+ self .operations_called [3 ][0 ].name , 'CompleteMultipartUpload'
446
+ )
447
+ self .assertEqual (
448
+ self .operations_called [4 ][0 ].name , 'AbortMultipartUpload'
449
+ )
450
+ # Verify the IfNoneMatch condition was set in the CompleteMultipartUpload request
451
+ self .assertEqual (self .operations_called [3 ][1 ]['IfNoneMatch' ], '*' )
452
+
453
+ def test_no_overwrite_flag_on_copy_when_zero_size_object_exists_at_destination (
454
+ self ,
455
+ ):
456
+ cmdline = f'{ self .prefix } s3://bucket1/file.txt s3://bucket2/file.txt --no-overwrite'
457
+ self .parsed_responses = [
458
+ self .head_object_response (
459
+ ContentLength = 0
460
+ ), # Source object (zero size)
461
+ self .head_object_response (), # Checking the object at destination
462
+ ]
463
+ self .run_cmd (cmdline , expected_rc = 0 )
464
+ self .assertEqual (len (self .operations_called ), 2 )
465
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
466
+ self .assertEqual (self .operations_called [1 ][0 ].name , 'HeadObject' )
467
+
468
+ def test_no_overwrite_flag_on_copy_when_zero_size_object_not_exists_at_destination (
469
+ self ,
470
+ ):
471
+ cmdline = f'{ self .prefix } s3://bucket1/file.txt s3://bucket2/file1.txt --no-overwrite'
472
+ self .parsed_responses = [
473
+ self .head_object_response (
474
+ ContentLength = 0
475
+ ), # Source object (zero size)
476
+ {
477
+ 'Error' : {'Code' : '404' , 'Message' : 'Not Found' }
478
+ }, # At destination object does not exists
479
+ self .copy_object_response (), # Copy Request when object does not exists
480
+ ]
481
+ self .run_cmd (cmdline , expected_rc = 0 )
482
+ self .assertEqual (len (self .operations_called ), 3 )
483
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
484
+ self .assertEqual (self .operations_called [1 ][0 ].name , 'HeadObject' )
485
+ self .assertEqual (self .operations_called [2 ][0 ].name , 'CopyObject' )
486
+
487
+ def test_no_overwrite_flag_on_copy_when_large_object_exists_on_target (
488
+ self ,
489
+ ):
490
+ cmdline = f'{ self .prefix } s3://bucket1/key.txt s3://bucket/key.txt --no-overwrite'
491
+ # Set up responses for multipart copy with large object
492
+ self .parsed_responses = [
493
+ self .head_object_response (
494
+ ContentLength = 10 * (1024 ** 2 )
495
+ ), # HeadObject with large content
496
+ self .get_object_tagging_response ({}), # GetObjectTagging response
497
+ self .create_mpu_response ('foo' ), # CreateMultipartUpload response
498
+ self .upload_part_copy_response (), # UploadPartCopy response part 1
499
+ self .upload_part_copy_response (), # UploadPartCopy response part 2
500
+ self .precondition_failed_error_response (), # CompleteMultipartUpload fails with PreconditionFailed
501
+ {}, # AbortMultipartUpload response
502
+ ]
503
+ self .run_cmd (cmdline , expected_rc = 0 )
504
+ # Verify all multipart operations were called
505
+ self .assertEqual (len (self .operations_called ), 7 )
506
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
507
+ self .assertEqual (self .operations_called [1 ][0 ].name , 'GetObjectTagging' )
508
+ self .assertEqual (
509
+ self .operations_called [2 ][0 ].name , 'CreateMultipartUpload'
510
+ )
511
+ self .assertEqual (self .operations_called [3 ][0 ].name , 'UploadPartCopy' )
512
+ self .assertEqual (self .operations_called [4 ][0 ].name , 'UploadPartCopy' )
513
+ self .assertEqual (
514
+ self .operations_called [5 ][0 ].name , 'CompleteMultipartUpload'
515
+ )
516
+ self .assertEqual (
517
+ self .operations_called [6 ][0 ].name , 'AbortMultipartUpload'
518
+ )
519
+ # Verify the IfNoneMatch condition was set in the CompleteMultipartUpload request
520
+ self .assertEqual (self .operations_called [5 ][1 ]['IfNoneMatch' ], '*' )
521
+
522
+ def test_no_overwrite_flag_on_copy_when_large_object_does_not_exist_on_target (
523
+ self ,
524
+ ):
525
+ cmdline = f'{ self .prefix } s3://bucket1/key.txt s3://bucket/key1.txt --no-overwrite'
526
+ # Set up responses for multipart copy with large object
527
+ self .parsed_responses = [
528
+ self .head_object_response (
529
+ ContentLength = 10 * (1024 ** 2 )
530
+ ), # HeadObject with large content
531
+ self .get_object_tagging_response ({}), # GetObjectTagging response
532
+ self .create_mpu_response ('foo' ), # CreateMultipartUpload response
533
+ self .upload_part_copy_response (), # UploadPartCopy response part 1
534
+ self .upload_part_copy_response (), # UploadPartCopy response part 2
535
+ {}, # CompleteMultipartUpload response
536
+ ]
537
+ self .run_cmd (cmdline , expected_rc = 0 )
538
+ # Verify all multipart operations were called
539
+ self .assertEqual (len (self .operations_called ), 6 )
540
+ self .assertEqual (self .operations_called [0 ][0 ].name , 'HeadObject' )
541
+ self .assertEqual (self .operations_called [1 ][0 ].name , 'GetObjectTagging' )
542
+ self .assertEqual (
543
+ self .operations_called [2 ][0 ].name , 'CreateMultipartUpload'
544
+ )
545
+ self .assertEqual (self .operations_called [3 ][0 ].name , 'UploadPartCopy' )
546
+ self .assertEqual (self .operations_called [4 ][0 ].name , 'UploadPartCopy' )
547
+ self .assertEqual (
548
+ self .operations_called [5 ][0 ].name , 'CompleteMultipartUpload'
549
+ )
550
+ # Verify the IfNoneMatch condition was set in the CompleteMultipartUpload request
551
+ self .assertEqual (self .operations_called [5 ][1 ]['IfNoneMatch' ], '*' )
552
+
400
553
def test_dryrun_download (self ):
401
554
self .parsed_responses = [self .head_object_response ()]
402
555
target = self .files .full_path ('file.txt' )
0 commit comments