@@ -191,6 +191,8 @@ describe('Bucket', () => {
191191 let Bucket : any ;
192192 // eslint-disable-next-line @typescript-eslint/no-explicit-any
193193 let bucket : any ;
194+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
195+ let ComposeCleanupError : any ;
194196
195197 const STORAGE = {
196198 createBucket : util . noop ,
@@ -211,7 +213,7 @@ describe('Bucket', () => {
211213 const BUCKET_NAME = 'test-bucket' ;
212214
213215 before ( ( ) => {
214- Bucket = proxyquire ( '../src/bucket.js' , {
216+ const bucketModule = proxyquire ( '../src/bucket.js' , {
215217 fs : fakeFs ,
216218 'p-limit' : fakePLimit ,
217219 '@google-cloud/promisify' : fakePromisify ,
@@ -225,7 +227,9 @@ describe('Bucket', () => {
225227 './iam.js' : { Iam : FakeIam } ,
226228 './notification.js' : { Notification : FakeNotification } ,
227229 './signer.js' : fakeSigner ,
228- } ) . Bucket ;
230+ } ) ;
231+ Bucket = bucketModule . Bucket ;
232+ ComposeCleanupError = bucketModule . ComposeCleanupError ;
229233 } ) ;
230234
231235 beforeEach ( ( ) => {
@@ -806,7 +810,7 @@ describe('Bucket', () => {
806810 const destination = bucket . file ( 'destination.txt' ) ;
807811
808812 destination . request = ( reqOpts : DecorateRequestOptions ) => {
809- assert . strictEqual ( reqOpts . qs , options ) ;
813+ assert . deepStrictEqual ( reqOpts . qs , options ) ;
810814 done ( ) ;
811815 } ;
812816
@@ -916,6 +920,141 @@ describe('Bucket', () => {
916920
917921 bucket . combine ( sources , destination , done ) ;
918922 } ) ;
923+
924+ it ( 'should delete source objects if deleteSourceObjects is true' , done => {
925+ const sources = [ bucket . file ( '1.foo' ) , bucket . file ( '2.foo' ) ] ;
926+ const destination = bucket . file ( 'destination.foo' ) ;
927+
928+ // Set generation on the first file and leave second file without generation
929+ sources [ 0 ] . generation = 12345 ;
930+
931+ let deletedCount = 0 ;
932+ sources [ 0 ] . delete = async ( opts ?: any ) => {
933+ assert . strictEqual ( opts ?. userProject , 'user-project-id' ) ;
934+ assert . strictEqual ( opts ?. ignoreNotFound , true ) ;
935+ assert . strictEqual ( opts ?. ifGenerationMatch , 12345 ) ;
936+ deletedCount ++ ;
937+ return [ { } ] ;
938+ } ;
939+ sources [ 1 ] . delete = async ( opts ?: any ) => {
940+ assert . strictEqual ( opts ?. userProject , 'user-project-id' ) ;
941+ assert . strictEqual ( opts ?. ignoreNotFound , true ) ;
942+ assert . strictEqual ( opts ?. ifGenerationMatch , undefined ) ;
943+ deletedCount ++ ;
944+ return [ { } ] ;
945+ } ;
946+
947+ destination . request = ( reqOpts : DecorateRequestOptions , callback : Function ) => {
948+ assert . strictEqual ( reqOpts . qs . deleteSourceObjects , undefined ) ;
949+ assert . strictEqual ( reqOpts . json . deleteSourceObjects , undefined ) ;
950+ assert . strictEqual ( reqOpts . json . sourceObjects [ 0 ] . generation , 12345 ) ;
951+ callback ( null , { } ) ;
952+ } ;
953+
954+ bucket . combine (
955+ sources ,
956+ destination ,
957+ { deleteSourceObjects : true , userProject : 'user-project-id' } ,
958+ ( err : any ) => {
959+ assert . ifError ( err ) ;
960+ assert . strictEqual ( deletedCount , 2 ) ;
961+ done ( ) ;
962+ }
963+ ) ;
964+ } ) ;
965+
966+ it ( 'should not delete source objects if deleteSourceObjects is false/omitted' , done => {
967+ const sources = [ bucket . file ( '1.foo' ) , bucket . file ( '2.foo' ) ] ;
968+ const destination = bucket . file ( 'destination.foo' ) ;
969+
970+ let deletedCount = 0 ;
971+ sources . forEach ( source => {
972+ source . delete = async ( ) => {
973+ deletedCount ++ ;
974+ return [ { } ] ;
975+ } ;
976+ } ) ;
977+
978+ destination . request = ( reqOpts : DecorateRequestOptions , callback : Function ) => {
979+ assert . strictEqual ( reqOpts . json . deleteSourceObjects , undefined ) ;
980+ callback ( null , { } ) ;
981+ } ;
982+
983+ bucket . combine ( sources , destination , ( err : any ) => {
984+ assert . ifError ( err ) ;
985+ assert . strictEqual ( deletedCount , 0 ) ;
986+ done ( ) ;
987+ } ) ;
988+ } ) ;
989+
990+ it ( 'should not delete source objects if compose operation fails' , done => {
991+ const sources = [ bucket . file ( '1.foo' ) , bucket . file ( '2.foo' ) ] ;
992+ const destination = bucket . file ( 'destination.foo' ) ;
993+ const composeError = new Error ( 'Compose failed.' ) ;
994+
995+ let deletedCount = 0 ;
996+ sources . forEach ( source => {
997+ source . delete = async ( ) => {
998+ deletedCount ++ ;
999+ return [ { } ] ;
1000+ } ;
1001+ } ) ;
1002+
1003+ destination . request = ( reqOpts : DecorateRequestOptions , callback : Function ) => {
1004+ assert . strictEqual ( reqOpts . json . deleteSourceObjects , undefined ) ;
1005+ callback ( composeError ) ;
1006+ } ;
1007+
1008+ bucket . combine ( sources , destination , { deleteSourceObjects : true } , ( err : any ) => {
1009+ assert . strictEqual ( err , composeError ) ;
1010+ assert . strictEqual ( deletedCount , 0 ) ;
1011+ done ( ) ;
1012+ } ) ;
1013+ } ) ;
1014+
1015+ it ( 'should return ComposeCleanupError if deleting source objects fails' , done => {
1016+ const sources = [ bucket . file ( '1.foo' ) , bucket . file ( '2.foo' ) ] ;
1017+ const destination = bucket . file ( 'destination.foo' ) ;
1018+ const deleteError = new Error ( 'Delete failed.' ) ;
1019+
1020+ sources [ 0 ] . delete = async ( opts ?: any ) => {
1021+ assert . strictEqual ( opts ?. userProject , 'user-project-id' ) ;
1022+ assert . strictEqual ( opts ?. ignoreNotFound , true ) ;
1023+ throw deleteError ;
1024+ } ;
1025+ sources [ 1 ] . delete = async ( opts ?: any ) => {
1026+ assert . strictEqual ( opts ?. userProject , 'user-project-id' ) ;
1027+ assert . strictEqual ( opts ?. ignoreNotFound , true ) ;
1028+ return [ { } ] ;
1029+ } ;
1030+
1031+ destination . request = ( reqOpts : DecorateRequestOptions , callback : Function ) => {
1032+ assert . strictEqual ( reqOpts . json . deleteSourceObjects , undefined ) ;
1033+ callback ( null , { success : true } ) ;
1034+ } ;
1035+
1036+ bucket . combine (
1037+ sources ,
1038+ destination ,
1039+ { deleteSourceObjects : true , userProject : 'user-project-id' } ,
1040+ ( err : any , newFile : any , apiResponse : any ) => {
1041+ try {
1042+ assert . ok ( err instanceof ComposeCleanupError ) ;
1043+ assert . strictEqual ( err . name , 'ComposeCleanupError' ) ;
1044+ assert . deepStrictEqual ( ( err as any ) . errors , [ deleteError ] ) ;
1045+ assert . strictEqual ( ( err as any ) . newFile , destination ) ;
1046+ assert . deepStrictEqual ( ( err as any ) . apiResponse , { success : true } ) ;
1047+
1048+ // Also check callback arguments
1049+ assert . strictEqual ( newFile , destination ) ;
1050+ assert . deepStrictEqual ( apiResponse , { success : true } ) ;
1051+ done ( ) ;
1052+ } catch ( assertErr ) {
1053+ done ( assertErr ) ;
1054+ }
1055+ }
1056+ ) ;
1057+ } ) ;
9191058 } ) ;
9201059
9211060 describe ( 'createChannel' , ( ) => {
0 commit comments