1515import unittest
1616
1717from concurrent .futures import ThreadPoolExecutor
18- from unittest .mock import Mock , ANY , call , patch
18+ from unittest .mock import Mock , ANY , call , patch , MagicMock
1919
20- from cassandra import OperationTimedOut , SchemaTargetType , SchemaChangeType
21- from cassandra .protocol import ResultMessage , RESULT_KIND_ROWS
20+ from cassandra import OperationTimedOut , SchemaTargetType , SchemaChangeType , ConsistencyLevel
21+ from cassandra .protocol import ResultMessage , RESULT_KIND_ROWS , QueryMessage
2222from cassandra .cluster import ControlConnection , _Scheduler , ProfileManager , EXEC_PROFILE_DEFAULT , ExecutionProfile
2323from cassandra .pool import Host
2424from cassandra .connection import EndPoint , DefaultEndPoint , DefaultEndPointFactory
@@ -168,6 +168,21 @@ def __init__(self):
168168 ]
169169 self .wait_for_responses = Mock (return_value = _node_meta_results (self .local_results , self .peer_results ))
170170
171+ def wait_for_response_side_effect (query_msg , timeout = None , fail_on_error = True ):
172+ result = ResultMessage (kind = RESULT_KIND_ROWS )
173+ if "peers" in query_msg .query .lower ():
174+ result .column_names = self .peer_results [0 ]
175+ result .parsed_rows = self .peer_results [1 ]
176+ else :
177+ result .column_names = self .local_results [0 ]
178+ result .parsed_rows = self .local_results [1 ]
179+ result .paging_state = None
180+ return result
181+ self .wait_for_response = Mock (side_effect = wait_for_response_side_effect )
182+
183+ def fetch_all_pages (self , query_msg , timeout , fail_on_error = True ):
184+ return self .wait_for_response (query_msg , timeout = timeout , fail_on_error = fail_on_error )
185+
171186
172187class FakeTime (object ):
173188
@@ -312,6 +327,91 @@ def test_wait_for_schema_agreement_none_timeout(self):
312327 cc ._time = self .time
313328 assert cc ._wait_for_schema_agreement ()
314329
330+ def test_topology_queries_use_paging (self ):
331+ self .control_connection .refresh_node_list_and_token_map ()
332+ assert self .connection .wait_for_response .called
333+ calls = self .connection .wait_for_response .call_args_list
334+ for call in calls :
335+ query_msg = call [0 ][0 ]
336+ assert isinstance (query_msg , QueryMessage )
337+ assert query_msg .fetch_size == self .control_connection ._schema_meta_page_size
338+
339+ def test_topology_queries_fetch_all_pages (self ):
340+ from cassandra .connection import Connection as RealConnection
341+ mock_connection = MagicMock ()
342+ mock_connection .endpoint = DefaultEndPoint ("192.168.1.0" )
343+ mock_connection .original_endpoint = mock_connection .endpoint
344+ mock_connection .fetch_all_pages = RealConnection .fetch_all_pages .__get__ (mock_connection , RealConnection )
345+ first_page = ResultMessage (kind = RESULT_KIND_ROWS )
346+ first_page .column_names = ["rpc_address" , "peer" , "schema_version" , "data_center" , "rack" , "tokens" , "host_id" ]
347+ first_page .parsed_rows = [["192.168.1.1" , "10.0.0.1" , "a" , "dc1" , "rack1" , ["1" , "101" , "201" ], "uuid2" ]]
348+ first_page .paging_state = b"has_more_pages"
349+ second_page = ResultMessage (kind = RESULT_KIND_ROWS )
350+ second_page .column_names = ["rpc_address" , "peer" , "schema_version" , "data_center" , "rack" , "tokens" , "host_id" ]
351+ second_page .parsed_rows = [["192.168.1.2" , "10.0.0.2" , "a" , "dc1" , "rack1" , ["2" , "102" , "202" ], "uuid3" ]]
352+ second_page .paging_state = None
353+ mock_connection .wait_for_response .side_effect = [first_page , second_page ]
354+ self .control_connection ._connection = mock_connection
355+ query_msg = QueryMessage (query = "SELECT * FROM system.peers" ,
356+ consistency_level = ConsistencyLevel .ONE ,
357+ fetch_size = self .control_connection ._schema_meta_page_size )
358+ result = mock_connection .fetch_all_pages (query_msg , timeout = 5 )
359+ assert len (result .parsed_rows ) == 2
360+ assert result .parsed_rows [0 ][0 ] == "192.168.1.1"
361+ assert result .parsed_rows [1 ][0 ] == "192.168.1.2"
362+ assert result .paging_state is None
363+ assert mock_connection .wait_for_response .call_count == 2
364+
365+ def test_topology_queries_fetch_all_pages_fail_on_error_false (self ):
366+ from cassandra .connection import Connection as RealConnection
367+ mock_connection = MagicMock ()
368+ mock_connection .endpoint = DefaultEndPoint ("192.168.1.0" )
369+ mock_connection .original_endpoint = mock_connection .endpoint
370+ mock_connection .fetch_all_pages = RealConnection .fetch_all_pages .__get__ (mock_connection , RealConnection )
371+ first_page = ResultMessage (kind = RESULT_KIND_ROWS )
372+ first_page .column_names = ["rpc_address" , "peer" , "schema_version" , "data_center" , "rack" , "tokens" , "host_id" ]
373+ first_page .parsed_rows = [["192.168.1.1" , "10.0.0.1" , "a" , "dc1" , "rack1" , ["1" , "101" , "201" ], "uuid2" ]]
374+ first_page .paging_state = b"has_more_pages"
375+ second_page = ResultMessage (kind = RESULT_KIND_ROWS )
376+ second_page .column_names = ["rpc_address" , "peer" , "schema_version" , "data_center" , "rack" , "tokens" , "host_id" ]
377+ second_page .parsed_rows = [["192.168.1.2" , "10.0.0.2" , "a" , "dc1" , "rack1" , ["2" , "102" , "202" ], "uuid3" ]]
378+ second_page .paging_state = None
379+ mock_connection .wait_for_response .side_effect = [
380+ (True , first_page ),
381+ (True , second_page ),
382+ ]
383+ query_msg = QueryMessage (query = "SELECT * FROM system.peers" ,
384+ consistency_level = ConsistencyLevel .ONE ,
385+ fetch_size = self .control_connection ._schema_meta_page_size )
386+ success , result = mock_connection .fetch_all_pages (query_msg , timeout = 5 , fail_on_error = False )
387+ assert success
388+ assert len (result .parsed_rows ) == 2
389+ assert result .parsed_rows [0 ][0 ] == "192.168.1.1"
390+ assert result .parsed_rows [1 ][0 ] == "192.168.1.2"
391+ assert mock_connection .wait_for_response .call_count == 2
392+
393+ def test_topology_queries_fetch_all_pages_page_failure (self ):
394+ from cassandra .connection import Connection as RealConnection
395+ mock_connection = MagicMock ()
396+ mock_connection .endpoint = DefaultEndPoint ("192.168.1.0" )
397+ mock_connection .original_endpoint = mock_connection .endpoint
398+ mock_connection .fetch_all_pages = RealConnection .fetch_all_pages .__get__ (mock_connection , RealConnection )
399+ first_page = ResultMessage (kind = RESULT_KIND_ROWS )
400+ first_page .column_names = ["rpc_address" , "peer" , "schema_version" , "data_center" , "rack" , "tokens" , "host_id" ]
401+ first_page .parsed_rows = [["192.168.1.1" , "10.0.0.1" , "a" , "dc1" , "rack1" , ["1" , "101" , "201" ], "uuid2" ]]
402+ first_page .paging_state = b"has_more_pages"
403+ mock_connection .wait_for_response .side_effect = [
404+ (True , first_page ),
405+ (False , OperationTimedOut ()),
406+ ]
407+ query_msg = QueryMessage (query = "SELECT * FROM system.peers" ,
408+ consistency_level = ConsistencyLevel .ONE ,
409+ fetch_size = self .control_connection ._schema_meta_page_size )
410+ success , error = mock_connection .fetch_all_pages (query_msg , timeout = 5 , fail_on_error = False )
411+ assert not success
412+ assert isinstance (error , OperationTimedOut )
413+ assert mock_connection .wait_for_response .call_count == 2
414+
315415 def test_refresh_nodes_and_tokens (self ):
316416 self .control_connection .refresh_node_list_and_token_map ()
317417 meta = self .cluster .metadata
@@ -328,7 +428,7 @@ def test_refresh_nodes_and_tokens(self):
328428 assert host .datacenter == "dc1"
329429 assert host .rack == "rack1"
330430
331- assert self .connection .wait_for_responses .call_count == 1
431+ assert self .connection .wait_for_response .call_count == 2
332432
333433 def test_refresh_nodes_and_tokens_with_invalid_peers (self ):
334434 def refresh_and_validate_added_hosts ():
@@ -444,11 +544,11 @@ def test_refresh_nodes_and_tokens_remove_host(self):
444544
445545 def test_refresh_nodes_and_tokens_timeout (self ):
446546
447- def bad_wait_for_responses (* args , ** kwargs ):
547+ def bad_wait_for_response (* args , ** kwargs ):
448548 assert kwargs ['timeout' ] == self .control_connection ._timeout
449549 raise OperationTimedOut ()
450550
451- self .connection .wait_for_responses = bad_wait_for_responses
551+ self .connection .wait_for_response = Mock ( side_effect = bad_wait_for_response )
452552 self .control_connection .refresh_node_list_and_token_map ()
453553 self .cluster .executor .submit .assert_called_with (self .control_connection ._reconnect )
454554
0 commit comments