@node-dlc/wire
Version:
Lightning Network Wire Protocol
147 lines (136 loc) • 4.75 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);
});
});
});