diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index b1d9a277cff38..5ad28727bc829 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -412,7 +412,7 @@ export class ExtensionEditor extends BaseEditor { this.instantiationService.createInstance(EnableDropDownAction), this.instantiationService.createInstance(DisableDropDownAction, runningExtensions), - this.instantiationService.createInstance(RemoteInstallAction), + this.instantiationService.createInstance(RemoteInstallAction, false), this.instantiationService.createInstance(LocalInstallAction), combinedInstallAction, systemDisabledWarningAction, diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 9cd3013fb78fe..9b17d113de3a3 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -54,7 +54,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { coalesce } from 'vs/base/common/arrays'; import { IWorkbenchThemeService, IWorkbenchTheme, IWorkbenchColorTheme, IWorkbenchFileIconTheme, IWorkbenchProductIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { prefersExecuteOnUI, prefersExecuteOnWorkspace } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { prefersExecuteOnUI, prefersExecuteOnWorkspace, canExecuteOnUI, canExecuteOnWorkspace } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IProductService } from 'vs/platform/product/common/productService'; import { IFileDialogService, IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -299,7 +299,11 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { constructor( id: string, private readonly server: IExtensionManagementServer | null, + private readonly canInstallAnyWhere: boolean, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, + @IProductService private readonly productService: IProductService, + @IConfigurationService private readonly configurationService: IConfigurationService, ) { super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false); this.update(); @@ -309,11 +313,7 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { this.enabled = false; this.class = InstallInOtherServerAction.Class; - if ( - this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed && this.extension.type === ExtensionType.User - // disabled by extension kind or it is a language pack extension - && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest)) - ) { + if (this.canInstall()) { const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === this.server)[0]; if (extensionInOtherServer) { // Getting installed in other server @@ -330,6 +330,48 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { } } + private canInstall(): boolean { + // Disable if extension is not installed or not an user extension + if ( + !this.extension + || !this.server + || !this.extension.local + || this.extension.state !== ExtensionState.Installed + || this.extension.type !== ExtensionType.User + || this.extension.enablementState === EnablementState.DisabledByEnvironemt + ) { + return false; + } + + if (isLanguagePackExtension(this.extension.local.manifest)) { + return true; + } + + // Prefers to run on UI + if (this.server === this.extensionManagementServerService.localExtensionManagementServer && prefersExecuteOnUI(this.extension.local.manifest, this.productService, this.configurationService)) { + return true; + } + + // Prefers to run on Workspace + if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && prefersExecuteOnWorkspace(this.extension.local.manifest, this.productService, this.configurationService)) { + return true; + } + + if (this.canInstallAnyWhere) { + // Can run on UI + if (this.server === this.extensionManagementServerService.localExtensionManagementServer && canExecuteOnUI(this.extension.local.manifest, this.productService, this.configurationService)) { + return true; + } + + // Can run on Workspace + if (this.server === this.extensionManagementServerService.remoteExtensionManagementServer && canExecuteOnWorkspace(this.extension.local.manifest, this.productService, this.configurationService)) { + return true; + } + } + + return false; + } + async run(): Promise { if (!this.extension) { return; @@ -352,10 +394,13 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { export class RemoteInstallAction extends InstallInOtherServerAction { constructor( + canInstallAnyWhere: boolean, @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService + @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, ) { - super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, extensionsWorkbenchService); + super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, canInstallAnyWhere, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService); } protected getInstallLabel(): string { @@ -368,9 +413,11 @@ export class LocalInstallAction extends InstallInOtherServerAction { constructor( @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService + @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, ) { - super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, extensionsWorkbenchService); + super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, false, extensionsWorkbenchService, extensionManagementServerService, productService, configurationService); } protected getInstallLabel(): string { @@ -1211,6 +1258,7 @@ export class ReloadAction extends ExtensionAction { if (!this._runningExtensions || !this.extension) { return; } + const isUninstalled = this.extension.state === ExtensionState.Uninstalled; const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); @@ -1234,15 +1282,38 @@ export class ReloadAction extends ExtensionAction { if (this.extensionService.canAddExtension(toExtensionDescription(this.extension.local))) { return; } + const runningExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); + if (isSameExtensionRunning) { // Different version of same extension is running. Requires reload to run the current version if (this.extension.version !== runningExtension.version) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); this.tooltip = localize('postUpdateTooltip', "Please reload Visual Studio Code to enable the updated extension."); + return; } + + const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)[0]; + if (extensionInOtherServer) { + // This extension prefers to run on UI/Local side but is running in remote + if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer && prefersExecuteOnUI(this.extension.local!.manifest, this.productService, this.configurationService)) { + this.enabled = true; + this.label = localize('reloadRequired', "Reload Required"); + this.tooltip = localize('enable locally', "Please reload Visual Studio Code to enable this extension locally."); + return; + } + + // This extension prefers to run on Workspace/Remote side but is running in local + if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer && prefersExecuteOnWorkspace(this.extension.local!.manifest, this.productService, this.configurationService)) { + this.enabled = true; + this.label = localize('reloadRequired', "Reload Required"); + this.tooltip = localize('enable remote', "Please reload Visual Studio Code to enable this extension in {0}.", this.extensionManagementServerService.remoteExtensionManagementServer?.label); + return; + } + } + } else { - const runningExtensionServer = this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); + if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { // This extension prefers to run on UI/Local side but is running in remote if (prefersExecuteOnUI(this.extension.local!.manifest, this.productService, this.configurationService)) { @@ -3137,7 +3208,7 @@ export class InstallLocalExtensionsInRemoteAction extends Action { private getExtensionsToInstall(local: IExtension[]): IExtension[] { return local.filter(extension => { - const action = this.instantiationService.createInstance(RemoteInstallAction); + const action = this.instantiationService.createInstance(RemoteInstallAction, true); action.extension = extension; return action.enabled; }); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts index 23187c381cd28..5eb1fff35fd80 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsList.ts @@ -99,7 +99,7 @@ export class Renderer implements IPagedRenderer { this.instantiationService.createInstance(UpdateAction), reloadAction, this.instantiationService.createInstance(InstallAction), - this.instantiationService.createInstance(RemoteInstallAction), + this.instantiationService.createInstance(RemoteInstallAction, false), this.instantiationService.createInstance(LocalInstallAction), this.instantiationService.createInstance(MaliciousStatusLabelAction, false), systemDisabledWarningAction, diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 322be3f8d39c6..dfe557cec9d98 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -52,73 +52,75 @@ import { IExperimentService } from 'vs/workbench/contrib/experiments/common/expe import { ExtensionTipsService } from 'vs/platform/extensionManagement/node/extensionTipsService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { DisposableStore } from 'vs/base/common/lifecycle'; + +let instantiationService: TestInstantiationService; +let installEvent: Emitter, + didInstallEvent: Emitter, + uninstallEvent: Emitter, + didUninstallEvent: Emitter; + +let disposables: DisposableStore; + +async function setupTest() { + disposables = new DisposableStore(); + installEvent = new Emitter(); + didInstallEvent = new Emitter(); + uninstallEvent = new Emitter(); + didUninstallEvent = new Emitter(); + + instantiationService = new TestInstantiationService(); + instantiationService.stub(ITelemetryService, NullTelemetryService); + instantiationService.stub(ILogService, NullLogService); + + instantiationService.stub(IWorkspaceContextService, new TestContextService()); + instantiationService.stub(IConfigurationService, new TestConfigurationService()); + instantiationService.stub(IProgressService, ProgressService); + instantiationService.stub(IStorageKeysSyncRegistryService, new StorageKeysSyncRegistryService()); + instantiationService.stub(IProductService, {}); + + instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); + instantiationService.stub(ISharedProcessService, TestSharedProcessService); + + instantiationService.stub(IExtensionManagementService, ExtensionManagementService); + instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); + instantiationService.stub(IRemoteAgentService, RemoteAgentService); + + instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { + private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; + constructor() { + super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService), instantiationService.get(ILabelService)); + } + get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; } + set localExtensionManagementServer(server: IExtensionManagementServer) { } + }()); + + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter().event }); + + instantiationService.stub(ILifecycleService, new TestLifecycleService()); + instantiationService.stub(IExperimentService, instantiationService.createInstance(TestExperimentService)); + instantiationService.stub(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService)); + instantiationService.stub(IExtensionRecommendationsService, {}); + instantiationService.stub(IURLService, URLService); + + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); + instantiationService.stub(IExtensionService, >{ getExtensions: () => Promise.resolve([]), onDidChangeExtensions: new Emitter().event, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false }); + (instantiationService.get(IWorkbenchExtensionEnablementService)).reset(); + + instantiationService.set(IExtensionsWorkbenchService, disposables.add(instantiationService.createInstance(ExtensionsWorkbenchService))); +} -suite('ExtensionsActions Test', () => { - - let instantiationService: TestInstantiationService; - - let installEvent: Emitter, - didInstallEvent: Emitter, - uninstallEvent: Emitter, - didUninstallEvent: Emitter; - - - setup(async () => { - installEvent = new Emitter(); - didInstallEvent = new Emitter(); - uninstallEvent = new Emitter(); - didUninstallEvent = new Emitter(); - - instantiationService = new TestInstantiationService(); - instantiationService.stub(ITelemetryService, NullTelemetryService); - instantiationService.stub(ILogService, NullLogService); - - instantiationService.stub(IWorkspaceContextService, new TestContextService()); - instantiationService.stub(IConfigurationService, new TestConfigurationService()); - instantiationService.stub(IProgressService, ProgressService); - instantiationService.stub(IStorageKeysSyncRegistryService, new StorageKeysSyncRegistryService()); - instantiationService.stub(IProductService, {}); - - instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); - instantiationService.stub(ISharedProcessService, TestSharedProcessService); - - instantiationService.stub(IExtensionManagementService, ExtensionManagementService); - instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); - instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event); - instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event); - instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); - instantiationService.stub(IRemoteAgentService, RemoteAgentService); - - instantiationService.stub(IExtensionManagementServerService, new class extends ExtensionManagementServerService { - private _localExtensionManagementServer: IExtensionManagementServer = { extensionManagementService: instantiationService.get(IExtensionManagementService), label: 'local', authority: 'vscode-local' }; - constructor() { - super(instantiationService.get(ISharedProcessService), instantiationService.get(IRemoteAgentService), instantiationService.get(IExtensionGalleryService), instantiationService.get(IConfigurationService), instantiationService.get(IProductService), instantiationService.get(ILogService), instantiationService.get(ILabelService)); - } - get localExtensionManagementServer(): IExtensionManagementServer { return this._localExtensionManagementServer; } - set localExtensionManagementServer(server: IExtensionManagementServer) { } - }()); - - instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); - instantiationService.stub(ILabelService, { onDidChangeFormatters: new Emitter().event }); - - instantiationService.stub(ILifecycleService, new TestLifecycleService()); - instantiationService.stub(IExperimentService, instantiationService.createInstance(TestExperimentService)); - instantiationService.stub(IExtensionTipsService, instantiationService.createInstance(ExtensionTipsService)); - instantiationService.stub(IExtensionRecommendationsService, {}); - instantiationService.stub(IURLService, URLService); - instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); - instantiationService.stubPromise(IExtensionManagementService, 'getExtensionsReport', []); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); - instantiationService.stub(IExtensionService, >{ getExtensions: () => Promise.resolve([]), onDidChangeExtensions: new Emitter().event, canAddExtension: (extension: IExtensionDescription) => false, canRemoveExtension: (extension: IExtensionDescription) => false }); - await (instantiationService.get(IWorkbenchExtensionEnablementService)).reset(); - - instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); - }); +suite('ExtensionsActions Test', () => { - teardown(() => { - (instantiationService.get(IExtensionsWorkbenchService)).dispose(); - }); + setup(setupTest); + teardown(() => disposables.dispose()); test('Install action is disabled when there is no extension', () => { const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); @@ -1068,6 +1070,17 @@ suite('ExtensionsActions Test', () => { }); }); + test(`RecommendToFolderAction`, () => { + // TODO: Implement test + }); + +}); + +suite('ReloadAction', () => { + + setup(setupTest); + teardown(() => disposables.dispose()); + test('Test ReloadAction when there is no extension', () => { const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1541,6 +1554,136 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); + test('Test ReloadAction for remote workspace+ui extension is enabled when it is installed and enabled in local server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'] }, { location: URI.file('pub.a') }); + const localExtensionManagementService = createExtensionManagementService([localExtension]); + const onDidInstallEvent = new Emitter(); + localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const remoteExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'] }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(localExtension)]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test ReloadAction for local ui+workspace extension is enabled when it is installed and enabled in remote server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file('pub.a') }); + const remoteExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const remoteExtensionManagementService = createExtensionManagementService([remoteExtension]); + const onDidInstallEvent = new Emitter(); + remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), remoteExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(remoteExtension)]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test ReloadAction for local workspace+ui extension is enabled when it is installed in both servers but running in local server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'] }, { location: URI.file('pub.a') }); + const localExtensionManagementService = createExtensionManagementService([localExtension]); + const onDidInstallEvent = new Emitter(); + localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const remoteExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'] }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(localExtension)]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test ReloadAction for remote ui+workspace extension is enabled when it is installed on both servers but running in remote server', async () => { + // multi server setup + const gallery = aGalleryExtension('a'); + const localExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file('pub.a') }); + const remoteExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file('pub.a').with({ scheme: Schemas.vscodeRemote }) }); + const remoteExtensionManagementService = createExtensionManagementService([remoteExtension]); + const onDidInstallEvent = new Emitter(); + remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localExtension]), remoteExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + const onDidChangeExtensionsEmitter: Emitter = new Emitter(); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(remoteExtension)]), + onDidChangeExtensions: onDidChangeExtensionsEmitter.event, + canAddExtension: (extension) => false + }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + await workbenchService.queryGallery(CancellationToken.None); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); +}); + +suite('RemoteInstallAction', () => { + + setup(setupTest); + teardown(() => disposables.dispose()); + test('Test remote install action is enabled for local workspace extension', async () => { // multi server setup const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['workspace'] }, { location: URI.file(`pub.a`) }); @@ -1551,7 +1694,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1577,7 +1720,7 @@ suite('ExtensionsActions Test', () => { const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1610,7 +1753,7 @@ suite('ExtensionsActions Test', () => { const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1641,7 +1784,51 @@ suite('ExtensionsActions Test', () => { await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install in remote', testObject.label); + assert.equal('extension-action label prominent install', testObject.class); + }); + + test('Test remote install action is enabled local workspace+ui extension', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['workspace', 'ui'] }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install in remote', testObject.label); + assert.equal('extension-action label prominent install', testObject.class); + }); + + test('Test remote install action is enabled for local ui+workapace extension if can install is true', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, true); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1652,6 +1839,26 @@ suite('ExtensionsActions Test', () => { assert.equal('extension-action label prominent install', testObject.class); }); + test('Test remote install action is disabled for local ui+workapace extension if can install is false', async () => { + // multi server setup + const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file(`pub.a`) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + await instantiationService.get(IWorkbenchExtensionEnablementService).setEnablement([localWorkspaceExtension], EnablementState.DisabledGlobally); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + }); + test('Test remote install action is disabled when extension is not set', async () => { // multi server setup const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['workspace'] }, { location: URI.file(`pub.a`) }); @@ -1661,7 +1868,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1678,7 +1885,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const pager = await workbenchService.queryGallery(CancellationToken.None); @@ -1698,7 +1905,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1715,7 +1922,7 @@ suite('ExtensionsActions Test', () => { const localWorkspaceExtension = aLocalExtension('a', { extensionKind: ['workspace'] }, { location: URI.file(`pub.a`) }); instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [localWorkspaceExtension]); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1737,7 +1944,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1761,7 +1968,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1781,7 +1988,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1800,7 +2007,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceSystemExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1819,7 +2026,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1839,7 +2046,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localUIExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1858,7 +2065,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1881,7 +2088,7 @@ suite('ExtensionsActions Test', () => { instantiationService.set(IExtensionsWorkbenchService, workbenchService); instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: languagePackExtension.identifier }))); - const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction, false); instantiationService.createInstance(ExtensionContainers, [testObject]); const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); @@ -1893,6 +2100,12 @@ suite('ExtensionsActions Test', () => { uninstallEvent.fire(languagePackExtension.identifier); assert.ok(!testObject.enabled); }); +}); + +suite('LocalInstallAction', () => { + + setup(setupTest); + teardown(() => disposables.dispose()); test('Test local install action is enabled for remote ui extension', async () => { // multi server setup @@ -1915,6 +2128,27 @@ suite('ExtensionsActions Test', () => { assert.equal('extension-action label prominent install', testObject.class); }); + test('Test local install action is enabled for remote ui+workspace extension', async () => { + // multi server setup + const remoteUIExtension = aLocalExtension('a', { extensionKind: ['ui', 'workspace'] }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IWorkbenchExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + await workbenchService.queryGallery(CancellationToken.None); + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Install Locally', testObject.label); + assert.equal('extension-action label prominent install', testObject.class); + }); + test('Test local install action when installing remote ui extension', async () => { // multi server setup const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); @@ -2250,89 +2484,87 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); - test(`RecommendToFolderAction`, () => { - // TODO: Implement test - }); +}); - function aLocalExtension(name: string = 'someext', manifest: any = {}, properties: any = {}): ILocalExtension { - manifest = assign({ name, publisher: 'pub', version: '1.0.0' }, manifest); - properties = assign({ - type: ExtensionType.User, - location: URI.file(`pub.${name}`), - identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: undefined }, - metadata: { id: getGalleryExtensionId(manifest.publisher, manifest.name), publisherId: manifest.publisher, publisherDisplayName: 'somename' } - }, properties); - return Object.create({ manifest, ...properties }); - } - - function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { - const galleryExtension = Object.create({}); - assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); - assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); - assign(galleryExtension.assets, assets); - galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; - return galleryExtension; - } - - function aPage(...objects: T[]): IPager { - return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null! }; - } - - function aSingleRemoteExtensionManagementServerService(instantiationService: TestInstantiationService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { - const remoteExtensionManagementServer: IExtensionManagementServer = { - authority: 'vscode-remote', - label: 'remote', - extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() - }; - return { - _serviceBrand: undefined, - localExtensionManagementServer: null, - remoteExtensionManagementServer, - getExtensionManagementServer: (location: URI) => { - if (location.scheme === REMOTE_HOST_SCHEME) { - return remoteExtensionManagementServer; - } - return null; +function aLocalExtension(name: string = 'someext', manifest: any = {}, properties: any = {}): ILocalExtension { + manifest = assign({ name, publisher: 'pub', version: '1.0.0' }, manifest); + properties = assign({ + type: ExtensionType.User, + location: URI.file(`pub.${name}`), + identifier: { id: getGalleryExtensionId(manifest.publisher, manifest.name), uuid: undefined }, + metadata: { id: getGalleryExtensionId(manifest.publisher, manifest.name), publisherId: manifest.publisher, publisherDisplayName: 'somename' } + }, properties); + return Object.create({ manifest, ...properties }); +} + +function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { + const galleryExtension = Object.create({}); + assign(galleryExtension, { name, publisher: 'pub', version: '1.0.0', properties: {}, assets: {} }, properties); + assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); + assign(galleryExtension.assets, assets); + galleryExtension.identifier = { id: getGalleryExtensionId(galleryExtension.publisher, galleryExtension.name), uuid: generateUuid() }; + return galleryExtension; +} + +function aPage(...objects: T[]): IPager { + return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null! }; +} + +function aSingleRemoteExtensionManagementServerService(instantiationService: TestInstantiationService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { + const remoteExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() + }; + return { + _serviceBrand: undefined, + localExtensionManagementServer: null, + remoteExtensionManagementServer, + getExtensionManagementServer: (location: URI) => { + if (location.scheme === REMOTE_HOST_SCHEME) { + return remoteExtensionManagementServer; } - }; - } - - function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IExtensionManagementService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { - const localExtensionManagementServer: IExtensionManagementServer = { - authority: 'vscode-local', - label: 'local', - extensionManagementService: localExtensionManagementService || createExtensionManagementService() - }; - const remoteExtensionManagementServer: IExtensionManagementServer = { - authority: 'vscode-remote', - label: 'remote', - extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() - }; - return { - _serviceBrand: undefined, - localExtensionManagementServer, - remoteExtensionManagementServer, - getExtensionManagementServer: (location: URI) => { - if (location.scheme === Schemas.file) { - return localExtensionManagementServer; - } - if (location.scheme === REMOTE_HOST_SCHEME) { - return remoteExtensionManagementServer; - } - return null; + return null; + } + }; +} + +function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService, localExtensionManagementService?: IExtensionManagementService, remoteExtensionManagementService?: IExtensionManagementService): IExtensionManagementServerService { + const localExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-local', + label: 'local', + extensionManagementService: localExtensionManagementService || createExtensionManagementService() + }; + const remoteExtensionManagementServer: IExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: remoteExtensionManagementService || createExtensionManagementService() + }; + return { + _serviceBrand: undefined, + localExtensionManagementServer, + remoteExtensionManagementServer, + getExtensionManagementServer: (location: URI) => { + if (location.scheme === Schemas.file) { + return localExtensionManagementServer; } - }; - } - - function createExtensionManagementService(installed: ILocalExtension[] = []): IExtensionManagementService { - return { - onInstallExtension: Event.None, - onDidInstallExtension: Event.None, - onUninstallExtension: Event.None, - onDidUninstallExtension: Event.None, - getInstalled: () => Promise.resolve(installed), - installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported')) - }; - } + if (location.scheme === REMOTE_HOST_SCHEME) { + return remoteExtensionManagementServer; + } + return null; + } + }; +} + +function createExtensionManagementService(installed: ILocalExtension[] = []): IExtensionManagementService { + return { + onInstallExtension: Event.None, + onDidInstallExtension: Event.None, + onUninstallExtension: Event.None, + onDidUninstallExtension: Event.None, + getInstalled: () => Promise.resolve(installed), + installFromGallery: (extension: IGalleryExtension) => Promise.reject(new Error('not supported')) + }; +} + -});