mirror of
https://github.com/vacp2p/nim-libp2p.git
synced 2026-01-09 02:38:19 -05:00
test(rendezvous): Refactor Rendezvous tests (#1644)
This commit is contained in:
committed by
GitHub
parent
9865cc39b5
commit
c7f29ed5db
3
tests/discovery/testdiscovery.nim
Normal file
3
tests/discovery/testdiscovery.nim
Normal file
@@ -0,0 +1,3 @@
|
||||
{.used.}
|
||||
|
||||
import testdiscoverymngr, testrendezvous, testrendezvousinterface
|
||||
@@ -11,25 +11,16 @@
|
||||
|
||||
import options, chronos, sets
|
||||
import
|
||||
../libp2p/[
|
||||
../../libp2p/[
|
||||
protocols/rendezvous,
|
||||
switch,
|
||||
builders,
|
||||
discovery/discoverymngr,
|
||||
discovery/rendezvousinterface,
|
||||
]
|
||||
import ./helpers, ./utils/async_tests
|
||||
|
||||
proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
|
||||
SwitchBuilder
|
||||
.new()
|
||||
.withRng(newRng())
|
||||
.withAddresses(@[MultiAddress.init(MemoryAutoAddress).tryGet()])
|
||||
.withMemoryTransport()
|
||||
.withMplex()
|
||||
.withNoise()
|
||||
.withRendezVous(rdv)
|
||||
.build()
|
||||
import ../helpers
|
||||
import ../utils/async_tests
|
||||
import ./utils
|
||||
|
||||
suite "Discovery":
|
||||
teardown:
|
||||
169
tests/discovery/testrendezvous.nim
Normal file
169
tests/discovery/testrendezvous.nim
Normal file
@@ -0,0 +1,169 @@
|
||||
{.used.}
|
||||
|
||||
# Nim-Libp2p
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import sequtils, strutils
|
||||
import chronos
|
||||
import ../../libp2p/[protocols/rendezvous, switch]
|
||||
import ../../libp2p/discovery/discoverymngr
|
||||
import ../helpers
|
||||
import ./utils
|
||||
|
||||
suite "RendezVous":
|
||||
teardown:
|
||||
checkTrackers()
|
||||
|
||||
asyncTest "Request locally returns 0 for empty namespace":
|
||||
let (nodes, rdvs) = setupNodes(1)
|
||||
nodes.startAndDeferStop()
|
||||
|
||||
const namespace = ""
|
||||
check rdvs[0].requestLocally(namespace).len == 0
|
||||
|
||||
asyncTest "Request locally returns registered peers":
|
||||
let (nodes, rdvs) = setupNodes(1)
|
||||
nodes.startAndDeferStop()
|
||||
|
||||
const namespace = "foo"
|
||||
await rdvs[0].advertise(namespace)
|
||||
let peerRecords = rdvs[0].requestLocally(namespace)
|
||||
|
||||
check:
|
||||
peerRecords.len == 1
|
||||
peerRecords[0] == nodes[0].peerInfo.signedPeerRecord.data
|
||||
|
||||
asyncTest "Unsubscribe Locally removes registered peer":
|
||||
let (nodes, rdvs) = setupNodes(1)
|
||||
nodes.startAndDeferStop()
|
||||
|
||||
const namespace = "foo"
|
||||
await rdvs[0].advertise(namespace)
|
||||
check rdvs[0].requestLocally(namespace).len == 1
|
||||
|
||||
rdvs[0].unsubscribeLocally(namespace)
|
||||
check rdvs[0].requestLocally(namespace).len == 0
|
||||
|
||||
asyncTest "Request returns 0 for empty namespace from remote":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(1)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodes(peerNodes[0], rendezvousNode)
|
||||
|
||||
const namespace = "empty"
|
||||
check (await peerRdvs[0].request(Opt.some(namespace))).len == 0
|
||||
|
||||
asyncTest "Request returns registered peers from remote":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(1)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodes(peerNodes[0], rendezvousNode)
|
||||
|
||||
const namespace = "foo"
|
||||
await peerRdvs[0].advertise(namespace)
|
||||
let peerRecords = await peerRdvs[0].request(Opt.some(namespace))
|
||||
check:
|
||||
peerRecords.len == 1
|
||||
peerRecords[0] == peerNodes[0].peerInfo.signedPeerRecord.data
|
||||
|
||||
asyncTest "Unsubscribe removes registered peer from remote":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(1)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodes(peerNodes[0], rendezvousNode)
|
||||
|
||||
const namespace = "foo"
|
||||
await peerRdvs[0].advertise(namespace)
|
||||
|
||||
check (await peerRdvs[0].request(Opt.some(namespace))).len == 1
|
||||
|
||||
await peerRdvs[0].unsubscribe(namespace)
|
||||
check (await peerRdvs[0].request(Opt.some(namespace))).len == 0
|
||||
|
||||
asyncTest "Consecutive requests with namespace returns peers with pagination":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(11)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodesToRendezvousNode(peerNodes, rendezvousNode)
|
||||
|
||||
const namespace = "foo"
|
||||
await allFutures(peerRdvs.mapIt(it.advertise(namespace)))
|
||||
|
||||
var data = peerNodes.mapIt(it.peerInfo.signedPeerRecord.data)
|
||||
var peerRecords = await peerRdvs[0].request(Opt.some(namespace), 5)
|
||||
check:
|
||||
peerRecords.len == 5
|
||||
peerRecords.allIt(it in data)
|
||||
data.keepItIf(it notin peerRecords)
|
||||
|
||||
peerRecords = await peerRdvs[0].request(Opt.some(namespace))
|
||||
check:
|
||||
peerRecords.len == 5
|
||||
peerRecords.allIt(it in data)
|
||||
|
||||
check (await peerRdvs[0].request(Opt.some(namespace))).len == 0
|
||||
|
||||
asyncTest "Request without namespace returns all registered peers":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(10)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodesToRendezvousNode(peerNodes, rendezvousNode)
|
||||
|
||||
const namespaceFoo = "foo"
|
||||
const namespaceBar = "Bar"
|
||||
await allFutures(peerRdvs[0 ..< 5].mapIt(it.advertise(namespaceFoo)))
|
||||
await allFutures(peerRdvs[5 ..< 10].mapIt(it.advertise(namespaceBar)))
|
||||
|
||||
check (await peerRdvs[0].request()).len == 10
|
||||
|
||||
check (await peerRdvs[0].request(Opt.none(string))).len == 10
|
||||
|
||||
asyncTest "Consecutive requests with namespace keep cookie and retun only new peers":
|
||||
let (rendezvousNode, peerNodes, peerRdvs, _) = setupRendezvousNodeWithPeerNodes(2)
|
||||
(rendezvousNode & peerNodes).startAndDeferStop()
|
||||
|
||||
await connectNodesToRendezvousNode(peerNodes, rendezvousNode)
|
||||
|
||||
let
|
||||
rdv0 = peerRdvs[0]
|
||||
rdv1 = peerRdvs[1]
|
||||
const namespace = "foo"
|
||||
|
||||
await rdv0.advertise(namespace)
|
||||
discard await rdv0.request(Opt.some(namespace))
|
||||
|
||||
await rdv1.advertise(namespace)
|
||||
let peerRecords = await rdv0.request(Opt.some(namespace))
|
||||
|
||||
check:
|
||||
peerRecords.len == 1
|
||||
peerRecords[0] == peerNodes[1].peerInfo.signedPeerRecord.data
|
||||
|
||||
asyncTest "Various local error":
|
||||
let rdv = RendezVous.new(minDuration = 1.minutes, maxDuration = 72.hours)
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A".repeat(300)))
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A"), -1)
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A"), 3000)
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A".repeat(300))
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A", 73.hours)
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A", 30.seconds)
|
||||
|
||||
test "Various config error":
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(minDuration = 30.seconds)
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(maxDuration = 73.hours)
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(minDuration = 15.minutes, maxDuration = 10.minutes)
|
||||
@@ -9,22 +9,11 @@
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import sequtils, strutils
|
||||
import chronos
|
||||
import ../libp2p/[protocols/rendezvous, switch, builders]
|
||||
import ../libp2p/discovery/[rendezvousinterface, discoverymngr]
|
||||
import ./helpers
|
||||
|
||||
proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
|
||||
SwitchBuilder
|
||||
.new()
|
||||
.withRng(newRng())
|
||||
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
||||
.withTcpTransport()
|
||||
.withMplex()
|
||||
.withNoise()
|
||||
.withRendezVous(rdv)
|
||||
.build()
|
||||
import ../../libp2p/[protocols/rendezvous, switch, builders]
|
||||
import ../../libp2p/discovery/[rendezvousinterface, discoverymngr]
|
||||
import ../helpers
|
||||
import ./utils
|
||||
|
||||
type
|
||||
MockRendezVous = ref object of RendezVous
|
||||
@@ -33,7 +22,9 @@ type
|
||||
|
||||
MockErrorRendezVous = ref object of MockRendezVous
|
||||
|
||||
method advertise*(self: MockRendezVous, namespace: string, ttl: Duration) {.async.} =
|
||||
method advertise*(
|
||||
self: MockRendezVous, namespace: string, ttl: Duration
|
||||
) {.async: (raises: [CancelledError, AdvertiseError]).} =
|
||||
if namespace == "ns1":
|
||||
self.numAdvertiseNs1 += 1
|
||||
elif namespace == "ns2":
|
||||
@@ -43,9 +34,9 @@ method advertise*(self: MockRendezVous, namespace: string, ttl: Duration) {.asyn
|
||||
|
||||
method advertise*(
|
||||
self: MockErrorRendezVous, namespace: string, ttl: Duration
|
||||
) {.async.} =
|
||||
) {.async: (raises: [CancelledError, AdvertiseError]).} =
|
||||
await procCall MockRendezVous(self).advertise(namespace, ttl)
|
||||
raise newException(CatchableError, "MockErrorRendezVous.advertise")
|
||||
raise newException(AdvertiseError, "MockErrorRendezVous.advertise")
|
||||
|
||||
suite "RendezVous Interface":
|
||||
teardown:
|
||||
55
tests/discovery/utils.nim
Normal file
55
tests/discovery/utils.nim
Normal file
@@ -0,0 +1,55 @@
|
||||
import sequtils
|
||||
import chronos
|
||||
import ../../libp2p/[protocols/rendezvous, switch, builders]
|
||||
|
||||
proc createSwitch*(rdv: RendezVous = RendezVous.new()): Switch =
|
||||
SwitchBuilder
|
||||
.new()
|
||||
.withRng(newRng())
|
||||
.withAddresses(@[MultiAddress.init(MemoryAutoAddress).tryGet()])
|
||||
.withMemoryTransport()
|
||||
.withMplex()
|
||||
.withNoise()
|
||||
.withRendezVous(rdv)
|
||||
.build()
|
||||
|
||||
proc setupNodes*(count: int): (seq[Switch], seq[RendezVous]) =
|
||||
doAssert(count > 0, "Count must be greater than 0")
|
||||
|
||||
var
|
||||
nodes: seq[Switch] = @[]
|
||||
rdvs: seq[RendezVous] = @[]
|
||||
|
||||
for x in 0 ..< count:
|
||||
let rdv = RendezVous.new()
|
||||
let node = createSwitch(rdv)
|
||||
nodes.add(node)
|
||||
rdvs.add(rdv)
|
||||
|
||||
return (nodes, rdvs)
|
||||
|
||||
proc setupRendezvousNodeWithPeerNodes*(
|
||||
count: int
|
||||
): (Switch, seq[Switch], seq[RendezVous], RendezVous) =
|
||||
let
|
||||
(nodes, rdvs) = setupNodes(count + 1)
|
||||
rendezvousNode = nodes[0]
|
||||
rendezvousRdv = rdvs[0]
|
||||
peerNodes = nodes[1 ..^ 1]
|
||||
peerRdvs = rdvs[1 ..^ 1]
|
||||
|
||||
return (rendezvousNode, peerNodes, peerRdvs, rendezvousRdv)
|
||||
|
||||
template startAndDeferStop*(nodes: seq[Switch]) =
|
||||
await allFutures(nodes.mapIt(it.start()))
|
||||
defer:
|
||||
await allFutures(nodes.mapIt(it.stop()))
|
||||
|
||||
proc connectNodes*[T: Switch](dialer: T, target: T) {.async.} =
|
||||
await dialer.connect(target.peerInfo.peerId, target.peerInfo.addrs)
|
||||
|
||||
proc connectNodesToRendezvousNode*[T: Switch](
|
||||
nodes: seq[T], rendezvousNode: T
|
||||
) {.async.} =
|
||||
for node in nodes:
|
||||
await connectNodes(node, rendezvousNode)
|
||||
@@ -30,10 +30,12 @@ import
|
||||
import
|
||||
testnameresolve, testmultistream, testbufferstream, testidentify,
|
||||
testobservedaddrmanager, testconnmngr, testswitch, testnoise, testpeerinfo,
|
||||
testpeerstore, testping, testmplex, testrelayv1, testrelayv2, testrendezvous,
|
||||
testdiscovery, testyamux, testyamuxheader, testautonat, testautonatservice,
|
||||
testautonatv2, testautorelay, testdcutr, testhpservice, testutility, testhelpers,
|
||||
testwildcardresolverservice, testperf
|
||||
testpeerstore, testping, testmplex, testrelayv1, testrelayv2, testyamux,
|
||||
testyamuxheader, testautonat, testautonatservice, testautonatv2, testautorelay,
|
||||
testdcutr, testhpservice, testutility, testhelpers, testwildcardresolverservice,
|
||||
testperf
|
||||
|
||||
import discovery/testdiscovery
|
||||
|
||||
import kademlia/[testencoding, testroutingtable, testfindnode, testputval]
|
||||
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
{.used.}
|
||||
|
||||
# Nim-Libp2p
|
||||
# Copyright (c) 2023 Status Research & Development GmbH
|
||||
# Licensed under either of
|
||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
||||
# at your option.
|
||||
# This file may not be copied, modified, or distributed except according to
|
||||
# those terms.
|
||||
|
||||
import sequtils, strutils
|
||||
import chronos
|
||||
import ../libp2p/[protocols/rendezvous, switch, builders]
|
||||
import ../libp2p/discovery/discoverymngr
|
||||
import ./helpers
|
||||
|
||||
proc createSwitch(rdv: RendezVous = RendezVous.new()): Switch =
|
||||
SwitchBuilder
|
||||
.new()
|
||||
.withRng(newRng())
|
||||
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
|
||||
.withTcpTransport()
|
||||
.withMplex()
|
||||
.withNoise()
|
||||
.withRendezVous(rdv)
|
||||
.build()
|
||||
|
||||
suite "RendezVous":
|
||||
teardown:
|
||||
checkTrackers()
|
||||
asyncTest "Simple local test":
|
||||
let
|
||||
rdv = RendezVous.new()
|
||||
s = createSwitch(rdv)
|
||||
|
||||
await s.start()
|
||||
let res0 = rdv.requestLocally("empty")
|
||||
check res0.len == 0
|
||||
await rdv.advertise("foo")
|
||||
let res1 = rdv.requestLocally("foo")
|
||||
check:
|
||||
res1.len == 1
|
||||
res1[0] == s.peerInfo.signedPeerRecord.data
|
||||
let res2 = rdv.requestLocally("bar")
|
||||
check res2.len == 0
|
||||
rdv.unsubscribeLocally("foo")
|
||||
let res3 = rdv.requestLocally("foo")
|
||||
check res3.len == 0
|
||||
await s.stop()
|
||||
|
||||
asyncTest "Simple remote test":
|
||||
let
|
||||
rdv = RendezVous.new()
|
||||
client = createSwitch(rdv)
|
||||
remoteSwitch = createSwitch()
|
||||
|
||||
await client.start()
|
||||
await remoteSwitch.start()
|
||||
await client.connect(remoteSwitch.peerInfo.peerId, remoteSwitch.peerInfo.addrs)
|
||||
let res0 = await rdv.request(Opt.some("empty"))
|
||||
check res0.len == 0
|
||||
|
||||
await rdv.advertise("foo")
|
||||
let res1 = await rdv.request(Opt.some("foo"))
|
||||
check:
|
||||
res1.len == 1
|
||||
res1[0] == client.peerInfo.signedPeerRecord.data
|
||||
|
||||
let res2 = await rdv.request(Opt.some("bar"))
|
||||
check res2.len == 0
|
||||
|
||||
await rdv.unsubscribe("foo")
|
||||
let res3 = await rdv.request(Opt.some("foo"))
|
||||
check res3.len == 0
|
||||
|
||||
await allFutures(client.stop(), remoteSwitch.stop())
|
||||
|
||||
asyncTest "Harder remote test":
|
||||
var
|
||||
rdvSeq: seq[RendezVous] = @[]
|
||||
clientSeq: seq[Switch] = @[]
|
||||
remoteSwitch = createSwitch()
|
||||
|
||||
for x in 0 .. 10:
|
||||
rdvSeq.add(RendezVous.new())
|
||||
clientSeq.add(createSwitch(rdvSeq[^1]))
|
||||
await remoteSwitch.start()
|
||||
await allFutures(clientSeq.mapIt(it.start()))
|
||||
await allFutures(
|
||||
clientSeq.mapIt(remoteSwitch.connect(it.peerInfo.peerId, it.peerInfo.addrs))
|
||||
)
|
||||
await allFutures(rdvSeq.mapIt(it.advertise("foo")))
|
||||
var data = clientSeq.mapIt(it.peerInfo.signedPeerRecord.data)
|
||||
let res1 = await rdvSeq[0].request(Opt.some("foo"), 5)
|
||||
check res1.len == 5
|
||||
for d in res1:
|
||||
check d in data
|
||||
data.keepItIf(it notin res1)
|
||||
let res2 = await rdvSeq[0].request(Opt.some("foo"))
|
||||
check res2.len == 5
|
||||
for d in res2:
|
||||
check d in data
|
||||
let res3 = await rdvSeq[0].request(Opt.some("foo"))
|
||||
check res3.len == 0
|
||||
let res4 = await rdvSeq[0].request()
|
||||
check res4.len == 11
|
||||
let res5 = await rdvSeq[0].request(Opt.none(string))
|
||||
check res5.len == 11
|
||||
await remoteSwitch.stop()
|
||||
await allFutures(clientSeq.mapIt(it.stop()))
|
||||
|
||||
asyncTest "Simple cookie test":
|
||||
let
|
||||
rdvA = RendezVous.new()
|
||||
rdvB = RendezVous.new()
|
||||
clientA = createSwitch(rdvA)
|
||||
clientB = createSwitch(rdvB)
|
||||
remoteSwitch = createSwitch()
|
||||
|
||||
await clientA.start()
|
||||
await clientB.start()
|
||||
await remoteSwitch.start()
|
||||
await clientA.connect(remoteSwitch.peerInfo.peerId, remoteSwitch.peerInfo.addrs)
|
||||
await clientB.connect(remoteSwitch.peerInfo.peerId, remoteSwitch.peerInfo.addrs)
|
||||
await rdvA.advertise("foo")
|
||||
let res1 = await rdvA.request(Opt.some("foo"))
|
||||
await rdvB.advertise("foo")
|
||||
let res2 = await rdvA.request(Opt.some("foo"))
|
||||
check:
|
||||
res2.len == 1
|
||||
res2[0] == clientB.peerInfo.signedPeerRecord.data
|
||||
await allFutures(clientA.stop(), clientB.stop(), remoteSwitch.stop())
|
||||
|
||||
asyncTest "Various local error":
|
||||
let
|
||||
rdv = RendezVous.new(minDuration = 1.minutes, maxDuration = 72.hours)
|
||||
switch = createSwitch(rdv)
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A".repeat(300)))
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A"), -1)
|
||||
expect AdvertiseError:
|
||||
discard await rdv.request(Opt.some("A"), 3000)
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A".repeat(300))
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A", 73.hours)
|
||||
expect AdvertiseError:
|
||||
await rdv.advertise("A", 30.seconds)
|
||||
|
||||
test "Various config error":
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(minDuration = 30.seconds)
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(maxDuration = 73.hours)
|
||||
expect RendezVousError:
|
||||
discard RendezVous.new(minDuration = 15.minutes, maxDuration = 10.minutes)
|
||||
Reference in New Issue
Block a user