@@ -114,7 +114,7 @@ def test_bucket_list_distinct():
114114 is_empty = _bucket_is_empty(bucket2)
115115 assert is_empty == True
116116
117- def _create_objects(bucket=None, bucket_name=None, keys=[]):
117+ def _create_objects(bucket=None, bucket_name=None, keys=[], put_object_args={} ):
118118 """
119119 Populate a (specified or new) bucket with objects with
120120 specified names (and contents identical to their names).
@@ -125,7 +125,7 @@ def _create_objects(bucket=None, bucket_name=None, keys=[]):
125125 bucket = get_new_bucket_resource(name=bucket_name)
126126
127127 for key in keys:
128- obj = bucket.put_object(Body=key, Key=key)
128+ obj = bucket.put_object(Body=key, Key=key, **put_object_args )
129129
130130 return bucket_name
131131
@@ -16528,6 +16528,11 @@ def test_get_object_attributes():
1652816528 'SSECustomerKey': 'pO3upElrwuEXSoFwCfnZPdSsmt/xWeFa0N9KgDijwVs=',
1652916529 'SSECustomerKeyMD5': 'DWygnHRtgiJ77HCm+1rvHw==',
1653016530 },
16531+ 'get_args': {
16532+ 'SSECustomerAlgorithm': 'AES256',
16533+ 'SSECustomerKey': 'pO3upElrwuEXSoFwCfnZPdSsmt/xWeFa0N9KgDijwVs=',
16534+ 'SSECustomerKeyMD5': 'DWygnHRtgiJ77HCm+1rvHw==',
16535+ },
1653116536 'source_copy_args': {
1653216537 'CopySourceSSECustomerAlgorithm': 'AES256',
1653316538 'CopySourceSSECustomerKey': 'pO3upElrwuEXSoFwCfnZPdSsmt/xWeFa0N9KgDijwVs=',
@@ -16724,3 +16729,77 @@ def test_copy_enc_storage_class(source_mode_key, dest_mode_key, source_storage_c
1672416729 f"{source_storage_class} -> {dest_storage_class} and object size {obj_size}"
1672516730 )
1672616731 _test_copy_enc(obj_size, source_mode_key, dest_mode_key, source_storage_class, dest_storage_class)
16732+
16733+ def generate_lifecycle_transition_params():
16734+ configure()
16735+ sc = configured_storage_classes()
16736+ if len(sc) < 2:
16737+ return []
16738+
16739+ params = []
16740+ for source_key in _copy_enc_source_modes.keys():
16741+ source_marks = _copy_enc_source_modes[source_key].get('marks', [])
16742+
16743+ for source_sc in sc:
16744+ for dest_sc in sc:
16745+ if source_sc == dest_sc:
16746+ continue
16747+
16748+ params.append(pytest.param(
16749+ source_key,
16750+ source_sc,
16751+ dest_sc,
16752+ marks=source_marks
16753+ ))
16754+
16755+ return params
16756+
16757+ def _test_lifecycle_transition(source_mode_key, source_sc=None, dest_sc=None):
16758+ source_args = _copy_enc_source_modes[source_mode_key]
16759+ args = {key: value() if callable(value) else value for key, value in source_args.get('args', {}).items()}
16760+ if source_sc:
16761+ args['StorageClass'] = source_sc
16762+
16763+ bucket_name = _create_objects(keys=['expire1/foo', 'expire1/bar'], put_object_args=args)
16764+ client = get_client()
16765+ rules=[{'ID': 'rule1', 'Prefix': '', 'Transitions': [{'Days': 1, 'StorageClass': dest_sc}], 'Status': 'Enabled'}]
16766+ lifecycle = {'Rules': rules}
16767+ client.put_bucket_lifecycle_configuration(Bucket=bucket_name, LifecycleConfiguration=lifecycle)
16768+
16769+ # Get list of all keys
16770+ response = client.list_objects(Bucket=bucket_name)
16771+ init_keys = _get_keys(response)
16772+ assert len(init_keys) == 2
16773+
16774+ lc_interval = get_lc_debug_interval()
16775+
16776+ # Wait for expiration
16777+ time.sleep(4*lc_interval)
16778+ expire1_keys = list_bucket_storage_class(client, bucket_name)
16779+ assert len(expire1_keys[source_sc]) == 0
16780+ assert len(expire1_keys[dest_sc]) == 2
16781+
16782+ # retrieve the objects
16783+ get_args = source_args.get('get_args', {})
16784+ for key in init_keys:
16785+ response = client.get_object(Bucket=bucket_name, Key=key, **get_args)
16786+ body = _get_body(response)
16787+ assert body == key
16788+
16789+ @pytest.mark.lifecycle
16790+ @pytest.mark.lifecycle_transition
16791+ @pytest.mark.fails_on_aws
16792+ @pytest.mark.encryption
16793+ @pytest.mark.fails_on_dbstore
16794+ @pytest.mark.parametrize(
16795+ "source_mode_key, source_storage_class, dest_storage_class",
16796+ generate_lifecycle_transition_params()
16797+ )
16798+ def test_lifecycle_transition_encrypted(source_mode_key, source_storage_class, dest_storage_class):
16799+ if len(configured_storage_classes()) < 2:
16800+ pytest.skip('need at least two storage classes to test lifecycle transition')
16801+
16802+ print(
16803+ f"Testing lifecycle transition of {source_mode_key} with storage class {source_storage_class} -> {dest_storage_class}"
16804+ )
16805+ _test_lifecycle_transition(source_mode_key, source_storage_class, dest_storage_class)
0 commit comments