From 3bbe234962c34214f96e01324fceae5b7836d8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lex=20Cabeza=20Romero?= Date: Thu, 4 Jan 2024 16:26:27 +0100 Subject: [PATCH] test(autosharding): Functional Tests (#2318) * Implement autosharding tests. --- tests/testlib/tables.nim | 28 +++++ tests/waku_core/test_sharding.nim | 145 --------------------- tests/waku_core/topics/test_sharding.nim | 153 +++++++++++++++++++++++ waku/waku_core/topics/sharding.nim | 2 +- 4 files changed, 182 insertions(+), 146 deletions(-) create mode 100644 tests/testlib/tables.nim delete mode 100644 tests/waku_core/test_sharding.nim create mode 100644 tests/waku_core/topics/test_sharding.nim diff --git a/tests/testlib/tables.nim b/tests/testlib/tables.nim new file mode 100644 index 000000000..188798228 --- /dev/null +++ b/tests/testlib/tables.nim @@ -0,0 +1,28 @@ +import + std/[ + tables, + sequtils, + options + ] + +import + ../../../waku/waku_core/topics, + ../testlib/wakucore + + + + + +proc `==`*(table: Table[pubsub_topic.NsPubsubTopic, seq[NsContentTopic]], other: array[0..0, (string, seq[string])]): bool = + let otherTyped = other.map( + proc(item: (string, seq[string])): (NsPubsubTopic, seq[NsContentTopic]) = + let + (pubsubTopic, contentTopics) = item + nsPubsubTopic = NsPubsubTopic.parse(pubsubTopic).value() + nsContentTopics = contentTopics.map( + proc(contentTopic: string): NsContentTopic = NsContentTopic.parse(contentTopic).value() + ) + return (nsPubsubTopic, nsContentTopics) + ) + + table == otherTyped.toTable() diff --git a/tests/waku_core/test_sharding.nim b/tests/waku_core/test_sharding.nim deleted file mode 100644 index ea385f5db..000000000 --- a/tests/waku_core/test_sharding.nim +++ /dev/null @@ -1,145 +0,0 @@ -{.used.} - -import - std/options, - std/strutils, - std/sugar, - std/random, - stew/results, - testutils/unittests -import - ../../../waku/waku_core/topics - -suite "Waku Sharding": - - randomize() - - const WordLength = 5 - - proc randomContentTopic(): NsContentTopic = - var app = "" - - for n in 0.. 0 are not supported yet" - - #[ test "Sorted shard list": - ## Given - let topic = "/0/toychat/2/huilong/proto" - - ## When - let contentTopic = NsContentTopic.parse(topic).expect("Parsing") - let count = shardCount(contentTopic).expect("Valid parameters") - let weights = repeat(1.0, count) - - let shardsRes = weightedShardList(contentTopic, count, weights) - - ## Then - assert shardsRes.isOk(), shardsRes.error - - let shards = shardsRes.get() - check: - shards.len == count - isSorted(shards, hashOrder) ]# - - test "Shard Choice Reproducibility": - ## Given - let topic = "/toychat/2/huilong/proto" - - ## When - let contentTopic = NsContentTopic.parse(topic).expect("Parsing") - - let pubsub = getGenZeroShard(contentTopic, GenerationZeroShardsCount) - - ## Then - check: - pubsub == NsPubsubTopic.staticSharding(ClusterId, 3) - - test "Shard Choice Simulation": - ## Given - let topics = collect: - for i in 0..<100000: - randomContentTopic() - - var counts = newSeq[0](GenerationZeroShardsCount) - - ## When - for topic in topics: - let pubsub = getShard(topic).expect("Valid Topic") - counts[pubsub.shard] += 1 - - ## Then - for i in 1..= (float64(counts[i]) * 0.95) - float64(counts[i]) >= (float64(counts[i - 1]) * 0.95) - - #echo counts - - - - - - - - - - diff --git a/tests/waku_core/topics/test_sharding.nim b/tests/waku_core/topics/test_sharding.nim new file mode 100644 index 000000000..102bb8219 --- /dev/null +++ b/tests/waku_core/topics/test_sharding.nim @@ -0,0 +1,153 @@ +import + std/[ + options, + tables + ], + testutils/unittests + + +import + ../../../../waku/waku_core/topics, + ../../testlib/[ + wakucore, + tables, + testutils + ] + + +suite "Autosharding": + const + pubsubTopic04 = "/waku/2/rs/0/4" + pubsubTopic13 = "/waku/2/rs/1/3" + contentTopicShort = "/toychat/2/huilong/proto" + contentTopicFull = "/0/toychat/2/huilong/proto" + contentTopicInvalid = "/1/toychat/2/huilong/proto" + + + suite "getGenZeroShard": + test "Generate Gen0 Shard": + # Given two valid topics + let + nsContentTopic1 = NsContentTopic.parse(contentTopicShort).value() + nsContentTopic2 = NsContentTopic.parse(contentTopicFull).value() + + # When we generate a gen0 shard from them + let + nsPubsubTopic1 = getGenZeroShard(nsContentTopic1, GenerationZeroShardsCount) + nsPubsubTopic2 = getGenZeroShard(nsContentTopic2, GenerationZeroShardsCount) + + # Then the generated shards are valid + check: + nsPubsubTopic1 == NsPubsubTopic.staticSharding(ClusterId, 3) + nsPubsubTopic2 == NsPubsubTopic.staticSharding(ClusterId, 3) + + suite "getShard from NsContentTopic": + test "Generate Gen0 Shard with topic.generation==none": + # When we get a shard from a topic without generation + let nsPubsubTopic = getShard(contentTopicShort) + + # Then the generated shard is valid + check: + nsPubsubTopic.value() == NsPubsubTopic.staticSharding(ClusterId, 3) + + test "Generate Gen0 Shard with topic.generation==0": + # When we get a shard from a gen0 topic + let nsPubsubTopic = getShard(contentTopicFull) + + # Then the generated shard is valid + check: + nsPubsubTopic.value() == NsPubsubTopic.staticSharding(ClusterId, 3) + + test "Generate Gen0 Shard with topic.generation==other": + # When we get a shard from ain invalid content topic + let nsPubsubTopic = getShard(contentTopicInvalid) + + # Then the generated shard is valid + check: + nsPubsubTopic.error() == "Generation > 0 are not supported yet" + + suite "getShard from ContentTopic": + test "Generate Gen0 Shard with topic.generation==none": + # When we get a shard from it + let nsPubsubTopic = getShard(contentTopicShort) + + # Then the generated shard is valid + check: + nsPubsubTopic.value() == NsPubsubTopic.staticSharding(ClusterId, 3) + + test "Generate Gen0 Shard with topic.generation==0": + # When we get a shard from it + let nsPubsubTopic = getShard(contentTopicFull) + + # Then the generated shard is valid + check: + nsPubsubTopic.value() == NsPubsubTopic.staticSharding(ClusterId, 3) + + test "Generate Gen0 Shard with topic.generation==other": + # When we get a shard from it + let nsPubsubTopic = getShard(contentTopicInvalid) + + # Then the generated shard is valid + check: + nsPubsubTopic.error() == "Generation > 0 are not supported yet" + + test "Generate Gen0 Shard invalid topic": + # When we get a shard from it + let nsPubsubTopic = getShard("invalid") + + # Then the generated shard is valid + check: + nsPubsubTopic.error() == "invalid format: topic must start with slash" + + suite "parseSharding": + test "contentTopics is ContentTopic": + # When calling with contentTopic as string + let topicMap = parseSharding(some(pubsubTopic04), contentTopicShort) + + # Then the topicMap is valid + check: + topicMap.value() == {pubsubTopic04: @[contentTopicShort]} + + test "contentTopics is seq[ContentTopic]": + # When calling with contentTopic as string seq + let topicMap = parseSharding(some(pubsubTopic04), @[contentTopicShort, "/0/foo/1/bar/proto"]) + + # Then the topicMap is valid + check: + topicMap.value() == {pubsubTopic04: @[contentTopicShort, "/0/foo/1/bar/proto"]} + + test "pubsubTopic is none": + # When calling with pubsubTopic as none + let topicMap = parseSharding(PubsubTopic.none(), contentTopicShort) + + # Then the topicMap is valid + check: + topicMap.value() == {pubsubTopic13: @[contentTopicShort]} + + test "content parse error": + # When calling with pubsubTopic as none with invalid content + let topicMap = parseSharding(PubsubTopic.none(), "invalid") + + # Then the topicMap is valid + check: + topicMap.error() == "Cannot parse content topic: invalid format: topic must start with slash" + + test "pubsubTopic parse error": + # When calling with pubsubTopic as none with invalid content + let topicMap = parseSharding(some("invalid"), contentTopicShort) + + # Then the topicMap is valid + check: + topicMap.error() == "Cannot parse pubsub topic: invalid format: must start with /waku/2" + + test "pubsubTopic getShard error": + # When calling with pubsubTopic as none with invalid content + let topicMap = parseSharding(PubsubTopic.none(), contentTopicInvalid) + + # Then the topicMap is valid + check: + topicMap.error() == "Cannot autoshard content topic: Generation > 0 are not supported yet" + + xtest "catchable error on add to topicMap": + # TODO: Trigger a CatchableError or mock + discard diff --git a/waku/waku_core/topics/sharding.nim b/waku/waku_core/topics/sharding.nim index ed4eef560..c62bacfbf 100644 --- a/waku/waku_core/topics/sharding.nim +++ b/waku/waku_core/topics/sharding.nim @@ -84,7 +84,7 @@ proc parseSharding*(pubsubTopic: Option[PubsubTopic], contentTopics: ContentTopi if shardsRes.isErr(): return err("Cannot autoshard content topic: " & $shardsRes.error) else: shardsRes.get() - + if not topicMap.hasKey(pubsub): topicMap[pubsub] = @[]