mirror of
https://github.com/status-im/status-go.git
synced 2026-08-31 00:51:12 +00:00
tests-functional/ -> test/functional/ tests-unit-network/ -> test/unit-network/ No Go code changes beyond the two package paths. Every reference follows: Makefile targets, the pytest-lint and reliability workflows, the three Jenkinsfiles, the root Dockerfile, pyrightconfig.json, .gitignore, the benchmark and functional-test scripts, and the docs. All paths inside the moved directories are self-contained (docker compose uses `context: .`, the Python helpers resolve from __file__), so the extra level of nesting does not reach outside. refs #7067
117 lines
4.6 KiB
Python
117 lines
4.6 KiB
Python
import logging
|
|
import threading
|
|
|
|
import pytest
|
|
from tenacity import retry, stop_after_delay, wait_fixed
|
|
|
|
from clients.status_backend import StatusBackend
|
|
|
|
|
|
@pytest.mark.rpc
|
|
class TestDiscovery:
|
|
def test_discovery(self, backend_new_profile):
|
|
# Desired topology: 3 full nodes, 2 light nodes
|
|
full_count = 3
|
|
light_count = 2
|
|
total_nodes = full_count + light_count
|
|
|
|
nodes: dict[str, StatusBackend] = {}
|
|
full_ids: set[str] = set()
|
|
|
|
known_nodes = {
|
|
# Boot node in the fleet: every client is expected to discover and stay
|
|
# connected to it.
|
|
"16Uiu2HAm3vFYHkGRURyJ6F7bwDyzMLtPEuCg4DU89T7km2u8Fjyb": "boot-1",
|
|
# Store node: queried on demand by the StoreClient, so it is NOT expected
|
|
# to be a persistent peer. Kept here only to label it in the peer dumps.
|
|
"16Uiu2HAmCDqxtfF1DwBqs7UJ4TgSnjoh6j1RtE1hhQxLLao84jLi": "store",
|
|
}
|
|
|
|
def create_node(node_index: int, waku_light_client: bool):
|
|
backend = backend_new_profile(
|
|
f"node_{node_index}",
|
|
# We mix full and light clients in a single test.
|
|
# Light clients (edge nodes) will not discover each,
|
|
# but they must discover full clients.
|
|
waku_light_client=waku_light_client,
|
|
# Force the container to only have the docker compose network.
|
|
# Otherwise, advertised ENRs may contain the wrong IP address.
|
|
bridge_network=False,
|
|
)
|
|
peer_id = backend.wakuext_service.peer_id()
|
|
known_nodes[peer_id] = f"backend_{node_index}"
|
|
if not waku_light_client:
|
|
full_ids.add(peer_id)
|
|
nodes[peer_id] = backend
|
|
info = f"Peer ID: {peer_id}"
|
|
info += f", URL: {backend.url}"
|
|
if backend.container:
|
|
info += f", Container: {backend.container.short_id()}"
|
|
info += f", Type: {'full' if not waku_light_client else 'light'}"
|
|
logging.info(f"Backend {node_index} ready. {info}")
|
|
|
|
# Start threads to create nodes
|
|
logging.info("Starting threads to create full and light clients...")
|
|
threads = []
|
|
|
|
# First start full nodes
|
|
for i in range(full_count):
|
|
t = threading.Thread(target=create_node, args=(i, False))
|
|
t.daemon = True
|
|
t.start()
|
|
threads.append(t)
|
|
|
|
# Then start light nodes
|
|
for i in range(full_count, total_nodes):
|
|
t = threading.Thread(target=create_node, args=(i, True))
|
|
t.daemon = True
|
|
t.start()
|
|
threads.append(t)
|
|
|
|
for t in threads:
|
|
t.join()
|
|
|
|
assert len(nodes.keys()) == total_nodes, "Not all nodes created"
|
|
|
|
# Build sets for expectations
|
|
all_node_ids = set(nodes.keys())
|
|
# Only the boot node is expected as a persistent peer. The store node is
|
|
# contacted on demand by the StoreClient (there is no storenode cycle keeping
|
|
# it connected), so it is intentionally excluded from the expectations.
|
|
boot_ids = {k for k, v in known_nodes.items() if v == "boot-1"}
|
|
|
|
# Pre-build expected peers per node (static expectations)
|
|
expected_by_node: dict[str, set[str]] = {}
|
|
for pid in nodes.keys():
|
|
if pid in full_ids:
|
|
# Full clients should discover all other clients and boot nodes
|
|
expected = (all_node_ids | boot_ids) - {pid}
|
|
else:
|
|
# Light clients should discover only full clients and boot nodes
|
|
expected = boot_ids | full_ids
|
|
expected_by_node[pid] = expected
|
|
|
|
# Check using tenacity.retry, logs peers on each iteration
|
|
@retry(stop=stop_after_delay(120), wait=wait_fixed(1), reraise=True)
|
|
def assert_discovery():
|
|
all_ok = True
|
|
|
|
for peer_id, node in nodes.items():
|
|
# Fetch peers once per node per attempt
|
|
peers = set(node.wakuext_service.peers())
|
|
|
|
# Log peer names
|
|
peer_names = [known_nodes.get(peer, peer[-5:]) for peer in peers]
|
|
logging.info(f"Checking node {known_nodes[peer_id]} peers: {peer_names}")
|
|
|
|
if peers >= expected_by_node[peer_id]:
|
|
logging.info(f"Node {known_nodes[peer_id]} discovered peers as expected")
|
|
nodes.pop(peer_id)
|
|
continue
|
|
|
|
all_ok = False
|
|
|
|
assert all_ok, "Not all nodes discovered as expected"
|
|
|
|
assert_discovery()
|