Fix: ListObjectsV2 behaving differently than AWS API (#3545)

* fix : localstack issue https://github.com/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+language%3Ago

* add assertion for error message as well
This commit is contained in:
irahulranjan 2020-12-13 19:08:25 +05:30 committed by GitHub
parent e6be3265ca
commit dffc0e449c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 1 deletions

View File

@ -424,3 +424,15 @@ class InvalidRange(S3ClientError):
actual_size=actual_size, actual_size=actual_size,
**kwargs **kwargs
) )
class InvalidContinuationToken(S3ClientError):
code = 400
def __init__(self, *args, **kwargs):
super(InvalidContinuationToken, self).__init__(
"InvalidArgument",
"The continuation token provided is incorrect",
*args,
**kwargs
)

View File

@ -25,6 +25,7 @@ from moto.s3bucket_path.utils import (
from .exceptions import ( from .exceptions import (
BucketAlreadyExists, BucketAlreadyExists,
DuplicateTagKeys, DuplicateTagKeys,
InvalidContinuationToken,
S3ClientError, S3ClientError,
MissingBucket, MissingBucket,
MissingKey, MissingKey,
@ -529,6 +530,10 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
template = self.response_template(S3_BUCKET_GET_RESPONSE_V2) template = self.response_template(S3_BUCKET_GET_RESPONSE_V2)
bucket = self.backend.get_bucket(bucket_name) bucket = self.backend.get_bucket(bucket_name)
continuation_token = querystring.get("continuation-token", [None])[0]
if continuation_token is not None and continuation_token == "":
raise InvalidContinuationToken()
prefix = querystring.get("prefix", [None])[0] prefix = querystring.get("prefix", [None])[0]
if prefix and isinstance(prefix, six.binary_type): if prefix and isinstance(prefix, six.binary_type):
prefix = prefix.decode("utf-8") prefix = prefix.decode("utf-8")
@ -539,7 +544,6 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
fetch_owner = querystring.get("fetch-owner", [False])[0] fetch_owner = querystring.get("fetch-owner", [False])[0]
max_keys = int(querystring.get("max-keys", [1000])[0]) max_keys = int(querystring.get("max-keys", [1000])[0])
continuation_token = querystring.get("continuation-token", [None])[0]
start_after = querystring.get("start-after", [None])[0] start_after = querystring.get("start-after", [None])[0]
# sort the combination of folders and keys into lexicographical order # sort the combination of folders and keys into lexicographical order

View File

@ -1809,6 +1809,32 @@ def test_boto3_list_objects_v2_common_prefix_pagination():
assert prefixes == [k[: k.rindex("/") + 1] for k in keys] assert prefixes == [k[: k.rindex("/") + 1] for k in keys]
@mock_s3
def test_boto3_list_objects_v2_common_invalid_continuation_token():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
s3.create_bucket(Bucket="mybucket")
max_keys = 1
keys = ["test/{i}/{i}".format(i=i) for i in range(3)]
for key in keys:
s3.put_object(Bucket="mybucket", Key=key, Body=b"v")
args = {
"Bucket": "mybucket",
"Delimiter": "/",
"Prefix": "test/",
"MaxKeys": max_keys,
"ContinuationToken": "",
}
with pytest.raises(botocore.exceptions.ClientError) as exc:
s3.list_objects_v2(**args)
exc.value.response["Error"]["Code"].should.equal("InvalidArgument")
exc.value.response["Error"]["Message"].should.equal(
"The continuation token provided is incorrect"
)
@mock_s3 @mock_s3
def test_boto3_list_objects_v2_truncated_response(): def test_boto3_list_objects_v2_truncated_response():
s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME) s3 = boto3.client("s3", region_name=DEFAULT_REGION_NAME)