def test_backward_last_page(self): # One result. partition_1 = self.create_results(1, 'B') # No results. partition_3 = [] expected_page = [partition_1[0]] table_mock = MagicMock() table_mock.query.side_effect = [{ 'Items': partition_1 }, { 'Items': partition_3 }] start_key = self.create_results(1, 'C')[0] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.forward = False page_token.set_start(1, start_key) # Partition 2 is is already at the end. page_token.set_start(3, start_key) search = dynamodb_pagination.PaginatedSearch( self.get_config(table_mock), page_token) page_size = 4 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, { 'partition': 1, 'key': start_key, 'limit': page_size, 'forward': False }, { 'partition': 3, 'key': start_key, 'limit': page_size, 'forward': False }) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) self.assertEqual( json.loads(base64.b64decode(forward_page_token)), { 'direction': 'forward', 'partitions': { '1': { 'key': partition_1[0] }, '2': {}, '3': {} } }) backward_page_token = search.get_page_token(forward=False) if backward_page_token: print 'Page token was not None: ', json.loads( base64.b64decode(backward_page_token)) self.assertIsNone(backward_page_token)
def test_backward_inclusive(self): query_for_direction_change_1 = self.create_results(1, 'H') partition_1 = self.create_results(1, 'F', 'D', 'B') query_for_direction_change_2 = self.create_results(1, 'G') partition_2 = self.create_results(2, 'E', 'C', 'A') expected_page = [ partition_2[1], partition_1[1], partition_2[0], partition_1[0], ] table_mock = MagicMock() table_mock.query.side_effect = [ {'Items': query_for_direction_change_1}, {'Items': partition_1}, {'Items': query_for_direction_change_2}, {'Items': partition_2} ] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.forward = False page_token.set_start(1, partition_1[0], True) page_token.set_start(2, partition_2[0], True) search = dynamodb_pagination.PaginatedSearch(self.get_config(table_mock), page_token) page_size = 4 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, {'partition': 1, 'key': partition_1[0], 'limit': 1, 'forward': True}, {'partition': 1, 'key': query_for_direction_change_1[0], 'limit': page_size, 'forward': False}, {'partition': 2, 'key': partition_2[0], 'limit': 1, 'forward': True}, {'partition': 2, 'key': query_for_direction_change_2[0], 'limit': page_size, 'forward': False} ) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) self.assertEqual(json.loads(base64.b64decode(forward_page_token)), { 'direction': 'forward', 'partitions': { '1': {'key': partition_1[0]}, '2': {'key': partition_2[0]}, '3': {} } } ) backward_page_token = search.get_page_token(forward=False) self.assertEqual(json.loads(base64.b64decode(backward_page_token)), { 'direction': 'backward', 'partitions': { '1': {'key': partition_1[1]}, '2': {'key': partition_2[1]} } } )
def test_first_page(self): partition_1 = self.create_results(1, 'A', 'D') partition_2 = self.create_results(2, 'B', 'E', 'G') partition_3 = self.create_results(3, 'C', 'F', 'H') expected_page = [ partition_1[0], partition_2[0], partition_3[0], partition_1[1], partition_2[1] ] table_mock = MagicMock() table_mock.query.side_effect = [ {'Items': partition_1, 'LastEvaluatedKey': partition_1[1]}, {'Items': partition_2}, {'Items': partition_3} ] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.set_start(1, None) page_token.set_start(2, None) page_token.set_start(3, None) search = dynamodb_pagination.PaginatedSearch(self.get_config(table_mock), page_token) page_size = 5 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, {'partition': 1, 'limit': page_size, 'forward': True}, {'partition': 2, 'limit': page_size, 'forward': True}, {'partition': 3, 'limit': page_size, 'forward': True} ) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) self.assertEqual(json.loads(base64.b64decode(forward_page_token)), { 'direction': 'forward', 'partitions': { '1': {'key': partition_1[1]}, '2': {'key': partition_2[1]}, '3': {'key': partition_3[0]} } } ) backward_page_token = search.get_page_token(forward=False) self.assertEqual(json.loads(base64.b64decode(backward_page_token)), { 'direction': 'backward', 'partitions': { '1': {'key': partition_1[0]}, '2': {'key': partition_2[0]}, '3': {'key': partition_3[0]} } } )
def test_forward_exclusive(self): """Test a forward search using an exclusive page token""" partition_1 = self.create_results(1, 'F', 'H', 'J') partition_2 = self.create_results(2, 'E', 'G', 'I') expected_page = [ partition_2[0], partition_1[0], partition_2[1], partition_1[1], ] table_mock = MagicMock() table_mock.query.side_effect = [ {'Items': partition_1}, {'Items': partition_2} ] start_key_1 = self.create_results(1, 'E')[0] start_key_2 = self.create_results(2, 'D')[0] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.set_start(1, start_key_1, False) page_token.set_start(2, start_key_2, False) search = dynamodb_pagination.PaginatedSearch(self.get_config(table_mock), page_token) page_size = 4 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, {'partition': 1, 'key': start_key_1, 'limit': page_size, 'forward': True}, {'partition': 2, 'key': start_key_2, 'limit': page_size, 'forward': True}, ) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) self.assertEqual(json.loads(base64.b64decode(forward_page_token)), { 'direction': 'forward', 'partitions': { '1': {'key': partition_1[1]}, '2': {'key': partition_2[1]} } } ) backward_page_token = search.get_page_token(forward=False) self.assertEqual(json.loads(base64.b64decode(backward_page_token)), { 'direction': 'backward', 'partitions': { '1': {'key': partition_1[0]}, '2': {'key': partition_2[0]}, '3': {} } } )
def test_forward_last_page_single_partition(self): partition_1 = self.create_results(1, 'A', 'B', 'C', 'D') expected_page = partition_1 table_mock = MagicMock() table_mock.query.side_effect = [{'Items': partition_1}] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.set_start(1, None) search = dynamodb_pagination.PaginatedSearch( self.get_config(table_mock), page_token) page_size = 4 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, { 'partition': 1, 'limit': page_size, 'forward': True }) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) if forward_page_token: print 'Page token was not None: ', json.loads( base64.b64decode(forward_page_token)) self.assertIsNone(forward_page_token) backward_page_token = search.get_page_token(forward=False) self.assertEqual( json.loads(base64.b64decode(backward_page_token)), { 'direction': 'backward', 'partitions': { '1': { 'key': partition_1[0] }, '2': {}, '3': {} } })
def search_by_start_name(start_player_name=None, serialized_page_token=None): page_size = 20 config = dynamodb_pagination.PartitionedIndexConfig( table=account_utils.get_account_table(), index_name='PlayerNameIndex', partition_key_name='PlayerNameSortKey', sort_key_name='IndexedPlayerName', partition_count=account_utils.get_name_sort_key_count(), required_fields={'AccountId': ' '}) if serialized_page_token: page_token = dynamodb_pagination.PageToken(config, serialized_page_token) else: page_token = dynamodb_pagination.get_page_token_for_inclusive_start( config, start_player_name, forward=True) search = dynamodb_pagination.PaginatedSearch(config, page_token, start_player_name) raw_account_items = search.get_next_page(page_size) accounts = [ account_utils.convert_account_from_dynamo_to_admin_model(item) for item in raw_account_items ] populate_identity_providers(accounts) result = {'Accounts': accounts} forward_token = search.get_page_token(forward=True) if forward_token: result['next'] = forward_token backward_token = search.get_page_token(forward=False) if backward_token: result['previous'] = backward_token return result
def test_forward_inclusive_match_sort_key(self): # 'D' is found on the second page and used as the exclusive start. query_for_direction_change_1A = self.create_results(1, 'F', 'F') query_for_direction_change_1B = self.create_results(1, 'F', 'D') partition_1 = self.create_results(1, 'F', 'H', 'J') # 'C' is found on the first page and used as the exclusive start. query_for_direction_change_2 = self.create_results(1, 'C') partition_2 = self.create_results(2, 'E', 'G', 'I') # All pages include matching keys. query_for_direction_change_3 = self.create_results(1, 'F', 'F') partition_3 = [] expected_page = [ partition_2[0], partition_1[0], partition_2[1], partition_1[1], ] table_mock = MagicMock() table_mock.query.side_effect = [{ 'Items': query_for_direction_change_1A, 'LastEvaluatedKey': query_for_direction_change_1A[-1] }, { 'Items': query_for_direction_change_1B }, { 'Items': partition_1 }, { 'Items': query_for_direction_change_2 }, { 'Items': partition_2 }, { 'Items': query_for_direction_change_3, 'LastEvaluatedKey': query_for_direction_change_3[-1] }, { 'Items': query_for_direction_change_3, 'LastEvaluatedKey': query_for_direction_change_3[-1] }, { 'Items': query_for_direction_change_3, 'LastEvaluatedKey': query_for_direction_change_3[-1] }, { 'Items': partition_3 }] page_token = dynamodb_pagination.PageToken(self.get_config(table_mock)) page_token.set_start(1, partition_1[0], 'match_sort_key') page_token.set_start(2, partition_2[0], 'match_sort_key') page_token.set_start(3, partition_1[0], 'match_sort_key') search = dynamodb_pagination.PaginatedSearch( self.get_config(table_mock), page_token) page_size = 4 page = search.get_next_page(page_size) self.assert_query_calls(table_mock.query, { 'partition': 1, 'key': partition_1[0], 'limit': 20, 'forward': False }, { 'partition': 1, 'key': query_for_direction_change_1A[-1], 'limit': 20, 'forward': False }, { 'partition': 1, 'key': query_for_direction_change_1B[-1], 'limit': page_size, 'forward': True }, { 'partition': 2, 'key': partition_2[0], 'limit': 20, 'forward': False }, { 'partition': 2, 'key': query_for_direction_change_2[0], 'limit': page_size, 'forward': True }, { 'partition': 3, 'key': partition_1[0], 'limit': 20, 'forward': False }, { 'partition': 3, 'key': query_for_direction_change_3[-1], 'limit': 20, 'forward': False }, { 'partition': 3, 'key': query_for_direction_change_3[-1], 'limit': 20, 'forward': False }, { 'partition': 3, 'key': query_for_direction_change_3[-1], 'limit': page_size, 'forward': True }) self.assertEqual(page, expected_page) forward_page_token = search.get_page_token(forward=True) self.assertEqual( json.loads(base64.b64decode(forward_page_token)), { 'direction': 'forward', 'partitions': { '1': { 'key': partition_1[1] }, '2': { 'key': partition_2[1] } } }) backward_page_token = search.get_page_token(forward=False) self.assertEqual( json.loads(base64.b64decode(backward_page_token)), { 'direction': 'backward', 'partitions': { '1': { 'key': partition_1[0] }, '2': { 'key': partition_2[0] }, '3': {} } })