mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-09 01:03:11 +00:00
feat: add command to test dev env
This commit is contained in:
parent
d2699e3326
commit
9e34309316
@ -167,6 +167,9 @@ try {
|
||||
const isPublished = __dirname.includes("dist");
|
||||
const cmdPrefix = isPublished ? "npx @waku/run" : "npm run";
|
||||
|
||||
process.stdout.write(
|
||||
` ${colors.cyan}${cmdPrefix} test${colors.reset} - Test network with a message\n`
|
||||
);
|
||||
process.stdout.write(
|
||||
` ${colors.cyan}${cmdPrefix} logs${colors.reset} - View logs\n`
|
||||
);
|
||||
|
||||
118
packages/run/scripts/test.ts
Normal file
118
packages/run/scripts/test.ts
Normal file
@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execSync } from "child_process";
|
||||
import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
import { Protocols } from "@waku/sdk";
|
||||
|
||||
import { WakuTestClient } from "../src/test-client.js";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
// In development: scripts are in packages/run/scripts
|
||||
// In published package: scripts are in node_modules/@waku/run/dist/scripts
|
||||
const packageRoot = __dirname.includes("dist")
|
||||
? join(__dirname, "..", "..")
|
||||
: join(__dirname, "..");
|
||||
|
||||
interface Colors {
|
||||
reset: string;
|
||||
cyan: string;
|
||||
green: string;
|
||||
red: string;
|
||||
yellow: string;
|
||||
}
|
||||
|
||||
// ANSI color codes
|
||||
const colors: Colors = {
|
||||
reset: "\x1b[0m",
|
||||
cyan: "\x1b[36m",
|
||||
green: "\x1b[32m",
|
||||
red: "\x1b[31m",
|
||||
yellow: "\x1b[33m"
|
||||
};
|
||||
|
||||
async function main(): Promise<void> {
|
||||
let client: WakuTestClient | null = null;
|
||||
|
||||
try {
|
||||
// Check if containers are running
|
||||
const output: string = execSync("docker compose ps --quiet", {
|
||||
cwd: packageRoot,
|
||||
encoding: "utf-8"
|
||||
}).trim();
|
||||
|
||||
if (!output) {
|
||||
process.stderr.write(
|
||||
`${colors.red}✗${colors.reset} No nodes running. Start with: ${colors.cyan}npx @waku/run start${colors.reset}\n`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.stdout.write(
|
||||
`${colors.cyan}Testing local Waku network...${colors.reset}\n\n`
|
||||
);
|
||||
|
||||
// Step 1: Create client
|
||||
process.stdout.write(
|
||||
`${colors.cyan}→${colors.reset} Creating Waku light node...\n`
|
||||
);
|
||||
client = new WakuTestClient();
|
||||
|
||||
// Step 2: Start and connect
|
||||
process.stdout.write(`${colors.cyan}→${colors.reset} Starting node...\n`);
|
||||
await client.start();
|
||||
|
||||
// Step 3: Wait for peers
|
||||
process.stdout.write(
|
||||
`${colors.cyan}→${colors.reset} Waiting for peers...\n`
|
||||
);
|
||||
await client.waku!.waitForPeers([Protocols.LightPush]);
|
||||
const connectedPeers = client.waku!.libp2p.getPeers().length;
|
||||
process.stdout.write(
|
||||
`${colors.green}✓${colors.reset} Connected to ${connectedPeers} peer(s)\n`
|
||||
);
|
||||
|
||||
// Step 4: Send test message
|
||||
process.stdout.write(
|
||||
`${colors.cyan}→${colors.reset} Sending lightpush message...\n`
|
||||
);
|
||||
const result = await client.sendTestMessage("Test from @waku/run");
|
||||
|
||||
if (result.success) {
|
||||
process.stdout.write(
|
||||
`${colors.green}✓${colors.reset} Message sent successfully to ${result.messagesSent} peer(s)\n`
|
||||
);
|
||||
process.stdout.write(
|
||||
`\n${colors.green}✓ All tests passed!${colors.reset}\n`
|
||||
);
|
||||
process.stdout.write(
|
||||
`${colors.cyan}The local Waku network is working correctly.${colors.reset}\n`
|
||||
);
|
||||
} else {
|
||||
process.stderr.write(
|
||||
`${colors.red}✗${colors.reset} Failed to send message: ${result.error || "Unknown error"}\n`
|
||||
);
|
||||
process.stderr.write(
|
||||
` Sent: ${result.messagesSent}, Failed: ${result.failures}\n`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const err = error as { message?: string };
|
||||
process.stderr.write(
|
||||
`${colors.red}✗${colors.reset} Test failed: ${err.message || String(error)}\n`
|
||||
);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
if (client) {
|
||||
await client.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
process.stderr.write(`Unexpected error: ${String(error)}\n`);
|
||||
process.exit(1);
|
||||
});
|
||||
@ -13,7 +13,8 @@ const scriptMap: Record<string, string> = {
|
||||
start: join(__dirname, "..", "scripts", "start.js"),
|
||||
stop: join(__dirname, "..", "scripts", "stop.js"),
|
||||
info: join(__dirname, "..", "scripts", "info.js"),
|
||||
logs: join(__dirname, "..", "scripts", "logs.js")
|
||||
logs: join(__dirname, "..", "scripts", "logs.js"),
|
||||
test: join(__dirname, "..", "scripts", "test.js")
|
||||
};
|
||||
|
||||
if (!command || !scriptMap[command]) {
|
||||
@ -24,6 +25,7 @@ if (!command || !scriptMap[command]) {
|
||||
process.stderr.write(" stop Stop the local Waku network\n");
|
||||
process.stderr.write(" info Show connection info for running network\n");
|
||||
process.stderr.write(" logs View logs from running network\n");
|
||||
process.stderr.write(" test Test the network by sending a message\n");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
116
packages/run/src/test-client.ts
Normal file
116
packages/run/src/test-client.ts
Normal file
@ -0,0 +1,116 @@
|
||||
import { createEncoder } from "@waku/core";
|
||||
import type { LightNode } from "@waku/interfaces";
|
||||
import { createLightNode } from "@waku/sdk";
|
||||
import { createRoutingInfo } from "@waku/utils";
|
||||
|
||||
import { NODE1_PEER_ID, NODE2_PEER_ID } from "./constants.js";
|
||||
|
||||
export interface WakuTestClientOptions {
|
||||
node1Port?: string;
|
||||
node2Port?: string;
|
||||
clusterId?: number;
|
||||
numShardsInCluster?: number;
|
||||
contentTopic?: string;
|
||||
}
|
||||
|
||||
export interface TestResult {
|
||||
success: boolean;
|
||||
connectedPeers: number;
|
||||
messagesSent: number;
|
||||
failures: number;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export class WakuTestClient {
|
||||
public waku: LightNode | null = null;
|
||||
private options: Required<WakuTestClientOptions>;
|
||||
|
||||
public constructor(options: WakuTestClientOptions = {}) {
|
||||
this.options = {
|
||||
node1Port: options.node1Port || process.env.NODE1_WS_PORT || "60000",
|
||||
node2Port: options.node2Port || process.env.NODE2_WS_PORT || "60001",
|
||||
clusterId: options.clusterId ?? 0,
|
||||
numShardsInCluster: options.numShardsInCluster ?? 8,
|
||||
contentTopic: options.contentTopic || "/waku-run/1/test/proto"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and start the Waku light node
|
||||
*/
|
||||
public async start(): Promise<void> {
|
||||
const { node1Port, node2Port, clusterId, numShardsInCluster } =
|
||||
this.options;
|
||||
|
||||
const networkConfig = {
|
||||
clusterId,
|
||||
numShardsInCluster
|
||||
};
|
||||
|
||||
this.waku = await createLightNode({
|
||||
defaultBootstrap: false,
|
||||
bootstrapPeers: [
|
||||
`/ip4/127.0.0.1/tcp/${node1Port}/ws/p2p/${NODE1_PEER_ID}`,
|
||||
`/ip4/127.0.0.1/tcp/${node2Port}/ws/p2p/${NODE2_PEER_ID}`
|
||||
],
|
||||
networkConfig,
|
||||
numPeersToUse: 2,
|
||||
libp2p: {
|
||||
filterMultiaddrs: false
|
||||
}
|
||||
});
|
||||
|
||||
await this.waku.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a test message via lightpush
|
||||
*/
|
||||
public async sendTestMessage(
|
||||
payload: string = "Hello Waku!"
|
||||
): Promise<TestResult> {
|
||||
if (!this.waku) {
|
||||
throw new Error("Waku node not started. Call start() first.");
|
||||
}
|
||||
|
||||
try {
|
||||
const { contentTopic, clusterId, numShardsInCluster } = this.options;
|
||||
const networkConfig = { clusterId, numShardsInCluster };
|
||||
|
||||
const routingInfo = createRoutingInfo(networkConfig, { contentTopic });
|
||||
const encoder = createEncoder({ contentTopic, routingInfo });
|
||||
|
||||
const result = await this.waku.lightPush.send(encoder, {
|
||||
payload: new TextEncoder().encode(payload)
|
||||
});
|
||||
|
||||
const connectedPeers = this.waku.libp2p.getPeers().length;
|
||||
|
||||
return {
|
||||
success:
|
||||
result.successes.length > 0 && (result.failures?.length || 0) === 0,
|
||||
connectedPeers,
|
||||
messagesSent: result.successes.length,
|
||||
failures: result.failures?.length || 0
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
connectedPeers: this.waku.libp2p.getPeers().length,
|
||||
messagesSent: 0,
|
||||
failures: 0,
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the Waku node
|
||||
*/
|
||||
public async stop(): Promise<void> {
|
||||
if (this.waku) {
|
||||
await this.waku.stop();
|
||||
this.waku = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,17 +1,14 @@
|
||||
import { execSync } from "child_process";
|
||||
|
||||
import { createEncoder } from "@waku/core";
|
||||
import type { LightNode } from "@waku/interfaces";
|
||||
import { createLightNode, Protocols } from "@waku/sdk";
|
||||
import { createRoutingInfo } from "@waku/utils";
|
||||
import { Protocols } from "@waku/sdk";
|
||||
import { expect } from "chai";
|
||||
|
||||
import { NODE1_PEER_ID, NODE2_PEER_ID } from "../src/constants.js";
|
||||
import { WakuTestClient } from "../src/test-client.js";
|
||||
|
||||
describe("Waku Run - Basic Test", function () {
|
||||
this.timeout(90000);
|
||||
|
||||
let waku: LightNode;
|
||||
let client: WakuTestClient;
|
||||
|
||||
before(async function () {
|
||||
// Step 1: Start the nodes
|
||||
@ -65,8 +62,8 @@ describe("Waku Run - Basic Test", function () {
|
||||
|
||||
after(async function () {
|
||||
// Step 4: Stop the nodes
|
||||
if (waku) {
|
||||
await waku.stop();
|
||||
if (client) {
|
||||
await client.stop();
|
||||
}
|
||||
execSync("docker compose down", {
|
||||
stdio: "inherit"
|
||||
@ -74,59 +71,29 @@ describe("Waku Run - Basic Test", function () {
|
||||
});
|
||||
|
||||
it("should connect to both nodes and send lightpush message to both peers", async function () {
|
||||
// Step 2: Connect to nodes via js-waku
|
||||
const node1Port = process.env.NODE1_WS_PORT || "60000";
|
||||
const node2Port = process.env.NODE2_WS_PORT || "60001";
|
||||
|
||||
// Static peer IDs from --nodekey configuration
|
||||
// cspell:ignore nodekey
|
||||
const peer1 = NODE1_PEER_ID;
|
||||
const peer2 = NODE2_PEER_ID;
|
||||
|
||||
const networkConfig = {
|
||||
clusterId: 0,
|
||||
numShardsInCluster: 8
|
||||
};
|
||||
|
||||
waku = await createLightNode({
|
||||
defaultBootstrap: false,
|
||||
bootstrapPeers: [
|
||||
`/ip4/127.0.0.1/tcp/${node1Port}/ws/p2p/${peer1}`,
|
||||
`/ip4/127.0.0.1/tcp/${node2Port}/ws/p2p/${peer2}`
|
||||
],
|
||||
networkConfig,
|
||||
numPeersToUse: 2, // Use both peers for sending
|
||||
libp2p: {
|
||||
filterMultiaddrs: false
|
||||
}
|
||||
// Step 2: Connect to nodes via js-waku using WakuTestClient
|
||||
client = new WakuTestClient({
|
||||
contentTopic: "/test/1/basic/proto"
|
||||
});
|
||||
|
||||
await waku.start();
|
||||
await client.start();
|
||||
|
||||
// Wait for both peers to be connected
|
||||
await waku.waitForPeers([Protocols.LightPush]);
|
||||
|
||||
// Verify we're connected to both peers
|
||||
const connectedPeers = waku.libp2p.getPeers();
|
||||
expect(connectedPeers.length).to.equal(
|
||||
await client.waku!.waitForPeers([Protocols.LightPush]);
|
||||
const connectedPeers = client.waku!.libp2p.getPeers().length;
|
||||
expect(connectedPeers).to.equal(
|
||||
2,
|
||||
"Should be connected to both nwaku nodes"
|
||||
);
|
||||
|
||||
// Step 3: Send lightpush message - it should be sent to both peers
|
||||
const contentTopic = "/test/1/basic/proto";
|
||||
const routingInfo = createRoutingInfo(networkConfig, { contentTopic });
|
||||
const encoder = createEncoder({ contentTopic, routingInfo });
|
||||
const result = await client.sendTestMessage("Hello Waku!");
|
||||
|
||||
const result = await waku.lightPush.send(encoder, {
|
||||
payload: new TextEncoder().encode("Hello Waku!")
|
||||
});
|
||||
|
||||
// With numPeersToUse=2, the message should be sent to both peers
|
||||
expect(result.successes.length).to.equal(
|
||||
expect(result.success).to.be.true;
|
||||
expect(result.messagesSent).to.equal(
|
||||
2,
|
||||
"Message should be sent to both peers"
|
||||
);
|
||||
expect(result.failures?.length || 0).to.equal(0, "Should have no failures");
|
||||
expect(result.failures).to.equal(0, "Should have no failures");
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user