@@ -20,9 +20,9 @@ describe('S3Backend', () => {
2020 beforeEach ( ( ) => {
2121 jest . clearAllMocks ( )
2222 mockSend = jest . fn ( )
23- ; ( S3Client as jest . Mock ) . mockImplementation ( ( ) => ( {
24- send : mockSend ,
25- } ) )
23+ ; ( S3Client as jest . Mock ) . mockImplementation ( ( ) => ( {
24+ send : mockSend ,
25+ } ) )
2626 } )
2727
2828 describe ( 'getObject' , ( ) => {
@@ -74,4 +74,56 @@ describe('S3Backend', () => {
7474 expect ( result . metadata . mimetype ) . toBe ( 'image/png' )
7575 } )
7676 } )
77+
78+ describe ( 'deleteObjects' , ( ) => {
79+ test ( 'should use batch DeleteObjectsCommand when backend supports it' , async ( ) => {
80+ mockSend . mockResolvedValue ( {
81+ Deleted : [ { Key : 'file1.txt' } , { Key : 'file2.txt' } ] ,
82+ $metadata : { httpStatusCode : 200 } ,
83+ } )
84+
85+ const backend = new S3Backend ( { region : 'us-east-1' , endpoint : 'http://localhost:9000' } )
86+ await backend . deleteObjects ( 'test-bucket' , [ 'file1.txt' , 'file2.txt' ] )
87+
88+ expect ( mockSend ) . toHaveBeenCalledTimes ( 1 )
89+ expect ( mockSend . mock . calls [ 0 ] [ 0 ] . constructor . name ) . toBe ( 'DeleteObjectsCommand' )
90+ } )
91+
92+ test ( 'should fall back to individual DeleteObjectCommands when backend returns NotImplemented' , async ( ) => {
93+ const err = Object . assign ( new Error ( 'NotImplemented' ) , { Code : 'NotImplemented' } )
94+ mockSend
95+ . mockRejectedValueOnce ( err )
96+ . mockResolvedValue ( { $metadata : { httpStatusCode : 204 } } )
97+
98+ const backend = new S3Backend ( { region : 'us-east-1' , endpoint : 'http://localhost:9000' } )
99+ await backend . deleteObjects ( 'test-bucket' , [ 'file1.txt' , 'file2.txt' ] )
100+
101+ expect ( mockSend ) . toHaveBeenCalledTimes ( 3 )
102+ expect ( mockSend . mock . calls [ 0 ] [ 0 ] . constructor . name ) . toBe ( 'DeleteObjectsCommand' )
103+ expect ( mockSend . mock . calls [ 1 ] [ 0 ] . constructor . name ) . toBe ( 'DeleteObjectCommand' )
104+ expect ( mockSend . mock . calls [ 2 ] [ 0 ] . constructor . name ) . toBe ( 'DeleteObjectCommand' )
105+ } )
106+
107+ test ( 'should not throw if some individual fallback deletes fail' , async ( ) => {
108+ const notImplemented = Object . assign ( new Error ( 'NotImplemented' ) , { Code : 'NotImplemented' } )
109+ mockSend
110+ . mockRejectedValueOnce ( notImplemented )
111+ . mockResolvedValueOnce ( { $metadata : { httpStatusCode : 204 } } )
112+ . mockRejectedValueOnce ( new Error ( 'AccessDenied' ) )
113+
114+ const backend = new S3Backend ( { region : 'us-east-1' , endpoint : 'http://localhost:9000' } )
115+ await expect (
116+ backend . deleteObjects ( 'test-bucket' , [ 'file1.txt' , 'file2.txt' ] )
117+ ) . resolves . toBeUndefined ( )
118+ } )
119+
120+ test ( 'should rethrow errors that are not NotImplemented' , async ( ) => {
121+ const err = Object . assign ( new Error ( 'AccessDenied' ) , { Code : 'AccessDenied' } )
122+ mockSend . mockRejectedValue ( err )
123+
124+ const backend = new S3Backend ( { region : 'us-east-1' , endpoint : 'http://localhost:9000' } )
125+ await expect ( backend . deleteObjects ( 'test-bucket' , [ 'file1.txt' ] ) ) . rejects . toThrow ( )
126+ expect ( mockSend ) . toHaveBeenCalledTimes ( 1 )
127+ } )
128+ } )
77129} )
0 commit comments