@@ -3,6 +3,7 @@ const http = require('http');
33const { GCP } = require ( '../../../../../lib/storage/data/external/GCP' ) ;
44const { ListObjectsCommand, ListObjectVersionsCommand } = require ( '@aws-sdk/client-s3' ) ;
55const MpuHelper = require ( '../../../../../lib/storage/data/external/GCP/GcpApis/mpuHelper' ) ;
6+ const { createMpuKey } = require ( '../../../../../lib/storage/data/external/GCP/GcpUtils' ) ;
67
78const httpPort = 8888 ;
89
@@ -495,6 +496,153 @@ describe('GcpService helper behavior', () => {
495496} ) ;
496497
497498describe ( 'GcpService mpu helper behavior' , ( ) => {
499+ let client ;
500+
501+ beforeEach ( ( ) => {
502+ client = new GCP ( {
503+ s3Params : {
504+ endpoint : 'http://localhost' ,
505+ maxAttempts : 1 ,
506+ forcePathStyle : true ,
507+ region : 'us-east-1' ,
508+ credentials : {
509+ accessKeyId : 'access' ,
510+ secretAccessKey : 'secret' ,
511+ } ,
512+ } ,
513+ bucketName : 'unit-bucket' ,
514+ dataStoreName : 'unit-location' ,
515+ } ) ;
516+ } ) ;
517+
518+ afterEach ( ( ) => {
519+ jest . restoreAllMocks ( ) ;
520+ } ) ;
521+
522+ it ( 'abortMultipartUpload should reject missing parameters' , done => {
523+ client . abortMultipartUpload ( { Bucket : 'b' } , err => {
524+ assert ( err ) ;
525+ assert ( err . is . InvalidRequest ) ;
526+ done ( ) ;
527+ } ) ;
528+ } ) ;
529+
530+ it ( 'abortMultipartUpload should call removeParts with derived Prefix' , done => {
531+ const removeSpy = jest . spyOn ( MpuHelper . prototype , 'removeParts' )
532+ . mockImplementation ( ( _delParams , cb ) => cb ( null ) ) ;
533+
534+ const params = {
535+ Bucket : 'b' ,
536+ MPU : 'mpu-b' ,
537+ Key : 'obj' ,
538+ UploadId : 'upload' ,
539+ } ;
540+
541+ client . abortMultipartUpload ( params , err => {
542+ assert . ifError ( err ) ;
543+ expect ( removeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
544+ expect ( removeSpy ) . toHaveBeenCalledWith ( {
545+ Bucket : params . Bucket ,
546+ MPU : params . MPU ,
547+ Prefix : createMpuKey ( params . Key , params . UploadId ) ,
548+ } , expect . any ( Function ) ) ;
549+ done ( ) ;
550+ } ) ;
551+ } ) ;
552+
553+ it ( 'completeMultipartUpload should reject missing parameters' , done => {
554+ client . completeMultipartUpload ( { Bucket : 'b' } , err => {
555+ assert ( err ) ;
556+ assert ( err . is . InvalidRequest ) ;
557+ done ( ) ;
558+ } ) ;
559+ } ) ;
560+
561+ it ( 'completeMultipartUpload should reject empty parts list' , done => {
562+ client . completeMultipartUpload ( {
563+ Bucket : 'b' ,
564+ MPU : 'mpu-b' ,
565+ Key : 'obj' ,
566+ UploadId : 'upload' ,
567+ MultipartUpload : { Parts : [ ] } ,
568+ } , err => {
569+ assert ( err ) ;
570+ assert ( err . is . InvalidRequest ) ;
571+ done ( ) ;
572+ } ) ;
573+ } ) ;
574+
575+ it ( 'completeMultipartUpload should reject invalid part order' , done => {
576+ client . completeMultipartUpload ( {
577+ Bucket : 'b' ,
578+ MPU : 'mpu-b' ,
579+ Key : 'obj' ,
580+ UploadId : 'upload' ,
581+ MultipartUpload : {
582+ Parts : [
583+ { PartNumber : 2 } ,
584+ { PartNumber : 1 } ,
585+ ] ,
586+ } ,
587+ } , err => {
588+ assert ( err ) ;
589+ assert . strictEqual ( err . message , 'InvalidPartOrder' ) ;
590+ done ( ) ;
591+ } ) ;
592+ } ) ;
593+
594+ it ( 'completeMultipartUpload should run MPU flow and remove parts' , done => {
595+ jest . spyOn ( console , 'log' ) . mockImplementation ( ( ) => undefined ) ;
596+
597+ const splitMergeSpy = jest . spyOn ( MpuHelper . prototype , 'splitMerge' )
598+ . mockImplementation ( ( params , partList , level , cb ) => cb ( null , 2 ) ) ;
599+ const composeFinalSpy = jest . spyOn ( MpuHelper . prototype , 'composeFinal' )
600+ . mockImplementation ( ( numParts , params , cb ) => cb ( null , 'finalKey' ) ) ;
601+ const generateSpy = jest . spyOn ( MpuHelper . prototype , 'generateMpuResult' )
602+ . mockImplementation ( ( result , partList , cb ) => cb ( null , result , 'aggEtag' ) ) ;
603+ const copySpy = jest . spyOn ( MpuHelper . prototype , 'copyToMain' )
604+ . mockImplementation ( ( result , aggregateETag , params , cb ) => cb ( null , {
605+ Bucket : params . Bucket ,
606+ Key : params . Key ,
607+ VersionId : 'v1' ,
608+ ETag : '"aggEtag"' ,
609+ } ) ) ;
610+ const removeSpy = jest . spyOn ( MpuHelper . prototype , 'removeParts' )
611+ . mockImplementation ( ( _delParams , cb ) => cb ( null ) ) ;
612+
613+ const params = {
614+ Bucket : 'b' ,
615+ MPU : 'mpu-b' ,
616+ Key : 'obj' ,
617+ UploadId : 'upload' ,
618+ MultipartUpload : {
619+ Parts : [
620+ { PartNumber : 1 } ,
621+ { PartNumber : 2 } ,
622+ ] ,
623+ } ,
624+ } ;
625+
626+ client . completeMultipartUpload ( params , ( err , res ) => {
627+ assert . ifError ( err ) ;
628+ assert ( res ) ;
629+ assert . strictEqual ( res . Bucket , params . Bucket ) ;
630+ assert . strictEqual ( res . Key , params . Key ) ;
631+
632+ expect ( splitMergeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
633+ expect ( composeFinalSpy ) . toHaveBeenCalledTimes ( 1 ) ;
634+ expect ( generateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
635+ expect ( copySpy ) . toHaveBeenCalledTimes ( 1 ) ;
636+ expect ( removeSpy ) . toHaveBeenCalledTimes ( 1 ) ;
637+ expect ( removeSpy ) . toHaveBeenCalledWith ( {
638+ Bucket : params . Bucket ,
639+ MPU : params . MPU ,
640+ Prefix : createMpuKey ( params . Key , params . UploadId ) ,
641+ } , expect . any ( Function ) ) ;
642+ done ( ) ;
643+ } ) ;
644+ } ) ;
645+
498646 describe ( 'removeParts' , ( ) => {
499647 it ( 'should list versions via send(ListObjectVersionsCommand) and delete each version' , done => {
500648 const service = {
0 commit comments