mirror of https://github.com/waku-org/nwaku.git
310 lines
8.0 KiB
Nim
310 lines
8.0 KiB
Nim
{.used.}
|
|
|
|
import
|
|
std/[sequtils, strutils, algorithm],
|
|
stew/results,
|
|
testutils/unittests
|
|
import
|
|
../../waku/v2/node/storage/message/waku_store_queue,
|
|
../../waku/v2/protocol/waku_message,
|
|
../../waku/v2/protocol/waku_store,
|
|
../../waku/v2/utils/time
|
|
|
|
|
|
# Helper functions
|
|
|
|
proc genIndexedWakuMessage(i: int8): IndexedWakuMessage =
|
|
## Use i to generate an IndexedWakuMessage
|
|
var data {.noinit.}: array[32, byte]
|
|
for x in data.mitems: x = i.byte
|
|
|
|
let
|
|
message = WakuMessage(payload: @[byte i], timestamp: Timestamp(i))
|
|
cursor = Index(
|
|
receiverTime: Timestamp(i),
|
|
senderTime: Timestamp(i),
|
|
digest: MessageDigest(data: data),
|
|
pubsubTopic: "test-pubsub-topic"
|
|
)
|
|
|
|
IndexedWakuMessage(msg: message, index: cursor)
|
|
|
|
proc getPrepopulatedTestStore(unsortedSet: auto, capacity: int): StoreQueueRef =
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
for i in unsortedSet:
|
|
let message = genIndexedWakuMessage(i.int8)
|
|
discard store.add(message)
|
|
|
|
store
|
|
|
|
|
|
procSuite "Sorted store queue":
|
|
|
|
test "Store capacity - add a message over the limit":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
## When
|
|
# Fill up the queue
|
|
for i in 1..capacity:
|
|
let message = genIndexedWakuMessage(i.int8)
|
|
require(store.add(message).isOk())
|
|
|
|
# Add one more. Capacity should not be exceeded
|
|
let message = genIndexedWakuMessage(capacity.int8 + 1)
|
|
require(store.add(message).isOk())
|
|
|
|
## Then
|
|
check:
|
|
store.len == capacity
|
|
|
|
test "Store capacity - add message older than oldest in the queue":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
## When
|
|
# Fill up the queue
|
|
for i in 1..capacity:
|
|
let message = genIndexedWakuMessage(i.int8)
|
|
require(store.add(message).isOk())
|
|
|
|
# Attempt to add message with older value than oldest in queue should fail
|
|
let
|
|
oldestTimestamp = store.first().get().index.senderTime
|
|
message = genIndexedWakuMessage(oldestTimestamp.int8 - 1)
|
|
addRes = store.add(message)
|
|
|
|
## Then
|
|
check:
|
|
addRes.isErr()
|
|
addRes.error() == "too_old"
|
|
|
|
check:
|
|
store.len == capacity
|
|
|
|
test "Store queue sort-on-insert works":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
# Walk forward through the set and verify ascending order
|
|
var prevSmaller = genIndexedWakuMessage(min(unsortedSet).int8 - 1).index
|
|
for i in store.fwdIterator:
|
|
let (index, indexedWakuMessage) = i
|
|
check cmp(index, prevSmaller) > 0
|
|
prevSmaller = index
|
|
|
|
# Walk backward through the set and verify descending order
|
|
var prevLarger = genIndexedWakuMessage(max(unsortedSet).int8 + 1).index
|
|
for i in store.bwdIterator:
|
|
let (index, indexedWakuMessage) = i
|
|
check cmp(index, prevLarger) < 0
|
|
prevLarger = index
|
|
|
|
test "access first item from store queue":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
## When
|
|
let firstRes = store.first()
|
|
|
|
## Then
|
|
check:
|
|
firstRes.isOk()
|
|
|
|
let first = firstRes.tryGet()
|
|
check:
|
|
first.msg.timestamp == Timestamp(1)
|
|
|
|
test "get first item from empty store should fail":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
## When
|
|
let firstRes = store.first()
|
|
|
|
## Then
|
|
check:
|
|
firstRes.isErr()
|
|
firstRes.error() == "Not found"
|
|
|
|
test "access last item from store queue":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
## When
|
|
let lastRes = store.last()
|
|
|
|
## Then
|
|
check:
|
|
lastRes.isOk()
|
|
|
|
let last = lastRes.tryGet()
|
|
check:
|
|
last.msg.timestamp == Timestamp(5)
|
|
|
|
test "get last item from empty store should fail":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
## When
|
|
let lastRes = store.last()
|
|
|
|
## Then
|
|
check:
|
|
lastRes.isErr()
|
|
lastRes.error() == "Not found"
|
|
|
|
test "Store queue pagination works with predicate - fwd direction":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
proc onlyEvenTimes(i: IndexedWakuMessage): bool = i.msg.timestamp.int64 mod 2 == 0
|
|
|
|
## When
|
|
let pageRes1 = store.getPage(onlyEvenTimes, PagingInfo(pageSize: 2, direction: PagingDirection.FORWARD))
|
|
|
|
## Then
|
|
# First page
|
|
check pageRes1.isOk()
|
|
|
|
var res = pageRes1.get().mapIt(it[1])
|
|
check:
|
|
res.mapIt(it.timestamp.int) == @[2,4]
|
|
|
|
|
|
test "Store queue pagination works with predicate - bwd direction":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
proc onlyOddTimes(i: IndexedWakuMessage): bool = i.msg.timestamp.int64 mod 2 != 0
|
|
|
|
## When
|
|
let pageRes1 = store.getPage(onlyOddTimes, PagingInfo(pageSize: 2, direction: PagingDirection.BACKWARD))
|
|
|
|
## Then
|
|
# First page
|
|
check pageRes1.isOk()
|
|
|
|
var res = pageRes1.get().mapIt(it[1])
|
|
check:
|
|
res.mapIt(it.timestamp.int) == @[3,5].reversed
|
|
|
|
test "handle pagination on empty store - fwd direction":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
proc predicate(i: IndexedWakuMessage): bool = true # no filtering
|
|
|
|
let pagingInfo = PagingInfo(pageSize: 3, direction: PagingDirection.FORWARD)
|
|
|
|
## When
|
|
# Get page from empty queue in fwd dir
|
|
let pageRes = store.getPage(predicate, pagingInfo)
|
|
|
|
## Then
|
|
# Empty response
|
|
check pageRes.isOk()
|
|
|
|
var res = pageRes.get()
|
|
check:
|
|
res.len == 0
|
|
|
|
test "handle pagination on empty store - bwd direction":
|
|
## Given
|
|
let capacity = 5
|
|
let store = StoreQueueRef.new(capacity)
|
|
|
|
proc predicate(i: IndexedWakuMessage): bool = true # no filtering
|
|
|
|
let pagingInfo = PagingInfo(pageSize: 3, direction: PagingDirection.BACKWARD)
|
|
|
|
## When
|
|
# Get page from empty queue in bwd dir
|
|
let pageRes = store.getPage(predicate, pagingInfo)
|
|
|
|
## Then
|
|
# Empty response
|
|
check pageRes.isOk()
|
|
|
|
let res = pageRes.get()
|
|
check:
|
|
res.len == 0
|
|
|
|
test "handle invalid cursor - fwd direction":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
proc predicate(i: IndexedWakuMessage): bool = true # no filtering
|
|
|
|
let cursor = PagingIndex(receiverTime: Timestamp(3), senderTime: Timestamp(3), digest: MessageDigest())
|
|
let pagingInfo = PagingInfo(pageSize: 3, cursor: cursor, direction: PagingDirection.FORWARD)
|
|
|
|
## When
|
|
let pageRes = store.getPage(predicate, pagingInfo)
|
|
|
|
## Then
|
|
check:
|
|
pageRes.isErr()
|
|
pageRes.error == HistoryResponseError.INVALID_CURSOR
|
|
|
|
test "handle invalid cursor - bwd direction":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
proc predicate(i: IndexedWakuMessage): bool = true # no filtering
|
|
|
|
let cursor = PagingIndex(receiverTime: Timestamp(3), senderTime: Timestamp(3), digest: MessageDigest())
|
|
let pagingInfo = PagingInfo(pageSize: 3, cursor: cursor, direction: PagingDirection.BACKWARD)
|
|
|
|
## When
|
|
let pageRes = store.getPage(predicate, pagingInfo)
|
|
|
|
## Then
|
|
# Empty response with error
|
|
check:
|
|
pageRes.isErr()
|
|
pageRes.error == HistoryResponseError.INVALID_CURSOR
|
|
|
|
test "verify if store queue contains an index":
|
|
## Given
|
|
let
|
|
capacity = 5
|
|
unsortedSet = [5,1,3,2,4]
|
|
let store = getPrepopulatedTestStore(unsortedSet, capacity)
|
|
|
|
let
|
|
existingIndex = genIndexedWakuMessage(4).index
|
|
nonExistingIndex = genIndexedWakuMessage(99).index
|
|
|
|
## Then
|
|
check:
|
|
store.contains(existingIndex) == true
|
|
store.contains(nonExistingIndex) == false
|