diff --git a/tests/pubsub/testgossipinternal.nim b/tests/pubsub/testgossipinternal.nim index 7f4220e7d..c0dca7f6f 100644 --- a/tests/pubsub/testgossipinternal.nim +++ b/tests/pubsub/testgossipinternal.nim @@ -910,15 +910,14 @@ suite "GossipSub internal": await teardownTest(gossip0, gossip1) asyncTest "GRAFT messages correctly add peers to mesh": - # Potential flaky test + # Potentially flaky test # Given 2 nodes let - topic = "foo" + topic = "foobar" graftMessage = ControlMessage(graft: @[ControlGraft(topicID: topic)]) numberOfNodes = 2 - # First of the hack - # Weird dValues so peers are not GRAFTed automatically + # First part 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) @@ -959,6 +958,7 @@ suite "GossipSub internal": g1.parameters.dLow = 1 g1.parameters.dHigh = 1 + # Potentially flaky due to this relying on sleep. Race condition against heartbeat. # When a GRAFT message is sent g0.broadcast(@[p1], RPCMsg(control: some(graftMessage)), isHighPriority = false) g1.broadcast(@[p0], RPCMsg(control: some(graftMessage)), isHighPriority = false) @@ -975,3 +975,62 @@ suite "GossipSub internal": # Cleanup await allFuturesThrowing(nodes.mapIt(it.switch.stop())) + + asyncTest "PRUNE messages correctly removes peers from mesh": + # Given 2 nodes + let + topic = "foo" + backoff = 1 + pruneMessage = ControlMessage( + prune: @[ControlPrune(topicID: topic, peers: @[], backoff: uint64(backoff))] + ) + numberOfNodes = 2 + nodes = generateNodes(numberOfNodes, gossip = true, verifySignature = false) + 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) + + 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 + + # When a PRUNE message is sent + g0.broadcast(@[p1], RPCMsg(control: some(pruneMessage)), isHighPriority = false) + await sleepAsync(300.milliseconds) + + # Then the peer is PRUNEd + 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) == false + + # When another PRUNE message is sent + g1.broadcast(@[p0], RPCMsg(control: some(pruneMessage)), isHighPriority = false) + await sleepAsync(300.milliseconds) + + # Then the peer is PRUNEd + 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 + + # Cleanup + await allFuturesThrowing(nodes.mapIt(it.switch.stop()))