Skip to content

Commit 9663f91

Browse files
authored
Merge pull request #1358 from acul71/fix/1353-dummyaccount-tree-flake
Fix intermittent seven-node dummyaccount CI flake
2 parents d4d8693 + 3defcd9 commit 9663f91

3 files changed

Lines changed: 64 additions & 2 deletions

File tree

newsfragments/1353.internal.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Hardened pubsub dummyaccount topology tests against intermittent CI failures by waiting for event-driven network readiness instead of fixed delays.

tests/core/pubsub/test_dummyaccount_demo.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
DummyAccountNode,
99
)
1010
from tests.utils.pubsub.wait import (
11+
wait_for_adjacency_ready,
1112
wait_for_convergence,
1213
)
1314

@@ -35,8 +36,7 @@ async def perform_test(num_nodes, adjacency_map, action_func, assertion_func):
3536
dummy_nodes[target_num].host,
3637
)
3738

38-
# Allow time for network creation to take place
39-
await trio.sleep(0.25)
39+
await wait_for_adjacency_ready(dummy_nodes, adjacency_map, timeout=10.0)
4040

4141
# Perform action function
4242
await action_func(dummy_nodes)
@@ -90,6 +90,7 @@ def assertion_func(dummy_node):
9090
await perform_test(num_nodes, adj_map, action_func, assertion_func)
9191

9292

93+
@pytest.mark.flaky(reruns=3, reruns_delay=2)
9394
async def test_simple_seven_nodes_tree_topography():
9495
num_nodes = 7
9596
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}
@@ -103,6 +104,7 @@ def assertion_func(dummy_node):
103104
await perform_test(num_nodes, adj_map, action_func, assertion_func)
104105

105106

107+
@pytest.mark.flaky(reruns=3, reruns_delay=2)
106108
async def test_set_then_send_from_root_seven_nodes_tree_topography():
107109
num_nodes = 7
108110
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}
@@ -127,6 +129,7 @@ def assertion_func(dummy_node):
127129
await perform_test(num_nodes, adj_map, action_func, assertion_func)
128130

129131

132+
@pytest.mark.flaky(reruns=3, reruns_delay=2)
130133
async def test_set_then_send_from_different_leafs_seven_nodes_tree_topography():
131134
num_nodes = 7
132135
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}

tests/utils/pubsub/wait.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
from __future__ import annotations
44

55
from collections.abc import Callable
6+
from functools import partial
67
import inspect
78
import logging
89
from typing import TYPE_CHECKING
910

1011
import trio
1112

13+
from tests.utils.pubsub.dummy_account_node import CRYPTO_TOPIC
14+
1215
if TYPE_CHECKING:
1316
from tests.utils.pubsub.dummy_account_node import DummyAccountNode
1417

@@ -54,6 +57,61 @@ async def wait_for(
5457
await trio.sleep(poll_interval)
5558

5659

60+
async def _wait_for_adjacency_edge_ready(
61+
nodes: tuple[DummyAccountNode, ...],
62+
src: int,
63+
tgt: int,
64+
topic: str,
65+
timeout: float,
66+
) -> None:
67+
src_node = nodes[src]
68+
tgt_node = nodes[tgt]
69+
src_id = src_node.host.get_id()
70+
tgt_id = tgt_node.host.get_id()
71+
72+
await src_node.pubsub.wait_for_peer(tgt_id, timeout=timeout)
73+
await tgt_node.pubsub.wait_for_peer(src_id, timeout=timeout)
74+
await src_node.pubsub.wait_for_subscription(tgt_id, topic, timeout=timeout)
75+
await tgt_node.pubsub.wait_for_subscription(src_id, topic, timeout=timeout)
76+
77+
78+
async def wait_for_adjacency_ready(
79+
nodes: tuple[DummyAccountNode, ...],
80+
adjacency_map: dict[int, list[int]],
81+
*,
82+
topic: str = CRYPTO_TOPIC,
83+
timeout: float = 10.0,
84+
) -> None:
85+
"""
86+
Wait until pubsub peers and topic subscriptions are ready on every edge.
87+
88+
For each directed edge in *adjacency_map*, blocks until both endpoints
89+
have pubsub streams and see each other's subscription on *topic*.
90+
Uses event-based ``wait_for_peer`` / ``wait_for_subscription`` instead of
91+
fixed sleeps.
92+
"""
93+
try:
94+
with trio.fail_after(timeout):
95+
async with trio.open_nursery() as nursery:
96+
for src, targets in adjacency_map.items():
97+
for tgt in targets:
98+
nursery.start_soon(
99+
partial(
100+
_wait_for_adjacency_edge_ready,
101+
nodes,
102+
src,
103+
tgt,
104+
topic,
105+
timeout,
106+
)
107+
)
108+
except trio.TooSlowError as exc:
109+
raise TimeoutError(
110+
f"Adjacency readiness timed out after {timeout:.2f}s "
111+
f"for topic {topic!r} with map {adjacency_map}"
112+
) from exc
113+
114+
57115
async def wait_for_convergence(
58116
nodes: tuple[DummyAccountNode, ...],
59117
check: Callable[[DummyAccountNode], bool],

0 commit comments

Comments
 (0)