Path: blob/main/src/vs/workbench/test/electron-browser/resolveExternal.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*--------------------------------------------------------------------------------------------*/4import assert from 'assert';5import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js';6import { NativeWindow } from '../../electron-browser/window.js';7import { ITunnelService, RemoteTunnel } from '../../../platform/tunnel/common/tunnel.js';8import { URI } from '../../../base/common/uri.js';9import { TestInstantiationService } from '../../../platform/instantiation/test/common/instantiationServiceMock.js';10import { IAddressProvider } from '../../../platform/remote/common/remoteAgentConnection.js';11import { workbenchInstantiationService } from './workbenchTestServices.js';12import { DisposableStore } from '../../../base/common/lifecycle.js';1314type PortMap = Record<number, number>;1516class TunnelMock implements Partial<ITunnelService> {17private assignedPorts: PortMap = {};18private expectedDispose = false;1920reset(ports: PortMap) {21this.assignedPorts = ports;22}2324expectDispose() {25this.expectedDispose = true;26}2728getExistingTunnel(): Promise<string | RemoteTunnel | undefined> {29return Promise.resolve(undefined);30}3132openTunnel(_addressProvider: IAddressProvider | undefined, _host: string | undefined, port: number): Promise<RemoteTunnel | string | undefined> | undefined {33if (!this.assignedPorts[port]) {34return Promise.reject(new Error('Unexpected tunnel request'));35}36const res: RemoteTunnel = {37localAddress: `localhost:${this.assignedPorts[port]}`,38tunnelRemoteHost: '4.3.2.1',39tunnelRemotePort: this.assignedPorts[port],40privacy: '',41dispose: () => {42assert(this.expectedDispose, 'Unexpected dispose');43this.expectedDispose = false;44return Promise.resolve();45}46};47delete this.assignedPorts[port];48return Promise.resolve(res);49}5051validate() {52try {53assert(Object.keys(this.assignedPorts).length === 0, 'Expected tunnel to be used');54assert(!this.expectedDispose, 'Expected dispose to be called');55} finally {56this.expectedDispose = false;57}58}59}6061class TestNativeWindow extends NativeWindow {62protected override create(): void { }63protected override registerListeners(): void { }64protected override enableMultiWindowAwareTimeout(): void { }65}6667suite.skip('NativeWindow:resolveExternal', () => {68const disposables = new DisposableStore();69const tunnelMock = new TunnelMock();70let window: TestNativeWindow;7172setup(() => {73const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);74instantiationService.stub(ITunnelService, tunnelMock);75window = disposables.add(instantiationService.createInstance(TestNativeWindow));76});7778teardown(() => {79disposables.clear();80});8182async function doTest(uri: string, ports: PortMap = {}, expectedUri?: string) {83tunnelMock.reset(ports);84const res = await window.resolveExternalUri(URI.parse(uri), {85allowTunneling: true,86openExternal: true87});88assert.strictEqual(!expectedUri, !res, `Expected URI ${expectedUri} but got ${res}`);89if (expectedUri && res) {90assert.strictEqual(res.resolved.toString(), URI.parse(expectedUri).toString());91}92tunnelMock.validate();93}9495test('invalid', async () => {96await doTest('file:///foo.bar/baz');97await doTest('http://foo.bar/path');98});99test('simple', async () => {100await doTest('http://localhost:1234/path', { 1234: 1234 }, 'http://localhost:1234/path');101});102test('all interfaces', async () => {103await doTest('http://0.0.0.0:1234/path', { 1234: 1234 }, 'http://localhost:1234/path');104});105test('changed port', async () => {106await doTest('http://localhost:1234/path', { 1234: 1235 }, 'http://localhost:1235/path');107});108test('query', async () => {109await doTest('http://foo.bar/path?a=b&c=http%3a%2f%2flocalhost%3a4455', { 4455: 4455 }, 'http://foo.bar/path?a=b&c=http%3a%2f%2flocalhost%3a4455');110});111test('query with different port', async () => {112tunnelMock.expectDispose();113await doTest('http://foo.bar/path?a=b&c=http%3a%2f%2flocalhost%3a4455', { 4455: 4567 });114});115test('both url and query', async () => {116await doTest('http://localhost:1234/path?a=b&c=http%3a%2f%2flocalhost%3a4455',117{ 1234: 4321, 4455: 4455 },118'http://localhost:4321/path?a=b&c=http%3a%2f%2flocalhost%3a4455');119});120test('both url and query, query rejected', async () => {121tunnelMock.expectDispose();122await doTest('http://localhost:1234/path?a=b&c=http%3a%2f%2flocalhost%3a4455',123{ 1234: 4321, 4455: 5544 },124'http://localhost:4321/path?a=b&c=http%3a%2f%2flocalhost%3a4455');125});126127ensureNoDisposablesAreLeakedInTestSuite();128});129130131