logos-messaging-nim/tests/api/test_conf.nim
Fabiana Cecin 28956856bb
Fix interop tests (#4020)
* logosdelivery_create_node takes a flat WakuNodeConf JSON conf (auto-detect)
* Fix tools/confutils/conf_from_json.nim not accepting Port(0)
* Fix: don't mount lightpush without relay
* Add tests
2026-07-09 17:23:34 -03:00

423 lines
17 KiB
Nim

{.used.}
import std/[options, net], results, chronos, testutils/unittests
import brokers/broker_context
import logos_delivery
import logos_delivery/api/logos_delivery_conf_json
import logos_delivery/waku/factory/[waku_conf, networks_config]
import logos_delivery/waku/common/logging
suite "MessagingClientConf - mode expansion (toWakuNodeConf)":
test "Core mode enables relay + service protocols":
let kc = MessagingClientConf().toWakuNodeConf(LogosDeliveryMode.Core).valueOr:
raiseAssert error
check:
kc.relay == true
kc.filter == true
kc.lightpush == true
kc.discv5Discovery == some(true)
kc.peerExchange == true
kc.rendezvous == true
test "Edge mode is client-only (no relay/filter/lightpush/store)":
let kc = MessagingClientConf().toWakuNodeConf(LogosDeliveryMode.Edge).valueOr:
raiseAssert error
check:
kc.relay == false
kc.filter == false
kc.lightpush == false
kc.store == false
kc.peerExchange == true
kc.discv5Discovery == some(true) # discovery stays on; mode does not force it off
suite "MessagingClientConf - field mapping + transport policy":
test "set fields are written to their kernel counterparts":
let mc = MessagingClientConf(
clusterId: some(3'u16),
numShardsInCluster: some(4'u16),
maxMessageSize: some("150KiB"),
)
let kc = mc.toWakuNodeConf(LogosDeliveryMode.Core).valueOr:
raiseAssert error
check:
kc.clusterId == some(3'u16)
kc.numShardsInNetwork == 4
kc.maxMessageSize == "150KiB"
test "messaging transport defaults: ephemeral ports, websocket off, quic on":
let kc = MessagingClientConf().toWakuNodeConf(LogosDeliveryMode.Core).valueOr:
raiseAssert error
check:
kc.tcpPort == Port(0)
kc.discv5UdpPort == Port(0)
kc.websocketSupport == false
kc.quicSupport == true
test "explicit transport overrides win":
let mc = MessagingClientConf(
p2pTcpPort: some(Port(1234)),
websocketSupport: some(true),
quicSupport: some(false),
)
let kc = mc.toWakuNodeConf(LogosDeliveryMode.Core).valueOr:
raiseAssert error
check:
kc.tcpPort == Port(1234)
kc.websocketSupport == true
kc.quicSupport == false
suite "MessagingClientConf - preset resolution":
test "resolvePreset lifts only messaging-exclusive fields, not kernel-mirrored ones":
let mc = resolvePreset("twn").valueOr:
raiseAssert error
check:
mc.reliabilityEnabled.isSome()
mc.clusterId.isNone()
mc.maxMessageSize.isNone()
test "resolvePreset does not lift entryNodes":
let mc = resolvePreset("logostest").valueOr:
raiseAssert error
check mc.entryNodes.isNone()
test "empty preset resolves to an empty config":
let mc = resolvePreset("").valueOr:
raiseAssert error
check:
mc.clusterId.isNone()
mc.maxMessageSize.isNone()
test "a messaging override of a kernel-mirrored field wins over the preset":
let presetConf = resolvePreset("logos.dev").valueOr:
raiseAssert error
let merged = merge(presetConf, MessagingClientConf(numShardsInCluster: some(1'u16)))
var kernelConf = toWakuNodeConf(merged, LogosDeliveryMode.Core).valueOr:
raiseAssert error
kernelConf.preset = "logos.dev"
let wakuConf = kernelConf.toWakuConf().valueOr:
raiseAssert error
check:
wakuConf.shardingConf.kind == AutoSharding
wakuConf.shardingConf.numShardsInCluster == 1
suite "MessagingClientConf - merge (override wins)":
test "a set override field wins; unset keeps the base":
let base = MessagingClientConf(clusterId: some(1'u16), maxMessageSize: some("1MB"))
let overrides = MessagingClientConf(clusterId: some(2'u16))
let mc = merge(base, overrides)
check:
mc.clusterId == some(2'u16) # override wins
mc.maxMessageSize == some("1MB") # base preserved
suite "parseLogosDeliveryConf - JSON parsing":
test "empty object resolves to a full Core node conf":
let lc = parseLogosDeliveryConf("{}").valueOr:
raiseAssert error
check:
lc.messagingConf.isSome() # full node: messaging + channels mounted
lc.channelsConf.isSome()
WakuNodeConf(lc.kernelConf).relay == true # Core enables relay
WakuNodeConf(lc.kernelConf).clusterId.isNone() # no cluster set
test "mode + preset fold into the kernel conf":
let lc = parseLogosDeliveryConf("""{"mode": "Edge", "preset": "logostest"}""").valueOr:
raiseAssert error
let kc = WakuNodeConf(lc.kernelConf)
check:
kc.preset == "logostest"
kc.relay == false # Edge disables relay
test "messaging overrides split: kernel fields to the kernel, reliability to the record":
let lc = parseLogosDeliveryConf(
"""{"mode": "Core", "messagingOverrides": {"clusterId": 7, "reliabilityEnabled": true}}"""
).valueOr:
raiseAssert error
require lc.messagingConf.isSome()
check:
WakuNodeConf(lc.kernelConf).clusterId == some(7'u16) # kernel field
lc.messagingConf.get().reliabilityEnabled == some(true) # messaging-only
test "messaging overrides are recorded verbatim, unset fields left none":
let lc = parseLogosDeliveryConf("""{"messagingOverrides": {"clusterId": 7}}""").valueOr:
raiseAssert error
require lc.messagingConf.isSome()
let overrides = lc.messagingConf.get()
check:
overrides.clusterId == some(7'u16) # the user's override, kept as given
overrides.reliabilityEnabled.isNone() # user didn't set it, so it stays none
test "a preset resolves reliability into the messaging record":
let lc = parseLogosDeliveryConf("""{"preset": "twn"}""").valueOr:
raiseAssert error
# the user set no reliability override, but the preset supplies one
require lc.messagingConf.isSome()
check lc.messagingConf.get().reliabilityEnabled.isSome()
test "channelsOverrides fold into the channel conf":
let lc = parseLogosDeliveryConf(
"""{"channelsOverrides": {"rateLimitEnabled": true, "sdsMaxRetransmissions": 9}}"""
).valueOr:
raiseAssert error
require lc.channelsConf.isSome()
let channels = lc.channelsConf.get()
check:
channels.rateLimitEnabled == some(true)
channels.sdsMaxRetransmissions == some(9)
test "invalid mode is rejected (Core or Edge only)":
check parseLogosDeliveryConf("""{"mode": "bogus"}""").isErr()
check parseLogosDeliveryConf("""{"mode": "noMode"}""").isErr()
check parseLogosDeliveryConf("""{"mode": ""}""").isErr()
test "invalid JSON is rejected":
check parseLogosDeliveryConf("{ not json }").isErr()
test "a truly unknown top-level key is rejected (flat walker rejects the field)":
# NB: a *known* WakuNodeConf field at top level (e.g. logLevel) is now accepted
# as a flat blob; only a field that is not a WakuNodeConf field is rejected.
check parseLogosDeliveryConf("""{"totallyBogusField": "x", "mode": "Core"}""").isErr()
test "override keys accept CLI switch names":
let lc = parseLogosDeliveryConf(
"""{"messagingOverrides": {"cluster-id": 7, "reliability": true, "tcp-port": 1234}}"""
).valueOr:
raiseAssert error
let kc = WakuNodeConf(lc.kernelConf)
require lc.messagingConf.isSome()
check:
kc.clusterId == some(7'u16)
lc.messagingConf.get().reliabilityEnabled == some(true) # messaging-only
kc.tcpPort == Port(1234)
test "unknown keys inside an overrides body are rejected":
check parseLogosDeliveryConf("""{"messagingOverrides": {"bogusKey": 1}}""").isErr()
check parseLogosDeliveryConf("""{"channelsOverrides": {"bogusKey": 1}}""").isErr()
test "a field set via both its name and its switch name is rejected":
check parseLogosDeliveryConf(
"""{"messagingOverrides": {"clusterId": 5, "cluster-id": 5}}"""
)
.isErr()
test "logLevel and nodeKey parse via switch names and map to the kernel":
let lc = parseLogosDeliveryConf(
"""{"messagingOverrides": {"log-level": "DEBUG", "log-format": "JSON", "nodekey": "0d714a1fada214dead6dc9c7274581ec20ff292451866e7d6d677dc818e8ccd2"}}"""
).valueOr:
raiseAssert error
let kc = WakuNodeConf(lc.kernelConf)
check:
kc.logLevel == logging.LogLevel.DEBUG
kc.logFormat == logging.LogFormat.JSON
kc.nodekey.isSome()
test "a null value leaves the field unset":
let lc = parseLogosDeliveryConf(
"""{"messagingOverrides": {"store": null, "clusterId": 7}}"""
).valueOr:
raiseAssert error
let kc = WakuNodeConf(lc.kernelConf)
check:
kc.clusterId == some(7'u16)
kc.store == false # null left store unset; Core does not enable it
test "an invalid Ethereum RPC URL is rejected at parse time":
check parseLogosDeliveryConf(
"""{"messagingOverrides": {"rln-relay-eth-client-address": ["ws://node:8546"]}}"""
)
.isErr()
let lc = parseLogosDeliveryConf(
"""{"messagingOverrides": {"rln-relay-eth-client-address": ["http://localhost:8540/"]}}"""
).valueOr:
raiseAssert error
check WakuNodeConf(lc.kernelConf).ethClientUrls.len == 1
test "store backend fields fold into the kernel conf":
let lc = parseLogosDeliveryConf(
"""{"messagingOverrides": {"store": true, "store-message-db-url": "sqlite://test.db", "store-message-retention-policy": "time:3600", "store-max-num-db-connections": 7}}"""
).valueOr:
raiseAssert error
let kc = WakuNodeConf(lc.kernelConf)
check:
kc.store == true
kc.storeMessageDbUrl == "sqlite://test.db"
kc.storeMessageRetentionPolicy == "time:3600"
kc.storeMaxNumDbConnections == 7
test "fleet mode parses a raw kernelConf":
let lc = parseLogosDeliveryConf(
"""{"mode": "fleet", "kernelConf": {"relay": false, "maxMessageSize": "150KiB"}}"""
).valueOr:
raiseAssert error
check:
lc.messagingConf.isNone() # kernel-only: no upper layers
lc.channelsConf.isNone()
let kc = WakuNodeConf(lc.kernelConf)
check:
kc.relay == false
kc.maxMessageSize == "150KiB"
test "fleet mode requires a kernelConf":
check parseLogosDeliveryConf("""{"mode": "fleet"}""").isErr()
test "fleet mode rejects anything besides kernelConf":
check parseLogosDeliveryConf(
"""{"mode": "fleet", "kernelConf": {}, "messagingOverrides": {"clusterId": 1}}"""
)
.isErr()
# a preset for a fleet node goes inside kernelConf (WakuNodeConf.preset); fleet
# treats kernelConf as a finished object and overlays nothing onto it
check parseLogosDeliveryConf(
"""{"mode": "fleet", "kernelConf": {}, "preset": "twn"}"""
)
.isErr()
test "kernelConf is rejected outside fleet mode":
# kernelConf is a fleet-only wrapper. Under Core/Edge it is neither consumed by the
# structured path nor a flat kernel field, so it must surface as an unknown key.
check parseLogosDeliveryConf("""{"mode": "core", "kernelConf": {}}""").isErr()
suite "LogosDelivery.new - construction (the app-dev entry)":
asyncTest "builds the full messaging stack from mode + overrides":
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (
await LogosDelivery.new(
LogosDeliveryMode.Core,
"",
MessagingClientConf(
clusterId: some(3'u16),
numShardsInCluster: some(1'u16),
listenIpv4: some(parseIpAddress("0.0.0.0")),
reliabilityEnabled: some(true),
),
)
).valueOr:
raiseAssert error
check:
not node.waku.isNil()
not node.messagingClient.isNil()
not node.reliableChannelManager.isNil()
(await node.stop()).expect("stop")
asyncTest "builds from a network preset":
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (
await LogosDelivery.new(
LogosDeliveryMode.Core,
"logostest",
MessagingClientConf(listenIpv4: some(parseIpAddress("0.0.0.0"))),
)
).valueOr:
raiseAssert error
check not node.waku.isNil()
(await node.stop()).expect("stop")
suite "MessagingClientConf - store override":
test "store opt-in overrides the mode default; protocol flags follow the mode":
let kc = MessagingClientConf(store: some(true)).toWakuNodeConf(
LogosDeliveryMode.Edge
).valueOr:
raiseAssert error
check:
kc.store == true # Edge defaults store off; the explicit opt-in wins
kc.relay == false # protocols are owned by the mode, not overridable
suite "LogosDelivery.new - raw kernel construction":
asyncTest "a fleet node mounts the kernel only; start/stop tolerate the nil layers":
let kernel = MessagingClientConf(listenIpv4: some(parseIpAddress("0.0.0.0"))).toWakuNodeConf(
LogosDeliveryMode.Core
).valueOr:
raiseAssert error
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(KernelConf(kernel))).valueOr:
raiseAssert error
check:
not node.waku.isNil()
node.messagingClient.isNil() # no messaging client on a fleet node
node.reliableChannelManager.isNil() # no channel manager either
# start()/stop() must skip the nil messaging + channel layers, not deref them
(await node.start()).expect("start")
(await node.stop()).expect("stop")
# [Legacy flat JSON config] These suites cover the legacy flat shape; delete them
# together with parseFlatConf when flat-shape support is dropped.
suite "parseLogosDeliveryConf - flat WakuNodeConf shape (interop compatibility)":
test "a flat blob of kernel fields is detected and parsed as a full stack":
let lc = parseLogosDeliveryConf(
"""{"relay": true, "clusterId": 7, "store": true, "filter": false}"""
).valueOr:
raiseAssert error
check:
WakuNodeConf(lc.kernelConf).relay == true
WakuNodeConf(lc.kernelConf).clusterId == some(7'u16)
lc.messagingConf.isSome() # full stack
lc.channelsConf.isSome()
test "flat blob carrying mode: mode expands to flags, explicit flags override":
let lc = parseLogosDeliveryConf(
"""{"mode": "Edge", "relay": true, "clusterId": 7}"""
).valueOr:
raiseAssert error
check:
WakuNodeConf(lc.kernelConf).relay == true
# explicit flat field overrides the Edge default
WakuNodeConf(lc.kernelConf).filter == false # Edge default, not set explicitly
WakuNodeConf(lc.kernelConf).clusterId == some(7'u16)
test "flat blob's reliabilityEnabled routes to the messaging conf, not the kernel":
let lc = parseLogosDeliveryConf("""{"relay": true, "reliabilityEnabled": true}""").valueOr:
raiseAssert error
check:
lc.messagingConf.get().reliabilityEnabled == some(true)
test "an unknown key in a flat blob is rejected":
check parseLogosDeliveryConf("""{"relay": true, "bogusKey": 1}""").isErr()
test "a flat blob's preset lifts reliability into the messaging record":
# twn defines a p2pReliability; the flat path must resolve it into the messaging
# conf (the kernel no longer carries reliability), matching master.
let lc = parseLogosDeliveryConf("""{"preset": "twn", "relay": true}""").valueOr:
raiseAssert error
let fromPreset = resolvePreset("twn").valueOr:
raiseAssert error
check lc.messagingConf.get().reliabilityEnabled == fromPreset.reliabilityEnabled
test "port 0 (auto-allocate) is accepted in a flat blob":
let lc = parseLogosDeliveryConf(
"""{"relay": true, "tcpPort": 0, "discv5UdpPort": 0}"""
).valueOr:
raiseAssert error
check:
WakuNodeConf(lc.kernelConf).tcpPort == Port(0)
WakuNodeConf(lc.kernelConf).discv5UdpPort == Port(0)
test "port 0 is accepted in structured messagingOverrides":
let lc = parseLogosDeliveryConf("""{"messagingOverrides": {"tcp-port": 0}}""").valueOr:
raiseAssert error
check lc.messagingConf.get().p2pTcpPort == some(Port(0))
test "mode/preset with no bare field stays structured; a bare field flips it to flat":
# No bare kernel field -> structured: mode owns relay, no per-flag override.
let structured = parseLogosDeliveryConf(
"""{"mode": "Edge", "preset": "logostest"}"""
).valueOr:
raiseAssert error
check WakuNodeConf(structured.kernelConf).relay == false # Edge, structured
# Adding a bare kernel field (relay) flips to flat, where the explicit flag wins;
# relay == true is only reachable via the flat path, so it proves the routing.
let flat = parseLogosDeliveryConf(
"""{"mode": "Edge", "preset": "logostest", "relay": true}"""
).valueOr:
raiseAssert error
check:
WakuNodeConf(flat.kernelConf).relay == true
WakuNodeConf(flat.kernelConf).preset == "logostest"
test "a wrapper key alongside a bare kernel field is rejected, not split":
# A wrapper key (messagingOverrides) marks the structured shape, so the blob does
# not flip to flat; the leftover bare field (relay) then has no structured home and
# is rejected. Guards against the discriminator silently splitting a mixed object.
check parseLogosDeliveryConf("""{"messagingOverrides": {}, "relay": true}""").isErr()