UNPKG

pocket-messaging

Version:

A small cryptographic messaging library written in TypeScript both for browser and nodejs supporting TCP and WebSockets

1,067 lines (955 loc) 36.8 kB
//@ts-nocheck disable check for now since access modifiers have been set in Messaging. // import { TestSuite, Test, AfterAll, expect } from 'testyts'; import EventEmitter from "eventemitter3"; import {Messaging, once, Header, EventType, SentMessage, TimeoutEvent, EncryptedClient} from "../"; import {CreatePair, Client} from "pocket-sockets"; const assert = require("assert"); @TestSuite() export class MessagingSpec { socket1: Client; socket2: Client; messaging1: Messaging; messaging2: Messaging; eventEmitter1: EventEmitter; eventEmitter2: EventEmitter; constructor() { [this.socket1, this.socket2] = CreatePair(); this.messaging1 = new Messaging(this.socket1, 0); this.messaging2 = new Messaging(this.socket2, 0); this.eventEmitter1 = this.messaging1.getEventEmitter(); this.eventEmitter2 = this.messaging1.getEventEmitter(); } @AfterAll() public shutdown() { this.messaging1.close(); expect.toBeTrue(this.messaging1.isOpen() === false); this.messaging2.close(); expect.toBeTrue(this.messaging2.isOpen() === false); } @Test() public basics() { expect.toBeTrue(this.eventEmitter1 != null); //@ts-ignore protected function const allEMs: EventEmitter[] = this.messaging1.getAllEventEmitters(); expect.toBeTrue(allEMs.length === 1); expect.toBeTrue(allEMs[0] === this.eventEmitter1); expect.toBeTrue(this.messaging1.isOpen() === false); this.messaging1.open(); expect.toBeTrue(this.messaging1.isOpen()); //@ts-ignore protected function const msgId1 = Messaging.GenerateMsgId(); expect.toBeTrue(msgId1.length === 4); //@ts-ignore protected function const msgId2 = Messaging.GenerateMsgId(); expect.toBeTrue(msgId2.length === 4); expect.toBeTrue(msgId1.compare(msgId2) !== 0); const header: Header = { version: 0, target: Buffer.from("ping"), msgId: msgId1, dataLength: 33, config: 2 }; //@ts-ignore protected function const headerBuffer = Messaging.EncodeHeader(header); expect.toBeTrue(headerBuffer.length === 11 + header.target.length); const messageBuffer = Buffer.concat([headerBuffer, Buffer.alloc(33).fill(33)]); //@ts-ignore protected function const ret = Messaging.DecodeHeader(messageBuffer); expect.toBeTrue(ret !== undefined); if (!ret) return; //@ts-chillax trust me on this one const [header2, data2] = ret; expect.toBeTrue(header2 !== undefined); expect.toBeTrue(header2.version === 0); expect.toBeTrue(header2.target.length === 4); expect.toBeTrue(data2 !== undefined); expect.toBeTrue(data2.length === 33); expect.toBeTrue(data2.compare(Buffer.alloc(33).fill(33)) === 0); let buffers: Buffer[] = []; //@ts-ignore protected function let extracted = this.messaging1.extractBuffer(buffers, 100); expect.toBeTrue(extracted === undefined); buffers = [Buffer.from("abc"), Buffer.from("def")]; //@ts-ignore protected function extracted = this.messaging1.extractBuffer(buffers, 100); expect.toBeTrue(extracted === undefined); //@ts-ignore protected function extracted = this.messaging1.extractBuffer(buffers, 1); expect.toBeTrue(extracted !== undefined); if (!extracted) return; //@ts-chillax trust me on this one expect.toBeTrue(extracted.compare(Buffer.from("a")) === 0); expect.toBeTrue(buffers.length === 2); expect.toBeTrue(buffers[0].length === 2); //@ts-ignore protected function extracted = this.messaging1.extractBuffer(buffers, 5); expect.toBeTrue(extracted !== undefined); if (!extracted) return; //@ts-chillax trust me on this one expect.toBeTrue(extracted.compare(Buffer.from("bcdef")) === 0); expect.toBeTrue(buffers.length === 0); } /** * Poke and test the eventsystem on single messaging instance. */ @Test() public async events() { process.nextTick( () => { //@ts-ignore protected function this.messaging1.emitEvent([this.eventEmitter1], "error", 111); }); let value = await once(this.eventEmitter1, "error"); expect.toBeTrue(value === 111); process.nextTick( () => { //@ts-ignore protected function this.messaging1.emitEvent([this.eventEmitter1], "error", 112); //@ts-ignore protected function this.messaging1.emitEvent([this.eventEmitter1], "reply", 113); }); value = await once(this.eventEmitter1, "reply"); expect.toBeTrue(value === 113); process.nextTick( () => { //@ts-ignore protected function this.messaging1.emitError(Buffer.from("hello")); }); let accept: Function; const p = new Promise( (accept2) => { accept = accept2; }); this.eventEmitter1.on("error", (err) => { expect.toBeTrue(err !== undefined); expect.toBeTrue(err.error.length === 5); accept(); }); let buf = await once(this.eventEmitter1, "any"); await p; } /** * Try communicating between two Messaging instances using leveraging the virtual socket pair. */ @Test() public async communication() { const data = Buffer.from("Hello World!"); this.messaging1.open(); this.messaging2.open(); const ee2 = this.messaging2.getEventEmitter(); expect.toBeTrue(ee2 !== undefined, "Expecting eventemitter returned"); process.nextTick( async () => { const ee1a = this.messaging1.send("ping", Buffer.from("A"), 10000, true); expect.toBeTrue(ee1a !== undefined, "Expecting eventemitter returned"); if (!ee1a || !ee1a.eventEmitter) return; //@ts-chillax const reply = await once(ee1a.eventEmitter, "reply"); // This will emit a close event this.messaging1.close(); }); const event = await once(ee2, "route"); const ee2a = this.messaging2.send(event.fromMsgId, Buffer.from("B"), 10000); expect.toBeTrue(ee2a !== undefined, "Expecting eventemitter returned"); if (!ee2a || !ee2a.eventEmitter) return; const reply = await once(ee2a.eventEmitter, "any"); // this also catched close event expect.toBeTrue(reply !== undefined); expect.toBeTrue(reply.type === "close"); } } @TestSuite() export class MessagingConstructor { @Test() public default_state() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert(Object.keys(messaging.pendingReply).length == 0); assert(!messaging.isOpened()); assert(!messaging.isClosed()); assert(messaging.dispatchLimit == -1); assert(messaging.isBusyOut == 0); assert(messaging.isBusyIn == 0); assert(messaging.instanceId.length == (8 * 2)); assert(messaging.incomingQueue.chunks.length == 0); assert(messaging.incomingQueue.messages.length == 0); assert(messaging.outgoingQueue.chunks.length == 0); assert(messaging.eventEmitter); } } @TestSuite() export class MessagingSetEncrypted { @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { const outKey = Buffer.alloc(32); const outNonce = Buffer.alloc(24); const inKey = Buffer.alloc(32); const inNonce = Buffer.alloc(24); const peerPubKey = Buffer.alloc(32); let encryptedClient = new EncryptedClient(messaging.getClient(), outKey, outNonce, inKey, inNonce, peerPubKey); await encryptedClient.init(); assert(encryptedClient.getPeerPublicKey()); }); } } @TestSuite() export class MessagingSetUnencrypted { @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { const outKey = Buffer.alloc(32); const outNonce = Buffer.alloc(24); const inKey = Buffer.alloc(32); const inNonce = Buffer.alloc(24); const peerPubKey = Buffer.alloc(32); let encryptedClient = new EncryptedClient(messaging.getClient(), outKey, outNonce, inKey, inNonce, peerPubKey); await encryptedClient.init(); }); } } @TestSuite() export class MessagingOpen { @Test() public already_closed() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { messaging._isClosed = true; assert(messaging.isOpened() == false); messaging.open(); assert(messaging.isOpened() == false); }); } @Test() public already_opened() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { messaging._isOpened = true; let flag = false; // Expected to be called only on success // @ts-ignore: protected method messaging.checkTimeouts = function() { flag = true; }; messaging.open(); assert(messaging.isOpened() == true); assert(flag == false); // No change }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { let flag = false; // Expected to be called only on success // @ts-ignore: protected method messaging.checkTimeouts = function() { flag = true; }; assert(messaging.isOpened() == false); assert(flag == false); messaging.open(); assert(messaging.isOpened() == true); // @ts-ignore: expected to be modified by custom checkTimeouts assert(flag == true); }); } } @TestSuite() export class MessagingClose { @Test() public already_closed() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { let flag = false; messaging.socket.close = function() { flag = true; } assert(flag == false); messaging.close(); //@ts-ignore assert(flag == true); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { assert(messaging.isClosed() == false); assert(messaging.isOpened() == false); messaging.open(); assert(messaging.isOpened() == true); messaging.close(); assert(messaging.isClosed() == true); }); } } @TestSuite() export class MessagingCorkUncork { @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { messaging.uncork(30); assert(messaging.dispatchLimit == 30); messaging.cork(); assert(messaging.dispatchLimit == 0); }); } @Test() public uncork_without_parameters() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { assert(messaging.dispatchLimit == -1); messaging.uncork(30); assert(messaging.dispatchLimit == 30); messaging.uncork(); assert(messaging.dispatchLimit == -1); }); } } @TestSuite() export class MessagingSend { @Test() public not_open_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { assert(messaging.isOpened() == false); assert(Object.keys(messaging.pendingReply).length == 0); messaging.send(Buffer.from("")); assert(Object.keys(messaging.pendingReply).length == 0); }); } @Test() public isClosed_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { messaging._isClosed = true; assert(Object.keys(messaging.pendingReply).length == 0); messaging.send(Buffer.from("")); assert(Object.keys(messaging.pendingReply).length == 0); }); } @Test() public exceed_target_length() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.throws(function() { assert(Object.keys(messaging.pendingReply).length == 0); messaging._isOpened = true; messaging._isClosed = false; messaging.send(Buffer.alloc(256).fill(256)); assert(Object.keys(messaging.pendingReply).length == 0); }, /target length cannot exceed 255 bytes/); } @Test() public successful_call_no_reply() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { assert(messaging.outgoingQueue.chunks.length == 0); assert(Object.keys(messaging.pendingReply).length == 0); messaging._isOpened = true; messaging._isClosed = false; const replyStatus = messaging.send(Buffer.alloc(255).fill(255)); assert(messaging.outgoingQueue.chunks.length == 1 + 1); assert(Object.keys(messaging.pendingReply).length == 0); assert(replyStatus !== undefined); assert(replyStatus && replyStatus.msgId !== undefined); }); } @Test() public successful_call_expectingReply() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { assert(messaging.outgoingQueue.chunks.length == 0); assert(Object.keys(messaging.pendingReply).length == 0); messaging._isOpened = true; messaging._isClosed = false; const replyStatus = messaging.send(Buffer.alloc(255).fill(255), undefined, 1); assert(messaging.outgoingQueue.chunks.length == 1 + 1); assert(Object.keys(messaging.pendingReply).length == 1); assert(replyStatus?.eventEmitter instanceof EventEmitter); }); } } @TestSuite() export class MessagingEncodeHeader { @Test() public target_length_exceeded() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.throws(function() { //@ts-ignore protected function const id = Messaging.GenerateMsgId(); const header: Header = { version: 0, target: Buffer.alloc(256).fill(256), msgId: id, dataLength: 33, config: 2 }; //@ts-ignore protected function Messaging.EncodeHeader(header); }, /Target length cannot exceed 255 bytes/); } @Test() public msgId_length_exceeded() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.throws(function() { const header: Header = { version: 0, target: Buffer.alloc(255).fill(255), msgId: Buffer.from(""), dataLength: 33, config: 2 }; //@ts-ignore protected function Messaging.EncodeHeader(header); }, /msgId length must be exactly 4 bytes long/); } } @TestSuite() export class MessagingDecodeHeader { @Test() public unsupported_version() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.throws(function() { //@ts-ignore protected function const id = Messaging.GenerateMsgId(); const header: Header = { version: 0, target: Buffer.alloc(255).fill(255), msgId: id, dataLength: 33, config: 2 }; //@ts-ignore protected function let encodedHeader = Messaging.EncodeHeader(header); encodedHeader.writeUInt8(255); //@ts-ignore protected function Messaging.DecodeHeader(encodedHeader); }, /Unexpected version nr, only supporting version 0/); } @Test() public buffer_length_mismatch() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.throws(function() { //@ts-ignore protected function const id = Messaging.GenerateMsgId(); const header: Header = { version: 0, target: Buffer.alloc(255).fill(255), msgId: id, dataLength: 33, config: 2 }; //@ts-ignore protected function let encodedHeader = Messaging.EncodeHeader(header); encodedHeader.writeUInt32LE(234, 1); //@ts-ignore protected function Messaging.DecodeHeader(encodedHeader); }, /Mismatch in expected length and provided buffer length/); } } @TestSuite() export class MessagingSocketClose { @Test() public alreadyClosed_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { messaging._isClosed = true; //@ts-ignore protected function messaging.socketClose(); assert(messaging.isClosed() == true); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { //@ts-ignore protected function messaging.emitEvent = function(emitters: EventEmitter[], type: EventType, arg: any) { assert(emitters) assert(type == EventType.CLOSE || type == EventType.ANY); assert(arg); }; assert(messaging.isClosed() == false); //@ts-ignore protected function messaging.socketClose(); assert(messaging.isClosed() == true); }); } } @TestSuite() export class MessagingSocketData { @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { let flag = false; //@ts-ignore custom signature messaging.processInqueue = function() { flag = true; } assert(messaging.incomingQueue.chunks.length == 0); assert(messaging.isBusyIn == 0); assert(flag == false); //@ts-ignore protected function messaging.socketData(Buffer.from("")); assert(messaging.incomingQueue.chunks.length == 1); assert(messaging.isBusyIn == 1); //@ts-ignore: expected to be changed by custom processInqueue assert(flag == true); }); } } @TestSuite() export class MessagingProcessInqueue { @Test() public not_busy_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(function() { let flag = false; assert(flag == false); messaging.isBusyIn = 0; //@ts-ignore protected function messaging.processInqueue(); assert(messaging.isBusyIn == 0); assert(flag == false); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { let counter = 0; //@ts-ignore custom signature messaging.assembleIncoming = function() { counter++; } //@ts-ignore custom signature messaging.dispatchIncoming = function() { counter++; } messaging.isBusyIn = 1; //@ts-ignore protected function await messaging.processInqueue(); assert(counter == 1); }); } } @TestSuite() export class MessagingAssembleIncoming { @Test() public no_data_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("")); assert(messaging.incomingQueue.chunks.length == 1); //@ts-ignore protected function messaging.assembleIncoming(); }); } @Test() public not_enough_data() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("1234")); //@ts-ignore protected function messaging.assembleIncoming(); }); } @Test() public bad_version() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); // Set custom version messaging.incomingQueue.chunks[0].writeUInt8(244); //@ts-ignore protected function messaging.assembleIncoming(); }); } @Test() public not_enough_data_extractBuffer() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return undefined; } //@ts-ignore protected function messaging.assembleIncoming(); }); } @Test() public bad_stream_decodeHeader() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return Buffer.from(""); } //@ts-ignore protected function Messaging.DecodeHeader = function() { return undefined; } //@ts-ignore protected function messaging.assembleIncoming(); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return Buffer.from(""); } //@ts-ignore protected function Messaging.DecodeHeader = function() { messaging.incomingQueue.chunks.length = 0; return [{version: 0, target: "tgt", dataLength: 3, config: false}, Buffer.from("")]; } assert(messaging.incomingQueue.messages.length == 0); //@ts-ignore protected function messaging.assembleIncoming(); assert(messaging.incomingQueue.messages.length == 1); }); } } @TestSuite() export class MessagingDispatchIncoming { @Test() public no_data_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("")); assert(messaging.incomingQueue.messages.length == 0); //@ts-ignore protected function messaging.dispatchIncoming(); assert(messaging.incomingQueue.messages.length == 0); }); } @Test() public dispatchLimit_is_zero() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return Buffer.from(""); } //@ts-ignore protected function Messaging.DecodeHeader = function() { messaging.incomingQueue.chunks.length = 0; return [{version: 0, target: Buffer.from("tgt"), dataLength: 3, config: false}, Buffer.from("")]; } //@ts-ignore protected function messaging.assembleIncoming(); assert(messaging.incomingQueue.messages.length == 1); messaging.dispatchLimit = 0; //@ts-ignore protected function messaging.dispatchIncoming(); assert(messaging.incomingQueue.messages.length == 1); }); } @Test() public dispatchLimit_is_one() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return Buffer.from(""); } //@ts-ignore protected function Messaging.DecodeHeader = function() { messaging.incomingQueue.chunks.length = 0; return [{version: 0, target: Buffer.from("tgt"), dataLength: 3, config: false}, Buffer.from("")]; } //@ts-ignore protected function messaging.assembleIncoming(); assert(messaging.incomingQueue.messages.length == 1); messaging.dispatchLimit = 1; //@ts-ignore protected function messaging.dispatchIncoming(); assert(messaging.incomingQueue.messages.length == 0); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.incomingQueue.chunks.push(Buffer.from("12345")); messaging.incomingQueue.chunks[0].writeUInt8(0); //@ts-ignore protected function messaging.extractBuffer = function() { return Buffer.from(""); } //@ts-ignore protected function Messaging.DecodeHeader = function() { messaging.incomingQueue.chunks.length = 0; return [{version: 0, target: Buffer.from("tgt"), dataLength: 3, config: false}, Buffer.from("")]; } //@ts-ignore protected function messaging.assembleIncoming(); assert(messaging.incomingQueue.messages.length == 1); //@ts-ignore protected function messaging.dispatchIncoming(); assert(messaging.incomingQueue.messages.length == 0); }); } } @TestSuite() export class MessagingProcessOutqueue { @Test() public isBusyOut_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.isBusyOut = 0; let counter = 0; //@ts-ignore protected function messaging.dispatchOutgoing = function() { counter++; } assert(counter == 0); //@ts-ignore protected function messaging.processOutqueue(); assert(counter == 0); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.isBusyOut = 1; let encryptFlag = false; let dispatchFlag = false; //@ts-ignore protected function messaging.dispatchOutgoing = function() { dispatchFlag = true; } //@ts-ignore protected function await messaging.processOutqueue(); //@ts-ignore expected to be set by custom function assert(dispatchFlag == true); }); } } @TestSuite() export class MessagingEncryptOutgoing { @Test() public unencrypted_successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = true; messaging._isClosed = false; const replyStatus = messaging.send(Buffer.alloc(255).fill(255)); assert(messaging.outgoingQueue.chunks.length == 1 + 1); }); } @Test() public encrypted_successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = true; messaging._isClosed = false; const outKey = Buffer.alloc(32); const outNonce = Buffer.alloc(24); const inKey = Buffer.alloc(32); const inNonce = Buffer.alloc(24); const peerPubKey = Buffer.alloc(32); let encryptedClient = new EncryptedClient(messaging.getClient(), outKey, outNonce, inKey, inNonce, peerPubKey); await encryptedClient.init(); const replyStatus = messaging.send(Buffer.alloc(255).fill(255)); assert(messaging.outgoingQueue.chunks.length == 1 + 1); }); } } @TestSuite() export class MessagingDispatchOutgoing { @Test() public no_encrypted_data_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { assert(messaging.outgoingQueue.chunks.length == 0); //@ts-ignore: protected function await messaging.dispatchOutgoing(); assert(messaging.outgoingQueue.chunks.length == 0); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = true; messaging._isClosed = false; const outKey = Buffer.alloc(32); const outNonce = Buffer.alloc(24); const inKey = Buffer.alloc(32); const inNonce = Buffer.alloc(24); const peerPubKey = Buffer.alloc(32); let encryptedClient = new EncryptedClient(messaging.getClient(), outKey, outNonce, inKey, inNonce, peerPubKey); await encryptedClient.init(); const replyStatus = messaging.send(Buffer.alloc(255).fill(255)); let flag = false; messaging.socket.send = function() { flag = true; } assert(flag == false); assert(messaging.outgoingQueue.chunks.length == 2); //@ts-ignore: protected function await messaging.dispatchOutgoing(); //@ts-ignore: flag expected to be toggled by custom socket send procedure assert(flag == true); assert(messaging.outgoingQueue.chunks.length == 0); }); } } @TestSuite() export class MessagingCheckTimeouts { @Test() public unset_isOpened_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = false; //@ts-ignore: protected function messaging.checkTimeouts(); }); } @Test() public set_isClosed_noop() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isClosed = true; //@ts-ignore: protected function messaging.checkTimeouts(); }); } @Test() public successful_call() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging.open(); assert(messaging.isOpened() == true); assert(messaging.isClosed() == false); //@ts-ignore: protected function messaging.getTimeoutedPendingMessages = function() { let messages: SentMessage[] = []; messages.push({ timestamp: 0, msgId: Buffer.from("10"), timeout: 0, timeoutStream: 0, replyCounter: 0, stream: false, eventEmitter: new EventEmitter(), isCleared: false, }); return messages; } messaging.cancelPendingMessage = function(id: Buffer) { assert(id.toString() == "10"); } //@ts-ignore: protected function messaging.emitEvent = function(emitter: EventEmitter[], type: EventType, timeout: TimeoutEvent) { assert(type == EventType.TIMEOUT); //@ts-ignore: protected function messaging.emitEvent = () => {}; // We need to cancel this because a "close" event would else reach this function and the assert will trigger. messaging.close(); } //@ts-ignore: protected function messaging.checkTimeouts(); }); } } @TestSuite() export class MessagingGetTimeoutedPendingMessages { @Test() public successful_call_timeout() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = true; messaging._isClosed = false; //@ts-ignore: protected function messaging.pendingReply["20"] = { timestamp: 0, msgId: Buffer.from("20"), timeout: 1, timeoutStream: 0, replyCounter: 0, stream: false, eventEmitter: new EventEmitter() }; //@ts-ignore: protected function let data = messaging.getTimeoutedPendingMessages(); assert(data.length == 1); }); } @Test() public successful_call_no_timeout() { let [socket, _] = CreatePair(); let messaging = new Messaging(socket, 0); assert.doesNotThrow(async function() { messaging._isOpened = true; messaging._isClosed = false; //@ts-ignore: protected function messaging.pendingReply["20"] = { timestamp: 0, msgId: Buffer.from("20"), timeout: 0, timeoutStream: 0, replyCounter: 0, stream: false, eventEmitter: new EventEmitter() }; //@ts-ignore: protected function let data = messaging.getTimeoutedPendingMessages(); assert(data.length == 0); }); } }