6767# the command-execution workers are left running (their join then hangs to the pytest cap). Cover
6868# the FI's slowest reshard (ASM scale = 600s).
6969RESHARD_OP_TIMEOUT = 600
70- # Per-test cap for the OSS-cluster reshard tests: must exceed RESHARD_OP_TIMEOUT so a legitimately
71- # slow ASM scale runs to completion instead of being killed mid-reshard (only bites on the slow
72- # path; fast reshards are unaffected).
73- RESHARD_TEST_TIMEOUT = 660
70+ # Default op-wait for non-reshard (standalone / single-window) triggers: comfortably under the
71+ # standalone tests' 300s pytest cap so a stuck FI poll can't outlive the cap and block teardown on
72+ # thread.join(). The reshard tests pass RESHARD_OP_TIMEOUT explicitly.
73+ DEFAULT_TRIGGER_OP_TIMEOUT = 180
74+ # Per-test cap for the OSS-cluster reshard tests: must exceed the worst-case reshard wall time =
75+ # the trigger op-wait (RESHARD_OP_TIMEOUT) plus the post-join node-cache drain (SMIGRATED_TIMEOUT),
76+ # with margin, so a legitimately slow ASM scale runs to completion instead of being killed mid-way.
77+ # Only bites on the slow path; fast reshards are unaffected.
78+ RESHARD_TEST_TIMEOUT = RESHARD_OP_TIMEOUT + SMIGRATED_TIMEOUT + 180
7479
7580DEFAULT_BIND_TTL = 15
7681DEFAULT_STANDALONE_CLIENT_SOCKET_TIMEOUT = 1
@@ -124,7 +129,7 @@ def _trigger_effect(
124129 target_node : Optional [str ] = None ,
125130 empty_node : Optional [str ] = None ,
126131 skip_end_notification : bool = False ,
127- timeout : int = RESHARD_OP_TIMEOUT ,
132+ timeout : int = DEFAULT_TRIGGER_OP_TIMEOUT ,
128133 ):
129134 trigger_effect_action_id = ClusterOperations .trigger_effect (
130135 fault_injector = fault_injector_client ,
@@ -1454,14 +1459,12 @@ def _wait_for_node_cache_delta(
14541459 # A connection to a node being removed may error; that is expected.
14551460 pass
14561461 time .sleep (0.5 )
1457- # Best-effort: the caller asserts the exact delta next, which will fail loudly if the
1458- # cache never reconciled. Log so a timeout here is not silent.
1459- logging .warning (
1460- "Node cache did not reach %s (delta %s) within %ss; current size=%s" ,
1461- expected ,
1462- expected_delta ,
1463- timeout ,
1464- len (client .nodes_manager .nodes_cache ),
1462+ # Fail explicitly on a drain timeout so it surfaces as a clear "node cache did not
1463+ # reconcile" error, rather than silently returning and letting the caller's exact-delta
1464+ # assertion fail later with a misleading node-count message.
1465+ pytest .fail (
1466+ f"Node cache did not reach { expected } (delta { expected_delta } ) within { timeout } s; "
1467+ f"current size={ len (client .nodes_manager .nodes_cache )} "
14651468 )
14661469
14671470 @pytest .fixture (autouse = True )
@@ -1541,6 +1544,7 @@ def test_notification_handling_during_node_shuffle_no_node_replacement(
15411544 effect_name ,
15421545 trigger ,
15431546 ),
1547+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
15441548 )
15451549 self .maintenance_ops_threads .append (trigger_effect_thread )
15461550 trigger_effect_thread .start ()
@@ -1657,6 +1661,7 @@ def test_notification_handling_with_node_replace(
16571661 effect_name ,
16581662 trigger ,
16591663 ),
1664+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
16601665 )
16611666 self .maintenance_ops_threads .append (trigger_effect_thread )
16621667 trigger_effect_thread .start ()
@@ -1778,6 +1783,7 @@ def test_notification_handling_with_node_remove(
17781783 effect_name ,
17791784 trigger ,
17801785 ),
1786+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
17811787 )
17821788 self .maintenance_ops_threads .append (trigger_effect_thread )
17831789 trigger_effect_thread .start ()
@@ -1910,6 +1916,7 @@ def test_notification_handling_with_node_add(
19101916 effect_name ,
19111917 trigger ,
19121918 ),
1919+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
19131920 )
19141921 self .maintenance_ops_threads .append (trigger_effect_thread )
19151922 trigger_effect_thread .start ()
@@ -1928,6 +1935,17 @@ def test_notification_handling_with_node_add(
19281935 assert conn ._sock .gettimeout () == RELAXED_TIMEOUT
19291936 assert conn .should_reconnect () is False
19301937
1938+ # During SMIGRATING (before reconciliation) the added node is not in the cache yet: the
1939+ # cache size is unchanged and every initial node key is still present. Mirrors the same
1940+ # invariant asserted by test_notification_handling_with_node_remove.
1941+ assert len (initial_cluster_nodes ) == len (
1942+ cluster_client_maint_notifications .nodes_manager .nodes_cache
1943+ )
1944+ for node_key in initial_cluster_nodes .keys ():
1945+ assert (
1946+ node_key in cluster_client_maint_notifications .nodes_manager .nodes_cache
1947+ )
1948+
19311949 logging .info ("Waiting for SMIGRATED push notifications..." )
19321950 con_to_read_smigrated = random .choice (list (in_use_connections .values ()))
19331951 ClientValidations .wait_push_notification (
@@ -2049,6 +2067,7 @@ def test_new_connections_receive_last_smigrating_smigrated_notification(
20492067 effect_name ,
20502068 trigger ,
20512069 ),
2070+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
20522071 )
20532072
20542073 self .maintenance_ops_threads .append (trigger_effect_thread )
@@ -2223,6 +2242,7 @@ def execute_commands(duration: int, errors: Queue):
22232242 effect_name ,
22242243 trigger ,
22252244 ),
2245+ kwargs = {"timeout" : RESHARD_OP_TIMEOUT },
22262246 )
22272247 self .maintenance_ops_threads .append (trigger_effect_thread )
22282248 trigger_effect_thread .start ()
0 commit comments