@@ -799,6 +799,123 @@ mocha.describe('lifecycle', () => {
799
799
}
800
800
} ) ;
801
801
802
+ mocha . describe ( 'bucket-lifecycle-expiration-header' , function ( ) {
803
+ const bucket = Bucket ;
804
+
805
+ const run_expiration_test = async ( { rules, expected_id, expected_days, key, tagging = undefined , size = 1000 } ) => {
806
+ const putLifecycleParams = {
807
+ Bucket : bucket ,
808
+ LifecycleConfiguration : { Rules : rules }
809
+ } ;
810
+ await s3 . putBucketLifecycleConfiguration ( putLifecycleParams ) ;
811
+
812
+ const putObjectParams = {
813
+ Bucket : bucket ,
814
+ Key : key ,
815
+ Body : 'x' . repeat ( size ) // default 1KB if size not specified
816
+ } ;
817
+ if ( tagging ) {
818
+ putObjectParams . Tagging = tagging ;
819
+ }
820
+ const start_time = new Date ( ) ;
821
+ let res = await s3 . putObject ( putObjectParams ) ;
822
+ assert . ok ( res . Expiration , 'expiration header missing in putObject response' ) ;
823
+
824
+ res = await s3 . headObject ( { Bucket : bucket , Key : key } ) ;
825
+ assert . ok ( res . Expiration , 'expiration header missing in headObject response' ) ;
826
+
827
+ const valid = validate_expiration_header ( res . Expiration , start_time , expected_id , expected_days ) ;
828
+ assert . ok ( valid , `expected rule ${ expected_id } to match` ) ;
829
+ } ;
830
+
831
+ function generate_rule ( id , prefix , tags , size_gt , size_lt , expiration_days ) {
832
+ const filter = { } ;
833
+ if ( prefix ) filter . Prefix = prefix ;
834
+ if ( tags . length ) filter . Tags = tags ;
835
+ if ( size_gt !== undefined ) filter . ObjectSizeGreaterThan = size_gt ;
836
+ if ( size_lt !== undefined ) filter . ObjectSizeLessThan = size_lt ;
837
+
838
+ return {
839
+ ID : id ,
840
+ Status : 'Enabled' ,
841
+ Filter : filter ,
842
+ Expiration : { Days : expiration_days } ,
843
+ } ;
844
+ }
845
+
846
+ function validate_expiration_header ( expiration_header , start_time , expected_rule_id , delta_days ) {
847
+ const match = expiration_header . match ( / e x p i r y - d a t e = " ( .+ ) " , r u l e - i d = " ( .+ ) " / ) ;
848
+ if ( ! match ) return false ;
849
+ console . log ( "match: " , match ) ;
850
+
851
+ const [ , expiry_str , rule_id ] = match ;
852
+ const expiration_date = new Date ( expiry_str ) ;
853
+ const start = new Date ( start_time ) ;
854
+ start_time . setUTCHours ( 0 , 0 , 0 , 0 ) ; // adjusting to midnight UTC otherwise the tests will fail - similar to ceph-s3 tests
855
+
856
+ const days_diff = Math . floor ( ( expiration_date . getTime ( ) - start . getTime ( ) ) / ( 24 * 60 * 60 * 1000 ) ) ;
857
+
858
+ return days_diff === delta_days && rule_id === expected_rule_id ;
859
+ }
860
+
861
+ mocha . it ( 'should select rule with longest prefix' , async ( ) => {
862
+ const rules = [
863
+ generate_rule ( 'short-prefix' , 'test1/' , [ ] , undefined , undefined , 10 ) ,
864
+ generate_rule ( 'long-prefix' , 'test1/logs/' , [ ] , undefined , undefined , 17 ) ,
865
+ ] ;
866
+ await run_expiration_test ( {
867
+ rules,
868
+ key : 'test1/logs//file.txt' ,
869
+ expected_id : 'long-prefix' ,
870
+ expected_days : 17
871
+ } ) ;
872
+ } ) ;
873
+
874
+ mocha . it ( 'should select rule with more tags when prefix is same' , async ( ) => {
875
+ const rules = [
876
+ generate_rule ( 'one-tag' , 'test2/' , [ { Key : 'env' , Value : 'prod' } ] , undefined , undefined , 5 ) ,
877
+ generate_rule ( 'two-tags' , 'test2/' , [
878
+ { Key : 'env' , Value : 'prod' } ,
879
+ { Key : 'team' , Value : 'backend' }
880
+ ] , undefined , undefined , 9 ) ,
881
+ ] ;
882
+ await run_expiration_test ( {
883
+ rules,
884
+ key : 'test2/file2.txt' ,
885
+ tagging : 'env=prod&team=backend' ,
886
+ expected_id : 'two-tags' ,
887
+ expected_days : 9
888
+ } ) ;
889
+ } ) ;
890
+
891
+ mocha . it ( 'should select rule with narrower size span when prefix and tags are matching' , async ( ) => {
892
+ const rules = [
893
+ generate_rule ( 'wide-range' , 'test3/' , [ ] , 100 , 10000 , 4 ) ,
894
+ generate_rule ( 'narrow-range' , 'test3/' , [ ] , 1000 , 5000 , 6 ) ,
895
+ ] ;
896
+ await run_expiration_test ( {
897
+ rules,
898
+ key : 'test3/file3.txt' ,
899
+ size : 1500 ,
900
+ expected_id : 'narrow-range' ,
901
+ expected_days : 6
902
+ } ) ;
903
+ } ) ;
904
+
905
+ mocha . it ( 'should fallback to first matching rule if all filters are equal' , async ( ) => {
906
+ const rules = [
907
+ generate_rule ( 'rule-a' , 'test4/' , [ ] , 0 , 10000 , 7 ) ,
908
+ generate_rule ( 'rule-b' , 'test4/' , [ ] , 0 , 10000 , 11 ) ,
909
+ ] ;
910
+ await run_expiration_test ( {
911
+ rules,
912
+ key : 'test4/file4.txt' ,
913
+ expected_id : 'rule-a' ,
914
+ expected_days : 7
915
+ } ) ;
916
+ } ) ;
917
+ } ) ;
918
+
802
919
function readable_buffer ( data , split = 1 , finish = 'end' ) {
803
920
const max = Math . ceil ( data . length / split ) ;
804
921
let pos = 0 ;
0 commit comments