2018-06-07 07:09:36 +00:00
|
|
|
import boto3
|
2020-10-06 05:54:49 +00:00
|
|
|
import pytest
|
2023-11-30 15:55:51 +00:00
|
|
|
from botocore.exceptions import ClientError
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
from moto import mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_storage_class_standard():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
s3_client.create_bucket(Bucket="Bucket")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
# add an object to the bucket with standard storage
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(Bucket="Bucket", Key="my_key", Body="my_value")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
list_of_objects = s3_client.list_objects(Bucket="Bucket")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
assert list_of_objects["Contents"][0]["StorageClass"] == "STANDARD"
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_storage_class_infrequent_access():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-2"}
|
|
|
|
)
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
# add an object to the bucket with standard storage
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
Bucket="Bucket",
|
|
|
|
Key="my_key_infrequent",
|
|
|
|
Body="my_value_infrequent",
|
|
|
|
StorageClass="STANDARD_IA",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
objs = s3_client.list_objects(Bucket="Bucket")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
assert objs["Contents"][0]["StorageClass"] == "STANDARD_IA"
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2019-08-05 15:34:39 +00:00
|
|
|
def test_s3_storage_class_intelligent_tiering():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
2019-08-05 15:34:39 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-east-2"}
|
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2019-08-05 15:34:39 +00:00
|
|
|
Bucket="Bucket",
|
|
|
|
Key="my_key_infrequent",
|
|
|
|
Body="my_value_infrequent",
|
|
|
|
StorageClass="INTELLIGENT_TIERING",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
objects = s3_client.list_objects(Bucket="Bucket")
|
2019-08-05 15:34:39 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
assert objects["Contents"][0]["StorageClass"] == "INTELLIGENT_TIERING"
|
2019-08-05 15:34:39 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_storage_class_copy():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
s3_client.create_bucket(Bucket="Bucket")
|
|
|
|
s3_client.put_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD"
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(Bucket="Bucket2")
|
2018-06-07 07:09:36 +00:00
|
|
|
# second object is originally of storage class REDUCED_REDUNDANCY
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.copy_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket2",
|
|
|
|
Key="Second_Object",
|
|
|
|
StorageClass="ONEZONE_IA",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
# checks that a copied object can be properly copied
|
2023-08-07 16:48:48 +00:00
|
|
|
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "ONEZONE_IA"
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_invalid_copied_storage_class():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
s3_client.create_bucket(Bucket="Bucket")
|
|
|
|
s3_client.put_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD"
|
|
|
|
)
|
2019-10-31 15:44:26 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(Bucket="Bucket2")
|
|
|
|
s3_client.put_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
Bucket="Bucket2",
|
|
|
|
Key="Second_Object",
|
|
|
|
Body="Body2",
|
|
|
|
StorageClass="REDUCED_REDUNDANCY",
|
|
|
|
)
|
2019-10-31 15:44:26 +00:00
|
|
|
|
2018-06-07 07:09:36 +00:00
|
|
|
# Try to copy an object with an invalid storage class
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError) as err:
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.copy_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket2",
|
|
|
|
Key="Second_Object",
|
|
|
|
StorageClass="STANDARD2",
|
|
|
|
)
|
2019-10-31 15:44:26 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
err_value = err.value
|
|
|
|
assert err_value.response["Error"]["Code"] == "InvalidStorageClass"
|
|
|
|
assert err_value.response["Error"]["Message"] == (
|
2018-06-07 07:09:36 +00:00
|
|
|
"The storage class you specified is not valid"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_invalid_storage_class():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
|
|
|
|
)
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
# Try to add an object with an invalid storage class
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError) as err:
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2018-06-07 07:09:36 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARDD"
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
err_value = err.value
|
|
|
|
assert err_value.response["Error"]["Code"] == "InvalidStorageClass"
|
|
|
|
assert err_value.response["Error"]["Message"] == (
|
2018-06-07 07:09:36 +00:00
|
|
|
"The storage class you specified is not valid"
|
|
|
|
)
|
|
|
|
|
2019-08-05 15:34:39 +00:00
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2018-06-07 07:09:36 +00:00
|
|
|
def test_s3_default_storage_class():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
|
|
|
|
)
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(Bucket="Bucket", Key="First_Object", Body="Body")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
list_of_objects = s3_client.list_objects(Bucket="Bucket")
|
2018-06-07 07:09:36 +00:00
|
|
|
|
|
|
|
# tests that the default storage class is still STANDARD
|
2023-08-07 16:48:48 +00:00
|
|
|
assert list_of_objects["Contents"][0]["StorageClass"] == "STANDARD"
|
2018-07-10 17:52:53 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-09-21 06:37:50 +00:00
|
|
|
def test_s3_copy_object_error_for_glacier_storage_class_not_restored():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
|
|
|
|
)
|
2019-08-05 15:34:39 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2019-08-05 15:34:39 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="GLACIER"
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
s3_client.copy_object(
|
2019-08-05 15:34:39 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket",
|
|
|
|
Key="Second_Object",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
assert exc.value.response["Error"]["Code"] == "ObjectNotInActiveTierError"
|
2019-08-05 15:34:39 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-09-21 06:37:50 +00:00
|
|
|
def test_s3_copy_object_error_for_deep_archive_storage_class_not_restored():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3")
|
|
|
|
s3_client.create_bucket(
|
2020-02-02 10:36:51 +00:00
|
|
|
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
|
|
|
|
)
|
2019-08-05 15:34:39 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2019-08-05 15:34:39 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="DEEP_ARCHIVE"
|
|
|
|
)
|
|
|
|
|
2020-10-06 05:54:49 +00:00
|
|
|
with pytest.raises(ClientError) as exc:
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.copy_object(
|
2019-08-05 15:34:39 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket",
|
|
|
|
Key="Second_Object",
|
|
|
|
)
|
2018-07-10 17:52:53 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
assert exc.value.response["Error"]["Code"] == "ObjectNotInActiveTierError"
|
2020-09-21 06:37:50 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-09-21 06:37:50 +00:00
|
|
|
def test_s3_copy_object_for_glacier_storage_class_restored():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
s3_client.create_bucket(Bucket="Bucket")
|
2020-09-21 06:37:50 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2020-09-21 06:37:50 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="GLACIER"
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(Bucket="Bucket2")
|
2024-03-10 14:51:22 +00:00
|
|
|
resp = s3_client.restore_object(
|
2023-08-07 16:48:48 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123}
|
|
|
|
)
|
2024-03-10 14:51:22 +00:00
|
|
|
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 202
|
2020-09-21 06:37:50 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.copy_object(
|
2020-09-21 06:37:50 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket2",
|
|
|
|
Key="Second_Object",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
|
2020-09-21 06:37:50 +00:00
|
|
|
# checks that copy of restored Glacier object has STANDARD storage class
|
2023-08-07 16:48:48 +00:00
|
|
|
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "STANDARD"
|
2020-09-21 06:37:50 +00:00
|
|
|
# checks that metadata of copy has no Restore property
|
2023-08-07 16:48:48 +00:00
|
|
|
assert not hasattr(
|
|
|
|
s3_client.head_object(Bucket="Bucket2", Key="Second_Object"), "Restore"
|
2020-09-21 06:37:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2020-09-21 06:37:50 +00:00
|
|
|
def test_s3_copy_object_for_deep_archive_storage_class_restored():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
s3_client.create_bucket(Bucket="Bucket")
|
2020-09-21 06:37:50 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2020-09-21 06:37:50 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="DEEP_ARCHIVE"
|
|
|
|
)
|
|
|
|
|
2023-03-09 22:00:17 +00:00
|
|
|
with pytest.raises(ClientError) as exc:
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.get_object(Bucket="Bucket", Key="First_Object")
|
2023-03-09 22:00:17 +00:00
|
|
|
err = exc.value.response["Error"]
|
2023-08-07 16:48:48 +00:00
|
|
|
assert err["Code"] == "InvalidObjectState"
|
|
|
|
assert err["Message"] == (
|
2023-03-09 22:00:17 +00:00
|
|
|
"The operation is not valid for the object's storage class"
|
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert err["StorageClass"] == "DEEP_ARCHIVE"
|
2023-03-09 22:00:17 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(Bucket="Bucket2")
|
2024-03-10 14:51:22 +00:00
|
|
|
resp = s3_client.restore_object(
|
2023-08-07 16:48:48 +00:00
|
|
|
Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123}
|
|
|
|
)
|
2024-03-10 14:51:22 +00:00
|
|
|
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 202
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.get_object(Bucket="Bucket", Key="First_Object")
|
2020-09-21 06:37:50 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.copy_object(
|
2020-09-21 06:37:50 +00:00
|
|
|
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
|
|
|
|
Bucket="Bucket2",
|
|
|
|
Key="Second_Object",
|
|
|
|
)
|
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
|
2020-09-21 06:37:50 +00:00
|
|
|
# checks that copy of restored Glacier object has STANDARD storage class
|
2023-08-07 16:48:48 +00:00
|
|
|
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "STANDARD"
|
2020-09-21 06:37:50 +00:00
|
|
|
# checks that metadata of copy has no Restore property
|
2023-08-07 16:48:48 +00:00
|
|
|
assert not hasattr(
|
|
|
|
s3_client.head_object(Bucket="Bucket2", Key="Second_Object"), "Restore"
|
2020-09-21 06:37:50 +00:00
|
|
|
)
|
2021-11-02 23:02:14 +00:00
|
|
|
|
|
|
|
|
2024-01-07 12:03:33 +00:00
|
|
|
@mock_aws
|
2021-11-02 23:02:14 +00:00
|
|
|
def test_s3_get_object_from_glacier():
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client = boto3.client("s3", region_name="us-east-1")
|
2021-11-02 23:02:14 +00:00
|
|
|
bucket_name = "tests3getobjectfromglacier"
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.create_bucket(Bucket=bucket_name)
|
2021-11-02 23:02:14 +00:00
|
|
|
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.put_object(
|
2021-11-02 23:02:14 +00:00
|
|
|
Bucket=bucket_name, Key="test.txt", Body="contents", StorageClass="GLACIER"
|
|
|
|
)
|
|
|
|
with pytest.raises(ClientError) as exc:
|
2023-08-07 16:48:48 +00:00
|
|
|
s3_client.get_object(Bucket=bucket_name, Key="test.txt")
|
2021-11-02 23:02:14 +00:00
|
|
|
err = exc.value.response["Error"]
|
2023-08-07 16:48:48 +00:00
|
|
|
assert err["Code"] == "InvalidObjectState"
|
|
|
|
assert err["Message"] == (
|
2021-11-02 23:02:14 +00:00
|
|
|
"The operation is not valid for the object's storage class"
|
|
|
|
)
|
2023-08-07 16:48:48 +00:00
|
|
|
assert err["StorageClass"] == "GLACIER"
|