Path: blob/main/src/vs/base/parts/ipc/test/node/ipc.net.test.ts
4780 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import sinon from 'sinon';7import { EventEmitter } from 'events';8import { AddressInfo, connect, createServer, Server, Socket } from 'net';9import { tmpdir } from 'os';10import { Barrier, timeout } from '../../../../common/async.js';11import { VSBuffer } from '../../../../common/buffer.js';12import { Emitter, Event } from '../../../../common/event.js';13import { Disposable, DisposableStore, toDisposable } from '../../../../common/lifecycle.js';14import { ILoadEstimator, PersistentProtocol, Protocol, ProtocolConstants, SocketCloseEvent, SocketDiagnosticsEventType } from '../../common/ipc.net.js';15import { createRandomIPCHandle, createStaticIPCHandle, NodeSocket, WebSocketNodeSocket } from '../../node/ipc.net.js';16import { flakySuite } from '../../../../test/common/testUtils.js';17import { runWithFakedTimers } from '../../../../test/common/timeTravelScheduler.js';18import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../test/common/utils.js';1920class MessageStream extends Disposable {2122private _currentComplete: ((data: VSBuffer) => void) | null;23private _messages: VSBuffer[];2425constructor(x: Protocol | PersistentProtocol) {26super();27this._currentComplete = null;28this._messages = [];29this._register(x.onMessage(data => {30this._messages.push(data);31this._trigger();32}));33}3435private _trigger(): void {36if (!this._currentComplete) {37return;38}39if (this._messages.length === 0) {40return;41}42const complete = this._currentComplete;43const msg = this._messages.shift()!;4445this._currentComplete = null;46complete(msg);47}4849public waitForOne(): Promise<VSBuffer> {50return new Promise<VSBuffer>((complete) => {51this._currentComplete = complete;52this._trigger();53});54}55}5657class EtherStream extends EventEmitter {58constructor(59private readonly _ether: Ether,60private readonly _name: 'a' | 'b'61) {62super();63}6465write(data: Buffer, cb?: Function): boolean {66if (!Buffer.isBuffer(data)) {67throw new Error(`Invalid data`);68}69this._ether.write(this._name, data);70return true;71}7273destroy(): void {74}75}7677class Ether {7879private readonly _a: EtherStream;80private readonly _b: EtherStream;8182private _ab: Buffer[];83private _ba: Buffer[];8485public get a(): Socket {86// eslint-disable-next-line local/code-no-any-casts87return <any>this._a;88}8990public get b(): Socket {91// eslint-disable-next-line local/code-no-any-casts92return <any>this._b;93}9495constructor(96private readonly _wireLatency = 097) {98this._a = new EtherStream(this, 'a');99this._b = new EtherStream(this, 'b');100this._ab = [];101this._ba = [];102}103104public write(from: 'a' | 'b', data: Buffer): void {105setTimeout(() => {106if (from === 'a') {107this._ab.push(data);108} else {109this._ba.push(data);110}111112setTimeout(() => this._deliver(), 0);113}, this._wireLatency);114}115116private _deliver(): void {117118if (this._ab.length > 0) {119const data = Buffer.concat(this._ab);120this._ab.length = 0;121this._b.emit('data', data);122setTimeout(() => this._deliver(), 0);123return;124}125126if (this._ba.length > 0) {127const data = Buffer.concat(this._ba);128this._ba.length = 0;129this._a.emit('data', data);130setTimeout(() => this._deliver(), 0);131return;132}133134}135}136137suite('IPC, Socket Protocol', () => {138139const ds = ensureNoDisposablesAreLeakedInTestSuite();140141let ether: Ether;142143setup(() => {144ether = new Ether();145});146147test('read/write', async () => {148149const a = new Protocol(new NodeSocket(ether.a));150const b = new Protocol(new NodeSocket(ether.b));151const bMessages = new MessageStream(b);152153a.send(VSBuffer.fromString('foobarfarboo'));154const msg1 = await bMessages.waitForOne();155assert.strictEqual(msg1.toString(), 'foobarfarboo');156157const buffer = VSBuffer.alloc(1);158buffer.writeUInt8(123, 0);159a.send(buffer);160const msg2 = await bMessages.waitForOne();161assert.strictEqual(msg2.readUInt8(0), 123);162163bMessages.dispose();164a.dispose();165b.dispose();166});167168169test('read/write, object data', async () => {170171const a = new Protocol(new NodeSocket(ether.a));172const b = new Protocol(new NodeSocket(ether.b));173const bMessages = new MessageStream(b);174175const data = {176pi: Math.PI,177foo: 'bar',178more: true,179data: 'Hello World'.split('')180};181182a.send(VSBuffer.fromString(JSON.stringify(data)));183const msg = await bMessages.waitForOne();184assert.deepStrictEqual(JSON.parse(msg.toString()), data);185186bMessages.dispose();187a.dispose();188b.dispose();189});190191192193test('issue #211462: destroy socket after end timeout', async () => {194const socket = new EventEmitter();195Object.assign(socket, { destroy: () => socket.emit('close') });196const protocol = ds.add(new Protocol(new NodeSocket(socket as Socket)));197198const disposed = sinon.stub();199const timers = sinon.useFakeTimers();200201ds.add(toDisposable(() => timers.restore()));202ds.add(protocol.onDidDispose(disposed));203204socket.emit('end');205assert.ok(!disposed.called);206timers.tick(29_999);207assert.ok(!disposed.called);208timers.tick(1);209assert.ok(disposed.called);210});211});212213suite('PersistentProtocol reconnection', () => {214215ensureNoDisposablesAreLeakedInTestSuite();216217test('acks get piggybacked with messages', async () => {218const ether = new Ether();219const a = new PersistentProtocol({ socket: new NodeSocket(ether.a) });220const aMessages = new MessageStream(a);221const b = new PersistentProtocol({ socket: new NodeSocket(ether.b) });222const bMessages = new MessageStream(b);223224a.send(VSBuffer.fromString('a1'));225assert.strictEqual(a.unacknowledgedCount, 1);226assert.strictEqual(b.unacknowledgedCount, 0);227228a.send(VSBuffer.fromString('a2'));229assert.strictEqual(a.unacknowledgedCount, 2);230assert.strictEqual(b.unacknowledgedCount, 0);231232a.send(VSBuffer.fromString('a3'));233assert.strictEqual(a.unacknowledgedCount, 3);234assert.strictEqual(b.unacknowledgedCount, 0);235236const a1 = await bMessages.waitForOne();237assert.strictEqual(a1.toString(), 'a1');238assert.strictEqual(a.unacknowledgedCount, 3);239assert.strictEqual(b.unacknowledgedCount, 0);240241const a2 = await bMessages.waitForOne();242assert.strictEqual(a2.toString(), 'a2');243assert.strictEqual(a.unacknowledgedCount, 3);244assert.strictEqual(b.unacknowledgedCount, 0);245246const a3 = await bMessages.waitForOne();247assert.strictEqual(a3.toString(), 'a3');248assert.strictEqual(a.unacknowledgedCount, 3);249assert.strictEqual(b.unacknowledgedCount, 0);250251b.send(VSBuffer.fromString('b1'));252assert.strictEqual(a.unacknowledgedCount, 3);253assert.strictEqual(b.unacknowledgedCount, 1);254255const b1 = await aMessages.waitForOne();256assert.strictEqual(b1.toString(), 'b1');257assert.strictEqual(a.unacknowledgedCount, 0);258assert.strictEqual(b.unacknowledgedCount, 1);259260a.send(VSBuffer.fromString('a4'));261assert.strictEqual(a.unacknowledgedCount, 1);262assert.strictEqual(b.unacknowledgedCount, 1);263264const b2 = await bMessages.waitForOne();265assert.strictEqual(b2.toString(), 'a4');266assert.strictEqual(a.unacknowledgedCount, 1);267assert.strictEqual(b.unacknowledgedCount, 0);268269aMessages.dispose();270bMessages.dispose();271a.dispose();272b.dispose();273});274275test('ack gets sent after a while', async () => {276await runWithFakedTimers({ useFakeTimers: true, maxTaskCount: 100 }, async () => {277const loadEstimator: ILoadEstimator = {278hasHighLoad: () => false279};280const ether = new Ether();281const aSocket = new NodeSocket(ether.a);282const a = new PersistentProtocol({ socket: aSocket, loadEstimator });283const aMessages = new MessageStream(a);284const bSocket = new NodeSocket(ether.b);285const b = new PersistentProtocol({ socket: bSocket, loadEstimator });286const bMessages = new MessageStream(b);287288// send one message A -> B289a.send(VSBuffer.fromString('a1'));290assert.strictEqual(a.unacknowledgedCount, 1);291assert.strictEqual(b.unacknowledgedCount, 0);292const a1 = await bMessages.waitForOne();293assert.strictEqual(a1.toString(), 'a1');294assert.strictEqual(a.unacknowledgedCount, 1);295assert.strictEqual(b.unacknowledgedCount, 0);296297// wait for ack to arrive B -> A298await timeout(2 * ProtocolConstants.AcknowledgeTime);299assert.strictEqual(a.unacknowledgedCount, 0);300assert.strictEqual(b.unacknowledgedCount, 0);301302aMessages.dispose();303bMessages.dispose();304a.dispose();305b.dispose();306});307});308309test('messages that are never written to a socket should not cause an ack timeout', async () => {310await runWithFakedTimers(311{312useFakeTimers: true,313useSetImmediate: true,314maxTaskCount: 1000315},316async () => {317// Date.now() in fake timers starts at 0, which is very inconvenient318// since we want to test exactly that a certain field is not initialized with Date.now()319// As a workaround we wait such that Date.now() starts producing more realistic values320await timeout(60 * 60 * 1000);321322const loadEstimator: ILoadEstimator = {323hasHighLoad: () => false324};325const ether = new Ether();326const aSocket = new NodeSocket(ether.a);327const a = new PersistentProtocol({ socket: aSocket, loadEstimator, sendKeepAlive: false });328const aMessages = new MessageStream(a);329const bSocket = new NodeSocket(ether.b);330const b = new PersistentProtocol({ socket: bSocket, loadEstimator, sendKeepAlive: false });331const bMessages = new MessageStream(b);332333// send message a1 before reconnection to get _recvAckCheck() scheduled334a.send(VSBuffer.fromString('a1'));335assert.strictEqual(a.unacknowledgedCount, 1);336assert.strictEqual(b.unacknowledgedCount, 0);337338// read message a1 at B339const a1 = await bMessages.waitForOne();340assert.strictEqual(a1.toString(), 'a1');341assert.strictEqual(a.unacknowledgedCount, 1);342assert.strictEqual(b.unacknowledgedCount, 0);343344// send message b1 to send the ack for a1345b.send(VSBuffer.fromString('b1'));346assert.strictEqual(a.unacknowledgedCount, 1);347assert.strictEqual(b.unacknowledgedCount, 1);348349// read message b1 at A to receive the ack for a1350const b1 = await aMessages.waitForOne();351assert.strictEqual(b1.toString(), 'b1');352assert.strictEqual(a.unacknowledgedCount, 0);353assert.strictEqual(b.unacknowledgedCount, 1);354355// begin reconnection356aSocket.dispose();357const aSocket2 = new NodeSocket(ether.a);358a.beginAcceptReconnection(aSocket2, null);359360let timeoutListenerCalled = false;361const socketTimeoutListener = a.onSocketTimeout(() => {362timeoutListenerCalled = true;363});364365// send message 2 during reconnection366a.send(VSBuffer.fromString('a2'));367assert.strictEqual(a.unacknowledgedCount, 1);368assert.strictEqual(b.unacknowledgedCount, 1);369370// wait for scheduled _recvAckCheck() to execute371await timeout(2 * ProtocolConstants.TimeoutTime);372373assert.strictEqual(a.unacknowledgedCount, 1);374assert.strictEqual(b.unacknowledgedCount, 1);375assert.strictEqual(timeoutListenerCalled, false);376377a.endAcceptReconnection();378assert.strictEqual(timeoutListenerCalled, false);379380await timeout(2 * ProtocolConstants.TimeoutTime);381assert.strictEqual(a.unacknowledgedCount, 0);382assert.strictEqual(b.unacknowledgedCount, 0);383assert.strictEqual(timeoutListenerCalled, false);384385socketTimeoutListener.dispose();386aMessages.dispose();387bMessages.dispose();388a.dispose();389b.dispose();390}391);392});393394test('acks are always sent after a reconnection', async () => {395await runWithFakedTimers(396{397useFakeTimers: true,398useSetImmediate: true,399maxTaskCount: 1000400},401async () => {402403const loadEstimator: ILoadEstimator = {404hasHighLoad: () => false405};406const wireLatency = 1000;407const ether = new Ether(wireLatency);408const aSocket = new NodeSocket(ether.a);409const a = new PersistentProtocol({ socket: aSocket, loadEstimator });410const aMessages = new MessageStream(a);411const bSocket = new NodeSocket(ether.b);412const b = new PersistentProtocol({ socket: bSocket, loadEstimator });413const bMessages = new MessageStream(b);414415// send message a1 to have something unacknowledged416a.send(VSBuffer.fromString('a1'));417assert.strictEqual(a.unacknowledgedCount, 1);418assert.strictEqual(b.unacknowledgedCount, 0);419420// read message a1 at B421const a1 = await bMessages.waitForOne();422assert.strictEqual(a1.toString(), 'a1');423assert.strictEqual(a.unacknowledgedCount, 1);424assert.strictEqual(b.unacknowledgedCount, 0);425426// wait for B to send an ACK message,427// but resume before A receives it428await timeout(ProtocolConstants.AcknowledgeTime + wireLatency / 2);429assert.strictEqual(a.unacknowledgedCount, 1);430assert.strictEqual(b.unacknowledgedCount, 0);431432// simulate complete reconnection433aSocket.dispose();434bSocket.dispose();435const ether2 = new Ether(wireLatency);436const aSocket2 = new NodeSocket(ether2.a);437const bSocket2 = new NodeSocket(ether2.b);438b.beginAcceptReconnection(bSocket2, null);439b.endAcceptReconnection();440a.beginAcceptReconnection(aSocket2, null);441a.endAcceptReconnection();442443// wait for quite some time444await timeout(2 * ProtocolConstants.AcknowledgeTime + wireLatency);445assert.strictEqual(a.unacknowledgedCount, 0);446assert.strictEqual(b.unacknowledgedCount, 0);447448aMessages.dispose();449bMessages.dispose();450a.dispose();451b.dispose();452}453);454});455456test('onSocketTimeout is emitted at most once every 20s', async () => {457await runWithFakedTimers(458{459useFakeTimers: true,460useSetImmediate: true,461maxTaskCount: 1000462},463async () => {464465const loadEstimator: ILoadEstimator = {466hasHighLoad: () => false467};468const ether = new Ether();469const aSocket = new NodeSocket(ether.a);470const a = new PersistentProtocol({ socket: aSocket, loadEstimator });471const aMessages = new MessageStream(a);472const bSocket = new NodeSocket(ether.b);473const b = new PersistentProtocol({ socket: bSocket, loadEstimator });474const bMessages = new MessageStream(b);475476// never receive acks477b.pauseSocketWriting();478479// send message a1 to have something unacknowledged480a.send(VSBuffer.fromString('a1'));481482// wait for the first timeout to fire483await Event.toPromise(a.onSocketTimeout);484485let timeoutFiredAgain = false;486const timeoutListener = a.onSocketTimeout(() => {487timeoutFiredAgain = true;488});489490// send more messages491a.send(VSBuffer.fromString('a2'));492a.send(VSBuffer.fromString('a3'));493494// wait for 10s495await timeout(ProtocolConstants.TimeoutTime / 2);496497assert.strictEqual(timeoutFiredAgain, false);498499timeoutListener.dispose();500aMessages.dispose();501bMessages.dispose();502a.dispose();503b.dispose();504}505);506});507508test('writing can be paused', async () => {509await runWithFakedTimers({ useFakeTimers: true, maxTaskCount: 100 }, async () => {510const loadEstimator: ILoadEstimator = {511hasHighLoad: () => false512};513const ether = new Ether();514const aSocket = new NodeSocket(ether.a);515const a = new PersistentProtocol({ socket: aSocket, loadEstimator });516const aMessages = new MessageStream(a);517const bSocket = new NodeSocket(ether.b);518const b = new PersistentProtocol({ socket: bSocket, loadEstimator });519const bMessages = new MessageStream(b);520521// send one message A -> B522a.send(VSBuffer.fromString('a1'));523const a1 = await bMessages.waitForOne();524assert.strictEqual(a1.toString(), 'a1');525526// ask A to pause writing527b.sendPause();528529// send a message B -> A530b.send(VSBuffer.fromString('b1'));531const b1 = await aMessages.waitForOne();532assert.strictEqual(b1.toString(), 'b1');533534// send a message A -> B (this should be blocked at A)535a.send(VSBuffer.fromString('a2'));536537// wait a long time and check that not even acks are written538await timeout(2 * ProtocolConstants.AcknowledgeTime);539assert.strictEqual(a.unacknowledgedCount, 1);540assert.strictEqual(b.unacknowledgedCount, 1);541542// ask A to resume writing543b.sendResume();544545// check that B receives message546const a2 = await bMessages.waitForOne();547assert.strictEqual(a2.toString(), 'a2');548549// wait a long time and check that acks are written550await timeout(2 * ProtocolConstants.AcknowledgeTime);551assert.strictEqual(a.unacknowledgedCount, 0);552assert.strictEqual(b.unacknowledgedCount, 0);553554aMessages.dispose();555bMessages.dispose();556a.dispose();557b.dispose();558});559});560});561562flakySuite('IPC, create handle', () => {563564test('createRandomIPCHandle', async () => {565return testIPCHandle(createRandomIPCHandle());566});567568test('createStaticIPCHandle', async () => {569return testIPCHandle(createStaticIPCHandle(tmpdir(), 'test', '1.64.0'));570});571572function testIPCHandle(handle: string): Promise<void> {573return new Promise<void>((resolve, reject) => {574const pipeName = createRandomIPCHandle();575576const server = createServer();577578server.on('error', () => {579return new Promise(() => server.close(() => reject()));580});581582server.listen(pipeName, () => {583server.removeListener('error', reject);584585return new Promise(() => {586server.close(() => resolve());587});588});589});590}591592});593594suite('WebSocketNodeSocket', () => {595596const ds = ensureNoDisposablesAreLeakedInTestSuite();597598function toUint8Array(data: number[]): Uint8Array {599const result = new Uint8Array(data.length);600for (let i = 0; i < data.length; i++) {601result[i] = data[i];602}603return result;604}605606function fromUint8Array(data: Uint8Array): number[] {607const result = [];608for (let i = 0; i < data.length; i++) {609result[i] = data[i];610}611return result;612}613614function fromCharCodeArray(data: number[]): string {615let result = '';616for (let i = 0; i < data.length; i++) {617result += String.fromCharCode(data[i]);618}619return result;620}621622class FakeNodeSocket extends Disposable {623624private readonly _onData = new Emitter<VSBuffer>();625public readonly onData = this._onData.event;626627private readonly _onClose = new Emitter<SocketCloseEvent>();628public readonly onClose = this._onClose.event;629630public writtenData: VSBuffer[] = [];631632public traceSocketEvent(type: SocketDiagnosticsEventType, data?: VSBuffer | Uint8Array | ArrayBuffer | ArrayBufferView | any): void {633}634635constructor() {636super();637}638639public write(data: VSBuffer): void {640this.writtenData.push(data);641}642643public fireData(data: number[]): void {644this._onData.fire(VSBuffer.wrap(toUint8Array(data)));645}646}647648async function testReading(frames: number[][], permessageDeflate: boolean): Promise<string> {649const disposables = new DisposableStore();650const socket = new FakeNodeSocket();651// eslint-disable-next-line local/code-no-any-casts652const webSocket = disposables.add(new WebSocketNodeSocket(<any>socket, permessageDeflate, null, false));653654const barrier = new Barrier();655let remainingFrameCount = frames.length;656657let receivedData: string = '';658disposables.add(webSocket.onData((buff) => {659receivedData += fromCharCodeArray(fromUint8Array(buff.buffer));660remainingFrameCount--;661if (remainingFrameCount === 0) {662barrier.open();663}664}));665666for (let i = 0; i < frames.length; i++) {667socket.fireData(frames[i]);668}669670await barrier.wait();671672disposables.dispose();673674return receivedData;675}676677test('A single-frame unmasked text message', async () => {678const frames = [679[0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f] // contains "Hello"680];681const actual = await testReading(frames, false);682assert.deepStrictEqual(actual, 'Hello');683});684685test('A single-frame masked text message', async () => {686const frames = [687[0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58] // contains "Hello"688];689const actual = await testReading(frames, false);690assert.deepStrictEqual(actual, 'Hello');691});692693test('A fragmented unmasked text message', async () => {694// contains "Hello"695const frames = [696[0x01, 0x03, 0x48, 0x65, 0x6c], // contains "Hel"697[0x80, 0x02, 0x6c, 0x6f], // contains "lo"698];699const actual = await testReading(frames, false);700assert.deepStrictEqual(actual, 'Hello');701});702703suite('compression', () => {704test('A single-frame compressed text message', async () => {705// contains "Hello"706const frames = [707[0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00], // contains "Hello"708];709const actual = await testReading(frames, true);710assert.deepStrictEqual(actual, 'Hello');711});712713test('A fragmented compressed text message', async () => {714// contains "Hello"715const frames = [ // contains "Hello"716[0x41, 0x03, 0xf2, 0x48, 0xcd],717[0x80, 0x04, 0xc9, 0xc9, 0x07, 0x00]718];719const actual = await testReading(frames, true);720assert.deepStrictEqual(actual, 'Hello');721});722723test('A single-frame non-compressed text message', async () => {724const frames = [725[0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f] // contains "Hello"726];727const actual = await testReading(frames, true);728assert.deepStrictEqual(actual, 'Hello');729});730731test('A single-frame compressed text message followed by a single-frame non-compressed text message', async () => {732const frames = [733[0xc1, 0x07, 0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00], // contains "Hello"734[0x81, 0x05, 0x77, 0x6f, 0x72, 0x6c, 0x64] // contains "world"735];736const actual = await testReading(frames, true);737assert.deepStrictEqual(actual, 'Helloworld');738});739});740741test('Large buffers are split and sent in chunks', async () => {742743let receivingSideOnDataCallCount = 0;744let receivingSideTotalBytes = 0;745const receivingSideSocketClosedBarrier = new Barrier();746747const server = await listenOnRandomPort((socket) => {748// stop the server when the first connection is received749server.close();750751const webSocketNodeSocket = new WebSocketNodeSocket(new NodeSocket(socket), true, null, false);752ds.add(webSocketNodeSocket.onData((data) => {753receivingSideOnDataCallCount++;754receivingSideTotalBytes += data.byteLength;755}));756757ds.add(webSocketNodeSocket.onClose(() => {758webSocketNodeSocket.dispose();759receivingSideSocketClosedBarrier.open();760}));761});762763const socket = connect({764host: '127.0.0.1',765port: (<AddressInfo>server.address()).port766});767768const buff = generateRandomBuffer(1 * 1024 * 1024);769770const webSocketNodeSocket = new WebSocketNodeSocket(new NodeSocket(socket), true, null, false);771webSocketNodeSocket.write(buff);772await webSocketNodeSocket.drain();773webSocketNodeSocket.dispose();774await receivingSideSocketClosedBarrier.wait();775776assert.strictEqual(receivingSideTotalBytes, buff.byteLength);777assert.strictEqual(receivingSideOnDataCallCount, 4);778});779780test('issue #194284: ping/pong opcodes are supported', async () => {781782const disposables = new DisposableStore();783const socket = new FakeNodeSocket();784// eslint-disable-next-line local/code-no-any-casts785const webSocket = disposables.add(new WebSocketNodeSocket(<any>socket, false, null, false));786787let receivedData: string = '';788disposables.add(webSocket.onData((buff) => {789receivedData += fromCharCodeArray(fromUint8Array(buff.buffer));790}));791792// A single-frame non-compressed text message that contains "Hello"793socket.fireData([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]);794795// A ping message that contains "data"796socket.fireData([0x89, 0x04, 0x64, 0x61, 0x74, 0x61]);797798// Another single-frame non-compressed text message that contains "Hello"799socket.fireData([0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f]);800801assert.strictEqual(receivedData, 'HelloHello');802assert.deepStrictEqual(803socket.writtenData.map(x => fromUint8Array(x.buffer)),804[805// A pong message that contains "data"806[0x8A, 0x04, 0x64, 0x61, 0x74, 0x61]807]808);809810disposables.dispose();811812return receivedData;813});814815function generateRandomBuffer(size: number): VSBuffer {816const buff = VSBuffer.alloc(size);817for (let i = 0; i < size; i++) {818buff.writeUInt8(Math.floor(256 * Math.random()), i);819}820return buff;821}822823function listenOnRandomPort(handler: (socket: Socket) => void): Promise<Server> {824return new Promise((resolve, reject) => {825const server = createServer(handler).listen(0);826server.on('listening', () => {827resolve(server);828});829server.on('error', (err) => {830reject(err);831});832});833}834});835836837