Skip to content

Commit

Permalink
remove base protocol sdk from light push, add unit tests for light push
Browse files Browse the repository at this point in the history
  • Loading branch information
weboko committed Oct 11, 2024
1 parent 92d0a28 commit 9d1afd7
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 19 deletions.
5 changes: 2 additions & 3 deletions packages/interfaces/src/light_push.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { IBaseProtocolCore, IBaseProtocolSDK } from "./protocols.js";
import { IBaseProtocolCore } from "./protocols.js";
import type { ISender } from "./sender.js";

export type ILightPush = ISender &
IBaseProtocolSDK & { protocol: IBaseProtocolCore };
export type ILightPush = ISender & { protocol: IBaseProtocolCore };
2 changes: 1 addition & 1 deletion packages/sdk/src/protocols/base_protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Options {
maintainPeersInterval?: number;
}

const DEFAULT_NUM_PEERS_TO_USE = 2;
export const DEFAULT_NUM_PEERS_TO_USE = 2;
const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000;

export class BaseProtocolSDK implements IBaseProtocolSDK {
Expand Down
170 changes: 165 additions & 5 deletions packages/sdk/src/protocols/light_push/light_push.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,170 @@
// TODO: add them after decoupling `BaseProtocolSDK` from LightPush
import { Peer } from "@libp2p/interface";
import {
ConnectionManager,
createEncoder,
Encoder,
LightPushCodec
} from "@waku/core";
import { Libp2p, ProtocolError } from "@waku/interfaces";
import { utf8ToBytes } from "@waku/utils/bytes";
import { expect } from "chai";
import sinon from "sinon";

import { LightPush } from "./light_push.js";

const PUBSUB_TOPIC = "/waku/2/rs/1/4";
const CONTENT_TOPIC = "/test/1/waku-light-push/utf8";

describe("LightPush SDK", () => {
it("should fail to send if pubsub topics are misconfigured");
let libp2p: Libp2p;
let encoder: Encoder;
let lightPush: LightPush;

beforeEach(() => {
libp2p = mockLibp2p();
encoder = createEncoder({ contentTopic: CONTENT_TOPIC });
lightPush = mockLightPush({ libp2p });
});

it("should fail to send if pubsub topics are misconfigured", async () => {
lightPush = mockLightPush({ libp2p, pubsubTopics: ["/wrong"] });

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.TOPIC_NOT_CONFIGURED))
.to.be.true;
});

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")]
});

// check default value that should be 2
lightPush = mockLightPush({ libp2p });
let sendSpy = sinon.spy(
(_encoder: any, _message: any, peer: Peer) =>
({ success: peer.id }) as any
);
lightPush.protocol.send = sendSpy;

let result = await lightPush.send(encoder, {
payload: utf8ToBytes("test")
});

expect(sendSpy.calledTwice).to.be.true;
expect(result.successes?.length).to.be.eq(2);

// check if setting another value works
lightPush = mockLightPush({ libp2p, numPeersToUse: 3 });
sendSpy = sinon.spy(
(_encoder: any, _message: any, peer: Peer) =>
({ success: peer.id }) as any
);
lightPush.protocol.send = sendSpy;

it("should fail to send if no connected peers found");
result = await lightPush.send(encoder, { payload: utf8ToBytes("test") });

it("should send to number of used peers");
expect(sendSpy.calledThrice).to.be.true;
expect(result.successes?.length).to.be.eq(3);
});

it("should retry on failure if specified");
it("should retry on failure if specified", async () => {
libp2p = mockLibp2p({
peers: [mockPeer("1"), mockPeer("2")]
});

lightPush = mockLightPush({ libp2p });
let sendSpy = sinon.spy((_encoder: any, _message: any, peer: Peer) => {
if (peer.id.toString() === "1") {
return { success: peer.id };
}

return { failure: { error: "problem" } };
});
lightPush.protocol.send = sendSpy as any;
const attemptRetriesSpy = sinon.spy(lightPush["attemptRetries"]);
lightPush["attemptRetries"] = attemptRetriesSpy;

const result = await lightPush.send(
encoder,
{ payload: utf8ToBytes("test") },
{ autoRetry: true }
);

expect(attemptRetriesSpy.calledOnce).to.be.true;
expect(result.successes?.length).to.be.eq(1);
expect(result.failures?.length).to.be.eq(1);

sendSpy = sinon.spy(() => ({ failure: { error: "problem" } })) as any;
await lightPush["attemptRetries"](sendSpy as any);

expect(sendSpy.callCount).to.be.eq(3);

sendSpy = sinon.spy(() => ({ failure: { error: "problem" } })) as any;
await lightPush["attemptRetries"](sendSpy as any, 2);

expect(sendSpy.callCount).to.be.eq(2);
});
});

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 {
return new LightPush(
{
configuredPubsubTopics: options.pubsubTopics || [PUBSUB_TOPIC]
} as ConnectionManager,
options.libp2p,
{ numPeersToUse: options.numPeersToUse }
);
}

function mockPeer(id: string): Peer {
return {
id,
protocols: [LightPushCodec]
} as unknown as Peer;
}
17 changes: 7 additions & 10 deletions packages/sdk/src/protocols/light_push/light_push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from "@waku/interfaces";
import { ensurePubsubTopicIsConfigured, Logger } from "@waku/utils";

import { BaseProtocolSDK } from "../base_protocol.js";
import { DEFAULT_NUM_PEERS_TO_USE } from "../base_protocol.js";

const log = new Logger("sdk:light-push");

Expand All @@ -31,23 +31,20 @@ const DEFAULT_SEND_OPTIONS: ISenderOptions = {

type RetryCallback = (peer: Peer) => Promise<CoreProtocolResult>;

export class LightPush extends BaseProtocolSDK implements ILightPush {
export class LightPush implements ILightPush {
private numPeersToUse: number = DEFAULT_NUM_PEERS_TO_USE;
public readonly protocol: LightPushCore;

public constructor(
connectionManager: ConnectionManager,
private libp2p: Libp2p,
options?: ProtocolCreateOptions
) {
super(
new LightPushCore(connectionManager.configuredPubsubTopics, libp2p),
connectionManager,
{
numPeersToUse: options?.numPeersToUse
}
this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE;
this.protocol = new LightPushCore(
connectionManager.configuredPubsubTopics,
libp2p
);

this.protocol = this.core as LightPushCore;
}

public async send(
Expand Down

0 comments on commit 9d1afd7

Please sign in to comment.