Skip to content

E2E testing of LogosDelivery Reliable Channel API #191

Description

@darshankabariya

E2E testing of LogosDelivery Reliable Channel API — channel-layer focus

Curated E2E / interop scenarios for the Reliable Channel API (logos_delivery/channels), driven against liblogosdelivery. This round is scoped to what the channel layer owns on its own: its call contract and the ChannelReceived delivery path. Store validation / the --reliability flag is out of scope (see rationale below).

Scope decision — reliability/store is a messaging concern, not a channel one:

  • The channel layer's own reliability (SDS: acks, retransmits, causal ordering, dedup) is always on — there is no toggle.
  • The channel layer is store-agnostic: it never queries a store; it only reacts to messaging-layer events.
  • Today the channel's send-terminal events (ChannelSent / ChannelError) are gated entirely on the messaging layer's store validation (they need a MessageSent, which only fires from a store-v3 check when --reliability + a store are configured). That coupling is a messaging-layer property, so ChannelSent / ChannelError are excluded from this channel-focused round and tracked separately.
  • By contrast, the receiver's ChannelReceived needs only relay propagation + SDS unwrap — no store, no reliability flag — so it is the real channel-layer surface we exercise here.

FFI surface:
logosdelivery_channel_create(ctx, cb, ud, channelId, contentTopic, senderId),
logosdelivery_channel_send(ctx, cb, ud, channelId, messageJson) where messageJson = {"payload": <base64>, "ephemeral": <bool>},
logosdelivery_channel_close(ctx, cb, ud, channelId).
Channel events via logosdelivery_set_event_callback: onChannelMessageReceived / onChannelMessageSent / onChannelMessageError.

Event-name legend (shorthand → FFI callback event → Nim event type):

Shorthand FFI callback event Nim event
ChannelReceived onChannelMessageReceived ChannelMessageReceivedEvent
ChannelSent (out of scope) onChannelMessageSent ChannelMessageSentEvent
ChannelError (out of scope) onChannelMessageError ChannelMessageErrorEvent

Behaviors worth asserting:

  • channel_send returns Ok(channelReqId) immediately; delivery is async. In these tests the sender's channelReqId is a handle only — we assert on the receiver's ChannelReceived, not on a sender terminal event.
  • Ingress drops messages without the RELIABLE-CHANNEL-API/1 marker, on the wrong content topic, or for a foreign SDS channelId.
  • SDS delivers to the app in causal order and de-duplicates — observable purely through ChannelReceived.
  • Topology (peers) is set at create_node time via config (staticnode); there is no peer-connect FFI call. No storenode / --reliability needed for any scenario here.

Recommended Minimal Matrix (prioritize): RC01, RC02, RC03, RC04, RC05, RC06, RC08, RC09.


Scenario Catalog (channel-layer E2E / [IT])

A. Lifecycle & API contract (single node; no events, no topology)

  • RC01. Create channel; duplicate create rejected [IT]

    • Setup: node created and started (mode = Core); reliable channel manager mounted automatically.
    • Action: channel_create(id, contentTopic, senderId); then channel_create again with the same id.
    • Expected result: first succeeds; second returns "channel already exists: <id>".
    • Expected events: none.
    • Purpose: channel registry create + duplicate guard.
  • RC02. Send on unknown channel [IT]

    • Action: channel_send(unknownId, {...}) for an id never created.
    • Expected result: "unknown channel: <id>". Expected events: none.
  • RC03. Close channel; close unknown rejected [IT]

    • Action: channel_close(id) on an existing channel; then channel_close again / on an unknown id.
    • Expected result: first succeeds; second returns "unknown channel: <id>".
    • Purpose: lifecycle teardown + idempotency guard.
  • RC04. Send empty payload; send returns a handle immediately [IT]

    • Action: channel_send(id, {"payload": "", "ephemeral": false}); then a normal channel_send with a non-empty payload.
    • Expected result: empty → "empty payload"; non-empty → Ok(channelReqId) returned synchronously (delivery is async).
    • Expected events: none required for this contract check.
    • Purpose: input validation + the immediate-handle contract of send.

B. Two-party delivery & ingress filtering (assert on receiver's ChannelReceived)

  • RC05. A → B on the same channel + topic → ChannelReceived [IT]

    • Setup: two liblogosdelivery nodes, both channel_create with the same channelId + contentTopic, connected on the shared shard; both subscribe(contentTopic). No store, no --reliability.
    • Action: A channel_send(payload).
    • Expected events: B emits ChannelReceived with the exact payload (byte-equal after SDS unwrap/reassemble) and A's senderId. (A's channelReqId is a handle only; no sender terminal event is asserted.)
    • Purpose: the core end-to-end delivery path — marker + topic match + SDS unwrap + reassemble + emit. Baseline for RC06/RC07 (drop cases) and RC08–RC12 (SDS semantics).
  • RC06. Missing spec marker → dropped [IT]

    • Action: as RC05, but the peer publishes a plain messaging message (logosdelivery_send, no channel marker) on the node-under-test's contentTopic.
    • Expected events: none (ChannelReceived must not fire).
  • RC07. Wrong content topic → dropped [IT]

    • Action: as RC05, but the peer delivers a correctly-marked channel message on a different contentTopic.
    • Expected events: none.

C. SDS delivery semantics (two-party; assert on receiver's ChannelReceived)

  • RC08. Bidirectional exchange preserves causal order [IT]

    • Action: A and B send interleaved messages that reference each other.
    • Expected events: each side delivers the other's messages via ChannelReceived in causal order.
  • RC09. A sends while B is offline; B joins later and recovers [IT]

    • Action: A sends; B is not yet connected; B joins during the SDS recovery window.
    • Expected events: B eventually emits ChannelReceived via SDS sync/repair.
  • RC10. Missing dependency triggers an SDS-R repair rebroadcast [IT, two-party]

    • Setup: a receiver reports missing dependencies; the holder participates in SDS-R.
    • Expected: a repair rebroadcast is dispatched on the wire (ephemeral); the receiver recovers and delivers the parked content via ChannelReceived.
  • RC11. Retransmission of an unacked send [IT, two-party]

    • Setup: a send goes unacknowledged.
    • Expected: retransmitted after the ack timeout (DefaultAcknowledgementTimeoutMs), up to DefaultMaxRetransmissions, until the receiver delivers it (ChannelReceived) / it is acked.
  • RC12. Three participants on one channel [IT]

    • Action: A, B, C share a channel; A sends.
    • Expected events: both B and C emit ChannelReceived; causal metadata stays consistent.

Out of scope for this round

Send-terminal events (ChannelSent / ChannelError) — currently gated on the messaging layer's store validation (--reliability + a reachable store), not on channel-layer behavior. Excluded here; track under messaging-layer E2E, or revisit if channel success is redefined to be SDS-ack-based rather than store-validated. (Covers: store-validated send → ChannelSent; propagated-but-not-validated → no terminal; isolated sender → ChannelError; ephemeral → never ChannelSent.)

Already covered in-process by tests/channels/test_reliable_channel_send_receive.nim (not re-implemented at E2E): history survives close/re-create; foreign channelId dropped; out-of-order parking; duplicate delivered once; unacked acked by later remote message; reply advances the lamport clock; three-deep dependency chain; sync envelope consumed silently; concurrent sibling sends finalise independently.

Not yet written (Nim-side, not E2E): encryption provider fails → ChannelError; decryption failure on ingress → MessageError; non-SDS/undecodable payload → MessageError; SDS state survives node restart.

Deferred (feature not implemented — segmentation / encryption skeletons): multi-segment split/reassemble; multi-segment aggregation; Reed-Solomon parity recovery; real encryption round-trip; selective-field encryption; wrong-key decryption.


logos-messaging/logos-delivery#3959

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions