diff --git a/moto/s3/models.py b/moto/s3/models.py index e6365dabf46f..930d7625697e 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -1888,9 +1888,13 @@ def put_object( return new_key def put_object_acl( - self, bucket_name: str, key_name: str, acl: Optional[FakeAcl] + self, + bucket_name: str, + key_name: str, + acl: Optional[FakeAcl], + key_is_clean: bool = False, ) -> None: - key = self.get_object(bucket_name, key_name) + key = self.get_object(bucket_name, key_name, key_is_clean=key_is_clean) # TODO: Support the XML-based ACL format if key is not None: key.set_acl(acl) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 10270de8ffa2..da42bac69880 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -2173,7 +2173,12 @@ def _key_response_post( ) key.set_metadata(multipart.metadata) self.backend.set_key_tags(key, multipart.tags) - self.backend.put_object_acl(bucket_name, key.name, multipart.acl) + self.backend.put_object_acl( + bucket_name=bucket_name, + key_name=key.name, + acl=multipart.acl, + key_is_clean=True, + ) template = self.response_template(S3_MULTIPART_COMPLETE_RESPONSE) headers: Dict[str, Any] = {} diff --git a/tests/test_s3/test_s3_multipart.py b/tests/test_s3/test_s3_multipart.py index b152c88bad0c..fb511e76afa5 100644 --- a/tests/test_s3/test_s3_multipart.py +++ b/tests/test_s3/test_s3_multipart.py @@ -107,34 +107,35 @@ def test_multipart_upload_too_small(): ) +@pytest.mark.parametrize("key", ["the-key", "the%20key"]) @mock_s3 @reduced_min_part_size -def test_multipart_upload(): +def test_multipart_upload(key: str): s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME) client = boto3.client("s3", region_name=DEFAULT_REGION_NAME) s3.create_bucket(Bucket="foobar") part1 = b"0" * REDUCED_PART_SIZE part2 = b"1" - mp = client.create_multipart_upload(Bucket="foobar", Key="the-key") + mp = client.create_multipart_upload(Bucket="foobar", Key=key) up1 = client.upload_part( Body=BytesIO(part1), PartNumber=1, Bucket="foobar", - Key="the-key", + Key=key, UploadId=mp["UploadId"], ) up2 = client.upload_part( Body=BytesIO(part2), PartNumber=2, Bucket="foobar", - Key="the-key", + Key=key, UploadId=mp["UploadId"], ) client.complete_multipart_upload( Bucket="foobar", - Key="the-key", + Key=key, MultipartUpload={ "Parts": [ {"ETag": up1["ETag"], "PartNumber": 1}, @@ -144,7 +145,7 @@ def test_multipart_upload(): UploadId=mp["UploadId"], ) # we should get both parts as the key contents - response = client.get_object(Bucket="foobar", Key="the-key") + response = client.get_object(Bucket="foobar", Key=key) response["Body"].read().should.equal(part1 + part2)