mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-03 14:33:12 +00:00
* chore: use distinct type for Light push status codes * Make naming more explicit * test: use new light push error code in tests * fix missed line * fix thing
374 lines
14 KiB
Nim
374 lines
14 KiB
Nim
{.used.}
|
|
|
|
import
|
|
std/[options, strscans],
|
|
testutils/unittests,
|
|
chronos,
|
|
chronicles,
|
|
libp2p/crypto/crypto
|
|
|
|
import
|
|
waku/[
|
|
node/peer_manager,
|
|
waku_core,
|
|
waku_lightpush,
|
|
waku_lightpush/client,
|
|
waku_lightpush/protocol_metrics,
|
|
],
|
|
../testlib/[assertions, wakucore, testasync, futures],
|
|
./lightpush_utils,
|
|
../resources/[pubsub_topics, content_topics, payloads]
|
|
|
|
suite "Waku Lightpush Client":
|
|
var
|
|
handlerFuture {.threadvar.}: Future[(PubsubTopic, WakuMessage)]
|
|
handler {.threadvar.}: PushMessageHandler
|
|
|
|
serverSwitch {.threadvar.}: Switch
|
|
clientSwitch {.threadvar.}: Switch
|
|
server {.threadvar.}: WakuLightPush
|
|
client {.threadvar.}: WakuLightPushClient
|
|
|
|
serverRemotePeerInfo {.threadvar.}: RemotePeerInfo
|
|
clientPeerId {.threadvar.}: PeerId
|
|
pubsubTopic {.threadvar.}: PubsubTopic
|
|
contentTopic {.threadvar.}: ContentTopic
|
|
message {.threadvar.}: WakuMessage
|
|
|
|
asyncSetup:
|
|
handlerFuture = newPushHandlerFuture()
|
|
handler = proc(
|
|
peer: PeerId, pubsubTopic: PubsubTopic, message: WakuMessage
|
|
): Future[WakuLightPushResult] {.async.} =
|
|
let msgLen = message.encode().buffer.len
|
|
if msgLen > int(DefaultMaxWakuMessageSize) + 64 * 1024:
|
|
return lighpushErrorResult(
|
|
LightPushErrorCode.PAYLOAD_TOO_LARGE, "length greater than maxMessageSize"
|
|
)
|
|
handlerFuture.complete((pubsubTopic, message))
|
|
# return that we published the message to 1 peer.
|
|
return ok(1)
|
|
|
|
serverSwitch = newTestSwitch()
|
|
clientSwitch = newTestSwitch()
|
|
server = await newTestWakuLightpushNode(serverSwitch, handler)
|
|
client = newTestWakuLightpushClient(clientSwitch)
|
|
|
|
await allFutures(serverSwitch.start(), clientSwitch.start())
|
|
|
|
serverRemotePeerInfo = serverSwitch.peerInfo.toRemotePeerInfo()
|
|
clientPeerId = clientSwitch.peerInfo.peerId
|
|
pubsubTopic = DefaultPubsubTopic
|
|
contentTopic = DefaultContentTopic
|
|
message = fakeWakuMessage()
|
|
|
|
asyncTeardown:
|
|
await allFutures(clientSwitch.stop(), serverSwitch.stop())
|
|
|
|
suite "Verification of PushRequest Payload":
|
|
asyncTest "Valid Payload Types":
|
|
# Given the following payloads
|
|
let
|
|
message2 = fakeWakuMessage(payloads.ALPHABETIC, content_topics.CURRENT)
|
|
message3 = fakeWakuMessage(payloads.ALPHANUMERIC, content_topics.TESTNET)
|
|
message4 = fakeWakuMessage(payloads.ALPHANUMERIC_SPECIAL, content_topics.PLAIN)
|
|
message5 = fakeWakuMessage(payloads.EMOJI, content_topics.CURRENT)
|
|
message6 = fakeWakuMessage(payloads.CODE, content_topics.TESTNET)
|
|
message7 = fakeWakuMessage(payloads.QUERY, content_topics.PLAIN)
|
|
message8 = fakeWakuMessage(payloads.TEXT_SMALL, content_topics.CURRENT)
|
|
message9 = fakeWakuMessage(payloads.TEXT_LARGE, content_topics.TESTNET)
|
|
|
|
# When publishing a valid payload
|
|
let publishResponse =
|
|
await client.publish(some(pubsubTopic), message, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsubTopic, message) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse2 = await client.publish(
|
|
some(pubsub_topics.CURRENT), message2, serverRemotePeerInfo
|
|
)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse2
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.CURRENT, message2) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse3 = await client.publish(
|
|
some(pubsub_topics.CURRENT_NESTED), message3, serverRemotePeerInfo
|
|
)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse3
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.CURRENT_NESTED, message3) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse4 = await client.publish(
|
|
some(pubsub_topics.SHARDING), message4, serverRemotePeerInfo
|
|
)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse4
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.SHARDING, message4) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse5 =
|
|
await client.publish(some(pubsub_topics.PLAIN), message5, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse5
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.PLAIN, message5) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse6 =
|
|
await client.publish(some(pubsub_topics.LEGACY), message6, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse6
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.LEGACY, message6) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse7 = await client.publish(
|
|
some(pubsub_topics.LEGACY_NESTED), message7, serverRemotePeerInfo
|
|
)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse7
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.LEGACY_NESTED, message7) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse8 = await client.publish(
|
|
some(pubsub_topics.LEGACY_ENCODING), message8, serverRemotePeerInfo
|
|
)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse8
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsub_topics.LEGACY_ENCODING, message8) == handlerFuture.read()
|
|
|
|
# When publishing a valid payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse9 =
|
|
await client.publish(some(pubsubTopic), message9, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse9
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
check (pubsubTopic, message9) == handlerFuture.read()
|
|
|
|
asyncTest "Valid Payload Sizes":
|
|
# Given some valid payloads
|
|
let
|
|
overheadBytes: uint64 = 112
|
|
message1 =
|
|
fakeWakuMessage(contentTopic = contentTopic, payload = getByteSequence(1024))
|
|
# 1KiB
|
|
message2 = fakeWakuMessage(
|
|
contentTopic = contentTopic, payload = getByteSequence(10 * 1024)
|
|
) # 10KiB
|
|
message3 = fakeWakuMessage(
|
|
contentTopic = contentTopic, payload = getByteSequence(100 * 1024)
|
|
) # 100KiB
|
|
message4 = fakeWakuMessage(
|
|
contentTopic = contentTopic,
|
|
payload = getByteSequence(DefaultMaxWakuMessageSize - overheadBytes - 1),
|
|
) # Inclusive Limit
|
|
message5 = fakeWakuMessage(
|
|
contentTopic = contentTopic,
|
|
payload = getByteSequence(DefaultMaxWakuMessageSize + 64 * 1024),
|
|
) # Exclusive Limit
|
|
|
|
# When publishing the 1KiB payload
|
|
let publishResponse1 =
|
|
await client.publish(some(pubsubTopic), message1, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
assertResultOk publishResponse1
|
|
check (pubsubTopic, message1) == (await handlerFuture.waitForResult()).value()
|
|
|
|
# When publishing the 10KiB payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse2 =
|
|
await client.publish(some(pubsubTopic), message2, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
assertResultOk publishResponse2
|
|
check (pubsubTopic, message2) == (await handlerFuture.waitForResult()).value()
|
|
|
|
# When publishing the 100KiB payload
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse3 =
|
|
await client.publish(some(pubsubTopic), message3, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
assertResultOk publishResponse3
|
|
check (pubsubTopic, message3) == (await handlerFuture.waitForResult()).value()
|
|
|
|
# When publishing the 1MiB + 63KiB + 911B payload (1113999B)
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse4 =
|
|
await client.publish(some(pubsubTopic), message4, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
assertResultOk publishResponse4
|
|
check (pubsubTopic, message4) == (await handlerFuture.waitForResult()).value()
|
|
|
|
# When publishing the 1MiB + 63KiB + 912B payload (1114000B)
|
|
handlerFuture = newPushHandlerFuture()
|
|
let publishResponse5 =
|
|
await client.publish(some(pubsubTopic), message5, serverRemotePeerInfo)
|
|
|
|
# Then the message is not received by the server
|
|
check:
|
|
publishResponse5.isErr()
|
|
publishResponse5.error.code == LightPushErrorCode.PAYLOAD_TOO_LARGE
|
|
(await handlerFuture.waitForResult()).isErr()
|
|
|
|
asyncTest "Invalid Encoding Payload":
|
|
# Given a payload with an invalid encoding
|
|
let fakeBuffer = @[byte(42)]
|
|
|
|
# When publishing the payload
|
|
let publishResponse = await server.handleRequest(clientPeerId, fakeBuffer)
|
|
|
|
# And the error is returned
|
|
check:
|
|
publishResponse.requestId == "N/A"
|
|
publishResponse.statusCode == LightPushErrorCode.BAD_REQUEST
|
|
publishResponse.statusDesc.isSome()
|
|
scanf(publishResponse.statusDesc.get(), decodeRpcFailure)
|
|
|
|
asyncTest "Handle Error":
|
|
# Given a lightpush server that fails
|
|
let
|
|
handlerError = "handler-error"
|
|
handlerFuture2 = newFuture[void]()
|
|
handler2 = proc(
|
|
peer: PeerId, pubsubTopic: PubsubTopic, message: WakuMessage
|
|
): Future[WakuLightPushResult] {.async.} =
|
|
handlerFuture2.complete()
|
|
return lighpushErrorResult(LightPushErrorCode.PAYLOAD_TOO_LARGE, handlerError)
|
|
|
|
let
|
|
serverSwitch2 = newTestSwitch()
|
|
server2 = await newTestWakuLightpushNode(serverSwitch2, handler2)
|
|
|
|
await serverSwitch2.start()
|
|
|
|
let serverRemotePeerInfo2 = serverSwitch2.peerInfo.toRemotePeerInfo()
|
|
|
|
# When publishing a payload
|
|
let publishResponse =
|
|
await client.publish(some(pubsubTopic), message, serverRemotePeerInfo2)
|
|
|
|
# Then the response is negative
|
|
check:
|
|
publishResponse.error.code == LightPushErrorCode.PAYLOAD_TOO_LARGE
|
|
publishResponse.error.desc == some(handlerError)
|
|
(await handlerFuture2.waitForResult()).isOk()
|
|
|
|
# Cleanup
|
|
await serverSwitch2.stop()
|
|
|
|
asyncTest "Check timestamp is not zero":
|
|
## This test validates that, even the generated message has a timestamp of 0,
|
|
## the node will eventually set a timestamp when publishing the message.
|
|
let
|
|
zeroTimestamp = 0
|
|
meta = "TEST-META"
|
|
message = fakeWakuMessage(
|
|
payloads.ALPHABETIC, content_topics.CURRENT, meta, zeroTimestamp
|
|
)
|
|
|
|
# When publishing a valid payload
|
|
let publishResponse =
|
|
await client.publish(some(pubsubTopic), message, serverRemotePeerInfo)
|
|
|
|
# Then the message is received by the server
|
|
discard await handlerFuture.withTimeout(FUTURE_TIMEOUT)
|
|
assertResultOk publishResponse
|
|
check handlerFuture.finished()
|
|
|
|
# And the message is received with the correct topic and payload
|
|
let (readPubsubTopic, readMessage) = handlerFuture.read()
|
|
|
|
check:
|
|
pubsubTopic == readPubsubTopic
|
|
message.payload == readMessage.payload
|
|
message.contentTopic == readMessage.contentTopic
|
|
message.meta == readMessage.meta
|
|
message.timestamp != readMessage.timestamp
|
|
message.ephemeral == readMessage.ephemeral
|
|
message.proof == readMessage.proof
|
|
message.version == readMessage.version
|
|
readMessage.timestamp > 0
|
|
|
|
suite "Verification of PushResponse Payload":
|
|
asyncTest "Positive Responses":
|
|
# When sending a valid PushRequest
|
|
let publishResponse =
|
|
await client.publish(some(pubsubTopic), message, serverRemotePeerInfo)
|
|
|
|
# Then the response is positive
|
|
assertResultOk publishResponse
|
|
|
|
# TODO: Improve: Add more negative responses variations
|
|
asyncTest "Negative Responses":
|
|
# Given a server that does not support Waku Lightpush
|
|
let
|
|
serverSwitch2 = newTestSwitch()
|
|
serverRemotePeerInfo2 = serverSwitch2.peerInfo.toRemotePeerInfo()
|
|
|
|
await serverSwitch2.start()
|
|
|
|
# When sending an invalid PushRequest
|
|
let publishResponse =
|
|
await client.publish(some(pubsubTopic), message, serverRemotePeerInfo2)
|
|
|
|
# Then the response is negative
|
|
check not publishResponse.isOk()
|
|
check publishResponse.error.code == LightPushErrorCode.NO_PEERS_TO_RELAY
|