2023-08-01 13:05:16 +00:00
|
|
|
{.used.}
|
|
|
|
|
|
|
|
import
|
|
|
|
std/options,
|
|
|
|
std/strutils,
|
|
|
|
std/sugar,
|
|
|
|
std/random,
|
|
|
|
stew/results,
|
|
|
|
testutils/unittests
|
|
|
|
import
|
2023-08-09 17:11:50 +00:00
|
|
|
../../../waku/waku_core/topics
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
suite "Waku Sharding":
|
|
|
|
|
|
|
|
randomize()
|
|
|
|
|
|
|
|
const WordLength = 5
|
|
|
|
|
|
|
|
proc randomContentTopic(): NsContentTopic =
|
|
|
|
var app = ""
|
|
|
|
|
|
|
|
for n in 0..<WordLength:
|
|
|
|
let letter = sample(Letters)
|
|
|
|
app.add(letter)
|
|
|
|
|
|
|
|
let version = "1"
|
|
|
|
|
|
|
|
var name = ""
|
|
|
|
|
|
|
|
for n in 0..<WordLength:
|
|
|
|
let letter = sample(Letters)
|
|
|
|
name.add(letter)
|
|
|
|
|
|
|
|
let enc = "cbor"
|
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
NsContentTopic.init(none(int), app, version, name, enc)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
test "Implicit content topic generation":
|
|
|
|
## Given
|
|
|
|
let topic = "/toychat/2/huilong/proto"
|
|
|
|
|
|
|
|
## When
|
2023-08-17 12:11:18 +00:00
|
|
|
let parseRes = NsContentTopic.parse(topic)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## Then
|
2023-08-17 12:11:18 +00:00
|
|
|
assert parseRes.isOk(), $parseRes.error
|
2023-08-01 13:05:16 +00:00
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
let nsTopic = parseRes.get()
|
2023-08-01 13:05:16 +00:00
|
|
|
check:
|
2023-08-17 12:11:18 +00:00
|
|
|
nsTopic.generation == none(int)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
test "Valid content topic":
|
|
|
|
## Given
|
2023-08-17 12:11:18 +00:00
|
|
|
let topic = "/0/toychat/2/huilong/proto"
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## When
|
2023-08-17 12:11:18 +00:00
|
|
|
let parseRes = NsContentTopic.parse(topic)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## Then
|
2023-08-17 12:11:18 +00:00
|
|
|
assert parseRes.isOk(), $parseRes.error
|
2023-08-01 13:05:16 +00:00
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
let nsTopic = parseRes.get()
|
2023-08-01 13:05:16 +00:00
|
|
|
check:
|
2023-08-17 12:11:18 +00:00
|
|
|
nsTopic.generation.get() == 0
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
test "Invalid content topic generation":
|
|
|
|
## Given
|
2023-08-17 12:11:18 +00:00
|
|
|
let topic = "/1/toychat/2/huilong/proto"
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## When
|
|
|
|
let ns = NsContentTopic.parse(topic).expect("Parsing")
|
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
let shardRes = getShard(ns)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## Then
|
2023-08-17 12:11:18 +00:00
|
|
|
assert shardRes.isErr(), $shardRes.get()
|
2023-08-01 13:05:16 +00:00
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
let err = shardRes.error
|
2023-08-01 13:05:16 +00:00
|
|
|
check:
|
|
|
|
err == "Generation > 0 are not supported yet"
|
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
#[ test "Sorted shard list":
|
2023-08-01 13:05:16 +00:00
|
|
|
## Given
|
2023-08-17 12:11:18 +00:00
|
|
|
let topic = "/0/toychat/2/huilong/proto"
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## When
|
|
|
|
let contentTopic = NsContentTopic.parse(topic).expect("Parsing")
|
|
|
|
let count = shardCount(contentTopic).expect("Valid parameters")
|
2023-08-17 12:11:18 +00:00
|
|
|
let weights = repeat(1.0, count)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
let shardsRes = weightedShardList(contentTopic, count, weights)
|
|
|
|
|
|
|
|
## Then
|
|
|
|
assert shardsRes.isOk(), shardsRes.error
|
|
|
|
|
|
|
|
let shards = shardsRes.get()
|
|
|
|
check:
|
|
|
|
shards.len == count
|
2023-08-17 12:11:18 +00:00
|
|
|
isSorted(shards, hashOrder) ]#
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
test "Shard Choice Reproducibility":
|
|
|
|
## Given
|
|
|
|
let topic = "/toychat/2/huilong/proto"
|
|
|
|
|
|
|
|
## When
|
|
|
|
let contentTopic = NsContentTopic.parse(topic).expect("Parsing")
|
|
|
|
|
2023-08-17 12:11:18 +00:00
|
|
|
let pubsub = getGenZeroShard(contentTopic, GenerationZeroShardsCount)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
## Then
|
|
|
|
check:
|
2023-08-17 12:11:18 +00:00
|
|
|
pubsub == NsPubsubTopic.staticSharding(ClusterIndex, 3)
|
2023-08-01 13:05:16 +00:00
|
|
|
|
|
|
|
test "Shard Choice Simulation":
|
|
|
|
## Given
|
|
|
|
let topics = collect:
|
|
|
|
for i in 0..<100000:
|
|
|
|
randomContentTopic()
|
|
|
|
|
|
|
|
var counts = newSeq[0](GenerationZeroShardsCount)
|
|
|
|
|
|
|
|
## When
|
|
|
|
for topic in topics:
|
2023-08-17 12:11:18 +00:00
|
|
|
let pubsub = getShard(topic).expect("Valid Topic")
|
2023-08-01 13:05:16 +00:00
|
|
|
counts[pubsub.shard] += 1
|
|
|
|
|
|
|
|
## Then
|
|
|
|
for i in 1..<GenerationZeroShardsCount:
|
|
|
|
check:
|
|
|
|
float64(counts[i - 1]) <= (float64(counts[i]) * 1.05)
|
|
|
|
float64(counts[i]) <= (float64(counts[i - 1]) * 1.05)
|
|
|
|
float64(counts[i - 1]) >= (float64(counts[i]) * 0.95)
|
|
|
|
float64(counts[i]) >= (float64(counts[i - 1]) * 0.95)
|
|
|
|
|
|
|
|
#echo counts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|