js-waku/packages/utils/src/common/sharding.spec.ts

131 lines
3.8 KiB
TypeScript
Raw Normal View History

import { expect } from "chai";
import {
contentTopicsByPubsubTopic,
contentTopicToPubsubTopic,
contentTopicToShardIndex,
ensureValidContentTopic
} from "./sharding";
const testInvalidCases = (
contentTopics: string[],
expectedError: string
): void => {
for (const invalidTopic of contentTopics) {
expect(() => ensureValidContentTopic(invalidTopic)).to.throw(expectedError);
}
};
describe("ensureValidContentTopic", () => {
it("does not throw on valid cases", () => {
const validTopics = [
"/0/myapp/1/mytopic/cbor",
"/myapp/1/mytopic/cbor",
"/myapp/v1.1/mytopic/cbor"
];
for (const validTopic of validTopics) {
expect(() => ensureValidContentTopic(validTopic)).to.not.throw;
}
});
it("throws on empty content topic", () => {
testInvalidCases(["", " ", " "], "Content topic format is invalid");
});
it("throws on content topic with too few or too many fields", () => {
testInvalidCases(
[
"myContentTopic",
"myapp1mytopiccbor/",
" /myapp/1/mytopic",
"/myapp/1/mytopic",
"/0/myapp/1/mytopic/cbor/extra"
],
"Content topic format is invalid"
);
});
it("throws on content topic with non-number generation field", () => {
testInvalidCases(
[
"/a/myapp/1/mytopic/cbor",
"/ /myapp/1/mytopic/cbor",
"/_/myapp/1/mytopic/cbor",
"/$/myapp/1/mytopic/cbor"
],
"Invalid generation field in content topic"
);
});
// Note that this test case should be removed once Waku supports other generations
it("throws on content topic with generation field greater than 0", () => {
testInvalidCases(
[
"/1/myapp/1/mytopic/cbor",
"/2/myapp/1/mytopic/cbor",
"/3/myapp/1/mytopic/cbor",
"/1000/myapp/1/mytopic/cbor"
],
"Generation greater than 0 is not supported"
);
});
it("throws on content topic with empty application field", () => {
testInvalidCases(
["/0//1/mytopic/cbor"],
"Application field cannot be empty"
);
});
it("throws on content topic with empty version field", () => {
testInvalidCases(
["/0/myapp//mytopic/cbor"],
"Version field cannot be empty"
);
});
it("throws on content topic with empty topic name field", () => {
testInvalidCases(["/0/myapp/1//cbor"], "Topic name field cannot be empty");
});
it("throws on content topic with empty encoding field", () => {
testInvalidCases(["/0/myapp/1/mytopic/"], "Encoding field cannot be empty");
});
});
describe("contentTopicToShardIndex", () => {
it("converts content topics to expected shard index", () => {
const contentTopics: [string, number][] = [
["/toychat/2/huilong/proto", 3],
["/myapp/1/latest/proto", 0],
["/waku/2/content/test.js", 1]
];
for (const [topic, shard] of contentTopics) {
expect(contentTopicToShardIndex(topic)).to.eq(shard);
}
});
it("topics with same application and version share the same shard", () => {
const contentTopics: [string, string][] = [
["/toychat/2/huilong/proto", "/toychat/2/othertopic/otherencoding"],
["/myapp/1/latest/proto", "/myapp/1/new/proto"],
["/waku/2/content/test.js", "/waku/2/users/proto"]
];
for (const [topic1, topic2] of contentTopics) {
expect(contentTopicToShardIndex(topic1)).to.eq(
contentTopicToShardIndex(topic2)
);
}
});
});
describe("contentTopicsByPubsubTopic", () => {
it("groups content topics by expected pubsub topic", () => {
const contentTopics = ["/toychat/2/huilong/proto", "/myapp/1/latest/proto"];
const grouped = contentTopicsByPubsubTopic(contentTopics);
for (const contentTopic of contentTopics) {
const pubsubTopic = contentTopicToPubsubTopic(contentTopic);
expect(grouped.get(pubsubTopic)?.includes(contentTopic)).to.be.true;
}
});
});