@node-lightning/wire
Version:
Lightning Network Wire Protocol
142 lines (132 loc) • 5.37 kB
text/typescript
import { expect } from "chai";
import sinon from "sinon";
import { PingPongState } from "../lib/PingPongState";
function createAndStart({ PING_INTERVAL_MS, PONG_TIMEOUT_MS, PING_FLOOD_THRESHOLD }: any) {
const peerClient = {
reconnect: sinon.stub(),
disconnect: sinon.stub(),
sendMessage: sinon.stub(),
logger: {
debug: sinon.stub(),
},
};
const sut = new PingPongState(peerClient as any);
if (PING_INTERVAL_MS) {
sut.PING_INTERVAL_MS = PING_INTERVAL_MS;
}
if (PONG_TIMEOUT_MS) {
sut.PONG_TIMEOUT_MS = PONG_TIMEOUT_MS;
}
if (PING_FLOOD_THRESHOLD) {
sut.PING_FLOOD_THRESHOLD = PING_FLOOD_THRESHOLD;
}
sut.start();
return sut;
}
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
describe("pingpong-state", () => {
let sut;
afterEach(() => {
sut.onDisconnecting();
});
describe("when ping interval expires", () => {
describe("when no message has been received", () => {
it("it should send a ping", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10 });
await wait(15);
expect(sut._peerClient.sendMessage.args[0][0]).to.deep.equal({
type: 18,
numPongBytes: 1,
ignored: Buffer.alloc(0),
});
});
});
describe("when last message is old", () => {
it("it should send a ping", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10 });
await wait(15);
sut.onMessage({ type: 258 });
expect(sut._peerClient.sendMessage.args[0][0]).to.deep.equal({
type: 18,
numPongBytes: 1,
ignored: Buffer.alloc(0),
});
});
});
describe("when message has been received", () => {
it("it should not send ping", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10 });
await wait(5);
sut.onMessage({ type: 258 });
await wait(10);
expect(sut._peerClient.sendMessage.callCount).to.equal(0);
});
});
});
describe("when pong expires", () => {
it("it should reconnect", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 1 });
await wait(15);
expect(sut._peerClient.reconnect.callCount).to.equal(1);
});
});
describe("when pong received", () => {
it("it should cancel pong timeout", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 3 });
await wait(12);
sut.onMessage({ type: 19, ignored: Buffer.alloc(1) });
await wait(5);
expect(sut._peerClient.disconnect.callCount).to.equal(0);
});
it("it should be happy if valid pong", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 3 });
await wait(12);
sut.onMessage({ type: 19, ignored: Buffer.alloc(1) });
expect(sut._peerClient.disconnect.callCount).to.equal(0);
});
it("it should disconnect if invalid pong", async () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 3 });
await wait(12);
sut.onMessage({ type: 19, ignored: Buffer.alloc(2) });
expect(sut._peerClient.disconnect.callCount).to.equal(1);
});
});
describe("when ping received", () => {
it("it should not send ping when numPongBytes gte 65532", () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 3 });
sut.onMessage({ type: 18, numPongBytes: 65532 });
expect(sut._peerClient.disconnect.callCount).to.equal(0);
});
it("it should send correct pong", () => {
sut = createAndStart({ PING_INTERVAL_MS: 10, PONG_TIMEOUT_MS: 3 });
sut.onMessage({ type: 18, numPongBytes: 1 });
expect(sut._peerClient.sendMessage.args[0][0]).to.deep.equal({
type: 19,
ignored: Buffer.alloc(1),
});
});
it("it should disconnect if ping flood", () => {
sut = createAndStart({ PING_FLOOD_THRESHOLD: 2 });
sut.onMessage({ type: 18, numPongBytes: 1 });
sut.onMessage({ type: 18, numPongBytes: 1 });
sut.onMessage({ type: 18, numPongBytes: 1 });
expect(sut._peerClient.disconnect.callCount).to.equal(1);
});
});
describe("normal ping frequency", () => {
it("should not trigger disconnect", async () => {
sut = createAndStart({ PING_FLOOD_THRESHOLD: 2, PING_INTERVAL_MS: 10 });
sut.onMessage({ type: 18, numPongBytes: 1 });
await wait(10);
sut.onMessage({ type: 18, numPongBytes: 1 });
await wait(10);
sut.onMessage({ type: 18, numPongBytes: 1 });
await wait(10);
sut.onMessage({ type: 18, numPongBytes: 1 });
await wait(10);
expect(sut._peerClient.disconnect.callCount).to.equal(0);
});
});
});