@@ -324,5 +324,146 @@ describe('DELETE object', () => {
324324 }
325325 ) ) ;
326326 } ) ;
327+
328+ describe ( 'with conditional headers (unofficial, for backbeat)' , ( ) => {
329+ const bucketName = 'testconditionaldelete' ;
330+ const testObjectKey = 'conditional-test-object' ;
331+ const testObjectBody = 'body' ;
332+ let objectLastModified ;
333+
334+ before ( async ( ) => {
335+ await s3 . createBucket ( { Bucket : bucketName } ) . promise ( ) ;
336+ } ) ;
337+
338+ beforeEach ( async ( ) => {
339+ // Re-create the object for each test since some tests will delete it
340+ await s3 . putObject ( {
341+ Bucket : bucketName ,
342+ Key : testObjectKey ,
343+ Body : testObjectBody ,
344+ } ) . promise ( ) ;
345+ const head = await s3 . headObject ( {
346+ Bucket : bucketName ,
347+ Key : testObjectKey ,
348+ } ) . promise ( ) ;
349+ objectLastModified = head . LastModified ;
350+ } ) ;
351+
352+ after ( async ( ) => {
353+ await bucketUtil . empty ( bucketName ) ;
354+ await bucketUtil . deleteOne ( bucketName ) ;
355+ } ) ;
356+
357+ function deleteObjectConditional ( s3 , params , headers , next ) {
358+ const request = s3 . deleteObject ( params ) ;
359+ request . on ( 'build' , ( ) => {
360+ for ( const [ key , value ] of Object . entries ( headers ) ) {
361+ request . httpRequest . headers [ key ] = value ;
362+ }
363+ } ) ;
364+ return request . send ( next ) ;
365+ }
366+
367+ describe ( 'If-Unmodified-Since header tests' , ( ) => {
368+ it ( 'should delete when condition is true (date after object modification)' , done => {
369+ const futureDate = new Date ( objectLastModified . getTime ( ) + 60_000 ) ; // 1 minute later
370+
371+ deleteObjectConditional ( s3 , {
372+ Bucket : bucketName ,
373+ Key : testObjectKey ,
374+ } , {
375+ 'If-Unmodified-Since' : futureDate . toUTCString ( ) ,
376+ } , ( err , data ) => {
377+ assert . ifError ( err ) ;
378+ assert . deepStrictEqual ( data , { } ) ;
379+ s3 . headObject ( {
380+ Bucket : bucketName ,
381+ Key : testObjectKey ,
382+ } , err => {
383+ assert . strictEqual ( err . code , 'NotFound' ) ;
384+ done ( ) ;
385+ } ) ;
386+ } ) ;
387+ } ) ;
388+
389+ it ( 'should fail (412) to delete when condition is false (date before object modification)' , done => {
390+ const pastDate = new Date ( objectLastModified . getTime ( ) - 60_000 ) ; // 1 minute earlier
391+
392+ deleteObjectConditional ( s3 , {
393+ Bucket : bucketName ,
394+ Key : testObjectKey ,
395+ } , {
396+ 'If-Unmodified-Since' : pastDate . toUTCString ( ) ,
397+ } , err => {
398+ assert . strictEqual ( err . code , 'PreconditionFailed' ) ;
399+ assert . strictEqual ( err . statusCode , 412 ) ;
400+ done ( ) ;
401+ } ) ;
402+ } ) ;
403+ } ) ;
404+
405+ describe ( 'If-Modified-Since header tests' , ( ) => {
406+ it ( 'should delete when condition is true (date before object modification)' , done => {
407+ const pastDate = new Date ( objectLastModified . getTime ( ) - 60_000 ) ; // 1 minute earlier
408+
409+ deleteObjectConditional ( s3 , {
410+ Bucket : bucketName ,
411+ Key : testObjectKey ,
412+ } , {
413+ 'If-Modified-Since' : pastDate . toUTCString ( ) ,
414+ } , ( err , data ) => {
415+ assert . ifError ( err ) ;
416+ assert . deepStrictEqual ( data , { } ) ;
417+ s3 . headObject ( {
418+ Bucket : bucketName ,
419+ Key : testObjectKey ,
420+ } , err => {
421+ assert . strictEqual ( err . code , 'NotFound' ) ;
422+ done ( ) ;
423+ } ) ;
424+ } ) ;
425+ } ) ;
426+
427+ it ( 'should fail (304) to delete when condition is false (date after object modification)' , done => {
428+ const futureDate = new Date ( objectLastModified . getTime ( ) + 60_000 ) ; // 1 minute later
429+
430+ deleteObjectConditional ( s3 , {
431+ Bucket : bucketName ,
432+ Key : testObjectKey ,
433+ } , {
434+ 'If-Modified-Since' : futureDate . toUTCString ( ) ,
435+ } , err => {
436+ assert . strictEqual ( err . code , 'NotModified' ) ;
437+ assert . strictEqual ( err . statusCode , 304 ) ;
438+ done ( ) ;
439+ } ) ;
440+ } ) ;
441+ } ) ;
442+
443+ describe ( 'combined conditional headers' , ( ) => {
444+ it ( 'should delete when both If-Modified-Since and If-Unmodified-Since conditions are true' , done => {
445+ const pastDate = new Date ( objectLastModified . getTime ( ) - 60_000 ) ; // 1 minute earlier
446+ const futureDate = new Date ( objectLastModified . getTime ( ) + 60_000 ) ; // 1 minute later
447+
448+ deleteObjectConditional ( s3 , {
449+ Bucket : bucketName ,
450+ Key : testObjectKey ,
451+ } , {
452+ 'If-Modified-Since' : pastDate . toUTCString ( ) ,
453+ 'If-Unmodified-Since' : futureDate . toUTCString ( ) ,
454+ } , ( err , data ) => {
455+ assert . ifError ( err ) ;
456+ assert . deepStrictEqual ( data , { } ) ;
457+ s3 . headObject ( {
458+ Bucket : bucketName ,
459+ Key : testObjectKey ,
460+ } , err => {
461+ assert . strictEqual ( err . code , 'NotFound' ) ;
462+ done ( ) ;
463+ } ) ;
464+ } ) ;
465+ } ) ;
466+ } ) ;
467+ } ) ;
327468 } ) ;
328469} ) ;
0 commit comments