@@ -233,6 +233,92 @@ def test_handle_change_merges_when_host_ids_present(self, mock_query):
233233 self .assertIsNotNone (handler ._routes .get_by_host_id (existing_host ))
234234 self .assertIsNotNone (handler ._routes .get_by_host_id (new_host ))
235235
236+ @patch .object (_ClientRoutesHandler , '_query_routes_for_change_event' )
237+ def test_handle_change_preserves_routes_for_unrelated_connection_ids (self , mock_query ):
238+ """Routes for unrelated connection_ids in mixed events should not be removed."""
239+ handler = _ClientRoutesHandler (self .config )
240+ mock_conn = Mock ()
241+
242+ conn_id = str (self .conn_id )
243+ changed_host = uuid .uuid4 ()
244+ unrelated_host = uuid .uuid4 ()
245+
246+ handler ._routes .update ([
247+ _Route (connection_id = conn_id , host_id = changed_host , address = "old.com" , port = 9042 ),
248+ _Route (connection_id = conn_id , host_id = unrelated_host , address = "keep.com" , port = 9042 ),
249+ ])
250+
251+ mock_query .return_value = [
252+ _Route (connection_id = conn_id , host_id = changed_host , address = "new.com" , port = 9042 ),
253+ ]
254+
255+ handler .handle_client_routes_change (
256+ mock_conn , 5.0 ,
257+ ClientRoutesChangeType .UPDATE_NODES ,
258+ connection_ids = [conn_id , "unrelated-conn-id" ],
259+ host_ids = [str (changed_host ), str (unrelated_host )],
260+ )
261+
262+ self .assertEqual (handler ._routes .get_by_host_id (changed_host ).address , "new.com" )
263+ self .assertEqual (handler ._routes .get_by_host_id (unrelated_host ).address , "keep.com" )
264+
265+ def test_handle_change_preserves_preferred_route_for_same_host (self ):
266+ conn_a = str (uuid .uuid4 ())
267+ conn_b = str (uuid .uuid4 ())
268+ host_id = uuid .uuid4 ()
269+ config = ClientRoutesConfig ([
270+ ClientRouteProxy (conn_a ),
271+ ClientRouteProxy (conn_b ),
272+ ])
273+ handler = _ClientRoutesHandler (config )
274+ handler ._routes .update ([
275+ _Route (connection_id = conn_b , host_id = host_id ,
276+ address = "current.example.com" , port = 9042 ),
277+ ])
278+
279+ table_routes = [
280+ _Route (connection_id = conn_a , host_id = host_id ,
281+ address = "changed.example.com" , port = 9042 ),
282+ _Route (connection_id = conn_b , host_id = host_id ,
283+ address = "current.example.com" , port = 9042 ),
284+ ]
285+
286+ def wait_for_response (query_msg , timeout ):
287+ conn_placeholders = query_msg .query .split (
288+ "connection_id IN (" , 1 )[1 ].split (")" , 1 )[0 ].count ("?" )
289+ conn_ids = {
290+ param .decode ("utf-8" )
291+ for param in query_msg .query_params [:conn_placeholders ]
292+ }
293+ host_ids = {
294+ uuid .UUID (bytes = param )
295+ for param in query_msg .query_params [conn_placeholders :]
296+ }
297+ rows = [
298+ (route .connection_id , route .host_id , route .address ,
299+ route .port , route .port )
300+ for route in table_routes
301+ if route .connection_id in conn_ids and route .host_id in host_ids
302+ ]
303+ return Mock (
304+ column_names = ["connection_id" , "host_id" , "address" , "port" , "tls_port" ],
305+ parsed_rows = rows ,
306+ )
307+
308+ mock_conn = Mock ()
309+ mock_conn .wait_for_response .side_effect = wait_for_response
310+
311+ handler .handle_client_routes_change (
312+ mock_conn , 5.0 ,
313+ ClientRoutesChangeType .UPDATE_NODES ,
314+ connection_ids = [conn_a ],
315+ host_ids = [str (host_id )],
316+ )
317+
318+ route = handler ._routes .get_by_host_id (host_id )
319+ self .assertEqual (route .connection_id , conn_b )
320+ self .assertEqual (route .address , "current.example.com" )
321+
236322 @patch .object (_ClientRoutesHandler , '_query_all_routes_for_connections' )
237323 def test_handle_change_updates_when_no_host_ids (self , mock_query ):
238324 """When no host_ids are provided, routes should be fully replaced."""
0 commit comments