logos-delivery/tests/api/test_entry_layer.nim
NagyZoltanPeter 9827be5990
feat: logos_delivery_node app + messaging REST API with event observability (#4014)
* WIP logosdeliverynode app initial commit

* WIP - extra cli option

* WIP: messaging client REST endpoints

* Add event poll for messaging rest with cache mechanism

* Messaging rest tests

* test: assert 404 via raw string client in messaging REST test

presto's typed REST client raises RestDecodingError when it cannot decode
a non-2xx text error body into the response type. Add a RestResponse[string]
stub (messagingGetSendEventsByIdRawV1) and point the "already-polled id ->
404" assertion at it, matching the relay REST test pattern.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* remove customized cli args as confutils has no support for it

* Introduce --entry-layer and re-introduce --mode flags into cli args, applied new driver into LogosDelivery + tests

* Add messaging REST client test

* Add docker image build of logosdeliverynode for CI builds

* Fix tests

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Refactor Messaging REST API to better match Messaging Send and Receive APIs

* chore: migrate messaging REST API to Opt[T]

Follow-up to the rebase onto master's repo-wide Option[T] -> Opt[T] change
(#4035). Converts the code this branch adds to the new convention:

- messaging/rest_api/types.nim: MessagingJsonEnvelope fields to Opt[T],
  Opt.some/Opt.none, and json_serialization/pkg/results instead of
  json_serialization/std/options.
- tests: WakuNodeConf.clusterId is now Opt[uint16]; DTO fields are Opt.

`Option[ContentBody]` in the handlers is presto's own API and stays as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-17 18:14:52 +02:00

129 lines
4.6 KiB
Nim

{.used.}
import std/[options, net]
import chronos, testutils/unittests, presto, presto/client as presto_client
import brokers/broker_context
import logos_delivery
import
logos_delivery/api/conf/logos_delivery_conf,
logos_delivery/messaging/rest_api/client as messaging_rest_client,
logos_delivery/waku/rest_api/endpoint/client
import tools/confutils/cli_args
import ../testlib/testasync
## Validates the layer-selection invariant of `LogosDelivery.new(WakuNodeConf)`:
## `messagingClient` (and `reliableChannelManager`) are instantiated only for the
## entry layers that call for them.
##
## kernel -> waku only
## messaging -> waku + messagingClient
## channels -> waku + messagingClient + reliableChannelManager
proc nodeConf(entryLayer: EntryLayer, rest = false): WakuNodeConf =
var conf = defaultWakuNodeConf().valueOr:
raiseAssert error
conf.entryLayer = entryLayer
conf.mode = LogosDeliveryMode.Core
conf.listenAddress = parseIpAddress("0.0.0.0")
conf.tcpPort = Port(0)
conf.discv5UdpPort = Port(0)
conf.clusterId = Opt.some(3'u16)
conf.numShardsInNetwork = 1
conf.rest = rest
conf.restAddress = parseIpAddress("127.0.0.1")
conf.restPort = 0'u16 # bind to an ephemeral port
return conf
proc restClientFor(node: LogosDelivery): RestClientRef =
let boundPort = node.waku.restServer.httpServer.address.port
newRestHttpClient(initTAddress(parseIpAddress("127.0.0.1"), boundPort))
suite "LogosDelivery - entry layer selection":
asyncTest "kernel: waku only, no messaging / channels":
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(nodeConf(EntryLayer.kernel))).valueOr:
raiseAssert error
check:
not node.waku.isNil()
node.messagingClient.isNil()
node.reliableChannelManager.isNil()
node.ensureMessaging().isErr()
node.ensureChannels().isErr()
(await node.stop()).isOkOr:
raiseAssert "stop failed: " & error
asyncTest "messaging: waku + messagingClient, no channels":
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(nodeConf(EntryLayer.messaging))).valueOr:
raiseAssert error
check:
not node.waku.isNil()
not node.messagingClient.isNil()
node.reliableChannelManager.isNil()
node.ensureMessaging().isOk()
node.ensureChannels().isErr()
(await node.stop()).isOkOr:
raiseAssert "stop failed: " & error
asyncTest "channels: full stack":
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(nodeConf(EntryLayer.channels))).valueOr:
raiseAssert error
check:
not node.waku.isNil()
not node.messagingClient.isNil()
not node.reliableChannelManager.isNil()
node.ensureMessaging().isOk()
node.ensureChannels().isOk()
(await node.stop()).isOkOr:
raiseAssert "stop failed: " & error
asyncTest "messaging + rest: messaging REST endpoints are installed and working":
## entry-layer=messaging, mode=Core, rest=true -> `start` mounts the messaging
## REST endpoints; they respond over HTTP.
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(nodeConf(EntryLayer.messaging, rest = true))).valueOr:
raiseAssert error
(await node.start()).isOkOr:
raiseAssert "start failed: " & error
check not node.messagingClient.isNil()
let client = restClientFor(node)
# A command endpoint and an observability endpoint both respond -> the
# handlers were installed onto the kernel router.
let subResp =
await client.messagingPostSubscriptionsV1(@["/test/1/entry-layer/proto"])
check subResp.status == 200
let sendEventsResp = await client.messagingGetSendEventsV1()
check sendEventsResp.status == 200
(await node.stop()).isOkOr:
raiseAssert "stop failed: " & error
asyncTest "kernel + rest: messaging REST endpoints are NOT installed":
## Gating check: a kernel-only node still starts a REST server, but the
## messaging endpoints must be absent (no messaging client to mount them).
var node: LogosDelivery
lockNewGlobalBrokerContext:
node = (await LogosDelivery.new(nodeConf(EntryLayer.kernel, rest = true))).valueOr:
raiseAssert error
(await node.start()).isOkOr:
raiseAssert "start failed: " & error
check node.messagingClient.isNil()
let client = restClientFor(node)
let subResp =
await client.messagingPostSubscriptionsV1(@["/test/1/entry-layer/proto"])
check subResp.status == 404 # route not mounted
(await node.stop()).isOkOr:
raiseAssert "stop failed: " & error