2026-04-14 19:43:20 +02:00

114 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
S17 No delivery peers at T0, relay peers appear later.
Setup: Sender starts isolated (no peers).
Action: send() is called immediately.
Then: A relay peer is started with the sender's multiaddr as a static peer,
causing both nodes to connect and the sender's retry loop to deliver.
Expected:
- send() returns Ok(RequestId) synchronously even with no peers.
- A MessagePropagatedEvent with the same RequestId arrives once the
relay peer joins.
- No MessageErrorEvent arrives before the Propagated event.
Reference: issue #163, scenario S17.
"""
import pytest
from src.node.wrappers_manager import WrapperManager
from src.node.wrappers_helpers import (
EventCollector,
get_node_multiaddr,
wait_for_propagated,
wait_for_error,
)
CONTENT_TOPIC = "/test/1/s17-relay-late-join/proto"
PROPAGATED_TIMEOUT_S = 30.0
class TestS17RelayPeersAppearLater:
@pytest.fixture
def sender_collector(self):
return EventCollector()
@pytest.fixture
def sender_node(self, node_config, sender_collector):
# node_config is provided by the conftest.py fixture;
# override only what differs from the default for an isolated sender.
node_config.update({"relay": True, "store": False, "discv5Discovery": False})
result = WrapperManager.create_and_start(config=node_config, event_cb=sender_collector.event_callback)
assert result.is_ok(), f"Failed to start sender: {result.err()}"
node = result.ok_value
yield node
node.stop_and_destroy()
def test_send_before_relay_peers_exist_then_peer_joins(self, sender_node, sender_collector, node_config):
"""
S17: send() is called while the sender has no peers.
A relay peer is then brought online with the sender's address as a
static peer, causing the sender's retry loop to deliver the message.
"""
# Step 1: send while isolated — must return Ok(RequestId) immediately
message = {
"contentTopic": CONTENT_TOPIC,
"payload": "UzE3IHJlbGF5IGxhdGUgam9pbg==", # base64("S17 relay late join")
}
send_result = sender_node.send_message(message)
assert send_result.is_ok(), f"send() must return Ok(RequestId) even with no peers, got: {send_result.err()}"
request_id = send_result.ok_value
assert request_id, "send() returned an empty RequestId"
# Step 2: get sender's multiaddr so the relay peer can dial back to it
sender_multiaddr = get_node_multiaddr(sender_node)
# Step 3: start the relay peer with the sender listed as a static peer.
# node_config produces a fresh config with its own free ports each call.
node_config.update({"relay": True, "store": False, "discv5Discovery": False})
node_config["staticPeers"] = [sender_multiaddr]
relay_peer_result = WrapperManager.create_and_start(config=node_config)
assert relay_peer_result.is_ok(), f"Failed to start relay peer: {relay_peer_result.err()}"
relay_peer = relay_peer_result.ok_value
try:
# Step 4: wait for a Propagated event — the sender's retry loop should
# deliver the message now that a relay peer is reachable
propagated_event = wait_for_propagated(
collector=sender_collector,
request_id=request_id,
timeout_s=PROPAGATED_TIMEOUT_S,
)
# Step 5: check no Error arrived before Propagated
error_event = wait_for_error(
collector=sender_collector,
request_id=request_id,
timeout_s=0,
)
# All events for this request must carry the same requestId
for event in sender_collector.get_events_for_request(request_id):
assert event.get("requestId") == request_id, f"Event carries wrong requestId: {event}"
assert propagated_event is not None, (
f"No MessagePropagatedEvent received within {PROPAGATED_TIMEOUT_S}s "
f"after relay peer joined. Collected events: {sender_collector.events}"
)
assert error_event is None, (
f"MessageErrorEvent arrived before Propagated — violates S17 expectations.\n"
f"Error : {error_event}\n"
f"Propagated: {propagated_event}"
)
finally:
relay_peer.stop_and_destroy()