diff --git a/tests/pubsub/testgossipinternal.nim b/tests/pubsub/testgossipinternal.nim index 95fbc3899..7f4220e7d 100644 --- a/tests/pubsub/testgossipinternal.nim +++ b/tests/pubsub/testgossipinternal.nim @@ -21,9 +21,15 @@ import ../../libp2p/switch import ../../libp2p/muxers/muxer import ../../libp2p/protocols/pubsub/rpc/protobuf import utils +import ../utils/[futures] import ../helpers +import std/[tables, sequtils, sets, strutils] + +proc voidTopicHandler(topic: string, data: seq[byte]) {.async.} = + discard + proc noop(data: seq[byte]) {.async: (raises: [CancelledError, LPStreamError]).} = discard @@ -902,3 +908,70 @@ suite "GossipSub internal": check receivedMessages[].len == 1 await teardownTest(gossip0, gossip1) + + asyncTest "GRAFT messages correctly add peers to mesh": + # Potential flaky test + + # Given 2 nodes + let + topic = "foo" + graftMessage = ControlMessage(graft: @[ControlGraft(topicID: topic)]) + numberOfNodes = 2 + # First of the hack + # Weird dValues so peers are not GRAFTed automatically + dValues = DValues(dLow: some(0), dHigh: some(0), d: some(0), dOut: some(-1)) + nodes = generateNodes( + numberOfNodes, gossip = true, verifySignature = false, dValues = some(dValues) + ) + nodesFut = nodes.mapIt(it.switch.start()) + g0 = GossipSub(nodes[0]) + g1 = GossipSub(nodes[1]) + tg0 = cast[TestGossipSub](g0) + tg1 = cast[TestGossipSub](g1) + p0 = tg1.getPubSubPeer(nodes[0].peerInfo.peerId) + p1 = tg0.getPubSubPeer(nodes[1].peerInfo.peerId) + + discard await allFinished(nodesFut) + + # And the nodes are connected + await subscribeNodes(nodes) + + # And both subscribe to the topic + g0.subscribe(topic, voidTopicHandler) + g1.subscribe(topic, voidTopicHandler) + await sleepAsync(DURATION_TIMEOUT) + + # Because of the hack-ish dValues, the peers are added to gossipsub but not GRAFTed to mesh + check: + g0.gossipsub.hasPeerId(topic, nodes[1].peerInfo.peerId) == true + g1.gossipsub.hasPeerId(topic, nodes[0].peerInfo.peerId) == true + g0.mesh.hasPeerId(topic, nodes[1].peerInfo.peerId) == false + g1.mesh.hasPeerId(topic, nodes[0].peerInfo.peerId) == false + + # Second part of the hack + # Set values so peers can be GRAFTed + g0.parameters.dOut = 1 + g0.parameters.d = 1 + g0.parameters.dLow = 1 + g0.parameters.dHigh = 1 + g1.parameters.dOut = 1 + g1.parameters.d = 1 + g1.parameters.dLow = 1 + g1.parameters.dHigh = 1 + + # When a GRAFT message is sent + g0.broadcast(@[p1], RPCMsg(control: some(graftMessage)), isHighPriority = false) + g1.broadcast(@[p0], RPCMsg(control: some(graftMessage)), isHighPriority = false) + # Minimal await to avoid heartbeat so that the GRAFT is due to the message + # Despite this, it could happen that it's due to heartbeat, even if local tests didn't show that behaviour + await sleepAsync(300.milliseconds) + + # Then the peers are GRAFTed + check: + g0.gossipsub.hasPeerId(topic, nodes[1].peerInfo.peerId) == true + g1.gossipsub.hasPeerId(topic, nodes[0].peerInfo.peerId) == true + g0.mesh.hasPeerId(topic, nodes[1].peerInfo.peerId) == true + g1.mesh.hasPeerId(topic, nodes[0].peerInfo.peerId) == true + + # Cleanup + await allFuturesThrowing(nodes.mapIt(it.switch.stop()))