mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
Fix all modules except for security
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import trio
|
||||
import secrets
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.host.ping import ID, PING_LENGTH
|
||||
from libp2p.tools.factories import host_pair_factory
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from libp2p.host.exceptions import ConnectionFailure
|
||||
from libp2p.peer.peerinfo import PeerInfo
|
||||
from libp2p.routing.kademlia.kademlia_peer_router import peer_info_to_str
|
||||
from libp2p.tools.utils import (
|
||||
set_up_nodes_by_transport_and_disc_opt,
|
||||
set_up_nodes_by_transport_opt,
|
||||
set_up_routers,
|
||||
)
|
||||
from libp2p.tools.factories import RoutedHostFactory
|
||||
|
||||
|
||||
# FIXME:
|
||||
|
||||
# TODO: Kademlia is full of asyncio code. Skip it for now
|
||||
@pytest.mark.skip
|
||||
@pytest.mark.trio
|
||||
async def test_host_routing_success(is_host_secure):
|
||||
async with RoutedHostFactory.create_batch_and_listen(
|
||||
is_host_secure, 2
|
||||
) as routed_hosts:
|
||||
# Set routing info
|
||||
await routed_hosts[0]._router.server.set(
|
||||
routed_hosts[0].get_id().xor_id,
|
||||
peer_info_to_str(
|
||||
PeerInfo(routed_hosts[0].get_id(), routed_hosts[0].get_addrs())
|
||||
),
|
||||
)
|
||||
await routed_hosts[1]._router.server.set(
|
||||
routed_hosts[1].get_id().xor_id,
|
||||
peer_info_to_str(
|
||||
PeerInfo(routed_hosts[1].get_id(), routed_hosts[1].get_addrs())
|
||||
),
|
||||
)
|
||||
|
||||
# forces to use routing as no addrs are provided
|
||||
await routed_hosts[0].connect(PeerInfo(routed_hosts[1].get_id(), []))
|
||||
await routed_hosts[1].connect(PeerInfo(routed_hosts[0].get_id(), []))
|
||||
|
||||
|
||||
# TODO: Kademlia is full of asyncio code. Skip it for now
|
||||
@pytest.mark.skip
|
||||
@pytest.mark.trio
|
||||
async def test_host_routing_fail():
|
||||
routers = await set_up_routers()
|
||||
transports = [["/ip4/127.0.0.1/tcp/0"], ["/ip4/127.0.0.1/tcp/0"]]
|
||||
transport_disc_opt_list = zip(transports, routers)
|
||||
(host_a, host_b) = await set_up_nodes_by_transport_and_disc_opt(
|
||||
transport_disc_opt_list
|
||||
)
|
||||
|
||||
host_c = (await set_up_nodes_by_transport_opt([["/ip4/127.0.0.1/tcp/0"]]))[0]
|
||||
|
||||
# Set routing info
|
||||
await routers[0].server.set(
|
||||
host_a.get_id().xor_id,
|
||||
peer_info_to_str(PeerInfo(host_a.get_id(), host_a.get_addrs())),
|
||||
)
|
||||
await routers[1].server.set(
|
||||
host_b.get_id().xor_id,
|
||||
peer_info_to_str(PeerInfo(host_b.get_id(), host_b.get_addrs())),
|
||||
)
|
||||
|
||||
# routing fails because host_c does not use routing
|
||||
with pytest.raises(ConnectionFailure):
|
||||
await host_a.connect(PeerInfo(host_c.get_id(), []))
|
||||
with pytest.raises(ConnectionFailure):
|
||||
await host_b.connect(PeerInfo(host_c.get_id(), []))
|
||||
|
||||
# Clean up
|
||||
routers[0].server.stop()
|
||||
routers[1].server.stop()
|
||||
@ -4,7 +4,6 @@ from libp2p.host.exceptions import StreamFailure
|
||||
from libp2p.tools.factories import HostFactory
|
||||
from libp2p.tools.utils import create_echo_stream_handler
|
||||
|
||||
|
||||
PROTOCOL_ECHO = "/echo/1.0.0"
|
||||
PROTOCOL_POTATO = "/potato/1.0.0"
|
||||
PROTOCOL_FOO = "/foo/1.0.0"
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from libp2p.tools.constants import GOSSIPSUB_PARAMS
|
||||
from libp2p.tools.factories import FloodsubFactory, GossipsubFactory, PubsubFactory
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pubsub_cache_size():
|
||||
return None # default
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def gossipsub_params():
|
||||
return GOSSIPSUB_PARAMS
|
||||
|
||||
|
||||
# @pytest.fixture
|
||||
# def pubsubs_gsub(num_hosts, hosts, pubsub_cache_size, gossipsub_params):
|
||||
# gossipsubs = GossipsubFactory.create_batch(num_hosts, **gossipsub_params._asdict())
|
||||
# _pubsubs_gsub = _make_pubsubs(hosts, gossipsubs, pubsub_cache_size)
|
||||
# yield _pubsubs_gsub
|
||||
# # TODO: Clean up
|
||||
@ -1,19 +1,10 @@
|
||||
import asyncio
|
||||
from threading import Thread
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.tools.pubsub.dummy_account_node import DummyAccountNode
|
||||
from libp2p.tools.utils import connect
|
||||
|
||||
|
||||
def create_setup_in_new_thread_func(dummy_node):
|
||||
def setup_in_new_thread():
|
||||
asyncio.ensure_future(dummy_node.setup_crypto_networking())
|
||||
|
||||
return setup_in_new_thread
|
||||
|
||||
|
||||
async def perform_test(num_nodes, adjacency_map, action_func, assertion_func):
|
||||
"""
|
||||
Helper function to allow for easy construction of custom tests for dummy
|
||||
@ -26,47 +17,35 @@ async def perform_test(num_nodes, adjacency_map, action_func, assertion_func):
|
||||
:param assertion_func: assertions for testing the results of the actions are correct
|
||||
"""
|
||||
|
||||
# Create nodes
|
||||
dummy_nodes = []
|
||||
for _ in range(num_nodes):
|
||||
dummy_nodes.append(await DummyAccountNode.create())
|
||||
async with DummyAccountNode.create(num_nodes) as dummy_nodes:
|
||||
# Create connections between nodes according to `adjacency_map`
|
||||
async with trio.open_nursery() as nursery:
|
||||
for source_num in adjacency_map:
|
||||
target_nums = adjacency_map[source_num]
|
||||
for target_num in target_nums:
|
||||
nursery.start_soon(
|
||||
connect,
|
||||
dummy_nodes[source_num].host,
|
||||
dummy_nodes[target_num].host,
|
||||
)
|
||||
|
||||
# Create network
|
||||
for source_num in adjacency_map:
|
||||
target_nums = adjacency_map[source_num]
|
||||
for target_num in target_nums:
|
||||
await connect(
|
||||
dummy_nodes[source_num].libp2p_node, dummy_nodes[target_num].libp2p_node
|
||||
)
|
||||
# Allow time for network creation to take place
|
||||
await trio.sleep(0.25)
|
||||
|
||||
# Allow time for network creation to take place
|
||||
await asyncio.sleep(0.25)
|
||||
# Perform action function
|
||||
await action_func(dummy_nodes)
|
||||
|
||||
# Start a thread for each node so that each node can listen and respond
|
||||
# to messages on its own thread, which will avoid waiting indefinitely
|
||||
# on the main thread. On this thread, call the setup func for the node,
|
||||
# which subscribes the node to the CRYPTO_TOPIC topic
|
||||
for dummy_node in dummy_nodes:
|
||||
thread = Thread(target=create_setup_in_new_thread_func(dummy_node))
|
||||
thread.run()
|
||||
# Allow time for action function to be performed (i.e. messages to propogate)
|
||||
await trio.sleep(1)
|
||||
|
||||
# Allow time for nodes to subscribe to CRYPTO_TOPIC topic
|
||||
await asyncio.sleep(0.25)
|
||||
|
||||
# Perform action function
|
||||
await action_func(dummy_nodes)
|
||||
|
||||
# Allow time for action function to be performed (i.e. messages to propogate)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Perform assertion function
|
||||
for dummy_node in dummy_nodes:
|
||||
assertion_func(dummy_node)
|
||||
# Perform assertion function
|
||||
for dummy_node in dummy_nodes:
|
||||
assertion_func(dummy_node)
|
||||
|
||||
# Success, terminate pending tasks.
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_simple_two_nodes():
|
||||
num_nodes = 2
|
||||
adj_map = {0: [1]}
|
||||
@ -80,7 +59,7 @@ async def test_simple_two_nodes():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_simple_three_nodes_line_topography():
|
||||
num_nodes = 3
|
||||
adj_map = {0: [1], 1: [2]}
|
||||
@ -94,7 +73,7 @@ async def test_simple_three_nodes_line_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_simple_three_nodes_triangle_topography():
|
||||
num_nodes = 3
|
||||
adj_map = {0: [1, 2], 1: [2]}
|
||||
@ -108,7 +87,7 @@ async def test_simple_three_nodes_triangle_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_simple_seven_nodes_tree_topography():
|
||||
num_nodes = 7
|
||||
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}
|
||||
@ -122,14 +101,14 @@ async def test_simple_seven_nodes_tree_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_set_then_send_from_root_seven_nodes_tree_topography():
|
||||
num_nodes = 7
|
||||
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}
|
||||
|
||||
async def action_func(dummy_nodes):
|
||||
await dummy_nodes[0].publish_set_crypto("aspyn", 20)
|
||||
await asyncio.sleep(0.25)
|
||||
await trio.sleep(0.25)
|
||||
await dummy_nodes[0].publish_send_crypto("aspyn", "alex", 5)
|
||||
|
||||
def assertion_func(dummy_node):
|
||||
@ -139,14 +118,14 @@ async def test_set_then_send_from_root_seven_nodes_tree_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_set_then_send_from_different_leafs_seven_nodes_tree_topography():
|
||||
num_nodes = 7
|
||||
adj_map = {0: [1, 2], 1: [3, 4], 2: [5, 6]}
|
||||
|
||||
async def action_func(dummy_nodes):
|
||||
await dummy_nodes[6].publish_set_crypto("aspyn", 20)
|
||||
await asyncio.sleep(0.25)
|
||||
await trio.sleep(0.25)
|
||||
await dummy_nodes[4].publish_send_crypto("aspyn", "alex", 5)
|
||||
|
||||
def assertion_func(dummy_node):
|
||||
@ -156,7 +135,7 @@ async def test_set_then_send_from_different_leafs_seven_nodes_tree_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_simple_five_nodes_ring_topography():
|
||||
num_nodes = 5
|
||||
adj_map = {0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}
|
||||
@ -170,14 +149,14 @@ async def test_simple_five_nodes_ring_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_set_then_send_from_diff_nodes_five_nodes_ring_topography():
|
||||
num_nodes = 5
|
||||
adj_map = {0: [1], 1: [2], 2: [3], 3: [4], 4: [0]}
|
||||
|
||||
async def action_func(dummy_nodes):
|
||||
await dummy_nodes[0].publish_set_crypto("alex", 20)
|
||||
await asyncio.sleep(0.25)
|
||||
await trio.sleep(0.25)
|
||||
await dummy_nodes[3].publish_send_crypto("alex", "rob", 12)
|
||||
|
||||
def assertion_func(dummy_node):
|
||||
@ -187,7 +166,7 @@ async def test_set_then_send_from_diff_nodes_five_nodes_ring_topography():
|
||||
await perform_test(num_nodes, adj_map, action_func, assertion_func)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
@pytest.mark.slow
|
||||
async def test_set_then_send_from_five_diff_nodes_five_nodes_ring_topography():
|
||||
num_nodes = 5
|
||||
@ -195,13 +174,13 @@ async def test_set_then_send_from_five_diff_nodes_five_nodes_ring_topography():
|
||||
|
||||
async def action_func(dummy_nodes):
|
||||
await dummy_nodes[0].publish_set_crypto("alex", 20)
|
||||
await asyncio.sleep(1)
|
||||
await trio.sleep(1)
|
||||
await dummy_nodes[1].publish_send_crypto("alex", "rob", 3)
|
||||
await asyncio.sleep(1)
|
||||
await trio.sleep(1)
|
||||
await dummy_nodes[2].publish_send_crypto("rob", "aspyn", 2)
|
||||
await asyncio.sleep(1)
|
||||
await trio.sleep(1)
|
||||
await dummy_nodes[3].publish_send_crypto("aspyn", "zx", 1)
|
||||
await asyncio.sleep(1)
|
||||
await trio.sleep(1)
|
||||
await dummy_nodes[4].publish_send_crypto("zx", "raul", 1)
|
||||
|
||||
def assertion_func(dummy_node):
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import asyncio
|
||||
import functools
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.tools.factories import FloodsubFactory
|
||||
from libp2p.tools.factories import PubsubFactory
|
||||
from libp2p.tools.pubsub.floodsub_integration_test_settings import (
|
||||
floodsub_protocol_pytest_params,
|
||||
perform_test_from_obj,
|
||||
@ -11,79 +12,83 @@ from libp2p.tools.pubsub.floodsub_integration_test_settings import (
|
||||
from libp2p.tools.utils import connect
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (2,))
|
||||
@pytest.mark.asyncio
|
||||
async def test_simple_two_nodes(pubsubs_fsub):
|
||||
topic = "my_topic"
|
||||
data = b"some data"
|
||||
@pytest.mark.trio
|
||||
async def test_simple_two_nodes():
|
||||
async with PubsubFactory.create_batch_with_floodsub(2) as pubsubs_fsub:
|
||||
topic = "my_topic"
|
||||
data = b"some data"
|
||||
|
||||
await connect(pubsubs_fsub[0].host, pubsubs_fsub[1].host)
|
||||
await asyncio.sleep(0.25)
|
||||
await connect(pubsubs_fsub[0].host, pubsubs_fsub[1].host)
|
||||
await trio.sleep(0.25)
|
||||
|
||||
sub_b = await pubsubs_fsub[1].subscribe(topic)
|
||||
# Sleep to let a know of b's subscription
|
||||
await asyncio.sleep(0.25)
|
||||
sub_b = await pubsubs_fsub[1].subscribe(topic)
|
||||
# Sleep to let a know of b's subscription
|
||||
await trio.sleep(0.25)
|
||||
|
||||
await pubsubs_fsub[0].publish(topic, data)
|
||||
await pubsubs_fsub[0].publish(topic, data)
|
||||
|
||||
res_b = await sub_b.get()
|
||||
res_b = await sub_b.receive()
|
||||
|
||||
# Check that the msg received by node_b is the same
|
||||
# as the message sent by node_a
|
||||
assert ID(res_b.from_id) == pubsubs_fsub[0].host.get_id()
|
||||
assert res_b.data == data
|
||||
assert res_b.topicIDs == [topic]
|
||||
|
||||
# Success, terminate pending tasks.
|
||||
# Check that the msg received by node_b is the same
|
||||
# as the message sent by node_a
|
||||
assert ID(res_b.from_id) == pubsubs_fsub[0].host.get_id()
|
||||
assert res_b.data == data
|
||||
assert res_b.topicIDs == [topic]
|
||||
|
||||
|
||||
# Initialize Pubsub with a cache_size of 4
|
||||
@pytest.mark.parametrize("num_hosts, pubsub_cache_size", ((2, 4),))
|
||||
@pytest.mark.asyncio
|
||||
async def test_lru_cache_two_nodes(pubsubs_fsub, monkeypatch):
|
||||
@pytest.mark.trio
|
||||
async def test_lru_cache_two_nodes(monkeypatch):
|
||||
# two nodes with cache_size of 4
|
||||
# `node_a` send the following messages to node_b
|
||||
message_indices = [1, 1, 2, 1, 3, 1, 4, 1, 5, 1]
|
||||
# `node_b` should only receive the following
|
||||
expected_received_indices = [1, 2, 3, 4, 5, 1]
|
||||
async with PubsubFactory.create_batch_with_floodsub(
|
||||
2, cache_size=4
|
||||
) as pubsubs_fsub:
|
||||
# `node_a` send the following messages to node_b
|
||||
message_indices = [1, 1, 2, 1, 3, 1, 4, 1, 5, 1]
|
||||
# `node_b` should only receive the following
|
||||
expected_received_indices = [1, 2, 3, 4, 5, 1]
|
||||
|
||||
topic = "my_topic"
|
||||
topic = "my_topic"
|
||||
|
||||
# Mock `get_msg_id` to make us easier to manipulate `msg_id` by `data`.
|
||||
def get_msg_id(msg):
|
||||
# Originally it is `(msg.seqno, msg.from_id)`
|
||||
return (msg.data, msg.from_id)
|
||||
# Mock `get_msg_id` to make us easier to manipulate `msg_id` by `data`.
|
||||
def get_msg_id(msg):
|
||||
# Originally it is `(msg.seqno, msg.from_id)`
|
||||
return (msg.data, msg.from_id)
|
||||
|
||||
import libp2p.pubsub.pubsub
|
||||
import libp2p.pubsub.pubsub
|
||||
|
||||
monkeypatch.setattr(libp2p.pubsub.pubsub, "get_msg_id", get_msg_id)
|
||||
monkeypatch.setattr(libp2p.pubsub.pubsub, "get_msg_id", get_msg_id)
|
||||
|
||||
await connect(pubsubs_fsub[0].host, pubsubs_fsub[1].host)
|
||||
await asyncio.sleep(0.25)
|
||||
await connect(pubsubs_fsub[0].host, pubsubs_fsub[1].host)
|
||||
await trio.sleep(0.25)
|
||||
|
||||
sub_b = await pubsubs_fsub[1].subscribe(topic)
|
||||
await asyncio.sleep(0.25)
|
||||
sub_b = await pubsubs_fsub[1].subscribe(topic)
|
||||
await trio.sleep(0.25)
|
||||
|
||||
def _make_testing_data(i: int) -> bytes:
|
||||
num_int_bytes = 4
|
||||
if i >= 2 ** (num_int_bytes * 8):
|
||||
raise ValueError("integer is too large to be serialized")
|
||||
return b"data" + i.to_bytes(num_int_bytes, "big")
|
||||
def _make_testing_data(i: int) -> bytes:
|
||||
num_int_bytes = 4
|
||||
if i >= 2 ** (num_int_bytes * 8):
|
||||
raise ValueError("integer is too large to be serialized")
|
||||
return b"data" + i.to_bytes(num_int_bytes, "big")
|
||||
|
||||
for index in message_indices:
|
||||
await pubsubs_fsub[0].publish(topic, _make_testing_data(index))
|
||||
await asyncio.sleep(0.25)
|
||||
for index in message_indices:
|
||||
await pubsubs_fsub[0].publish(topic, _make_testing_data(index))
|
||||
await trio.sleep(0.25)
|
||||
|
||||
for index in expected_received_indices:
|
||||
res_b = await sub_b.get()
|
||||
assert res_b.data == _make_testing_data(index)
|
||||
assert sub_b.empty()
|
||||
for index in expected_received_indices:
|
||||
res_b = await sub_b.receive()
|
||||
assert res_b.data == _make_testing_data(index)
|
||||
|
||||
# Success, terminate pending tasks.
|
||||
with pytest.raises(trio.WouldBlock):
|
||||
sub_b.receive_nowait()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params)
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
@pytest.mark.slow
|
||||
async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
|
||||
await perform_test_from_obj(test_case_obj, FloodsubFactory)
|
||||
async def test_gossipsub_run_with_floodsub_tests(test_case_obj, is_host_secure):
|
||||
await perform_test_from_obj(
|
||||
test_case_obj,
|
||||
functools.partial(
|
||||
PubsubFactory.create_batch_with_floodsub, is_secure=is_host_secure
|
||||
),
|
||||
)
|
||||
|
||||
@ -1,368 +1,350 @@
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.tools.constants import GossipsubParams
|
||||
from libp2p.tools.factories import PubsubFactory
|
||||
from libp2p.tools.pubsub.utils import dense_connect, one_to_all_connect
|
||||
from libp2p.tools.utils import connect
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_hosts, gossipsub_params",
|
||||
((4, GossipsubParams(degree=4, degree_low=3, degree_high=5)),),
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_join(num_hosts, hosts, pubsubs_gsub):
|
||||
gossipsubs = tuple(pubsub.router for pubsub in pubsubs_gsub)
|
||||
hosts_indices = list(range(num_hosts))
|
||||
@pytest.mark.trio
|
||||
async def test_join():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(
|
||||
4, degree=4, degree_low=3, degree_high=5
|
||||
) as pubsubs_gsub:
|
||||
gossipsubs = [pubsub.router for pubsub in pubsubs_gsub]
|
||||
hosts = [pubsub.host for pubsub in pubsubs_gsub]
|
||||
hosts_indices = list(range(len(pubsubs_gsub)))
|
||||
|
||||
topic = "test_join"
|
||||
central_node_index = 0
|
||||
# Remove index of central host from the indices
|
||||
hosts_indices.remove(central_node_index)
|
||||
num_subscribed_peer = 2
|
||||
subscribed_peer_indices = random.sample(hosts_indices, num_subscribed_peer)
|
||||
topic = "test_join"
|
||||
central_node_index = 0
|
||||
# Remove index of central host from the indices
|
||||
hosts_indices.remove(central_node_index)
|
||||
num_subscribed_peer = 2
|
||||
subscribed_peer_indices = random.sample(hosts_indices, num_subscribed_peer)
|
||||
|
||||
# All pubsub except the one of central node subscribe to topic
|
||||
for i in subscribed_peer_indices:
|
||||
await pubsubs_gsub[i].subscribe(topic)
|
||||
# All pubsub except the one of central node subscribe to topic
|
||||
for i in subscribed_peer_indices:
|
||||
await pubsubs_gsub[i].subscribe(topic)
|
||||
|
||||
# Connect central host to all other hosts
|
||||
await one_to_all_connect(hosts, central_node_index)
|
||||
# Connect central host to all other hosts
|
||||
await one_to_all_connect(hosts, central_node_index)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Central node publish to the topic so that this topic
|
||||
# is added to central node's fanout
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[central_node_index].publish(topic, b"data")
|
||||
|
||||
# Check that the gossipsub of central node has fanout for the topic
|
||||
assert topic in gossipsubs[central_node_index].fanout
|
||||
# Check that the gossipsub of central node does not have a mesh for the topic
|
||||
assert topic not in gossipsubs[central_node_index].mesh
|
||||
|
||||
# Central node subscribes the topic
|
||||
await pubsubs_gsub[central_node_index].subscribe(topic)
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Check that the gossipsub of central node no longer has fanout for the topic
|
||||
assert topic not in gossipsubs[central_node_index].fanout
|
||||
|
||||
for i in hosts_indices:
|
||||
if i in subscribed_peer_indices:
|
||||
assert hosts[i].get_id() in gossipsubs[central_node_index].mesh[topic]
|
||||
assert hosts[central_node_index].get_id() in gossipsubs[i].mesh[topic]
|
||||
else:
|
||||
assert hosts[i].get_id() not in gossipsubs[central_node_index].mesh[topic]
|
||||
assert topic not in gossipsubs[i].mesh
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (1,))
|
||||
@pytest.mark.asyncio
|
||||
async def test_leave(pubsubs_gsub):
|
||||
gossipsub = pubsubs_gsub[0].router
|
||||
topic = "test_leave"
|
||||
|
||||
assert topic not in gossipsub.mesh
|
||||
|
||||
await gossipsub.join(topic)
|
||||
assert topic in gossipsub.mesh
|
||||
|
||||
await gossipsub.leave(topic)
|
||||
assert topic not in gossipsub.mesh
|
||||
|
||||
# Test re-leave
|
||||
await gossipsub.leave(topic)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (2,))
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_graft(pubsubs_gsub, hosts, event_loop, monkeypatch):
|
||||
gossipsubs = tuple(pubsub.router for pubsub in pubsubs_gsub)
|
||||
|
||||
index_alice = 0
|
||||
id_alice = hosts[index_alice].get_id()
|
||||
index_bob = 1
|
||||
id_bob = hosts[index_bob].get_id()
|
||||
await connect(hosts[index_alice], hosts[index_bob])
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(2)
|
||||
|
||||
topic = "test_handle_graft"
|
||||
# Only lice subscribe to the topic
|
||||
await gossipsubs[index_alice].join(topic)
|
||||
|
||||
# Monkey patch bob's `emit_prune` function so we can
|
||||
# check if it is called in `handle_graft`
|
||||
event_emit_prune = asyncio.Event()
|
||||
|
||||
async def emit_prune(topic, sender_peer_id):
|
||||
event_emit_prune.set()
|
||||
|
||||
monkeypatch.setattr(gossipsubs[index_bob], "emit_prune", emit_prune)
|
||||
|
||||
# Check that alice is bob's peer but not his mesh peer
|
||||
assert id_alice in gossipsubs[index_bob].peers_gossipsub
|
||||
assert topic not in gossipsubs[index_bob].mesh
|
||||
|
||||
await gossipsubs[index_alice].emit_graft(topic, id_bob)
|
||||
|
||||
# Check that `emit_prune` is called
|
||||
await asyncio.wait_for(event_emit_prune.wait(), timeout=1, loop=event_loop)
|
||||
assert event_emit_prune.is_set()
|
||||
|
||||
# Check that bob is alice's peer but not her mesh peer
|
||||
assert topic in gossipsubs[index_alice].mesh
|
||||
assert id_bob not in gossipsubs[index_alice].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].peers_gossipsub
|
||||
|
||||
await gossipsubs[index_bob].emit_graft(topic, id_alice)
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Check that bob is now alice's mesh peer
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_hosts, gossipsub_params", ((2, GossipsubParams(heartbeat_interval=3)),)
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_prune(pubsubs_gsub, hosts):
|
||||
gossipsubs = tuple(pubsub.router for pubsub in pubsubs_gsub)
|
||||
|
||||
index_alice = 0
|
||||
id_alice = hosts[index_alice].get_id()
|
||||
index_bob = 1
|
||||
id_bob = hosts[index_bob].get_id()
|
||||
|
||||
topic = "test_handle_prune"
|
||||
for pubsub in pubsubs_gsub:
|
||||
await pubsub.subscribe(topic)
|
||||
|
||||
await connect(hosts[index_alice], hosts[index_bob])
|
||||
|
||||
# Wait 3 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(3)
|
||||
|
||||
# Check that they are each other's mesh peer
|
||||
assert id_alice in gossipsubs[index_bob].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
# alice emit prune message to bob, alice should be removed
|
||||
# from bob's mesh peer
|
||||
await gossipsubs[index_alice].emit_prune(topic, id_bob)
|
||||
|
||||
# FIXME: This test currently works because the heartbeat interval
|
||||
# is increased to 3 seconds, so alice won't get add back into
|
||||
# bob's mesh peer during heartbeat.
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Check that alice is no longer bob's mesh peer
|
||||
assert id_alice not in gossipsubs[index_bob].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (10,))
|
||||
@pytest.mark.asyncio
|
||||
async def test_dense(num_hosts, pubsubs_gsub, hosts):
|
||||
num_msgs = 5
|
||||
|
||||
# All pubsub subscribe to foobar
|
||||
queues = []
|
||||
for pubsub in pubsubs_gsub:
|
||||
q = await pubsub.subscribe("foobar")
|
||||
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
|
||||
# Densely connect libp2p hosts in a random way
|
||||
await dense_connect(hosts)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(2)
|
||||
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
|
||||
# randomly pick a message origin
|
||||
origin_idx = random.randint(0, num_hosts - 1)
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(2)
|
||||
|
||||
# Central node publish to the topic so that this topic
|
||||
# is added to central node's fanout
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish("foobar", msg_content)
|
||||
await pubsubs_gsub[central_node_index].publish(topic, b"data")
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.get()
|
||||
assert msg.data == msg_content
|
||||
# Check that the gossipsub of central node has fanout for the topic
|
||||
assert topic in gossipsubs[central_node_index].fanout
|
||||
# Check that the gossipsub of central node does not have a mesh for the topic
|
||||
assert topic not in gossipsubs[central_node_index].mesh
|
||||
|
||||
# Central node subscribes the topic
|
||||
await pubsubs_gsub[central_node_index].subscribe(topic)
|
||||
|
||||
await trio.sleep(2)
|
||||
|
||||
# Check that the gossipsub of central node no longer has fanout for the topic
|
||||
assert topic not in gossipsubs[central_node_index].fanout
|
||||
|
||||
for i in hosts_indices:
|
||||
if i in subscribed_peer_indices:
|
||||
assert hosts[i].get_id() in gossipsubs[central_node_index].mesh[topic]
|
||||
assert hosts[central_node_index].get_id() in gossipsubs[i].mesh[topic]
|
||||
else:
|
||||
assert (
|
||||
hosts[i].get_id() not in gossipsubs[central_node_index].mesh[topic]
|
||||
)
|
||||
assert topic not in gossipsubs[i].mesh
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (10,))
|
||||
@pytest.mark.asyncio
|
||||
async def test_fanout(hosts, pubsubs_gsub):
|
||||
num_msgs = 5
|
||||
@pytest.mark.trio
|
||||
async def test_leave():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(1) as pubsubs_gsub:
|
||||
gossipsub = pubsubs_gsub[0].router
|
||||
topic = "test_leave"
|
||||
|
||||
# All pubsub subscribe to foobar except for `pubsubs_gsub[0]`
|
||||
queues = []
|
||||
for i in range(1, len(pubsubs_gsub)):
|
||||
q = await pubsubs_gsub[i].subscribe("foobar")
|
||||
assert topic not in gossipsub.mesh
|
||||
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
await gossipsub.join(topic)
|
||||
assert topic in gossipsub.mesh
|
||||
|
||||
# Sparsely connect libp2p hosts in random way
|
||||
await dense_connect(hosts)
|
||||
await gossipsub.leave(topic)
|
||||
assert topic not in gossipsub.mesh
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(2)
|
||||
|
||||
topic = "foobar"
|
||||
# Send messages with origin not subscribed
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.get()
|
||||
assert msg.data == msg_content
|
||||
|
||||
# Subscribe message origin
|
||||
queues.insert(0, await pubsubs_gsub[0].subscribe(topic))
|
||||
|
||||
# Send messages again
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"bar " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.get()
|
||||
assert msg.data == msg_content
|
||||
# Test re-leave
|
||||
await gossipsub.leave(topic)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("num_hosts", (10,))
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
async def test_handle_graft(monkeypatch):
|
||||
async with PubsubFactory.create_batch_with_gossipsub(2) as pubsubs_gsub:
|
||||
gossipsubs = tuple(pubsub.router for pubsub in pubsubs_gsub)
|
||||
|
||||
index_alice = 0
|
||||
id_alice = pubsubs_gsub[index_alice].my_id
|
||||
index_bob = 1
|
||||
id_bob = pubsubs_gsub[index_bob].my_id
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(2)
|
||||
|
||||
topic = "test_handle_graft"
|
||||
# Only lice subscribe to the topic
|
||||
await gossipsubs[index_alice].join(topic)
|
||||
|
||||
# Monkey patch bob's `emit_prune` function so we can
|
||||
# check if it is called in `handle_graft`
|
||||
event_emit_prune = trio.Event()
|
||||
|
||||
async def emit_prune(topic, sender_peer_id):
|
||||
event_emit_prune.set()
|
||||
|
||||
monkeypatch.setattr(gossipsubs[index_bob], "emit_prune", emit_prune)
|
||||
|
||||
# Check that alice is bob's peer but not his mesh peer
|
||||
assert id_alice in gossipsubs[index_bob].peers_gossipsub
|
||||
assert topic not in gossipsubs[index_bob].mesh
|
||||
|
||||
await gossipsubs[index_alice].emit_graft(topic, id_bob)
|
||||
|
||||
# Check that `emit_prune` is called
|
||||
await event_emit_prune.wait()
|
||||
|
||||
# Check that bob is alice's peer but not her mesh peer
|
||||
assert topic in gossipsubs[index_alice].mesh
|
||||
assert id_bob not in gossipsubs[index_alice].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].peers_gossipsub
|
||||
|
||||
await gossipsubs[index_bob].emit_graft(topic, id_alice)
|
||||
|
||||
await trio.sleep(1)
|
||||
|
||||
# Check that bob is now alice's mesh peer
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_handle_prune():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(
|
||||
2, heartbeat_interval=3
|
||||
) as pubsubs_gsub:
|
||||
gossipsubs = tuple(pubsub.router for pubsub in pubsubs_gsub)
|
||||
|
||||
index_alice = 0
|
||||
id_alice = pubsubs_gsub[index_alice].my_id
|
||||
index_bob = 1
|
||||
id_bob = pubsubs_gsub[index_bob].my_id
|
||||
|
||||
topic = "test_handle_prune"
|
||||
for pubsub in pubsubs_gsub:
|
||||
await pubsub.subscribe(topic)
|
||||
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
|
||||
# Wait 3 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(3)
|
||||
|
||||
# Check that they are each other's mesh peer
|
||||
assert id_alice in gossipsubs[index_bob].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
# alice emit prune message to bob, alice should be removed
|
||||
# from bob's mesh peer
|
||||
await gossipsubs[index_alice].emit_prune(topic, id_bob)
|
||||
|
||||
# FIXME: This test currently works because the heartbeat interval
|
||||
# is increased to 3 seconds, so alice won't get add back into
|
||||
# bob's mesh peer during heartbeat.
|
||||
await trio.sleep(1)
|
||||
|
||||
# Check that alice is no longer bob's mesh peer
|
||||
assert id_alice not in gossipsubs[index_bob].mesh[topic]
|
||||
assert id_bob in gossipsubs[index_alice].mesh[topic]
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_dense():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(10) as pubsubs_gsub:
|
||||
hosts = [pubsub.host for pubsub in pubsubs_gsub]
|
||||
num_msgs = 5
|
||||
|
||||
# All pubsub subscribe to foobar
|
||||
queues = [await pubsub.subscribe("foobar") for pubsub in pubsubs_gsub]
|
||||
|
||||
# Densely connect libp2p hosts in a random way
|
||||
await dense_connect(hosts)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(2)
|
||||
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
|
||||
# randomly pick a message origin
|
||||
origin_idx = random.randint(0, len(hosts) - 1)
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish("foobar", msg_content)
|
||||
|
||||
await trio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_fanout():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(10) as pubsubs_gsub:
|
||||
hosts = [pubsub.host for pubsub in pubsubs_gsub]
|
||||
num_msgs = 5
|
||||
|
||||
# All pubsub subscribe to foobar except for `pubsubs_gsub[0]`
|
||||
subs = [await pubsub.subscribe("foobar") for pubsub in pubsubs_gsub[1:]]
|
||||
|
||||
# Sparsely connect libp2p hosts in random way
|
||||
await dense_connect(hosts)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(2)
|
||||
|
||||
topic = "foobar"
|
||||
# Send messages with origin not subscribed
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await trio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for sub in subs:
|
||||
msg = await sub.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
# Subscribe message origin
|
||||
subs.insert(0, await pubsubs_gsub[0].subscribe(topic))
|
||||
|
||||
# Send messages again
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"bar " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await trio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for sub in subs:
|
||||
msg = await sub.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
@pytest.mark.slow
|
||||
async def test_fanout_maintenance(hosts, pubsubs_gsub):
|
||||
num_msgs = 5
|
||||
async def test_fanout_maintenance():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(10) as pubsubs_gsub:
|
||||
hosts = [pubsub.host for pubsub in pubsubs_gsub]
|
||||
num_msgs = 5
|
||||
|
||||
# All pubsub subscribe to foobar
|
||||
queues = []
|
||||
topic = "foobar"
|
||||
for i in range(1, len(pubsubs_gsub)):
|
||||
q = await pubsubs_gsub[i].subscribe(topic)
|
||||
# All pubsub subscribe to foobar
|
||||
queues = []
|
||||
topic = "foobar"
|
||||
for i in range(1, len(pubsubs_gsub)):
|
||||
q = await pubsubs_gsub[i].subscribe(topic)
|
||||
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
|
||||
# Sparsely connect libp2p hosts in random way
|
||||
await dense_connect(hosts)
|
||||
# Sparsely connect libp2p hosts in random way
|
||||
await dense_connect(hosts)
|
||||
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await asyncio.sleep(2)
|
||||
# Wait 2 seconds for heartbeat to allow mesh to connect
|
||||
await trio.sleep(2)
|
||||
|
||||
# Send messages with origin not subscribed
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
# Send messages with origin not subscribed
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"foo " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await trio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
for sub in pubsubs_gsub:
|
||||
await sub.unsubscribe(topic)
|
||||
|
||||
queues = []
|
||||
|
||||
await trio.sleep(2)
|
||||
|
||||
# Resub and repeat
|
||||
for i in range(1, len(pubsubs_gsub)):
|
||||
q = await pubsubs_gsub[i].subscribe(topic)
|
||||
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
|
||||
await trio.sleep(2)
|
||||
|
||||
# Check messages can still be sent
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"bar " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await trio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_gossip_propagation():
|
||||
async with PubsubFactory.create_batch_with_gossipsub(
|
||||
2, degree=1, degree_low=0, degree_high=2, gossip_window=50, gossip_history=100
|
||||
) as pubsubs_gsub:
|
||||
topic = "foo"
|
||||
await pubsubs_gsub[0].subscribe(topic)
|
||||
|
||||
# node 0 publish to topic
|
||||
msg_content = b"foo_msg"
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
await pubsubs_gsub[0].publish(topic, msg_content)
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.get()
|
||||
assert msg.data == msg_content
|
||||
# now node 1 subscribes
|
||||
queue_1 = await pubsubs_gsub[1].subscribe(topic)
|
||||
|
||||
for sub in pubsubs_gsub:
|
||||
await sub.unsubscribe(topic)
|
||||
await connect(pubsubs_gsub[0].host, pubsubs_gsub[1].host)
|
||||
|
||||
queues = []
|
||||
# wait for gossip heartbeat
|
||||
await trio.sleep(2)
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Resub and repeat
|
||||
for i in range(1, len(pubsubs_gsub)):
|
||||
q = await pubsubs_gsub[i].subscribe(topic)
|
||||
|
||||
# Add each blocking queue to an array of blocking queues
|
||||
queues.append(q)
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Check messages can still be sent
|
||||
for i in range(num_msgs):
|
||||
msg_content = b"bar " + i.to_bytes(1, "big")
|
||||
|
||||
# Pick the message origin to the node that is not subscribed to 'foobar'
|
||||
origin_idx = 0
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[origin_idx].publish(topic, msg_content)
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
# Assert that all blocking queues receive the message
|
||||
for queue in queues:
|
||||
msg = await queue.get()
|
||||
assert msg.data == msg_content
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"num_hosts, gossipsub_params",
|
||||
(
|
||||
(
|
||||
2,
|
||||
GossipsubParams(
|
||||
degree=1,
|
||||
degree_low=0,
|
||||
degree_high=2,
|
||||
gossip_window=50,
|
||||
gossip_history=100,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_gossip_propagation(hosts, pubsubs_gsub):
|
||||
topic = "foo"
|
||||
await pubsubs_gsub[0].subscribe(topic)
|
||||
|
||||
# node 0 publish to topic
|
||||
msg_content = b"foo_msg"
|
||||
|
||||
# publish from the randomly chosen host
|
||||
await pubsubs_gsub[0].publish(topic, msg_content)
|
||||
|
||||
# now node 1 subscribes
|
||||
queue_1 = await pubsubs_gsub[1].subscribe(topic)
|
||||
|
||||
await connect(hosts[0], hosts[1])
|
||||
|
||||
# wait for gossip heartbeat
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# should be able to read message
|
||||
msg = await queue_1.get()
|
||||
assert msg.data == msg_content
|
||||
# should be able to read message
|
||||
msg = await queue_1.receive()
|
||||
assert msg.data == msg_content
|
||||
|
||||
@ -3,25 +3,25 @@ import functools
|
||||
import pytest
|
||||
|
||||
from libp2p.tools.constants import FLOODSUB_PROTOCOL_ID
|
||||
from libp2p.tools.factories import GossipsubFactory
|
||||
from libp2p.tools.factories import PubsubFactory
|
||||
from libp2p.tools.pubsub.floodsub_integration_test_settings import (
|
||||
floodsub_protocol_pytest_params,
|
||||
perform_test_from_obj,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_gossipsub_initialize_with_floodsub_protocol():
|
||||
GossipsubFactory(protocols=[FLOODSUB_PROTOCOL_ID])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("test_case_obj", floodsub_protocol_pytest_params)
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.trio
|
||||
@pytest.mark.slow
|
||||
async def test_gossipsub_run_with_floodsub_tests(test_case_obj):
|
||||
await perform_test_from_obj(
|
||||
test_case_obj,
|
||||
functools.partial(
|
||||
GossipsubFactory, degree=3, degree_low=2, degree_high=4, time_to_live=30
|
||||
PubsubFactory.create_batch_with_gossipsub,
|
||||
protocols=[FLOODSUB_PROTOCOL_ID],
|
||||
degree=3,
|
||||
degree_low=2,
|
||||
degree_high=4,
|
||||
time_to_live=30,
|
||||
),
|
||||
)
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import pytest
|
||||
|
||||
from libp2p.pubsub.mcache import MessageCache
|
||||
|
||||
|
||||
@ -12,8 +10,7 @@ class Msg:
|
||||
self.from_id = from_id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mcache():
|
||||
def test_mcache():
|
||||
# Ported from:
|
||||
# https://github.com/libp2p/go-libp2p-pubsub/blob/51b7501433411b5096cac2b4994a36a68515fc03/mcache_test.go
|
||||
mcache = MessageCache(3, 5)
|
||||
|
||||
@ -5,12 +5,11 @@ import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.exceptions import ValidationError
|
||||
from libp2p.peer.id import ID
|
||||
from libp2p.pubsub.pb import rpc_pb2
|
||||
from libp2p.tools.constants import MAX_READ_LEN
|
||||
from libp2p.tools.factories import IDFactory, PubsubFactory, net_stream_pair_factory
|
||||
from libp2p.tools.pubsub.utils import make_pubsub_msg
|
||||
from libp2p.tools.utils import connect
|
||||
from libp2p.tools.constants import MAX_READ_LEN
|
||||
from libp2p.tools.factories import PubsubFactory, net_stream_pair_factory, IDFactory
|
||||
from libp2p.utils import encode_varint_prefixed
|
||||
|
||||
TESTING_TOPIC = "TEST_SUBSCRIBE"
|
||||
@ -250,14 +249,14 @@ async def test_continuously_read_stream(monkeypatch, nursery, is_host_secure):
|
||||
|
||||
async def mock_push_msg(msg_forwarder, msg):
|
||||
event_push_msg.set()
|
||||
await trio.sleep(0)
|
||||
await trio.hazmat.checkpoint()
|
||||
|
||||
def mock_handle_subscription(origin_id, sub_message):
|
||||
event_handle_subscription.set()
|
||||
|
||||
async def mock_handle_rpc(rpc, sender_peer_id):
|
||||
event_handle_rpc.set()
|
||||
await trio.sleep(0)
|
||||
await trio.hazmat.checkpoint()
|
||||
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr(pubsubs_fsub[0], "push_msg", mock_push_msg)
|
||||
|
||||
@ -69,33 +69,10 @@ async def test_mplex_stream_read_after_remote_closed(mplex_stream_pair):
|
||||
await stream_0.close()
|
||||
assert stream_0.event_local_closed.is_set()
|
||||
await trio.sleep(0.01)
|
||||
print(
|
||||
"!@# ",
|
||||
stream_0.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_0.muxed_conn.event_closed.is_set(),
|
||||
stream_1.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_1.muxed_conn.event_closed.is_set(),
|
||||
)
|
||||
# await trio.sleep(100000)
|
||||
await wait_all_tasks_blocked()
|
||||
print(
|
||||
"!@# ",
|
||||
stream_0.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_0.muxed_conn.event_closed.is_set(),
|
||||
stream_1.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_1.muxed_conn.event_closed.is_set(),
|
||||
)
|
||||
print("!@# sleeping")
|
||||
print("!@# result=", stream_1.event_remote_closed.is_set())
|
||||
# await trio.sleep_forever()
|
||||
assert stream_1.event_remote_closed.is_set()
|
||||
print(
|
||||
"!@# ",
|
||||
stream_0.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_0.muxed_conn.event_closed.is_set(),
|
||||
stream_1.muxed_conn.event_shutting_down.is_set(),
|
||||
stream_1.muxed_conn.event_closed.is_set(),
|
||||
)
|
||||
assert (await stream_1.read(MAX_READ_LEN)) == DATA
|
||||
with pytest.raises(MplexStreamEOF):
|
||||
await stream_1.read(MAX_READ_LEN)
|
||||
|
||||
@ -3,7 +3,7 @@ import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.network.connection.raw_connection import RawConnection
|
||||
from libp2p.tools.constants import LISTEN_MADDR, MAX_READ_LEN
|
||||
from libp2p.tools.constants import LISTEN_MADDR
|
||||
from libp2p.transport.tcp.tcp import TCP
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user