Sasha 75fcca4cd9
feat: replace waitForRemotePeers() with waku.waitForPeer() method (#2161)
* fix comment of default number of peers

* export default number of peers from base protocol sdk

* rename to light_push, move class to separate file

* move waitForRemotePeer to sdk package

* add todo to move waitForGossipSubPeerInMesh into @waku/relay

* clean up waitForRemotePeer, split metadata await from event and optimise, decouple from protocol implementations

* simplify and rename ILightPush interface

* use only connected peers in light push based on connections instead of peer renewal mechanism

* improve readability of result processing in light push

* fix check & update tests

* address tests, add new test cases, fix racing condition in StreamManager

* use libp2p.getPeers

* feat: confirm metadata and protocols needed in waitForRemotePeer

* rely on passed protocols and fallback to mounted

* add I prefix to Waku interface

* implement waku.connect method

* add docs to IWaku interface

* remove export and usage of waitForRemotePeer

* move wait for remote peer related to Realy out of @waku/sdk

* change tests to use new API

* fix linting

* update size limit

* rename .connect to .waitForPeer

* export waitForRemotePeer and mark as deprecated

* feat: add mocha tests to @waku/sdk and cover waitForRemotePeer (#2163)

* feat: add mocha tests to @waku/sdk and cover waitForRemotePeer

* add waitForRemote UTs

* remove junk

* feat: expose peerId and protocols from WakuNode (#2166)

* chore: expose peerId and protocols from WakuNode

* remove unused method

* move to private method

* rename to waitForPeers

* up test
2024-10-09 00:43:34 +02:00

177 lines
4.7 KiB
TypeScript

import { HealthStatus, IWaku, LightNode, Protocols } from "@waku/interfaces";
import { createLightNode } from "@waku/sdk";
import { shardInfoToPubsubTopics } from "@waku/utils";
import { expect } from "chai";
import {
afterEachCustom,
runMultipleNodes,
ServiceNode,
ServiceNodesFleet
} from "../../src/index.js";
import {
messagePayload,
TestDecoder,
TestEncoder,
TestShardInfo
} from "./utils.js";
describe("Node Health Status Matrix Tests", function () {
let waku: LightNode;
let serviceNodes: ServiceNode[];
afterEachCustom(this, async function () {
if (waku) {
await waku.stop();
}
if (serviceNodes) {
await Promise.all(serviceNodes.map((node) => node.stop()));
}
});
const peerCounts = [0, 1, 2, 3];
peerCounts.forEach((lightPushPeers) => {
peerCounts.forEach((filterPeers) => {
it(`LightPush: ${lightPushPeers} peers, Filter: ${filterPeers} peers`, async function () {
this.timeout(10_000);
[waku, serviceNodes] = await setupTestEnvironment(
this.ctx,
lightPushPeers,
filterPeers
);
if (lightPushPeers > 0) {
await waku.lightPush.send(TestEncoder, messagePayload, {
forceUseAllPeers: true
});
}
if (filterPeers > 0) {
await waku.filter.subscribe([TestDecoder], () => {});
}
const lightPushHealth = waku.health.getProtocolStatus(
Protocols.LightPush
);
const filterHealth = waku.health.getProtocolStatus(Protocols.Filter);
lightPushPeers = await getPeerCounBasedOnConnections(
waku,
waku.lightPush.protocol.multicodec
);
expect(lightPushHealth?.status).to.equal(
getExpectedProtocolStatus(lightPushPeers)
);
expect(filterHealth?.status).to.equal(
getExpectedProtocolStatus(filterPeers)
);
const expectedHealth = getExpectedNodeHealth(
lightPushPeers,
filterPeers
);
const nodeHealth = waku.health.getHealthStatus();
expect(nodeHealth).to.equal(expectedHealth);
});
});
});
});
function getExpectedProtocolStatus(peerCount: number): HealthStatus {
if (peerCount === 0) return HealthStatus.Unhealthy;
if (peerCount === 1) return HealthStatus.MinimallyHealthy;
return HealthStatus.SufficientlyHealthy;
}
async function getPeerCounBasedOnConnections(
waku: IWaku,
codec: string
): Promise<number> {
const peerIDs = waku.libp2p
.getConnections()
.map((c) => c.remotePeer.toString());
const peers = await waku.libp2p.peerStore.all();
return peers
.filter((peer) => peerIDs.includes(peer.id.toString()))
.filter((peer) => peer.protocols.includes(codec)).length;
}
function getExpectedNodeHealth(
lightPushPeers: number,
filterPeers: number
): HealthStatus {
if (lightPushPeers === 0 || filterPeers === 0) {
return HealthStatus.Unhealthy;
} else if (lightPushPeers === 1 || filterPeers === 1) {
return HealthStatus.MinimallyHealthy;
} else {
return HealthStatus.SufficientlyHealthy;
}
}
async function runNodeWithProtocols(
lightPush: boolean,
filter: boolean
): Promise<ServiceNode> {
const serviceNode = new ServiceNode(`node-${Date.now()}`);
await serviceNode.start({
lightpush: lightPush,
filter: filter,
relay: true,
clusterId: TestShardInfo.clusterId,
pubsubTopic: shardInfoToPubsubTopics(TestShardInfo)
});
return serviceNode;
}
async function setupTestEnvironment(
context: Mocha.Context,
lightPushPeers: number,
filterPeers: number
): Promise<[LightNode, ServiceNode[]]> {
let commonPeers: number;
if (lightPushPeers === 0 || filterPeers === 0) {
commonPeers = Math.max(lightPushPeers, filterPeers);
} else {
commonPeers = Math.min(lightPushPeers, filterPeers);
}
let waku: LightNode;
const serviceNodes: ServiceNode[] = [];
let serviceNodesFleet: ServiceNodesFleet;
if (commonPeers > 0) {
[serviceNodesFleet, waku] = await runMultipleNodes(
context,
TestShardInfo,
{ filter: true, lightpush: true },
undefined,
commonPeers
);
serviceNodes.push(...serviceNodesFleet.nodes);
} else {
waku = await createLightNode({ networkConfig: TestShardInfo });
}
// Create additional LightPush nodes if needed
for (let i = commonPeers; i < lightPushPeers; i++) {
const node = await runNodeWithProtocols(true, false);
serviceNodes.push(node);
await waku.dial(await node.getMultiaddrWithId());
}
// Create additional Filter nodes if needed
for (let i = commonPeers; i < filterPeers; i++) {
const node = await runNodeWithProtocols(false, true);
serviceNodes.push(node);
await waku.dial(await node.getMultiaddrWithId());
}
return [waku, serviceNodes];
}