10000 add special char s3 test + fix moto lookup with cleaned up key name (… · codeperl/localstack@b7e9ac8 · GitHub
[go: up one dir, main page]

Skip to content

Commit b7e9ac8

Browse files
authored
add special char s3 test + fix moto lookup with cleaned up key name (localstack#8470)
1 parent 3d8dd50 commit b7e9ac8

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

localstack/services/s3/utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from botocore.utils import InvalidArnException
99
from moto.s3.exceptions import MissingBucket
1010
from moto.s3.models import FakeBucket, FakeDeleteMarker, FakeKey
11+
from moto.s3.utils import clean_key_name
1112

1213
from localstack.aws.api import CommonServiceException, ServiceException
1314
from localstack.aws.api.s3 import (
@@ -162,10 +163,11 @@ def get_key_from_moto_bucket(
162163
) -> FakeKey | FakeDeleteMarker:
163164
# TODO: rework the delete marker handling
164165
# we basically need to re-implement moto `get_object` to account for FakeDeleteMarker
166+
clean_key = clean_key_name(key)
165167
if version_id is None:
166-
fake_key = moto_bucket.keys.get(key)
168+
fake_key = moto_bucket.keys.get(clean_key)
167169
else:
168-
for key_version in moto_bucket.keys.getlist(key, default=[]):
170+
for key_version in moto_bucket.keys.getlist(clean_key, default=[]):
169171
if str(key_version.version_id) == str(version_id):
170172
fake_key = key_version
171173
break

tests/integration/s3/test_s3.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,22 @@ def test_upload_file_multipart(self, s3_bucket, tmpdir, snapshot, aws_client):
626626
assert obj["Body"].read() == data, f"body did not contain expected data {obj}"
627627
snapshot.match("get_object", obj)
628628

629+
@pytest.mark.aws_validated
630+
@pytest.mark.skip_snapshot_verify(paths=["$..ServerSideEncryption"])
631+
@pytest.mark.parametrize("key", ["file%2Fname", "test@key/"])
632+
def test_put_get_object_special_character(self, s3_bucket, aws_client, snapshot, key):
633+
snapshot.add_transformer(snapshot.transform.s3_api())
634+
resp = aws_client.s3.put_object(Bucket=s3_bucket, Key=key, Body=b"test")
635+
snapshot.match("put-object-special-char", resp)
636+
resp = aws_client.s3.list_objects_v2(Bucket=s3_bucket)
637+
# FIXME: Moto will by default clean up key name, but they will return the cleaned up key name in ListObject...
638+
if "%" not in key or is_aws_cloud():
639+
snapshot.match("list-object-special-char", resp)
640+
resp = aws_client.s3.get_object(Bucket=s3_bucket, Key=key)
641+
snapshot.match("get-object-special-char", resp)
642+
resp = aws_client.s3.delete_object(Bucket=s3_bucket, Key=key)
643+
snapshot.match("del-object-special-char", resp)
644+
629645
@pytest.mark.aws_validated
630646
@pytest.mark.parametrize("delimiter", ["/", "%2F"])
631647
def test_list_objects_with_prefix(self, s3_create_bucket, delimiter, snapshot, aws_client):

tests/integration/s3/test_s3.snapshot.json

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7414,5 +7414,113 @@
74147414
}
74157415
}
74167416
}
7417+
},
7418+
"tests/integration/s3/test_s3.py::TestS3::test_put_get_object_special_character[file%2Fname]": {
7419+
"recorded-date": "09-06-2023, 17:15:35",
7420+
"recorded-content": {
7421+
"put-object-special-char": {
7422+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7423+
"ServerSideEncryption": "AES256",
7424+
"ResponseMetadata": {
7425+
"HTTPHeaders": {},
7426+
"HTTPStatusCode": 200
7427+
}
7428+
},
7429+
"list-object-special-char": {
7430+
"Contents": [
7431+
{
7432+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7433+
"Key": "file%2Fname",
7434+
"LastModified": "datetime",
7435+
"Size": 4,
7436+
"StorageClass": "STANDARD"
7437+
}
7438+
],
7439+
"EncodingType": "url",
7440+
"IsTruncated": false,
7441+
"KeyCount": 1,
7442+
"MaxKeys": 1000,
7443+
"Name": "<bucket-name:1>",
7444+
"Prefix": "",
7445+
"ResponseMetadata": {
7446+
"HTTPHeaders": {},
7447+
"HTTPStatusCode": 200
7448+
}
7449+
},
7450+
"get-object-special-char": {
7451+
"AcceptRanges": "bytes",
7452+
"Body": "test",
7453+
"ContentLength": 4,
7454+
"ContentType": "binary/octet-stream",
7455+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7456+
"LastModified": "datetime",
7457+
"Metadata": {},
7458+
"ServerSideEncryption": "AES256",
7459+
"ResponseMetadata": {
7460+
"HTTPHeaders": {},
7461+
"HTTPStatusCode": 200
7462+
}
7463+
},
7464+
"del-object-special-char": {
7465+
"ResponseMetadata": {
7466+
"HTTPHeaders": {},
7467+
"HTTPStatusCode": 204
7468+
}
7469+
}
7470+
}
7471+
},
7472+
"tests/integration/s3/test_s3.py::TestS3::test_put_get_object_special_character[test@key/]": {
7473+
"recorded-date": "09-06-2023, 17:15:39",
7474+
"recorded-content": {
7475+
"put-object-special-char": {
7476+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7477+
"ServerSideEncryption": "AES256",
7478+
"ResponseMetadata": {
7479+
"HTTPHeaders": {},
7480+
"HTTPStatusCode": 200
7481+
}
7482+
},
7483+
"list-object-special-char": {
7484+
"Contents": [
7485+
{
7486+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7487+
"Key": "test@key/",
7488+
"LastModified": "datetime",
7489+
"Size": 4,
7490+
"StorageClass": "STANDARD"
7491+
}
7492+
],
7493+
"EncodingType": "url",
7494+
"IsTruncated": false,
7495+
"KeyCount": 1,
7496+
"MaxKeys": 1000,
7497+
"Name": "<bucket-name:1>",
7498+
"Prefix": "",
7499+
"ResponseMetadata": {
7500+
"HTTPHeaders": {},
7501+
"HTTPStatusCode": 200
7502+
}
7503+
},
7504+
"get-object-special-char": {
7505+
"AcceptRanges": "bytes",
7506+
"Body": "test",
7507+
"ContentLength": 4,
7508+
"ContentType": "binary/octet-stream",
7509+
"ETag": "\"098f6bcd4621d373cade4e832627b4f6\"",
7510+
"LastModified": "datetime",
7511+
"Metadata": {},
7512+
"ServerSideEncryption": "AES256",
7513+
"ResponseMetadata": {
7514+
"HTTPHeaders": {},
7515+
"HTTPStatusCode": 200
7516+
}
7517+
},
7518+
"del-object-special-char": {
7519+
"ResponseMetadata": {
7520+
"HTTPHeaders": {},
7521+
"HTTPStatusCode": 204
7522+
}
7523+
}
7524+
}
74177525
}
74187526
}

0 commit comments

Comments
 (0)
0