Techdebt: Replace sure with regular assertions in S3 (#6603)

This commit is contained in:
kbalk 2023-08-07 12:48:48 -04:00 committed by GitHub
parent 673e9479b0
commit 29b66fe10c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 2289 additions and 2241 deletions

View File

@ -1,8 +1,9 @@
from unittest import SkipTest
import requests
from moto import settings
from moto.server import ThreadedMotoServer
from unittest import SkipTest
SERVER_PORT = 5001
@ -27,8 +28,8 @@ class TestAccountIdResolution:
requests.put(f"http://{name}.localhost:{SERVER_PORT}/")
res = requests.get(BASE_URL)
res.content.should.contain(b"<Name>foo</Name>")
res.content.should.contain(b"<Name>bar</Name>")
assert b"<Name>foo</Name>" in res.content
assert b"<Name>bar</Name>" in res.content
# Create two more buckets in another account
headers = {"x-moto-account-id": "333344445555"}
@ -38,12 +39,12 @@ class TestAccountIdResolution:
# Verify only these buckets exist in this account
res = requests.get(BASE_URL, headers=headers)
res.content.should.contain(b"<Name>baz</Name>")
res.content.should.contain(b"<Name>bla</Name>")
res.content.shouldnt.contain(b"<Name>foo</Name>")
res.content.shouldnt.contain(b"<Name>bar</Name>")
assert b"<Name>baz</Name>" in res.content
assert b"<Name>bla</Name>" in res.content
assert b"<Name>foo</Name>" not in res.content
assert b"<Name>bar</Name>" not in res.content
# Verify these buckets do not exist in the original account
res = requests.get(BASE_URL)
res.content.shouldnt.contain(b"<Name>baz</Name>")
res.content.shouldnt.contain(b"<Name>bla</Name>")
assert b"<Name>baz</Name>" not in res.content
assert b"<Name>bla</Name>" not in res.content

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
import boto3
import os
from uuid import uuid4
import boto3
import pytest
import requests
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from botocore.handlers import disable_signing
from moto import mock_s3
from uuid import uuid4
DEFAULT_REGION_NAME = "us-east-1"
@ -22,10 +22,10 @@ DEFAULT_REGION_NAME = "us-east-1"
@pytest.mark.parametrize("readwrite", ["Read", "Write"])
@mock_s3
def test_put_object_acl_using_grant(readwrite, type_key, value, has_quotes):
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = str(uuid4())
bucket = s3.Bucket(bucket_name)
bucket = s3_resource.Bucket(bucket_name)
bucket.create()
keyname = "test.txt"
@ -40,16 +40,16 @@ def test_put_object_acl_using_grant(readwrite, type_key, value, has_quotes):
client.put_object_acl(**args)
grants = client.get_object_acl(Bucket=bucket_name, Key=keyname)["Grants"]
grants.should.have.length_of(1)
grants[0].should.have.key("Grantee").equal({"Type": _type, response_key: value})
grants[0].should.have.key("Permission").equal(readwrite.upper())
assert len(grants) == 1
assert grants[0]["Grantee"] == {"Type": _type, response_key: value}
assert grants[0]["Permission"] == readwrite.upper()
@mock_s3
def test_acl_switching_boto3():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3.Bucket("foobar")
bucket = s3_resource.Bucket("foobar")
bucket.create()
keyname = "test.txt"
@ -57,32 +57,30 @@ def test_acl_switching_boto3():
client.put_object_acl(ACL="private", Bucket="foobar", Key=keyname)
grants = client.get_object_acl(Bucket="foobar", Key=keyname)["Grants"]
grants.shouldnt.contain(
{
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
}
)
assert {
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
} not in grants
@mock_s3
def test_acl_switching_nonexistent_key():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="mybucket")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="mybucket")
with pytest.raises(ClientError) as e:
s3.put_object_acl(Bucket="mybucket", Key="nonexistent", ACL="private")
with pytest.raises(ClientError) as exc:
s3_client.put_object_acl(Bucket="mybucket", Key="nonexistent", ACL="private")
e.value.response["Error"]["Code"].should.equal("NoSuchKey")
assert exc.value.response["Error"]["Code"] == "NoSuchKey"
@mock_s3
def test_s3_object_in_public_bucket():
s3 = boto3.resource("s3")
bucket = s3.Bucket("test-bucket")
s3_resource = boto3.resource("s3")
bucket = s3_resource.Bucket("test-bucket")
bucket.create(
ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
@ -96,19 +94,19 @@ def test_s3_object_in_public_bucket():
.get()["Body"]
.read()
)
contents.should.equal(b"ABCD")
assert contents == b"ABCD"
bucket.put_object(ACL="private", Body=b"ABCD", Key="file.txt")
with pytest.raises(ClientError) as exc:
s3_anonymous.Object(key="file.txt", bucket_name="test-bucket").get()
exc.value.response["Error"]["Code"].should.equal("403")
assert exc.value.response["Error"]["Code"] == "403"
@mock_s3
def test_s3_object_in_public_bucket_using_multiple_presigned_urls():
s3 = boto3.resource("s3")
bucket = s3.Bucket("test-bucket")
s3_resource = boto3.resource("s3")
bucket = s3_resource.Bucket("test-bucket")
bucket.create(
ACL="public-read", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
@ -125,8 +123,8 @@ def test_s3_object_in_public_bucket_using_multiple_presigned_urls():
@mock_s3
def test_s3_object_in_private_bucket():
s3 = boto3.resource("s3")
bucket = s3.Bucket("test-bucket")
s3_resource = boto3.resource("s3")
bucket = s3_resource.Bucket("test-bucket")
bucket.create(
ACL="private", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
@ -137,7 +135,7 @@ def test_s3_object_in_private_bucket():
with pytest.raises(ClientError) as exc:
s3_anonymous.Object(key="file.txt", bucket_name="test-bucket").get()
exc.value.response["Error"]["Code"].should.equal("403")
assert exc.value.response["Error"]["Code"] == "403"
bucket.put_object(ACL="public-read", Body=b"ABCD", Key="file.txt")
contents = (
@ -145,15 +143,15 @@ def test_s3_object_in_private_bucket():
.get()["Body"]
.read()
)
contents.should.equal(b"ABCD")
assert contents == b"ABCD"
@mock_s3
def test_put_bucket_acl_body():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="bucket")
bucket_owner = s3.get_bucket_acl(Bucket="bucket")["Owner"]
s3.put_bucket_acl(
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="bucket")
bucket_owner = s3_client.get_bucket_acl(Bucket="bucket")["Owner"]
s3_client.put_bucket_acl(
Bucket="bucket",
AccessControlPolicy={
"Grants": [
@ -176,15 +174,17 @@ def test_put_bucket_acl_body():
},
)
result = s3.get_bucket_acl(Bucket="bucket")
result = s3_client.get_bucket_acl(Bucket="bucket")
assert len(result["Grants"]) == 2
for g in result["Grants"]:
assert g["Grantee"]["URI"] == "http://acs.amazonaws.com/groups/s3/LogDelivery"
assert g["Grantee"]["Type"] == "Group"
assert g["Permission"] in ["WRITE", "READ_ACP"]
for grant in result["Grants"]:
assert (
grant["Grantee"]["URI"] == "http://acs.amazonaws.com/groups/s3/LogDelivery"
)
assert grant["Grantee"]["Type"] == "Group"
assert grant["Permission"] in ["WRITE", "READ_ACP"]
# With one:
s3.put_bucket_acl(
s3_client.put_bucket_acl(
Bucket="bucket",
AccessControlPolicy={
"Grants": [
@ -199,12 +199,12 @@ def test_put_bucket_acl_body():
"Owner": bucket_owner,
},
)
result = s3.get_bucket_acl(Bucket="bucket")
result = s3_client.get_bucket_acl(Bucket="bucket")
assert len(result["Grants"]) == 1
# With no owner:
with pytest.raises(ClientError) as err:
s3.put_bucket_acl(
s3_client.put_bucket_acl(
Bucket="bucket",
AccessControlPolicy={
"Grants": [
@ -222,7 +222,7 @@ def test_put_bucket_acl_body():
# With incorrect permission:
with pytest.raises(ClientError) as err:
s3.put_bucket_acl(
s3_client.put_bucket_acl(
Bucket="bucket",
AccessControlPolicy={
"Grants": [
@ -240,7 +240,7 @@ def test_put_bucket_acl_body():
assert err.value.response["Error"]["Code"] == "MalformedACLError"
# Clear the ACLs:
result = s3.put_bucket_acl(
result = s3_client.put_bucket_acl(
Bucket="bucket", AccessControlPolicy={"Grants": [], "Owner": bucket_owner}
)
assert not result.get("Grants")
@ -248,31 +248,31 @@ def test_put_bucket_acl_body():
@mock_s3
def test_object_acl_with_presigned_post():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "imageS3Bucket"
object_name = "text.txt"
fields = {"acl": "public-read"}
file = open("text.txt", "w")
file = open("text.txt", "w", encoding="utf-8")
file.write("test")
file.close()
s3.create_bucket(Bucket=bucket_name)
response = s3.generate_presigned_post(
s3_client.create_bucket(Bucket=bucket_name)
response = s3_client.generate_presigned_post(
bucket_name, object_name, Fields=fields, ExpiresIn=60000
)
with open(object_name, "rb") as f:
files = {"file": (object_name, f)}
with open(object_name, "rb") as fhandle:
files = {"file": (object_name, fhandle)}
requests.post(response["url"], data=response["fields"], files=files)
response = s3.get_object_acl(Bucket=bucket_name, Key=object_name)
response = s3_client.get_object_acl(Bucket=bucket_name, Key=object_name)
assert "Grants" in response
assert len(response["Grants"]) == 2
assert response["Grants"][1]["Permission"] == "READ"
response = s3.get_object(Bucket=bucket_name, Key=object_name)
response = s3_client.get_object(Bucket=bucket_name, Key=object_name)
assert "ETag" in response
assert "Body" in response
@ -281,9 +281,9 @@ def test_object_acl_with_presigned_post():
@mock_s3
def test_acl_setting_boto3():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3.Bucket("foobar")
bucket = s3_resource.Bucket("foobar")
bucket.create()
content = b"imafile"
@ -293,22 +293,20 @@ def test_acl_setting_boto3():
)
grants = client.get_object_acl(Bucket="foobar", Key=keyname)["Grants"]
grants.should.contain(
{
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
}
)
assert {
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
} in grants
@mock_s3
def test_acl_setting_via_headers_boto3():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3.Bucket("foobar")
bucket = s3_resource.Bucket("foobar")
bucket.create()
keyname = "test.txt"
@ -317,28 +315,27 @@ def test_acl_setting_via_headers_boto3():
client.put_object_acl(ACL="public-read", Bucket="foobar", Key=keyname)
grants = client.get_object_acl(Bucket="foobar", Key=keyname)["Grants"]
grants.should.contain(
{
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
}
)
assert {
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AllUsers",
},
"Permission": "READ",
} in grants
@mock_s3
def test_raise_exception_for_grant_and_acl():
client = boto3.client("s3")
s3 = boto3.resource("s3")
s3_resource = boto3.resource("s3")
bucket_name = "bucketname"
client.create_bucket(Bucket=bucket_name)
bucket = s3.Bucket(bucket_name)
bucket = s3_resource.Bucket(bucket_name)
acl = client.get_bucket_acl(Bucket=bucket_name)
acl_grantee_id = acl["Owner"]["ID"]
# This should raise an exception or provide some error message, but runs without exception instead.
# This should raise an exception or provide some error message,
# but runs without exception instead.
with pytest.raises(ClientError) as exc:
bucket.put_object(
ACL="bucket-owner-full-control",
@ -348,7 +345,7 @@ def test_raise_exception_for_grant_and_acl():
GrantFullControl=f'id="{acl_grantee_id}"',
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidRequest")
err["Message"].should.equal(
"Specifying both Canned ACLs and Header Grants is not allowed"
assert err["Code"] == "InvalidRequest"
assert (
err["Message"] == "Specifying both Canned ACLs and Header Grants is not allowed"
)

View File

@ -1,12 +1,12 @@
import boto3
import json
from unittest import SkipTest
import boto3
import pytest
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from moto import mock_iam, mock_s3, mock_sts, settings
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID, set_initial_no_auth_action_count
from unittest import SkipTest
@mock_s3
@ -15,15 +15,15 @@ def test_load_unexisting_object_without_auth_should_return_403():
if settings.TEST_SERVER_MODE:
raise SkipTest("Auth decorator does not work in server mode")
"""Head an S3 object we should have no access to."""
# Head an S3 object we should have no access to.
resource = boto3.resource("s3", region_name="us-east-1")
obj = resource.Object("myfakebucket", "myfakekey")
with pytest.raises(ClientError) as ex:
obj.load()
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidAccessKeyId")
err["Message"].should.equal(
assert err["Code"] == "InvalidAccessKeyId"
assert err["Message"] == (
"The AWS Access Key Id you provided does not exist in our records."
)
@ -38,12 +38,12 @@ def test_head_bucket_with_correct_credentials():
iam_keys = create_user_with_access_key_and_policy()
# This S3-client has correct credentials
s3 = boto3.client(
s3_client = boto3.client(
"s3",
aws_access_key_id=iam_keys["AccessKeyId"],
aws_secret_access_key=iam_keys["SecretAccessKey"],
)
s3.create_bucket(Bucket="mock_bucket")
s3_client.create_bucket(Bucket="mock_bucket")
# Calling head_bucket with the correct credentials works
my_head_bucket(
@ -52,10 +52,11 @@ def test_head_bucket_with_correct_credentials():
aws_secret_access_key=iam_keys["SecretAccessKey"],
)
# Verify we can make calls that contain a querystring
# Specifically, verify that we are able to build/match the AWS signature for a URL with a querystring
s3.get_bucket_location(Bucket="mock_bucket")
s3.list_objects_v2(Bucket="mock_bucket")
# Verify we can make calls that contain a querystring. Specifically,
# verify that we are able to build/match the AWS signature for a URL
# with a querystring.
s3_client.get_bucket_location(Bucket="mock_bucket")
s3_client.list_objects_v2(Bucket="mock_bucket")
@set_initial_no_auth_action_count(4)
@ -68,12 +69,12 @@ def test_head_bucket_with_incorrect_credentials():
iam_keys = create_user_with_access_key_and_policy()
# Create the bucket with correct credentials
s3 = boto3.client(
s3_client = boto3.client(
"s3",
aws_access_key_id=iam_keys["AccessKeyId"],
aws_secret_access_key=iam_keys["SecretAccessKey"],
)
s3.create_bucket(Bucket="mock_bucket")
s3_client.create_bucket(Bucket="mock_bucket")
# Call head_bucket with incorrect credentials
with pytest.raises(ClientError) as ex:
@ -83,8 +84,8 @@ def test_head_bucket_with_incorrect_credentials():
aws_secret_access_key="invalid",
)
err = ex.value.response["Error"]
err["Code"].should.equal("SignatureDoesNotMatch")
err["Message"].should.equal(
assert err["Code"] == "SignatureDoesNotMatch"
assert err["Message"] == (
"The request signature we calculated does not match the signature you provided. "
"Check your key and signing method."
)
@ -200,12 +201,13 @@ def test_delete_objects_without_access_throws_custom_error():
)
bucket = s3_resource.Bucket(bucket_name)
# This action is not allowed
# It should return a 200-response, with the body indicating that we do not have access
# This action is not allowed.
# It should return a 200-response, with the body indicating that we
# do not have access.
response = bucket.objects.filter(Prefix="some/prefix").delete()[0]
response.should.have.key("Errors").length_of(1)
assert len(response["Errors"]) == 1
error = response["Errors"][0]
error.should.have.key("Key").equals("some/prefix/test_file.txt")
error.should.have.key("Code").equals("AccessDenied")
error.should.have.key("Message").equals("Access Denied")
assert error["Key"] == "some/prefix/test_file.txt"
assert error["Code"] == "AccessDenied"
assert error["Message"] == "Access Denied"

View File

@ -1,15 +1,15 @@
import boto3
import json
import boto3
import requests
import pytest
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from moto.moto_server.threaded_moto_server import ThreadedMotoServer
class TestBucketPolicy:
@staticmethod
@classmethod
def setup_class(cls):
cls.server = ThreadedMotoServer(port="6000", verbose=False)
cls.server.start()
@ -30,7 +30,7 @@ class TestBucketPolicy:
self.client.delete_object(Bucket="mybucket", Key="test_txt")
self.client.delete_bucket(Bucket="mybucket")
@staticmethod
@classmethod
def teardown_class(cls):
cls.server.stop()
@ -67,7 +67,7 @@ class TestBucketPolicy:
with pytest.raises(ClientError):
self.client.get_object(Bucket="mybucket", Key="test_txt")
requests.get(self.key_name).status_code.should.equal(status)
assert requests.get(self.key_name).status_code == status
def test_block_put_object(self):
# Block Put-access
@ -80,9 +80,9 @@ class TestBucketPolicy:
with pytest.raises(ClientError) as exc:
self.client.put_object(Bucket="mybucket", Key="test_txt", Body="new data")
err = exc.value.response["Error"]
err["Message"].should.equal("Forbidden")
assert err["Message"] == "Forbidden"
requests.put(self.key_name).status_code.should.equal(403)
assert requests.put(self.key_name).status_code == 403
def test_block_all_actions(self):
# Block all access
@ -92,16 +92,16 @@ class TestBucketPolicy:
with pytest.raises(ClientError) as exc:
self.client.get_object(Bucket="mybucket", Key="test_txt")
err = exc.value.response["Error"]
err["Message"].should.equal("Forbidden")
assert err["Message"] == "Forbidden"
# But Put (via boto3 or requests) is not allowed
with pytest.raises(ClientError) as exc:
self.client.put_object(Bucket="mybucket", Key="test_txt", Body="new data")
err = exc.value.response["Error"]
err["Message"].should.equal("Forbidden")
assert err["Message"] == "Forbidden"
requests.get(self.key_name).status_code.should.equal(403)
requests.put(self.key_name).status_code.should.equal(403)
assert requests.get(self.key_name).status_code == 403
assert requests.put(self.key_name).status_code == 403
# Allow access again, because we want to delete the object during teardown
self._put_policy(**{"effect": "Allow", "actions": ["s3:*"]})

View File

@ -1,6 +1,6 @@
import boto3
import sure # noqa # pylint: disable=unused-import
import unittest
import boto3
from moto import mock_s3
@ -9,10 +9,9 @@ class ClassDecoratorTest(unittest.TestCase):
"""
https://github.com/getmoto/moto/issues/3535
An update to the mock-package introduced a failure during teardown.
This test is in place to catch any similar failures with our mocking approach
This test is in place to catch any similar failures with our
mocking approach.
"""
def test_instantiation_succeeds(self):
s3 = boto3.client("s3", region_name="us-east-1")
assert s3 is not None
assert boto3.client("s3", region_name="us-east-1") is not None

View File

@ -1,7 +1,7 @@
import json
import boto3
import re
import sure # noqa # pylint: disable=unused-import
import boto3
from moto import mock_s3, mock_cloudformation
@ -9,8 +9,8 @@ from moto import mock_s3, mock_cloudformation
@mock_s3
@mock_cloudformation
def test_s3_bucket_cloudformation_basic():
s3 = boto3.client("s3", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
cf_client = boto3.client("cloudformation", region_name="us-east-1")
template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -18,17 +18,17 @@ def test_s3_bucket_cloudformation_basic():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
@mock_s3
@mock_cloudformation
def test_s3_bucket_cloudformation_with_properties():
s3 = boto3.client("s3", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
cf_client = boto3.client("cloudformation", region_name="us-east-1")
bucket_name = "MyBucket"
template = {
@ -53,21 +53,24 @@ def test_s3_bucket_cloudformation_with_properties():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
cf.describe_stacks(StackName="test_stack")
s3.head_bucket(Bucket=bucket_name)
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
cf_client.describe_stacks(StackName="test_stack")
s3_client.head_bucket(Bucket=bucket_name)
encryption = s3.get_bucket_encryption(Bucket=bucket_name)
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
"ApplyServerSideEncryptionByDefault"
]["SSEAlgorithm"].should.equal("AES256")
encryption = s3_client.get_bucket_encryption(Bucket=bucket_name)
assert (
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
"ApplyServerSideEncryptionByDefault"
]["SSEAlgorithm"]
== "AES256"
)
@mock_s3
@mock_cloudformation
def test_s3_bucket_cloudformation_update_no_interruption():
s3 = boto3.client("s3", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
cf_client = boto3.client("cloudformation", region_name="us-east-1")
template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -75,9 +78,9 @@ def test_s3_bucket_cloudformation_update_no_interruption():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -100,20 +103,23 @@ def test_s3_bucket_cloudformation_update_no_interruption():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.update_stack(StackName="test_stack", TemplateBody=template_json)
encryption = s3.get_bucket_encryption(
cf_client.update_stack(StackName="test_stack", TemplateBody=template_json)
encryption = s3_client.get_bucket_encryption(
Bucket=stack_description["Outputs"][0]["OutputValue"]
)
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
"ApplyServerSideEncryptionByDefault"
]["SSEAlgorithm"].should.equal("AES256")
assert (
encryption["ServerSideEncryptionConfiguration"]["Rules"][0][
"ApplyServerSideEncryptionByDefault"
]["SSEAlgorithm"]
== "AES256"
)
@mock_s3
@mock_cloudformation
def test_s3_bucket_cloudformation_update_replacement():
s3 = boto3.client("s3", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
cf_client = boto3.client("cloudformation", region_name="us-east-1")
template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -121,9 +127,9 @@ def test_s3_bucket_cloudformation_update_replacement():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
cf_client.create_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -136,17 +142,17 @@ def test_s3_bucket_cloudformation_update_replacement():
"Outputs": {"Bucket": {"Value": {"Ref": "testInstance"}}},
}
template_json = json.dumps(template)
cf.update_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
s3.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
cf_client.update_stack(StackName="test_stack", TemplateBody=template_json)
stack_description = cf_client.describe_stacks(StackName="test_stack")["Stacks"][0]
s3_client.head_bucket(Bucket=stack_description["Outputs"][0]["OutputValue"])
@mock_s3
@mock_cloudformation
def test_s3_bucket_cloudformation_outputs():
region_name = "us-east-1"
s3 = boto3.client("s3", region_name=region_name)
cf = boto3.resource("cloudformation", region_name=region_name)
s3_client = boto3.client("s3", region_name=region_name)
cf_client = boto3.resource("cloudformation", region_name=region_name)
stack_name = "test-stack"
bucket_name = "test-bucket"
template = {
@ -188,19 +194,19 @@ def test_s3_bucket_cloudformation_outputs():
},
},
}
cf.create_stack(StackName=stack_name, TemplateBody=json.dumps(template))
outputs_list = cf.Stack(stack_name).outputs
cf_client.create_stack(StackName=stack_name, TemplateBody=json.dumps(template))
outputs_list = cf_client.Stack(stack_name).outputs
output = {item["OutputKey"]: item["OutputValue"] for item in outputs_list}
s3.head_bucket(Bucket=output["BucketName"])
output["BucketARN"].should.match(f"arn:aws:s3.+{bucket_name}")
output["BucketDomainName"].should.equal(f"{bucket_name}.s3.amazonaws.com")
output["BucketDualStackDomainName"].should.equal(
s3_client.head_bucket(Bucket=output["BucketName"])
assert re.match(f"arn:aws:s3.+{bucket_name}", output["BucketARN"])
assert output["BucketDomainName"] == f"{bucket_name}.s3.amazonaws.com"
assert output["BucketDualStackDomainName"] == (
f"{bucket_name}.s3.dualstack.{region_name}.amazonaws.com"
)
output["BucketRegionalDomainName"].should.equal(
assert output["BucketRegionalDomainName"] == (
f"{bucket_name}.s3.{region_name}.amazonaws.com"
)
output["BucketWebsiteURL"].should.equal(
assert output["BucketWebsiteURL"] == (
f"http://{bucket_name}.s3-website.{region_name}.amazonaws.com"
)
output["BucketName"].should.equal(bucket_name)
assert output["BucketName"] == bucket_name

View File

@ -1,6 +1,5 @@
import json
import pytest
import sure # noqa # pylint: disable=unused-import
from moto import mock_s3
from moto.core.exceptions import InvalidNextTokenException
@ -53,30 +52,30 @@ def test_list_config_discovered_resources():
) == ([], None)
# With 10 buckets in us-west-2:
for x in range(0, 10):
s3_config_query_backend.create_bucket(f"bucket{x}", "us-west-2")
for idx in range(0, 10):
s3_config_query_backend.create_bucket(f"bucket{idx}", "us-west-2")
# With 2 buckets in eu-west-1:
for x in range(10, 12):
s3_config_query_backend.create_bucket(f"eu-bucket{x}", "eu-west-1")
for idx in range(10, 12):
s3_config_query_backend.create_bucket(f"eu-bucket{idx}", "eu-west-1")
result, next_token = s3_config_query.list_config_service_resources(
DEFAULT_ACCOUNT_ID, None, None, 100, None
)
assert not next_token
assert len(result) == 12
for x in range(0, 10):
assert result[x] == {
for idx in range(0, 10):
assert result[idx] == {
"type": "AWS::S3::Bucket",
"id": f"bucket{x}",
"name": f"bucket{x}",
"id": f"bucket{idx}",
"name": f"bucket{idx}",
"region": "us-west-2",
}
for x in range(10, 12):
assert result[x] == {
for idx in range(10, 12):
assert result[idx] == {
"type": "AWS::S3::Bucket",
"id": f"eu-bucket{x}",
"name": f"eu-bucket{x}",
"id": f"eu-bucket{idx}",
"name": f"eu-bucket{idx}",
"region": "eu-west-1",
}

View File

@ -3,13 +3,10 @@ import datetime
import boto3
from botocore.client import ClientError
from moto import mock_s3, mock_kms
from moto.s3.responses import DEFAULT_REGION_NAME
import pytest
import sure # noqa # pylint: disable=unused-import
from moto import mock_s3, mock_kms
@pytest.mark.parametrize(
"key_name",
@ -22,38 +19,38 @@ from moto import mock_s3, mock_kms
)
@mock_s3
def test_copy_key_boto3(key_name):
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
key = s3.Object("foobar", key_name)
key = s3_resource.Object("foobar", key_name)
key.put(Body=b"some value")
key2 = s3.Object("foobar", "new-key")
key2 = s3_resource.Object("foobar", "new-key")
key2.copy_from(CopySource=f"foobar/{key_name}")
resp = client.get_object(Bucket="foobar", Key=key_name)
resp["Body"].read().should.equal(b"some value")
assert resp["Body"].read() == b"some value"
resp = client.get_object(Bucket="foobar", Key="new-key")
resp["Body"].read().should.equal(b"some value")
assert resp["Body"].read() == b"some value"
@mock_s3
def test_copy_key_boto3_with_sha256_checksum():
# Setup
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
key_name = "key"
new_key = "new_key"
bucket = "foobar"
expected_hash = "qz0H8xacy9DtbEtF3iFRn5+TjHLSQSSZiquUnOg7tRs="
s3.create_bucket(Bucket=bucket)
key = s3.Object("foobar", key_name)
s3_resource.create_bucket(Bucket=bucket)
key = s3_resource.Object("foobar", key_name)
key.put(Body=b"some value")
# Execute
key2 = s3.Object(bucket, new_key)
key2 = s3_resource.Object(bucket, new_key)
key2.copy(
CopySource={"Bucket": bucket, "Key": key_name},
ExtraArgs={"ChecksumAlgorithm": "SHA256"},
@ -83,14 +80,14 @@ def test_copy_key_boto3_with_sha256_checksum():
@mock_s3
def test_copy_key_with_version_boto3():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
client.put_bucket_versioning(
Bucket="foobar", VersioningConfiguration={"Status": "Enabled"}
)
key = s3.Object("foobar", "the-key")
key = s3_resource.Object("foobar", "the-key")
key.put(Body=b"some value")
key.put(Body=b"another value")
@ -99,26 +96,26 @@ def test_copy_key_with_version_boto3():
]
old_version = [v for v in all_versions if not v["IsLatest"]][0]
key2 = s3.Object("foobar", "new-key")
key2 = s3_resource.Object("foobar", "new-key")
key2.copy_from(CopySource=f"foobar/the-key?versionId={old_version['VersionId']}")
resp = client.get_object(Bucket="foobar", Key="the-key")
resp["Body"].read().should.equal(b"another value")
assert resp["Body"].read() == b"another value"
resp = client.get_object(Bucket="foobar", Key="new-key")
resp["Body"].read().should.equal(b"some value")
assert resp["Body"].read() == b"some value"
@mock_s3
def test_copy_object_with_bucketkeyenabled_returns_the_value():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "test-copy-object-with-bucketkeyenabled"
s3.create_bucket(Bucket=bucket_name)
s3_resource.create_bucket(Bucket=bucket_name)
key = s3.Object(bucket_name, "the-key")
key = s3_resource.Object(bucket_name, "the-key")
key.put(Body=b"some value")
key2 = s3.Object(bucket_name, "new-key")
key2 = s3_resource.Object(bucket_name, "new-key")
key2.copy_from(
CopySource=f"{bucket_name}/the-key",
BucketKeyEnabled=True,
@ -127,29 +124,30 @@ def test_copy_object_with_bucketkeyenabled_returns_the_value():
resp = client.get_object(Bucket=bucket_name, Key="the-key")
src_headers = resp["ResponseMetadata"]["HTTPHeaders"]
src_headers.shouldnt.have.key("x-amz-server-side-encryption")
src_headers.shouldnt.have.key("x-amz-server-side-encryption-aws-kms-key-id")
src_headers.shouldnt.have.key("x-amz-server-side-encryption-bucket-key-enabled")
assert "x-amz-server-side-encryption" not in src_headers
assert "x-amz-server-side-encryption-aws-kms-key-id" not in src_headers
assert "x-amz-server-side-encryption-bucket-key-enabled" not in src_headers
resp = client.get_object(Bucket=bucket_name, Key="new-key")
target_headers = resp["ResponseMetadata"]["HTTPHeaders"]
target_headers.should.have.key("x-amz-server-side-encryption")
assert "x-amz-server-side-encryption" in target_headers
# AWS will also return the KMS default key id - not yet implemented
# target_headers.should.have.key("x-amz-server-side-encryption-aws-kms-key-id")
# assert "x-amz-server-side-encryption-aws-kms-key-id" in target_headers
# This field is only returned if encryption is set to 'aws:kms'
target_headers.should.have.key("x-amz-server-side-encryption-bucket-key-enabled")
str(
target_headers["x-amz-server-side-encryption-bucket-key-enabled"]
).lower().should.equal("true")
assert "x-amz-server-side-encryption-bucket-key-enabled" in target_headers
assert (
str(target_headers["x-amz-server-side-encryption-bucket-key-enabled"]).lower()
== "true"
)
@mock_s3
def test_copy_key_with_metadata():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
key = s3.Object("foobar", "the-key")
key = s3_resource.Object("foobar", "the-key")
metadata = {"md": "Metadatastring"}
content_type = "application/json"
initial = key.put(Body=b"{}", Metadata=metadata, ContentType=content_type)
@ -157,18 +155,18 @@ def test_copy_key_with_metadata():
client.copy_object(Bucket="foobar", CopySource="foobar/the-key", Key="new-key")
resp = client.get_object(Bucket="foobar", Key="new-key")
resp["Metadata"].should.equal(metadata)
resp["ContentType"].should.equal(content_type)
resp["ETag"].should.equal(initial["ETag"])
assert resp["Metadata"] == metadata
assert resp["ContentType"] == content_type
assert resp["ETag"] == initial["ETag"]
@mock_s3
def test_copy_key_replace_metadata():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
key = s3.Object("foobar", "the-key")
key = s3_resource.Object("foobar", "the-key")
initial = key.put(Body=b"some value", Metadata={"md": "Metadatastring"})
client.copy_object(
@ -180,29 +178,31 @@ def test_copy_key_replace_metadata():
)
resp = client.get_object(Bucket="foobar", Key="new-key")
resp["Metadata"].should.equal({"momd": "Mometadatastring"})
resp["ETag"].should.equal(initial["ETag"])
assert resp["Metadata"] == {"momd": "Mometadatastring"}
assert resp["ETag"] == initial["ETag"]
@mock_s3
def test_copy_key_without_changes_should_error():
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "my_bucket"
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
key_name = "my_key"
key = s3.Object(bucket_name, key_name)
key = s3_resource.Object(bucket_name, key_name)
s3.create_bucket(Bucket=bucket_name)
s3_resource.create_bucket(Bucket=bucket_name)
key.put(Body=b"some value")
with pytest.raises(ClientError) as e:
with pytest.raises(ClientError) as exc:
client.copy_object(
Bucket=bucket_name,
CopySource=f"{bucket_name}/{key_name}",
Key=key_name,
)
e.value.response["Error"]["Message"].should.equal(
"This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes."
assert exc.value.response["Error"]["Message"] == (
"This copy request is illegal because it is trying to copy an "
"object to itself without changing the object's metadata, storage "
"class, website redirect location or encryption attributes."
)
@ -210,11 +210,11 @@ def test_copy_key_without_changes_should_error():
def test_copy_key_without_changes_should_not_error():
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "my_bucket"
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
key_name = "my_key"
key = s3.Object(bucket_name, key_name)
key = s3_resource.Object(bucket_name, key_name)
s3.create_bucket(Bucket=bucket_name)
s3_resource.create_bucket(Bucket=bucket_name)
key.put(Body=b"some value")
client.copy_object(
@ -232,9 +232,9 @@ def test_copy_key_without_changes_should_not_error():
@mock_s3
def test_copy_key_reduced_redundancy():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3.Bucket("test_bucket")
bucket = s3_resource.Bucket("test_bucket")
bucket.create()
bucket.put_object(Key="the-key", Body=b"somedata")
@ -246,18 +246,18 @@ def test_copy_key_reduced_redundancy():
StorageClass="REDUCED_REDUNDANCY",
)
keys = dict([(k.key, k) for k in bucket.objects.all()])
keys["new-key"].storage_class.should.equal("REDUCED_REDUNDANCY")
keys["the-key"].storage_class.should.equal("STANDARD")
keys = {k.key: k for k in bucket.objects.all()}
assert keys["new-key"].storage_class == "REDUCED_REDUNDANCY"
assert keys["the-key"].storage_class == "STANDARD"
@mock_s3
def test_copy_non_existing_file():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
src = "srcbucket"
target = "target"
s3.create_bucket(Bucket=src)
s3.create_bucket(Bucket=target)
s3_resource.create_bucket(Bucket=src)
s3_resource.create_bucket(Bucket=target)
s3_client = boto3.client("s3")
with pytest.raises(ClientError) as exc:
@ -265,9 +265,9 @@ def test_copy_non_existing_file():
Bucket=target, CopySource={"Bucket": src, "Key": "foofoofoo"}, Key="newkey"
)
err = exc.value.response["Error"]
err["Code"].should.equal("NoSuchKey")
err["Message"].should.equal("The specified key does not exist.")
err["Key"].should.equal("foofoofoo")
assert err["Code"] == "NoSuchKey"
assert err["Message"] == "The specified key does not exist."
assert err["Key"] == "foofoofoo"
@mock_s3
@ -284,7 +284,7 @@ def test_copy_object_with_versioning():
client.put_object(Bucket="blah", Key="test1", Body=b"test1")
client.put_object(Bucket="blah", Key="test2", Body=b"test2")
client.get_object(Bucket="blah", Key="test1")["VersionId"]
_ = client.get_object(Bucket="blah", Key="test1")["VersionId"]
obj2_version = client.get_object(Bucket="blah", Key="test2")["VersionId"]
client.copy_object(
@ -293,7 +293,7 @@ def test_copy_object_with_versioning():
obj2_version_new = client.get_object(Bucket="blah", Key="test2")["VersionId"]
# Version should be different to previous version
obj2_version_new.should_not.equal(obj2_version)
assert obj2_version_new != obj2_version
client.copy_object(
CopySource={"Bucket": "blah", "Key": "test2", "VersionId": obj2_version},
@ -301,16 +301,16 @@ def test_copy_object_with_versioning():
Key="test3",
)
obj3_version_new = client.get_object(Bucket="blah", Key="test3")["VersionId"]
obj3_version_new.should_not.equal(obj2_version_new)
assert obj3_version_new != obj2_version_new
# Copy file that doesn't exist
with pytest.raises(ClientError) as e:
with pytest.raises(ClientError) as exc:
client.copy_object(
CopySource={"Bucket": "blah", "Key": "test4", "VersionId": obj2_version},
Bucket="blah",
Key="test5",
)
e.value.response["Error"]["Code"].should.equal("NoSuchKey")
assert exc.value.response["Error"]["Code"] == "NoSuchKey"
response = client.create_multipart_upload(Bucket="blah", Key="test4")
upload_id = response["UploadId"]
@ -331,7 +331,7 @@ def test_copy_object_with_versioning():
response = client.get_object(Bucket="blah", Key="test4")
data = response["Body"].read()
data.should.equal(b"test2")
assert data == b"test2"
@mock_s3
@ -355,7 +355,7 @@ def test_copy_object_from_unversioned_to_versioned_bucket():
).get("VersionId")
# VersionId should be present in the response
obj2_version_new.should_not.equal(None)
assert obj2_version_new is not None
@mock_s3
@ -376,8 +376,8 @@ def test_copy_object_with_replacement_tagging():
Tagging="aws:tag=invalid_key",
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidTag")
exc = err.value
assert exc.response["Error"]["Code"] == "InvalidTag"
client.copy_object(
CopySource={"Bucket": "mybucket", "Key": "original"},
@ -394,9 +394,9 @@ def test_copy_object_with_replacement_tagging():
)
tags1 = client.get_object_tagging(Bucket="mybucket", Key="copy1")["TagSet"]
tags1.should.equal([{"Key": "tag", "Value": "new"}])
assert tags1 == [{"Key": "tag", "Value": "new"}]
tags2 = client.get_object_tagging(Bucket="mybucket", Key="copy2")["TagSet"]
tags2.should.equal([{"Key": "tag", "Value": "old"}])
assert tags2 == [{"Key": "tag", "Value": "old"}]
@mock_s3
@ -428,10 +428,10 @@ def test_copy_object_with_kms_encryption():
@mock_kms
def test_copy_object_in_place_with_encryption():
kms_client = boto3.client("kms", region_name=DEFAULT_REGION_NAME)
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
kms_key = kms_client.create_key()["KeyMetadata"]["KeyId"]
bucket = s3.Bucket("test_bucket")
bucket = s3_resource.Bucket("test_bucket")
bucket.create()
key = "source-key"
resp = client.put_object(
@ -464,8 +464,9 @@ def test_copy_object_in_place_with_encryption():
)
assert "BucketKeyEnabled" not in resp
# this is an edge case, if the source object SSE was not AES256, AWS allows you to not specify any fields
# as it will use AES256 by default and is different from the source key
# This is an edge case, if the source object SSE was not AES256,
# AWS allows you to not specify any fields as it will use AES256 by
# default and is different from the source key.
resp = client.copy_object(
Bucket="test_bucket",
CopySource=f"test_bucket/{key}",
@ -473,7 +474,8 @@ def test_copy_object_in_place_with_encryption():
)
assert resp["ServerSideEncryption"] == "AES256"
# check that it allows copying in the place with the same ServerSideEncryption setting as the source
# Check that it allows copying in the place with the same
# ServerSideEncryption setting as the source.
resp = client.copy_object(
Bucket="test_bucket",
CopySource=f"test_bucket/{key}",
@ -485,11 +487,14 @@ def test_copy_object_in_place_with_encryption():
@mock_s3
def test_copy_object_in_place_with_storage_class():
# this test will validate that setting StorageClass (even the same as source) allows a copy in place
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
"""Validate setting StorageClass allows a copy in place.
This should be true even if destination object is the same as source.
"""
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "test-bucket"
bucket = s3.Bucket(bucket_name)
bucket = s3_resource.Bucket(bucket_name)
bucket.create()
key = "source-key"
bucket.put_object(Key=key, Body=b"somedata", StorageClass="STANDARD")
@ -508,9 +513,9 @@ def test_copy_object_in_place_with_storage_class():
@mock_s3
def test_copy_object_does_not_copy_storage_class():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3.Bucket("test_bucket")
bucket = s3_resource.Bucket("test_bucket")
bucket.create()
source_key = "source-key"
dest_key = "dest-key"
@ -522,17 +527,17 @@ def test_copy_object_does_not_copy_storage_class():
)
# Verify that the destination key does not have STANDARD_IA as StorageClass
keys = dict([(k.key, k) for k in bucket.objects.all()])
keys[source_key].storage_class.should.equal("STANDARD_IA")
keys[dest_key].storage_class.should.equal("STANDARD")
keys = {k.key: k for k in bucket.objects.all()}
assert keys[source_key].storage_class == "STANDARD_IA"
assert keys[dest_key].storage_class == "STANDARD"
@mock_s3
def test_copy_object_does_not_copy_acl():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "testbucket"
bucket = s3.Bucket(bucket_name)
bucket = s3_resource.Bucket(bucket_name)
bucket.create()
source_key = "source-key"
dest_key = "dest-key"
@ -560,24 +565,27 @@ def test_copy_object_does_not_copy_acl():
@mock_s3
def test_copy_object_in_place_with_metadata():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "testbucket"
bucket = s3.Bucket(bucket_name)
bucket = s3_resource.Bucket(bucket_name)
bucket.create()
key_name = "source-key"
bucket.put_object(Key=key_name, Body=b"somedata")
# test that giving metadata is not enough, and should provide MetadataDirective=REPLACE on top
with pytest.raises(ClientError) as e:
# test that giving metadata is not enough and should provide
# MetadataDirective=REPLACE on top.
with pytest.raises(ClientError) as exc:
client.copy_object(
Bucket=bucket_name,
CopySource=f"{bucket_name}/{key_name}",
Key=key_name,
Metadata={"key": "value"},
)
e.value.response["Error"]["Message"].should.equal(
"This copy request is illegal because it is trying to copy an object to itself without changing the object's metadata, storage class, website redirect location or encryption attributes."
assert exc.value.response["Error"]["Message"] == (
"This copy request is illegal because it is trying to copy an "
"object to itself without changing the object's metadata, "
"storage class, website redirect location or encryption attributes."
)
# you can only provide MetadataDirective=REPLACE and it will copy without any metadata
@ -672,7 +680,8 @@ def test_copy_object_in_place_website_redirect_location():
bucket_name = "testbucket"
key = "source-key"
client.create_bucket(Bucket=bucket_name)
# this test will validate that setting WebsiteRedirectLocation (even the same as source) allows a copy in place
# This test will validate that setting WebsiteRedirectLocation
# (even the same as source) allows a copy in place.
client.put_object(
Bucket=bucket_name,
@ -738,11 +747,18 @@ def test_copy_object_in_place_with_bucket_encryption():
["CRC32", "SHA1", "SHA256"],
)
def test_copy_key_boto3_with_both_sha256_checksum(algorithm):
# This test will validate that moto S3 checksum calculations are correct
# We first create an object with a Checksum calculated by boto, by specifying ChecksumAlgorithm="SHA256"
# we then retrieve the right checksum from this request
# we copy the object while requesting moto to recalculate the checksum for that key
# we verify that both checksums are equal
"""Validate that moto S3 checksum calculations are correct.
We first create an object with a Checksum calculated by boto, by
specifying ChecksumAlgorithm="SHA256".
We then retrieve the right checksum from this request.
We copy the object while requesting moto to recalculate the checksum
for that key.
We verify that both checksums are equal.
"""
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
source_key = "source-key"
dest_key = "dest-key"

View File

@ -1,11 +1,11 @@
import boto3
import sure # noqa # pylint: disable=unused-import
import os
from unittest import SkipTest
from unittest.mock import patch
import boto3
import pytest
from moto import mock_s3, settings
from unittest import SkipTest
from unittest.mock import patch
DEFAULT_REGION_NAME = "us-east-1"
@ -25,9 +25,9 @@ def test_create_and_list_buckets(url):
conn = boto3.resource("s3", endpoint_url=url)
conn.create_bucket(Bucket=bucket)
s3 = boto3.client("s3", endpoint_url=url)
all_buckets = s3.list_buckets()["Buckets"]
[b["Name"] for b in all_buckets].should.contain(bucket)
s3_client = boto3.client("s3", endpoint_url=url)
all_buckets = s3_client.list_buckets()["Buckets"]
assert bucket in [b["Name"] for b in all_buckets]
@pytest.mark.parametrize("url", [CUSTOM_ENDPOINT, CUSTOM_ENDPOINT_2])
@ -45,9 +45,9 @@ def test_create_and_list_buckets_with_multiple_supported_endpoints(url):
conn = boto3.resource("s3", endpoint_url=url)
conn.create_bucket(Bucket=bucket)
s3 = boto3.client("s3", endpoint_url=url)
all_buckets = s3.list_buckets()["Buckets"]
[b["Name"] for b in all_buckets].should.contain(bucket)
s3_client = boto3.client("s3", endpoint_url=url)
all_buckets = s3_client.list_buckets()["Buckets"]
assert bucket in [b["Name"] for b in all_buckets]
@pytest.mark.parametrize("url", [CUSTOM_ENDPOINT, CUSTOM_ENDPOINT_2])
@ -63,12 +63,12 @@ def test_put_and_get_object(url):
conn = boto3.resource("s3", endpoint_url=url)
conn.create_bucket(Bucket=bucket)
s3 = boto3.client("s3", endpoint_url=url)
s3.put_object(Bucket=bucket, Key=key, Body=contents)
s3_client = boto3.client("s3", endpoint_url=url)
s3_client.put_object(Bucket=bucket, Key=key, Body=contents)
body = conn.Object(bucket, key).get()["Body"].read().decode()
body.should.equal(contents)
assert body == contents
@pytest.mark.parametrize("url", [CUSTOM_ENDPOINT, CUSTOM_ENDPOINT_2])
@ -80,12 +80,12 @@ def test_put_and_list_objects(url):
with mock_s3():
bucket = "mybucket"
s3 = boto3.client("s3", endpoint_url=url)
s3.create_bucket(Bucket=bucket)
s3.put_object(Bucket=bucket, Key="one", Body=b"1")
s3.put_object(Bucket=bucket, Key="two", Body=b"22")
s3.put_object(Bucket=bucket, Key="three", Body=b"333")
s3_client = boto3.client("s3", endpoint_url=url)
s3_client.create_bucket(Bucket=bucket)
s3_client.put_object(Bucket=bucket, Key="one", Body=b"1")
s3_client.put_object(Bucket=bucket, Key="two", Body=b"22")
s3_client.put_object(Bucket=bucket, Key="three", Body=b"333")
contents = s3.list_objects(Bucket=bucket)["Contents"]
contents.should.have.length_of(3)
[c["Key"] for c in contents].should.contain("two")
contents = s3_client.list_objects(Bucket=bucket)["Contents"]
assert len(contents) == 3
assert "two" in [c["Key"] for c in contents]

View File

@ -1,9 +1,10 @@
from uuid import uuid4
import boto3
from botocore.exceptions import ClientError
import pytest
from botocore.exceptions import ClientError
from moto import mock_s3
from uuid import uuid4
@mock_s3
@ -14,11 +15,9 @@ def test_encryption_on_new_bucket_fails():
with pytest.raises(ClientError) as exc:
conn.get_bucket_encryption(Bucket="mybucket")
err = exc.value.response["Error"]
err["Code"].should.equal("ServerSideEncryptionConfigurationNotFoundError")
err["Message"].should.equal(
"The server side encryption configuration was not found"
)
err["BucketName"].should.equal("mybucket")
assert err["Code"] == "ServerSideEncryptionConfigurationNotFoundError"
assert err["Message"] == "The server side encryption configuration was not found"
assert err["BucketName"] == "mybucket"
@mock_s3
@ -46,7 +45,7 @@ def test_put_and_get_encryption():
assert "ServerSideEncryptionConfiguration" in resp
return_config = sse_config.copy()
return_config["Rules"][0]["BucketKeyEnabled"] = False
assert resp["ServerSideEncryptionConfiguration"].should.equal(return_config)
assert resp["ServerSideEncryptionConfiguration"] == return_config
@mock_s3
@ -75,65 +74,65 @@ def test_delete_and_get_encryption():
with pytest.raises(ClientError) as exc:
conn.get_bucket_encryption(Bucket="mybucket")
err = exc.value.response["Error"]
err["Code"].should.equal("ServerSideEncryptionConfigurationNotFoundError")
assert err["Code"] == "ServerSideEncryptionConfigurationNotFoundError"
@mock_s3
def test_encryption_status_on_new_objects():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket=bucket_name)
s3.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket=bucket_name)
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
# verify encryption status on object itself
res = s3.get_object(Bucket=bucket_name, Key="file.txt")
res.shouldnt.have.key("ServerSideEncryption")
res = s3_client.get_object(Bucket=bucket_name, Key="file.txt")
assert "ServerSideEncryption" not in res
# enable encryption
sse_config = {
"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]
}
s3.put_bucket_encryption(
s3_client.put_bucket_encryption(
Bucket=bucket_name, ServerSideEncryptionConfiguration=sse_config
)
# verify encryption status on existing object hasn't changed
res = s3.get_object(Bucket=bucket_name, Key="file.txt")
res.shouldnt.have.key("ServerSideEncryption")
res = s3_client.get_object(Bucket=bucket_name, Key="file.txt")
assert "ServerSideEncryption" not in res
# create object2
s3.put_object(Bucket=bucket_name, Body=b"test", Key="file2.txt")
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key="file2.txt")
# verify encryption status on object2
res = s3.get_object(Bucket=bucket_name, Key="file2.txt")
res.should.have.key("ServerSideEncryption").equals("AES256")
res = s3_client.get_object(Bucket=bucket_name, Key="file2.txt")
assert res["ServerSideEncryption"] == "AES256"
@mock_s3
def test_encryption_status_on_copied_objects():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket=bucket_name)
s3.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket=bucket_name)
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
# enable encryption
sse_config = {
"Rules": [{"ApplyServerSideEncryptionByDefault": {"SSEAlgorithm": "AES256"}}]
}
s3.put_bucket_encryption(
s3_client.put_bucket_encryption(
Bucket=bucket_name, ServerSideEncryptionConfiguration=sse_config
)
# copy object
s3.copy_object(
s3_client.copy_object(
CopySource=f"{bucket_name}/file.txt", Bucket=bucket_name, Key="file2.txt"
)
# verify encryption status on object1 hasn't changed
res = s3.get_object(Bucket=bucket_name, Key="file.txt")
res.shouldnt.have.key("ServerSideEncryption")
res = s3_client.get_object(Bucket=bucket_name, Key="file.txt")
assert "ServerSideEncryption" not in res
# verify encryption status on object2 does have encryption
res = s3.get_object(Bucket=bucket_name, Key="file2.txt")
res.should.have.key("ServerSideEncryption").equals("AES256")
res = s3_client.get_object(Bucket=bucket_name, Key="file2.txt")
assert res["ServerSideEncryption"] == "AES256"
@mock_s3
def test_encryption_bucket_key_for_aes_not_returned():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket=bucket_name)
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket=bucket_name)
# enable encryption
sse_config = {
"Rules": [
@ -143,8 +142,8 @@ def test_encryption_bucket_key_for_aes_not_returned():
}
]
}
s3.put_bucket_encryption(
s3_client.put_bucket_encryption(
Bucket=bucket_name, ServerSideEncryptionConfiguration=sse_config
)
res = s3.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
res.shouldnt.have.key("BucketKeyEnabled")
res = s3_client.put_object(Bucket=bucket_name, Body=b"test", Key="file.txt")
assert "BucketKeyEnabled" not in res

View File

@ -1,13 +1,15 @@
import boto3
import copy
import gc
import warnings
from functools import wraps
from unittest import SkipTest, TestCase
import boto3
from moto import settings, mock_s3
from moto.dynamodb.models import DynamoDBBackend
from moto.s3 import models as s3model, s3_backends
from moto.s3.responses import S3ResponseInstance
from unittest import SkipTest, TestCase
from tests import DEFAULT_ACCOUNT_ID
@ -17,49 +19,51 @@ TEST_BUCKET_VERSIONED = "versioned-bucket"
TEST_KEY = "my-key"
def verify_zero_warnings(f):
@wraps(f)
def verify_zero_warnings(func):
@wraps(func)
def wrapped(*args, **kwargs):
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter("always", ResourceWarning) # add filter
resp = f(*args, **kwargs)
# Get the TestClass reference, and reset any S3Backends that we've created as part of that class
resp = func(*args, **kwargs)
# Get the TestClass reference, and reset any S3Backends that
# we've created as part of that class.
(class_ref,) = args
for obj in class_ref.__dict__:
if isinstance(obj, s3model.S3Backend):
obj.reset()
# Now collect garbage, which will throw any warnings if there are unclosed FileHandles
# Now collect garbage, which will throw any warnings if there
# are unclosed FileHandles.
gc.collect()
warning_types = [type(warn.message) for warn in warning_list]
warning_types.shouldnt.contain(ResourceWarning)
assert ResourceWarning not in warning_types
return resp
return wrapped
class TestS3FileHandleClosures(TestCase):
"""
Large Uploads are written to disk for performance reasons
These tests verifies that the filehandles are properly closed after specific actions
"""Verifies filehandles are properly closed after specific actions.
Large Uploads are written to disk for performance reasons.
"""
def setUp(self) -> None:
if settings.TEST_SERVER_MODE:
raise SkipTest("No point in testing ServerMode, we're not using boto3")
self.s3 = s3_backends[DEFAULT_ACCOUNT_ID]["global"]
self.s3.create_bucket(TEST_BUCKET, "us-west-1")
self.s3.create_bucket(TEST_BUCKET_VERSIONED, "us-west-1")
self.s3.put_object(TEST_BUCKET, TEST_KEY, "x" * 10_000_000)
self.s3_client = s3_backends[DEFAULT_ACCOUNT_ID]["global"]
self.s3_client.create_bucket(TEST_BUCKET, "us-west-1")
self.s3_client.create_bucket(TEST_BUCKET_VERSIONED, "us-west-1")
self.s3_client.put_object(TEST_BUCKET, TEST_KEY, "x" * 10_000_000)
def tearDown(self) -> None:
for bucket_name in (
TEST_BUCKET,
TEST_BUCKET_VERSIONED,
):
keys = list(self.s3.get_bucket(bucket_name).keys.keys())
keys = list(self.s3_client.get_bucket(bucket_name).keys.keys())
for key in keys:
self.s3.delete_object(bucket_name, key)
self.s3.delete_bucket(bucket_name)
self.s3_client.delete_object(bucket_name, key)
self.s3_client.delete_bucket(bucket_name)
@verify_zero_warnings
def test_upload_large_file(self):
@ -69,27 +73,27 @@ class TestS3FileHandleClosures(TestCase):
@verify_zero_warnings
def test_delete_large_file(self):
self.s3.delete_object(bucket_name=TEST_BUCKET, key_name=TEST_KEY)
self.s3_client.delete_object(bucket_name=TEST_BUCKET, key_name=TEST_KEY)
@verify_zero_warnings
def test_overwriting_file(self):
self.s3.put_object(TEST_BUCKET, TEST_KEY, "b" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET, TEST_KEY, "b" * 10_000_000)
@verify_zero_warnings
def test_versioned_file(self):
self.s3.put_bucket_versioning(TEST_BUCKET, "Enabled")
self.s3.put_object(TEST_BUCKET, TEST_KEY, "b" * 10_000_000)
self.s3_client.put_bucket_versioning(TEST_BUCKET, "Enabled")
self.s3_client.put_object(TEST_BUCKET, TEST_KEY, "b" * 10_000_000)
@verify_zero_warnings
def test_copy_object(self):
key = self.s3.get_object(TEST_BUCKET, TEST_KEY)
self.s3.copy_object(
key = self.s3_client.get_object(TEST_BUCKET, TEST_KEY)
self.s3_client.copy_object(
src_key=key, dest_bucket_name=TEST_BUCKET, dest_key_name="key-2"
)
@verify_zero_warnings
def test_part_upload(self):
multipart_id = self.s3.create_multipart_upload(
multipart_id = self.s3_client.create_multipart_upload(
bucket_name=TEST_BUCKET,
key_name="mp-key",
metadata={},
@ -99,7 +103,7 @@ class TestS3FileHandleClosures(TestCase):
sse_encryption=None,
kms_key_id=None,
)
self.s3.upload_part(
self.s3_client.upload_part(
bucket_name=TEST_BUCKET,
multipart_id=multipart_id,
part_id=1,
@ -108,7 +112,7 @@ class TestS3FileHandleClosures(TestCase):
@verify_zero_warnings
def test_overwriting_part_upload(self):
multipart_id = self.s3.create_multipart_upload(
multipart_id = self.s3_client.create_multipart_upload(
bucket_name=TEST_BUCKET,
key_name="mp-key",
metadata={},
@ -118,13 +122,13 @@ class TestS3FileHandleClosures(TestCase):
sse_encryption=None,
kms_key_id=None,
)
self.s3.upload_part(
self.s3_client.upload_part(
bucket_name=TEST_BUCKET,
multipart_id=multipart_id,
part_id=1,
value="b" * 10_000_000,
)
self.s3.upload_part(
self.s3_client.upload_part(
bucket_name=TEST_BUCKET,
multipart_id=multipart_id,
part_id=1,
@ -133,7 +137,7 @@ class TestS3FileHandleClosures(TestCase):
@verify_zero_warnings
def test_aborting_part_upload(self):
multipart_id = self.s3.create_multipart_upload(
multipart_id = self.s3_client.create_multipart_upload(
bucket_name=TEST_BUCKET,
key_name="mp-key",
metadata={},
@ -143,19 +147,19 @@ class TestS3FileHandleClosures(TestCase):
sse_encryption=None,
kms_key_id=None,
)
self.s3.upload_part(
self.s3_client.upload_part(
bucket_name=TEST_BUCKET,
multipart_id=multipart_id,
part_id=1,
value="b" * 10_000_000,
)
self.s3.abort_multipart_upload(
self.s3_client.abort_multipart_upload(
bucket_name=TEST_BUCKET, multipart_id=multipart_id
)
@verify_zero_warnings
def test_completing_part_upload(self):
multipart_id = self.s3.create_multipart_upload(
multipart_id = self.s3_client.create_multipart_upload(
bucket_name=TEST_BUCKET,
key_name="mp-key",
metadata={},
@ -165,78 +169,87 @@ class TestS3FileHandleClosures(TestCase):
sse_encryption=None,
kms_key_id=None,
)
etag = self.s3.upload_part(
etag = self.s3_client.upload_part(
bucket_name=TEST_BUCKET,
multipart_id=multipart_id,
part_id=1,
value="b" * 10_000_000,
).etag
mp_body = f"""<CompleteMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Part><ETag>{etag}</ETag><PartNumber>1</PartNumber></Part></CompleteMultipartUpload>"""
mp_body = (
"<CompleteMultipartUpload "
'xmlns="http://s3.amazonaws.com/doc/2006-03-01/">'
f"<Part><ETag>{etag}</ETag><PartNumber>1</PartNumber></Part>"
"</CompleteMultipartUpload>"
)
body = S3ResponseInstance._complete_multipart_body(mp_body)
self.s3.complete_multipart_upload(
self.s3_client.complete_multipart_upload(
bucket_name=TEST_BUCKET, multipart_id=multipart_id, body=body
)
@verify_zero_warnings
def test_single_versioned_upload(self):
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
@verify_zero_warnings
def test_overwrite_versioned_upload(self):
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
@verify_zero_warnings
def test_multiple_versions_upload(self):
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "y" * 10_000_000)
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "z" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "y" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "z" * 10_000_000)
@verify_zero_warnings
def test_delete_versioned_upload(self):
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3.delete_object(bucket_name=TEST_BUCKET, key_name=TEST_KEY)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
self.s3_client.delete_object(bucket_name=TEST_BUCKET, key_name=TEST_KEY)
@verify_zero_warnings
def test_delete_specific_version(self):
self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
key = self.s3.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "y" * 10_000_000)
self.s3.delete_object(
self.s3_client.put_object(TEST_BUCKET_VERSIONED, TEST_KEY, "x" * 10_000_000)
key = self.s3_client.put_object(
TEST_BUCKET_VERSIONED, TEST_KEY, "y" * 10_000_000
)
self.s3_client.delete_object(
bucket_name=TEST_BUCKET, key_name=TEST_KEY, version_id=key._version_id
)
@verify_zero_warnings
def test_reset_other_backend(self):
db = DynamoDBBackend("us-west-1", "1234")
# This used to empty the entire list of `model_instances`, which can contain FakeKey-references
# Verify that we can reset an unrelated backend, without throwing away FakeKey-references that still need to be disposed
db.reset()
dbase = DynamoDBBackend("us-west-1", "1234")
# This used to empty the entire list of `model_instances`, which
# can contain FakeKey-references.
# Verify that we can reset an unrelated backend, without throwing
# away FakeKey-references that still need to be disposed.
dbase.reset()
class TestS3FileHandleClosuresUsingMocks(TestCase):
def setUp(self) -> None:
self.s3 = boto3.client("s3", "us-east-1")
self.s3_client = boto3.client("s3", "us-east-1")
@verify_zero_warnings
@mock_s3
def test_use_decorator(self):
self.s3.create_bucket(Bucket="foo")
self.s3.put_object(Bucket="foo", Key="bar", Body="stuff")
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_object(Bucket="foo", Key="bar", Body="stuff")
@verify_zero_warnings
@mock_s3
def test_use_decorator_and_context_mngt(self):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_object(Bucket="foo", Key="bar", Body="stuff")
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_object(Bucket="foo", Key="bar", Body="stuff")
@verify_zero_warnings
def test_use_multiple_context_managers(self):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_object(Bucket="foo", Key="bar", Body="stuff")
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_object(Bucket="foo", Key="bar", Body="stuff")
with mock_s3():
pass
@ -244,16 +257,16 @@ class TestS3FileHandleClosuresUsingMocks(TestCase):
@verify_zero_warnings
def test_create_multipart(self):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_object(Bucket="foo", Key="k1", Body="stuff")
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_object(Bucket="foo", Key="k1", Body="stuff")
mp = self.s3.create_multipart_upload(Bucket="foo", Key="key2")
self.s3.upload_part(
mpart = self.s3_client.create_multipart_upload(Bucket="foo", Key="key2")
self.s3_client.upload_part(
Body=b"hello",
PartNumber=1,
Bucket="foo",
Key="key2",
UploadId=mp["UploadId"],
UploadId=mpart["UploadId"],
)
with mock_s3():
@ -262,9 +275,9 @@ class TestS3FileHandleClosuresUsingMocks(TestCase):
@verify_zero_warnings
def test_overwrite_file(self):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_object(Bucket="foo", Key="k1", Body="stuff")
self.s3.put_object(Bucket="foo", Key="k1", Body="b" * 10_000_000)
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_object(Bucket="foo", Key="k1", Body="stuff")
self.s3_client.put_object(Bucket="foo", Key="k1", Body="b" * 10_000_000)
with mock_s3():
pass
@ -272,28 +285,30 @@ class TestS3FileHandleClosuresUsingMocks(TestCase):
@verify_zero_warnings
def test_delete_object_with_version(self):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_bucket_versioning(
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_bucket_versioning(
Bucket="foo",
VersioningConfiguration={"Status": "Enabled", "MFADelete": "Disabled"},
)
version = self.s3.put_object(Bucket="foo", Key="b", Body="s")["VersionId"]
self.s3.delete_object(Bucket="foo", Key="b", VersionId=version)
version = self.s3_client.put_object(Bucket="foo", Key="b", Body="s")[
"VersionId"
]
self.s3_client.delete_object(Bucket="foo", Key="b", VersionId=version)
@verify_zero_warnings
def test_update_versioned_object__while_looping(self):
for _ in (1, 2):
with mock_s3():
self.s3.create_bucket(Bucket="foo")
self.s3.put_bucket_versioning(
self.s3_client.create_bucket(Bucket="foo")
self.s3_client.put_bucket_versioning(
Bucket="foo",
VersioningConfiguration={
"Status": "Enabled",
"MFADelete": "Disabled",
},
)
self.s3.put_object(Bucket="foo", Key="bar", Body="stuff")
self.s3.put_object(Bucket="foo", Key="bar", Body="stuff2")
self.s3_client.put_object(Bucket="foo", Key="bar", Body="stuff")
self.s3_client.put_object(Bucket="foo", Key="bar", Body="stuff2")
def test_verify_key_can_be_copied_after_disposing():
@ -302,13 +317,15 @@ def test_verify_key_can_be_copied_after_disposing():
# - User: calls list_object_versions
# - Moto creates a list of all keys
# - User: deletes a key
# - Moto iterates over the previously created list, that contains a now-deleted key, and creates a copy of it
# - Moto iterates over the previously created list, that contains i
# a now-deleted key, and creates a copy of it
#
# This test verifies the copy-operation succeeds, it will just not have any data
# This test verifies the copy-operation succeeds, it will just not
# have any data.
key = s3model.FakeKey(name="test", bucket_name="bucket", value="sth")
assert not key._value_buffer.closed
key.dispose()
assert key._value_buffer.closed
copied_key = copy.copy(key)
copied_key.value.should.equal(b"")
assert copied_key.value == b""

View File

@ -1,6 +1,9 @@
import boto3
import json
from uuid import uuid4
import boto3
import pytest
from moto import mock_lambda, mock_logs, mock_s3, mock_sqs
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
from tests.markers import requires_docker
@ -9,7 +12,6 @@ from tests.test_awslambda.utilities import (
get_role_name,
wait_for_log_msg,
)
from uuid import uuid4
REGION_NAME = "us-east-1"
@ -89,24 +91,20 @@ def test_objectcreated_put__invokes_lambda(match_events, actual_event):
records = [line for line in all_logs if line.startswith("{'Records'")][0]
records = json.loads(records.replace("'", '"'))["Records"]
records.should.have.length_of(1)
records[0].should.have.key("awsRegion").equals(REGION_NAME)
records[0].should.have.key("eventName").equals(actual_event)
records[0].should.have.key("eventSource").equals("aws:s3")
records[0].should.have.key("eventTime")
records[0].should.have.key("s3")
records[0]["s3"].should.have.key("bucket")
records[0]["s3"]["bucket"].should.have.key("arn").equals(
f"arn:aws:s3:::{bucket_name}"
)
records[0]["s3"]["bucket"].should.have.key("name").equals(bucket_name)
records[0]["s3"].should.have.key("configurationId").equals("s3eventtriggerslambda")
records[0]["s3"].should.have.key("object")
records[0]["s3"]["object"].should.have.key("eTag").equals(
"61ea96c3c8d2c76fc5a42bfccb6affd9"
)
records[0]["s3"]["object"].should.have.key("key").equals("keyname")
records[0]["s3"]["object"].should.have.key("size").equals(15)
assert len(records) == 1
assert records[0]["awsRegion"] == REGION_NAME
assert records[0]["eventName"] == actual_event
assert records[0]["eventSource"] == "aws:s3"
assert "eventTime" in records[0]
assert "s3" in records[0]
assert "bucket" in records[0]["s3"]
assert records[0]["s3"]["bucket"]["arn"] == f"arn:aws:s3:::{bucket_name}"
assert records[0]["s3"]["bucket"]["name"] == bucket_name
assert records[0]["s3"]["configurationId"] == "s3eventtriggerslambda"
assert "object" in records[0]["s3"]
assert records[0]["s3"]["object"]["eTag"] == "61ea96c3c8d2c76fc5a42bfccb6affd9"
assert records[0]["s3"]["object"]["key"] == "keyname"
assert records[0]["s3"]["object"]["size"] == 15
@mock_logs
@ -138,8 +136,8 @@ def test_objectcreated_put__unknown_lambda_is_handled_gracefully():
# The object was persisted successfully
resp = s3_client.get_object(Bucket=bucket_name, Key="keyname")
resp.should.have.key("ContentLength").equal(15)
resp["Body"].read().should.equal(b"bodyofnewobject")
assert resp["ContentLength"] == 15
assert resp["Body"].read() == b"bodyofnewobject"
@mock_s3
@ -175,12 +173,12 @@ def test_object_copy__sends_to_queue():
# We should have received a test event now
messages = sqs_client.receive_message(QueueUrl=queue_url)["Messages"]
messages.should.have.length_of(1)
assert len(messages) == 1
message = json.loads(messages[0]["Body"])
message.should.have.key("Service").equals("Amazon S3")
message.should.have.key("Event").equals("s3:TestEvent")
message.should.have.key("Time")
message.should.have.key("Bucket").equals(bucket_name)
assert message["Service"] == "Amazon S3"
assert message["Event"] == "s3:TestEvent"
assert "Time" in message
assert message["Bucket"] == bucket_name
# Copy an Object
s3_client.put_object(Bucket=bucket_name, Key="keyname", Body="bodyofnewobject")
@ -190,27 +188,23 @@ def test_object_copy__sends_to_queue():
# Read SQS messages - we should have the Copy-event here
resp = sqs_client.receive_message(QueueUrl=queue_url)
resp.should.have.key("Messages").length_of(1)
assert len(resp["Messages"]) == 1
records = json.loads(resp["Messages"][0]["Body"])["Records"]
records.should.have.length_of(1)
records[0].should.have.key("awsRegion").equals(REGION_NAME)
records[0].should.have.key("eventName").equals("ObjectCreated:Copy")
records[0].should.have.key("eventSource").equals("aws:s3")
records[0].should.have.key("eventTime")
records[0].should.have.key("s3")
records[0]["s3"].should.have.key("bucket")
records[0]["s3"]["bucket"].should.have.key("arn").equals(
f"arn:aws:s3:::{bucket_name}"
)
records[0]["s3"]["bucket"].should.have.key("name").equals(bucket_name)
records[0]["s3"].should.have.key("configurationId").equals("queue_config")
records[0]["s3"].should.have.key("object")
records[0]["s3"]["object"].should.have.key("eTag").equals(
"61ea96c3c8d2c76fc5a42bfccb6affd9"
)
records[0]["s3"]["object"].should.have.key("key").equals("key2")
records[0]["s3"]["object"].should.have.key("size").equals(15)
assert len(records) == 1
assert records[0]["awsRegion"] == REGION_NAME
assert records[0]["eventName"] == "ObjectCreated:Copy"
assert records[0]["eventSource"] == "aws:s3"
assert "eventTime" in records[0]
assert "s3" in records[0]
assert "bucket" in records[0]["s3"]
assert records[0]["s3"]["bucket"]["arn"] == f"arn:aws:s3:::{bucket_name}"
assert records[0]["s3"]["bucket"]["name"] == bucket_name
assert records[0]["s3"]["configurationId"] == "queue_config"
assert "object" in records[0]["s3"]
assert records[0]["s3"]["object"]["eTag"] == "61ea96c3c8d2c76fc5a42bfccb6affd9"
assert records[0]["s3"]["object"]["key"] == "key2"
assert records[0]["s3"]["object"]["size"] == 15
@mock_s3
@ -260,34 +254,34 @@ def test_object_put__sends_to_queue__using_filter():
# Read the test-event
resp = queue.receive_messages()
[m.delete() for m in resp]
_ = [m.delete() for m in resp]
# Create an Object that does not meet any filter
s3_client.put_object(Bucket=bucket_name, Key="bb", Body="sth")
messages = queue.receive_messages()
messages.should.have.length_of(0)
[m.delete() for m in messages]
assert not messages
_ = [m.delete() for m in messages]
# Create an Object that does meet the filter - using the prefix only
s3_client.put_object(Bucket=bucket_name, Key="aafilter", Body="sth")
messages = queue.receive_messages()
messages.should.have.length_of(1)
[m.delete() for m in messages]
assert len(messages) == 1
_ = [m.delete() for m in messages]
# Create an Object that does meet the filter - using the prefix + suffix
s3_client.put_object(Bucket=bucket_name, Key="image/yes.jpg", Body="img")
messages = queue.receive_messages()
messages.should.have.length_of(1)
[m.delete() for m in messages]
assert len(messages) == 1
_ = [m.delete() for m in messages]
# Create an Object that does not meet the filter - only the prefix
s3_client.put_object(Bucket=bucket_name, Key="image/no.gif", Body="img")
messages = queue.receive_messages()
messages.should.have.length_of(0)
[m.delete() for m in messages]
assert not messages
_ = [m.delete() for m in messages]
# Create an Object that does not meet the filter - only the suffix
s3_client.put_object(Bucket=bucket_name, Key="nonimages/yes.jpg", Body="img")
messages = queue.receive_messages()
messages.should.have.length_of(0)
[m.delete() for m in messages]
assert not messages
_ = [m.delete() for m in messages]

View File

@ -1,8 +1,7 @@
import boto3
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from datetime import datetime
import boto3
from botocore.exceptions import ClientError
import pytest
from moto import mock_s3
@ -489,9 +488,9 @@ def test_lifecycle_with_aimu():
@mock_s3
def test_lifecycle_with_glacier_transition_boto3():
s3 = boto3.resource("s3", region_name="us-east-1")
s3_resource = boto3.resource("s3", region_name="us-east-1")
client = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
client.put_bucket_lifecycle_configuration(
Bucket="foobar",
@ -508,24 +507,24 @@ def test_lifecycle_with_glacier_transition_boto3():
)
response = client.get_bucket_lifecycle_configuration(Bucket="foobar")
response.should.have.key("Rules")
assert "Rules" in response
rules = response["Rules"]
rules.should.have.length_of(1)
rules[0].should.have.key("ID").equal("myid")
assert len(rules) == 1
assert rules[0]["ID"] == "myid"
transition = rules[0]["Transitions"][0]
transition["Days"].should.equal(30)
transition["StorageClass"].should.equal("GLACIER")
transition.shouldnt.have.key("Date")
assert transition["Days"] == 30
assert transition["StorageClass"] == "GLACIER"
assert "Date" not in transition
@mock_s3
def test_lifecycle_multi_boto3():
s3 = boto3.resource("s3", region_name="us-east-1")
s3_resource = boto3.resource("s3", region_name="us-east-1")
client = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
date = "2022-10-12T00:00:00.000Z"
sc = "GLACIER"
storage_class = "GLACIER"
client.put_bucket_lifecycle_configuration(
Bucket="foobar",
@ -565,37 +564,36 @@ def test_lifecycle_multi_boto3():
for rule in rules:
if rule["ID"] == "1":
rule["Prefix"].should.equal("1/")
rule.shouldnt.have.key("Expiration")
assert rule["Prefix"] == "1/"
assert "Expiration" not in rule
elif rule["ID"] == "2":
rule["Prefix"].should.equal("2/")
rule["Expiration"]["Days"].should.equal(2)
assert rule["Prefix"] == "2/"
assert rule["Expiration"]["Days"] == 2
elif rule["ID"] == "3":
rule["Prefix"].should.equal("3/")
rule["Expiration"]["Date"].should.be.a(datetime)
rule["Expiration"]["Date"].strftime("%Y-%m-%dT%H:%M:%S.000Z").should.equal(
date
)
assert rule["Prefix"] == "3/"
assert isinstance(rule["Expiration"]["Date"], datetime)
assert rule["Expiration"]["Date"].strftime("%Y-%m-%dT%H:%M:%S.000Z") == date
elif rule["ID"] == "4":
rule["Prefix"].should.equal("4/")
rule["Transitions"][0]["Days"].should.equal(4)
rule["Transitions"][0]["StorageClass"].should.equal(sc)
assert rule["Prefix"] == "4/"
assert rule["Transitions"][0]["Days"] == 4
assert rule["Transitions"][0]["StorageClass"] == storage_class
elif rule["ID"] == "5":
rule["Prefix"].should.equal("5/")
rule["Transitions"][0]["Date"].should.be.a(datetime)
rule["Transitions"][0]["Date"].strftime(
"%Y-%m-%dT%H:%M:%S.000Z"
).should.equal(date)
rule["Transitions"][0]["StorageClass"].should.equal(sc)
assert rule["Prefix"] == "5/"
assert isinstance(rule["Transitions"][0]["Date"], datetime)
assert (
rule["Transitions"][0]["Date"].strftime("%Y-%m-%dT%H:%M:%S.000Z")
== date
)
assert rule["Transitions"][0]["StorageClass"] == storage_class
else:
assert False, "Invalid rule id"
@mock_s3
def test_lifecycle_delete_boto3():
s3 = boto3.resource("s3", region_name="us-east-1")
s3_resource = boto3.resource("s3", region_name="us-east-1")
client = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
client.put_bucket_lifecycle_configuration(
Bucket="foobar",
@ -608,7 +606,7 @@ def test_lifecycle_delete_boto3():
with pytest.raises(ClientError) as ex:
client.get_bucket_lifecycle_configuration(Bucket="foobar")
ex.value.response["Error"]["Code"].should.equal("NoSuchLifecycleConfiguration")
ex.value.response["Error"]["Message"].should.equal(
assert ex.value.response["Error"]["Code"] == "NoSuchLifecycleConfiguration"
assert ex.value.response["Error"]["Message"] == (
"The lifecycle configuration does not exist"
)

View File

@ -1,26 +1,27 @@
import time
import boto3
import datetime
import pytest
from moto import mock_s3
import time
import boto3
from botocore.config import Config
from botocore.client import ClientError
import pytest
from moto import mock_s3
from moto.s3.responses import DEFAULT_REGION_NAME
import sure # noqa # pylint: disable=unused-import
@mock_s3
def test_locked_object():
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "locked-bucket-test"
key_name = "file.txt"
seconds_lock = 2
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
until = datetime.datetime.utcnow() + datetime.timedelta(0, seconds_lock)
s3.put_object(
s3_client.put_object(
Bucket=bucket_name,
Body=b"test",
Key=key_name,
@ -28,22 +29,22 @@ def test_locked_object():
ObjectLockRetainUntilDate=until,
)
versions_response = s3.list_object_versions(Bucket=bucket_name)
versions_response = s3_client.list_object_versions(Bucket=bucket_name)
version_id = versions_response["Versions"][0]["VersionId"]
deleted = False
try:
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
deleted = True
except ClientError as e:
e.response["Error"]["Code"].should.equal("AccessDenied")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "AccessDenied"
deleted.should.equal(False)
assert deleted is False
# cleaning
time.sleep(seconds_lock)
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3.delete_bucket(Bucket=bucket_name)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_bucket(Bucket=bucket_name)
@mock_s3
@ -52,44 +53,44 @@ def test_fail_locked_object():
key_name = "file.txt"
seconds_lock = 2
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=False)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=False)
until = datetime.datetime.utcnow() + datetime.timedelta(0, seconds_lock)
failed = False
try:
s3.put_object(
s3_client.put_object(
Bucket=bucket_name,
Body=b"test",
Key=key_name,
ObjectLockMode="COMPLIANCE",
ObjectLockRetainUntilDate=until,
)
except ClientError as e:
e.response["Error"]["Code"].should.equal("InvalidRequest")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "InvalidRequest"
failed = True
failed.should.equal(True)
s3.delete_bucket(Bucket=bucket_name)
assert failed is True
s3_client.delete_bucket(Bucket=bucket_name)
@mock_s3
def test_put_object_lock():
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "put-lock-bucket-test"
key_name = "file.txt"
seconds_lock = 2
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
versions_response = s3.list_object_versions(Bucket=bucket_name)
versions_response = s3_client.list_object_versions(Bucket=bucket_name)
version_id = versions_response["Versions"][0]["VersionId"]
until = datetime.datetime.utcnow() + datetime.timedelta(0, seconds_lock)
s3.put_object_retention(
s3_client.put_object_retention(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id,
@ -98,34 +99,34 @@ def test_put_object_lock():
deleted = False
try:
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
deleted = True
except ClientError as e:
e.response["Error"]["Code"].should.equal("AccessDenied")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "AccessDenied"
deleted.should.equal(False)
assert deleted is False
# cleaning
time.sleep(seconds_lock)
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3.delete_bucket(Bucket=bucket_name)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_bucket(Bucket=bucket_name)
@mock_s3
def test_put_object_legal_hold():
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "put-legal-bucket"
key_name = "file.txt"
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
versions_response = s3.list_object_versions(Bucket=bucket_name)
versions_response = s3_client.list_object_versions(Bucket=bucket_name)
version_id = versions_response["Versions"][0]["VersionId"]
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id,
@ -134,29 +135,29 @@ def test_put_object_legal_hold():
deleted = False
try:
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
deleted = True
except ClientError as e:
e.response["Error"]["Code"].should.equal("AccessDenied")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "AccessDenied"
deleted.should.equal(False)
assert deleted is False
# cleaning
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id,
LegalHold={"Status": "OFF"},
)
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3.delete_bucket(Bucket=bucket_name)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_bucket(Bucket=bucket_name)
@mock_s3
def test_put_default_lock():
# do not run this test in aws, it will block the deletion for a whole day
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "put-default-lock-bucket"
key_name = "file.txt"
@ -164,8 +165,8 @@ def test_put_default_lock():
mode = "COMPLIANCE"
enabled = "Enabled"
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3.put_object_lock_configuration(
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.put_object_lock_configuration(
Bucket=bucket_name,
ObjectLockConfiguration={
"ObjectLockEnabled": enabled,
@ -173,43 +174,43 @@ def test_put_default_lock():
},
)
s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
deleted = False
versions_response = s3.list_object_versions(Bucket=bucket_name)
versions_response = s3_client.list_object_versions(Bucket=bucket_name)
version_id = versions_response["Versions"][0]["VersionId"]
try:
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id)
deleted = True
except ClientError as e:
e.response["Error"]["Code"].should.equal("AccessDenied")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "AccessDenied"
deleted.should.equal(False)
assert deleted is False
response = s3.get_object_lock_configuration(Bucket=bucket_name)
response["ObjectLockConfiguration"]["ObjectLockEnabled"].should.equal(enabled)
response["ObjectLockConfiguration"]["Rule"]["DefaultRetention"][
"Mode"
].should.equal(mode)
response["ObjectLockConfiguration"]["Rule"]["DefaultRetention"][
"Days"
].should.equal(days)
response = s3_client.get_object_lock_configuration(Bucket=bucket_name)
assert response["ObjectLockConfiguration"]["ObjectLockEnabled"] == enabled
assert (
response["ObjectLockConfiguration"]["Rule"]["DefaultRetention"]["Mode"] == mode
)
assert (
response["ObjectLockConfiguration"]["Rule"]["DefaultRetention"]["Days"] == days
)
@mock_s3
def test_put_object_legal_hold_with_versions():
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "put-legal-bucket"
key_name = "file.txt"
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
put_obj_1 = s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
put_obj_1 = s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
version_id_1 = put_obj_1["VersionId"]
# lock the object with the version, locking the version 1
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id_1,
@ -217,10 +218,10 @@ def test_put_object_legal_hold_with_versions():
)
# put an object on the same key, effectively creating a version 2 of the object
put_obj_2 = s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
put_obj_2 = s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
version_id_2 = put_obj_2["VersionId"]
# also lock the version 2 of the object
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id_2,
@ -228,13 +229,13 @@ def test_put_object_legal_hold_with_versions():
)
# assert that the version 1 is locked
head_obj_1 = s3.head_object(
head_obj_1 = s3_client.head_object(
Bucket=bucket_name, Key=key_name, VersionId=version_id_1
)
assert head_obj_1["ObjectLockLegalHoldStatus"] == "ON"
# remove the lock from the version 1 of the object
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id_1,
@ -242,41 +243,41 @@ def test_put_object_legal_hold_with_versions():
)
# assert that you can now delete the version 1 of the object
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
with pytest.raises(ClientError) as e:
s3.head_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
assert e.value.response["Error"]["Code"] == "404"
with pytest.raises(ClientError) as exc:
s3_client.head_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
assert exc.value.response["Error"]["Code"] == "404"
# cleaning
s3.put_object_legal_hold(
s3_client.put_object_legal_hold(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id_2,
LegalHold={"Status": "OFF"},
)
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
s3.delete_bucket(Bucket=bucket_name)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
s3_client.delete_bucket(Bucket=bucket_name)
@mock_s3
def test_put_object_lock_with_versions():
s3 = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
s3_client = boto3.client("s3", config=Config(region_name=DEFAULT_REGION_NAME))
bucket_name = "put-lock-bucket-test"
key_name = "file.txt"
seconds_lock = 2
s3.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
s3_client.create_bucket(Bucket=bucket_name, ObjectLockEnabledForBucket=True)
put_obj_1 = s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
put_obj_1 = s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
version_id_1 = put_obj_1["VersionId"]
put_obj_2 = s3.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
put_obj_2 = s3_client.put_object(Bucket=bucket_name, Body=b"test", Key=key_name)
version_id_2 = put_obj_2["VersionId"]
until = datetime.datetime.utcnow() + datetime.timedelta(seconds=seconds_lock)
s3.put_object_retention(
s3_client.put_object_retention(
Bucket=bucket_name,
Key=key_name,
VersionId=version_id_1,
@ -286,20 +287,22 @@ def test_put_object_lock_with_versions():
# assert that you can delete the locked version 1 of the object
deleted = False
try:
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
s3_client.delete_object(
Bucket=bucket_name, Key=key_name, VersionId=version_id_1
)
deleted = True
except ClientError as e:
e.response["Error"]["Code"].should.equal("AccessDenied")
except ClientError as exc:
assert exc.response["Error"]["Code"] == "AccessDenied"
deleted.should.equal(False)
assert deleted is False
# assert that you can delete the version 2 of the object, not concerned by the lock
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
with pytest.raises(ClientError) as e:
s3.head_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
assert e.value.response["Error"]["Code"] == "404"
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
with pytest.raises(ClientError) as exc:
s3_client.head_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_2)
assert exc.value.response["Error"]["Code"] == "404"
# cleaning
time.sleep(seconds_lock)
s3.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
s3.delete_bucket(Bucket=bucket_name)
s3_client.delete_object(Bucket=bucket_name, Key=key_name, VersionId=version_id_1)
s3_client.delete_bucket(Bucket=bucket_name)

View File

@ -1,34 +1,32 @@
import boto3
from botocore.client import ClientError
from moto.s3.responses import DEFAULT_REGION_NAME
import pytest
import sure # noqa # pylint: disable=unused-import
from moto import mock_s3
from moto.s3.responses import DEFAULT_REGION_NAME
@mock_s3
def test_put_bucket_logging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
log_bucket = "logbucket"
wrong_region_bucket = "wrongregionlogbucket"
s3.create_bucket(Bucket=bucket_name)
s3.create_bucket(Bucket=log_bucket) # Adding the ACL for log-delivery later...
s3.create_bucket(
s3_client.create_bucket(Bucket=bucket_name)
# Adding the ACL for log-delivery later...
s3_client.create_bucket(Bucket=log_bucket)
s3_client.create_bucket(
Bucket=wrong_region_bucket,
CreateBucketConfiguration={"LocationConstraint": "us-west-2"},
)
# No logging config:
result = s3.get_bucket_logging(Bucket=bucket_name)
result = s3_client.get_bucket_logging(Bucket=bucket_name)
assert not result.get("LoggingEnabled")
# A log-bucket that doesn't exist:
with pytest.raises(ClientError) as err:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {"TargetBucket": "IAMNOTREAL", "TargetPrefix": ""}
@ -38,7 +36,7 @@ def test_put_bucket_logging():
# A log-bucket that's missing the proper ACLs for LogDelivery:
with pytest.raises(ClientError) as err:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {"TargetBucket": log_bucket, "TargetPrefix": ""}
@ -48,9 +46,9 @@ def test_put_bucket_logging():
assert "log-delivery" in err.value.response["Error"]["Message"]
# Add the proper "log-delivery" ACL to the log buckets:
bucket_owner = s3.get_bucket_acl(Bucket=log_bucket)["Owner"]
bucket_owner = s3_client.get_bucket_acl(Bucket=log_bucket)["Owner"]
for bucket in [log_bucket, wrong_region_bucket]:
s3.put_bucket_acl(
s3_client.put_bucket_acl(
Bucket=bucket,
AccessControlPolicy={
"Grants": [
@ -79,7 +77,7 @@ def test_put_bucket_logging():
# A log-bucket that's in the wrong region:
with pytest.raises(ClientError) as err:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -91,7 +89,7 @@ def test_put_bucket_logging():
assert err.value.response["Error"]["Code"] == "CrossLocationLoggingProhibitted"
# Correct logging:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -100,17 +98,17 @@ def test_put_bucket_logging():
}
},
)
result = s3.get_bucket_logging(Bucket=bucket_name)
result = s3_client.get_bucket_logging(Bucket=bucket_name)
assert result["LoggingEnabled"]["TargetBucket"] == log_bucket
assert result["LoggingEnabled"]["TargetPrefix"] == f"{bucket_name}/"
assert not result["LoggingEnabled"].get("TargetGrants")
# And disabling:
s3.put_bucket_logging(Bucket=bucket_name, BucketLoggingStatus={})
assert not s3.get_bucket_logging(Bucket=bucket_name).get("LoggingEnabled")
s3_client.put_bucket_logging(Bucket=bucket_name, BucketLoggingStatus={})
assert not s3_client.get_bucket_logging(Bucket=bucket_name).get("LoggingEnabled")
# And enabling with multiple target grants:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -136,7 +134,7 @@ def test_put_bucket_logging():
},
)
result = s3.get_bucket_logging(Bucket=bucket_name)
result = s3_client.get_bucket_logging(Bucket=bucket_name)
assert len(result["LoggingEnabled"]["TargetGrants"]) == 2
assert (
result["LoggingEnabled"]["TargetGrants"][0]["Grantee"]["ID"]
@ -144,7 +142,7 @@ def test_put_bucket_logging():
)
# Test with just 1 grant:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -162,12 +160,12 @@ def test_put_bucket_logging():
}
},
)
result = s3.get_bucket_logging(Bucket=bucket_name)
result = s3_client.get_bucket_logging(Bucket=bucket_name)
assert len(result["LoggingEnabled"]["TargetGrants"]) == 1
# With an invalid grant:
with pytest.raises(ClientError) as err:
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -176,7 +174,10 @@ def test_put_bucket_logging():
"TargetGrants": [
{
"Grantee": {
"ID": "SOMEIDSTRINGHERE9238748923734823917498237489237409123840983274",
"ID": (
"SOMEIDSTRINGHERE9238748923734823917498"
"237489237409123840983274"
),
"Type": "CanonicalUser",
},
"Permission": "NOTAREALPERM",
@ -191,15 +192,15 @@ def test_put_bucket_logging():
@mock_s3
def test_log_file_is_created():
# Create necessary buckets
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
log_bucket = "logbucket"
s3.create_bucket(Bucket=bucket_name)
s3.create_bucket(Bucket=log_bucket)
s3_client.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=log_bucket)
# Enable logging
bucket_owner = s3.get_bucket_acl(Bucket=log_bucket)["Owner"]
s3.put_bucket_acl(
bucket_owner = s3_client.get_bucket_acl(Bucket=log_bucket)["Owner"]
s3_client.put_bucket_acl(
Bucket=log_bucket,
AccessControlPolicy={
"Grants": [
@ -225,7 +226,7 @@ def test_log_file_is_created():
"Owner": bucket_owner,
},
)
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {
@ -236,27 +237,27 @@ def test_log_file_is_created():
)
# Make some requests against the source bucket
s3.put_object(Bucket=bucket_name, Key="key1", Body=b"")
s3.put_object(Bucket=bucket_name, Key="key2", Body=b"data")
s3_client.put_object(Bucket=bucket_name, Key="key1", Body=b"")
s3_client.put_object(Bucket=bucket_name, Key="key2", Body=b"data")
s3.put_bucket_logging(
s3_client.put_bucket_logging(
Bucket=bucket_name,
BucketLoggingStatus={
"LoggingEnabled": {"TargetBucket": log_bucket, "TargetPrefix": ""}
},
)
s3.list_objects_v2(Bucket=bucket_name)
s3_client.list_objects_v2(Bucket=bucket_name)
# Verify files are created in the target (logging) bucket
keys = [k["Key"] for k in s3.list_objects_v2(Bucket=log_bucket)["Contents"]]
[k for k in keys if k.startswith("mybucket/")].should.have.length_of(3)
[k for k in keys if not k.startswith("mybucket/")].should.have.length_of(1)
keys = [k["Key"] for k in s3_client.list_objects_v2(Bucket=log_bucket)["Contents"]]
assert len([k for k in keys if k.startswith("mybucket/")]) == 3
assert len([k for k in keys if not k.startswith("mybucket/")]) == 1
# Verify (roughly) files have the correct content
contents = [
s3.get_object(Bucket=log_bucket, Key=key)["Body"].read().decode("utf-8")
s3_client.get_object(Bucket=log_bucket, Key=key)["Body"].read().decode("utf-8")
for key in keys
]
assert any([c for c in contents if bucket_name in c])
assert any([c for c in contents if "REST.GET.BUCKET" in c])
assert any([c for c in contents if "REST.PUT.BUCKET" in c])
assert any(c for c in contents if bucket_name in c)
assert any(c for c in contents if "REST.GET.BUCKET" in c)
assert any(c for c in contents if "REST.PUT.BUCKET" in c)

View File

@ -3,25 +3,23 @@ import boto3
from moto import mock_s3
from moto.s3.responses import DEFAULT_REGION_NAME
import sure # noqa # pylint: disable=unused-import
@mock_s3
def test_s3_returns_requestid():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
resp = s3.create_bucket(Bucket="mybucket")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
resp = s3_client.create_bucket(Bucket="mybucket")
_check_metadata(resp)
resp = s3.put_object(Bucket="mybucket", Key="steve", Body=b"is awesome")
resp = s3_client.put_object(Bucket="mybucket", Key="steve", Body=b"is awesome")
_check_metadata(resp)
resp = s3.get_object(Bucket="mybucket", Key="steve")
resp = s3_client.get_object(Bucket="mybucket", Key="steve")
_check_metadata(resp)
def _check_metadata(resp):
meta = resp["ResponseMetadata"]
headers = meta["HTTPHeaders"]
meta.should.have.key("RequestId")
headers.should.have.key("x-amzn-requestid")
meta["RequestId"].should.equal(headers["x-amzn-requestid"])
assert "RequestId" in meta
assert "x-amzn-requestid" in headers
assert meta["RequestId"] == headers["x-amzn-requestid"]

View File

@ -1,18 +1,16 @@
import boto3
import os
import pytest
import sure # noqa # pylint: disable=unused-import
import requests
from botocore.client import ClientError
from functools import wraps
from io import BytesIO
import os
import re
from moto.s3.responses import DEFAULT_REGION_NAME
import boto3
from botocore.client import ClientError
import pytest
import requests
from moto import settings, mock_s3
import moto.s3.models as s3model
from moto.s3.responses import DEFAULT_REGION_NAME
from moto.settings import get_s3_default_key_buffer_size, S3_UPLOAD_PART_MIN_SIZE
if settings.TEST_SERVER_MODE:
@ -23,17 +21,15 @@ else:
EXPECTED_ETAG = '"66d1a1a2ed08fd05c137f316af4ff255-2"'
def reduced_min_part_size(f):
"""speed up tests by temporarily making the multipart minimum part size
small
"""
def reduced_min_part_size(func):
"""Speed up tests by temporarily making multipart min. part size small."""
orig_size = S3_UPLOAD_PART_MIN_SIZE
@wraps(f)
@wraps(func)
def wrapped(*args, **kwargs):
try:
s3model.S3_UPLOAD_PART_MIN_SIZE = REDUCED_PART_SIZE
return f(*args, **kwargs)
return func(*args, **kwargs)
finally:
s3model.S3_UPLOAD_PART_MIN_SIZE = orig_size
@ -49,16 +45,17 @@ def test_default_key_buffer_size():
os.environ["MOTO_S3_DEFAULT_KEY_BUFFER_SIZE"] = "2" # 2 bytes
assert get_s3_default_key_buffer_size() == 2
fk = s3model.FakeKey("a", os.urandom(1)) # 1 byte string
assert fk._value_buffer._rolled is False
fake_key = s3model.FakeKey("a", os.urandom(1)) # 1 byte string
assert fake_key._value_buffer._rolled is False
os.environ["MOTO_S3_DEFAULT_KEY_BUFFER_SIZE"] = "1" # 1 byte
assert get_s3_default_key_buffer_size() == 1
fk = s3model.FakeKey("a", os.urandom(3)) # 3 byte string
assert fk._value_buffer._rolled is True
fake_key = s3model.FakeKey("a", os.urandom(3)) # 3 byte string
assert fake_key._value_buffer._rolled is True
# if no MOTO_S3_DEFAULT_KEY_BUFFER_SIZE env variable is present the buffer size should be less than
# S3_UPLOAD_PART_MIN_SIZE to prevent in memory caching of multi part uploads
# if no MOTO_S3_DEFAULT_KEY_BUFFER_SIZE env variable is present the
# buffer size should be less than S3_UPLOAD_PART_MIN_SIZE to prevent
# in memory caching of multi part uploads.
del os.environ["MOTO_S3_DEFAULT_KEY_BUFFER_SIZE"]
assert get_s3_default_key_buffer_size() < S3_UPLOAD_PART_MIN_SIZE
@ -69,24 +66,24 @@ def test_default_key_buffer_size():
@mock_s3
def test_multipart_upload_too_small():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
mp = client.create_multipart_upload(Bucket="foobar", Key="the-key")
multipart = client.create_multipart_upload(Bucket="foobar", Key="the-key")
up1 = client.upload_part(
Body=BytesIO(b"hello"),
PartNumber=1,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
up2 = client.upload_part(
Body=BytesIO(b"world"),
PartNumber=2,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# Multipart with total size under 5MB is refused
with pytest.raises(ClientError) as ex:
@ -99,10 +96,10 @@ def test_multipart_upload_too_small():
{"ETag": up2["ETag"], "PartNumber": 2},
]
},
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
ex.value.response["Error"]["Code"].should.equal("EntityTooSmall")
ex.value.response["Error"]["Message"].should.equal(
assert ex.value.response["Error"]["Code"] == "EntityTooSmall"
assert ex.value.response["Error"]["Message"] == (
"Your proposed upload is smaller than the minimum allowed object size."
)
@ -111,26 +108,26 @@ def test_multipart_upload_too_small():
@mock_s3
@reduced_min_part_size
def test_multipart_upload(key: str):
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
part1 = b"0" * REDUCED_PART_SIZE
part2 = b"1"
mp = client.create_multipart_upload(Bucket="foobar", Key=key)
multipart = client.create_multipart_upload(Bucket="foobar", Key=key)
up1 = client.upload_part(
Body=BytesIO(part1),
PartNumber=1,
Bucket="foobar",
Key=key,
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
up2 = client.upload_part(
Body=BytesIO(part2),
PartNumber=2,
Bucket="foobar",
Key=key,
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
client.complete_multipart_upload(
@ -142,36 +139,36 @@ def test_multipart_upload(key: str):
{"ETag": up2["ETag"], "PartNumber": 2},
]
},
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# we should get both parts as the key contents
response = client.get_object(Bucket="foobar", Key=key)
response["Body"].read().should.equal(part1 + part2)
assert response["Body"].read() == part1 + part2
@mock_s3
@reduced_min_part_size
def test_multipart_upload_out_of_order():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
part1 = b"0" * REDUCED_PART_SIZE
part2 = b"1"
mp = client.create_multipart_upload(Bucket="foobar", Key="the-key")
multipart = client.create_multipart_upload(Bucket="foobar", Key="the-key")
up1 = client.upload_part(
Body=BytesIO(part1),
PartNumber=4,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
up2 = client.upload_part(
Body=BytesIO(part2),
PartNumber=2,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
client.complete_multipart_upload(
@ -183,24 +180,24 @@ def test_multipart_upload_out_of_order():
{"ETag": up2["ETag"], "PartNumber": 2},
]
},
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# we should get both parts as the key contents
response = client.get_object(Bucket="foobar", Key="the-key")
response["Body"].read().should.equal(part1 + part2)
assert response["Body"].read() == part1 + part2
@mock_s3
@reduced_min_part_size
def test_multipart_upload_with_headers():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "fancymultiparttest"
key_name = "the-key"
s3.create_bucket(Bucket=bucket_name)
s3_resource.create_bucket(Bucket=bucket_name)
part1 = b"0" * REDUCED_PART_SIZE
mp = client.create_multipart_upload(
multipart = client.create_multipart_upload(
Bucket=bucket_name,
Key=key_name,
Metadata={"meta": "data"},
@ -212,31 +209,29 @@ def test_multipart_upload_with_headers():
PartNumber=1,
Bucket=bucket_name,
Key=key_name,
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
client.complete_multipart_upload(
Bucket=bucket_name,
Key=key_name,
MultipartUpload={"Parts": [{"ETag": up1["ETag"], "PartNumber": 1}]},
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# we should get both parts as the key contents
response = client.get_object(Bucket=bucket_name, Key=key_name)
response["Metadata"].should.equal({"meta": "data"})
response["StorageClass"].should.equal("STANDARD_IA")
assert response["Metadata"] == {"meta": "data"}
assert response["StorageClass"] == "STANDARD_IA"
grants = client.get_object_acl(Bucket=bucket_name, Key=key_name)["Grants"]
grants.should.have.length_of(2)
grants.should.contain(
{
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers",
},
"Permission": "READ",
}
)
assert len(grants) == 2
assert {
"Grantee": {
"Type": "Group",
"URI": "http://acs.amazonaws.com/groups/global/AuthenticatedUsers",
},
"Permission": "READ",
} in grants
@pytest.mark.parametrize(
@ -251,20 +246,20 @@ def test_multipart_upload_with_headers():
@mock_s3
@reduced_min_part_size
def test_multipart_upload_with_copy_key(original_key_name):
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3.put_object(Bucket="foobar", Key=original_key_name, Body="key_value")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="foobar")
s3_client.put_object(Bucket="foobar", Key=original_key_name, Body="key_value")
mpu = s3.create_multipart_upload(Bucket="foobar", Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket="foobar", Key="the-key")
part1 = b"0" * REDUCED_PART_SIZE
up1 = s3.upload_part(
up1 = s3_client.upload_part(
Bucket="foobar",
Key="the-key",
PartNumber=1,
UploadId=mpu["UploadId"],
Body=BytesIO(part1),
)
up2 = s3.upload_part_copy(
up2 = s3_client.upload_part_copy(
Bucket="foobar",
Key="the-key",
CopySource={"Bucket": "foobar", "Key": original_key_name},
@ -272,7 +267,7 @@ def test_multipart_upload_with_copy_key(original_key_name):
PartNumber=2,
UploadId=mpu["UploadId"],
)
s3.complete_multipart_upload(
s3_client.complete_multipart_upload(
Bucket="foobar",
Key="the-key",
MultipartUpload={
@ -283,19 +278,19 @@ def test_multipart_upload_with_copy_key(original_key_name):
},
UploadId=mpu["UploadId"],
)
response = s3.get_object(Bucket="foobar", Key="the-key")
response["Body"].read().should.equal(part1 + b"key_")
response = s3_client.get_object(Bucket="foobar", Key="the-key")
assert response["Body"].read() == part1 + b"key_"
@mock_s3
@reduced_min_part_size
def test_multipart_upload_cancel():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="foobar")
mpu = s3.create_multipart_upload(Bucket="foobar", Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket="foobar", Key="the-key")
part1 = b"0" * REDUCED_PART_SIZE
s3.upload_part(
s3_client.upload_part(
Bucket="foobar",
Key="the-key",
PartNumber=1,
@ -303,25 +298,27 @@ def test_multipart_upload_cancel():
Body=BytesIO(part1),
)
uploads = s3.list_multipart_uploads(Bucket="foobar")["Uploads"]
uploads.should.have.length_of(1)
uploads[0]["Key"].should.equal("the-key")
uploads = s3_client.list_multipart_uploads(Bucket="foobar")["Uploads"]
assert len(uploads) == 1
assert uploads[0]["Key"] == "the-key"
s3.abort_multipart_upload(Bucket="foobar", Key="the-key", UploadId=mpu["UploadId"])
s3_client.abort_multipart_upload(
Bucket="foobar", Key="the-key", UploadId=mpu["UploadId"]
)
s3.list_multipart_uploads(Bucket="foobar").shouldnt.have.key("Uploads")
assert "Uploads" not in s3_client.list_multipart_uploads(Bucket="foobar")
@mock_s3
@reduced_min_part_size
def test_multipart_etag_quotes_stripped():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3.put_object(Bucket="foobar", Key="original-key", Body="key_value")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="foobar")
s3_client.put_object(Bucket="foobar", Key="original-key", Body="key_value")
mpu = s3.create_multipart_upload(Bucket="foobar", Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket="foobar", Key="the-key")
part1 = b"0" * REDUCED_PART_SIZE
up1 = s3.upload_part(
up1 = s3_client.upload_part(
Bucket="foobar",
Key="the-key",
PartNumber=1,
@ -329,7 +326,7 @@ def test_multipart_etag_quotes_stripped():
Body=BytesIO(part1),
)
etag1 = up1["ETag"].replace('"', "")
up2 = s3.upload_part_copy(
up2 = s3_client.upload_part_copy(
Bucket="foobar",
Key="the-key",
CopySource={"Bucket": "foobar", "Key": "original-key"},
@ -338,7 +335,7 @@ def test_multipart_etag_quotes_stripped():
UploadId=mpu["UploadId"],
)
etag2 = up2["CopyPartResult"]["ETag"].replace('"', "")
s3.complete_multipart_upload(
s3_client.complete_multipart_upload(
Bucket="foobar",
Key="the-key",
MultipartUpload={
@ -349,26 +346,26 @@ def test_multipart_etag_quotes_stripped():
},
UploadId=mpu["UploadId"],
)
response = s3.get_object(Bucket="foobar", Key="the-key")
response["Body"].read().should.equal(part1 + b"key_")
response = s3_client.get_object(Bucket="foobar", Key="the-key")
assert response["Body"].read() == part1 + b"key_"
@mock_s3
@reduced_min_part_size
def test_multipart_duplicate_upload():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_resource.create_bucket(Bucket="foobar")
part1 = b"0" * REDUCED_PART_SIZE
part2 = b"1"
mp = client.create_multipart_upload(Bucket="foobar", Key="the-key")
multipart = client.create_multipart_upload(Bucket="foobar", Key="the-key")
client.upload_part(
Body=BytesIO(part1),
PartNumber=1,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# same part again
up1 = client.upload_part(
@ -376,14 +373,14 @@ def test_multipart_duplicate_upload():
PartNumber=1,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
up2 = client.upload_part(
Body=BytesIO(part2),
PartNumber=2,
Bucket="foobar",
Key="the-key",
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
client.complete_multipart_upload(
@ -395,37 +392,41 @@ def test_multipart_duplicate_upload():
{"ETag": up2["ETag"], "PartNumber": 2},
]
},
UploadId=mp["UploadId"],
UploadId=multipart["UploadId"],
)
# we should get both parts as the key contents
response = client.get_object(Bucket="foobar", Key="the-key")
response["Body"].read().should.equal(part1 + part2)
assert response["Body"].read() == part1 + part2
@mock_s3
def test_list_multiparts():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="foobar")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="foobar")
mpu1 = s3.create_multipart_upload(Bucket="foobar", Key="one-key")
mpu2 = s3.create_multipart_upload(Bucket="foobar", Key="two-key")
mpu1 = s3_client.create_multipart_upload(Bucket="foobar", Key="one-key")
mpu2 = s3_client.create_multipart_upload(Bucket="foobar", Key="two-key")
uploads = s3.list_multipart_uploads(Bucket="foobar")["Uploads"]
uploads.should.have.length_of(2)
{u["Key"]: u["UploadId"] for u in uploads}.should.equal(
uploads = s3_client.list_multipart_uploads(Bucket="foobar")["Uploads"]
assert len(uploads) == 2
assert {u["Key"]: u["UploadId"] for u in uploads} == (
{"one-key": mpu1["UploadId"], "two-key": mpu2["UploadId"]}
)
s3.abort_multipart_upload(Bucket="foobar", Key="the-key", UploadId=mpu2["UploadId"])
s3_client.abort_multipart_upload(
Bucket="foobar", Key="the-key", UploadId=mpu2["UploadId"]
)
uploads = s3.list_multipart_uploads(Bucket="foobar")["Uploads"]
uploads.should.have.length_of(1)
uploads[0]["Key"].should.equal("one-key")
uploads = s3_client.list_multipart_uploads(Bucket="foobar")["Uploads"]
assert len(uploads) == 1
assert uploads[0]["Key"] == "one-key"
s3.abort_multipart_upload(Bucket="foobar", Key="the-key", UploadId=mpu1["UploadId"])
s3_client.abort_multipart_upload(
Bucket="foobar", Key="the-key", UploadId=mpu1["UploadId"]
)
res = s3.list_multipart_uploads(Bucket="foobar")
res.shouldnt.have.key("Uploads")
res = s3_client.list_multipart_uploads(Bucket="foobar")
assert "Uploads" not in res
@mock_s3
@ -442,25 +443,26 @@ def test_multipart_should_throw_nosuchupload_if_there_are_no_parts():
with pytest.raises(ClientError) as ex:
list(multipart_upload.parts.all())
err = ex.value.response["Error"]
err["Code"].should.equal("NoSuchUpload")
err["Message"].should.equal(
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed."
assert err["Code"] == "NoSuchUpload"
assert err["Message"] == (
"The specified upload does not exist. The upload ID may be invalid, "
"or the upload may have been aborted or completed."
)
err["UploadId"].should.equal(multipart_upload.id)
assert err["UploadId"] == multipart_upload.id
@mock_s3
def test_multipart_wrong_partnumber():
bucket_name = "mputest-3593"
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket=bucket_name)
mpu = s3.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu_id = mpu["UploadId"]
body = b"111"
with pytest.raises(ClientError) as ex:
s3.upload_part(
s3_client.upload_part(
Bucket=bucket_name,
Key="the-key",
PartNumber=-1,
@ -469,9 +471,10 @@ def test_multipart_wrong_partnumber():
ContentLength=len(body),
)
err = ex.value.response["Error"]
err["Code"].should.equal("NoSuchUpload")
err["Message"].should.equal(
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed."
assert err["Code"] == "NoSuchUpload"
assert err["Message"] == (
"The specified upload does not exist. The upload ID may be invalid, "
"or the upload may have been aborted or completed."
)
@ -485,21 +488,21 @@ def test_multipart_upload_with_tags():
client.create_bucket(Bucket=bucket)
response = client.create_multipart_upload(Bucket=bucket, Key=key, Tagging=tags)
u = boto3.resource("s3").MultipartUpload(bucket, key, response["UploadId"])
upload = boto3.resource("s3").MultipartUpload(bucket, key, response["UploadId"])
parts = [
{
"ETag": u.Part(i).upload(Body=os.urandom(5 * (2**20)))["ETag"],
"ETag": upload.Part(i).upload(Body=os.urandom(5 * (2**20)))["ETag"],
"PartNumber": i,
}
for i in range(1, 3)
]
u.complete(MultipartUpload={"Parts": parts})
upload.complete(MultipartUpload={"Parts": parts})
# check tags
response = client.get_object_tagging(Bucket=bucket, Key=key)
actual = {t["Key"]: t["Value"] for t in response.get("TagSet", [])}
actual.should.equal({"a": "b"})
assert actual == {"a": "b"}
@mock_s3
@ -524,7 +527,7 @@ def test_multipart_upload_should_return_part_10000():
all_parts = s3_client.list_parts(Bucket=bucket, Key=key, UploadId=mpu_id)["Parts"]
part_nrs = [part["PartNumber"] for part in all_parts]
part_nrs.should.equal([1, 2, 10000])
assert part_nrs == [1, 2, 10000]
@mock_s3
@ -539,7 +542,7 @@ def test_multipart_upload_without_parts():
mpu_id = mpu["UploadId"]
list_parts_result = s3_client.list_parts(Bucket=bucket, Key=key, UploadId=mpu_id)
list_parts_result["IsTruncated"].should.equal(False)
assert list_parts_result["IsTruncated"] is False
@mock_s3
@ -559,12 +562,12 @@ def test_s3_multipart_upload_cannot_upload_part_over_10000(part_nr):
Bucket=bucket, Key=key, PartNumber=part_nr, UploadId=mpu_id, Body="data"
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidArgument")
err["Message"].should.equal(
assert err["Code"] == "InvalidArgument"
assert err["Message"] == (
"Part number must be an integer between 1 and 10000, inclusive"
)
err["ArgumentName"].should.equal("partNumber")
err["ArgumentValue"].should.equal(f"{part_nr}")
assert err["ArgumentName"] == "partNumber"
assert err["ArgumentValue"] == f"{part_nr}"
@mock_s3
@ -578,25 +581,28 @@ def test_s3_abort_multipart_data_with_invalid_upload_and_key():
Bucket="blah", Key="foobar", UploadId="dummy_upload_id"
)
err = err.value.response["Error"]
err["Code"].should.equal("NoSuchUpload")
err["Message"].should.equal(
"The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed."
assert err["Code"] == "NoSuchUpload"
assert err["Message"] == (
"The specified upload does not exist. The upload ID may be invalid, "
"or the upload may have been aborted or completed."
)
err["UploadId"].should.equal("dummy_upload_id")
assert err["UploadId"] == "dummy_upload_id"
@mock_s3
@reduced_min_part_size
def test_multipart_etag():
# Create Bucket so that test can run
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="mybucket")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="mybucket")
upload_id = s3.create_multipart_upload(Bucket="mybucket", Key="the-key")["UploadId"]
upload_id = s3_client.create_multipart_upload(Bucket="mybucket", Key="the-key")[
"UploadId"
]
part1 = b"0" * REDUCED_PART_SIZE
etags = []
etags.append(
s3.upload_part(
s3_client.upload_part(
Bucket="mybucket",
Key="the-key",
PartNumber=1,
@ -607,7 +613,7 @@ def test_multipart_etag():
# last part, can be less than 5 MB
part2 = b"1"
etags.append(
s3.upload_part(
s3_client.upload_part(
Bucket="mybucket",
Key="the-key",
PartNumber=2,
@ -616,7 +622,7 @@ def test_multipart_etag():
)["ETag"]
)
s3.complete_multipart_upload(
s3_client.complete_multipart_upload(
Bucket="mybucket",
Key="the-key",
UploadId=upload_id,
@ -627,26 +633,28 @@ def test_multipart_etag():
},
)
# we should get both parts as the key contents
resp = s3.get_object(Bucket="mybucket", Key="the-key")
resp["ETag"].should.equal(EXPECTED_ETAG)
resp = s3_client.get_object(Bucket="mybucket", Key="the-key")
assert resp["ETag"] == EXPECTED_ETAG
@mock_s3
@reduced_min_part_size
def test_multipart_version():
# Create Bucket so that test can run
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="mybucket")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="mybucket")
s3.put_bucket_versioning(
s3_client.put_bucket_versioning(
Bucket="mybucket", VersioningConfiguration={"Status": "Enabled"}
)
upload_id = s3.create_multipart_upload(Bucket="mybucket", Key="the-key")["UploadId"]
upload_id = s3_client.create_multipart_upload(Bucket="mybucket", Key="the-key")[
"UploadId"
]
part1 = b"0" * REDUCED_PART_SIZE
etags = []
etags.append(
s3.upload_part(
s3_client.upload_part(
Bucket="mybucket",
Key="the-key",
PartNumber=1,
@ -657,7 +665,7 @@ def test_multipart_version():
# last part, can be less than 5 MB
part2 = b"1"
etags.append(
s3.upload_part(
s3_client.upload_part(
Bucket="mybucket",
Key="the-key",
PartNumber=2,
@ -665,7 +673,7 @@ def test_multipart_version():
Body=part2,
)["ETag"]
)
response = s3.complete_multipart_upload(
response = s3_client.complete_multipart_upload(
Bucket="mybucket",
Key="the-key",
UploadId=upload_id,
@ -676,7 +684,7 @@ def test_multipart_version():
},
)
response["VersionId"].should.match("[-a-z0-9]+")
assert re.match("[-a-z0-9]+", response["VersionId"])
@mock_s3
@ -696,37 +704,39 @@ def test_multipart_version():
],
)
def test_multipart_list_parts_invalid_argument(part_nr, msg, msg2):
s3 = boto3.client("s3", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
bucket_name = "mybucketasdfljoqwerasdfas"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
mpu = s3.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu_id = mpu["UploadId"]
def get_parts(**kwarg):
s3.list_parts(Bucket=bucket_name, Key="the-key", UploadId=mpu_id, **kwarg)
s3_client.list_parts(
Bucket=bucket_name, Key="the-key", UploadId=mpu_id, **kwarg
)
with pytest.raises(ClientError) as err:
get_parts(**{"MaxParts": part_nr})
e = err.value.response["Error"]
e["Code"].should.equal("InvalidArgument")
e["Message"].should.equal(msg)
err_rsp = err.value.response["Error"]
assert err_rsp["Code"] == "InvalidArgument"
assert err_rsp["Message"] == msg
with pytest.raises(ClientError) as err:
get_parts(**{"PartNumberMarker": part_nr})
e = err.value.response["Error"]
e["Code"].should.equal("InvalidArgument")
e["Message"].should.equal(msg2)
err_rsp = err.value.response["Error"]
assert err_rsp["Code"] == "InvalidArgument"
assert err_rsp["Message"] == msg2
@mock_s3
@reduced_min_part_size
def test_multipart_list_parts():
s3 = boto3.client("s3", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
bucket_name = "mybucketasdfljoqwerasdfas"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
mpu = s3.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket=bucket_name, Key="the-key")
mpu_id = mpu["UploadId"]
parts = []
@ -736,7 +746,9 @@ def test_multipart_list_parts():
# Get uploaded parts using default values
uploaded_parts = []
uploaded = s3.list_parts(Bucket=bucket_name, Key="the-key", UploadId=mpu_id)
uploaded = s3_client.list_parts(
Bucket=bucket_name, Key="the-key", UploadId=mpu_id
)
assert uploaded["PartNumberMarker"] == 0
@ -762,7 +774,7 @@ def test_multipart_list_parts():
uploaded_parts = []
while "there are parts":
uploaded = s3.list_parts(
uploaded = s3_client.list_parts(
Bucket=bucket_name,
Key="the-key",
UploadId=mpu_id,
@ -800,7 +812,7 @@ def test_multipart_list_parts():
for i in range(1, n_parts + 1):
part_size = REDUCED_PART_SIZE + i
body = b"1" * part_size
part = s3.upload_part(
part = s3_client.upload_part(
Bucket=bucket_name,
Key="the-key",
PartNumber=i,
@ -818,7 +830,7 @@ def test_multipart_list_parts():
get_parts_all(11)
get_parts_by_batch(11)
s3.complete_multipart_upload(
s3_client.complete_multipart_upload(
Bucket=bucket_name,
Key="the-key",
UploadId=mpu_id,
@ -829,10 +841,10 @@ def test_multipart_list_parts():
@mock_s3
@reduced_min_part_size
def test_multipart_part_size():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="mybucket")
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket="mybucket")
mpu = s3.create_multipart_upload(Bucket="mybucket", Key="the-key")
mpu = s3_client.create_multipart_upload(Bucket="mybucket", Key="the-key")
mpu_id = mpu["UploadId"]
parts = []
@ -840,7 +852,7 @@ def test_multipart_part_size():
for i in range(1, n_parts + 1):
part_size = REDUCED_PART_SIZE + i
body = b"1" * part_size
part = s3.upload_part(
part = s3_client.upload_part(
Bucket="mybucket",
Key="the-key",
PartNumber=i,
@ -850,7 +862,7 @@ def test_multipart_part_size():
)
parts.append({"PartNumber": i, "ETag": part["ETag"]})
s3.complete_multipart_upload(
s3_client.complete_multipart_upload(
Bucket="mybucket",
Key="the-key",
UploadId=mpu_id,
@ -858,17 +870,13 @@ def test_multipart_part_size():
)
for i in range(1, n_parts + 1):
obj = s3.head_object(Bucket="mybucket", Key="the-key", PartNumber=i)
obj = s3_client.head_object(Bucket="mybucket", Key="the-key", PartNumber=i)
assert obj["ContentLength"] == REDUCED_PART_SIZE + i
@mock_s3
def test_complete_multipart_with_empty_partlist():
"""
When completing a MultipartUpload with an empty part list, AWS responds with an InvalidXML-error
Verify that we send the same error, to duplicate boto3's behaviour
"""
"""Verify InvalidXML-error sent for MultipartUpload with empty part list."""
bucket = "testbucketthatcompletesmultipartuploadwithoutparts"
key = "test-multi-empty"
@ -883,9 +891,10 @@ def test_complete_multipart_with_empty_partlist():
with pytest.raises(ClientError) as exc:
upload.complete(MultipartUpload={"Parts": []})
err = exc.value.response["Error"]
err["Code"].should.equal("MalformedXML")
err["Message"].should.equal(
"The XML you provided was not well-formed or did not validate against our published schema"
assert err["Code"] == "MalformedXML"
assert err["Message"] == (
"The XML you provided was not well-formed or did not validate "
"against our published schema"
)
@ -969,7 +978,7 @@ def test_generate_presigned_url_on_multipart_upload_without_acl():
"head_object", Params={"Bucket": bucket_name, "Key": object_key}
)
res = requests.get(url)
res.status_code.should.equal(200)
assert res.status_code == 200
@mock_s3
@ -986,16 +995,16 @@ def test_head_object_returns_part_count():
num_parts = 2
parts = []
for p in range(1, num_parts + 1):
for part in range(1, num_parts + 1):
response = client.upload_part(
Body=b"x" * (REDUCED_PART_SIZE + p),
Body=b"x" * (REDUCED_PART_SIZE + part),
Bucket=bucket,
Key=key,
PartNumber=p,
PartNumber=part,
UploadId=mp_id,
)
parts.append({"ETag": response["ETag"], "PartNumber": p})
parts.append({"ETag": response["ETag"], "PartNumber": part})
client.complete_multipart_upload(
Bucket=bucket,
@ -1005,8 +1014,8 @@ def test_head_object_returns_part_count():
)
resp = client.head_object(Bucket=bucket, Key=key, PartNumber=1)
resp.should.have.key("PartsCount").equals(num_parts)
assert resp["PartsCount"] == num_parts
# Header is not returned when we do not pass PartNumber
resp = client.head_object(Bucket=bucket, Key=key)
resp.shouldnt.have.key("PartsCount")
assert "PartsCount" not in resp

View File

@ -1,16 +1,18 @@
from uuid import uuid4
import boto3
import pytest
from moto import mock_s3
from uuid import uuid4
@mock_s3
class TestS3ObjectAttributes:
def setup_method(self, *args) -> None: # pylint: disable=unused-argument
self.bucket_name = str(uuid4())
self.s3 = boto3.resource("s3", region_name="us-east-1")
self.s3_resource = boto3.resource("s3", region_name="us-east-1")
self.client = boto3.client("s3", region_name="us-east-1")
self.bucket = self.s3.Bucket(self.bucket_name)
self.bucket = self.s3_resource.Bucket(self.bucket_name)
self.bucket.create()
self.key = self.bucket.put_object(Key="mykey", Body=b"somedata")

View File

@ -1,8 +1,7 @@
import boto3
from botocore.client import ClientError
import pytest
import sure # noqa # pylint: disable=unused-import
from moto import mock_s3
@ -14,7 +13,7 @@ def test_create_bucket_with_ownership():
client.create_bucket(Bucket=bucket, ObjectOwnership=ownership)
response = client.get_bucket_ownership_controls(Bucket=bucket)
response["OwnershipControls"]["Rules"][0]["ObjectOwnership"].should.equal(ownership)
assert response["OwnershipControls"]["Rules"][0]["ObjectOwnership"] == ownership
@mock_s3
@ -29,7 +28,7 @@ def test_put_ownership_to_bucket():
)
response = client.get_bucket_ownership_controls(Bucket=bucket)
response["OwnershipControls"]["Rules"][0]["ObjectOwnership"].should.equal(ownership)
assert response["OwnershipControls"]["Rules"][0]["ObjectOwnership"] == ownership
@mock_s3
@ -44,7 +43,7 @@ def test_delete_ownership_from_bucket():
with pytest.raises(ClientError) as ex:
client.get_bucket_ownership_controls(Bucket=bucket)
ex.value.response["Error"]["Code"].should.equal("OwnershipControlsNotFoundError")
ex.value.response["Error"]["Message"].should.equal(
assert ex.value.response["Error"]["Code"] == "OwnershipControlsNotFoundError"
assert ex.value.response["Error"]["Message"] == (
"The bucket ownership controls were not found"
)

View File

@ -1,70 +1,70 @@
import boto3
import pytest
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
from moto import mock_s3
from uuid import uuid4
import boto3
from botocore.exceptions import ClientError
import pytest
from moto import mock_s3
DEFAULT_REGION_NAME = "us-east-1"
@mock_s3
def test_get_bucket_replication_for_unexisting_bucket():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
with pytest.raises(ClientError) as exc:
s3.get_bucket_replication(Bucket=bucket_name)
s3_client.get_bucket_replication(Bucket=bucket_name)
err = exc.value.response["Error"]
err["Code"].should.equal("NoSuchBucket")
err["Message"].should.equal("The specified bucket does not exist")
err["BucketName"].should.equal(bucket_name)
assert err["Code"] == "NoSuchBucket"
assert err["Message"] == "The specified bucket does not exist"
assert err["BucketName"] == bucket_name
@mock_s3
def test_get_bucket_replication_bucket_without_replication():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket=bucket_name)
with pytest.raises(ClientError) as exc:
s3.get_bucket_replication(Bucket=bucket_name)
s3_client.get_bucket_replication(Bucket=bucket_name)
err = exc.value.response["Error"]
err["Code"].should.equal("ReplicationConfigurationNotFoundError")
err["Message"].should.equal("The replication configuration was not found")
err["BucketName"].should.equal(bucket_name)
assert err["Code"] == "ReplicationConfigurationNotFoundError"
assert err["Message"] == "The replication configuration was not found"
assert err["BucketName"] == bucket_name
@mock_s3
def test_delete_bucket_replication_unknown_bucket():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
with pytest.raises(ClientError) as exc:
s3.delete_bucket_replication(Bucket=bucket_name)
s3_client.delete_bucket_replication(Bucket=bucket_name)
err = exc.value.response["Error"]
err["Code"].should.equal("NoSuchBucket")
err["Message"].should.equal("The specified bucket does not exist")
err["BucketName"].should.equal(bucket_name)
assert err["Code"] == "NoSuchBucket"
assert err["Message"] == "The specified bucket does not exist"
assert err["BucketName"] == bucket_name
@mock_s3
def test_delete_bucket_replication_bucket_without_replication():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
# No-op
s3.delete_bucket_replication(Bucket=bucket_name)
s3_client.delete_bucket_replication(Bucket=bucket_name)
@mock_s3
def test_create_replication_without_versioning():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client.create_bucket(Bucket=bucket_name)
with pytest.raises(ClientError) as exc:
s3.put_bucket_replication(
s3_client.put_bucket_replication(
Bucket=bucket_name,
ReplicationConfiguration={
"Role": "myrole",
@ -74,23 +74,23 @@ def test_create_replication_without_versioning():
},
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidRequest")
err["Message"].should.equal(
assert err["Code"] == "InvalidRequest"
assert err["Message"] == (
"Versioning must be 'Enabled' on the bucket to apply a replication configuration"
)
err["BucketName"].should.equal(bucket_name)
assert err["BucketName"] == bucket_name
@mock_s3
def test_create_and_retrieve_replication_with_single_rules():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3.put_bucket_versioning(
s3_client.create_bucket(Bucket=bucket_name)
s3_client.put_bucket_versioning(
Bucket=bucket_name, VersioningConfiguration={"Status": "Enabled"}
)
s3.put_bucket_replication(
s3_client.put_bucket_replication(
Bucket=bucket_name,
ReplicationConfiguration={
"Role": "myrole",
@ -105,44 +105,44 @@ def test_create_and_retrieve_replication_with_single_rules():
},
)
config = s3.get_bucket_replication(Bucket=bucket_name)["ReplicationConfiguration"]
config.should.equal(
{
"Role": "myrole",
"Rules": [
{
"DeleteMarkerReplication": {"Status": "Disabled"},
"Destination": {"Bucket": "secondbucket"},
"Filter": {"Prefix": ""},
"ID": "firstrule",
"Priority": 2,
"Status": "Enabled",
}
],
}
)
config = s3_client.get_bucket_replication(Bucket=bucket_name)[
"ReplicationConfiguration"
]
assert config == {
"Role": "myrole",
"Rules": [
{
"DeleteMarkerReplication": {"Status": "Disabled"},
"Destination": {"Bucket": "secondbucket"},
"Filter": {"Prefix": ""},
"ID": "firstrule",
"Priority": 2,
"Status": "Enabled",
}
],
}
s3.delete_bucket_replication(Bucket=bucket_name)
s3_client.delete_bucket_replication(Bucket=bucket_name)
# Can't retrieve replication that has been deleted
with pytest.raises(ClientError) as exc:
s3.get_bucket_replication(Bucket=bucket_name)
s3_client.get_bucket_replication(Bucket=bucket_name)
err = exc.value.response["Error"]
err["Code"].should.equal("ReplicationConfigurationNotFoundError")
err["Message"].should.equal("The replication configuration was not found")
err["BucketName"].should.equal(bucket_name)
assert err["Code"] == "ReplicationConfigurationNotFoundError"
assert err["Message"] == "The replication configuration was not found"
assert err["BucketName"] == bucket_name
@mock_s3
def test_create_and_retrieve_replication_with_multiple_rules():
bucket_name = str(uuid4())
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket=bucket_name)
s3.put_bucket_versioning(
s3_client.create_bucket(Bucket=bucket_name)
s3_client.put_bucket_versioning(
Bucket=bucket_name, VersioningConfiguration={"Status": "Enabled"}
)
s3.put_bucket_replication(
s3_client.put_bucket_replication(
Bucket=bucket_name,
ReplicationConfiguration={
"Role": "myrole",
@ -158,19 +158,21 @@ def test_create_and_retrieve_replication_with_multiple_rules():
},
)
config = s3.get_bucket_replication(Bucket=bucket_name)["ReplicationConfiguration"]
config.should.have.key("Role").equal("myrole")
config = s3_client.get_bucket_replication(Bucket=bucket_name)[
"ReplicationConfiguration"
]
assert config["Role"] == "myrole"
rules = config["Rules"]
rules.should.have.length_of(2)
assert len(rules) == 2
first_rule = rules[0]
first_rule.should.have.key("ID")
first_rule.should.have.key("Priority").equal(1)
first_rule.should.have.key("Status").equal("Enabled")
first_rule.should.have.key("Destination").equal({"Bucket": "secondbucket"})
assert "ID" in first_rule
assert first_rule["Priority"] == 1
assert first_rule["Status"] == "Enabled"
assert first_rule["Destination"] == {"Bucket": "secondbucket"}
second = rules[1]
second.should.have.key("ID").equal("secondrule")
second.should.have.key("Priority").equal(2)
second.should.have.key("Status").equal("Disabled")
second.should.have.key("Destination").equal({"Bucket": "thirdbucket"})
assert second["ID"] == "secondrule"
assert second["Priority"] == 2
assert second["Status"] == "Disabled"
assert second["Destination"] == {"Bucket": "thirdbucket"}

View File

@ -1,10 +1,12 @@
import boto3
import json
import pytest
from moto import mock_s3
from unittest import TestCase
from uuid import uuid4
import boto3
import pytest
from moto import mock_s3
SIMPLE_JSON = {"a1": "b1", "a2": "b2", "a3": None}
SIMPLE_JSON2 = {"a1": "b2", "a3": "b3"}
@ -53,7 +55,7 @@ class TestS3Select(TestCase):
self.client.delete_bucket(Bucket=self.bucket_name)
def test_query_all(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="simple.json",
Expression="SELECT * FROM S3Object",
@ -61,30 +63,26 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result.should.contain(
{"Records": {"Payload": b'{"a1":"b1","a2":"b2","a3":null},'}}
)
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"a1":"b1","a2":"b2","a3":null},'}} in result
# Verify result is valid JSON
json.loads(result[0]["Records"]["Payload"][0:-1].decode("utf-8"))
# Verify result contains metadata
result.should.contain(
{
"Stats": {
"Details": {
"BytesScanned": 24,
"BytesProcessed": 24,
"BytesReturned": 22,
}
assert {
"Stats": {
"Details": {
"BytesScanned": 24,
"BytesProcessed": 24,
"BytesReturned": 22,
}
}
)
result.should.contain({"End": {}})
} in result
assert {"End": {}} in result
def test_count_function(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="simple.json",
Expression="SELECT count(*) FROM S3Object",
@ -92,12 +90,12 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result.should.contain({"Records": {"Payload": b'{"_1":1},'}})
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"_1":1},'}} in result
@pytest.mark.xfail(message="Not yet implement in our parser")
def test_count_as(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="simple.json",
Expression="SELECT count(*) as cnt FROM S3Object",
@ -105,12 +103,12 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result.should.contain({"Records": {"Payload": b'{"cnt":1},'}})
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"cnt":1},'}} in result
@pytest.mark.xfail(message="Not yet implement in our parser")
def test_count_list_as(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="list.json",
Expression="SELECT count(*) as cnt FROM S3Object",
@ -118,11 +116,11 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result.should.contain({"Records": {"Payload": b'{"cnt":1},'}})
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"cnt":1},'}} in result
def test_count_csv(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="simple_csv",
Expression="SELECT count(*) FROM S3Object",
@ -132,11 +130,11 @@ class TestS3Select(TestCase):
},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result.should.contain({"Records": {"Payload": b'{"_1":3},'}})
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"_1":3},'}} in result
def test_extensive_json__select_list(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="extensive.json",
Expression="select * from s3object[*].staff[*] s",
@ -144,11 +142,11 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result = list(content["Payload"])
assert {"Records": {"Payload": b"{},"}} in result
def test_extensive_json__select_all(self):
x = self.client.select_object_content(
content = self.client.select_object_content(
Bucket=self.bucket_name,
Key="extensive.json",
Expression="select * from s3object s",
@ -156,7 +154,7 @@ class TestS3Select(TestCase):
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(x["Payload"])
result = list(content["Payload"])
assert {
"Records": {
"Payload": b'{"_1":[{"staff":[{"name":"Janelyn M","city":"Chicago","kids":2},{"name":"Stacy P","city":"Seattle","kids":1}],"country":"USA"}]},'

View File

@ -1,6 +1,4 @@
import boto3
import sure # noqa # pylint: disable=unused-import
from botocore.exceptions import ClientError
import pytest
@ -9,93 +7,93 @@ from moto import mock_s3
@mock_s3
def test_s3_storage_class_standard():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="Bucket")
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket="Bucket")
# add an object to the bucket with standard storage
s3.put_object(Bucket="Bucket", Key="my_key", Body="my_value")
s3_client.put_object(Bucket="Bucket", Key="my_key", Body="my_value")
list_of_objects = s3.list_objects(Bucket="Bucket")
list_of_objects = s3_client.list_objects(Bucket="Bucket")
list_of_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
assert list_of_objects["Contents"][0]["StorageClass"] == "STANDARD"
@mock_s3
def test_s3_storage_class_infrequent_access():
s3 = boto3.client("s3")
s3.create_bucket(
s3_client = boto3.client("s3")
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-2"}
)
# add an object to the bucket with standard storage
s3.put_object(
s3_client.put_object(
Bucket="Bucket",
Key="my_key_infrequent",
Body="my_value_infrequent",
StorageClass="STANDARD_IA",
)
D = s3.list_objects(Bucket="Bucket")
objs = s3_client.list_objects(Bucket="Bucket")
D["Contents"][0]["StorageClass"].should.equal("STANDARD_IA")
assert objs["Contents"][0]["StorageClass"] == "STANDARD_IA"
@mock_s3
def test_s3_storage_class_intelligent_tiering():
s3 = boto3.client("s3")
s3_client = boto3.client("s3")
s3.create_bucket(
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-east-2"}
)
s3.put_object(
s3_client.put_object(
Bucket="Bucket",
Key="my_key_infrequent",
Body="my_value_infrequent",
StorageClass="INTELLIGENT_TIERING",
)
objects = s3.list_objects(Bucket="Bucket")
objects = s3_client.list_objects(Bucket="Bucket")
objects["Contents"][0]["StorageClass"].should.equal("INTELLIGENT_TIERING")
assert objects["Contents"][0]["StorageClass"] == "INTELLIGENT_TIERING"
@mock_s3
def test_s3_storage_class_copy():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="Bucket")
s3.put_object(
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket="Bucket")
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD"
)
s3.create_bucket(Bucket="Bucket2")
s3_client.create_bucket(Bucket="Bucket2")
# second object is originally of storage class REDUCED_REDUNDANCY
s3.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2")
s3_client.put_object(Bucket="Bucket2", Key="Second_Object", Body="Body2")
s3.copy_object(
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket2",
Key="Second_Object",
StorageClass="ONEZONE_IA",
)
list_of_copied_objects = s3.list_objects(Bucket="Bucket2")
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
# checks that a copied object can be properly copied
list_of_copied_objects["Contents"][0]["StorageClass"].should.equal("ONEZONE_IA")
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "ONEZONE_IA"
@mock_s3
def test_s3_invalid_copied_storage_class():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="Bucket")
s3.put_object(
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket="Bucket")
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARD"
)
s3.create_bucket(Bucket="Bucket2")
s3.put_object(
s3_client.create_bucket(Bucket="Bucket2")
s3_client.put_object(
Bucket="Bucket2",
Key="Second_Object",
Body="Body2",
@ -104,175 +102,179 @@ def test_s3_invalid_copied_storage_class():
# Try to copy an object with an invalid storage class
with pytest.raises(ClientError) as err:
s3.copy_object(
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket2",
Key="Second_Object",
StorageClass="STANDARD2",
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
e.response["Error"]["Message"].should.equal(
err_value = err.value
assert err_value.response["Error"]["Code"] == "InvalidStorageClass"
assert err_value.response["Error"]["Message"] == (
"The storage class you specified is not valid"
)
@mock_s3
def test_s3_invalid_storage_class():
s3 = boto3.client("s3")
s3.create_bucket(
s3_client = boto3.client("s3")
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
# Try to add an object with an invalid storage class
with pytest.raises(ClientError) as err:
s3.put_object(
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="STANDARDD"
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidStorageClass")
e.response["Error"]["Message"].should.equal(
err_value = err.value
assert err_value.response["Error"]["Code"] == "InvalidStorageClass"
assert err_value.response["Error"]["Message"] == (
"The storage class you specified is not valid"
)
@mock_s3
def test_s3_default_storage_class():
s3 = boto3.client("s3")
s3.create_bucket(
s3_client = boto3.client("s3")
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
s3.put_object(Bucket="Bucket", Key="First_Object", Body="Body")
s3_client.put_object(Bucket="Bucket", Key="First_Object", Body="Body")
list_of_objects = s3.list_objects(Bucket="Bucket")
list_of_objects = s3_client.list_objects(Bucket="Bucket")
# tests that the default storage class is still STANDARD
list_of_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
assert list_of_objects["Contents"][0]["StorageClass"] == "STANDARD"
@mock_s3
def test_s3_copy_object_error_for_glacier_storage_class_not_restored():
s3 = boto3.client("s3")
s3.create_bucket(
s3_client = boto3.client("s3")
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
s3.put_object(
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="GLACIER"
)
with pytest.raises(ClientError) as ex:
s3.copy_object(
with pytest.raises(ClientError) as exc:
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket",
Key="Second_Object",
)
ex.value.response["Error"]["Code"].should.equal("ObjectNotInActiveTierError")
assert exc.value.response["Error"]["Code"] == "ObjectNotInActiveTierError"
@mock_s3
def test_s3_copy_object_error_for_deep_archive_storage_class_not_restored():
s3 = boto3.client("s3")
s3.create_bucket(
s3_client = boto3.client("s3")
s3_client.create_bucket(
Bucket="Bucket", CreateBucketConfiguration={"LocationConstraint": "us-west-1"}
)
s3.put_object(
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="DEEP_ARCHIVE"
)
with pytest.raises(ClientError) as exc:
s3.copy_object(
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket",
Key="Second_Object",
)
exc.value.response["Error"]["Code"].should.equal("ObjectNotInActiveTierError")
assert exc.value.response["Error"]["Code"] == "ObjectNotInActiveTierError"
@mock_s3
def test_s3_copy_object_for_glacier_storage_class_restored():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="Bucket")
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket="Bucket")
s3.put_object(
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="GLACIER"
)
s3.create_bucket(Bucket="Bucket2")
s3.restore_object(Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123})
s3_client.create_bucket(Bucket="Bucket2")
s3_client.restore_object(
Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123}
)
s3.copy_object(
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket2",
Key="Second_Object",
)
list_of_copied_objects = s3.list_objects(Bucket="Bucket2")
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
# checks that copy of restored Glacier object has STANDARD storage class
list_of_copied_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "STANDARD"
# checks that metadata of copy has no Restore property
s3.head_object(Bucket="Bucket2", Key="Second_Object").should.not_have.property(
"Restore"
assert not hasattr(
s3_client.head_object(Bucket="Bucket2", Key="Second_Object"), "Restore"
)
@mock_s3
def test_s3_copy_object_for_deep_archive_storage_class_restored():
s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="Bucket")
s3_client = boto3.client("s3", region_name="us-east-1")
s3_client.create_bucket(Bucket="Bucket")
s3.put_object(
s3_client.put_object(
Bucket="Bucket", Key="First_Object", Body="Body", StorageClass="DEEP_ARCHIVE"
)
with pytest.raises(ClientError) as exc:
s3.get_object(Bucket="Bucket", Key="First_Object")
s3_client.get_object(Bucket="Bucket", Key="First_Object")
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidObjectState")
err["Message"].should.equal(
assert err["Code"] == "InvalidObjectState"
assert err["Message"] == (
"The operation is not valid for the object's storage class"
)
err["StorageClass"].should.equal("DEEP_ARCHIVE")
assert err["StorageClass"] == "DEEP_ARCHIVE"
s3.create_bucket(Bucket="Bucket2")
s3.restore_object(Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123})
s3.get_object(Bucket="Bucket", Key="First_Object")
s3_client.create_bucket(Bucket="Bucket2")
s3_client.restore_object(
Bucket="Bucket", Key="First_Object", RestoreRequest={"Days": 123}
)
s3_client.get_object(Bucket="Bucket", Key="First_Object")
s3.copy_object(
s3_client.copy_object(
CopySource={"Bucket": "Bucket", "Key": "First_Object"},
Bucket="Bucket2",
Key="Second_Object",
)
list_of_copied_objects = s3.list_objects(Bucket="Bucket2")
list_of_copied_objects = s3_client.list_objects(Bucket="Bucket2")
# checks that copy of restored Glacier object has STANDARD storage class
list_of_copied_objects["Contents"][0]["StorageClass"].should.equal("STANDARD")
assert list_of_copied_objects["Contents"][0]["StorageClass"] == "STANDARD"
# checks that metadata of copy has no Restore property
s3.head_object(Bucket="Bucket2", Key="Second_Object").should.not_have.property(
"Restore"
assert not hasattr(
s3_client.head_object(Bucket="Bucket2", Key="Second_Object"), "Restore"
)
@mock_s3
def test_s3_get_object_from_glacier():
s3 = boto3.client("s3", region_name="us-east-1")
s3_client = boto3.client("s3", region_name="us-east-1")
bucket_name = "tests3getobjectfromglacier"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3.put_object(
s3_client.put_object(
Bucket=bucket_name, Key="test.txt", Body="contents", StorageClass="GLACIER"
)
with pytest.raises(ClientError) as exc:
s3.get_object(Bucket=bucket_name, Key="test.txt")
s3_client.get_object(Bucket=bucket_name, Key="test.txt")
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidObjectState")
err["Message"].should.equal(
assert err["Code"] == "InvalidObjectState"
assert err["Message"] == (
"The operation is not valid for the object's storage class"
)
err["StorageClass"].should.equal("GLACIER")
assert err["StorageClass"] == "GLACIER"

View File

@ -1,13 +1,10 @@
import boto3
import requests
import pytest
import sure # noqa # pylint: disable=unused-import
from botocore.client import ClientError
from moto.s3.responses import DEFAULT_REGION_NAME
import pytest
import requests
from moto import mock_s3
from moto.s3.responses import DEFAULT_REGION_NAME
@mock_s3
@ -16,54 +13,56 @@ def test_get_bucket_tagging_unknown_bucket():
with pytest.raises(ClientError) as ex:
client.get_bucket_tagging(Bucket="foobar")
ex.value.response["Error"]["Code"].should.equal("NoSuchBucket")
ex.value.response["Error"]["Message"].should.equal(
assert ex.value.response["Error"]["Code"] == "NoSuchBucket"
assert ex.value.response["Error"]["Message"] == (
"The specified bucket does not exist"
)
@mock_s3
def test_put_object_with_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
# using system tags will fail
with pytest.raises(ClientError) as err:
s3.put_object(Bucket=bucket_name, Key=key, Body="test", Tagging="aws:foo=bar")
s3_client.put_object(
Bucket=bucket_name, Key=key, Body="test", Tagging="aws:foo=bar"
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidTag")
err_value = err.value
assert err_value.response["Error"]["Code"] == "InvalidTag"
s3.put_object(Bucket=bucket_name, Key=key, Body="test", Tagging="foo=bar")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test", Tagging="foo=bar")
s3.get_object_tagging(Bucket=bucket_name, Key=key)["TagSet"].should.contain(
{"Key": "foo", "Value": "bar"}
)
assert {"Key": "foo", "Value": "bar"} in s3_client.get_object_tagging(
Bucket=bucket_name, Key=key
)["TagSet"]
resp = s3.get_object(Bucket=bucket_name, Key=key)
resp.should.have.key("TagCount").equals(1)
resp = s3_client.get_object(Bucket=bucket_name, Key=key)
assert resp["TagCount"] == 1
s3.delete_object_tagging(Bucket=bucket_name, Key=key)
s3_client.delete_object_tagging(Bucket=bucket_name, Key=key)
s3.get_object_tagging(Bucket=bucket_name, Key=key)["TagSet"].should.equal([])
assert s3_client.get_object_tagging(Bucket=bucket_name, Key=key)["TagSet"] == []
@mock_s3
def test_put_bucket_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
# With 1 tag:
resp = s3.put_bucket_tagging(
resp = s3_client.put_bucket_tagging(
Bucket=bucket_name, Tagging={"TagSet": [{"Key": "TagOne", "Value": "ValueOne"}]}
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
# With multiple tags:
resp = s3.put_bucket_tagging(
resp = s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={
"TagSet": [
@ -74,15 +73,15 @@ def test_put_bucket_tagging():
},
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
# No tags is also OK:
resp = s3.put_bucket_tagging(Bucket=bucket_name, Tagging={"TagSet": []})
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
resp = s3_client.put_bucket_tagging(Bucket=bucket_name, Tagging={"TagSet": []})
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
# With duplicate tag keys:
with pytest.raises(ClientError) as err:
s3.put_bucket_tagging(
s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={
"TagSet": [
@ -91,26 +90,26 @@ def test_put_bucket_tagging():
]
},
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidTag")
e.response["Error"]["Message"].should.equal(
err_value = err.value
assert err_value.response["Error"]["Code"] == "InvalidTag"
assert err_value.response["Error"]["Message"] == (
"Cannot provide multiple Tags with the same key"
)
# Cannot put tags that are "system" tags - i.e. tags that start with "aws:"
with pytest.raises(ClientError) as ce:
s3.put_bucket_tagging(
with pytest.raises(ClientError) as ce_exc:
s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={"TagSet": [{"Key": "aws:sometag", "Value": "nope"}]},
)
e = ce.value
e.response["Error"]["Code"].should.equal("InvalidTag")
e.response["Error"]["Message"].should.equal(
err_value = ce_exc.value
assert err_value.response["Error"]["Code"] == "InvalidTag"
assert err_value.response["Error"]["Message"] == (
"System tags cannot be added/updated by requester"
)
# This is OK though:
s3.put_bucket_tagging(
s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={"TagSet": [{"Key": "something:aws:stuff", "Value": "this is fine"}]},
)
@ -118,10 +117,10 @@ def test_put_bucket_tagging():
@mock_s3
def test_get_bucket_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
s3.create_bucket(Bucket=bucket_name)
s3.put_bucket_tagging(
s3_client.create_bucket(Bucket=bucket_name)
s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={
"TagSet": [
@ -132,28 +131,28 @@ def test_get_bucket_tagging():
)
# Get the tags for the bucket:
resp = s3.get_bucket_tagging(Bucket=bucket_name)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
len(resp["TagSet"]).should.equal(2)
resp = s3_client.get_bucket_tagging(Bucket=bucket_name)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
assert len(resp["TagSet"]) == 2
# With no tags:
s3.put_bucket_tagging(Bucket=bucket_name, Tagging={"TagSet": []})
s3_client.put_bucket_tagging(Bucket=bucket_name, Tagging={"TagSet": []})
with pytest.raises(ClientError) as err:
s3.get_bucket_tagging(Bucket=bucket_name)
s3_client.get_bucket_tagging(Bucket=bucket_name)
e = err.value
e.response["Error"]["Code"].should.equal("NoSuchTagSet")
e.response["Error"]["Message"].should.equal("The TagSet does not exist")
err_value = err.value
assert err_value.response["Error"]["Code"] == "NoSuchTagSet"
assert err_value.response["Error"]["Message"] == "The TagSet does not exist"
@mock_s3
def test_delete_bucket_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3.put_bucket_tagging(
s3_client.put_bucket_tagging(
Bucket=bucket_name,
Tagging={
"TagSet": [
@ -163,26 +162,26 @@ def test_delete_bucket_tagging():
},
)
resp = s3.delete_bucket_tagging(Bucket=bucket_name)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(204)
resp = s3_client.delete_bucket_tagging(Bucket=bucket_name)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 204
with pytest.raises(ClientError) as err:
s3.get_bucket_tagging(Bucket=bucket_name)
s3_client.get_bucket_tagging(Bucket=bucket_name)
e = err.value
e.response["Error"]["Code"].should.equal("NoSuchTagSet")
e.response["Error"]["Message"].should.equal("The TagSet does not exist")
err_value = err.value
assert err_value.response["Error"]["Code"] == "NoSuchTagSet"
assert err_value.response["Error"]["Message"] == "The TagSet does not exist"
@mock_s3
def test_put_object_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
with pytest.raises(ClientError) as err:
s3.put_object_tagging(
s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -193,30 +192,28 @@ def test_put_object_tagging():
},
)
e = err.value
e.response["Error"].should.equal(
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)
err_value = err.value
assert err_value.response["Error"] == {
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
s3.put_object(Bucket=bucket_name, Key=key, Body="test")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test")
# using system tags will fail
with pytest.raises(ClientError) as err:
s3.put_object_tagging(
s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={"TagSet": [{"Key": "aws:item1", "Value": "foo"}]},
)
e = err.value
e.response["Error"]["Code"].should.equal("InvalidTag")
err_value = err.value
assert err_value.response["Error"]["Code"] == "InvalidTag"
resp = s3.put_object_tagging(
resp = s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -228,22 +225,22 @@ def test_put_object_tagging():
},
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
@mock_s3
def test_put_object_tagging_on_earliest_version():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3_resource = boto3.resource("s3")
bucket_versioning = s3_resource.BucketVersioning(bucket_name)
bucket_versioning.enable()
bucket_versioning.status.should.equal("Enabled")
assert bucket_versioning.status == "Enabled"
with pytest.raises(ClientError) as err:
s3.put_object_tagging(
s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -254,24 +251,22 @@ def test_put_object_tagging_on_earliest_version():
},
)
e = err.value
e.response["Error"].should.equal(
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)
err_value = err.value
assert err_value.response["Error"] == {
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
s3.put_object(Bucket=bucket_name, Key=key, Body="test")
s3.put_object(Bucket=bucket_name, Key=key, Body="test_updated")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test_updated")
object_versions = list(s3_resource.Bucket(bucket_name).object_versions.all())
first_object = object_versions[0]
second_object = object_versions[1]
resp = s3.put_object_tagging(
resp = s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -283,38 +278,41 @@ def test_put_object_tagging_on_earliest_version():
VersionId=first_object.id,
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
# Older version has tags while the most recent does not
resp = s3.get_object_tagging(Bucket=bucket_name, Key=key, VersionId=first_object.id)
resp["VersionId"].should.equal(first_object.id)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
sorted_tagset = sorted(resp["TagSet"], key=lambda t: t["Key"])
sorted_tagset.should.equal(
[{"Key": "item1", "Value": "foo"}, {"Key": "item2", "Value": "bar"}]
resp = s3_client.get_object_tagging(
Bucket=bucket_name, Key=key, VersionId=first_object.id
)
assert resp["VersionId"] == first_object.id
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
sorted_tagset = sorted(resp["TagSet"], key=lambda t: t["Key"])
assert sorted_tagset == [
{"Key": "item1", "Value": "foo"},
{"Key": "item2", "Value": "bar"},
]
resp = s3.get_object_tagging(
resp = s3_client.get_object_tagging(
Bucket=bucket_name, Key=key, VersionId=second_object.id
)
resp["VersionId"].should.equal(second_object.id)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
resp["TagSet"].should.equal([])
assert resp["VersionId"] == second_object.id
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
assert resp["TagSet"] == []
@mock_s3
def test_put_object_tagging_on_both_version():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3_resource = boto3.resource("s3")
bucket_versioning = s3_resource.BucketVersioning(bucket_name)
bucket_versioning.enable()
bucket_versioning.status.should.equal("Enabled")
assert bucket_versioning.status == "Enabled"
with pytest.raises(ClientError) as err:
s3.put_object_tagging(
s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -325,24 +323,22 @@ def test_put_object_tagging_on_both_version():
},
)
e = err.value
e.response["Error"].should.equal(
{
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
)
err_value = err.value
assert err_value.response["Error"] == {
"Code": "NoSuchKey",
"Message": "The specified key does not exist.",
"Key": "key-with-tags",
"RequestID": "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE",
}
s3.put_object(Bucket=bucket_name, Key=key, Body="test")
s3.put_object(Bucket=bucket_name, Key=key, Body="test_updated")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test_updated")
object_versions = list(s3_resource.Bucket(bucket_name).object_versions.all())
first_object = object_versions[0]
second_object = object_versions[1]
resp = s3.put_object_tagging(
resp = s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -353,9 +349,9 @@ def test_put_object_tagging_on_both_version():
},
VersionId=first_object.id,
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
resp = s3.put_object_tagging(
resp = s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -366,56 +362,60 @@ def test_put_object_tagging_on_both_version():
},
VersionId=second_object.id,
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
resp = s3.get_object_tagging(Bucket=bucket_name, Key=key, VersionId=first_object.id)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
sorted_tagset = sorted(resp["TagSet"], key=lambda t: t["Key"])
sorted_tagset.should.equal(
[{"Key": "item1", "Value": "foo"}, {"Key": "item2", "Value": "bar"}]
resp = s3_client.get_object_tagging(
Bucket=bucket_name, Key=key, VersionId=first_object.id
)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
sorted_tagset = sorted(resp["TagSet"], key=lambda t: t["Key"])
assert sorted_tagset == [
{"Key": "item1", "Value": "foo"},
{"Key": "item2", "Value": "bar"},
]
resp = s3.get_object_tagging(
resp = s3_client.get_object_tagging(
Bucket=bucket_name, Key=key, VersionId=second_object.id
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
sorted_tagset = sorted(resp["TagSet"], key=lambda t: t["Key"])
sorted_tagset.should.equal(
[{"Key": "item1", "Value": "baz"}, {"Key": "item2", "Value": "bin"}]
)
assert sorted_tagset == [
{"Key": "item1", "Value": "baz"},
{"Key": "item2", "Value": "bin"},
]
@mock_s3
def test_put_object_tagging_with_single_tag():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3.put_object(Bucket=bucket_name, Key=key, Body="test")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test")
resp = s3.put_object_tagging(
resp = s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={"TagSet": [{"Key": "item1", "Value": "foo"}]},
)
resp["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
@mock_s3
def test_get_object_tagging():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket_name = "mybucket"
key = "key-with-tags"
s3.create_bucket(Bucket=bucket_name)
s3_client.create_bucket(Bucket=bucket_name)
s3.put_object(Bucket=bucket_name, Key=key, Body="test")
s3_client.put_object(Bucket=bucket_name, Key=key, Body="test")
resp = s3.get_object_tagging(Bucket=bucket_name, Key=key)
resp["TagSet"].should.have.length_of(0)
resp = s3_client.get_object_tagging(Bucket=bucket_name, Key=key)
assert not resp["TagSet"]
s3.put_object_tagging(
s3_client.put_object_tagging(
Bucket=bucket_name,
Key=key,
Tagging={
@ -425,34 +425,34 @@ def test_get_object_tagging():
]
},
)
resp = s3.get_object_tagging(Bucket=bucket_name, Key=key)
resp = s3_client.get_object_tagging(Bucket=bucket_name, Key=key)
resp["TagSet"].should.have.length_of(2)
resp["TagSet"].should.contain({"Key": "item1", "Value": "foo"})
resp["TagSet"].should.contain({"Key": "item2", "Value": "bar"})
assert len(resp["TagSet"]) == 2
assert {"Key": "item1", "Value": "foo"} in resp["TagSet"]
assert {"Key": "item2", "Value": "bar"} in resp["TagSet"]
@mock_s3
def test_objects_tagging_with_same_key_name():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3_client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
key_name = "file.txt"
bucket1 = "bucket-1"
s3.create_bucket(Bucket=bucket1)
s3_client.create_bucket(Bucket=bucket1)
tagging = "variable=one"
s3.put_object(Bucket=bucket1, Body=b"test", Key=key_name, Tagging=tagging)
s3_client.put_object(Bucket=bucket1, Body=b"test", Key=key_name, Tagging=tagging)
bucket2 = "bucket-2"
s3.create_bucket(Bucket=bucket2)
s3_client.create_bucket(Bucket=bucket2)
tagging2 = "variable=two"
s3.put_object(Bucket=bucket2, Body=b"test", Key=key_name, Tagging=tagging2)
s3_client.put_object(Bucket=bucket2, Body=b"test", Key=key_name, Tagging=tagging2)
variable1 = s3.get_object_tagging(Bucket=bucket1, Key=key_name)["TagSet"][0][
variable1 = s3_client.get_object_tagging(Bucket=bucket1, Key=key_name)["TagSet"][0][
"Value"
]
variable2 = s3.get_object_tagging(Bucket=bucket2, Key=key_name)["TagSet"][0][
variable2 = s3_client.get_object_tagging(Bucket=bucket2, Key=key_name)["TagSet"][0][
"Value"
]
@ -462,14 +462,14 @@ def test_objects_tagging_with_same_key_name():
@mock_s3
def test_generate_url_for_tagged_object():
s3 = boto3.client("s3")
s3.create_bucket(Bucket="my-bucket")
s3.put_object(
s3_client = boto3.client("s3")
s3_client.create_bucket(Bucket="my-bucket")
s3_client.put_object(
Bucket="my-bucket", Key="test.txt", Body=b"abc", Tagging="MyTag=value"
)
url = s3.generate_presigned_url(
url = s3_client.generate_presigned_url(
"get_object", Params={"Bucket": "my-bucket", "Key": "test.txt"}
)
response = requests.get(url)
response.content.should.equal(b"abc")
response.headers["x-amz-tagging-count"].should.equal("1")
assert response.content == b"abc"
assert response.headers["x-amz-tagging-count"] == "1"

View File

@ -1,5 +1,6 @@
from unittest.mock import patch
import pytest
from sure import expect
from moto.s3.utils import (
bucket_name_from_url,
_VersionedKeyStore,
@ -9,66 +10,63 @@ from moto.s3.utils import (
compute_checksum,
cors_matches_origin,
)
from unittest.mock import patch
def test_base_url():
expect(bucket_name_from_url("https://s3.amazonaws.com/")).should.equal(None)
assert bucket_name_from_url("https://s3.amazonaws.com/") is None
def test_localhost_bucket():
expect(bucket_name_from_url("https://wfoobar.localhost:5000/abc")).should.equal(
"wfoobar"
)
assert bucket_name_from_url("https://wfoobar.localhost:5000/abc") == "wfoobar"
def test_localhost_without_bucket():
expect(bucket_name_from_url("https://www.localhost:5000/def")).should.equal(None)
assert bucket_name_from_url("https://www.localhost:5000/def") is None
def test_force_ignore_subdomain_for_bucketnames():
with patch("moto.s3.utils.S3_IGNORE_SUBDOMAIN_BUCKETNAME", True):
expect(
assert (
bucket_name_from_url("https://subdomain.localhost:5000/abc/resource")
).should.equal(None)
is None
)
def test_versioned_key_store():
d = _VersionedKeyStore()
key_store = _VersionedKeyStore()
d.should.have.length_of(0)
assert not key_store
d["key"] = [1]
key_store["key"] = [1]
assert len(key_store) == 1
d.should.have.length_of(1)
key_store["key"] = 2
assert len(key_store) == 1
d["key"] = 2
d.should.have.length_of(1)
d.should.have.key("key").being.equal(2)
d.get.when.called_with("key").should.return_value(2)
d.get.when.called_with("badkey").should.return_value(None)
d.get.when.called_with("badkey", "HELLO").should.return_value("HELLO")
assert key_store["key"] == 2
assert key_store.get("key") == 2
assert key_store.get("badkey") is None
assert key_store.get("badkey", "HELLO") == "HELLO"
# Tests key[
d.shouldnt.have.key("badkey")
d.__getitem__.when.called_with("badkey").should.throw(KeyError)
assert "badkey" not in key_store
with pytest.raises(KeyError):
_ = key_store["badkey"]
d.getlist("key").should.have.length_of(2)
d.getlist("key").should.be.equal([[1], 2])
d.getlist("badkey").should.be.none
assert len(key_store.getlist("key")) == 2
assert key_store.getlist("key") == [[1], 2]
assert key_store.getlist("badkey") is None
d.setlist("key", 1)
d.getlist("key").should.be.equal([1])
key_store.setlist("key", 1)
assert key_store.getlist("key") == [1]
d.setlist("key", (1, 2))
d.getlist("key").shouldnt.be.equal((1, 2))
d.getlist("key").should.be.equal([1, 2])
key_store.setlist("key", (1, 2))
assert key_store.getlist("key") != (1, 2)
assert key_store.getlist("key") == [1, 2]
d.setlist("key", [[1], [2]])
d["key"].should.have.length_of(1)
d.getlist("key").should.be.equal([[1], [2]])
key_store.setlist("key", [[1], [2]])
assert len(key_store["key"]) == 1
assert key_store.getlist("key") == [[1], [2]]
def test_parse_region_from_url():
@ -81,7 +79,7 @@ def test_parse_region_from_url():
"https://s3.us-west-2.amazonaws.com/bucket",
"https://bucket.s3-us-west-2.amazonaws.com",
]:
parse_region_from_url(url).should.equal(expected)
assert parse_region_from_url(url) == expected
expected = "us-east-1"
for url in [
@ -90,7 +88,7 @@ def test_parse_region_from_url():
"https://s3.amazonaws.com/bucket",
"https://bucket.s3.amazonaws.com",
]:
parse_region_from_url(url).should.equal(expected)
assert parse_region_from_url(url) == expected
@pytest.mark.parametrize(
@ -105,7 +103,7 @@ def test_parse_region_from_url():
],
)
def test_clean_key_name(key, expected):
clean_key_name(key).should.equal(expected)
assert clean_key_name(key) == expected
@pytest.mark.parametrize(
@ -120,32 +118,32 @@ def test_clean_key_name(key, expected):
],
)
def test_undo_clean_key_name(key, expected):
undo_clean_key_name(key).should.equal(expected)
assert undo_clean_key_name(key) == expected
def test_checksum_sha256():
checksum = b"h9FJy0JMA4dlbyEdJYn7Wx4WIpkhMJ6YWIQZzMqKc2I="
compute_checksum(b"somedata", "SHA256").should.equal(checksum)
assert compute_checksum(b"somedata", "SHA256") == checksum
# Unknown algorithms fallback to SHA256 for now
compute_checksum(b"somedata", algorithm="unknown").should.equal(checksum)
assert compute_checksum(b"somedata", algorithm="unknown") == checksum
def test_checksum_sha1():
compute_checksum(b"somedata", "SHA1").should.equal(b"76oxGuRIpzdMEiBhv+2VLZQOnjc=")
assert compute_checksum(b"somedata", "SHA1") == b"76oxGuRIpzdMEiBhv+2VLZQOnjc="
def test_checksum_crc32():
compute_checksum(b"somedata", "CRC32").should.equal(b"Uwy90A==")
assert compute_checksum(b"somedata", "CRC32") == b"Uwy90A=="
def test_checksum_crc32c():
try:
import crc32c # noqa # pylint: disable=unused-import
compute_checksum(b"somedata", "CRC32C").should.equal(b"dB9qBQ==")
assert compute_checksum(b"somedata", "CRC32C") == b"dB9qBQ=="
except: # noqa: E722 Do not use bare except
# Optional library Can't be found - just revert to CRC32
compute_checksum(b"somedata", "CRC32C").should.equal(b"Uwy90A==")
assert compute_checksum(b"somedata", "CRC32C") == b"Uwy90A=="
def test_cors_utils():

View File

@ -1,18 +1,15 @@
"""Test different server responses."""
import io
from unittest.mock import patch
from urllib.parse import urlparse, parse_qs
import sure # noqa # pylint: disable=unused-import
import requests
import pytest
import xmltodict
from flask.testing import FlaskClient
import pytest
import requests
import moto.server as server
from moto.moto_server.threaded_moto_server import ThreadedMotoServer
from unittest.mock import patch
"""
Test the different server responses
"""
class AuthenticatedClient(FlaskClient):
@ -33,7 +30,7 @@ def test_s3_server_get():
test_client = authenticated_client()
res = test_client.get("/")
res.data.should.contain(b"ListAllMyBucketsResult")
assert b"ListAllMyBucketsResult" in res.data
@pytest.mark.parametrize("key_name", ["bar_baz", "bar+baz", "baz bar"])
@ -41,31 +38,31 @@ def test_s3_server_bucket_create(key_name):
test_client = authenticated_client()
res = test_client.put("/", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
assert res.status_code == 200
res = test_client.get("/")
res.data.should.contain(b"<Name>foobaz</Name>")
assert b"<Name>foobaz</Name>" in res.data
res = test_client.get("/", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
res.data.should.contain(b"ListBucketResult")
assert res.status_code == 200
assert b"ListBucketResult" in res.data
res = test_client.put(
f"/{key_name}", "http://foobaz.localhost:5000/", data="test value"
)
res.status_code.should.equal(200)
assert res.status_code == 200
assert "ETag" in dict(res.headers)
# ListBuckets
res = test_client.get(
"/", "http://foobaz.localhost:5000/", query_string={"prefix": key_name}
)
res.status_code.should.equal(200)
assert res.status_code == 200
content = xmltodict.parse(res.data)["ListBucketResult"]["Contents"]
# If we receive a dict, we only received one result
# If content is of type list, our call returned multiple results - which is not correct
content.should.be.a(dict)
content["Key"].should.equal(key_name)
assert isinstance(content, dict)
assert content["Key"] == key_name
# GetBucket
res = test_client.head("http://foobaz.localhost:5000")
@ -74,13 +71,13 @@ def test_s3_server_bucket_create(key_name):
# HeadObject
res = test_client.head(f"/{key_name}", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
assert res.status_code == 200
assert res.headers.get("Accept-Ranges") == "bytes"
# GetObject
res = test_client.get(f"/{key_name}", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
res.data.should.equal(b"test value")
assert res.status_code == 200
assert res.data == b"test value"
assert res.headers.get("Accept-Ranges") == "bytes"
@ -89,27 +86,27 @@ def test_s3_server_ignore_subdomain_for_bucketnames():
test_client = authenticated_client()
res = test_client.put("/mybucket", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
res.data.should.contain(b"mybucket")
assert res.status_code == 200
assert b"mybucket" in res.data
def test_s3_server_bucket_versioning():
test_client = authenticated_client()
res = test_client.put("/", "http://foobaz.localhost:5000/")
res.status_code.should.equal(200)
assert res.status_code == 200
# Just enough XML to enable versioning
body = "<Status>Enabled</Status>"
res = test_client.put("/?versioning", "http://foobaz.localhost:5000", data=body)
res.status_code.should.equal(200)
assert res.status_code == 200
def test_s3_server_post_to_bucket():
test_client = authenticated_client()
res = test_client.put("/", "http://tester.localhost:5000/")
res.status_code.should.equal(200)
assert res.status_code == 200
test_client.post(
"/",
@ -118,15 +115,15 @@ def test_s3_server_post_to_bucket():
)
res = test_client.get("/the-key", "http://tester.localhost:5000/")
res.status_code.should.equal(200)
res.data.should.equal(b"nothing")
assert res.status_code == 200
assert res.data == b"nothing"
def test_s3_server_post_to_bucket_redirect():
test_client = authenticated_client()
res = test_client.put("/", "http://tester.localhost:5000/")
res.status_code.should.equal(200)
assert res.status_code == 200
redirect_base = "https://redirect.com/success/"
filecontent = "nothing"
@ -141,7 +138,7 @@ def test_s3_server_post_to_bucket_redirect():
},
)
real_key = f"asdf/the-key/{filename}"
res.status_code.should.equal(303)
assert res.status_code == 303
redirect = res.headers["location"]
assert redirect.startswith(redirect_base)
@ -151,8 +148,8 @@ def test_s3_server_post_to_bucket_redirect():
assert args["bucket"][0] == "tester"
res = test_client.get(f"/{real_key}", "http://tester.localhost:5000/")
res.status_code.should.equal(200)
res.data.should.equal(filecontent.encode("utf8"))
assert res.status_code == 200
assert res.data == filecontent.encode("utf8")
def test_s3_server_post_without_content_length():
@ -162,7 +159,7 @@ def test_s3_server_post_without_content_length():
res = test_client.put(
"/", "http://tester.localhost:5000/", environ_overrides={"CONTENT_LENGTH": ""}
)
res.status_code.should.equal(200)
assert res.status_code == 200
# You can specify a bucket in another region without specifying Content-Length
# (The body is just ignored..)
@ -170,26 +167,30 @@ def test_s3_server_post_without_content_length():
"/",
"http://tester.localhost:5000/",
environ_overrides={"CONTENT_LENGTH": ""},
data="<CreateBucketConfiguration><LocationConstraint>us-west-2</LocationConstraint></CreateBucketConfiguration>",
data=(
"<CreateBucketConfiguration>"
"<LocationConstraint>us-west-2</LocationConstraint>"
"</CreateBucketConfiguration>"
),
)
res.status_code.should.equal(200)
assert res.status_code == 200
# You cannot make any other bucket-related requests without specifying Content-Length
for path in ["/?versioning", "/?policy"]:
res = test_client.put(
path, "http://t.localhost:5000", environ_overrides={"CONTENT_LENGTH": ""}
)
res.status_code.should.equal(411)
assert res.status_code == 411
# You cannot make any POST-request
res = test_client.post(
"/", "https://tester.localhost:5000/", environ_overrides={"CONTENT_LENGTH": ""}
)
res.status_code.should.equal(411)
assert res.status_code == 411
def test_s3_server_post_unicode_bucket_key():
# Make sure that we can deal with non-ascii characters in request URLs (e.g., S3 object names)
"""Verify non-ascii characters in request URLs (e.g., S3 object names)."""
dispatcher = server.DomainDispatcherApplication(server.create_backend_app)
backend_app = dispatcher.get_application(
{"HTTP_HOST": "s3.amazonaws.com", "PATH_INFO": "/test-bucket/test-object-てすと"}
@ -226,16 +227,12 @@ def test_s3_server_post_cors():
set(res.headers["Access-Control-Allow-Methods"].split(", ")) == expected_methods
)
res.headers.should.have.key("Access-Control-Allow-Origin").which.should.equal(
"https://localhost:9000"
)
res.headers.should.have.key("Access-Control-Allow-Headers").which.should.equal(
"origin, x-requested-with"
)
assert res.headers["Access-Control-Allow-Origin"] == "https://localhost:9000"
assert res.headers["Access-Control-Allow-Headers"] == "origin, x-requested-with"
def test_s3_server_post_cors_exposed_header():
"""Test that we can override default CORS headers with custom bucket rules"""
"""Test overriding default CORS headers with custom bucket rules"""
# github.com/getmoto/moto/issues/4220
cors_config_payload = """<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
@ -386,10 +383,12 @@ def test_s3_server_post_cors_multiple_origins():
assert b"<Code>AccessForbidden</Code>" in preflight_response.content
# Verify we can use a wildcard anywhere in the origin
cors_config_payload = """<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule>
<AllowedOrigin>https://*.google.com</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
</CORSRule></CORSConfiguration>"""
cors_config_payload = (
'<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule>'
"<AllowedOrigin>https://*.google.com</AllowedOrigin>"
"<AllowedMethod>POST</AllowedMethod>"
"</CORSRule></CORSConfiguration>"
)
requests.put("http://testcors.localhost:6789/?cors", data=cors_config_payload)
for origin in ["https://sth.google.com", "https://a.google.com"]:
preflight_response = requests.options(
@ -411,10 +410,12 @@ def test_s3_server_post_cors_multiple_origins():
assert b"<Code>AccessForbidden</Code>" in preflight_response.content
# Verify we can use a wildcard as the origin
cors_config_payload = """<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
</CORSRule></CORSConfiguration>"""
cors_config_payload = (
'<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><CORSRule>'
"<AllowedOrigin>*</AllowedOrigin>"
"<AllowedMethod>POST</AllowedMethod>"
"</CORSRule></CORSConfiguration>"
)
requests.put("http://testcors.localhost:6789/?cors", data=cors_config_payload)
for origin in ["https://a.google.com", "http://b.microsoft.com", "any"]:
preflight_response = requests.options(