Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion moto/s3/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,9 @@ def complete(
full_etag = md5_hash()
full_etag.update(bytes(md5s))
if checksum_algo:
encoded_checksum = compute_checksum(checksum, checksum_algo).decode("utf-8")
encoded_checksum = (
f"{compute_checksum(checksum, checksum_algo).decode('utf-8')}-{count}"
)
else:
encoded_checksum = None
return total, f"{full_etag.hexdigest()}-{count}", encoded_checksum
Expand Down
63 changes: 63 additions & 0 deletions tests/test_s3/test_s3_multipart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import moto.s3.models as s3model
from moto import mock_aws, settings
from moto.s3.responses import DEFAULT_REGION_NAME
from moto.s3.utils import compute_checksum
from moto.settings import (
S3_UPLOAD_PART_MIN_SIZE,
get_s3_default_key_buffer_size,
Expand Down Expand Up @@ -159,6 +160,68 @@ def test_multipart_upload(key: str):
assert response["Body"].read() == part1 + part2


@mock_aws
@reduced_min_part_size
def test_multipart_upload_checksum_has_composite_suffix():
s3_resource = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
bucket = s3_resource.create_bucket(Bucket=str(uuid4()))

part1 = b"0" * REDUCED_PART_SIZE
part2 = b"1"

multipart = client.create_multipart_upload(
Bucket=bucket.name,
Key="the-key",
ChecksumAlgorithm="SHA256",
)
up1 = client.upload_part(
Body=BytesIO(part1),
PartNumber=1,
Bucket=bucket.name,
Key="the-key",
UploadId=multipart["UploadId"],
)
up2 = client.upload_part(
Body=BytesIO(part2),
PartNumber=2,
Bucket=bucket.name,
Key="the-key",
UploadId=multipart["UploadId"],
)

client.complete_multipart_upload(
Bucket=bucket.name,
Key="the-key",
MultipartUpload={
"Parts": [
{"ETag": up1["ETag"], "PartNumber": 1},
{"ETag": up2["ETag"], "PartNumber": 2},
]
},
UploadId=multipart["UploadId"],
)

response = client.get_object(
Bucket=bucket.name,
Key="the-key",
ChecksumMode="ENABLED",
)
checksum = response["ChecksumSHA256"]

expected_composite = (
compute_checksum(
compute_checksum(part1, "SHA256", encode_base64=False)
+ compute_checksum(part2, "SHA256", encode_base64=False),
"SHA256",
).decode("utf-8")
+ "-2"
)

assert checksum == expected_composite
assert checksum.endswith("-2")


@pytest.mark.aws_verified
@s3_aws_verified
def test_idempotent_multipart_upload(bucket_name=None):
Expand Down
Loading