Path: blob/main/src/vs/workbench/api/test/browser/mainThreadManagedSockets.test.ts
3296 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 { disposableTimeout, timeout } from '../../../../base/common/async.js';7import { VSBuffer } from '../../../../base/common/buffer.js';8import { Emitter } from '../../../../base/common/event.js';9import { DisposableStore } from '../../../../base/common/lifecycle.js';10import { SocketCloseEvent } from '../../../../base/parts/ipc/common/ipc.net.js';11import { mock } from '../../../../base/test/common/mock.js';12import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';13import { RemoteSocketHalf } from '../../../../platform/remote/common/managedSocket.js';14import { MainThreadManagedSocket } from '../../browser/mainThreadManagedSockets.js';15import { ExtHostManagedSocketsShape } from '../../common/extHost.protocol.js';1617suite('MainThreadManagedSockets', () => {1819const ds = ensureNoDisposablesAreLeakedInTestSuite();2021suite('ManagedSocket', () => {22let extHost: ExtHostMock;23let half: RemoteSocketHalf;2425class ExtHostMock extends mock<ExtHostManagedSocketsShape>() {26private onDidFire = new Emitter<void>();27public readonly events: any[] = [];2829override $remoteSocketWrite(socketId: number, buffer: VSBuffer): void {30this.events.push({ socketId, data: buffer.toString() });31this.onDidFire.fire();32}3334override $remoteSocketDrain(socketId: number) {35this.events.push({ socketId, event: 'drain' });36this.onDidFire.fire();37return Promise.resolve();38}3940override $remoteSocketEnd(socketId: number) {41this.events.push({ socketId, event: 'end' });42this.onDidFire.fire();43}4445expectEvent(test: (evt: any) => void, message: string) {46if (this.events.some(test)) {47return;48}4950const d = new DisposableStore();51return new Promise<void>(resolve => {52d.add(this.onDidFire.event(() => {53if (this.events.some(test)) {54return;55}56}));57d.add(disposableTimeout(() => {58throw new Error(`Expected ${message} but only had ${JSON.stringify(this.events, null, 2)}`);59}, 1000));60}).finally(() => d.dispose());61}62}6364setup(() => {65extHost = new ExtHostMock();66half = {67onClose: new Emitter<SocketCloseEvent>(),68onData: new Emitter<VSBuffer>(),69onEnd: new Emitter<void>(),70};71});7273async function doConnect() {74const socket = MainThreadManagedSocket.connect(1, extHost, '/hello', 'world=true', '', half);75await extHost.expectEvent(evt => evt.data && evt.data.startsWith('GET ws://localhost/hello?world=true&skipWebSocketFrames=true HTTP/1.1\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Key:'), 'websocket open event');76half.onData.fire(VSBuffer.fromString('Opened successfully ;)\r\n\r\n'));77return ds.add(await socket);78}7980test('connects', async () => {81await doConnect();82});8384test('includes trailing connection data', async () => {85const socketProm = MainThreadManagedSocket.connect(1, extHost, '/hello', 'world=true', '', half);86await extHost.expectEvent(evt => evt.data && evt.data.includes('GET ws://localhost'), 'websocket open event');87half.onData.fire(VSBuffer.fromString('Opened successfully ;)\r\n\r\nSome trailing data'));88const socket = ds.add(await socketProm);8990const data: string[] = [];91ds.add(socket.onData(d => data.push(d.toString())));92await timeout(1); // allow microtasks to flush93assert.deepStrictEqual(data, ['Some trailing data']);94});9596test('round trips data', async () => {97const socket = await doConnect();98const data: string[] = [];99ds.add(socket.onData(d => data.push(d.toString())));100101socket.write(VSBuffer.fromString('ping'));102await extHost.expectEvent(evt => evt.data === 'ping', 'expected ping');103half.onData.fire(VSBuffer.fromString("pong"));104assert.deepStrictEqual(data, ['pong']);105});106});107});108109110