mirror of
https://github.com/logos-messaging/logos-messaging-js.git
synced 2026-02-07 09:43:18 +00:00
Concepts are being mixed up between the global network config (static vs auto sharding), that needs to be the same of all nodes in the network, individual node configuration (eg relay node subscribing to a given shard), and the routing characteristic of a specific message (eg pubsub topic, shard). This stops proper configuration of nwaku post 0.36.0 because we know need to be deliberate on whether nwaku nodes are running with auto or static sharding. It also included various back and forth conversions between shards, pubsub topics, etc. With this change, we tidy up the network configuration, and make it explicit whether it is static or auto sharded. We also introduce the concept of routing info, which is specific to a message, and tied to the overall network configuration. Routing info abstract pubsub topic, shard, and autosharding needs. Which should lead to easier tidy up of the pubsub concept at a later stage.
188 lines
5.1 KiB
TypeScript
188 lines
5.1 KiB
TypeScript
import { Peer, PeerId } from "@libp2p/interface";
|
|
import { createEncoder, Encoder, LightPushCodec } from "@waku/core";
|
|
import { Libp2p, ProtocolError } from "@waku/interfaces";
|
|
import { createRoutingInfo } from "@waku/utils";
|
|
import { utf8ToBytes } from "@waku/utils/bytes";
|
|
import { expect } from "chai";
|
|
import sinon, { SinonSpy } from "sinon";
|
|
|
|
import { PeerManager } from "../peer_manager/index.js";
|
|
|
|
import { LightPush } from "./light_push.js";
|
|
|
|
const testContentTopic = "/test/1/waku-light-push/utf8";
|
|
const testRoutingInfo = createRoutingInfo(
|
|
{
|
|
clusterId: 0,
|
|
numShardsInCluster: 7
|
|
},
|
|
{ contentTopic: testContentTopic }
|
|
);
|
|
|
|
describe("LightPush SDK", () => {
|
|
let libp2p: Libp2p;
|
|
let encoder: Encoder;
|
|
let lightPush: LightPush;
|
|
|
|
beforeEach(() => {
|
|
libp2p = mockLibp2p();
|
|
encoder = createEncoder({
|
|
contentTopic: testContentTopic,
|
|
routingInfo: testRoutingInfo
|
|
});
|
|
lightPush = mockLightPush({ libp2p });
|
|
});
|
|
|
|
it("should fail to send if no connected peers found", async () => {
|
|
const result = await lightPush.send(encoder, {
|
|
payload: utf8ToBytes("test")
|
|
});
|
|
const failures = result.failures ?? [];
|
|
|
|
expect(failures.length).to.be.eq(1);
|
|
expect(failures.some((v) => v.error === ProtocolError.NO_PEER_AVAILABLE)).to
|
|
.be.true;
|
|
});
|
|
|
|
it("should send to specified number of peers of used peers", async () => {
|
|
libp2p = mockLibp2p({
|
|
peers: [mockPeer("1"), mockPeer("2"), mockPeer("3"), mockPeer("4")]
|
|
});
|
|
|
|
lightPush = mockLightPush({ libp2p, numPeersToUse: 2 });
|
|
let sendSpy = sinon.spy(
|
|
(_encoder: any, _message: any, peerId: PeerId) =>
|
|
Promise.resolve({ success: peerId }) as any
|
|
);
|
|
lightPush["protocol"].send = sendSpy;
|
|
|
|
let result = await lightPush.send(encoder, {
|
|
payload: utf8ToBytes("test")
|
|
});
|
|
|
|
expect(sendSpy.calledTwice, "1").to.be.true;
|
|
expect(result.successes?.length, "2").to.be.eq(2);
|
|
|
|
// check if setting another value works
|
|
lightPush = mockLightPush({ libp2p, numPeersToUse: 3 });
|
|
sendSpy = sinon.spy(
|
|
(_encoder: any, _message: any, peerId: PeerId) =>
|
|
Promise.resolve({ success: peerId }) as any
|
|
);
|
|
lightPush["protocol"].send = sendSpy;
|
|
|
|
result = await lightPush.send(encoder, { payload: utf8ToBytes("test") });
|
|
|
|
expect(sendSpy.calledThrice, "3").to.be.true;
|
|
expect(result.successes?.length, "4").to.be.eq(3);
|
|
});
|
|
|
|
it("should retry on complete failure if specified", async () => {
|
|
libp2p = mockLibp2p({
|
|
peers: [mockPeer("1"), mockPeer("2")]
|
|
});
|
|
|
|
lightPush = mockLightPush({ libp2p });
|
|
const sendSpy = sinon.spy((_encoder: any, _message: any, _peerId: PeerId) =>
|
|
Promise.resolve({ failure: { error: "problem" } })
|
|
);
|
|
lightPush["protocol"].send = sendSpy as any;
|
|
|
|
const retryPushSpy = (lightPush as any)["retryManager"].push as SinonSpy;
|
|
const result = await lightPush.send(
|
|
encoder,
|
|
{ payload: utf8ToBytes("test") },
|
|
{ autoRetry: true }
|
|
);
|
|
|
|
expect(retryPushSpy.callCount).to.be.eq(1);
|
|
expect(result.failures?.length).to.be.eq(2);
|
|
});
|
|
|
|
it("should not retry if at least one success", async () => {
|
|
libp2p = mockLibp2p({
|
|
peers: [mockPeer("1"), mockPeer("2")]
|
|
});
|
|
|
|
lightPush = mockLightPush({ libp2p });
|
|
const sendSpy = sinon.spy(
|
|
(_encoder: any, _message: any, peerId: PeerId) => {
|
|
if (peerId.toString() === "1") {
|
|
return Promise.resolve({ success: peerId });
|
|
}
|
|
|
|
return Promise.resolve({ failure: { error: "problem" } });
|
|
}
|
|
);
|
|
lightPush["protocol"].send = sendSpy as any;
|
|
const retryPushSpy = (lightPush as any)["retryManager"].push as SinonSpy;
|
|
|
|
const result = await lightPush.send(
|
|
encoder,
|
|
{ payload: utf8ToBytes("test") },
|
|
{ autoRetry: true }
|
|
);
|
|
|
|
expect(retryPushSpy.callCount).to.be.eq(0);
|
|
expect(result.successes?.length).to.be.eq(1);
|
|
expect(result.failures?.length).to.be.eq(1);
|
|
});
|
|
});
|
|
|
|
type MockLibp2pOptions = {
|
|
peers?: Peer[];
|
|
};
|
|
|
|
function mockLibp2p(options?: MockLibp2pOptions): Libp2p {
|
|
const peers = options?.peers || [];
|
|
const peerStore = {
|
|
get: (id: any) => Promise.resolve(peers.find((p) => p.id === id))
|
|
};
|
|
|
|
return {
|
|
peerStore,
|
|
getPeers: () => peers.map((p) => p.id),
|
|
components: {
|
|
events: new EventTarget(),
|
|
connectionManager: {
|
|
getConnections: () => []
|
|
} as any,
|
|
peerStore
|
|
}
|
|
} as unknown as Libp2p;
|
|
}
|
|
|
|
type MockLightPushOptions = {
|
|
libp2p: Libp2p;
|
|
pubsubTopics?: string[];
|
|
numPeersToUse?: number;
|
|
};
|
|
|
|
function mockLightPush(options: MockLightPushOptions): LightPush {
|
|
const lightPush = new LightPush({
|
|
peerManager: {
|
|
getPeers: () =>
|
|
options.libp2p
|
|
.getPeers()
|
|
.slice(0, options.numPeersToUse || options.libp2p.getPeers().length)
|
|
} as unknown as PeerManager,
|
|
libp2p: options.libp2p,
|
|
options: {
|
|
numPeersToUse: options.numPeersToUse
|
|
}
|
|
});
|
|
|
|
(lightPush as any)["retryManager"] = {
|
|
push: sinon.spy()
|
|
};
|
|
|
|
return lightPush;
|
|
}
|
|
|
|
function mockPeer(id: string): Peer {
|
|
return {
|
|
id,
|
|
protocols: [LightPushCodec]
|
|
} as unknown as Peer;
|
|
}
|