js-waku/packages/sdk/src/protocols/peer_manager.spec.ts
Danish Arora b2efce5ec2
feat(filter): enhancing protocol peer management with mutex locks (#2137)
* chore: improvements

* chore: add logs for subscription maintenance

* chore: update logging

* chore: trimming down BaseProtocolCore

* chore: track peers in a hashmap instead of array

* chore: peer mgmt responds to conenction/disconnection and improve logging

* feat: add mutex locks to tackle race conditions over shared state

* fix: build

* chore: some mutex lock-release improvements

* feat: peer manager

* chore: rm tests for remove internal util

* chore: update HealthManager updates

* chore: update tests

* rm: only

* fix: hasPeers management

* chore: add modularity to getting connected peers

* chore: improve logs & add debug

* chore: renewal doesnt disconnect, only removes

* chore: await for sequential operations

* chore: add TODO

* chore: minor improvements

* chore: fix rebase

* chore: update playright

* chore: remove additional arg

* chore: update interafce

* feat(peer-manager): unit tests

* chore: improve hasPeers()

* chore: update lockfile

* feat: Filter reacts to peer:disconnect event, add tests

* chore: fix lock

* chore: update playright

* chore: update protocol health for lightpush

* chore: remove .only

* chore: address comments and improvements

* fix: tsconfig
2024-10-10 23:47:12 +02:00

149 lines
4.4 KiB
TypeScript

import { Peer, PeerId } from "@libp2p/interface";
import { ConnectionManager, LightPushCodec } from "@waku/core";
import { BaseProtocol } from "@waku/core/lib/base_protocol";
import { Logger } from "@waku/utils";
import { expect } from "chai";
import sinon from "sinon";
import { PeerManager } from "./peer_manager.js";
describe("PeerManager", () => {
let peerManager: PeerManager;
let mockConnectionManager: sinon.SinonStubbedInstance<ConnectionManager>;
let mockCore: sinon.SinonStubbedInstance<BaseProtocol>;
let mockLogger: any;
beforeEach(() => {
mockConnectionManager = sinon.createStubInstance(ConnectionManager);
mockCore = sinon.createStubInstance(BaseProtocol);
mockLogger = {
info: sinon.stub(),
warn: sinon.stub(),
error: sinon.stub(),
debug: sinon.stub(),
extend: sinon.stub().returns({
info: sinon.stub(),
warn: sinon.stub(),
error: sinon.stub(),
debug: sinon.stub()
})
};
mockCore.multicodec = LightPushCodec;
peerManager = new PeerManager(
mockConnectionManager as any,
mockCore as any,
mockLogger as Logger
);
});
afterEach(() => {
sinon.restore();
});
const createMockPeer = (id: string): Peer =>
({
id: {
toString: () => id
} as PeerId
}) as Peer;
describe("addPeer", () => {
it("should add a peer", async () => {
const peer = createMockPeer("peer1");
await peerManager.addPeer(peer);
expect(mockConnectionManager.attemptDial.calledWith(peer.id)).to.be.true;
expect(
mockLogger.info.calledWith(sinon.match(/Added and dialed peer: peer1/))
).to.be.true;
expect(await peerManager.getPeerCount()).to.equal(1);
});
});
describe("removePeer", () => {
it("should remove a peer", async () => {
const peer = createMockPeer("peer1");
await peerManager.addPeer(peer);
await peerManager.removePeer(peer.id);
expect(mockLogger.info.calledWith(sinon.match(/Removed peer: peer1/))).to
.be.true;
expect(await peerManager.getPeerCount()).to.equal(0);
});
});
describe("getPeerCount", () => {
it("should return the correct number of peers", async () => {
await peerManager.addPeer(createMockPeer("peer1"));
await peerManager.addPeer(createMockPeer("peer2"));
const count = await peerManager.getPeerCount();
expect(count).to.equal(2);
});
});
describe("hasPeers", () => {
it("should return true when peers exist", async () => {
await peerManager.addPeer(createMockPeer("peer1"));
const result = await peerManager.hasPeers();
expect(result).to.be.true;
});
it("should return false when no peers exist", async () => {
const result = await peerManager.hasPeers();
expect(result).to.be.false;
});
});
describe("removeExcessPeers", () => {
it("should remove the specified number of excess peers", async () => {
await peerManager.addPeer(createMockPeer("peer1"));
await peerManager.addPeer(createMockPeer("peer2"));
await peerManager.addPeer(createMockPeer("peer3"));
await peerManager.removeExcessPeers(2);
const count = await peerManager.getPeerCount();
expect(count).to.equal(1);
expect(mockLogger.info.calledWith(`Removing 2 excess peer(s)`)).to.be
.true;
});
});
describe("findAndAddPeers", () => {
it("should find and add new peers", async () => {
const newPeers = [createMockPeer("peer1"), createMockPeer("peer2")];
mockCore.getPeers.resolves(newPeers);
const addedPeers = await peerManager.findAndAddPeers(2);
expect(addedPeers).to.have.lengthOf(2);
expect(mockConnectionManager.attemptDial.callCount).to.equal(2);
});
it("should not add existing peers", async () => {
const existingPeer = createMockPeer("existing");
await peerManager.addPeer(existingPeer);
const newPeers = [existingPeer, createMockPeer("new")];
mockCore.getPeers.resolves(newPeers);
const addedPeers = await peerManager.findAndAddPeers(2);
expect(addedPeers).to.have.lengthOf(1);
expect(mockConnectionManager.attemptDial.callCount).to.equal(2); // Once for existing, once for new
});
it("should log when no additional peers are found", async () => {
mockCore.getPeers.resolves([]);
await peerManager.findAndAddPeers(2);
expect(mockLogger.warn.calledWith("No additional peers found")).to.be
.true;
});
});
});