2021-06-24 07:14:28 +00:00
|
|
|
from botocore.exceptions import ClientError
|
|
|
|
from moto import mock_s3
|
|
|
|
import boto3
|
2021-11-09 19:49:29 +00:00
|
|
|
import os
|
2021-06-24 07:14:28 +00:00
|
|
|
import pytest
|
2021-11-23 19:47:48 +00:00
|
|
|
import sure # noqa # pylint: disable=unused-import
|
2021-06-24 07:14:28 +00:00
|
|
|
|
2021-06-28 14:57:07 +00:00
|
|
|
from .test_s3 import DEFAULT_REGION_NAME
|
|
|
|
|
2021-06-24 07:14:28 +00:00
|
|
|
|
|
|
|
@mock_s3
|
|
|
|
def test_multipart_should_throw_nosuchupload_if_there_are_no_parts():
|
2021-08-18 19:25:33 +00:00
|
|
|
bucket = boto3.resource("s3", region_name=DEFAULT_REGION_NAME).Bucket(
|
|
|
|
"randombucketname"
|
|
|
|
)
|
2021-06-24 07:14:28 +00:00
|
|
|
bucket.create()
|
|
|
|
s3_object = bucket.Object("my/test2")
|
|
|
|
|
|
|
|
multipart_upload = s3_object.initiate_multipart_upload()
|
|
|
|
multipart_upload.abort()
|
|
|
|
|
|
|
|
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."
|
|
|
|
)
|
|
|
|
err["UploadId"].should.equal(multipart_upload.id)
|
2021-06-28 14:57:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_s3
|
|
|
|
def test_boto3_multipart_part_size():
|
|
|
|
bucket_name = "mputest-3593"
|
|
|
|
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
|
|
|
|
s3.create_bucket(Bucket=bucket_name)
|
|
|
|
|
|
|
|
mpu = s3.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(
|
|
|
|
Bucket=bucket_name,
|
|
|
|
Key="the-key",
|
|
|
|
PartNumber=-1,
|
|
|
|
UploadId=mpu_id,
|
|
|
|
Body=body,
|
|
|
|
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."
|
|
|
|
)
|
2021-11-09 19:49:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_s3
|
|
|
|
def test_multipart_upload_with_tags():
|
|
|
|
bucket = "mybucket"
|
|
|
|
key = "test/multipartuploadtag/file.txt"
|
|
|
|
tags = "a=b"
|
|
|
|
|
|
|
|
client = boto3.client("s3", region_name="us-east-1")
|
|
|
|
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"])
|
|
|
|
parts = [
|
|
|
|
{
|
|
|
|
"ETag": u.Part(i).upload(Body=os.urandom(5 * (2 ** 20)))["ETag"],
|
|
|
|
"PartNumber": i,
|
|
|
|
}
|
|
|
|
for i in range(1, 3)
|
|
|
|
]
|
|
|
|
|
|
|
|
u.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"})
|
2021-11-23 19:47:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_s3
|
|
|
|
def test_multipart_upload_should_return_part_10000():
|
|
|
|
bucket = "dummybucket"
|
|
|
|
s3_client = boto3.client("s3", "us-east-1")
|
|
|
|
|
|
|
|
key = "test_file"
|
|
|
|
s3_client.create_bucket(Bucket=bucket)
|
|
|
|
|
|
|
|
mpu = s3_client.create_multipart_upload(Bucket=bucket, Key=key)
|
|
|
|
mpu_id = mpu["UploadId"]
|
|
|
|
s3_client.upload_part(
|
|
|
|
Bucket=bucket, Key=key, PartNumber=1, UploadId=mpu_id, Body="data"
|
|
|
|
)
|
|
|
|
s3_client.upload_part(
|
|
|
|
Bucket=bucket, Key=key, PartNumber=2, UploadId=mpu_id, Body="data"
|
|
|
|
)
|
|
|
|
s3_client.upload_part(
|
|
|
|
Bucket=bucket, Key=key, PartNumber=10000, UploadId=mpu_id, Body="data"
|
|
|
|
)
|
|
|
|
|
|
|
|
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])
|
|
|
|
|
|
|
|
|
|
|
|
@mock_s3
|
|
|
|
@pytest.mark.parametrize("part_nr", [10001, 10002, 20000])
|
|
|
|
def test_s3_multipart_upload_cannot_upload_part_over_10000(part_nr):
|
|
|
|
bucket = "dummy"
|
|
|
|
s3_client = boto3.client("s3", "us-east-1")
|
|
|
|
|
|
|
|
key = "test_file"
|
|
|
|
s3_client.create_bucket(Bucket=bucket)
|
|
|
|
|
|
|
|
mpu = s3_client.create_multipart_upload(Bucket=bucket, Key=key)
|
|
|
|
mpu_id = mpu["UploadId"]
|
|
|
|
|
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
s3_client.upload_part(
|
|
|
|
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(
|
|
|
|
"Part number must be an integer between 1 and 10000, inclusive"
|
|
|
|
)
|
|
|
|
err["ArgumentName"].should.equal("partNumber")
|
|
|
|
err["ArgumentValue"].should.equal(f"{part_nr}")
|