From e94b2ffd1c6cd29485306ac4e4ed4b3ef48bd86f Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 29 Jan 2025 20:35:44 +0530 Subject: [PATCH 01/19] chore: fix logs --- packages/tests/src/run-tests.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/tests/src/run-tests.js b/packages/tests/src/run-tests.js index db9547f876..ef1ce723f5 100644 --- a/packages/tests/src/run-tests.js +++ b/packages/tests/src/run-tests.js @@ -31,13 +31,25 @@ async function main() { mochaArgs.push( "--reporter", - "json", - "--reporter-option", - `output=${reportPath}`, + "mocha-multi-reporters", + "--reporter-options", + `configFile=${dirname(reportPath)}/config.json`, "--parallel", "--jobs", "6" ); + + // Write reporter config file + const fs = await import("fs/promises"); + await fs.writeFile( + `${dirname(reportPath)}/config.json`, + JSON.stringify({ + reporterEnabled: "spec, json", + jsonReporterOptions: { + output: reportPath + } + }) + ); } // Add test files @@ -48,7 +60,7 @@ async function main() { } mochaArgs.push(...testFiles); - console.log("Running mocha with args:", mochaArgs); + console.info("Running mocha with args:", mochaArgs); // Run mocha tests const mocha = spawn("npx", mochaArgs, { From e8873da1bd3e848388fc45173fc3fffd7bd89398 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 9 Oct 2024 15:48:25 +0530 Subject: [PATCH 02/19] chore: upgrade nwaku to v0.33.1 --- .github/workflows/ci.yml | 4 ++-- packages/tests/src/run-tests.js | 2 +- packages/tests/src/sync-rln-tree.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 49f5a52038..4e6482a13d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,13 +122,13 @@ jobs: uses: ./.github/workflows/test-node.yml secrets: inherit with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.31.0' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.33.1' }} test_type: node node_optional: uses: ./.github/workflows/test-node.yml with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.31.0' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.33.1' }} test_type: node-optional node_with_nwaku_master: diff --git a/packages/tests/src/run-tests.js b/packages/tests/src/run-tests.js index ef1ce723f5..a16e87f1b4 100644 --- a/packages/tests/src/run-tests.js +++ b/packages/tests/src/run-tests.js @@ -5,7 +5,7 @@ import { promisify } from "util"; const execAsync = promisify(exec); -const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.31.0"; +const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.33.1"; async function main() { try { diff --git a/packages/tests/src/sync-rln-tree.js b/packages/tests/src/sync-rln-tree.js index d69c3d1899..d54bec683f 100644 --- a/packages/tests/src/sync-rln-tree.js +++ b/packages/tests/src/sync-rln-tree.js @@ -7,7 +7,7 @@ import { ServiceNode } from "./lib/index.js"; const execAsync = promisify(exec); -const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.31.0"; +const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.33.1"; const containerName = "rln_tree"; async function syncRlnTree() { From 75d3c6539ae5c9541f2ad03db0d96888320de850 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 15 Jan 2025 16:08:51 +0530 Subject: [PATCH 03/19] chore: upgrade to nwaku 0.34.0 --- .github/workflows/ci.yml | 4 ++-- packages/tests/src/run-tests.js | 2 +- packages/tests/src/sync-rln-tree.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e6482a13d..523975d3ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -122,13 +122,13 @@ jobs: uses: ./.github/workflows/test-node.yml secrets: inherit with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.33.1' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.34.0' }} test_type: node node_optional: uses: ./.github/workflows/test-node.yml with: - nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.33.1' }} + nim_wakunode_image: ${{ inputs.nim_wakunode_image || 'wakuorg/nwaku:v0.34.0' }} test_type: node-optional node_with_nwaku_master: diff --git a/packages/tests/src/run-tests.js b/packages/tests/src/run-tests.js index a16e87f1b4..857bc09876 100644 --- a/packages/tests/src/run-tests.js +++ b/packages/tests/src/run-tests.js @@ -5,7 +5,7 @@ import { promisify } from "util"; const execAsync = promisify(exec); -const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.33.1"; +const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.34.0"; async function main() { try { diff --git a/packages/tests/src/sync-rln-tree.js b/packages/tests/src/sync-rln-tree.js index d54bec683f..a84a40d741 100644 --- a/packages/tests/src/sync-rln-tree.js +++ b/packages/tests/src/sync-rln-tree.js @@ -7,7 +7,7 @@ import { ServiceNode } from "./lib/index.js"; const execAsync = promisify(exec); -const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.33.1"; +const WAKUNODE_IMAGE = process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.34.0"; const containerName = "rln_tree"; async function syncRlnTree() { From ff1847ed595e20e562467eebd2593810a8177d2f Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 17 Jan 2025 15:46:53 +0530 Subject: [PATCH 04/19] feat: connect nwaku nodes amongst each other over relay --- packages/tests/src/lib/dockerode.ts | 2 +- packages/tests/src/lib/index.ts | 119 ++++++++++++++++++++----- packages/tests/src/lib/service_node.ts | 9 ++ 3 files changed, 108 insertions(+), 22 deletions(-) diff --git a/packages/tests/src/lib/dockerode.ts b/packages/tests/src/lib/dockerode.ts index 823a02859b..2428b67cb9 100644 --- a/packages/tests/src/lib/dockerode.ts +++ b/packages/tests/src/lib/dockerode.ts @@ -18,7 +18,7 @@ export default class Dockerode { public containerId?: string; private static network: Docker.Network; - private containerIp: string; + public readonly containerIp: string; private constructor(imageName: string, containerIp: string) { this.docker = new Docker(); diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index 8f804633a3..2a5c02acdf 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -29,24 +29,28 @@ export class ServiceNodesFleet { _args?: Args, withoutFilter = false ): Promise { - const serviceNodePromises = Array.from( - { length: nodesToCreate }, - async () => { - const node = new ServiceNode( - makeLogFileName(mochaContext) + - Math.random().toString(36).substring(7) - ); + const nodes: ServiceNode[] = []; + + for (let index = 0; index < nodesToCreate; index++) { + const node = new ServiceNode( + makeLogFileName(mochaContext) + Math.random().toString(36).substring(7) + ); - const args = getArgs(networkConfig, _args); - await node.start(args, { - retries: 3 - }); + const args = getArgs(networkConfig, _args); - return node; + // If this is not the first node and previous node had a nodekey, use its multiaddr as static node + if (index > 0) { + const prevNode = nodes[index - 1]; + const multiaddr = await prevNode.getExternalWebsocketMultiaddr(); + args.staticnode = multiaddr; } - ); - const nodes = await Promise.all(serviceNodePromises); + await node.start(args, { + retries: 3 + }); + + nodes.push(node); + } return new ServiceNodesFleet(nodes, withoutFilter, strictChecking); } @@ -182,21 +186,21 @@ class MultipleNodesMessageCollector { } ): boolean { if (this.strictChecking) { - return this.messageCollectors.every((collector) => { + return this.messageCollectors.every((collector, _i) => { try { collector.verifyReceivedMessage(index, options); - return true; // Verification successful + return true; } catch (error) { - return false; // Verification failed, continue with the next collector + return false; } }); } else { - return this.messageCollectors.some((collector) => { + return this.messageCollectors.some((collector, _i) => { try { collector.verifyReceivedMessage(index, options); - return true; // Verification successful + return true; } catch (error) { - return false; // Verification failed, continue with the next collector + return false; } }); } @@ -239,7 +243,8 @@ class MultipleNodesMessageCollector { } } - if (Date.now() - startTime > timeoutDuration * numMessages) { + const elapsed = Date.now() - startTime; + if (elapsed > timeoutDuration * numMessages) { return false; } @@ -253,7 +258,79 @@ class MultipleNodesMessageCollector { log.warn( `Was expecting exactly ${numMessages} messages. Received: ${this.messageList.length}` ); + return false; + } + } else { + return true; + } + } + /** + * Waits for a total number of messages across all nodes using autosharding. + */ + public async waitForMessagesAutosharding( + numMessages: number, + options?: { + contentTopic: string; + timeoutDuration?: number; + exact?: boolean; + } + ): Promise { + const startTime = Date.now(); + const timeoutDuration = options?.timeoutDuration || 400; + const exact = options?.exact || false; + + while (this.messageList.length < numMessages) { + if (this.relayNodes) { + if (this.strictChecking) { + // In strict mode, all nodes must have the messages + const results = await Promise.all( + this.messageCollectors.map(async (collector) => { + return collector.waitForMessagesAutosharding( + numMessages, + options + ); + }) + ); + if (results.every((result) => result)) { + return true; + } + } else { + // In non-strict mode, at least one node must have the messages + const results = await Promise.all( + this.messageCollectors.map(async (collector) => { + return collector.waitForMessagesAutosharding( + numMessages, + options + ); + }) + ); + if (results.some((result) => result)) { + return true; + } + } + + if (Date.now() - startTime > timeoutDuration * numMessages) { + return false; + } + + await delay(10); + } else { + // If no relay nodes, just wait for messages in the list + if (Date.now() - startTime > timeoutDuration * numMessages) { + return false; + } + await delay(10); + } + } + + if (exact) { + if (this.messageList.length == numMessages) { + return true; + } else { + log.warn( + `Was expecting exactly ${numMessages} messages. Received: ${this.messageList.length}` + ); return false; } } else { diff --git a/packages/tests/src/lib/service_node.ts b/packages/tests/src/lib/service_node.ts index b443fd6cb2..5dac5d318f 100644 --- a/packages/tests/src/lib/service_node.ts +++ b/packages/tests/src/lib/service_node.ts @@ -402,6 +402,15 @@ export class ServiceNode { throw `${this.type} container hasn't started`; } } + + public async getExternalWebsocketMultiaddr(): Promise { + if (!this.docker?.container) { + return undefined; + } + const containerIp = this.docker.containerIp; + const peerId = await this.getPeerId(); + return `/ip4/${containerIp}/tcp/${this.websocketPort}/ws/p2p/${peerId}`; + } } export function defaultArgs(): Args { From a05dea53735ecf26ad4e7bcac8bc2db7b02d7ec5 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 17 Jan 2025 15:47:36 +0530 Subject: [PATCH 05/19] chore(lightpush): use multiple service nodes for lightpush (instead of just one) - nwaku now expects >=1 nodes at least connected --- .../single_node/multiple_pubsub.node.spec.ts | 232 +++++++++--------- 1 file changed, 121 insertions(+), 111 deletions(-) diff --git a/packages/tests/tests/light-push/single_node/multiple_pubsub.node.spec.ts b/packages/tests/tests/light-push/single_node/multiple_pubsub.node.spec.ts index 02e6c7668a..7e5fdd71fe 100644 --- a/packages/tests/tests/light-push/single_node/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/light-push/single_node/multiple_pubsub.node.spec.ts @@ -16,24 +16,20 @@ import { } from "@waku/utils"; import { utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; -import { Context } from "mocha"; import { afterEachCustom, beforeEachCustom, - makeLogFileName, - MessageCollector, - ServiceNode, + runMultipleNodes, + ServiceNodesFleet, tearDownNodes } from "../../../src/index.js"; -import { messageText, runNodes } from "../utils.js"; +import { messageText } from "../utils.js"; describe("Waku Light Push : Multiple PubsubTopics", function () { this.timeout(30000); let waku: LightNode; - let nwaku: ServiceNode; - let nwaku2: ServiceNode; - let messageCollector: MessageCollector; + let serviceNodes: ServiceNodesFleet; const shardInfo: ShardInfo = { clusterId: 3, shards: [1, 2] }; const singleShardInfo1: SingleShardInfo = { clusterId: 3, shard: 1 }; @@ -55,13 +51,19 @@ describe("Waku Light Push : Multiple PubsubTopics", function () { let node1PeerId: PeerId; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, shardInfo); - messageCollector = new MessageCollector(nwaku); - node1PeerId = await nwaku.getPeerId(); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfo, + undefined, + true, + 2, + true + ); + node1PeerId = await serviceNodes.nodes[0].getPeerId(); }); afterEachCustom(this, async () => { - await tearDownNodes([nwaku, nwaku2], waku); + await tearDownNodes(serviceNodes.nodes, waku); }); it("Push message on custom pubsubTopic", async function () { @@ -72,11 +74,11 @@ describe("Waku Light Push : Multiple PubsubTopics", function () { expect(pushResponse.successes[0].toString()).to.eq(node1PeerId.toString()); expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: customPubsubTopic1 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: customContentTopic1 }); @@ -92,50 +94,48 @@ describe("Waku Light Push : Multiple PubsubTopics", function () { expect(pushResponse1.successes[0].toString()).to.eq(node1PeerId.toString()); expect(pushResponse2.successes[0].toString()).to.eq(node1PeerId.toString()); - const messageCollector2 = new MessageCollector(nwaku); - expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: customPubsubTopic1 }) ).to.eq(true); expect( - await messageCollector2.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: customPubsubTopic2 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: customPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: customPubsubTopic2 }); }); - it("Light push messages to 2 nwaku nodes each with different pubsubtopics", async function () { - // Set up and start a new nwaku node with Default PubsubTopic - nwaku2 = new ServiceNode(makeLogFileName(this) + "2"); - await nwaku2.start({ - filter: true, - lightpush: true, - relay: true, - pubsubTopic: [singleShardInfoToPubsubTopic(singleShardInfo2)], - clusterId: singleShardInfo2.clusterId - }); - await nwaku2.ensureSubscriptions([ + it("Light push messages to 2 service nodes each with different pubsubtopics", async function () { + const [serviceNodes2, waku2] = await runMultipleNodes( + this.ctx, + { + clusterId: singleShardInfo2.clusterId, + shards: [singleShardInfo2.shard!] + }, + undefined, + true, + 1 + ); + + await serviceNodes2.nodes[0].ensureSubscriptions([ singleShardInfoToPubsubTopic(singleShardInfo2) ]); - await waku.dial(await nwaku2.getMultiaddrWithId()); + await waku.dial(await serviceNodes2.nodes[0].getMultiaddrWithId()); await waku.waitForPeers([Protocols.LightPush]); - const messageCollector2 = new MessageCollector(nwaku2); - await waku.lightPush.send(customEncoder1, { payload: utf8ToBytes("M1") }); @@ -143,33 +143,33 @@ describe("Waku Light Push : Multiple PubsubTopics", function () { payload: utf8ToBytes("M2") }); - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: customPubsubTopic1 }); - - await messageCollector2.waitForMessages(1, { + await serviceNodes2.messageCollector.waitForMessages(1, { pubsubTopic: singleShardInfoToPubsubTopic(singleShardInfo2) }); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: customPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes2.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: singleShardInfoToPubsubTopic(singleShardInfo2) }); + + // Clean up second fleet + await tearDownNodes(serviceNodes2.nodes, waku2); }); }); describe("Waku Light Push (Autosharding): Multiple PubsubTopics", function () { this.timeout(30000); let waku: LightNode; - let nwaku: ServiceNode; - let nwaku2: ServiceNode; - let messageCollector: MessageCollector; + let serviceNodes: ServiceNodesFleet; const clusterId = 4; const customContentTopic1 = "/waku/2/content/test.js"; @@ -198,13 +198,19 @@ describe("Waku Light Push (Autosharding): Multiple PubsubTopics", function () { let node1PeerId: PeerId; beforeEachCustom(this, async () => { - [nwaku, waku] = await runNodes(this.ctx, shardInfo); - messageCollector = new MessageCollector(nwaku); - node1PeerId = await nwaku.getPeerId(); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfo, + undefined, + true, + 2, + true + ); + node1PeerId = await serviceNodes.nodes[0].getPeerId(); }); afterEachCustom(this, async () => { - await tearDownNodes([nwaku, nwaku2], waku); + await tearDownNodes(serviceNodes.nodes, waku); }); it("Push message on custom pubsubTopic", async function () { @@ -212,15 +218,14 @@ describe("Waku Light Push (Autosharding): Multiple PubsubTopics", function () { payload: utf8ToBytes(messageText) }); - expect(pushResponse.failures).to.be.empty; expect(pushResponse.successes[0].toString()).to.eq(node1PeerId.toString()); expect( - await messageCollector.waitForMessagesAutosharding(1, { - contentTopic: customContentTopic1 + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: autoshardingPubsubTopic1 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: customContentTopic1 }); @@ -236,48 +241,46 @@ describe("Waku Light Push (Autosharding): Multiple PubsubTopics", function () { expect(pushResponse1.successes[0].toString()).to.eq(node1PeerId.toString()); expect(pushResponse2.successes[0].toString()).to.eq(node1PeerId.toString()); - const messageCollector2 = new MessageCollector(nwaku); - expect( - await messageCollector.waitForMessagesAutosharding(1, { - contentTopic: customContentTopic1 + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: autoshardingPubsubTopic1 }) ).to.eq(true); expect( - await messageCollector2.waitForMessagesAutosharding(1, { - contentTopic: customContentTopic2 + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: autoshardingPubsubTopic2 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: autoshardingPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: autoshardingPubsubTopic2 }); }); - it("Light push messages to 2 nwaku nodes each with different pubsubtopics", async function () { - // Set up and start a new nwaku node with Default PubsubTopic - nwaku2 = new ServiceNode(makeLogFileName(this) + "2"); - await nwaku2.start({ - filter: true, - lightpush: true, - relay: true, - pubsubTopic: [autoshardingPubsubTopic2], - clusterId: shardInfo.clusterId - }); - await nwaku2.ensureSubscriptionsAutosharding([customContentTopic2]); - await waku.dial(await nwaku2.getMultiaddrWithId()); + it("Light push messages to 2 service nodes each with different pubsubtopics", async function () { + // Create a second fleet for the second pubsub topic + const [serviceNodes2, waku2] = await runMultipleNodes( + this.ctx, + { clusterId, contentTopics: [customContentTopic2] }, + undefined, + true, + 1 // Only need one node for second fleet + ); + + await serviceNodes2.nodes[0].ensureSubscriptionsAutosharding([ + customContentTopic2 + ]); + await waku.dial(await serviceNodes2.nodes[0].getMultiaddrWithId()); await waku.waitForPeers([Protocols.LightPush]); - const messageCollector2 = new MessageCollector(nwaku2); - await waku.lightPush.send(customEncoder1, { payload: utf8ToBytes("M1") }); @@ -285,34 +288,33 @@ describe("Waku Light Push (Autosharding): Multiple PubsubTopics", function () { payload: utf8ToBytes("M2") }); - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: customContentTopic1 }); - await messageCollector2.waitForMessagesAutosharding(1, { + await serviceNodes2.messageCollector.waitForMessagesAutosharding(1, { contentTopic: customContentTopic2 }); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: autoshardingPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes2.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: autoshardingPubsubTopic2 }); + + // Clean up second fleet + await tearDownNodes(serviceNodes2.nodes, waku2); }); }); describe("Waku Light Push (named sharding): Multiple PubsubTopics", function () { this.timeout(30000); let waku: LightNode; - let waku2: LightNode; - let nwaku: ServiceNode; - let nwaku2: ServiceNode; - let messageCollector: MessageCollector; - let ctx: Context; + let serviceNodes: ServiceNodesFleet; const clusterId = 3; const customContentTopic1 = "/waku/2/content/utf8"; @@ -355,14 +357,19 @@ describe("Waku Light Push (named sharding): Multiple PubsubTopics", function () let node1PeerId: PeerId; beforeEachCustom(this, async () => { - ctx = this.ctx; - [nwaku, waku] = await runNodes(ctx, testShardInfo); - messageCollector = new MessageCollector(nwaku); - node1PeerId = await nwaku.getPeerId(); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + testShardInfo, + undefined, + true, + 2, + true + ); + node1PeerId = await serviceNodes.nodes[0].getPeerId(); }); afterEachCustom(this, async () => { - await tearDownNodes([nwaku, nwaku2], [waku, waku2]); + await tearDownNodes(serviceNodes.nodes, waku); }); it("Push message on custom pubsubTopic", async function () { @@ -373,11 +380,11 @@ describe("Waku Light Push (named sharding): Multiple PubsubTopics", function () expect(pushResponse.successes[0].toString()).to.eq(node1PeerId.toString()); expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: autoshardingPubsubTopic1 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: messageText, expectedContentTopic: customContentTopic1 }); @@ -393,68 +400,71 @@ describe("Waku Light Push (named sharding): Multiple PubsubTopics", function () expect(pushResponse1.successes[0].toString()).to.eq(node1PeerId.toString()); expect(pushResponse2.successes[0].toString()).to.eq(node1PeerId.toString()); - const messageCollector2 = new MessageCollector(nwaku); - expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: autoshardingPubsubTopic1 }) ).to.eq(true); expect( - await messageCollector2.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: autoshardingPubsubTopic2 }) ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: autoshardingPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(1, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: autoshardingPubsubTopic2 }); }); - it("Light push messages to 2 nwaku nodes each with different pubsubtopics", async function () { - // Set up and start a new nwaku node with Default PubsubTopic - [nwaku2] = await runNodes(ctx, shardInfo2); - - await nwaku2.ensureSubscriptions([autoshardingPubsubTopic2]); - await waku.dial(await nwaku2.getMultiaddrWithId()); + it("Light push messages to 2 service nodes each with different pubsubtopics", async function () { + const [serviceNodes2, waku2] = await runMultipleNodes( + this.ctx, + shardInfo2, + undefined, + true, + 1 + ); + + await serviceNodes2.nodes[0].ensureSubscriptions([ + autoshardingPubsubTopic2 + ]); + await waku.dial(await serviceNodes2.nodes[0].getMultiaddrWithId()); await waku.waitForPeers([Protocols.LightPush]); - const messageCollector2 = new MessageCollector(nwaku2); - - const { failures: f1 } = await waku.lightPush.send(customEncoder1, { + await waku.lightPush.send(customEncoder1, { payload: utf8ToBytes("M1") }); - const { failures: f2 } = await waku.lightPush.send(customEncoder2, { + await waku.lightPush.send(customEncoder2, { payload: utf8ToBytes("M2") }); - expect(f1).to.be.empty; - expect(f2).to.be.empty; - - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: autoshardingPubsubTopic1 }); - await messageCollector2.waitForMessages(1, { + await serviceNodes2.messageCollector.waitForMessages(1, { pubsubTopic: autoshardingPubsubTopic2 }); - messageCollector.verifyReceivedMessage(0, { + serviceNodes.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M1", expectedContentTopic: customContentTopic1, expectedPubsubTopic: autoshardingPubsubTopic1 }); - messageCollector2.verifyReceivedMessage(0, { + serviceNodes2.messageCollector.verifyReceivedMessage(0, { expectedMessageText: "M2", expectedContentTopic: customContentTopic2, expectedPubsubTopic: autoshardingPubsubTopic2 }); + + // Clean up second fleet + await tearDownNodes(serviceNodes2.nodes, waku2); }); }); From ec6ab559255ef408187e74f2a27152bb0433c3d7 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 17 Jan 2025 16:00:14 +0530 Subject: [PATCH 06/19] chore: all single-node lightpush requests should now be expected to fail --- .../light-push/single_node/index.node.spec.ts | 188 +++--------------- 1 file changed, 23 insertions(+), 165 deletions(-) diff --git a/packages/tests/tests/light-push/single_node/index.node.spec.ts b/packages/tests/tests/light-push/single_node/index.node.spec.ts index a8b8835264..be1b46fae1 100644 --- a/packages/tests/tests/light-push/single_node/index.node.spec.ts +++ b/packages/tests/tests/light-push/single_node/index.node.spec.ts @@ -7,7 +7,6 @@ import { afterEachCustom, beforeEachCustom, generateRandomUint8Array, - MessageCollector, ServiceNode, tearDownNodes, TEST_STRING @@ -22,16 +21,16 @@ import { TestShardInfo } from "../utils.js"; -describe("Waku Light Push: Single Node", function () { +// These tests are expected to fail as service nodes now require at least one more connected node: https://github.com/waku-org/nwaku/pull/2951/files + +describe.only("Waku Light Push: Single Node: Fails as expected", function () { // Set the timeout for all tests in this suite. Can be overwritten at test level this.timeout(15000); let waku: LightNode; let nwaku: ServiceNode; - let messageCollector: MessageCollector; beforeEachCustom(this, async () => { [nwaku, waku] = await runNodes(this.ctx, TestShardInfo); - messageCollector = new MessageCollector(nwaku); await nwaku.ensureSubscriptions([TestPubsubTopic]); }); @@ -45,18 +44,9 @@ describe("Waku Light Push: Single Node", function () { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes(testItem.value) }); - expect(pushResponse.successes.length).to.eq(1); - - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: testItem.value, - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); + // Expect failure since node requires another connected node + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); }); }); @@ -67,73 +57,9 @@ describe("Waku Light Push: Single Node", function () { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes(generateMessageText(i)) }); - expect(pushResponse.successes.length).to.eq(1); - } - - expect( - await messageCollector.waitForMessages(30, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - - for (let i = 0; i < 30; i++) { - messageCollector.verifyReceivedMessage(i, { - expectedMessageText: generateMessageText(i), - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); - } - }); - - it("Throws when trying to push message with empty payload", async function () { - const pushResponse = await waku.lightPush.send(TestEncoder, { - payload: new Uint8Array() - }); - - expect(pushResponse.successes.length).to.eq(0); - expect(pushResponse.failures?.map((failure) => failure.error)).to.include( - ProtocolError.EMPTY_PAYLOAD - ); - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(false); - }); - - TEST_STRING.forEach((testItem) => { - it(`Push message with content topic containing ${testItem.description}`, async function () { - const customEncoder = createEncoder({ - contentTopic: testItem.value, - pubsubTopic: TestPubsubTopic - }); - const pushResponse = await waku.lightPush.send( - customEncoder, - messagePayload - ); - expect(pushResponse.successes.length).to.eq(1); - - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: messageText, - expectedContentTopic: testItem.value, - expectedPubsubTopic: TestPubsubTopic - }); - }); - }); - - it("Fails to push message with empty content topic", async function () { - try { - createEncoder({ contentTopic: "" }); - expect.fail("Expected an error but didn't get one"); - } catch (error) { - expect((error as Error).message).to.equal( - "Content topic must be specified" - ); + // Expect failure since node requires another connected node + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); } }); @@ -148,62 +74,19 @@ describe("Waku Light Push: Single Node", function () { customTestEncoder, messagePayload ); - expect(pushResponse.successes.length).to.eq(1); - - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: messageText, - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); }); - it("Fails to push message with large meta", async function () { - const customTestEncoder = createEncoder({ - contentTopic: TestContentTopic, - pubsubTopic: TestPubsubTopic, - metaSetter: () => new Uint8Array(105024) // see the note below *** + it("Fails to push message with empty payload", async function () { + const pushResponse = await waku.lightPush.send(TestEncoder, { + payload: new Uint8Array() }); - // *** note: this test used 10 ** 6 when `nwaku` node had MaxWakuMessageSize == 1MiB ( 1*2^20 .) - // `nwaku` establishes the max lightpush msg size as `const MaxRpcSize* = MaxWakuMessageSize + 64 * 1024` - // see: https://github.com/waku-org/nwaku/blob/07beea02095035f4f4c234ec2dec1f365e6955b8/waku/waku_lightpush/rpc_codec.nim#L15 - // In the PR https://github.com/waku-org/nwaku/pull/2298 we reduced the MaxWakuMessageSize - // from 1MiB to 150KiB. Therefore, the 105024 number comes from substracting ( 1*2^20 - 150*2^10 ) - // to the original 10^6 that this test had when MaxWakuMessageSize == 1*2^20 - - const pushResponse = await waku.lightPush.send( - customTestEncoder, - messagePayload + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.map((failure) => failure.error)).to.include( + ProtocolError.EMPTY_PAYLOAD ); - - if (nwaku.type == "go-waku") { - expect(pushResponse.successes.length).to.eq(1); - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: messageText, - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); - } else { - expect(pushResponse.successes.length).to.eq(0); - expect(pushResponse.failures?.map((failure) => failure.error)).to.include( - ProtocolError.REMOTE_PEER_REJECTED - ); - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(false); - } }); it("Push message with rate limit", async function () { @@ -221,18 +104,8 @@ describe("Waku Light Push: Single Node", function () { payload: utf8ToBytes(messageText), rateLimitProof: rateLimitProof }); - expect(pushResponse.successes.length).to.eq(1); - - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: messageText, - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); }); [ @@ -245,19 +118,8 @@ describe("Waku Light Push: Single Node", function () { payload: utf8ToBytes(messageText), timestamp: new Date(testItem) }); - expect(pushResponse.successes.length).to.eq(1); - - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(true); - messageCollector.verifyReceivedMessage(0, { - expectedMessageText: messageText, - expectedTimestamp: testItem, - expectedContentTopic: TestContentTopic, - expectedPubsubTopic: TestPubsubTopic - }); + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); }); }); @@ -266,7 +128,8 @@ describe("Waku Light Push: Single Node", function () { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: bigPayload }); - expect(pushResponse.successes.length).to.greaterThan(0); + expect(pushResponse.successes.length).to.eq(0); + expect(pushResponse.failures?.length).to.be.greaterThan(0); }); it("Fails to push message bigger that 1MB", async function () { @@ -279,10 +142,5 @@ describe("Waku Light Push: Single Node", function () { expect(pushResponse.failures?.map((failure) => failure.error)).to.include( ProtocolError.SIZE_TOO_BIG ); - expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: TestPubsubTopic - }) - ).to.eq(false); }); }); From 97a866a5b963561da725a812e6f35ea02f806150 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 17 Jan 2025 16:36:43 +0530 Subject: [PATCH 07/19] chore: update sharding tests --- packages/tests/src/lib/service_node.ts | 2 +- .../light-push/single_node/index.node.spec.ts | 2 +- .../tests/sharding/auto_sharding.spec.ts | 203 +++++++++--------- .../tests/sharding/static_sharding.spec.ts | 197 ++++++++--------- 4 files changed, 191 insertions(+), 213 deletions(-) diff --git a/packages/tests/src/lib/service_node.ts b/packages/tests/src/lib/service_node.ts index 5dac5d318f..10eb5a37ea 100644 --- a/packages/tests/src/lib/service_node.ts +++ b/packages/tests/src/lib/service_node.ts @@ -27,7 +27,7 @@ const WAKU_SERVICE_NODE_PARAMS = const NODE_READY_LOG_LINE = "Node setup complete"; export const DOCKER_IMAGE_NAME = - process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.31.0"; + process.env.WAKUNODE_IMAGE || "wakuorg/nwaku:v0.34.0"; const isGoWaku = DOCKER_IMAGE_NAME.includes("go-waku"); diff --git a/packages/tests/tests/light-push/single_node/index.node.spec.ts b/packages/tests/tests/light-push/single_node/index.node.spec.ts index be1b46fae1..af0c3232d6 100644 --- a/packages/tests/tests/light-push/single_node/index.node.spec.ts +++ b/packages/tests/tests/light-push/single_node/index.node.spec.ts @@ -23,7 +23,7 @@ import { // These tests are expected to fail as service nodes now require at least one more connected node: https://github.com/waku-org/nwaku/pull/2951/files -describe.only("Waku Light Push: Single Node: Fails as expected", function () { +describe("Waku Light Push: Single Node: Fails as expected", function () { // Set the timeout for all tests in this suite. Can be overwritten at test level this.timeout(15000); let waku: LightNode; diff --git a/packages/tests/tests/sharding/auto_sharding.spec.ts b/packages/tests/tests/sharding/auto_sharding.spec.ts index e2cdca6d41..3d2f4cebf0 100644 --- a/packages/tests/tests/sharding/auto_sharding.spec.ts +++ b/packages/tests/tests/sharding/auto_sharding.spec.ts @@ -1,4 +1,4 @@ -import { LightNode, ProtocolError, Protocols } from "@waku/interfaces"; +import { LightNode, ProtocolError } from "@waku/interfaces"; import { createEncoder, createLightNode, utf8ToBytes } from "@waku/sdk"; import { contentTopicToPubsubTopic, @@ -8,10 +8,8 @@ import { expect } from "chai"; import { afterEachCustom, - beforeEachCustom, - makeLogFileName, - MessageCollector, - ServiceNode, + runMultipleNodes, + ServiceNodesFleet, tearDownNodes } from "../../src/index.js"; @@ -22,41 +20,33 @@ describe("Autosharding: Running Nodes", function () { this.timeout(50000); const clusterId = 10; let waku: LightNode; - let nwaku: ServiceNode; - let messageCollector: MessageCollector; - - beforeEachCustom(this, async () => { - nwaku = new ServiceNode(makeLogFileName(this.ctx)); - messageCollector = new MessageCollector(nwaku); - }); + let serviceNodes: ServiceNodesFleet; afterEachCustom(this, async () => { - await tearDownNodes(nwaku, waku); + await tearDownNodes(serviceNodes.nodes, waku); }); describe("Different clusters and topics", function () { - // js-waku allows autosharding for cluster IDs different than 1 it("Cluster ID 0 - Default/Global Cluster", async function () { const clusterId = 0; const pubsubTopics = [contentTopicToPubsubTopic(ContentTopic, clusterId)]; - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: pubsubTopics - }); - - await nwaku.ensureSubscriptions(pubsubTopics); - waku = await createLightNode({ - networkConfig: { - clusterId: clusterId, + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId, contentTopics: [ContentTopic] - } - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + }, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: pubsubTopics + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -70,9 +60,10 @@ describe("Autosharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); // Expect 2 successes for 2 nodes + console.log("good"); expect( - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic }) ).to.eq(true); @@ -81,24 +72,23 @@ describe("Autosharding: Running Nodes", function () { it("Non TWN Cluster", async function () { const clusterId = 5; const pubsubTopics = [contentTopicToPubsubTopic(ContentTopic, clusterId)]; - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: pubsubTopics - }); - - await nwaku.ensureSubscriptions(pubsubTopics); - waku = await createLightNode({ - networkConfig: { - clusterId: clusterId, + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId, contentTopics: [ContentTopic] - } - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + }, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: pubsubTopics + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -112,9 +102,9 @@ describe("Autosharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); // Expect 2 successes for 2 nodes expect( - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic }) ).to.eq(true); @@ -138,24 +128,23 @@ describe("Autosharding: Running Nodes", function () { contentTopicToPubsubTopic(ContentTopic, clusterId) ]; - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: pubsubTopics, - contentTopic: [ContentTopic] - }); - - waku = await createLightNode({ - networkConfig: { - clusterId: clusterId, + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId, contentTopics: [ContentTopic] - } - }); - - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + }, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: pubsubTopics, + contentTopic: [ContentTopic] + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -169,9 +158,9 @@ describe("Autosharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); // Expect 2 successes for 2 nodes expect( - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic }) ).to.eq(true); @@ -201,24 +190,23 @@ describe("Autosharding: Running Nodes", function () { contentTopicToPubsubTopic(ContentTopic2, clusterId) ]; - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: pubsubTopics, - contentTopic: [ContentTopic, ContentTopic2] - }); - - waku = await createLightNode({ - networkConfig: { - clusterId: clusterId, - // For autosharding, we configure multiple pubsub topics by using two content topics that hash to different shards + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId, contentTopics: [ContentTopic, ContentTopic2] - } - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + }, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: pubsubTopics, + contentTopic: [ContentTopic, ContentTopic2] + }, + false, + 2, + true + ); const encoder1 = createEncoder({ contentTopic: ContentTopic, @@ -239,9 +227,9 @@ describe("Autosharding: Running Nodes", function () { const request1 = await waku.lightPush.send(encoder1, { payload: utf8ToBytes("Hello World") }); - expect(request1.successes.length).to.eq(1); + expect(request1.successes.length).to.eq(2); // Expect 2 successes for 2 nodes expect( - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic }) ).to.eq(true); @@ -249,9 +237,9 @@ describe("Autosharding: Running Nodes", function () { const request2 = await waku.lightPush.send(encoder2, { payload: utf8ToBytes("Hello World") }); - expect(request2.successes.length).to.eq(1); + expect(request2.successes.length).to.eq(2); // Expect 2 successes for 2 nodes expect( - await messageCollector.waitForMessagesAutosharding(1, { + await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic }) ).to.eq(true); @@ -259,21 +247,24 @@ describe("Autosharding: Running Nodes", function () { it("using a protocol with unconfigured pubsub topic should fail", async function () { const pubsubTopics = [contentTopicToPubsubTopic(ContentTopic, clusterId)]; - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: pubsubTopics, - contentTopic: [ContentTopic] - }); - waku = await createLightNode({ - networkConfig: { - clusterId: clusterId, + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId, contentTopics: [ContentTopic] - } - }); + }, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: pubsubTopics, + contentTopic: [ContentTopic] + }, + false, + 2, + true + ); // use a content topic that is not configured const encoder = createEncoder({ @@ -288,17 +279,17 @@ describe("Autosharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - if (successes.length > 0 || failures?.length === 0) { + if (successes.length > 0 || !failures?.length) { throw new Error("The request should've thrown an error"); } - const errors = failures?.map((failure) => failure.error); + const errors = failures.map((failure) => failure.error); expect(errors).to.include(ProtocolError.TOPIC_NOT_CONFIGURED); }); it("start node with empty content topic", async function () { try { - waku = await createLightNode({ + await createLightNode({ networkConfig: { clusterId: clusterId, contentTopics: [] diff --git a/packages/tests/tests/sharding/static_sharding.spec.ts b/packages/tests/tests/sharding/static_sharding.spec.ts index f4cdccb4ee..c2151d9d01 100644 --- a/packages/tests/tests/sharding/static_sharding.spec.ts +++ b/packages/tests/tests/sharding/static_sharding.spec.ts @@ -1,7 +1,6 @@ import { LightNode, ProtocolError, - Protocols, ShardInfo, SingleShardInfo } from "@waku/interfaces"; @@ -15,10 +14,8 @@ import { expect } from "chai"; import { afterEachCustom, - beforeEachCustom, - makeLogFileName, - MessageCollector, - ServiceNode, + runMultipleNodes, + ServiceNodesFleet, tearDownNodes } from "../../src/index.js"; @@ -27,16 +24,10 @@ const ContentTopic = "/waku/2/content/test.js"; describe("Static Sharding: Running Nodes", function () { this.timeout(15_000); let waku: LightNode; - let nwaku: ServiceNode; - let messageCollector: MessageCollector; - - beforeEachCustom(this, async () => { - nwaku = new ServiceNode(makeLogFileName(this.ctx)); - messageCollector = new MessageCollector(nwaku); - }); + let serviceNodes: ServiceNodesFleet; afterEachCustom(this, async () => { - await tearDownNodes(nwaku, waku); + await tearDownNodes(serviceNodes.nodes, waku); }); describe("Different clusters and shards", function () { @@ -44,20 +35,19 @@ describe("Static Sharding: Running Nodes", function () { const singleShardInfo = { clusterId: 0, shard: 0 }; const shardInfo = singleShardInfosToShardInfo([singleShardInfo]); - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - pubsubTopic: shardInfoToPubsubTopics(shardInfo) - }); - - await nwaku.ensureSubscriptions(shardInfoToPubsubTopics(shardInfo)); - - waku = await createLightNode({ - networkConfig: shardInfo - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfo, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: shardInfoToPubsubTopics(shardInfo) + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -71,33 +61,31 @@ describe("Static Sharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: shardInfoToPubsubTopics(shardInfo)[0] }) ).to.eq(true); }); - // dedicated test for Default Cluster ID 0 it("Cluster ID 0 - Default/Global Cluster", async function () { const singleShardInfo = { clusterId: 0, shard: 1 }; const shardInfo = singleShardInfosToShardInfo([singleShardInfo]); - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - pubsubTopic: shardInfoToPubsubTopics(shardInfo) - }); - - await nwaku.ensureSubscriptions(shardInfoToPubsubTopics(shardInfo)); - - waku = await createLightNode({ - networkConfig: shardInfo - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfo, + { + store: true, + lightpush: true, + relay: true, + pubsubTopic: shardInfoToPubsubTopics(shardInfo) + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -108,9 +96,9 @@ describe("Static Sharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: shardInfoToPubsubTopics(shardInfo)[0] }) ).to.eq(true); @@ -120,33 +108,29 @@ describe("Static Sharding: Running Nodes", function () { for (let i = 0; i < numTest; i++) { // Random clusterId between 2 and 1000 const clusterId = Math.floor(Math.random() * 999) + 2; - // Random shardId between 1 and 1000 const shardId = Math.floor(Math.random() * 1000) + 1; it(`random static sharding ${ i + 1 } - Cluster ID: ${clusterId}, Shard ID: ${shardId}`, async function () { - afterEach(async () => { - await tearDownNodes(nwaku, waku); - }); - const singleShardInfo = { clusterId: clusterId, shard: shardId }; const shardInfo = singleShardInfosToShardInfo([singleShardInfo]); - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: shardInfoToPubsubTopics(shardInfo) - }); - - waku = await createLightNode({ - networkConfig: shardInfo - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfo, + { + store: true, + lightpush: true, + relay: true, + clusterId: clusterId, + pubsubTopic: shardInfoToPubsubTopics(shardInfo) + }, + false, + 2, + true + ); const encoder = createEncoder({ contentTopic: ContentTopic, @@ -157,9 +141,9 @@ describe("Static Sharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - expect(request.successes.length).to.eq(1); + expect(request.successes.length).to.eq(2); expect( - await messageCollector.waitForMessages(1, { + await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: shardInfoToPubsubTopics(shardInfo)[0] }) ).to.eq(true); @@ -169,12 +153,14 @@ describe("Static Sharding: Running Nodes", function () { describe("Others", function () { const clusterId = 2; - let shardInfo: ShardInfo; - const shardInfoFirstShard: ShardInfo = { clusterId: clusterId, shards: [2] }; + const shardInfoSecondShard: ShardInfo = { + clusterId: clusterId, + shards: [3] + }; const shardInfoBothShards: ShardInfo = { clusterId: clusterId, shards: [2, 3] @@ -188,31 +174,21 @@ describe("Static Sharding: Running Nodes", function () { shard: 3 }; - beforeEachCustom(this, async () => { - shardInfo = { - clusterId: clusterId, - shards: [2] - }; - - await nwaku.start({ - store: true, - lightpush: true, - relay: true, - clusterId: clusterId, - pubsubTopic: shardInfoToPubsubTopics(shardInfo) - }); - }); - - afterEachCustom(this, async () => { - await tearDownNodes(nwaku, waku); - }); - - it("configure the node with multiple pubsub topics", async function () { - waku = await createLightNode({ - networkConfig: shardInfoBothShards - }); - await waku.dial(await nwaku.getMultiaddrWithId()); - await waku.waitForPeers([Protocols.LightPush]); + it.only("configure the node with multiple pubsub topics", async function () { + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfoBothShards, + { + store: true, + lightpush: true, + relay: true, + clusterId: clusterId, + pubsubTopic: shardInfoToPubsubTopics(shardInfoBothShards) + }, + false, + 2, + true + ); const encoder1 = createEncoder({ contentTopic: ContentTopic, @@ -227,29 +203,40 @@ describe("Static Sharding: Running Nodes", function () { const request1 = await waku.lightPush.send(encoder1, { payload: utf8ToBytes("Hello World2") }); - expect(request1.successes.length).to.eq(1); + expect(request1.successes.length).to.eq(2); expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: shardInfoToPubsubTopics(shardInfo)[0] + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: shardInfoToPubsubTopics(shardInfoFirstShard)[0] }) ).to.eq(true); const request2 = await waku.lightPush.send(encoder2, { payload: utf8ToBytes("Hello World3") }); - expect(request2.successes.length).to.eq(1); + expect(request2.successes.length).to.eq(2); expect( - await messageCollector.waitForMessages(1, { - pubsubTopic: shardInfoToPubsubTopics(shardInfo)[0] + await serviceNodes.messageCollector.waitForMessages(1, { + pubsubTopic: shardInfoToPubsubTopics(shardInfoSecondShard)[0] }) ).to.eq(true); }); it("using a protocol with unconfigured pubsub topic should fail", async function () { this.timeout(15_000); - waku = await createLightNode({ - networkConfig: shardInfoFirstShard - }); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + shardInfoFirstShard, + { + store: true, + lightpush: true, + relay: true, + clusterId: clusterId, + pubsubTopic: shardInfoToPubsubTopics(shardInfoFirstShard) + }, + false, + 2, + true + ); // use a pubsub topic that is not configured const encoder = createEncoder({ @@ -261,17 +248,17 @@ describe("Static Sharding: Running Nodes", function () { payload: utf8ToBytes("Hello World") }); - if (successes.length > 0 || failures?.length === 0) { + if (successes.length > 0 || !failures?.length) { throw new Error("The request should've thrown an error"); } - const errors = failures?.map((failure) => failure.error); + const errors = failures.map((failure) => failure.error); expect(errors).to.include(ProtocolError.TOPIC_NOT_CONFIGURED); }); it("start node with empty shard should fail", async function () { try { - waku = await createLightNode({ + await createLightNode({ networkConfig: { clusterId: clusterId, shards: [] } }); throw new Error( From 40c190ed9f70876d097fed07f899c976e8747ecd Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Mon, 20 Jan 2025 17:02:11 +0530 Subject: [PATCH 08/19] chore: update tests --- packages/tests/src/utils/nodes.ts | 20 +++++++++++-------- .../tests/tests/light-push/index.node.spec.ts | 16 +++++++-------- .../tests/sharding/static_sharding.spec.ts | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/tests/src/utils/nodes.ts b/packages/tests/src/utils/nodes.ts index c3e8cc7a9b..f6ceea680e 100644 --- a/packages/tests/src/utils/nodes.ts +++ b/packages/tests/src/utils/nodes.ts @@ -1,9 +1,9 @@ import { - CreateNodeOptions, DefaultNetworkConfig, IWaku, LightNode, NetworkConfig, + ProtocolCreateOptions, Protocols } from "@waku/interfaces"; import { createLightNode } from "@waku/sdk"; @@ -13,6 +13,7 @@ import pRetry from "p-retry"; import { NOISE_KEY_1 } from "../constants.js"; import { ServiceNodesFleet } from "../lib/index.js"; +import { verifyServiceNodesConnected } from "../lib/service_node.js"; import { Args } from "../types.js"; import { waitForConnections } from "./waitForConnections.js"; @@ -35,7 +36,9 @@ export async function runMultipleNodes( withoutFilter ); - const wakuOptions: CreateNodeOptions = { + await verifyServiceNodesConnected(serviceNodes.nodes); + + const wakuOptions: ProtocolCreateOptions = { staticNoiseKey: NOISE_KEY_1, libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } @@ -57,17 +60,18 @@ export async function runMultipleNodes( derivePubsubTopicsFromNetworkConfig(networkConfig) ); - const wakuConnections = waku.libp2p.getConnections(); - - if (wakuConnections.length < 1) { - throw new Error(`Expected at least 1 connection for js-waku.`); - } - await node.waitForLog(waku.libp2p.peerId.toString(), 100); } await waitForConnections(numServiceNodes, waku); + const wakuConnections = waku.libp2p.getConnections(); + if (wakuConnections.length < numServiceNodes) { + throw new Error( + `Expected at least ${numServiceNodes} connections for js-waku.` + ); + } + return [serviceNodes, waku]; } diff --git a/packages/tests/tests/light-push/index.node.spec.ts b/packages/tests/tests/light-push/index.node.spec.ts index d9bc508bc5..9ddd500481 100644 --- a/packages/tests/tests/light-push/index.node.spec.ts +++ b/packages/tests/tests/light-push/index.node.spec.ts @@ -50,7 +50,7 @@ const runTests = (strictNodeCheck: boolean): void => { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes(testItem.value) }); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -73,7 +73,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(generateMessageText(i)) }); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); } expect( @@ -119,7 +119,7 @@ const runTests = (strictNodeCheck: boolean): void => { customEncoder, messagePayload ); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -156,7 +156,7 @@ const runTests = (strictNodeCheck: boolean): void => { customTestEncoder, messagePayload ); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -190,7 +190,7 @@ const runTests = (strictNodeCheck: boolean): void => { ); if (serviceNodes.type == "go-waku") { - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: TestPubsubTopic @@ -229,7 +229,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(messageText), rateLimitProof: rateLimitProof }); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -253,7 +253,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(messageText), timestamp: new Date(testItem) }); - expect(pushResponse.successes.length).to.eq(numServiceNodes); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -274,7 +274,7 @@ const runTests = (strictNodeCheck: boolean): void => { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: bigPayload }); - expect(pushResponse.successes.length).to.greaterThan(0); + expect(pushResponse.successes.length).to.greaterThanOrEqual(1); }); it("Fails to push message bigger that 1MB", async function () { diff --git a/packages/tests/tests/sharding/static_sharding.spec.ts b/packages/tests/tests/sharding/static_sharding.spec.ts index c2151d9d01..066c0c6324 100644 --- a/packages/tests/tests/sharding/static_sharding.spec.ts +++ b/packages/tests/tests/sharding/static_sharding.spec.ts @@ -174,7 +174,7 @@ describe("Static Sharding: Running Nodes", function () { shard: 3 }; - it.only("configure the node with multiple pubsub topics", async function () { + it("configure the node with multiple pubsub topics", async function () { [serviceNodes, waku] = await runMultipleNodes( this.ctx, shardInfoBothShards, From 5774a1559076f75fcf7c3eae90de4905991b0f97 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Mon, 20 Jan 2025 17:32:49 +0530 Subject: [PATCH 09/19] chore: improve Docker network config reliability --- packages/tests/src/lib/dockerode.ts | 22 +++++++++++++--------- packages/tests/src/lib/service_node.ts | 17 +++++++++++++++++ packages/tests/src/utils/nodes.ts | 4 +++- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/packages/tests/src/lib/dockerode.ts b/packages/tests/src/lib/dockerode.ts index 2428b67cb9..5aa8e2db22 100644 --- a/packages/tests/src/lib/dockerode.ts +++ b/packages/tests/src/lib/dockerode.ts @@ -107,6 +107,7 @@ export default class Dockerode { const container = await this.docker.createContainer({ Image: this.IMAGE_NAME, HostConfig: { + NetworkMode: NETWORK_NAME, AutoRemove: true, PortBindings: { [`${restPort}/tcp`]: [{ HostPort: restPort.toString() }], @@ -116,6 +117,8 @@ export default class Dockerode { [`${discv5UdpPort}/udp`]: [{ HostPort: discv5UdpPort.toString() }] }) }, + Dns: ["8.8.8.8"], + Links: [], Mounts: args.rlnRelayEthClientAddress ? [ { @@ -135,18 +138,19 @@ export default class Dockerode { [`${discv5UdpPort}/udp`]: {} }) }, - Cmd: argsArrayWithIP - }); - await container.start(); - - await Dockerode.network.connect({ - Container: container.id, - EndpointConfig: { - IPAMConfig: { - IPv4Address: this.containerIp + Cmd: argsArrayWithIP, + NetworkingConfig: { + EndpointsConfig: { + [NETWORK_NAME]: { + IPAMConfig: { + IPv4Address: this.containerIp + } + } } } }); + await container.start(); + const logStream = fs.createWriteStream(logPath); container.logs( diff --git a/packages/tests/src/lib/service_node.ts b/packages/tests/src/lib/service_node.ts index 10eb5a37ea..baa905762a 100644 --- a/packages/tests/src/lib/service_node.ts +++ b/packages/tests/src/lib/service_node.ts @@ -431,3 +431,20 @@ interface RpcInfoResponse { listenAddresses: string[]; enrUri?: string; } + +export async function verifyServiceNodesConnected( + nodes: ServiceNode[] +): Promise { + for (const node of nodes) { + const peers = await node.peers(); + log.info(`Service node ${node.containerName} peers:`, peers.length); + log.info(`Service node ${node.containerName} peers:`, peers); + + if (nodes.length > 1 && peers.length === 0) { + log.error(`Service node ${node.containerName} has no peers connected`); + throw new Error( + `Service node ${node.containerName} has no peers connected` + ); + } + } +} diff --git a/packages/tests/src/utils/nodes.ts b/packages/tests/src/utils/nodes.ts index f6ceea680e..2318c80521 100644 --- a/packages/tests/src/utils/nodes.ts +++ b/packages/tests/src/utils/nodes.ts @@ -36,7 +36,9 @@ export async function runMultipleNodes( withoutFilter ); - await verifyServiceNodesConnected(serviceNodes.nodes); + if (numServiceNodes > 1) { + await verifyServiceNodesConnected(serviceNodes.nodes); + } const wakuOptions: ProtocolCreateOptions = { staticNoiseKey: NOISE_KEY_1, From 37686f736eafb0c88ab91fcbb5a4a96e787ba04c Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 22 Jan 2025 17:40:38 +0530 Subject: [PATCH 10/19] chore: deduplicate ecies encrypted payloads --- packages/tests/src/lib/index.ts | 17 ++++++++++++++++- .../tests/tests/filter/subscribe.node.spec.ts | 3 +-- .../tests/tests/sharding/auto_sharding.spec.ts | 1 - 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index 2a5c02acdf..d549d00d90 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -111,7 +111,16 @@ export class ServiceNodesFleet { return relayMessages.every((message) => message); } - public async confirmMessageLength(numMessages: number): Promise { + public async confirmMessageLength( + numMessages: number, + { encryptedPayload }: { encryptedPayload?: boolean } = { + encryptedPayload: false + } + ): Promise { + if (encryptedPayload) { + expect(this.messageCollector.count).to.equal(numMessages); + } + if (this.strictChecking) { await Promise.all( this.nodes.map(async (node) => @@ -144,6 +153,12 @@ class MultipleNodesMessageCollector { ) { this.callback = (msg: DecodedMessage): void => { log.info("Got a message"); + if ( + this.messageList.find( + (m) => m.payload.toString() === msg.payload.toString() + ) + ) + return; this.messageList.push(msg); }; } diff --git a/packages/tests/tests/filter/subscribe.node.spec.ts b/packages/tests/tests/filter/subscribe.node.spec.ts index af281c039c..88bf921c74 100644 --- a/packages/tests/tests/filter/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/subscribe.node.spec.ts @@ -102,8 +102,7 @@ const runTests = (strictCheckNodes: boolean): void => { expectedVersion: 1, expectedPubsubTopic: TestPubsubTopic }); - - await serviceNodes.confirmMessageLength(1); + await serviceNodes.confirmMessageLength(1, { encryptedPayload: true }); }); it("Subscribe and receive symmetrically encrypted messages via lightPush", async function () { diff --git a/packages/tests/tests/sharding/auto_sharding.spec.ts b/packages/tests/tests/sharding/auto_sharding.spec.ts index 3d2f4cebf0..37410df49d 100644 --- a/packages/tests/tests/sharding/auto_sharding.spec.ts +++ b/packages/tests/tests/sharding/auto_sharding.spec.ts @@ -61,7 +61,6 @@ describe("Autosharding: Running Nodes", function () { }); expect(request.successes.length).to.eq(2); // Expect 2 successes for 2 nodes - console.log("good"); expect( await serviceNodes.messageCollector.waitForMessagesAutosharding(1, { contentTopic: ContentTopic From 54ad1412f9196b9d11dd0af341e6a4950db7cf2d Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 22 Jan 2025 17:55:13 +0530 Subject: [PATCH 11/19] chore: update to precise expects --- .../tests/tests/light-push/index.node.spec.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/tests/tests/light-push/index.node.spec.ts b/packages/tests/tests/light-push/index.node.spec.ts index 9ddd500481..0a2e8bc611 100644 --- a/packages/tests/tests/light-push/index.node.spec.ts +++ b/packages/tests/tests/light-push/index.node.spec.ts @@ -50,7 +50,7 @@ const runTests = (strictNodeCheck: boolean): void => { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes(testItem.value) }); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -73,7 +73,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(generateMessageText(i)) }); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); } expect( @@ -119,7 +119,7 @@ const runTests = (strictNodeCheck: boolean): void => { customEncoder, messagePayload ); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -156,7 +156,7 @@ const runTests = (strictNodeCheck: boolean): void => { customTestEncoder, messagePayload ); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -190,7 +190,7 @@ const runTests = (strictNodeCheck: boolean): void => { ); if (serviceNodes.type == "go-waku") { - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { pubsubTopic: TestPubsubTopic @@ -229,7 +229,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(messageText), rateLimitProof: rateLimitProof }); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -253,7 +253,7 @@ const runTests = (strictNodeCheck: boolean): void => { payload: utf8ToBytes(messageText), timestamp: new Date(testItem) }); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); expect( await serviceNodes.messageCollector.waitForMessages(1, { @@ -274,7 +274,7 @@ const runTests = (strictNodeCheck: boolean): void => { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: bigPayload }); - expect(pushResponse.successes.length).to.greaterThanOrEqual(1); + expect(pushResponse.successes.length).to.equal(numServiceNodes); }); it("Fails to push message bigger that 1MB", async function () { From b702aa039bdb5ef8e237bee1d70671c518d63cb3 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 22 Jan 2025 18:01:04 +0530 Subject: [PATCH 12/19] fix: return early if expect passes --- packages/tests/src/lib/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index d549d00d90..8f514cc61f 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -119,6 +119,7 @@ export class ServiceNodesFleet { ): Promise { if (encryptedPayload) { expect(this.messageCollector.count).to.equal(numMessages); + return; } if (this.strictChecking) { @@ -153,13 +154,14 @@ class MultipleNodesMessageCollector { ) { this.callback = (msg: DecodedMessage): void => { log.info("Got a message"); + // Only add message if we haven't seen it before if ( - this.messageList.find( + !this.messageList.find( (m) => m.payload.toString() === msg.payload.toString() ) - ) - return; - this.messageList.push(msg); + ) { + this.messageList.push(msg); + } }; } From f7832d0b71699c73f0d66c7b9a6d7e64699e7cf9 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 22 Jan 2025 18:15:34 +0530 Subject: [PATCH 13/19] chore: lightpush 5 times instead of 30 --- packages/tests/tests/light-push/index.node.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/tests/tests/light-push/index.node.spec.ts b/packages/tests/tests/light-push/index.node.spec.ts index 0a2e8bc611..060a283982 100644 --- a/packages/tests/tests/light-push/index.node.spec.ts +++ b/packages/tests/tests/light-push/index.node.spec.ts @@ -65,24 +65,24 @@ const runTests = (strictNodeCheck: boolean): void => { }); }); - it("Push 30 different messages", async function () { + it("Push 5 different messages", async function () { const generateMessageText = (index: number): string => `M${index}`; - for (let i = 0; i < 30; i++) { + for (let i = 0; i < 5; i++) { const pushResponse = await waku.lightPush.send(TestEncoder, { payload: utf8ToBytes(generateMessageText(i)) }); - + if (pushResponse.failures.length > 0) console.log(i + 1); expect(pushResponse.successes.length).to.equal(numServiceNodes); } expect( - await serviceNodes.messageCollector.waitForMessages(30, { + await serviceNodes.messageCollector.waitForMessages(5, { pubsubTopic: TestPubsubTopic }) ).to.eq(true); - for (let i = 0; i < 30; i++) { + for (let i = 0; i < 5; i++) { serviceNodes.messageCollector.verifyReceivedMessage(i, { expectedMessageText: generateMessageText(i), expectedContentTopic: TestContentTopic, From 055105d2f83b597c8b7d427a3d174d33571bbb78 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Wed, 22 Jan 2025 18:29:04 +0530 Subject: [PATCH 14/19] fix: non duplicacy should happen in application-specific scenario --- packages/tests/src/lib/index.ts | 20 +++++++++---------- .../tests/tests/filter/subscribe.node.spec.ts | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index 8f514cc61f..f9339ae085 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -118,7 +118,14 @@ export class ServiceNodesFleet { } ): Promise { if (encryptedPayload) { - expect(this.messageCollector.count).to.equal(numMessages); + const filteredMessageList = Array.from( + new Set( + this.messageCollector.messageList + .filter((msg) => msg.payload?.toString) + .map((msg) => msg.payload.toString()) + ) + ); + expect(filteredMessageList.length).to.equal(numMessages); return; } @@ -146,7 +153,7 @@ export class ServiceNodesFleet { class MultipleNodesMessageCollector { public callback: (msg: DecodedMessage) => void = () => {}; - protected messageList: Array = []; + public readonly messageList: Array = []; public constructor( private messageCollectors: MessageCollector[], private relayNodes?: ServiceNode[], @@ -154,14 +161,7 @@ class MultipleNodesMessageCollector { ) { this.callback = (msg: DecodedMessage): void => { log.info("Got a message"); - // Only add message if we haven't seen it before - if ( - !this.messageList.find( - (m) => m.payload.toString() === msg.payload.toString() - ) - ) { - this.messageList.push(msg); - } + this.messageList.push(msg); }; } diff --git a/packages/tests/tests/filter/subscribe.node.spec.ts b/packages/tests/tests/filter/subscribe.node.spec.ts index 88bf921c74..8098fd6745 100644 --- a/packages/tests/tests/filter/subscribe.node.spec.ts +++ b/packages/tests/tests/filter/subscribe.node.spec.ts @@ -135,7 +135,7 @@ const runTests = (strictCheckNodes: boolean): void => { expectedPubsubTopic: TestPubsubTopic }); - await serviceNodes.confirmMessageLength(1); + await serviceNodes.confirmMessageLength(1, { encryptedPayload: true }); }); it("Subscribe and receive messages via waku relay post", async function () { From 9d1edb52725d3f585b192f9dd709fee5eb31d3dd Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Thu, 23 Jan 2025 14:25:10 +0530 Subject: [PATCH 15/19] chore: update mocha config + fix epehermal tests --- packages/tests/.mocharc.cjs | 2 +- packages/tests/src/run-tests.js | 9 +++ packages/tests/tests/ephemeral.node.spec.ts | 89 ++++++++++++--------- 3 files changed, 59 insertions(+), 41 deletions(-) diff --git a/packages/tests/.mocharc.cjs b/packages/tests/.mocharc.cjs index 78120b5e32..4ec6dca000 100644 --- a/packages/tests/.mocharc.cjs +++ b/packages/tests/.mocharc.cjs @@ -7,7 +7,7 @@ const config = { 'loader=ts-node/esm' ], exit: true, - retries: 4 + retries: 2 }; if (process.env.CI) { diff --git a/packages/tests/src/run-tests.js b/packages/tests/src/run-tests.js index 857bc09876..c8a558d115 100644 --- a/packages/tests/src/run-tests.js +++ b/packages/tests/src/run-tests.js @@ -78,6 +78,15 @@ async function main() { mocha.on("exit", (code) => { console.log(`Mocha tests exited with code ${code}`); + try { + execAsync( + `docker ps -q -f "ancestor=${WAKUNODE_IMAGE}" | xargs -r docker stop` + ).catch((error) => { + console.error("Error cleaning up containers:", error); + }); + } catch (error) { + console.error("Error cleaning up containers:", error); + } process.exit(code || 0); }); } diff --git a/packages/tests/tests/ephemeral.node.spec.ts b/packages/tests/tests/ephemeral.node.spec.ts index 2abed950d2..cfd8467231 100644 --- a/packages/tests/tests/ephemeral.node.spec.ts +++ b/packages/tests/tests/ephemeral.node.spec.ts @@ -23,11 +23,11 @@ import { afterEachCustom, beforeEachCustom, delay, - makeLogFileName, NOISE_KEY_1, NOISE_KEY_2, - ServiceNode, - tearDownNodes + runMultipleNodes, + ServiceNodesFleet, + teardownNodesWithRedundancy } from "../src/index.js"; const log = new Logger("test:ephemeral"); @@ -76,41 +76,39 @@ const SymDecoder = createSymDecoder(SymContentTopic, symKey, PubsubTopic); describe("Waku Message Ephemeral field", function () { let waku: LightNode; - let nwaku: ServiceNode; + let serviceNodes: ServiceNodesFleet; afterEachCustom(this, async () => { - await tearDownNodes(nwaku, waku); + await teardownNodesWithRedundancy(serviceNodes, waku); }); beforeEachCustom(this, async () => { - nwaku = new ServiceNode(makeLogFileName(this.ctx)); - await nwaku.start({ - filter: true, - lightpush: true, - store: true, - relay: true, - pubsubTopic: [PubsubTopic], - contentTopic: [TestContentTopic, AsymContentTopic, SymContentTopic], - clusterId: ClusterId - }); - await nwaku.ensureSubscriptionsAutosharding([ - TestContentTopic, - AsymContentTopic, - SymContentTopic - ]); - - waku = await createLightNode({ - staticNoiseKey: NOISE_KEY_1, - libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } }, - networkConfig: { - contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic], - clusterId: ClusterId - } - }); - await waku.start(); - await waku.dial(await nwaku.getMultiaddrWithId()); + [serviceNodes, waku] = await runMultipleNodes( + this.ctx, + { + clusterId: ClusterId, + contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic] + }, + { + filter: true, + lightpush: true, + store: true, + relay: true, + pubsubTopic: [PubsubTopic] + }, + true, + 2 + ); - await waku.waitForPeers([Protocols.Filter, Protocols.LightPush]); + await Promise.all( + serviceNodes.nodes.map(async (node) => { + await node.ensureSubscriptionsAutosharding([ + TestContentTopic, + AsymContentTopic, + SymContentTopic + ]); + }) + ); }); it("Ephemeral messages are not stored", async function () { @@ -130,7 +128,7 @@ describe("Waku Message Ephemeral field", function () { payload: utf8ToBytes(clearText) }; - const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([ + const [waku1, waku2] = await Promise.all([ createLightNode({ staticNoiseKey: NOISE_KEY_1, networkConfig: { @@ -144,16 +142,18 @@ describe("Waku Message Ephemeral field", function () { contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic], clusterId: ClusterId } - }).then((waku) => waku.start().then(() => waku)), - nwaku.getMultiaddrWithId() + }).then((waku) => waku.start().then(() => waku)) ]); log.info("Waku nodes created"); - await Promise.all([ - waku1.dial(nimWakuMultiaddr), - waku2.dial(nimWakuMultiaddr) - ]); + await Promise.all( + serviceNodes.nodes.map(async (node) => { + const multiaddr = await node.getMultiaddrWithId(); + await waku1.dial(multiaddr); + await waku2.dial(multiaddr); + }) + ); log.info("Waku nodes connected to nwaku"); @@ -186,7 +186,16 @@ describe("Waku Message Ephemeral field", function () { expect(messages?.length).eq(0); - await tearDownNodes([], [waku1, waku2]); + const additionalServiceNodes = await ServiceNodesFleet.createAndRun( + this.ctx, + 0, + false, + { + clusterId: ClusterId, + contentTopics: [TestContentTopic, AsymContentTopic, SymContentTopic] + } + ); + await teardownNodesWithRedundancy(additionalServiceNodes, [waku1, waku2]); }); it("Ephemeral field is preserved - encoder v0", async function () { From bfb5dfff5df1e2ebe4339a79623174e45336253e Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Tue, 28 Jan 2025 15:14:42 +0530 Subject: [PATCH 16/19] chore: reinstall deps after rebase From 6680e0c78b507fa1d32ad9f5ace01cfbefe66f3a Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 31 Jan 2025 17:55:48 +0530 Subject: [PATCH 17/19] chore: attempt stability for test suite --- .github/workflows/test-node.yml | 1 + packages/tests/.mocharc.cjs | 10 +-- packages/tests/src/lib/index.ts | 22 ++++--- packages/tests/src/utils/nodes.ts | 4 +- packages/tests/src/utils/teardown.ts | 66 +++++++++++-------- .../tests/tests/dns-peer-discovery.spec.ts | 2 +- packages/tests/tests/store/index.node.spec.ts | 3 - 7 files changed, 63 insertions(+), 45 deletions(-) diff --git a/.github/workflows/test-node.yml b/.github/workflows/test-node.yml index 21cc501ddc..a59c5bb9c3 100644 --- a/.github/workflows/test-node.yml +++ b/.github/workflows/test-node.yml @@ -28,6 +28,7 @@ env: jobs: node: runs-on: ubuntu-latest + timeout-minutes: 60 # Add a 1-hour timeout to fail faster env: WAKUNODE_IMAGE: ${{ inputs.nim_wakunode_image }} permissions: diff --git a/packages/tests/.mocharc.cjs b/packages/tests/.mocharc.cjs index 4ec6dca000..4b7c9d771f 100644 --- a/packages/tests/.mocharc.cjs +++ b/packages/tests/.mocharc.cjs @@ -7,15 +7,17 @@ const config = { 'loader=ts-node/esm' ], exit: true, - retries: 2 + retries: 2, + timeout: 150_000 }; if (process.env.CI) { console.log("Running tests in parallel"); config.parallel = true; - config.jobs = 6; - console.log("Using JSON reporter for test results"); - config.reporter = 'json'; + config.jobs = 4; + config.timeout = 1800000; + console.log("Using multi reporters for test results"); + config.reporter = 'mocha-multi-reporters'; config.reporterOptions = { output: 'reports/mocha-results.json' }; diff --git a/packages/tests/src/lib/index.ts b/packages/tests/src/lib/index.ts index f9339ae085..03b6c46182 100644 --- a/packages/tests/src/lib/index.ts +++ b/packages/tests/src/lib/index.ts @@ -237,6 +237,7 @@ class MultipleNodesMessageCollector { const startTime = Date.now(); const pubsubTopic = options?.pubsubTopic || DefaultTestPubsubTopic; const timeoutDuration = options?.timeoutDuration || 400; + const maxTimeout = Math.min(timeoutDuration * numMessages, 30000); const exact = options?.exact || false; while (this.messageList.length < numMessages) { @@ -248,7 +249,9 @@ class MultipleNodesMessageCollector { return msgs.length >= numMessages; }) ); - return results.every((result) => result); + if (results.every((result) => result)) { + return true; + } } else { const results = await Promise.all( this.relayNodes.map(async (node) => { @@ -256,16 +259,19 @@ class MultipleNodesMessageCollector { return msgs.length >= numMessages; }) ); - return results.some((result) => result); + if (results.some((result) => result)) { + return true; + } } - } - const elapsed = Date.now() - startTime; - if (elapsed > timeoutDuration * numMessages) { - return false; - } + const elapsed = Date.now() - startTime; + if (elapsed > maxTimeout) { + log.warn(`Timeout waiting for messages after ${elapsed}ms`); + return false; + } - await delay(10); + await delay(10); + } } if (exact) { diff --git a/packages/tests/src/utils/nodes.ts b/packages/tests/src/utils/nodes.ts index 2318c80521..623c3d54a2 100644 --- a/packages/tests/src/utils/nodes.ts +++ b/packages/tests/src/utils/nodes.ts @@ -1,9 +1,9 @@ import { + CreateNodeOptions, DefaultNetworkConfig, IWaku, LightNode, NetworkConfig, - ProtocolCreateOptions, Protocols } from "@waku/interfaces"; import { createLightNode } from "@waku/sdk"; @@ -40,7 +40,7 @@ export async function runMultipleNodes( await verifyServiceNodesConnected(serviceNodes.nodes); } - const wakuOptions: ProtocolCreateOptions = { + const wakuOptions: CreateNodeOptions = { staticNoiseKey: NOISE_KEY_1, libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } diff --git a/packages/tests/src/utils/teardown.ts b/packages/tests/src/utils/teardown.ts index 86257ceb41..a4fc2573b2 100644 --- a/packages/tests/src/utils/teardown.ts +++ b/packages/tests/src/utils/teardown.ts @@ -6,6 +6,8 @@ import { ServiceNode } from "../lib/service_node.js"; const log = new Logger("test:teardown"); +const TEARDOWN_TIMEOUT = 10000; // 10 seconds timeout for teardown + export async function tearDownNodes( nwakuNodes: ServiceNode | ServiceNode[], wakuNodes: IWaku | IWaku[] @@ -13,37 +15,47 @@ export async function tearDownNodes( const nNodes = Array.isArray(nwakuNodes) ? nwakuNodes : [nwakuNodes]; const wNodes = Array.isArray(wakuNodes) ? wakuNodes : [wakuNodes]; - const stopNwakuNodes = nNodes.map(async (nwaku) => { - if (nwaku) { - await pRetry( - async () => { - try { - await nwaku.stop(); - } catch (error) { - log.error("Nwaku failed to stop:", error); - throw error; - } - }, - { retries: 3 } - ); - } - }); - - const stopWakuNodes = wNodes.map(async (waku) => { - if (waku) { - await pRetry( - async () => { + try { + // Use Promise.race to implement timeout + const teardownPromise = Promise.all([ + ...nNodes.map(async (nwaku) => { + if (nwaku) { + await pRetry( + async () => { + try { + await nwaku.stop(); + } catch (error) { + log.error("Nwaku failed to stop:", error); + throw error; + } + }, + { retries: 3, minTimeout: 1000 } + ); + } + }), + ...wNodes.map(async (waku) => { + if (waku) { try { await waku.stop(); } catch (error) { log.error("Waku failed to stop:", error); - throw error; } - }, - { retries: 3 } - ); - } - }); + } + }) + ]); - await Promise.all([...stopNwakuNodes, ...stopWakuNodes]); + await Promise.race([ + teardownPromise, + new Promise((_, reject) => + setTimeout( + () => reject(new Error("Teardown timeout")), + TEARDOWN_TIMEOUT + ) + ) + ]); + } catch (error) { + log.error("Teardown failed:", error); + // Force process cleanup if needed + process.exit(1); + } } diff --git a/packages/tests/tests/dns-peer-discovery.spec.ts b/packages/tests/tests/dns-peer-discovery.spec.ts index ad3ab013db..e05d97fe8c 100644 --- a/packages/tests/tests/dns-peer-discovery.spec.ts +++ b/packages/tests/tests/dns-peer-discovery.spec.ts @@ -56,7 +56,7 @@ describe("DNS Node Discovery [live data]", function () { }); it(`should use DNS peer discovery with light client`, async function () { - this.timeout(100000); + this.timeout(100_000); const maxQuantity = 3; const nodeRequirements = { diff --git a/packages/tests/tests/store/index.node.spec.ts b/packages/tests/tests/store/index.node.spec.ts index d9a055fb3e..c95acffc86 100644 --- a/packages/tests/tests/store/index.node.spec.ts +++ b/packages/tests/tests/store/index.node.spec.ts @@ -304,13 +304,10 @@ describe("Waku Store, general", function () { for await (const msg of query) { if (msg) { messages.push(msg as DecodedMessage); - console.log(bytesToUtf8(msg.payload!)); } } } - console.log(messages.length); - // Messages are ordered from oldest to latest within a page (1 page query) expect(bytesToUtf8(messages[0].payload!)).to.eq(asymText); expect(bytesToUtf8(messages[1].payload!)).to.eq(symText); From 6be02e21900d1957fa3187dc79284f1b94bb9321 Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 31 Jan 2025 18:00:33 +0530 Subject: [PATCH 18/19] chore: add mocha-multi-reporters --- package-lock.json | 18 ++++++++++++++++++ package.json | 1 + 2 files changed, 19 insertions(+) diff --git a/package-lock.json b/package-lock.json index 4aff4d781a..f8dbd377f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "karma-webkit-launcher": "^2.4.0", "karma-webpack": "github:codymikol/karma-webpack#2337a82beb078c0d8e25ae8333a06249b8e72828", "lint-staged": "^15.4.3", + "mocha-multi-reporters": "^1.5.1", "playwright": "^1.40.1", "size-limit": "^11.0.1", "ts-loader": "^9.5.1", @@ -26336,6 +26337,23 @@ "node": ">= 14.0.0" } }, + "node_modules/mocha-multi-reporters": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz", + "integrity": "sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "mocha": ">=3.1.2" + } + }, "node_modules/mocha/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", diff --git a/package.json b/package.json index 2bfb2b3cc3..8c428aa6bc 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "karma-webkit-launcher": "^2.4.0", "karma-webpack": "github:codymikol/karma-webpack#2337a82beb078c0d8e25ae8333a06249b8e72828", "lint-staged": "^15.4.3", + "mocha-multi-reporters": "^1.5.1", "playwright": "^1.40.1", "size-limit": "^11.0.1", "ts-loader": "^9.5.1", From 27267e0537722593598c87679747078a9aaae5ce Mon Sep 17 00:00:00 2001 From: Danish Arora Date: Fri, 31 Jan 2025 18:05:00 +0530 Subject: [PATCH 19/19] chore: fix reporting --- .github/workflows/test-node.yml | 3 +++ packages/tests/.mocharc.cjs | 9 ++++++++- packages/tests/reporter-config.json | 6 ++++++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 packages/tests/reporter-config.json diff --git a/.github/workflows/test-node.yml b/.github/workflows/test-node.yml index a59c5bb9c3..df226ad4d7 100644 --- a/.github/workflows/test-node.yml +++ b/.github/workflows/test-node.yml @@ -48,6 +48,9 @@ jobs: - run: npm run build:esm + - name: Create reports directory + run: mkdir -p packages/tests/reports + - run: ${{ (inputs.test_type == 'node-optional') && 'npm run test:optional --workspace=@waku/tests' || 'npm run test:node' }} - name: Test Report diff --git a/packages/tests/.mocharc.cjs b/packages/tests/.mocharc.cjs index 4b7c9d771f..3b621a82aa 100644 --- a/packages/tests/.mocharc.cjs +++ b/packages/tests/.mocharc.cjs @@ -19,8 +19,15 @@ if (process.env.CI) { console.log("Using multi reporters for test results"); config.reporter = 'mocha-multi-reporters'; config.reporterOptions = { - output: 'reports/mocha-results.json' + configFile: 'reporter-config.json' }; + // Ensure reports directory exists + const fs = require('fs'); + const path = require('path'); + const reportsDir = path.join(__dirname, 'reports'); + if (!fs.existsSync(reportsDir)){ + fs.mkdirSync(reportsDir, { recursive: true }); + } } else { console.log("Running tests serially. To enable parallel execution update mocha config"); } diff --git a/packages/tests/reporter-config.json b/packages/tests/reporter-config.json new file mode 100644 index 0000000000..b374d6ecf4 --- /dev/null +++ b/packages/tests/reporter-config.json @@ -0,0 +1,6 @@ +{ + "reporterEnabled": "spec, json", + "jsonReporter": { + "output": "reports/mocha-results.json" + } +} \ No newline at end of file