@@ -44,10 +44,10 @@ const bucket = 'bucket';
44
44
const region = 'region' ;
45
45
const defaultKey = 'key' ;
46
46
const defaultContentType = 'application/octet-stream' ;
47
- const defaultCacheKey =
48
- 'Jz3O2w== _8388608_application/octet-stream_bucket_public_key' ;
47
+ const emptyOptionHash = 'o6a/Qw==' ; // crc32 for '{}'
48
+ const defaultCacheKey = ` ${ emptyOptionHash } _8388608_application/octet-stream_bucket_public_key` ;
49
49
const testPath = 'testPath/object' ;
50
- const testPathCacheKey = `Jz3O2w== _8388608_${ defaultContentType } _${ bucket } _custom_${ testPath } ` ;
50
+ const testPathCacheKey = `${ emptyOptionHash } _8388608_${ defaultContentType } _${ bucket } _custom_${ testPath } ` ;
51
51
52
52
const mockCreateMultipartUpload = jest . mocked ( createMultipartUpload ) ;
53
53
const mockUploadPart = jest . mocked ( uploadPart ) ;
@@ -545,14 +545,14 @@ describe('getMultipartUploadHandlers with key', () => {
545
545
describe ( 'cache validation' , ( ) => {
546
546
it . each ( [
547
547
{
548
- name : 'wrong part count' ,
548
+ name : 'mismatched part count between cached upload and actual upload ' ,
549
549
parts : [ { PartNumber : 1 } , { PartNumber : 2 } , { PartNumber : 3 } ] ,
550
550
} ,
551
551
{
552
- name : 'wrong part numbers' ,
552
+ name : 'mismatched part numbers between cached upload and actual upload ' ,
553
553
parts : [ { PartNumber : 1 } , { PartNumber : 1 } ] ,
554
554
} ,
555
- ] ) ( 'should throw with $name' , async ( { parts } ) => {
555
+ ] ) ( 'should throw integrity error with $name' , async ( { parts } ) => {
556
556
mockMultipartUploadSuccess ( ) ;
557
557
558
558
const mockDefaultStorage = defaultStorage as jest . Mocked <
@@ -619,6 +619,42 @@ describe('getMultipartUploadHandlers with key', () => {
619
619
expect ( mockListParts ) . not . toHaveBeenCalled ( ) ;
620
620
} ) ;
621
621
622
+ it ( 'should omit unserializable option properties when calculating the hash key' , async ( ) => {
623
+ mockMultipartUploadSuccess ( ) ;
624
+ const serializableOptions = {
625
+ useAccelerateEndpoint : true ,
626
+ bucket : { bucketName : 'bucket' , region : 'us-west-2' } ,
627
+ expectedBucketOwner : '123' ,
628
+ contentDisposition : 'attachment' ,
629
+ contentEncoding : 'deflate' ,
630
+ contentType : 'text/html' ,
631
+ customEndpoint : 'abc' ,
632
+ metadata : { } ,
633
+ preventOverwrite : true ,
634
+ checksumAlgorithm : 'crc-32' as const ,
635
+ } ;
636
+ const size = 8 * MB ;
637
+ const { multipartUploadJob } = getMultipartUploadHandlers (
638
+ {
639
+ key : defaultKey ,
640
+ data : new ArrayBuffer ( size ) ,
641
+ options : {
642
+ ...serializableOptions ,
643
+ // The following options will be omitted
644
+ locationCredentialsProvider : jest . fn ( ) ,
645
+ onProgress : jest . fn ( ) ,
646
+ resumableUploadsCache : mockDefaultStorage ,
647
+ } ,
648
+ } ,
649
+ size ,
650
+ ) ;
651
+ await multipartUploadJob ( ) ;
652
+ expect ( mockCalculateContentCRC32 ) . toHaveBeenNthCalledWith (
653
+ 1 ,
654
+ JSON . stringify ( serializableOptions ) ,
655
+ ) ;
656
+ } ) ;
657
+
622
658
it ( 'should send createMultipartUpload request if the upload task is not cached' , async ( ) => {
623
659
mockMultipartUploadSuccess ( ) ;
624
660
const size = 8 * MB ;
@@ -693,7 +729,7 @@ describe('getMultipartUploadHandlers with key', () => {
693
729
expect ( Object . keys ( cacheValue ) ) . toEqual ( [
694
730
expect . stringMatching (
695
731
// \d{13} is the file lastModified property of a file
696
- / s o m e N a m e _ \d { 13 } _ J z 3 O 2 w = = _ 8 3 8 8 6 0 8 _ a p p l i c a t i o n \/ o c t e t - s t r e a m _ b u c k e t _ p u b l i c _ k e y / ,
732
+ new RegExp ( ` someName_\\ d{13}_ ${ defaultCacheKey } ` ) ,
697
733
) ,
698
734
] ) ;
699
735
} ) ;
@@ -1451,6 +1487,42 @@ describe('getMultipartUploadHandlers with path', () => {
1451
1487
expect ( mockListParts ) . not . toHaveBeenCalled ( ) ;
1452
1488
} ) ;
1453
1489
1490
+ it ( 'should omit unserializable option properties when calculating the hash key' , async ( ) => {
1491
+ mockMultipartUploadSuccess ( ) ;
1492
+ const serializableOptions = {
1493
+ useAccelerateEndpoint : true ,
1494
+ bucket : { bucketName : 'bucket' , region : 'us-west-2' } ,
1495
+ expectedBucketOwner : '123' ,
1496
+ contentDisposition : 'attachment' ,
1497
+ contentEncoding : 'deflate' ,
1498
+ contentType : 'text/html' ,
1499
+ customEndpoint : 'abc' ,
1500
+ metadata : { } ,
1501
+ preventOverwrite : true ,
1502
+ checksumAlgorithm : 'crc-32' as const ,
1503
+ } ;
1504
+ const size = 8 * MB ;
1505
+ const { multipartUploadJob } = getMultipartUploadHandlers (
1506
+ {
1507
+ path : testPath ,
1508
+ data : new ArrayBuffer ( size ) ,
1509
+ options : {
1510
+ ...serializableOptions ,
1511
+ // The following options will be omitted
1512
+ locationCredentialsProvider : jest . fn ( ) ,
1513
+ onProgress : jest . fn ( ) ,
1514
+ resumableUploadsCache : mockDefaultStorage ,
1515
+ } ,
1516
+ } ,
1517
+ size ,
1518
+ ) ;
1519
+ await multipartUploadJob ( ) ;
1520
+ expect ( mockCalculateContentCRC32 ) . toHaveBeenNthCalledWith (
1521
+ 1 ,
1522
+ JSON . stringify ( serializableOptions ) ,
1523
+ ) ;
1524
+ } ) ;
1525
+
1454
1526
it ( 'should send createMultipartUpload request if the upload task is cached but outdated' , async ( ) => {
1455
1527
mockDefaultStorage . getItem . mockResolvedValue (
1456
1528
JSON . stringify ( {
0 commit comments