mirror of
https://github.com/Microsoft/vscode
synced 2024-10-02 09:18:59 +00:00
Add more logging and perf markers around resolving the connection token and the socket factory (#170490)
* Add more logging and perf markers around resolving the connection token and the socket factory * set `exposeFunction` earlier * bla windows * also expose function for unit tests beofre opening Co-authored-by: Benjamin Pasero <benjamin.pasero@microsoft.com>
This commit is contained in:
parent
79c4f9b75d
commit
06b97f6be7
|
@ -6,9 +6,12 @@
|
|||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { RemoteAuthorities } from 'vs/base/common/network';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService {
|
||||
|
@ -23,7 +26,12 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
private readonly _connectionToken: Promise<string> | string | undefined;
|
||||
private readonly _connectionTokens: Map<string, string>;
|
||||
|
||||
constructor(@IProductService productService: IProductService, connectionToken: Promise<string> | string | undefined, resourceUriProvider: ((uri: URI) => URI) | undefined) {
|
||||
constructor(
|
||||
connectionToken: Promise<string> | string | undefined,
|
||||
resourceUriProvider: ((uri: URI) => URI) | undefined,
|
||||
@IProductService productService: IProductService,
|
||||
@ILogService private readonly _logService: ILogService,
|
||||
) {
|
||||
super();
|
||||
this._connectionToken = connectionToken;
|
||||
this._connectionTokens = new Map<string, string>();
|
||||
|
@ -60,7 +68,13 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot
|
|||
}
|
||||
|
||||
private async _doResolveAuthority(authority: string): Promise<ResolverResult> {
|
||||
const authorityPrefix = getRemoteAuthorityPrefix(authority);
|
||||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`Resolving connection token (${authorityPrefix})...`);
|
||||
performance.mark(`code/willResolveConnectionToken/${authorityPrefix}`);
|
||||
const connectionToken = await Promise.resolve(this._connectionTokens.get(authority) || this._connectionToken);
|
||||
performance.mark(`code/didResolveConnectionToken/${authorityPrefix}`);
|
||||
this._logService.info(`Resolved connection token (${authorityPrefix}) after ${sw.elapsed()} ms`);
|
||||
const defaultPort = (/^https:/.test(window.location.href) ? 443 : 80);
|
||||
const { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort);
|
||||
const result: ResolverResult = { authority: { authority, host: host, port: port, connectionToken } };
|
||||
|
|
|
@ -9,6 +9,8 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cance
|
|||
import { isCancellationError, onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IIPCLogger } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Client, ConnectionHealth, ISocket, PersistentProtocol, ProtocolConstants, SocketCloseEventType } from 'vs/base/parts/ipc/common/ipc.net';
|
||||
|
@ -190,18 +192,27 @@ function readOneControlMessage<T>(protocol: PersistentProtocol, timeoutCancellat
|
|||
return result.promise;
|
||||
}
|
||||
|
||||
function createSocket(logService: ILogService, socketFactory: ISocketFactory, host: string, port: number, path: string, query: string, debugLabel: string, timeoutCancellationToken: CancellationToken): Promise<ISocket> {
|
||||
function createSocket(logService: ILogService, socketFactory: ISocketFactory, host: string, port: number, path: string, query: string, debugConnectionType: string, debugLabel: string, timeoutCancellationToken: CancellationToken): Promise<ISocket> {
|
||||
const result = new PromiseWithTimeout<ISocket>(timeoutCancellationToken);
|
||||
const sw = StopWatch.create(false);
|
||||
logService.info(`Creating a socket (${debugLabel})...`);
|
||||
performance.mark(`code/willCreateSocket/${debugConnectionType}`);
|
||||
socketFactory.connect(host, port, path, query, debugLabel, (err: any, socket: ISocket | undefined) => {
|
||||
if (result.didTimeout) {
|
||||
performance.mark(`code/didCreateSocketError/${debugConnectionType}`);
|
||||
logService.info(`Creating a socket (${debugLabel}) finished after ${sw.elapsed()} ms, but this is too late and has timed out already.`);
|
||||
if (err) {
|
||||
logService.error(err);
|
||||
}
|
||||
socket?.dispose();
|
||||
} else {
|
||||
if (err || !socket) {
|
||||
performance.mark(`code/didCreateSocketError/${debugConnectionType}`);
|
||||
logService.info(`Creating a socket (${debugLabel}) returned an error after ${sw.elapsed()} ms.`);
|
||||
result.reject(err);
|
||||
} else {
|
||||
performance.mark(`code/didCreateSocketOK/${debugConnectionType}`);
|
||||
logService.info(`Creating a socket (${debugLabel}) was successful after ${sw.elapsed()} ms.`);
|
||||
result.resolve(socket);
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +244,7 @@ async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptio
|
|||
|
||||
let socket: ISocket;
|
||||
try {
|
||||
socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, getRemoteServerRootPath(options), `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken);
|
||||
socket = await createSocket(options.logService, options.socketFactory, options.host, options.port, getRemoteServerRootPath(options), `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, connectionTypeToString(connectionType), `renderer-${connectionTypeToString(connectionType)}-${options.reconnectionToken}`, timeoutCancellationToken);
|
||||
} catch (error) {
|
||||
options.logService.error(`${logPrefix} socketFactory.connect() failed or timed out. Error:`);
|
||||
options.logService.error(error);
|
||||
|
|
|
@ -124,3 +124,11 @@ export interface IRemoteAuthorityResolverService {
|
|||
_setAuthorityConnectionToken(authority: string, connectionToken: string): void;
|
||||
_setCanonicalURIProvider(provider: (uri: URI) => Promise<URI>): void;
|
||||
}
|
||||
|
||||
export function getRemoteAuthorityPrefix(remoteAuthority: string): string {
|
||||
const plusIndex = remoteAuthority.indexOf('+');
|
||||
if (plusIndex === -1) {
|
||||
return remoteAuthority;
|
||||
}
|
||||
return remoteAuthority.substring(0, plusIndex);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
|||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtensionGlobalMemento, ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { RemoteAuthorityResolverError, ExtensionKind, ExtensionMode, ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
|
@ -1039,14 +1039,6 @@ function filterExtensions(globalRegistry: ExtensionDescriptionRegistry, desiredE
|
|||
);
|
||||
}
|
||||
|
||||
function getRemoteAuthorityPrefix(remoteAuthority: string): string {
|
||||
const plusIndex = remoteAuthority.indexOf('+');
|
||||
if (plusIndex === -1) {
|
||||
return remoteAuthority;
|
||||
}
|
||||
return remoteAuthority.substring(0, plusIndex);
|
||||
}
|
||||
|
||||
export class ExtensionPaths {
|
||||
|
||||
constructor(
|
||||
|
|
|
@ -247,7 +247,7 @@ export class BrowserMain extends Disposable {
|
|||
|
||||
// Remote
|
||||
const connectionToken = environmentService.options.connectionToken || getCookieValue(connectionTokenCookieName);
|
||||
const remoteAuthorityResolverService = new RemoteAuthorityResolverService(productService, connectionToken, this.configuration.resourceUriProvider);
|
||||
const remoteAuthorityResolverService = new RemoteAuthorityResolverService(connectionToken, this.configuration.resourceUriProvider, productService, logService);
|
||||
serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService);
|
||||
|
||||
// Signing
|
||||
|
|
|
@ -88,7 +88,7 @@ suite('WorkspaceContextService - Folder', () => {
|
|||
fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService())));
|
||||
const uriIdentityService = new UriIdentityService(fileService);
|
||||
const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, uriIdentityService, logService);
|
||||
testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined, TestProductService, logService), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
await (<WorkspaceService>testObject).initialize(convertToWorkspacePayload(folder));
|
||||
});
|
||||
|
||||
|
@ -130,7 +130,7 @@ suite('WorkspaceContextService - Folder', () => {
|
|||
fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService())));
|
||||
const uriIdentityService = new UriIdentityService(fileService);
|
||||
const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, uriIdentityService, logService);
|
||||
const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined, TestProductService, logService), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
await (<WorkspaceService>testObject).initialize(convertToWorkspacePayload(folder));
|
||||
|
||||
const actual = testObject.getWorkspaceFolder(joinPath(folder, 'a'));
|
||||
|
@ -152,7 +152,7 @@ suite('WorkspaceContextService - Folder', () => {
|
|||
fileService.registerProvider(Schemas.vscodeUserData, disposables.add(new FileUserDataProvider(ROOT.scheme, fileSystemProvider, Schemas.vscodeUserData, new NullLogService())));
|
||||
const uriIdentityService = new UriIdentityService(fileService);
|
||||
const userDataProfilesService = new UserDataProfilesService(environmentService, fileService, uriIdentityService, logService);
|
||||
const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(TestProductService, undefined, undefined), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
const testObject = disposables.add(new WorkspaceService({ configurationCache: new ConfigurationCache() }, environmentService, new UserDataProfileService(userDataProfilesService.defaultProfile, userDataProfilesService), userDataProfilesService, fileService, new RemoteAgentService(null, environmentService, TestProductService, new RemoteAuthorityResolverService(undefined, undefined, TestProductService, logService), new SignService(undefined), new NullLogService()), uriIdentityService, new NullLogService(), new NullPolicyService()));
|
||||
await (<WorkspaceService>testObject).initialize(convertToWorkspacePayload(folder));
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
|
|||
import { ExtHostCustomersRegistry, IInternalExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
|
||||
import { Proxied, ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { RemoteAuthorityResolverErrorCode, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import * as nls from 'vs/nls';
|
||||
import { registerAction2, Action2 } from 'vs/platform/actions/common/actions';
|
||||
|
@ -27,7 +27,6 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IExtensionHostProxy, IResolveAuthorityResult } from 'vs/workbench/services/extensions/common/extensionHostProxy';
|
||||
import { IExtensionDescriptionDelta } from 'vs/workbench/services/extensions/common/extensionHostProtocol';
|
||||
import { getRemoteAuthorityPrefix } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
|
||||
// Enable to see detailed message communication between window and extension host
|
||||
const LOG_EXTENSION_HOST_COMMUNICATION = false;
|
||||
|
|
|
@ -285,10 +285,3 @@ export class RemoteExtensionHost extends Disposable implements IExtensionHost {
|
|||
}
|
||||
}
|
||||
|
||||
export function getRemoteAuthorityPrefix(remoteAuthority: string): string {
|
||||
const plusIndex = remoteAuthority.indexOf('+');
|
||||
if (plusIndex === -1) {
|
||||
return remoteAuthority;
|
||||
}
|
||||
return remoteAuthority.substring(0, plusIndex);
|
||||
}
|
||||
|
|
|
@ -6,14 +6,15 @@
|
|||
import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-sandbox/cachedExtensionScanner';
|
||||
import { AbstractExtensionService, ExtensionHostCrashTracker, ExtensionRunningPreference, extensionRunningPreferenceToString, filterByRunningLocation } from 'vs/workbench/services/extensions/common/abstractExtensionService';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as performance from 'vs/base/common/performance';
|
||||
import { runWhenIdle } from 'vs/base/common/async';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IWorkbenchExtensionEnablementService, EnablementState, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData, getRemoteAuthorityPrefix } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { IRemoteExtensionHostDataProvider, RemoteExtensionHost, IRemoteExtensionHostInitData } from 'vs/workbench/services/extensions/common/remoteExtensionHost';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, RemoteAuthorityResolverErrorCode, ResolverResult, getRemoteAuthorityPrefix } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
|
@ -424,15 +425,9 @@ export class NativeExtensionService extends AbstractExtensionService implements
|
|||
const MAX_ATTEMPTS = 5;
|
||||
|
||||
for (let attempt = 1; ; attempt++) {
|
||||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`[attempt ${attempt}] Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`);
|
||||
try {
|
||||
const resolverResult = await this._resolveAuthority(remoteAuthority);
|
||||
this._logService.info(`[attempt ${attempt}] resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${resolverResult.authority.host}:${resolverResult.authority.port}' after ${sw.elapsed()} ms`);
|
||||
return resolverResult;
|
||||
return this._resolveAuthorityWithLogging(remoteAuthority);
|
||||
} catch (err) {
|
||||
this._logService.error(`[attempt ${attempt}] resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned an error after ${sw.elapsed()} ms`, err);
|
||||
|
||||
if (RemoteAuthorityResolverError.isNoResolverFound(err)) {
|
||||
// There is no point in retrying if there is no resolver found
|
||||
throw err;
|
||||
|
@ -458,18 +453,31 @@ export class NativeExtensionService extends AbstractExtensionService implements
|
|||
}
|
||||
|
||||
this._remoteAuthorityResolverService._clearResolvedAuthority(remoteAuthority);
|
||||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`Invoking resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)})`);
|
||||
try {
|
||||
const result = await this._resolveAuthority(remoteAuthority);
|
||||
this._logService.info(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned '${result.authority.host}:${result.authority.port}' after ${sw.elapsed()} ms`);
|
||||
const result = await this._resolveAuthorityWithLogging(remoteAuthority);
|
||||
this._remoteAuthorityResolverService._setResolvedAuthority(result.authority, result.options);
|
||||
} catch (err) {
|
||||
this._logService.error(`resolveAuthority(${getRemoteAuthorityPrefix(remoteAuthority)}) returned an error after ${sw.elapsed()} ms`, err);
|
||||
this._remoteAuthorityResolverService._setResolvedAuthorityError(remoteAuthority, err);
|
||||
}
|
||||
}
|
||||
|
||||
private async _resolveAuthorityWithLogging(remoteAuthority: string): Promise<ResolverResult> {
|
||||
const authorityPrefix = getRemoteAuthorityPrefix(remoteAuthority);
|
||||
const sw = StopWatch.create(false);
|
||||
this._logService.info(`Invoking resolveAuthority(${authorityPrefix})...`);
|
||||
try {
|
||||
performance.mark(`code/willResolveAuthority/${authorityPrefix}`);
|
||||
const result = await this._resolveAuthority(remoteAuthority);
|
||||
performance.mark(`code/didResolveAuthorityOK/${authorityPrefix}`);
|
||||
this._logService.info(`resolveAuthority(${authorityPrefix}) returned '${result.authority.host}:${result.authority.port}' after ${sw.elapsed()} ms`);
|
||||
return result;
|
||||
} catch (err) {
|
||||
performance.mark(`code/didResolveAuthorityError/${authorityPrefix}`);
|
||||
this._logService.error(`resolveAuthority(${authorityPrefix}) returned an error after ${sw.elapsed()} ms`, err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
protected async _scanAndHandleExtensions(): Promise<void> {
|
||||
this._extensionScanner.startScanningExtensions();
|
||||
|
||||
|
@ -485,12 +493,14 @@ export class NativeExtensionService extends AbstractExtensionService implements
|
|||
// The current remote authority resolver cannot give the canonical URI for this URI
|
||||
return uri;
|
||||
}
|
||||
performance.mark(`code/willGetCanonicalURI/${getRemoteAuthorityPrefix(remoteAuthority)}`);
|
||||
if (isCI) {
|
||||
this._logService.info(`Invoking getCanonicalURI for authority ${getRemoteAuthorityPrefix(remoteAuthority)}...`);
|
||||
}
|
||||
try {
|
||||
return this._getCanonicalURI(remoteAuthority, uri);
|
||||
} finally {
|
||||
performance.mark(`code/didGetCanonicalURI/${getRemoteAuthorityPrefix(remoteAuthority)}`);
|
||||
if (isCI) {
|
||||
this._logService.info(`getCanonicalURI returned for authority ${getRemoteAuthorityPrefix(remoteAuthority)}.`);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,12 @@ type BrowserType = 'chromium' | 'firefox' | 'webkit';
|
|||
async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWithStringQuery, server: cp.ChildProcess): Promise<void> {
|
||||
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
|
||||
const context = await browser.newContext();
|
||||
try {
|
||||
await context.grantPermissions([`clipboard-read`, `clipboard-write`]); // some tests need clipboard access
|
||||
} catch (error) {
|
||||
// ignore, seems to fail on Windows
|
||||
}
|
||||
|
||||
const page = await context.newPage();
|
||||
await page.setViewportSize({ width, height });
|
||||
|
||||
|
@ -58,21 +64,6 @@ async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWith
|
|||
console.error('Request Failed', e.url(), e.failure()?.errorText);
|
||||
});
|
||||
|
||||
const host = endpoint.host;
|
||||
const protocol = 'vscode-remote';
|
||||
|
||||
const testWorkspacePath = URI.file(path.resolve(optimist.argv.workspacePath)).path;
|
||||
const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true });
|
||||
const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true });
|
||||
|
||||
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","ef65ac1ba57f57f2a3961bfe94aa20481caca4c6"],["skipWelcome","true"]]`;
|
||||
|
||||
if (path.extname(testWorkspacePath) === '.code-workspace') {
|
||||
await page.goto(`${endpoint.href}&workspace=${testWorkspacePath}&payload=${payloadParam}`);
|
||||
} else {
|
||||
await page.goto(`${endpoint.href}&folder=${testWorkspacePath}&payload=${payloadParam}`);
|
||||
}
|
||||
|
||||
await page.exposeFunction('codeAutomationLog', (type: string, args: any[]) => {
|
||||
console[type](...args);
|
||||
});
|
||||
|
@ -92,6 +83,21 @@ async function runTestsInBrowser(browserType: BrowserType, endpoint: url.UrlWith
|
|||
|
||||
process.exit(code);
|
||||
});
|
||||
|
||||
const host = endpoint.host;
|
||||
const protocol = 'vscode-remote';
|
||||
|
||||
const testWorkspacePath = URI.file(path.resolve(optimist.argv.workspacePath)).path;
|
||||
const testExtensionUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionDevelopmentPath)).path, protocol, host, slashes: true });
|
||||
const testFilesUri = url.format({ pathname: URI.file(path.resolve(optimist.argv.extensionTestsPath)).path, protocol, host, slashes: true });
|
||||
|
||||
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"],["enableProposedApi",""],["webviewExternalEndpointCommit","ef65ac1ba57f57f2a3961bfe94aa20481caca4c6"],["skipWelcome","true"]]`;
|
||||
|
||||
if (path.extname(testWorkspacePath) === '.code-workspace') {
|
||||
await page.goto(`${endpoint.href}&workspace=${testWorkspacePath}&payload=${payloadParam}`);
|
||||
} else {
|
||||
await page.goto(`${endpoint.href}&folder=${testWorkspacePath}&payload=${payloadParam}`);
|
||||
}
|
||||
}
|
||||
|
||||
function consoleLogFn(msg: playwright.ConsoleMessage) {
|
||||
|
|
|
@ -133,13 +133,14 @@ async function runTestsInBrowser(testModules, browserType) {
|
|||
if (argv.build) {
|
||||
target.search = `?build=true`;
|
||||
}
|
||||
await page.goto(target.href);
|
||||
|
||||
const emitter = new events.EventEmitter();
|
||||
await page.exposeFunction('mocha_report', (type, data1, data2) => {
|
||||
emitter.emit(type, data1, data2);
|
||||
});
|
||||
|
||||
await page.goto(target.href);
|
||||
|
||||
page.on('console', async msg => {
|
||||
consoleLogFn(msg)(msg.text(), await Promise.all(msg.args().map(async arg => await arg.jsonValue())));
|
||||
});
|
||||
|
@ -176,7 +177,7 @@ async function runTestsInBrowser(testModules, browserType) {
|
|||
await browser.close();
|
||||
|
||||
if (failingTests.length > 0) {
|
||||
let res = `The followings tests are failing:\n - ${failingTests.map(({ title, message }) => `${title} (reason: ${message})`).join('\n - ')}`;
|
||||
let res = `The followings tests are failing:\n - ${failingTests.map(({ title, message }) => `${title} (reason: ${message})`).join('\n - ')}`;
|
||||
|
||||
if (failingModuleIds.length > 0) {
|
||||
res += `\n\nTo DEBUG, open ${browserType.toUpperCase()} and navigate to ${target.href}?${failingModuleIds.map(module => `m=${module}`).join('&')}`;
|
||||
|
|
Loading…
Reference in a new issue