logos-messaging-nim/tests/factory/test_node_factory.nim
Fabiana Cecin 71a369ffad
feat: allow a port value of zero for service ports (auto-assign port) (#3828)
* any port set to 0 on conf results in a random port bound
* Debug API MyBoundPorts reports actually bound ports for all services, reports 0 if disabled
* write back bound values to both WakuConf and WakuNode.ports
* setupDiscoveryV5 returns Result and errors out on port 0
* rename setupAndStartDiscv5WithAutoPort to setupAndStartDiscv5
* updateWaku ENR rebuild now runs after discv5 startup
* Add DefaultP2pTcpPort, DefaultDiscv5UdpPort, DefaultWebSocketPort, DefaultRestPort, DefaultMetricsHttpPort
* add tests
2026-05-11 15:22:22 -03:00

207 lines
5.7 KiB
Nim

{.used.}
import
std/[net, options, sequtils, strutils],
testutils/unittests,
chronos,
chronos/transports/[stream, datagram, common],
metrics/chronos_httpserver,
libp2p/[crypto/crypto, multiaddress, protocols/connectivity/relay/relay],
eth/p2p/discoveryv5/enr
import
tests/testlib/[wakunode, wakucore],
waku/[waku_node, waku_enr, net/auto_port, discovery/waku_discv5, node/waku_metrics],
waku/factory/[
node_factory,
internal_config,
conf_builder/conf_builder,
conf_builder/web_socket_conf_builder,
]
suite "Node Factory":
asynctest "Set up a node based on default configurations":
let conf = defaultTestWakuConf()
let node = (await setupNode(conf, relay = Relay.new())).valueOr:
raiseAssert error
check:
not node.isNil()
node.wakuArchive.isNil()
node.wakuStore.isNil()
node.wakuFilter.isNil()
not node.wakuStoreClient.isNil()
not node.wakuRendezvous.isNil()
asynctest "Set up a node with Store enabled":
var confBuilder = defaultTestWakuConfBuilder()
confBuilder.storeServiceConf.withEnabled(true)
confBuilder.storeServiceConf.withDbUrl("sqlite://store.sqlite3")
let conf = confBuilder.build().value
let node = (await setupNode(conf, relay = Relay.new())).valueOr:
raiseAssert error
check:
not node.isNil()
not node.wakuStore.isNil()
not node.wakuArchive.isNil()
test "ENR configuration trims multiaddrs until record fits":
var conf = defaultTestWakuConf()
let bindIp = conf.endpointConf.p2pListenAddress
let bindPort = Port(30303)
let oversizedMultiaddrs = (0 .. 11).mapIt(
MultiAddress
.init(
"/dns4/very-long-logical-hostname-" & $it &
".example.logos.dev.status.im/tcp/30303/wss"
)
.get()
)
let netConfig = NetConfig.init(
clusterId = conf.clusterId,
bindIp = bindIp,
bindPort = bindPort,
extMultiAddrs = oversizedMultiaddrs,
extMultiAddrsOnly = true,
wakuFlags = some(conf.wakuFlags),
).valueOr:
raiseAssert error
let record = enrConfiguration(conf, netConfig).valueOr:
raiseAssert error
let typedRecord = record.toTyped()
require typedRecord.isOk()
let multiaddrsOpt = typedRecord.value.multiaddrs
require multiaddrsOpt.isSome()
let retainedMultiaddrs = multiaddrsOpt.get()
check:
retainedMultiaddrs.len < oversizedMultiaddrs.len
retainedMultiaddrs.len > 0
retainedMultiaddrs == oversizedMultiaddrs[0 ..< retainedMultiaddrs.len]
asynctest "Set up a node with Filter enabled":
var confBuilder = defaultTestWakuConfBuilder()
confBuilder.filterServiceConf.withEnabled(true)
let conf = confBuilder.build().value
let node = (await setupNode(conf, relay = Relay.new())).valueOr:
raiseAssert error
check:
not node.isNil()
not node.wakuFilter.isNil()
echo "TEST END"
asynctest "Start a node based on default test configuration":
let conf = defaultTestWakuConf()
let node = (await setupNode(conf, relay = Relay.new())).valueOr:
raiseAssert error
assert not node.isNil(), "Node can't be nil"
let startRes = catch:
(await startNode(node, conf))
assert not startRes.isErr(), "Exception starting node"
assert startRes.get().isOk(), "Error starting node " & startRes.get().error
check:
node.started == true
# Default conf has p2pTcpPort=0, so the OS must have assigned a real port.
var hasNonZeroTcp = false
for a in node.switch.peerInfo.listenAddrs:
let s = $a
if ("/tcp/" in s) and not ("/tcp/0" in s):
hasNonZeroTcp = true
check hasNonZeroTcp
## Cleanup
await node.stop()
suite "Auto-port retry":
asynctest "metrics binds on free TCP port, fails on taken":
let takenPort = Port(55100)
let freePort = Port(55101)
let taken = createStreamServer(initTAddress("127.0.0.1", takenPort))
defer:
taken.stop()
await taken.closeWait()
proc buildMetricsConf(port: Port): MetricsServerConf =
var b = MetricsServerConfBuilder.init()
b.withEnabled(true)
b.withHttpPort(port)
b.build().value.get()
let failRes = await startMetricsServerAndLogging(buildMetricsConf(takenPort), 0'u16)
check failRes.isErr()
let okRes = await startMetricsServerAndLogging(buildMetricsConf(freePort), 0'u16)
check okRes.isOk()
if okRes.isOk():
await okRes.get().server.close()
asynctest "discv5 binds on free UDP port, fails on taken":
let takenPort = Port(55200)
let freePort = Port(55201)
proc dummyCb(
transp: DatagramTransport, raddr: TransportAddress
): Future[void] {.async: (raises: []).} =
discard
let takenUdp =
newDatagramTransport(dummyCb, local = initTAddress("0.0.0.0", takenPort))
defer:
await takenUdp.closeWait()
let nodeKey = generateSecp256k1Key()
let node = newTestWakuNode(nodeKey, parseIpAddress("0.0.0.0"), Port(0))
await node.start()
defer:
await node.stop()
proc buildDiscv5Conf(port: Port): Discv5Conf =
var b = Discv5ConfBuilder.init()
b.withEnabled(true)
b.withUdpPort(port)
b.build().value.get()
let failRes = await setupAndStartDiscv5(
node.enr,
node.peerManager,
node.topicSubscriptionQueue,
buildDiscv5Conf(takenPort),
@[],
node.rng,
nodeKey,
parseIpAddress("0.0.0.0"),
0'u16,
)
check failRes.isErr()
let okRes = await setupAndStartDiscv5(
node.enr,
node.peerManager,
node.topicSubscriptionQueue,
buildDiscv5Conf(freePort),
@[],
node.rng,
nodeKey,
parseIpAddress("0.0.0.0"),
0'u16,
)
check okRes.isOk()
if okRes.isOk():
await okRes.get().stop()