Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a paginator bug involving optional tokens. #1057

Merged
merged 1 commit into from
Dec 22, 2016
Merged
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
7 changes: 4 additions & 3 deletions botocore/paginate.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,10 @@ def _inject_starting_params(self, op_kwargs):

def _inject_token_into_kwargs(self, op_kwargs, next_token):
for name, token in next_token.items():
if token is None or token == 'None':
continue
op_kwargs[name] = token
if (token is not None) and (token != 'None'):
op_kwargs[name] = token
elif name in op_kwargs:
del op_kwargs[name]

def _handle_first_request(self, parsed, primary_result_key,
starting_truncation):
Expand Down
48 changes: 48 additions & 0 deletions tests/unit/test_paginate.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,54 @@ def test_s3_list_multipart_uploads(self):
])


class TestOptionalTokens(unittest.TestCase):
"""
Tests a paginator with an optional output token.

The Route53 ListResourceRecordSets paginator includes three output tokens,
one of which only appears in certain records. If this gets left in the
request params from a previous page, the API will skip over a record.

"""
def setUp(self):
self.method = mock.Mock()
# This is based on Route53 pagination.
self.paginate_config = {
"output_token": ["NextRecordName",
"NextRecordType",
"NextRecordIdentifier"],
"input_token": ["StartRecordName",
"StartRecordType",
"StartRecordIdentifier"],
"result_key": 'Foo',
}
self.paginator = Paginator(self.method, self.paginate_config)

def test_clean_token(self):
responses = [
{"Foo": [1],
"IsTruncated": True,
"NextRecordName": "aaa.example.com",
"NextRecordType": "A",
"NextRecordIdentifier": "id"},
{"Foo": [2],
"IsTruncated": True,
"NextRecordName": "bbb.example.com",
"NextRecordType": "A"},
{"Foo": [3],
"IsTruncated": False},
]
self.method.side_effect = responses
list(self.paginator.paginate())
self.assertEqual(
self.method.call_args_list,
[mock.call(),
mock.call(StartRecordName='aaa.example.com', StartRecordType='A',
StartRecordIdentifier='id'),
mock.call(StartRecordName='bbb.example.com', StartRecordType='A')
])


class TestKeyIterators(unittest.TestCase):
def setUp(self):
self.method = mock.Mock()
Expand Down