Cleanup tests (#435)

* add async testing methods

* refactor with async testing methods

* use iffy in async tests
This commit is contained in:
Dmitriy Ryajov 2020-11-12 21:44:02 -06:00 committed by GitHub
parent 23ffd1f9f9
commit 55b763264e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 3010 additions and 3544 deletions

View File

@ -46,6 +46,27 @@ template checkTrackers*() =
# Also test the GC is not fooling with us # Also test the GC is not fooling with us
GC_fullCollect() GC_fullCollect()
template asyncTeardown*(body: untyped): untyped =
teardown:
waitFor((
proc() {.async.} =
body
)())
template asyncSetup*(body: untyped): untyped =
setup:
waitFor((
proc() {.async.} =
body
)())
template asyncTest*(name: string, body: untyped): untyped =
test name:
waitFor((
proc() {.async.} =
body
)())
type RngWrap = object type RngWrap = object
rng: ref BrHmacDrbgContext rng: ref BrHmacDrbgContext

View File

@ -38,357 +38,336 @@ suite "FloodSub":
teardown: teardown:
checkTrackers() checkTrackers()
test "FloodSub basic publish/subscribe A -> B": asyncTest "FloodSub basic publish/subscribe A -> B":
proc runTests() {.async.} = var completionFut = newFuture[bool]()
var completionFut = newFuture[bool]() proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} = check topic == "foobar"
check topic == "foobar" completionFut.complete(true)
completionFut.complete(true)
let let
nodes = generateNodes(2) nodes = generateNodes(2)
# start switches # start switches
nodesFut = await allFinished( nodesFut = await allFinished(
nodes[0].switch.start(), nodes[0].switch.start(),
nodes[1].switch.start(), nodes[1].switch.start(),
) )
# start pubsub # start pubsub
await allFuturesThrowing( await allFuturesThrowing(
allFinished( allFinished(
nodes[0].start(), nodes[0].start(),
nodes[1].start(), nodes[1].start(),
)) ))
await subscribeNodes(nodes) await subscribeNodes(nodes)
await nodes[1].subscribe("foobar", handler) await nodes[1].subscribe("foobar", handler)
await waitSub(nodes[0], nodes[1], "foobar") await waitSub(nodes[0], nodes[1], "foobar")
check (await nodes[0].publish("foobar", "Hello!".toBytes())) > 0 check (await nodes[0].publish("foobar", "Hello!".toBytes())) > 0
check (await completionFut.wait(5.seconds)) == true check (await completionFut.wait(5.seconds)) == true
await allFuturesThrowing( await allFuturesThrowing(
nodes[0].switch.stop(),
nodes[1].switch.stop()
)
await allFuturesThrowing(
nodes[0].stop(),
nodes[1].stop()
)
await allFuturesThrowing(nodesFut.concat())
asyncTest "FloodSub basic publish/subscribe B -> A":
var completionFut = newFuture[bool]()
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
completionFut.complete(true)
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
)
# start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes)
await nodes[0].subscribe("foobar", handler)
await waitSub(nodes[1], nodes[0], "foobar")
check (await nodes[1].publish("foobar", "Hello!".toBytes())) > 0
check (await completionFut.wait(5.seconds)) == true
await allFuturesThrowing(
nodes[0].switch.stop(),
nodes[1].switch.stop()
)
await allFuturesThrowing(
nodes[0].stop(),
nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
asyncTest "FloodSub validation should succeed":
var handlerFut = newFuture[bool]()
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
handlerFut.complete(true)
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
)
# start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes)
await nodes[1].subscribe("foobar", handler)
await waitSub(nodes[0], nodes[1], "foobar")
var validatorFut = newFuture[bool]()
proc validator(topic: string,
message: Message): Future[ValidationResult] {.async.} =
check topic == "foobar"
validatorFut.complete(true)
result = ValidationResult.Accept
nodes[1].addValidator("foobar", validator)
check (await nodes[0].publish("foobar", "Hello!".toBytes())) > 0
check (await handlerFut) == true
await allFuturesThrowing(
nodes[0].switch.stop(), nodes[0].switch.stop(),
nodes[1].switch.stop() nodes[1].switch.stop()
) )
await allFuturesThrowing( await allFuturesThrowing(
nodes[0].stop(), nodes[0].stop(),
nodes[1].stop() nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
asyncTest "FloodSub validation should fail":
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check false # if we get here, it should fail
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
) )
await allFuturesThrowing(nodesFut.concat()) # start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
waitFor(runTests()) await subscribeNodes(nodes)
await nodes[1].subscribe("foobar", handler)
await waitSub(nodes[0], nodes[1], "foobar")
test "FloodSub basic publish/subscribe B -> A": var validatorFut = newFuture[bool]()
proc runTests() {.async.} = proc validator(topic: string,
var completionFut = newFuture[bool]() message: Message): Future[ValidationResult] {.async.} =
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} = validatorFut.complete(true)
check topic == "foobar" result = ValidationResult.Reject
completionFut.complete(true)
let nodes[1].addValidator("foobar", validator)
nodes = generateNodes(2)
# start switches discard await nodes[0].publish("foobar", "Hello!".toBytes())
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
)
# start pubsubcon await allFuturesThrowing(
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes)
await nodes[0].subscribe("foobar", handler)
await waitSub(nodes[1], nodes[0], "foobar")
check (await nodes[1].publish("foobar", "Hello!".toBytes())) > 0
check (await completionFut.wait(5.seconds)) == true
await allFuturesThrowing(
nodes[0].switch.stop(), nodes[0].switch.stop(),
nodes[1].switch.stop() nodes[1].switch.stop()
) )
await allFuturesThrowing( await allFuturesThrowing(
nodes[0].stop(), nodes[0].stop(),
nodes[1].stop() nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
asyncTest "FloodSub validation one fails and one succeeds":
var handlerFut = newFuture[bool]()
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foo"
handlerFut.complete(true)
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
) )
await allFuturesThrowing(nodesFut) # start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
waitFor(runTests()) await subscribeNodes(nodes)
await nodes[1].subscribe("foo", handler)
await waitSub(nodes[0], nodes[1], "foo")
await nodes[1].subscribe("bar", handler)
await waitSub(nodes[0], nodes[1], "bar")
test "FloodSub validation should succeed": proc validator(topic: string,
proc runTests() {.async.} = message: Message): Future[ValidationResult] {.async.} =
var handlerFut = newFuture[bool]() if topic == "foo":
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
handlerFut.complete(true)
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
)
# start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes)
await nodes[1].subscribe("foobar", handler)
await waitSub(nodes[0], nodes[1], "foobar")
var validatorFut = newFuture[bool]()
proc validator(topic: string,
message: Message): Future[ValidationResult] {.async.} =
check topic == "foobar"
validatorFut.complete(true)
result = ValidationResult.Accept result = ValidationResult.Accept
else:
nodes[1].addValidator("foobar", validator)
check (await nodes[0].publish("foobar", "Hello!".toBytes())) > 0
check (await handlerFut) == true
await allFuturesThrowing(
nodes[0].switch.stop(),
nodes[1].switch.stop()
)
await allFuturesThrowing(
nodes[0].stop(),
nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
waitFor(runTests())
test "FloodSub validation should fail":
proc runTests() {.async.} =
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} =
check false # if we get here, it should fail
let
nodes = generateNodes(2)
# start switches
nodesFut = await allFinished(
nodes[0].switch.start(),
nodes[1].switch.start(),
)
# start pubsubcon
await allFuturesThrowing(
allFinished(
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes)
await nodes[1].subscribe("foobar", handler)
await waitSub(nodes[0], nodes[1], "foobar")
var validatorFut = newFuture[bool]()
proc validator(topic: string,
message: Message): Future[ValidationResult] {.async.} =
validatorFut.complete(true)
result = ValidationResult.Reject result = ValidationResult.Reject
nodes[1].addValidator("foobar", validator) nodes[1].addValidator("foo", "bar", validator)
discard await nodes[0].publish("foobar", "Hello!".toBytes()) check (await nodes[0].publish("foo", "Hello!".toBytes())) > 0
check (await nodes[0].publish("bar", "Hello!".toBytes())) > 0
await allFuturesThrowing( await allFuturesThrowing(
nodes[0].switch.stop(), nodes[0].switch.stop(),
nodes[1].switch.stop() nodes[1].switch.stop()
)
await allFuturesThrowing(
nodes[0].stop(),
nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
asyncTest "FloodSub multiple peers, no self trigger":
var runs = 10
var futs = newSeq[(Future[void], TopicHandler, ref int)](runs)
for i in 0..<runs:
closureScope:
var
fut = newFuture[void]()
counter = new int
futs[i] = (
fut,
(proc(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
inc counter[]
if counter[] == runs - 1:
fut.complete()),
counter
) )
await allFuturesThrowing( let
nodes[0].stop(), nodes = generateNodes(runs, triggerSelf = false)
nodes[1].stop() nodesFut = nodes.mapIt(it.switch.start())
)
await allFuturesThrowing(nodesFut) await allFuturesThrowing(nodes.mapIt(it.start()))
await subscribeNodes(nodes)
waitFor(runTests()) for i in 0..<runs:
await nodes[i].subscribe("foobar", futs[i][1])
test "FloodSub validation one fails and one succeeds": var subs: seq[Future[void]]
proc runTests() {.async.} = for i in 0..<runs:
var handlerFut = newFuture[bool]() for y in 0..<runs:
proc handler(topic: string, data: seq[byte]) {.async, gcsafe.} = if y != i:
check topic == "foo" subs &= waitSub(nodes[i], nodes[y], "foobar")
handlerFut.complete(true) await allFuturesThrowing(subs)
let var pubs: seq[Future[int]]
nodes = generateNodes(2) for i in 0..<runs:
pubs &= nodes[i].publish("foobar", ("Hello!" & $i).toBytes())
await allFuturesThrowing(pubs)
# start switches await allFuturesThrowing(futs.mapIt(it[0]))
nodesFut = await allFinished( await allFuturesThrowing(
nodes[0].switch.start(), nodes.mapIt(
nodes[1].switch.start(), allFutures(
it.stop(),
it.switch.stop())))
await allFuturesThrowing(nodesFut)
asyncTest "FloodSub multiple peers, with self trigger":
var runs = 10
var futs = newSeq[(Future[void], TopicHandler, ref int)](runs)
for i in 0..<runs:
closureScope:
var
fut = newFuture[void]()
counter = new int
futs[i] = (
fut,
(proc(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
inc counter[]
if counter[] == runs - 1:
fut.complete()),
counter
) )
# start pubsubcon let
await allFuturesThrowing( nodes = generateNodes(runs, triggerSelf = true)
allFinished( nodesFut = nodes.mapIt(it.switch.start())
nodes[0].start(),
nodes[1].start(),
))
await subscribeNodes(nodes) await allFuturesThrowing(nodes.mapIt(it.start()))
await nodes[1].subscribe("foo", handler) await subscribeNodes(nodes)
await waitSub(nodes[0], nodes[1], "foo")
await nodes[1].subscribe("bar", handler)
await waitSub(nodes[0], nodes[1], "bar")
proc validator(topic: string, for i in 0..<runs:
message: Message): Future[ValidationResult] {.async.} = await nodes[i].subscribe("foobar", futs[i][1])
if topic == "foo":
result = ValidationResult.Accept
else:
result = ValidationResult.Reject
nodes[1].addValidator("foo", "bar", validator) var subs: seq[Future[void]]
for i in 0..<runs:
for y in 0..<runs:
if y != i:
subs &= waitSub(nodes[i], nodes[y], "foobar")
await allFuturesThrowing(subs)
check (await nodes[0].publish("foo", "Hello!".toBytes())) > 0 var pubs: seq[Future[int]]
check (await nodes[0].publish("bar", "Hello!".toBytes())) > 0 for i in 0..<runs:
pubs &= nodes[i].publish("foobar", ("Hello!" & $i).toBytes())
await allFuturesThrowing(pubs)
await allFuturesThrowing( await allFuturesThrowing(futs.mapIt(it[0]))
nodes[0].switch.stop(), await allFuturesThrowing(
nodes[1].switch.stop() nodes.mapIt(
) allFutures(
it.stop(),
it.switch.stop())))
await allFuturesThrowing( await allFuturesThrowing(nodesFut)
nodes[0].stop(),
nodes[1].stop()
)
await allFuturesThrowing(nodesFut)
waitFor(runTests())
test "FloodSub multiple peers, no self trigger":
proc runTests() {.async.} =
var runs = 10
var futs = newSeq[(Future[void], TopicHandler, ref int)](runs)
for i in 0..<runs:
closureScope:
var
fut = newFuture[void]()
counter = new int
futs[i] = (
fut,
(proc(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
inc counter[]
if counter[] == runs - 1:
fut.complete()),
counter
)
let
nodes = generateNodes(runs, triggerSelf = false)
nodesFut = nodes.mapIt(it.switch.start())
await allFuturesThrowing(nodes.mapIt(it.start()))
await subscribeNodes(nodes)
for i in 0..<runs:
await nodes[i].subscribe("foobar", futs[i][1])
var subs: seq[Future[void]]
for i in 0..<runs:
for y in 0..<runs:
if y != i:
subs &= waitSub(nodes[i], nodes[y], "foobar")
await allFuturesThrowing(subs)
var pubs: seq[Future[int]]
for i in 0..<runs:
pubs &= nodes[i].publish("foobar", ("Hello!" & $i).toBytes())
await allFuturesThrowing(pubs)
await allFuturesThrowing(futs.mapIt(it[0]))
await allFuturesThrowing(
nodes.mapIt(
allFutures(
it.stop(),
it.switch.stop())))
await allFuturesThrowing(nodesFut)
waitFor(runTests())
test "FloodSub multiple peers, with self trigger":
proc runTests() {.async.} =
var runs = 10
var futs = newSeq[(Future[void], TopicHandler, ref int)](runs)
for i in 0..<runs:
closureScope:
var
fut = newFuture[void]()
counter = new int
futs[i] = (
fut,
(proc(topic: string, data: seq[byte]) {.async, gcsafe.} =
check topic == "foobar"
inc counter[]
if counter[] == runs - 1:
fut.complete()),
counter
)
let
nodes = generateNodes(runs, triggerSelf = true)
nodesFut = nodes.mapIt(it.switch.start())
await allFuturesThrowing(nodes.mapIt(it.start()))
await subscribeNodes(nodes)
for i in 0..<runs:
await nodes[i].subscribe("foobar", futs[i][1])
var subs: seq[Future[void]]
for i in 0..<runs:
for y in 0..<runs:
if y != i:
subs &= waitSub(nodes[i], nodes[y], "foobar")
await allFuturesThrowing(subs)
var pubs: seq[Future[int]]
for i in 0..<runs:
pubs &= nodes[i].publish("foobar", ("Hello!" & $i).toBytes())
await allFuturesThrowing(pubs)
await allFuturesThrowing(futs.mapIt(it[0]))
await allFuturesThrowing(
nodes.mapIt(
allFutures(
it.stop(),
it.switch.stop())))
await allFuturesThrowing(nodesFut)
waitFor(runTests())

View File

@ -30,404 +30,345 @@ suite "GossipSub internal":
teardown: teardown:
checkTrackers() checkTrackers()
test "topic params": asyncTest "topic params":
proc testRun(): Future[bool] {.async.} = let params = TopicParams.init()
let params = TopicParams.init() params.validateParameters().tryGet()
params.validateParameters().tryGet()
return true asyncTest "`rebalanceMesh` Degree Lo":
let gossipSub = TestGossipSub.init(newStandardSwitch())
check: let topic = "foobar"
waitFor(testRun()) == true gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.topicParams[topic] = TopicParams.init()
test "`rebalanceMesh` Degree Lo": var conns = newSeq[Connection]()
proc testRun(): Future[bool] {.async.} = gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
let gossipSub = TestGossipSub.init(newStandardSwitch()) for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.sendConn = conn
gossipSub.onNewPeer(peer)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.gossipsub[topic].incl(peer)
let topic = "foobar" check gossipSub.peers.len == 15
gossipSub.mesh[topic] = initHashSet[PubSubPeer]() await gossipSub.rebalanceMesh(topic)
gossipSub.topicParams[topic] = TopicParams.init() check gossipSub.mesh[topic].len == GossipSubD # + 2 # account opportunistic grafts
var conns = newSeq[Connection]() await allFuturesThrowing(conns.mapIt(it.close()))
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]() await gossipSub.switch.stop()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.sendConn = conn
gossipSub.onNewPeer(peer)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.gossipsub[topic].incl(peer)
check gossipSub.peers.len == 15 asyncTest "`rebalanceMesh` Degree Hi":
await gossipSub.rebalanceMesh(topic) let gossipSub = TestGossipSub.init(newStandardSwitch())
check gossipSub.mesh[topic].len == GossipSubD # + 2 # account opportunistic grafts
await allFuturesThrowing(conns.mapIt(it.close())) let topic = "foobar"
await gossipSub.switch.stop() gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
result = true gossipSub.topicParams[topic] = TopicParams.init()
check: var conns = newSeq[Connection]()
waitFor(testRun()) == true gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
gossipSub.grafted(peer, topic)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.mesh[topic].incl(peer)
test "`rebalanceMesh` Degree Hi": check gossipSub.mesh[topic].len == 15
proc testRun(): Future[bool] {.async.} = await gossipSub.rebalanceMesh(topic)
let gossipSub = TestGossipSub.init(newStandardSwitch()) check gossipSub.mesh[topic].len == GossipSubD + gossipSub.parameters.dScore
let topic = "foobar" await allFuturesThrowing(conns.mapIt(it.close()))
gossipSub.mesh[topic] = initHashSet[PubSubPeer]() await gossipSub.switch.stop()
gossipSub.topicParams[topic] = TopicParams.init()
var conns = newSeq[Connection]() asyncTest "`replenishFanout` Degree Lo":
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]() let gossipSub = TestGossipSub.init(newStandardSwitch())
for i in 0..<15:
let conn = newBufferStream(noop) proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
conns &= conn discard
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo let topic = "foobar"
let peer = gossipSub.getPubSubPeer(peerInfo.peerId) gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
gossipSub.onNewPeer(peer) gossipSub.topicParams[topic] = TopicParams.init()
var conns = newSeq[Connection]()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
var peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
check gossipSub.gossipsub[topic].len == 15
gossipSub.replenishFanout(topic)
check gossipSub.fanout[topic].len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`dropFanoutPeers` drop expired fanout topics":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic] = Moment.fromNow(1.millis)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.fanout[topic].incl(peer)
check gossipSub.fanout[topic].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic notin gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`dropFanoutPeers` leave unexpired fanout topics":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic1 = "foobar1"
let topic2 = "foobar2"
gossipSub.topicParams[topic1] = TopicParams.init()
gossipSub.topicParams[topic2] = TopicParams.init()
gossipSub.fanout[topic1] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic2] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic1] = Moment.fromNow(1.millis)
gossipSub.lastFanoutPubSub[topic2] = Moment.fromNow(1.minutes)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.fanout[topic1].incl(peer)
gossipSub.fanout[topic2].incl(peer)
check gossipSub.fanout[topic1].len == GossipSubD
check gossipSub.fanout[topic2].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic1 notin gossipSub.fanout
check topic2 in gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`getGossipPeers` - should gather up to degree D non intersecting peers":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
# generate mesh and fanout peers
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.grafted(peer, topic) gossipSub.grafted(peer, topic)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.mesh[topic].incl(peer) gossipSub.mesh[topic].incl(peer)
check gossipSub.mesh[topic].len == 15 # generate gossipsub (free standing) peers
await gossipSub.rebalanceMesh(topic) for i in 0..<15:
check gossipSub.mesh[topic].len == GossipSubD + gossipSub.parameters.dScore let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
await allFuturesThrowing(conns.mapIt(it.close())) # generate messages
await gossipSub.switch.stop() var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
result = true check gossipSub.fanout[topic].len == 15
check gossipSub.mesh[topic].len == 15
check gossipSub.gossipsub[topic].len == 15
check: let peers = gossipSub.getGossipPeers()
waitFor(testRun()) == true check peers.len == GossipSubD
for p in peers.keys:
check not gossipSub.fanout.hasPeerID(topic, p.peerId)
check not gossipSub.mesh.hasPeerID(topic, p.peerId)
test "`replenishFanout` Degree Lo": await allFuturesThrowing(conns.mapIt(it.close()))
proc testRun(): Future[bool] {.async.} = await gossipSub.switch.stop()
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} = asyncTest "`getGossipPeers` - should not crash on missing topics in mesh":
discard let gossipSub = TestGossipSub.init(newStandardSwitch())
let topic = "foobar" proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]() discard
gossipSub.topicParams[topic] = TopicParams.init()
var conns = newSeq[Connection]() let topic = "foobar"
for i in 0..<15: gossipSub.topicParams[topic] = TopicParams.init()
let conn = newBufferStream(noop) gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
conns &= conn gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var peerInfo = randomPeerInfo() var conns = newSeq[Connection]()
conn.peerInfo = peerInfo for i in 0..<30:
let peer = gossipSub.getPubSubPeer(peerInfo.peerId) let conn = newBufferStream(noop)
gossipSub.onNewPeer(peer) conns &= conn
peer.handler = handler let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.gossipsub[topic].incl(peer) gossipSub.gossipsub[topic].incl(peer)
check gossipSub.gossipsub[topic].len == 15 # generate messages
gossipSub.replenishFanout(topic) var seqno = 0'u64
check gossipSub.fanout[topic].len == GossipSubD for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
await allFuturesThrowing(conns.mapIt(it.close())) let peers = gossipSub.getGossipPeers()
await gossipSub.switch.stop() check peers.len == GossipSubD
result = true await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
check: asyncTest "`getGossipPeers` - should not crash on missing topics in fanout":
waitFor(testRun()) == true let gossipSub = TestGossipSub.init(newStandardSwitch())
test "`dropFanoutPeers` drop expired fanout topics": proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
proc testRun(): Future[bool] {.async.} = discard
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} = let topic = "foobar"
discard gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
gossipSub.grafted(peer, topic)
else:
gossipSub.gossipsub[topic].incl(peer)
let topic = "foobar" # generate messages
gossipSub.topicParams[topic] = TopicParams.init() var seqno = 0'u64
gossipSub.fanout[topic] = initHashSet[PubSubPeer]() for i in 0..5:
gossipSub.lastFanoutPubSub[topic] = Moment.fromNow(1.millis) let conn = newBufferStream(noop)
await sleepAsync(5.millis) # allow the topic to expire conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
var conns = newSeq[Connection]() let peers = gossipSub.getGossipPeers()
for i in 0..<6: check peers.len == GossipSubD
let conn = newBufferStream(noop)
conns &= conn await allFuturesThrowing(conns.mapIt(it.close()))
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) await gossipSub.switch.stop()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId) asyncTest "`getGossipPeers` - should not crash on missing topics in gossip":
gossipSub.onNewPeer(peer) let gossipSub = TestGossipSub.init(newStandardSwitch())
peer.handler = handler
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
gossipSub.grafted(peer, topic)
else:
gossipSub.fanout[topic].incl(peer) gossipSub.fanout[topic].incl(peer)
check gossipSub.fanout[topic].len == GossipSubD # generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
gossipSub.dropFanoutPeers() let peers = gossipSub.getGossipPeers()
check topic notin gossipSub.fanout check peers.len == 0
await allFuturesThrowing(conns.mapIt(it.close())) await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop() await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`dropFanoutPeers` leave unexpired fanout topics":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic1 = "foobar1"
let topic2 = "foobar2"
gossipSub.topicParams[topic1] = TopicParams.init()
gossipSub.topicParams[topic2] = TopicParams.init()
gossipSub.fanout[topic1] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic2] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic1] = Moment.fromNow(1.millis)
gossipSub.lastFanoutPubSub[topic2] = Moment.fromNow(1.minutes)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.fanout[topic1].incl(peer)
gossipSub.fanout[topic2].incl(peer)
check gossipSub.fanout[topic1].len == GossipSubD
check gossipSub.fanout[topic2].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic1 notin gossipSub.fanout
check topic2 in gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should gather up to degree D non intersecting peers":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
# generate mesh and fanout peers
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.grafted(peer, topic)
gossipSub.mesh[topic].incl(peer)
# generate gossipsub (free standing) peers
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
check gossipSub.fanout[topic].len == 15
check gossipSub.mesh[topic].len == 15
check gossipSub.gossipsub[topic].len == 15
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
for p in peers.keys:
check not gossipSub.fanout.hasPeerID(topic, p.peerId)
check not gossipSub.mesh.hasPeerID(topic, p.peerId)
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in mesh":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in fanout":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
gossipSub.grafted(peer, topic)
else:
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in gossip":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.topicParams[topic] = TopicParams.init()
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.onNewPeer(peer)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
gossipSub.grafted(peer, topic)
else:
gossipSub.fanout[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == 0
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true

View File

@ -28,375 +28,320 @@ proc randomPeerInfo(): PeerInfo =
suite "GossipSub internal": suite "GossipSub internal":
teardown: teardown:
for tracker in testTrackers(): checkTrackers()
# echo tracker.dump()
check tracker.isLeaked() == false
test "`rebalanceMesh` Degree Lo": asyncTest "`rebalanceMesh` Degree Lo":
proc testRun(): Future[bool] {.async.} = let gossipSub = TestGossipSub.init(newStandardSwitch())
let gossipSub = TestGossipSub.init(newStandardSwitch())
let topic = "foobar" let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]() gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]() var conns = newSeq[Connection]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]() gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
for i in 0..<15: for i in 0..<15:
let conn = newBufferStream(noop) let conn = newBufferStream(noop)
conns &= conn conns &= conn
let peerInfo = randomPeerInfo() let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId) let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.sendConn = conn peer.sendConn = conn
gossipSub.peers[peerInfo.peerId] = peer gossipSub.peers[peerInfo.peerId] = peer
gossipSub.mesh[topic].incl(peer)
check gossipSub.peers.len == 15
await gossipSub.rebalanceMesh(topic)
check gossipSub.mesh[topic].len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`rebalanceMesh` Degree Hi":
let gossipSub = TestGossipSub.init(newStandardSwitch())
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.topics[topic] = Topic() # has to be in topics to rebalance
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.mesh[topic].incl(peer)
check gossipSub.mesh[topic].len == 15
await gossipSub.rebalanceMesh(topic)
check gossipSub.mesh[topic].len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`replenishFanout` Degree Lo":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
var peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
check gossipSub.gossipsub[topic].len == 15
gossipSub.replenishFanout(topic)
check gossipSub.fanout[topic].len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`dropFanoutPeers` drop expired fanout topics":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic] = Moment.fromNow(1.millis)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.fanout[topic].incl(peer)
check gossipSub.fanout[topic].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic notin gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTEst "`dropFanoutPeers` leave unexpired fanout topics":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic1 = "foobar1"
let topic2 = "foobar2"
gossipSub.fanout[topic1] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic2] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic1] = Moment.fromNow(1.millis)
gossipSub.lastFanoutPubSub[topic2] = Moment.fromNow(1.minutes)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.fanout[topic1].incl(peer)
gossipSub.fanout[topic2].incl(peer)
check gossipSub.fanout[topic1].len == GossipSubD
check gossipSub.fanout[topic2].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic1 notin gossipSub.fanout
check topic2 in gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
asyncTest "`getGossipPeers` - should gather up to degree D non intersecting peers":
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
# generate mesh and fanout peers
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.mesh[topic].incl(peer) gossipSub.mesh[topic].incl(peer)
check gossipSub.peers.len == 15 # generate gossipsub (free standing) peers
await gossipSub.rebalanceMesh(topic) for i in 0..<15:
check gossipSub.mesh[topic].len == GossipSubD let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
await allFuturesThrowing(conns.mapIt(it.close())) # generate messages
await gossipSub.switch.stop() var seqno = 0'u64
result = true for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
check: check gossipSub.fanout[topic].len == 15
waitFor(testRun()) == true check gossipSub.mesh[topic].len == 15
check gossipSub.gossipsub[topic].len == 15
test "`rebalanceMesh` Degree Hi": let peers = gossipSub.getGossipPeers()
proc testRun(): Future[bool] {.async.} = check peers.len == GossipSubD
let gossipSub = TestGossipSub.init(newStandardSwitch()) for p in peers.keys:
check not gossipSub.fanout.hasPeerID(topic, p.peerId)
check not gossipSub.mesh.hasPeerID(topic, p.peerId)
let topic = "foobar" await allFuturesThrowing(conns.mapIt(it.close()))
gossipSub.mesh[topic] = initHashSet[PubSubPeer]() await gossipSub.switch.stop()
gossipSub.topics[topic] = Topic() # has to be in topics to rebalance
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]() asyncTest "`getGossipPeers` - should not crash on missing topics in mesh":
var conns = newSeq[Connection]() let gossipSub = TestGossipSub.init(newStandardSwitch())
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
gossipSub.peers[peerInfo.peerId] = peer
gossipSub.mesh[topic].incl(peer)
check gossipSub.mesh[topic].len == 15 proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
await gossipSub.rebalanceMesh(topic) discard
check gossipSub.mesh[topic].len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close())) let topic = "foobar"
await gossipSub.switch.stop() gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
result = true var conns = newSeq[Connection]()
for i in 0..<30:
check: let conn = newBufferStream(noop)
waitFor(testRun()) == true conns &= conn
let peerInfo = randomPeerInfo()
test "`replenishFanout` Degree Lo": conn.peerInfo = peerInfo
proc testRun(): Future[bool] {.async.} = let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
let gossipSub = TestGossipSub.init(newStandardSwitch()) peer.handler = handler
if i mod 2 == 0:
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} = gossipSub.fanout[topic].incl(peer)
discard else:
let topic = "foobar"
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
var peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer) gossipSub.gossipsub[topic].incl(peer)
check gossipSub.gossipsub[topic].len == 15 # generate messages
gossipSub.replenishFanout(topic) var seqno = 0'u64
check gossipSub.fanout[topic].len == GossipSubD for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
await allFuturesThrowing(conns.mapIt(it.close())) let peers = gossipSub.getGossipPeers()
await gossipSub.switch.stop() check peers.len == GossipSubD
result = true await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
check: asyncTest "`getGossipPeers` - should not crash on missing topics in fanout":
waitFor(testRun()) == true let gossipSub = TestGossipSub.init(newStandardSwitch())
test "`dropFanoutPeers` drop expired fanout topics": proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
proc testRun(): Future[bool] {.async.} = discard
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} = let topic = "foobar"
discard gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
else:
gossipSub.gossipsub[topic].incl(peer)
let topic = "foobar" # generate messages
gossipSub.fanout[topic] = initHashSet[PubSubPeer]() var seqno = 0'u64
gossipSub.lastFanoutPubSub[topic] = Moment.fromNow(1.millis) for i in 0..5:
await sleepAsync(5.millis) # allow the topic to expire let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
var conns = newSeq[Connection]() let peers = gossipSub.getGossipPeers()
for i in 0..<6: check peers.len == GossipSubD
let conn = newBufferStream(noop)
conns &= conn await allFuturesThrowing(conns.mapIt(it.close()))
let peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) await gossipSub.switch.stop()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId) asyncTest "`getGossipPeers` - should not crash on missing topics in gossip":
peer.handler = handler let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
else:
gossipSub.fanout[topic].incl(peer) gossipSub.fanout[topic].incl(peer)
check gossipSub.fanout[topic].len == GossipSubD # generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
gossipSub.dropFanoutPeers() let peers = gossipSub.getGossipPeers()
check topic notin gossipSub.fanout check peers.len == 0
await allFuturesThrowing(conns.mapIt(it.close())) await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop() await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`dropFanoutPeers` leave unexpired fanout topics":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic1 = "foobar1"
let topic2 = "foobar2"
gossipSub.fanout[topic1] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic2] = initHashSet[PubSubPeer]()
gossipSub.lastFanoutPubSub[topic1] = Moment.fromNow(1.millis)
gossipSub.lastFanoutPubSub[topic2] = Moment.fromNow(1.minutes)
await sleepAsync(5.millis) # allow the topic to expire
var conns = newSeq[Connection]()
for i in 0..<6:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.fanout[topic1].incl(peer)
gossipSub.fanout[topic2].incl(peer)
check gossipSub.fanout[topic1].len == GossipSubD
check gossipSub.fanout[topic2].len == GossipSubD
gossipSub.dropFanoutPeers()
check topic1 notin gossipSub.fanout
check topic2 in gossipSub.fanout
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should gather up to degree D non intersecting peers":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
# generate mesh and fanout peers
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.mesh[topic].incl(peer)
# generate gossipsub (free standing) peers
for i in 0..<15:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
check gossipSub.fanout[topic].len == 15
check gossipSub.mesh[topic].len == 15
check gossipSub.gossipsub[topic].len == 15
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
for p in peers.keys:
check not gossipSub.fanout.hasPeerID(topic, p.peerId)
check not gossipSub.mesh.hasPeerID(topic, p.peerId)
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in mesh":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.fanout[topic].incl(peer)
else:
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in fanout":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.gossipsub[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
else:
gossipSub.gossipsub[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("HELLO" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == GossipSubD
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true
test "`getGossipPeers` - should not crash on missing topics in gossip":
proc testRun(): Future[bool] {.async.} =
let gossipSub = TestGossipSub.init(newStandardSwitch())
proc handler(peer: PubSubPeer, msg: RPCMsg) {.async.} =
discard
let topic = "foobar"
gossipSub.mesh[topic] = initHashSet[PubSubPeer]()
gossipSub.fanout[topic] = initHashSet[PubSubPeer]()
var conns = newSeq[Connection]()
for i in 0..<30:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
let peer = gossipSub.getPubSubPeer(peerInfo.peerId)
peer.handler = handler
if i mod 2 == 0:
gossipSub.mesh[topic].incl(peer)
else:
gossipSub.fanout[topic].incl(peer)
# generate messages
var seqno = 0'u64
for i in 0..5:
let conn = newBufferStream(noop)
conns &= conn
let peerInfo = randomPeerInfo()
conn.peerInfo = peerInfo
inc seqno
let msg = Message.init(some(peerInfo), ("bar" & $i).toBytes(), topic, some(seqno), false)
gossipSub.mcache.put(gossipSub.msgIdProvider(msg), msg)
let peers = gossipSub.getGossipPeers()
check peers.len == 0
await allFuturesThrowing(conns.mapIt(it.close()))
await gossipSub.switch.stop()
result = true
check:
waitFor(testRun()) == true

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@ import chronos, stew/byteutils
import ../libp2p/stream/bufferstream, import ../libp2p/stream/bufferstream,
../libp2p/stream/lpstream ../libp2p/stream/lpstream
import ./helpers
{.used.} {.used.}
suite "BufferStream": suite "BufferStream":
@ -10,224 +12,154 @@ suite "BufferStream":
# echo getTracker(BufferStreamTrackerName).dump() # echo getTracker(BufferStreamTrackerName).dump()
check getTracker(BufferStreamTrackerName).isLeaked() == false check getTracker(BufferStreamTrackerName).isLeaked() == false
test "push data to buffer": asyncTest "push data to buffer":
proc testpushData(): Future[bool] {.async.} = let buff = newBufferStream()
let buff = newBufferStream() check buff.len == 0
check buff.len == 0 var data = "12345"
var data = "12345" await buff.pushData(data.toBytes())
await buff.pushData(data.toBytes()) check buff.len == 5
check buff.len == 5 await buff.close()
result = true
await buff.close() asyncTest "push and wait":
let buff = newBufferStream()
check buff.len == 0
check: let fut0 = buff.pushData("1234".toBytes())
waitFor(testpushData()) == true let fut1 = buff.pushData("5".toBytes())
check buff.len == 4 # the second write should not be visible yet
test "push and wait": var data: array[1, byte]
proc testpushData(): Future[bool] {.async.} = check: 1 == await buff.readOnce(addr data[0], data.len)
let buff = newBufferStream()
check buff.len == 0
let fut0 = buff.pushData("1234".toBytes()) check ['1'] == string.fromBytes(data)
let fut1 = buff.pushData("5".toBytes()) await fut0
check buff.len == 4 # the second write should not be visible yet await fut1
check buff.len == 4
await buff.close()
var data: array[1, byte] asyncTest "read with size":
check: 1 == await buff.readOnce(addr data[0], data.len) let buff = newBufferStream()
check buff.len == 0
check ['1'] == string.fromBytes(data) await buff.pushData("12345".toBytes())
await fut0 var data: array[3, byte]
await fut1 await buff.readExactly(addr data[0], data.len)
check buff.len == 4 check ['1', '2', '3'] == string.fromBytes(data)
await buff.close()
result = true asyncTest "readExactly":
let buff = newBufferStream()
check buff.len == 0
await buff.close() await buff.pushData("12345".toBytes())
check buff.len == 5
var data: array[2, byte]
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == ['1', '2']
await buff.close()
check: asyncTest "readExactly raises":
waitFor(testpushData()) == true let buff = newBufferStream()
check buff.len == 0
test "read with size": await buff.pushData("123".toBytes())
proc testRead(): Future[bool] {.async.} = var data: array[5, byte]
let buff = newBufferStream() var readFut = buff.readExactly(addr data[0], data.len)
check buff.len == 0 await buff.close()
await buff.pushData("12345".toBytes()) expect LPStreamIncompleteError:
var data: array[3, byte] await readFut
await buff.readExactly(addr data[0], data.len)
check ['1', '2', '3'] == string.fromBytes(data)
result = true asyncTest "readOnce":
let buff = newBufferStream()
check buff.len == 0
await buff.close() var data: array[3, byte]
let readFut = buff.readOnce(addr data[0], data.len)
await buff.pushData("123".toBytes())
check buff.len == 3
check: check (await readFut) == 3
waitFor(testRead()) == true check string.fromBytes(data) == ['1', '2', '3']
await buff.close()
test "readExactly": asyncTest "reads should happen in order":
proc testReadExactly(): Future[bool] {.async.} = let buff = newBufferStream()
let buff = newBufferStream() check buff.len == 0
check buff.len == 0
await buff.pushData("12345".toBytes()) let w1 = buff.pushData("Msg 1".toBytes())
check buff.len == 5 let w2 = buff.pushData("Msg 2".toBytes())
var data: array[2, byte] let w3 = buff.pushData("Msg 3".toBytes())
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == ['1', '2']
result = true var data: array[5, byte]
await buff.readExactly(addr data[0], data.len)
await buff.close() check string.fromBytes(data) == "Msg 1"
check: await buff.readExactly(addr data[0], data.len)
waitFor(testReadExactly()) == true check string.fromBytes(data) == "Msg 2"
test "readExactly raises": await buff.readExactly(addr data[0], data.len)
proc testReadExactly(): Future[bool] {.async.} = check string.fromBytes(data) == "Msg 3"
let buff = newBufferStream()
check buff.len == 0
await buff.pushData("123".toBytes()) for f in [w1, w2, w3]: await f
var data: array[5, byte]
var readFut = buff.readExactly(addr data[0], data.len)
await buff.close()
try: let w4 = buff.pushData("Msg 4".toBytes())
await readFut let w5 = buff.pushData("Msg 5".toBytes())
except LPStreamIncompleteError: let w6 = buff.pushData("Msg 6".toBytes())
result = true
check: await buff.close()
waitFor(testReadExactly()) == true
test "readOnce": await buff.readExactly(addr data[0], data.len)
proc testReadOnce(): Future[bool] {.async.} = check string.fromBytes(data) == "Msg 4"
let buff = newBufferStream()
check buff.len == 0
var data: array[3, byte] await buff.readExactly(addr data[0], data.len)
let readFut = buff.readOnce(addr data[0], data.len) check string.fromBytes(data) == "Msg 5"
await buff.pushData("123".toBytes())
check buff.len == 3
check (await readFut) == 3 await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == ['1', '2', '3'] check string.fromBytes(data) == "Msg 6"
for f in [w4, w5, w6]: await f
result = true asyncTest "small reads":
let buff = newBufferStream()
check buff.len == 0
await buff.close() var writes: seq[Future[void]]
var str: string
for i in 0..<10:
writes.add buff.pushData("123".toBytes())
str &= "123"
await buff.close() # all data should still be read after close
check: var str2: string
waitFor(testReadOnce()) == true var data: array[2, byte]
expect LPStreamEOFError:
while true:
let x = await buff.readOnce(addr data[0], data.len)
str2 &= string.fromBytes(data[0..<x])
test "reads should happen in order": for f in writes: await f
proc testWritePtr(): Future[bool] {.async.} = check str == str2
let buff = newBufferStream() await buff.close()
check buff.len == 0
let w1 = buff.pushData("Msg 1".toBytes()) asyncTest "shouldn't get stuck on close":
let w2 = buff.pushData("Msg 2".toBytes()) var stream = newBufferStream()
let w3 = buff.pushData("Msg 3".toBytes()) var
fut = stream.pushData(toBytes("hello"))
fut2 = stream.pushData(toBytes("again"))
await stream.close()
expect AsyncTimeoutError:
await wait(fut, 100.milliseconds)
await wait(fut2, 100.milliseconds)
var data: array[5, byte] await stream.close()
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == "Msg 1" asyncTest "no push after close":
var stream = newBufferStream()
await stream.pushData("123".toBytes())
var data: array[3, byte]
await stream.readExactly(addr data[0], data.len)
await stream.close()
await buff.readExactly(addr data[0], data.len) expect LPStreamEOFError:
check string.fromBytes(data) == "Msg 2"
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == "Msg 3"
for f in [w1, w2, w3]: await f
let w4 = buff.pushData("Msg 4".toBytes())
let w5 = buff.pushData("Msg 5".toBytes())
let w6 = buff.pushData("Msg 6".toBytes())
await buff.close()
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == "Msg 4"
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == "Msg 5"
await buff.readExactly(addr data[0], data.len)
check string.fromBytes(data) == "Msg 6"
for f in [w4, w5, w6]: await f
result = true
check:
waitFor(testWritePtr()) == true
test "small reads":
proc testWritePtr(): Future[bool] {.async.} =
let buff = newBufferStream()
check buff.len == 0
var writes: seq[Future[void]]
var str: string
for i in 0..<10:
writes.add buff.pushData("123".toBytes())
str &= "123"
await buff.close() # all data should still be read after close
var str2: string
var data: array[2, byte]
try:
while true:
let x = await buff.readOnce(addr data[0], data.len)
str2 &= string.fromBytes(data[0..<x])
except LPStreamEOFError:
discard
for f in writes: await f
check str == str2
result = true
await buff.close()
check:
waitFor(testWritePtr()) == true
test "shouldn't get stuck on close":
proc closeTest(): Future[bool] {.async.} =
var stream = newBufferStream()
var
fut = stream.pushData(toBytes("hello"))
fut2 = stream.pushData(toBytes("again"))
await stream.close()
try:
await wait(fut, 100.milliseconds)
await wait(fut2, 100.milliseconds)
result = true
except AsyncTimeoutError:
result = false
await stream.close()
check:
waitFor(closeTest()) == true
test "no push after close":
proc closeTest(): Future[bool] {.async.} =
var stream = newBufferStream()
await stream.pushData("123".toBytes()) await stream.pushData("123".toBytes())
var data: array[3, byte]
await stream.readExactly(addr data[0], data.len)
await stream.close()
try:
await stream.pushData("123".toBytes())
except LPStreamClosedError:
result = true
check:
waitFor(closeTest()) == true

View File

@ -3,47 +3,29 @@ import chronos, nimcrypto/utils
import ../libp2p/[stream/connection, import ../libp2p/[stream/connection,
stream/bufferstream] stream/bufferstream]
import ./helpers
suite "Connection": suite "Connection":
test "close": asyncTest "close":
proc test(): Future[bool] {.async.} = var conn = newBufferStream()
var conn = newBufferStream() await conn.close()
await conn.close()
check:
conn.closed == true
result = true
check: check:
waitFor(test()) == true conn.closed == true
test "parent close": asyncTest "parent close":
proc test(): Future[bool] {.async.} = var buf = newBufferStream()
var buf = newBufferStream() var conn = buf
var conn = buf
await conn.close()
check:
conn.closed == true
buf.closed == true
await sleepAsync(1.seconds)
result = true
await conn.close()
check: check:
waitFor(test()) == true conn.closed == true
buf.closed == true
test "child close": asyncTest "child close":
proc test(): Future[bool] {.async.} = var buf = newBufferStream()
var buf = newBufferStream() var conn = buf
var conn = buf
await buf.close()
check:
conn.closed == true
buf.closed == true
await sleepAsync(1.seconds)
result = true
await buf.close()
check: check:
waitFor(test()) == true conn.closed == true
buf.closed == true

View File

@ -17,75 +17,68 @@ suite "Identify":
teardown: teardown:
checkTrackers() checkTrackers()
test "handle identify message": asyncTest "handle identify message":
proc testHandle(): Future[bool] {.async.} = let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let remoteSecKey = PrivateKey.random(ECDSA, rng[]).get()
let remoteSecKey = PrivateKey.random(ECDSA, rng[]).get() let remotePeerInfo = PeerInfo.init(remoteSecKey,
let remotePeerInfo = PeerInfo.init(remoteSecKey, [ma],
[ma], ["/test/proto1/1.0.0",
["/test/proto1/1.0.0", "/test/proto2/1.0.0"])
"/test/proto2/1.0.0"]) var serverFut: Future[void]
var serverFut: Future[void] let identifyProto1 = newIdentify(remotePeerInfo)
let identifyProto1 = newIdentify(remotePeerInfo) let msListen = newMultistream()
let msListen = newMultistream()
msListen.addHandler(IdentifyCodec, identifyProto1) msListen.addHandler(IdentifyCodec, identifyProto1)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} = proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn) await msListen.handle(conn)
var transport1 = TcpTransport.init() var transport1 = TcpTransport.init()
serverFut = await transport1.listen(ma, connHandler) serverFut = await transport1.listen(ma, connHandler)
let msDial = newMultistream() let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init() let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma) let conn = await transport2.dial(transport1.ma)
var peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma]) var peerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma])
let identifyProto2 = newIdentify(peerInfo) let identifyProto2 = newIdentify(peerInfo)
discard await msDial.select(conn, IdentifyCodec) discard await msDial.select(conn, IdentifyCodec)
let id = await identifyProto2.identify(conn, remotePeerInfo) let id = await identifyProto2.identify(conn, remotePeerInfo)
check id.pubKey.get() == remoteSecKey.getKey().get() check id.pubKey.get() == remoteSecKey.getKey().get()
check id.addrs[0] == ma check id.addrs[0] == ma
check id.protoVersion.get() == ProtoVersion check id.protoVersion.get() == ProtoVersion
# check id.agentVersion.get() == AgentVersion # check id.agentVersion.get() == AgentVersion
check id.protos == @["/test/proto1/1.0.0", "/test/proto2/1.0.0"] check id.protos == @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
await conn.close()
await transport1.close()
await serverFut
await transport2.close()
asyncTest "handle failed identify":
let ma = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var remotePeerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma])
let identifyProto1 = newIdentify(remotePeerInfo)
let msListen = newMultistream()
let done = newFuture[void]()
msListen.addHandler(IdentifyCodec, identifyProto1)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
await conn.close() await conn.close()
await transport1.close() done.complete()
await serverFut
result = true let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
await transport2.close() let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
check: let conn = await transport2.dial(transport1.ma)
waitFor(testHandle()) == true var localPeerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma])
let identifyProto2 = newIdentify(localPeerInfo)
test "handle failed identify":
proc testHandleError() {.async.} =
let ma = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var remotePeerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma])
let identifyProto1 = newIdentify(remotePeerInfo)
let msListen = newMultistream()
let done = newFuture[void]()
msListen.addHandler(IdentifyCodec, identifyProto1)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
await conn.close()
done.complete()
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
var localPeerInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [ma])
let identifyProto2 = newIdentify(localPeerInfo)
expect IdentityNoMatchError:
try: try:
let pi2 = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get()) let pi2 = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get())
discard await msDial.select(conn, IdentifyCodec) discard await msDial.select(conn, IdentifyCodec)
@ -95,6 +88,3 @@ suite "Identify":
await conn.close() await conn.close()
await transport2.close() await transport2.close()
await transport1.close() await transport1.close()
expect IdentityNoMatchError:
waitFor(testHandleError())

View File

@ -58,8 +58,7 @@ proc readLp*(s: StreamTransport): Future[seq[byte]] {.async, gcsafe.} =
if size > 0.uint: if size > 0.uint:
await s.readExactly(addr result[0], int(size)) await s.readExactly(addr result[0], int(size))
proc testPubSubDaemonPublish(gossip: bool = false, proc testPubSubDaemonPublish(gossip: bool = false, count: int = 1) {.async.} =
count: int = 1): Future[bool] {.async.} =
var pubsubData = "TEST MESSAGE" var pubsubData = "TEST MESSAGE"
var testTopic = "test-topic" var testTopic = "test-topic"
var msgData = pubsubData.toBytes() var msgData = pubsubData.toBytes()
@ -120,14 +119,12 @@ proc testPubSubDaemonPublish(gossip: bool = false,
await wait(publisher(), 5.minutes) # should be plenty of time await wait(publisher(), 5.minutes) # should be plenty of time
result = true
await nativeNode.stop() await nativeNode.stop()
await pubsub.stop() await pubsub.stop()
await allFutures(awaiters) await allFutures(awaiters)
await daemonNode.close() await daemonNode.close()
proc testPubSubNodePublish(gossip: bool = false, proc testPubSubNodePublish(gossip: bool = false, count: int = 1) {.async.} =
count: int = 1): Future[bool] {.async.} =
var pubsubData = "TEST MESSAGE" var pubsubData = "TEST MESSAGE"
var testTopic = "test-topic" var testTopic = "test-topic"
var msgData = pubsubData.toBytes() var msgData = pubsubData.toBytes()
@ -187,7 +184,7 @@ proc testPubSubNodePublish(gossip: bool = false,
await wait(publisher(), 5.minutes) # should be plenty of time await wait(publisher(), 5.minutes) # should be plenty of time
result = finished check finished
await nativeNode.stop() await nativeNode.stop()
await pubsub.stop() await pubsub.stop()
await allFutures(awaiters) await allFutures(awaiters)
@ -199,268 +196,236 @@ suite "Interop":
# and libp2p, so not sure which one it is, # and libp2p, so not sure which one it is,
# need to investigate more # need to investigate more
# teardown: # teardown:
# for tracker in testTrackers(): # checkTrackers()
# # echo tracker.dump()
# # check tracker.isLeaked() == false
# TODO: this test is failing sometimes on windows # TODO: this test is failing sometimes on windows
# For some reason we receive EOF before test 4 sometimes # For some reason we receive EOF before test 4 sometimes
test "native -> daemon multiple reads and writes": asyncTest "native -> daemon multiple reads and writes":
proc runTests(): Future[bool] {.async.} = var protos = @["/test-stream"]
var protos = @["/test-stream"]
let nativeNode = newStandardSwitch( let nativeNode = newStandardSwitch(
secureManagers = [SecureProtocol.Noise], secureManagers = [SecureProtocol.Noise],
outTimeout = 5.minutes) outTimeout = 5.minutes)
let awaiters = await nativeNode.start() let awaiters = await nativeNode.start()
let daemonNode = await newDaemonApi() let daemonNode = await newDaemonApi()
let daemonPeer = await daemonNode.identity() let daemonPeer = await daemonNode.identity()
var testFuture = newFuture[void]("test.future") var testFuture = newFuture[void]("test.future")
proc daemonHandler(api: DaemonAPI, stream: P2PStream) {.async.} = proc daemonHandler(api: DaemonAPI, stream: P2PStream) {.async.} =
check string.fromBytes(await stream.transp.readLp()) == "test 1" check string.fromBytes(await stream.transp.readLp()) == "test 1"
discard await stream.transp.writeLp("test 2") discard await stream.transp.writeLp("test 2")
check string.fromBytes(await stream.transp.readLp()) == "test 3" check string.fromBytes(await stream.transp.readLp()) == "test 3"
discard await stream.transp.writeLp("test 4") discard await stream.transp.writeLp("test 4")
testFuture.complete() testFuture.complete()
await daemonNode.addHandler(protos, daemonHandler) await daemonNode.addHandler(protos, daemonHandler)
let conn = await nativeNode.dial(NativePeerInfo.init(daemonPeer.peer, let conn = await nativeNode.dial(NativePeerInfo.init(daemonPeer.peer,
daemonPeer.addresses), daemonPeer.addresses),
protos[0]) protos[0])
await conn.writeLp("test 1") await conn.writeLp("test 1")
check "test 2" == string.fromBytes((await conn.readLp(1024))) check "test 2" == string.fromBytes((await conn.readLp(1024)))
await conn.writeLp("test 3")
check "test 4" == string.fromBytes((await conn.readLp(1024)))
await wait(testFuture, 10.secs) await conn.writeLp("test 3")
check "test 4" == string.fromBytes((await conn.readLp(1024)))
await nativeNode.stop() await wait(testFuture, 10.secs)
await daemonNode.close()
await allFutures(awaiters)
await sleepAsync(1.seconds) await nativeNode.stop()
result = true await daemonNode.close()
await allFutures(awaiters)
check: await sleepAsync(1.seconds)
waitFor(runTests()) == true
test "native -> daemon connection": asyncTest "native -> daemon connection":
proc runTests(): Future[bool] {.async.} = var protos = @["/test-stream"]
var protos = @["/test-stream"] var test = "TEST STRING"
var test = "TEST STRING" # We are preparing expect string, which should be prefixed with varint
# We are preparing expect string, which should be prefixed with varint # length and do not have `\r\n` suffix, because we going to use
# length and do not have `\r\n` suffix, because we going to use # readLine().
# readLine(). var buffer = initVBuffer()
var buffer = initVBuffer() buffer.writeSeq(test & "\r\n")
buffer.writeSeq(test & "\r\n") buffer.finish()
buffer.finish() var expect = newString(len(buffer) - 2)
var expect = newString(len(buffer) - 2) copyMem(addr expect[0], addr buffer.buffer[0], len(expect))
copyMem(addr expect[0], addr buffer.buffer[0], len(expect))
let nativeNode = newStandardSwitch( let nativeNode = newStandardSwitch(
secureManagers = [SecureProtocol.Noise], secureManagers = [SecureProtocol.Noise],
outTimeout = 5.minutes) outTimeout = 5.minutes)
let awaiters = await nativeNode.start() let awaiters = await nativeNode.start()
let daemonNode = await newDaemonApi() let daemonNode = await newDaemonApi()
let daemonPeer = await daemonNode.identity() let daemonPeer = await daemonNode.identity()
var testFuture = newFuture[string]("test.future") var testFuture = newFuture[string]("test.future")
proc daemonHandler(api: DaemonAPI, stream: P2PStream) {.async.} = proc daemonHandler(api: DaemonAPI, stream: P2PStream) {.async.} =
# We should perform `readLp()` instead of `readLine()`. `readLine()` # We should perform `readLp()` instead of `readLine()`. `readLine()`
# here reads actually length prefixed string. # here reads actually length prefixed string.
var line = await stream.transp.readLine() var line = await stream.transp.readLine()
check line == expect check line == expect
testFuture.complete(line) testFuture.complete(line)
await stream.close() await stream.close()
await daemonNode.addHandler(protos, daemonHandler) await daemonNode.addHandler(protos, daemonHandler)
let conn = await nativeNode.dial(NativePeerInfo.init(daemonPeer.peer, let conn = await nativeNode.dial(NativePeerInfo.init(daemonPeer.peer,
daemonPeer.addresses), daemonPeer.addresses),
protos[0]) protos[0])
await conn.writeLp(test & "\r\n") await conn.writeLp(test & "\r\n")
result = expect == (await wait(testFuture, 10.secs)) check expect == (await wait(testFuture, 10.secs))
await conn.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
asyncTest "daemon -> native connection":
var protos = @["/test-stream"]
var test = "TEST STRING"
var testFuture = newFuture[string]("test.future")
proc nativeHandler(conn: Connection, proto: string) {.async.} =
var line = string.fromBytes(await conn.readLp(1024))
check line == test
testFuture.complete(line)
await conn.close() await conn.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
check: # custom proto
waitFor(runTests()) == true var proto = new LPProtocol
proto.handler = nativeHandler
proto.codec = protos[0] # codec
test "daemon -> native connection": let nativeNode = newStandardSwitch(
proc runTests(): Future[bool] {.async.} = secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes)
var protos = @["/test-stream"]
var test = "TEST STRING"
var testFuture = newFuture[string]("test.future") nativeNode.mount(proto)
proc nativeHandler(conn: Connection, proto: string) {.async.} =
let awaiters = await nativeNode.start()
let nativePeer = nativeNode.peerInfo
let daemonNode = await newDaemonApi()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs)
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
discard await stream.transp.writeLp(test)
check test == (await wait(testFuture, 10.secs))
await stream.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
await sleepAsync(1.seconds)
asyncTest "daemon -> multiple reads and writes":
var protos = @["/test-stream"]
var testFuture = newFuture[void]("test.future")
proc nativeHandler(conn: Connection, proto: string) {.async.} =
check "test 1" == string.fromBytes(await conn.readLp(1024))
await conn.writeLp("test 2".toBytes())
check "test 3" == string.fromBytes(await conn.readLp(1024))
await conn.writeLp("test 4".toBytes())
testFuture.complete()
await conn.close()
# custom proto
var proto = new LPProtocol
proto.handler = nativeHandler
proto.codec = protos[0] # codec
let nativeNode = newStandardSwitch(
secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes)
nativeNode.mount(proto)
let awaiters = await nativeNode.start()
let nativePeer = nativeNode.peerInfo
let daemonNode = await newDaemonApi()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs)
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
asyncDiscard stream.transp.writeLp("test 1")
check "test 2" == string.fromBytes(await stream.transp.readLp())
asyncDiscard stream.transp.writeLp("test 3")
check "test 4" == string.fromBytes(await stream.transp.readLp())
await wait(testFuture, 10.secs)
await stream.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
asyncTest "read write multiple":
var protos = @["/test-stream"]
var test = "TEST STRING"
var count = 0
var testFuture = newFuture[int]("test.future")
proc nativeHandler(conn: Connection, proto: string) {.async.} =
while count < 10:
var line = string.fromBytes(await conn.readLp(1024)) var line = string.fromBytes(await conn.readLp(1024))
check line == test check line == test
testFuture.complete(line) await conn.writeLp(test.toBytes())
await conn.close() count.inc()
# custom proto testFuture.complete(count)
var proto = new LPProtocol await conn.close()
proto.handler = nativeHandler
proto.codec = protos[0] # codec
let nativeNode = newStandardSwitch( # custom proto
secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes) var proto = new LPProtocol
proto.handler = nativeHandler
proto.codec = protos[0] # codec
nativeNode.mount(proto) let nativeNode = newStandardSwitch(
secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes)
let awaiters = await nativeNode.start() nativeNode.mount(proto)
let nativePeer = nativeNode.peerInfo
let daemonNode = await newDaemonApi() let awaiters = await nativeNode.start()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs) let nativePeer = nativeNode.peerInfo
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
let daemonNode = await newDaemonApi()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs)
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
var count2 = 0
while count2 < 10:
discard await stream.transp.writeLp(test) discard await stream.transp.writeLp(test)
let line = await stream.transp.readLp()
check test == string.fromBytes(line)
inc(count2)
result = test == (await wait(testFuture, 10.secs)) check 10 == (await wait(testFuture, 1.minutes))
await stream.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
await stream.close() asyncTest "floodsub: daemon publish one":
await nativeNode.stop() await testPubSubDaemonPublish()
await allFutures(awaiters)
await daemonNode.close()
await sleepAsync(1.seconds)
check: asyncTest "floodsub: daemon publish many":
waitFor(runTests()) == true await testPubSubDaemonPublish(count = 10)
test "daemon -> multiple reads and writes": asyncTest "gossipsub: daemon publish one":
proc runTests(): Future[bool] {.async.} = await testPubSubDaemonPublish(gossip = true)
var protos = @["/test-stream"]
var testFuture = newFuture[void]("test.future") asyncTest "gossipsub: daemon publish many":
proc nativeHandler(conn: Connection, proto: string) {.async.} = await testPubSubDaemonPublish(gossip = true, count = 10)
check "test 1" == string.fromBytes(await conn.readLp(1024))
await conn.writeLp("test 2".toBytes())
check "test 3" == string.fromBytes(await conn.readLp(1024)) asyncTest "floodsub: node publish one":
await conn.writeLp("test 4".toBytes()) await testPubSubNodePublish()
testFuture.complete() asyncTest "floodsub: node publish many":
await conn.close() await testPubSubNodePublish(count = 10)
# custom proto asyncTest "gossipsub: node publish one":
var proto = new LPProtocol await testPubSubNodePublish(gossip = true)
proto.handler = nativeHandler
proto.codec = protos[0] # codec
let nativeNode = newStandardSwitch( asyncTest "gossipsub: node publish many":
secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes) await testPubSubNodePublish(gossip = true, count = 10)
nativeNode.mount(proto)
let awaiters = await nativeNode.start()
let nativePeer = nativeNode.peerInfo
let daemonNode = await newDaemonApi()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs)
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
asyncDiscard stream.transp.writeLp("test 1")
check "test 2" == string.fromBytes(await stream.transp.readLp())
asyncDiscard stream.transp.writeLp("test 3")
check "test 4" == string.fromBytes(await stream.transp.readLp())
await wait(testFuture, 10.secs)
result = true
await stream.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
check:
waitFor(runTests()) == true
test "read write multiple":
proc runTests(): Future[bool] {.async.} =
var protos = @["/test-stream"]
var test = "TEST STRING"
var count = 0
var testFuture = newFuture[int]("test.future")
proc nativeHandler(conn: Connection, proto: string) {.async.} =
while count < 10:
var line = string.fromBytes(await conn.readLp(1024))
check line == test
await conn.writeLp(test.toBytes())
count.inc()
testFuture.complete(count)
await conn.close()
# custom proto
var proto = new LPProtocol
proto.handler = nativeHandler
proto.codec = protos[0] # codec
let nativeNode = newStandardSwitch(
secureManagers = [SecureProtocol.Noise], outTimeout = 5.minutes)
nativeNode.mount(proto)
let awaiters = await nativeNode.start()
let nativePeer = nativeNode.peerInfo
let daemonNode = await newDaemonApi()
await daemonNode.connect(nativePeer.peerId, nativePeer.addrs)
var stream = await daemonNode.openStream(nativePeer.peerId, protos)
var count2 = 0
while count2 < 10:
discard await stream.transp.writeLp(test)
let line = await stream.transp.readLp()
check test == string.fromBytes(line)
inc(count2)
result = 10 == (await wait(testFuture, 1.minutes))
await stream.close()
await nativeNode.stop()
await allFutures(awaiters)
await daemonNode.close()
check:
waitFor(runTests()) == true
test "floodsub: daemon publish one":
check:
waitFor(testPubSubDaemonPublish()) == true
test "floodsub: daemon publish many":
check:
waitFor(testPubSubDaemonPublish(count = 10)) == true
test "gossipsub: daemon publish one":
check:
waitFor(testPubSubDaemonPublish(gossip = true)) == true
test "gossipsub: daemon publish many":
check:
waitFor(testPubSubDaemonPublish(gossip = true, count = 10)) == true
test "floodsub: node publish one":
check:
waitFor(testPubSubNodePublish()) == true
test "floodsub: node publish many":
check:
waitFor(testPubSubNodePublish(count = 10)) == true
test "gossipsub: node publish one":
check:
waitFor(testPubSubNodePublish(gossip = true)) == true
test "gossipsub: node publish many":
check:
waitFor(testPubSubNodePublish(gossip = true, count = 10)) == true

View File

@ -20,8 +20,8 @@ suite "Mplex":
teardown: teardown:
checkTrackers() checkTrackers()
test "encode header with channel id 0": suite "channel encoding":
proc testEncodeHeader() {.async.} = asyncTest "encode header with channel id 0":
proc encHandler(msg: seq[byte]) {.async.} = proc encHandler(msg: seq[byte]) {.async.} =
check msg == fromHex("000873747265616d2031") check msg == fromHex("000873747265616d2031")
@ -29,10 +29,7 @@ suite "Mplex":
await conn.writeMsg(0, MessageType.New, ("stream 1").toBytes) await conn.writeMsg(0, MessageType.New, ("stream 1").toBytes)
await conn.close() await conn.close()
waitFor(testEncodeHeader()) asyncTest "encode header with channel id other than 0":
test "encode header with channel id other than 0":
proc testEncodeHeader() {.async.} =
proc encHandler(msg: seq[byte]) {.async.} = proc encHandler(msg: seq[byte]) {.async.} =
check msg == fromHex("88010873747265616d2031") check msg == fromHex("88010873747265616d2031")
@ -40,10 +37,7 @@ suite "Mplex":
await conn.writeMsg(17, MessageType.New, ("stream 1").toBytes) await conn.writeMsg(17, MessageType.New, ("stream 1").toBytes)
await conn.close() await conn.close()
waitFor(testEncodeHeader()) asyncTest "encode header and body with channel id 0":
test "encode header and body with channel id 0":
proc testEncodeHeaderBody() {.async.} =
proc encHandler(msg: seq[byte]) {.async.} = proc encHandler(msg: seq[byte]) {.async.} =
check msg == fromHex("020873747265616d2031") check msg == fromHex("020873747265616d2031")
@ -51,10 +45,7 @@ suite "Mplex":
await conn.writeMsg(0, MessageType.MsgOut, ("stream 1").toBytes) await conn.writeMsg(0, MessageType.MsgOut, ("stream 1").toBytes)
await conn.close() await conn.close()
waitFor(testEncodeHeaderBody()) asyncTest "encode header and body with channel id other than 0":
test "encode header and body with channel id other than 0":
proc testEncodeHeaderBody() {.async.} =
proc encHandler(msg: seq[byte]) {.async.} = proc encHandler(msg: seq[byte]) {.async.} =
check msg == fromHex("8a010873747265616d2031") check msg == fromHex("8a010873747265616d2031")
@ -62,10 +53,7 @@ suite "Mplex":
await conn.writeMsg(17, MessageType.MsgOut, ("stream 1").toBytes) await conn.writeMsg(17, MessageType.MsgOut, ("stream 1").toBytes)
await conn.close() await conn.close()
waitFor(testEncodeHeaderBody()) asyncTest "decode header with channel id 0":
test "decode header with channel id 0":
proc testDecodeHeader() {.async.} =
let stream = newBufferStream() let stream = newBufferStream()
let conn = stream let conn = stream
await stream.pushData(fromHex("000873747265616d2031")) await stream.pushData(fromHex("000873747265616d2031"))
@ -75,10 +63,7 @@ suite "Mplex":
check msg.msgType == MessageType.New check msg.msgType == MessageType.New
await conn.close() await conn.close()
waitFor(testDecodeHeader()) asyncTest "decode header and body with channel id 0":
test "decode header and body with channel id 0":
proc testDecodeHeader() {.async.} =
let stream = newBufferStream() let stream = newBufferStream()
let conn = stream let conn = stream
await stream.pushData(fromHex("021668656C6C6F2066726F6D206368616E6E656C20302121")) await stream.pushData(fromHex("021668656C6C6F2066726F6D206368616E6E656C20302121"))
@ -89,10 +74,7 @@ suite "Mplex":
check string.fromBytes(msg.data) == "hello from channel 0!!" check string.fromBytes(msg.data) == "hello from channel 0!!"
await conn.close() await conn.close()
waitFor(testDecodeHeader()) asyncTest "decode header and body with channel id other than 0":
test "decode header and body with channel id other than 0":
proc testDecodeHeader() {.async.} =
let stream = newBufferStream() let stream = newBufferStream()
let conn = stream let conn = stream
await stream.pushData(fromHex("8a011668656C6C6F2066726F6D206368616E6E656C20302121")) await stream.pushData(fromHex("8a011668656C6C6F2066726F6D206368616E6E656C20302121"))
@ -103,28 +85,21 @@ suite "Mplex":
check string.fromBytes(msg.data) == "hello from channel 0!!" check string.fromBytes(msg.data) == "hello from channel 0!!"
await conn.close() await conn.close()
waitFor(testDecodeHeader()) suite "channel half-closed":
asyncTest "(local close) - should close for write":
test "half closed (local close) - should close for write":
proc testClosedForWrite(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
chann = LPChannel.init(1, conn, true) chann = LPChannel.init(1, conn, true)
await chann.close() await chann.close()
try: expect LPStreamClosedError:
await chann.write("Hello") await chann.write("Hello")
except LPStreamClosedError:
result = true
finally:
await chann.reset()
await conn.close()
check: await chann.reset()
waitFor(testClosedForWrite()) == true await conn.close()
test "half closed (local close) - should allow reads until remote closes": asyncTest "(local close) - should allow reads until remote closes":
proc testOpenForRead(): Future[bool] {.async.} =
let let
conn = newBufferStream( conn = newBufferStream(
proc (data: seq[byte]) {.gcsafe, async.} = proc (data: seq[byte]) {.gcsafe, async.} =
@ -142,21 +117,16 @@ suite "Mplex":
let closeFut = chann.pushEof() let closeFut = chann.pushEof()
# should still allow reading until buffer EOF # should still allow reading until buffer EOF
await chann.readExactly(addr data[3], 3) await chann.readExactly(addr data[3], 3)
try:
expect LPStreamEOFError:
# this should fail now # this should fail now
await chann.readExactly(addr data[0], 3) await chann.readExactly(addr data[0], 3)
except LPStreamEOFError:
result = true await chann.close()
finally: await conn.close()
await chann.close()
await conn.close()
await closeFut await closeFut
check: asyncTest "(remote close) - channel should close for reading by remote":
waitFor(testOpenForRead()) == true
test "half closed (remote close) - channel should close for reading by remote":
proc testClosedForRead(): Future[bool] {.async.} =
let let
conn = newBufferStream( conn = newBufferStream(
proc (data: seq[byte]) {.gcsafe, async.} = proc (data: seq[byte]) {.gcsafe, async.} =
@ -171,19 +141,14 @@ suite "Mplex":
let closeFut = chann.pushEof() # closing channel let closeFut = chann.pushEof() # closing channel
let readFut = chann.readExactly(addr data[3], 3) let readFut = chann.readExactly(addr data[3], 3)
await all(closeFut, readFut) await all(closeFut, readFut)
try:
expect LPStreamEOFError:
await chann.readExactly(addr data[0], 6) # this should fail now await chann.readExactly(addr data[0], 6) # this should fail now
except LPStreamEOFError:
result = true
finally:
await chann.close()
await conn.close()
check: await chann.close()
waitFor(testClosedForRead()) == true await conn.close()
test "half closed (remote close) - channel should allow writing on remote close": asyncTest "(remote close) - channel should allow writing on remote close":
proc testClosedForRead(): Future[bool] {.async.} =
let let
testData = "Hello!".toBytes testData = "Hello!".toBytes
conn = newBufferStream( conn = newBufferStream(
@ -195,16 +160,11 @@ suite "Mplex":
await chann.pushEof() # closing channel await chann.pushEof() # closing channel
try: try:
await chann.writeLp(testData) await chann.writeLp(testData)
return true
finally: finally:
await chann.reset() # there's nobody reading the EOF! await chann.reset() # there's nobody reading the EOF!
await conn.close() await conn.close()
check: asyncTest "should not allow pushing data to channel when remote end closed":
waitFor(testClosedForRead()) == true
test "should not allow pushing data to channel when remote end closed":
proc testResetWrite(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
@ -212,19 +172,16 @@ suite "Mplex":
await chann.pushEof() await chann.pushEof()
var buf: array[1, byte] var buf: array[1, byte]
check: (await chann.readOnce(addr buf[0], 1)) == 0 # EOF marker read check: (await chann.readOnce(addr buf[0], 1)) == 0 # EOF marker read
try:
expect LPStreamEOFError:
await chann.pushData(@[byte(1)]) await chann.pushData(@[byte(1)])
except LPStreamEOFError:
result = true
finally:
await chann.close()
await conn.close()
check: await chann.close()
waitFor(testResetWrite()) == true await conn.close()
test "reset - channel should fail reading": suite "channel reset":
proc testResetRead(): Future[bool] {.async.} =
asyncTest "channel should fail reading":
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
@ -232,18 +189,12 @@ suite "Mplex":
await chann.reset() await chann.reset()
var data = newSeq[byte](1) var data = newSeq[byte](1)
try: expect LPStreamEOFError:
await chann.readExactly(addr data[0], 1) await chann.readExactly(addr data[0], 1)
except LPStreamEOFError:
result = true
finally:
await conn.close()
check: await conn.close()
waitFor(testResetRead()) == true
test "reset - should complete read": asyncTest "should complete read":
proc testResetRead(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
@ -251,19 +202,14 @@ suite "Mplex":
var data = newSeq[byte](1) var data = newSeq[byte](1)
let fut = chann.readExactly(addr data[0], 1) let fut = chann.readExactly(addr data[0], 1)
await chann.reset() await chann.reset()
try: expect LPStreamEOFError:
await fut await fut
except LPStreamEOFError:
result = true
finally:
await conn.close()
check: await conn.close()
waitFor(testResetRead()) == true
test "reset - should complete pushData": asyncTest "should complete pushData":
proc testResetRead(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
@ -272,14 +218,10 @@ suite "Mplex":
await chann.pushData(@[0'u8]) await chann.pushData(@[0'u8])
let fut = chann.pushData(@[0'u8]) let fut = chann.pushData(@[0'u8])
await chann.reset() await chann.reset()
result = await fut.withTimeout(100.millis) check await fut.withTimeout(100.millis)
await conn.close() await conn.close()
check: asyncTest "should complete both read and push":
waitFor(testResetRead()) == true
test "reset - should complete both read and push":
proc testResetRead(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
@ -290,46 +232,33 @@ suite "Mplex":
let wfut = chann.pushData(@[0'u8]) let wfut = chann.pushData(@[0'u8])
let wfut2 = chann.pushData(@[0'u8]) let wfut2 = chann.pushData(@[0'u8])
await chann.reset() await chann.reset()
result = await allFutures(rfut, wfut, wfut2).withTimeout(100.millis) check await allFutures(rfut, wfut, wfut2).withTimeout(100.millis)
await conn.close() await conn.close()
check: asyncTest "channel should fail writing":
waitFor(testResetRead()) == true
test "reset - channel should fail writing":
proc testResetWrite(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
chann = LPChannel.init(1, conn, true) chann = LPChannel.init(1, conn, true)
await chann.reset() await chann.reset()
try:
expect LPStreamClosedError:
await chann.write(("Hello!").toBytes) await chann.write(("Hello!").toBytes)
except LPStreamClosedError:
result = true
finally:
await conn.close()
check: await conn.close()
waitFor(testResetWrite()) == true
test "reset - channel should reset on timeout": asyncTest "channel should reset on timeout":
proc testResetWrite(): Future[bool] {.async.} =
proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard proc writeHandler(data: seq[byte]) {.async, gcsafe.} = discard
let let
conn = newBufferStream(writeHandler) conn = newBufferStream(writeHandler)
chann = LPChannel.init( chann = LPChannel.init(
1, conn, true, timeout = 100.millis) 1, conn, true, timeout = 100.millis)
check await chann.closeEvent.wait().withTimeout(1.minutes) check await chann.join().withTimeout(1.minutes)
await conn.close() await conn.close()
result = true
check: suite "mplex e2e":
waitFor(testResetWrite()) asyncTest "read/write receiver":
test "e2e - read/write receiver":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var done = newFuture[void]() var done = newFuture[void]()
@ -364,12 +293,10 @@ suite "Mplex":
await allFuturesThrowing( await allFuturesThrowing(
transport1.close(), transport1.close(),
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "read/write receiver lazy":
test "e2e - read/write receiver lazy":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var done = newFuture[void]() var done = newFuture[void]()
@ -407,10 +334,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "write fragmented":
test "e2e - write fragmented":
proc testNewStream() {.async.} =
let let
ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
listenJob = newFuture[void]() listenJob = newFuture[void]()
@ -449,10 +373,7 @@ suite "Mplex":
let stream = await mplexDial.newStream() let stream = await mplexDial.newStream()
await stream.writeLp(bigseq) await stream.writeLp(bigseq)
try: await listenJob.wait(10.seconds)
await listenJob.wait(10.seconds)
except AsyncTimeoutError:
check false
await stream.close() await stream.close()
await conn.close() await conn.close()
@ -460,12 +381,10 @@ suite "Mplex":
await allFuturesThrowing( await allFuturesThrowing(
transport1.close(), transport1.close(),
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "read/write initiator":
test "e2e - read/write initiator":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
@ -501,10 +420,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "multiple streams":
test "e2e - multiple streams":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
@ -545,10 +461,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "multiple read/write streams":
test "e2e - multiple read/write streams":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let done = newFuture[void]() let done = newFuture[void]()
@ -592,10 +505,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "channel closes listener with EOF":
test "e2e - channel closes listener with EOF":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var listenStreams: seq[Connection] var listenStreams: seq[Connection]
@ -641,10 +551,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "channel closes dialer with EOF":
test "e2e - channel closes dialer with EOF":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var listenStreams: seq[Connection] var listenStreams: seq[Connection]
@ -707,10 +614,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "dialing mplex closes both ends":
test "e2e - dialing mplex closes both ends":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var listenStreams: seq[Connection] var listenStreams: seq[Connection]
@ -750,10 +654,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "listening mplex closes both ends":
test "e2e - listening mplex closes both ends":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var mplexListen: Mplex var mplexListen: Mplex
@ -794,10 +695,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "canceling mplex handler closes both ends":
test "e2e - canceling mplex handler closes both ends":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var mplexHandle: Future[void] var mplexHandle: Future[void]
@ -839,10 +737,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "closing dialing connection should close both ends":
test "e2e - closing dialing connection should close both ends":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var listenStreams: seq[Connection] var listenStreams: seq[Connection]
@ -882,10 +777,7 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) asyncTest "canceling listening connection should close both ends":
test "e2e - canceling listening connection should close both ends":
proc testNewStream() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var listenConn: Connection var listenConn: Connection
@ -927,137 +819,130 @@ suite "Mplex":
transport2.close()) transport2.close())
await listenFut await listenFut
waitFor(testNewStream()) suite "jitter":
asyncTest "channel should be able to handle erratic read/writes":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
test "jitter - channel should be able to handle erratic read/writes": var complete = newFuture[void]()
proc test() {.async.} = const MsgSize = 1024
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() proc connHandler(conn: Connection) {.async, gcsafe.} =
let mplexListen = Mplex.init(conn)
mplexListen.streamHandler = proc(stream: Connection)
{.async, gcsafe.} =
try:
let msg = await stream.readLp(MsgSize)
check msg.len == MsgSize
except CatchableError as e:
echo e.msg
await stream.close()
complete.complete()
var complete = newFuture[void]() await mplexListen.handle()
const MsgSize = 1024 await mplexListen.close()
proc connHandler(conn: Connection) {.async, gcsafe.} =
let mplexListen = Mplex.init(conn) let transport1: TcpTransport = TcpTransport.init()
mplexListen.streamHandler = proc(stream: Connection) let listenFut = await transport1.listen(ma, connHandler)
{.async, gcsafe.} =
try: let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
let mplexDial = Mplex.init(conn)
let mplexDialFut = mplexDial.handle()
let stream = await mplexDial.newStream()
var bigseq = newSeqOfCap[uint8](MaxMsgSize + 1)
for _ in 0..<MsgSize: # write one less than max size
bigseq.add(uint8(rand(uint('A')..uint('z'))))
## create length prefixed libp2p frame
var buf = initVBuffer()
buf.writeSeq(bigseq)
buf.finish()
## create mplex header
var mplexBuf = initVBuffer()
mplexBuf.writePBVarint((1.uint shl 3) or ord(MessageType.MsgOut).uint)
mplexBuf.writePBVarint(buf.buffer.len.uint) # size should be always sent
await conn.write(mplexBuf.buffer)
proc writer() {.async.} =
var sent = 0
randomize()
let total = buf.buffer.len
const min = 20
const max = 50
while sent < total:
var size = rand(min..max)
size = if size > buf.buffer.len: buf.buffer.len else: size
var send = buf.buffer[0..<size]
await conn.write(send)
sent += size
buf.buffer = buf.buffer[size..^1]
await writer()
await complete.wait(1.seconds)
await stream.close()
await conn.close()
await mplexDialFut
await allFuturesThrowing(
transport1.close(),
transport2.close())
await listenFut
asyncTest "channel should handle 1 byte read/write":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var complete = newFuture[void]()
const MsgSize = 512
proc connHandler(conn: Connection) {.async, gcsafe.} =
let mplexListen = Mplex.init(conn)
mplexListen.streamHandler = proc(stream: Connection)
{.async, gcsafe.} =
let msg = await stream.readLp(MsgSize) let msg = await stream.readLp(MsgSize)
check msg.len == MsgSize check msg.len == MsgSize
except CatchableError as e: await stream.close()
echo e.msg complete.complete()
await stream.close()
complete.complete()
await mplexListen.handle() await mplexListen.handle()
await mplexListen.close() await mplexListen.close()
let transport1: TcpTransport = TcpTransport.init() let transport1: TcpTransport = TcpTransport.init()
let listenFut = await transport1.listen(ma, connHandler) let listenFut = await transport1.listen(ma, connHandler)
let transport2: TcpTransport = TcpTransport.init() let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma) let conn = await transport2.dial(transport1.ma)
let mplexDial = Mplex.init(conn) let mplexDial = Mplex.init(conn)
let mplexDialFut = mplexDial.handle() let stream = await mplexDial.newStream()
let stream = await mplexDial.newStream() let mplexDialFut = mplexDial.handle()
var bigseq = newSeqOfCap[uint8](MaxMsgSize + 1) var bigseq = newSeqOfCap[uint8](MsgSize + 1)
for _ in 0..<MsgSize: # write one less than max size for _ in 0..<MsgSize: # write one less than max size
bigseq.add(uint8(rand(uint('A')..uint('z')))) bigseq.add(uint8(rand(uint('A')..uint('z'))))
## create length prefixed libp2p frame ## create length prefixed libp2p frame
var buf = initVBuffer() var buf = initVBuffer()
buf.writeSeq(bigseq) buf.writeSeq(bigseq)
buf.finish() buf.finish()
## create mplex header ## create mplex header
var mplexBuf = initVBuffer() var mplexBuf = initVBuffer()
mplexBuf.writePBVarint((1.uint shl 3) or ord(MessageType.MsgOut).uint) mplexBuf.writePBVarint((1.uint shl 3) or ord(MessageType.MsgOut).uint)
mplexBuf.writePBVarint(buf.buffer.len.uint) # size should be always sent mplexBuf.writePBVarint(buf.buffer.len.uint) # size should be always sent
await conn.write(mplexBuf.buffer) await conn.write(mplexBuf.buffer)
proc writer() {.async.} = proc writer() {.async.} =
var sent = 0 for i in buf.buffer:
randomize() await conn.write(@[i])
let total = buf.buffer.len
const min = 20
const max = 50
while sent < total:
var size = rand(min..max)
size = if size > buf.buffer.len: buf.buffer.len else: size
var send = buf.buffer[0..<size]
await conn.write(send)
sent += size
buf.buffer = buf.buffer[size..^1]
await writer() await writer()
await complete.wait(1.seconds)
await stream.close() await complete.wait(5.seconds)
await conn.close() await stream.close()
await conn.close()
await mplexDialFut await mplexDialFut
await allFuturesThrowing(
await allFuturesThrowing( transport1.close(),
transport1.close(), transport2.close())
transport2.close()) await listenFut
await listenFut
waitFor(test())
test "jitter - channel should handle 1 byte read/write":
proc test() {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var complete = newFuture[void]()
const MsgSize = 512
proc connHandler(conn: Connection) {.async, gcsafe.} =
let mplexListen = Mplex.init(conn)
mplexListen.streamHandler = proc(stream: Connection)
{.async, gcsafe.} =
let msg = await stream.readLp(MsgSize)
check msg.len == MsgSize
await stream.close()
complete.complete()
await mplexListen.handle()
await mplexListen.close()
let transport1: TcpTransport = TcpTransport.init()
let listenFut = await transport1.listen(ma, connHandler)
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
let mplexDial = Mplex.init(conn)
let stream = await mplexDial.newStream()
let mplexDialFut = mplexDial.handle()
var bigseq = newSeqOfCap[uint8](MsgSize + 1)
for _ in 0..<MsgSize: # write one less than max size
bigseq.add(uint8(rand(uint('A')..uint('z'))))
## create length prefixed libp2p frame
var buf = initVBuffer()
buf.writeSeq(bigseq)
buf.finish()
## create mplex header
var mplexBuf = initVBuffer()
mplexBuf.writePBVarint((1.uint shl 3) or ord(MessageType.MsgOut).uint)
mplexBuf.writePBVarint(buf.buffer.len.uint) # size should be always sent
await conn.write(mplexBuf.buffer)
proc writer() {.async.} =
for i in buf.buffer:
await conn.write(@[i])
await writer()
await complete.wait(5.seconds)
await stream.close()
await conn.close()
await mplexDialFut
await allFuturesThrowing(
transport1.close(),
transport2.close())
await listenFut
waitFor(test())

View File

@ -170,263 +170,217 @@ suite "Multistream select":
teardown: teardown:
checkTrackers() checkTrackers()
test "test select custom proto": asyncTest "test select custom proto":
proc testSelect(): Future[bool] {.async.} = let ms = newMultistream()
let ms = newMultistream() let conn = newTestSelectStream()
let conn = newTestSelectStream() check (await ms.select(conn, @["/test/proto/1.0.0"])) == "/test/proto/1.0.0"
result = (await ms.select(conn, @["/test/proto/1.0.0"])) == "/test/proto/1.0.0" await conn.close()
asyncTest "test handle custom proto":
let ms = newMultistream()
let conn = newTestSelectStream()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
check proto == "/test/proto/1.0.0"
await conn.close() await conn.close()
check: protocol.handler = testHandler
waitFor(testSelect()) == true ms.addHandler("/test/proto/1.0.0", protocol)
await ms.handle(conn)
test "test handle custom proto": asyncTest "test handle `ls`":
proc testHandle(): Future[bool] {.async.} = let ms = newMultistream()
let ms = newMultistream()
let conn = newTestSelectStream()
var protocol: LPProtocol = new LPProtocol proc testLsHandler(proto: seq[byte]) {.async, gcsafe.} # forward declaration
proc testHandler(conn: Connection, let conn = Connection(newTestLsStream(testLsHandler))
proto: string): let done = newFuture[void]()
Future[void] {.async, gcsafe.} = proc testLsHandler(proto: seq[byte]) {.async, gcsafe.} =
check proto == "/test/proto/1.0.0" var strProto: string = string.fromBytes(proto)
await conn.close() check strProto == "\x26/test/proto1/1.0.0\n/test/proto2/1.0.0\n"
await conn.close()
done.complete()
protocol.handler = testHandler proc testHandler(conn: Connection, proto: string): Future[void]
ms.addHandler("/test/proto/1.0.0", protocol) {.async, gcsafe.} = discard
await ms.handle(conn) var protocol: LPProtocol = new LPProtocol
result = true protocol.handler = testHandler
ms.addHandler("/test/proto1/1.0.0", protocol)
ms.addHandler("/test/proto2/1.0.0", protocol)
await ms.handle(conn)
await done.wait(5.seconds)
check: asyncTest "test handle `na`":
waitFor(testHandle()) == true let ms = newMultistream()
test "test handle `ls`": proc testNaHandler(msg: string): Future[void] {.async, gcsafe.}
proc testLs(): Future[bool] {.async.} = let conn = newTestNaStream(testNaHandler)
let ms = newMultistream()
proc testLsHandler(proto: seq[byte]) {.async, gcsafe.} # forward declaration proc testNaHandler(msg: string): Future[void] {.async, gcsafe.} =
let conn = Connection(newTestLsStream(testLsHandler)) echo msg
let done = newFuture[void]() check msg == Na
proc testLsHandler(proto: seq[byte]) {.async, gcsafe.} =
var strProto: string = string.fromBytes(proto)
check strProto == "\x26/test/proto1/1.0.0\n/test/proto2/1.0.0\n"
await conn.close()
done.complete()
proc testHandler(conn: Connection, proto: string): Future[void]
{.async, gcsafe.} = discard
var protocol: LPProtocol = new LPProtocol
protocol.handler = testHandler
ms.addHandler("/test/proto1/1.0.0", protocol)
ms.addHandler("/test/proto2/1.0.0", protocol)
await ms.handle(conn)
result = true
await done.wait(5.seconds)
check:
waitFor(testLs()) == true
test "test handle `na`":
proc testNa(): Future[bool] {.async.} =
let ms = newMultistream()
proc testNaHandler(msg: string): Future[void] {.async, gcsafe.}
let conn = newTestNaStream(testNaHandler)
proc testNaHandler(msg: string): Future[void] {.async, gcsafe.} =
echo msg
check msg == Na
await conn.close()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} = discard
protocol.handler = testHandler
ms.addHandler("/unabvailable/proto/1.0.0", protocol)
await ms.handle(conn)
result = true
check:
waitFor(testNa()) == true
test "e2e - handle":
proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let
handlerWait1 = newFuture[void]()
handlerWait2 = newFuture[void]()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
check proto == "/test/proto/1.0.0"
await conn.writeLp("Hello!")
await conn.close()
handlerWait1.complete()
protocol.handler = testHandler
let msListen = newMultistream()
msListen.addHandler("/test/proto/1.0.0", protocol)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
await conn.close()
handlerWait2.complete()
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
check (await msDial.select(conn, "/test/proto/1.0.0")) == true
let hello = string.fromBytes(await conn.readLp(1024))
result = hello == "Hello!"
await conn.close() await conn.close()
await transport2.close() var protocol: LPProtocol = new LPProtocol
await transport1.close() proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} = discard
protocol.handler = testHandler
ms.addHandler("/unabvailable/proto/1.0.0", protocol)
await allFuturesThrowing( await ms.handle(conn)
handlerWait1.wait(30.seconds),
handlerWait2.wait(30.seconds))
check: asyncTest "e2e - handle":
waitFor(endToEnd()) == true let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
test "e2e - ls": let
proc endToEnd(): Future[bool] {.async.} = handlerWait1 = newFuture[void]()
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() handlerWait2 = newFuture[void]()
let
handlerWait = newFuture[void]()
let msListen = newMultistream()
var protocol: LPProtocol = new LPProtocol
protocol.handler = proc(conn: Connection, proto: string) {.async, gcsafe.} =
# never reached
discard
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async.} =
# never reached
discard
protocol.handler = testHandler
msListen.addHandler("/test/proto1/1.0.0", protocol)
msListen.addHandler("/test/proto2/1.0.0", protocol)
let transport1: TcpTransport = TcpTransport.init()
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
try:
await msListen.handle(conn)
except LPStreamEOFError:
discard
except LPStreamClosedError:
discard
finally:
await conn.close()
let listenFut = transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
let ls = await msDial.list(conn)
let protos: seq[string] = @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
result = ls == protos
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
check proto == "/test/proto/1.0.0"
await conn.writeLp("Hello!")
await conn.close() await conn.close()
await transport2.close() handlerWait1.complete()
await transport1.close()
discard await listenFut.wait(5.seconds)
check: protocol.handler = testHandler
waitFor(endToEnd()) == true let msListen = newMultistream()
msListen.addHandler("/test/proto/1.0.0", protocol)
test "e2e - select one from a list with unsupported protos":
proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
check proto == "/test/proto/1.0.0"
await conn.writeLp("Hello!")
await conn.close()
protocol.handler = testHandler
let msListen = newMultistream()
msListen.addHandler("/test/proto/1.0.0", protocol)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
check (await msDial.select(conn,
@["/test/proto/1.0.0", "/test/no/proto/1.0.0"])) == "/test/proto/1.0.0"
let hello = string.fromBytes(await conn.readLp(1024))
result = hello == "Hello!"
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
await conn.close() await conn.close()
await transport2.close() handlerWait2.complete()
await transport1.close()
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
check: let msDial = newMultistream()
waitFor(endToEnd()) == true let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
test "e2e - select one with both valid": check (await msDial.select(conn, "/test/proto/1.0.0")) == true
proc endToEnd(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol let hello = string.fromBytes(await conn.readLp(1024))
proc testHandler(conn: Connection, check hello == "Hello!"
proto: string): await conn.close()
Future[void] {.async, gcsafe.} =
await conn.writeLp(&"Hello from {proto}!")
await conn.close()
protocol.handler = testHandler await transport2.close()
let msListen = newMultistream() await transport1.close()
msListen.addHandler("/test/proto1/1.0.0", protocol)
msListen.addHandler("/test/proto2/1.0.0", protocol)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} = await allFuturesThrowing(
await msListen.handle(conn) handlerWait1.wait(30.seconds),
handlerWait2.wait(30.seconds))
let transport1: TcpTransport = TcpTransport.init() asyncTest "e2e - ls":
asyncCheck transport1.listen(ma, connHandler) let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let msDial = newMultistream() let
let transport2: TcpTransport = TcpTransport.init() handlerWait = newFuture[void]()
let conn = await transport2.dial(transport1.ma)
check (await msDial.select(conn, @["/test/proto2/1.0.0", "/test/proto1/1.0.0"])) == "/test/proto2/1.0.0" let msListen = newMultistream()
var protocol: LPProtocol = new LPProtocol
protocol.handler = proc(conn: Connection, proto: string) {.async, gcsafe.} =
# never reached
discard
result = string.fromBytes(await conn.readLp(1024)) == "Hello from /test/proto2/1.0.0!" proc testHandler(conn: Connection,
proto: string):
Future[void] {.async.} =
# never reached
discard
protocol.handler = testHandler
msListen.addHandler("/test/proto1/1.0.0", protocol)
msListen.addHandler("/test/proto2/1.0.0", protocol)
let transport1: TcpTransport = TcpTransport.init()
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
await conn.close() await conn.close()
await transport2.close()
await transport1.close()
check: let listenFut = transport1.listen(ma, connHandler)
waitFor(endToEnd()) == true let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
let ls = await msDial.list(conn)
let protos: seq[string] = @["/test/proto1/1.0.0", "/test/proto2/1.0.0"]
check ls == protos
await conn.close()
await transport2.close()
await transport1.close()
discard await listenFut.wait(5.seconds)
asyncTest "e2e - select one from a list with unsupported protos":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
check proto == "/test/proto/1.0.0"
await conn.writeLp("Hello!")
await conn.close()
protocol.handler = testHandler
let msListen = newMultistream()
msListen.addHandler("/test/proto/1.0.0", protocol)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
check (await msDial.select(conn,
@["/test/proto/1.0.0", "/test/no/proto/1.0.0"])) == "/test/proto/1.0.0"
let hello = string.fromBytes(await conn.readLp(1024))
check hello == "Hello!"
await conn.close()
await transport2.close()
await transport1.close()
asyncTest "e2e - select one with both valid":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var protocol: LPProtocol = new LPProtocol
proc testHandler(conn: Connection,
proto: string):
Future[void] {.async, gcsafe.} =
await conn.writeLp(&"Hello from {proto}!")
await conn.close()
protocol.handler = testHandler
let msListen = newMultistream()
msListen.addHandler("/test/proto1/1.0.0", protocol)
msListen.addHandler("/test/proto2/1.0.0", protocol)
proc connHandler(conn: Connection): Future[void] {.async, gcsafe.} =
await msListen.handle(conn)
let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
let msDial = newMultistream()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
check (await msDial.select(conn, @["/test/proto2/1.0.0", "/test/proto1/1.0.0"])) == "/test/proto2/1.0.0"
check string.fromBytes(await conn.readLp(1024)) == "Hello from /test/proto2/1.0.0!"
await conn.close()
await transport2.close()
await transport1.close()

View File

@ -74,232 +74,199 @@ suite "Noise":
teardown: teardown:
checkTrackers() checkTrackers()
test "e2e: handle write + noise": asyncTest "e2e: handle write + noise":
proc testListenerDialer(): Future[bool] {.async.} = let
let server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server]) serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
proc connHandler(conn: Connection) {.async, gcsafe.} = proc connHandler(conn: Connection) {.async, gcsafe.} =
let sconn = await serverNoise.secure(conn, false) let sconn = await serverNoise.secure(conn, false)
try: try:
await sconn.write("Hello!") await sconn.write("Hello!")
finally: finally:
await sconn.close() await sconn.close()
await conn.close() await conn.close()
let let
transport1: TcpTransport = TcpTransport.init() transport1: TcpTransport = TcpTransport.init()
asyncCheck await transport1.listen(server, connHandler) asyncCheck await transport1.listen(server, connHandler)
let let
transport2: TcpTransport = TcpTransport.init() transport2: TcpTransport = TcpTransport.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma]) clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma])
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true) clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true)
conn = await transport2.dial(transport1.ma) conn = await transport2.dial(transport1.ma)
sconn = await clientNoise.secure(conn, true) sconn = await clientNoise.secure(conn, true)
var msg = newSeq[byte](6)
await sconn.readExactly(addr msg[0], 6)
await sconn.close()
await conn.close()
await transport1.close()
await transport2.close()
check string.fromBytes(msg) == "Hello!"
asyncTest "e2e: handle write + noise (wrong prologue)":
let
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
proc connHandler(conn: Connection) {.async, gcsafe.} =
let sconn = await serverNoise.secure(conn, false)
try:
await sconn.write("Hello!")
finally:
await sconn.close()
await conn.close()
let
transport1: TcpTransport = TcpTransport.init()
asyncCheck await transport1.listen(server, connHandler)
let
transport2: TcpTransport = TcpTransport.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma])
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true, commonPrologue = @[1'u8, 2'u8, 3'u8])
conn = await transport2.dial(transport1.ma)
var sconn: Connection = nil
expect(NoiseDecryptTagError):
sconn = await clientNoise.secure(conn, true)
await conn.close()
await transport1.close()
await transport2.close()
asyncTest "e2e: handle read + noise":
let
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
readTask = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
let sconn = await serverNoise.secure(conn, false)
defer:
await sconn.close()
await conn.close()
var msg = newSeq[byte](6) var msg = newSeq[byte](6)
await sconn.readExactly(addr msg[0], 6) await sconn.readExactly(addr msg[0], 6)
check string.fromBytes(msg) == "Hello!"
readTask.complete()
await sconn.close() let
await conn.close() transport1: TcpTransport = TcpTransport.init()
await transport1.close() asyncCheck await transport1.listen(server, connHandler)
await transport2.close()
result = string.fromBytes(msg) == "Hello!" let
transport2: TcpTransport = TcpTransport.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma])
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true)
conn = await transport2.dial(transport1.ma)
sconn = await clientNoise.secure(conn, true)
check: await sconn.write("Hello!")
waitFor(testListenerDialer()) == true await readTask
await sconn.close()
await conn.close()
await transport1.close()
await transport2.close()
test "e2e: handle write + noise (wrong prologue)": asyncTest "e2e: handle read + noise fragmented":
proc testListenerDialer(): Future[bool] {.async.} = let
let server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server]) serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false) readTask = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = var hugePayload = newSeq[byte](0xFFFFF)
let sconn = await serverNoise.secure(conn, false) brHmacDrbgGenerate(rng[], hugePayload)
try: trace "Sending huge payload", size = hugePayload.len
await sconn.write("Hello!")
finally:
await sconn.close()
await conn.close()
let proc connHandler(conn: Connection) {.async, gcsafe.} =
transport1: TcpTransport = TcpTransport.init() let sconn = await serverNoise.secure(conn, false)
asyncCheck await transport1.listen(server, connHandler) defer:
await sconn.close()
let msg = await sconn.readLp(1024*1024)
check msg == hugePayload
readTask.complete()
let let
transport2: TcpTransport = TcpTransport.init() transport1: TcpTransport = TcpTransport.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma]) listenFut = await transport1.listen(server, connHandler)
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true, commonPrologue = @[1'u8, 2'u8, 3'u8])
conn = await transport2.dial(transport1.ma)
var sconn: Connection = nil
expect(NoiseDecryptTagError):
sconn = await clientNoise.secure(conn, true)
await conn.close() let
await transport1.close() transport2: TcpTransport = TcpTransport.init()
await transport2.close() clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma])
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true)
conn = await transport2.dial(transport1.ma)
sconn = await clientNoise.secure(conn, true)
result = true await sconn.writeLp(hugePayload)
await readTask
check: await sconn.close()
waitFor(testListenerDialer()) == true await conn.close()
await transport2.close()
await transport1.close()
await listenFut
test "e2e: handle read + noise": asyncTest "e2e use switch dial proto string":
proc testListenerDialer(): Future[bool] {.async.} = let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
readTask = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} = var peerInfo1, peerInfo2: PeerInfo
let sconn = await serverNoise.secure(conn, false) var switch1, switch2: Switch
defer: var awaiters: seq[Future[void]]
await sconn.close()
await conn.close()
var msg = newSeq[byte](6)
await sconn.readExactly(addr msg[0], 6)
check string.fromBytes(msg) == "Hello!"
readTask.complete()
let (switch1, peerInfo1) = createSwitch(ma1, false)
transport1: TcpTransport = TcpTransport.init()
asyncCheck await transport1.listen(server, connHandler)
let let testProto = new TestProto
transport2: TcpTransport = TcpTransport.init() testProto.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma]) testProto.codec = TestCodec
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true) switch1.mount(testProto)
conn = await transport2.dial(transport1.ma) (switch2, peerInfo2) = createSwitch(ma2, true)
sconn = await clientNoise.secure(conn, true) awaiters.add(await switch1.start())
awaiters.add(await switch2.start())
let conn = await switch2.dial(switch1.peerInfo, TestCodec)
await conn.writeLp("Hello!")
let msg = string.fromBytes(await conn.readLp(1024))
check "Hello!" == msg
await conn.close()
await sconn.write("Hello!") await allFuturesThrowing(
await readTask switch1.stop(),
await sconn.close() switch2.stop())
await conn.close() await allFuturesThrowing(awaiters)
await transport1.close()
await transport2.close()
result = true asyncTest "e2e test wrong secure negotiation":
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
check: var peerInfo1, peerInfo2: PeerInfo
waitFor(testListenerDialer()) == true var switch1, switch2: Switch
var awaiters: seq[Future[void]]
test "e2e: handle read + noise fragmented": (switch1, peerInfo1) = createSwitch(ma1, false)
proc testListenerDialer(): Future[bool] {.async.} =
let
server = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
serverInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [server])
serverNoise = newNoise(rng, serverInfo.privateKey, outgoing = false)
readTask = newFuture[void]()
var hugePayload = newSeq[byte](0xFFFFF) let testProto = new TestProto
brHmacDrbgGenerate(rng[], hugePayload) testProto.init()
trace "Sending huge payload", size = hugePayload.len testProto.codec = TestCodec
switch1.mount(testProto)
proc connHandler(conn: Connection) {.async, gcsafe.} = (switch2, peerInfo2) = createSwitch(ma2, true, true) # secio, we want to fail
let sconn = await serverNoise.secure(conn, false) awaiters.add(await switch1.start())
defer: awaiters.add(await switch2.start())
await sconn.close() expect(UpgradeFailedError):
let msg = await sconn.readLp(1024*1024)
check msg == hugePayload
readTask.complete()
let
transport1: TcpTransport = TcpTransport.init()
listenFut = await transport1.listen(server, connHandler)
let
transport2: TcpTransport = TcpTransport.init()
clientInfo = PeerInfo.init(PrivateKey.random(ECDSA, rng[]).get(), [transport1.ma])
clientNoise = newNoise(rng, clientInfo.privateKey, outgoing = true)
conn = await transport2.dial(transport1.ma)
sconn = await clientNoise.secure(conn, true)
await sconn.writeLp(hugePayload)
await readTask
await sconn.close()
await conn.close()
await transport2.close()
await transport1.close()
await listenFut
result = true
check:
waitFor(testListenerDialer()) == true
test "e2e use switch dial proto string":
proc testSwitch(): Future[bool] {.async, gcsafe.} =
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var peerInfo1, peerInfo2: PeerInfo
var switch1, switch2: Switch
var awaiters: seq[Future[void]]
(switch1, peerInfo1) = createSwitch(ma1, false)
let testProto = new TestProto
testProto.init()
testProto.codec = TestCodec
switch1.mount(testProto)
(switch2, peerInfo2) = createSwitch(ma2, true)
awaiters.add(await switch1.start())
awaiters.add(await switch2.start())
let conn = await switch2.dial(switch1.peerInfo, TestCodec) let conn = await switch2.dial(switch1.peerInfo, TestCodec)
await conn.writeLp("Hello!")
let msg = string.fromBytes(await conn.readLp(1024))
check "Hello!" == msg
await conn.close()
await allFuturesThrowing( await allFuturesThrowing(
switch1.stop(), switch1.stop(),
switch2.stop()) switch2.stop())
await allFuturesThrowing(awaiters)
result = true
check: await allFuturesThrowing(awaiters)
waitFor(testSwitch()) == true
test "e2e test wrong secure negotiation":
proc testSwitch(): Future[bool] {.async, gcsafe.} =
let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
var peerInfo1, peerInfo2: PeerInfo
var switch1, switch2: Switch
var awaiters: seq[Future[void]]
(switch1, peerInfo1) = createSwitch(ma1, false)
let testProto = new TestProto
testProto.init()
testProto.codec = TestCodec
switch1.mount(testProto)
(switch2, peerInfo2) = createSwitch(ma2, true, true) # secio, we want to fail
awaiters.add(await switch1.start())
awaiters.add(await switch2.start())
expect(UpgradeFailedError):
let conn = await switch2.dial(switch1.peerInfo, TestCodec)
await allFuturesThrowing(
switch1.stop(),
switch2.stop())
await allFuturesThrowing(awaiters)
result = true
check:
waitFor(testSwitch()) == true
# test "interop with rust noise": # test "interop with rust noise":
# when true: # disable cos in CI we got no interop server/client # when true: # disable cos in CI we got no interop server/client

File diff suppressed because it is too large Load Diff

View File

@ -13,180 +13,156 @@ suite "TCP transport":
teardown: teardown:
checkTrackers() checkTrackers()
test "test listener: handle write": asyncTest "test listener: handle write":
proc testListener(): Future[bool] {.async, gcsafe.} = let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() let handlerWait = newFuture[void]()
let handlerWait = newFuture[void]() proc connHandler(conn: Connection) {.async, gcsafe.} =
proc connHandler(conn: Connection) {.async, gcsafe.} = await conn.write(cstring("Hello!"), 6)
await conn.write(cstring("Hello!"), 6) await conn.close()
await conn.close() handlerWait.complete()
handlerWait.complete()
let transport: TcpTransport = TcpTransport.init() let transport: TcpTransport = TcpTransport.init()
asyncCheck transport.listen(ma, connHandler) asyncCheck transport.listen(ma, connHandler)
let streamTransport = await connect(transport.ma) let streamTransport = await connect(transport.ma)
let msg = await streamTransport.read(6) let msg = await streamTransport.read(6)
await handlerWait.wait(5000.millis) # when no issues will not wait that long! await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await streamTransport.closeWait() await streamTransport.closeWait()
await transport.close() await transport.close()
result = string.fromBytes(msg) == "Hello!" check string.fromBytes(msg) == "Hello!"
check: asyncTest "test listener: handle read":
waitFor(testListener()) == true let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]()
test "test listener: handle read": proc connHandler(conn: Connection) {.async, gcsafe.} =
proc testListener(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6)
await conn.readExactly(addr msg[0], 6)
check string.fromBytes(msg) == "Hello!"
await conn.close()
handlerWait.complete()
let transport: TcpTransport = TcpTransport.init()
asyncCheck await transport.listen(ma, connHandler)
let streamTransport: StreamTransport = await connect(transport.ma)
let sent = await streamTransport.write("Hello!", 6)
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await streamTransport.closeWait()
await transport.close()
result = sent == 6
check:
waitFor(testListener()) == true
test "test dialer: handle write":
proc testDialer(address: TransportAddress): Future[bool] {.async.} =
let handlerWait = newFuture[void]()
proc serveClient(server: StreamServer,
transp: StreamTransport) {.async, gcsafe.} =
var wstream = newAsyncStreamWriter(transp)
await wstream.write("Hello!")
await wstream.finish()
await wstream.closeWait()
await transp.closeWait()
server.stop()
server.close()
handlerWait.complete()
var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet()
let transport: TcpTransport = TcpTransport.init()
let conn = await transport.dial(ma)
var msg = newSeq[byte](6) var msg = newSeq[byte](6)
await conn.readExactly(addr msg[0], 6) await conn.readExactly(addr msg[0], 6)
result = string.fromBytes(msg) == "Hello!" check string.fromBytes(msg) == "Hello!"
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await conn.close() await conn.close()
await transport.close() handlerWait.complete()
let transport: TcpTransport = TcpTransport.init()
asyncCheck await transport.listen(ma, connHandler)
let streamTransport: StreamTransport = await connect(transport.ma)
let sent = await streamTransport.write("Hello!", 6)
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await streamTransport.closeWait()
await transport.close()
check sent == 6
asyncTest "test dialer: handle write":
let address = initTAddress("0.0.0.0:0")
let handlerWait = newFuture[void]()
proc serveClient(server: StreamServer,
transp: StreamTransport) {.async, gcsafe.} =
var wstream = newAsyncStreamWriter(transp)
await wstream.write("Hello!")
await wstream.finish()
await wstream.closeWait()
await transp.closeWait()
server.stop() server.stop()
server.close() server.close()
await server.join() handlerWait.complete()
check: var server = createStreamServer(address, serveClient, {ReuseAddr})
waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true server.start()
test "test dialer: handle write": let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet()
proc testDialer(address: TransportAddress): Future[bool] {.async, gcsafe.} = let transport: TcpTransport = TcpTransport.init()
let handlerWait = newFuture[void]() let conn = await transport.dial(ma)
proc serveClient(server: StreamServer, var msg = newSeq[byte](6)
transp: StreamTransport) {.async, gcsafe.} = await conn.readExactly(addr msg[0], 6)
var rstream = newAsyncStreamReader(transp) check string.fromBytes(msg) == "Hello!"
let msg = await rstream.read(6)
check string.fromBytes(msg) == "Hello!"
await rstream.closeWait() await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await transp.closeWait()
server.stop()
server.close()
handlerWait.complete()
var server = createStreamServer(address, serveClient, {ReuseAddr}) await conn.close()
server.start() await transport.close()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet() server.stop()
let transport: TcpTransport = TcpTransport.init() server.close()
let conn = await transport.dial(ma) await server.join()
asyncTest "test dialer: handle write":
let address = initTAddress("0.0.0.0:0")
let handlerWait = newFuture[void]()
proc serveClient(server: StreamServer,
transp: StreamTransport) {.async, gcsafe.} =
var rstream = newAsyncStreamReader(transp)
let msg = await rstream.read(6)
check string.fromBytes(msg) == "Hello!"
await rstream.closeWait()
await transp.closeWait()
server.stop()
server.close()
handlerWait.complete()
var server = createStreamServer(address, serveClient, {ReuseAddr})
server.start()
let ma: MultiAddress = MultiAddress.init(server.sock.getLocalAddress()).tryGet()
let transport: TcpTransport = TcpTransport.init()
let conn = await transport.dial(ma)
await conn.write(cstring("Hello!"), 6)
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await conn.close()
await transport.close()
server.stop()
server.close()
await server.join()
asyncTest "e2e: handle write":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6) await conn.write(cstring("Hello!"), 6)
result = true
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await conn.close() await conn.close()
await transport.close() handlerWait.complete()
server.stop() let transport1: TcpTransport = TcpTransport.init()
server.close() asyncCheck transport1.listen(ma, connHandler)
await server.join()
check:
waitFor(testDialer(initTAddress("0.0.0.0:0"))) == true
test "e2e: handle write": let transport2: TcpTransport = TcpTransport.init()
proc testListenerDialer(): Future[bool] {.async.} = let conn = await transport2.dial(transport1.ma)
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet() var msg = newSeq[byte](6)
let handlerWait = newFuture[void]() await conn.readExactly(addr msg[0], 6)
proc connHandler(conn: Connection) {.async, gcsafe.} =
await conn.write(cstring("Hello!"), 6)
await conn.close()
handlerWait.complete()
let transport1: TcpTransport = TcpTransport.init() await handlerWait.wait(5000.millis) # when no issues will not wait that long!
asyncCheck transport1.listen(ma, connHandler)
let transport2: TcpTransport = TcpTransport.init() await conn.close()
let conn = await transport2.dial(transport1.ma) await transport2.close()
await transport1.close()
check string.fromBytes(msg) == "Hello!"
asyncTest "e2e: handle read":
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6) var msg = newSeq[byte](6)
await conn.readExactly(addr msg[0], 6) await conn.readExactly(addr msg[0], 6)
check string.fromBytes(msg) == "Hello!"
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await conn.close() await conn.close()
await transport2.close() handlerWait.complete()
await transport1.close()
result = string.fromBytes(msg) == "Hello!" let transport1: TcpTransport = TcpTransport.init()
asyncCheck transport1.listen(ma, connHandler)
check: let transport2: TcpTransport = TcpTransport.init()
waitFor(testListenerDialer()) == true let conn = await transport2.dial(transport1.ma)
await conn.write(cstring("Hello!"), 6)
test "e2e: handle read": await handlerWait.wait(5000.millis) # when no issues will not wait that long!
proc testListenerDialer(): Future[bool] {.async.} =
let ma: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
let handlerWait = newFuture[void]()
proc connHandler(conn: Connection) {.async, gcsafe.} =
var msg = newSeq[byte](6)
await conn.readExactly(addr msg[0], 6)
check string.fromBytes(msg) == "Hello!"
await conn.close()
handlerWait.complete()
let transport1: TcpTransport = TcpTransport.init() await conn.close()
asyncCheck transport1.listen(ma, connHandler) await transport2.close()
await transport1.close()
let transport2: TcpTransport = TcpTransport.init()
let conn = await transport2.dial(transport1.ma)
await conn.write(cstring("Hello!"), 6)
await handlerWait.wait(5000.millis) # when no issues will not wait that long!
await conn.close()
await transport2.close()
await transport1.close()
result = true
check:
waitFor(testListenerDialer()) == true