nim-codex/tests/codex/stores/testmemorystore.nim
2023-06-15 08:19:07 +02:00

253 lines
6.8 KiB
Nim

import std/os
import std/strutils
import std/sequtils
import pkg/questionable
import pkg/questionable/results
import pkg/chronos
import pkg/asynctest
import pkg/libp2p
import pkg/stew/byteutils
import pkg/stew/endians2
import pkg/datastore
import pkg/codex/stores/cachestore
import pkg/codex/chunker
import pkg/codex/stores
import pkg/codex/blocktype as bt
import pkg/codex/clock
import ../helpers
import ../helpers/mockclock
import ./commonstoretests
proc createTestBlock(size: int): bt.Block =
bt.Block.new('a'.repeat(size).toBytes).tryGet()
suite "MemoryStore":
var
initialBlock: bt.Block
repo: MemoryStore
let
capacity = 100
chunkSize = 10
setup:
initialBlock = createTestBlock(chunkSize)
repo = MemoryStore.new([initialBlock], capacity, chunkSize)
# teardown:
# discard
# test "Should update current used bytes on block put":
# let blk = createTestBlock(200)
# check repo.quotaUsedBytes == 0
# (await repo.putBlock(blk)).tryGet
# check:
# repo.quotaUsedBytes == 200
# uint64.fromBytesBE((await metaDs.get(QuotaUsedKey)).tryGet) == 200'u
# test "Should update current used bytes on block delete":
# let blk = createTestBlock(100)
# check repo.quotaUsedBytes == 0
# (await repo.putBlock(blk)).tryGet
# check repo.quotaUsedBytes == 100
# (await repo.delBlock(blk.cid)).tryGet
# check:
# repo.quotaUsedBytes == 0
# uint64.fromBytesBE((await metaDs.get(QuotaUsedKey)).tryGet) == 0'u
# test "Should not update current used bytes if block exist":
# let blk = createTestBlock(100)
# check repo.quotaUsedBytes == 0
# (await repo.putBlock(blk)).tryGet
# check repo.quotaUsedBytes == 100
# # put again
# (await repo.putBlock(blk)).tryGet
# check repo.quotaUsedBytes == 100
# check:
# uint64.fromBytesBE((await metaDs.get(QuotaUsedKey)).tryGet) == 100'u
# test "Should fail storing passed the quota":
# let blk = createTestBlock(300)
# check repo.totalUsed == 0
# expect QuotaUsedError:
# (await repo.putBlock(blk)).tryGet
# test "Should reserve bytes":
# let blk = createTestBlock(100)
# check repo.totalUsed == 0
# (await repo.putBlock(blk)).tryGet
# check repo.totalUsed == 100
# (await repo.reserve(100)).tryGet
# check:
# repo.totalUsed == 200
# repo.quotaUsedBytes == 100
# repo.quotaReservedBytes == 100
# uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 100'u
# test "Should not reserve bytes over max quota":
# let blk = createTestBlock(100)
# check repo.totalUsed == 0
# (await repo.putBlock(blk)).tryGet
# check repo.totalUsed == 100
# expect QuotaNotEnoughError:
# (await repo.reserve(101)).tryGet
# check:
# repo.totalUsed == 100
# repo.quotaUsedBytes == 100
# repo.quotaReservedBytes == 0
# expect DatastoreKeyNotFound:
# discard (await metaDs.get(QuotaReservedKey)).tryGet
# test "Should release bytes":
# discard createTestBlock(100)
# check repo.totalUsed == 0
# (await repo.reserve(100)).tryGet
# check repo.totalUsed == 100
# (await repo.release(100)).tryGet
# check:
# repo.totalUsed == 0
# repo.quotaUsedBytes == 0
# repo.quotaReservedBytes == 0
# uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 0'u
# test "Should not release bytes less than quota":
# check repo.totalUsed == 0
# (await repo.reserve(100)).tryGet
# check repo.totalUsed == 100
# expect CatchableError:
# (await repo.release(101)).tryGet
# check:
# repo.totalUsed == 100
# repo.quotaUsedBytes == 0
# repo.quotaReservedBytes == 100
# uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 100'u
# proc queryMetaDs(key: Key): Future[seq[QueryResponse]] {.async.} =
# let
# query = Query.init(key)
# responseIter = (await metaDs.query(query)).tryGet
# response = (await allFinished(toSeq(responseIter)))
# .mapIt(it.read.tryGet)
# .filterIt(it.key.isSome)
# return response
# test "Should store block expiration timestamp":
# let
# duration = 10.seconds
# blk = createTestBlock(100)
# let
# expectedExpiration: SecondsSince1970 = 123 + 10
# expectedKey = Key.init("meta/ttl/" & $blk.cid).tryGet
# (await repo.putBlock(blk, duration.some)).tryGet
# let response = await queryMetaDs(expectedKey)
# check:
# response.len == 1
# !response[0].key == expectedKey
# response[0].data == expectedExpiration.toBytes
# test "Should store block with default expiration timestamp when not provided":
# let
# blk = createTestBlock(100)
# let
# expectedExpiration: SecondsSince1970 = 123 + DefaultBlockTtl.seconds
# expectedKey = Key.init("meta/ttl/" & $blk.cid).tryGet
# (await repo.putBlock(blk)).tryGet
# let response = await queryMetaDs(expectedKey)
# check:
# response.len == 1
# !response[0].key == expectedKey
# response[0].data == expectedExpiration.toBytes
# test "delBlock should remove expiration metadata":
# let
# blk = createTestBlock(100)
# expectedKey = Key.init("meta/ttl/" & $blk.cid).tryGet
# (await repo.putBlock(blk, 10.seconds.some)).tryGet
# (await repo.delBlock(blk.cid)).tryGet
# let response = await queryMetaDs(expectedKey)
# check:
# response.len == 0
# test "Should retrieve block expiration information":
# proc unpack(beIter: Future[?!BlockExpirationIter]): Future[seq[BlockExpiration]] {.async.} =
# var expirations = newSeq[BlockExpiration](0)
# without iter =? (await beIter), err:
# return expirations
# for be in toSeq(iter):
# if value =? (await be):
# expirations.add(value)
# return expirations
# let
# duration = 10.seconds
# blk1 = createTestBlock(10)
# blk2 = createTestBlock(11)
# blk3 = createTestBlock(12)
# let
# expectedExpiration: SecondsSince1970 = 123 + 10
# proc assertExpiration(be: BlockExpiration, expectedBlock: bt.Block) =
# check:
# be.cid == expectedBlock.cid
# be.expiration == expectedExpiration
# (await repo.putBlock(blk1, duration.some)).tryGet
# (await repo.putBlock(blk2, duration.some)).tryGet
# (await repo.putBlock(blk3, duration.some)).tryGet
# let
# blockExpirations1 = await unpack(repo.getBlockExpirations(maxNumber=2, offset=0))
# blockExpirations2 = await unpack(repo.getBlockExpirations(maxNumber=2, offset=2))
# check blockExpirations1.len == 2
# assertExpiration(blockExpirations1[0], blk2)
# assertExpiration(blockExpirations1[1], blk1)
# check blockExpirations2.len == 1
# assertExpiration(blockExpirations2[0], blk3)
commonBlockStoreTests(
"MemoryStore", proc: BlockStore =
MemoryStore.new([])
)