Path: blob/main/src/vs/workbench/services/extensions/test/common/extensionRunningLocationTracker.test.ts
5266 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 { URI } from '../../../../../base/common/uri.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';9import { ExtensionIdentifier, IExtensionDescription } from '../../../../../platform/extensions/common/extensions.js';10import { NullLogService } from '../../../../../platform/log/common/log.js';11import { ExtensionRunningLocationTracker } from '../../common/extensionRunningLocationTracker.js';12import { ExtensionHostKind, IExtensionHostKindPicker } from '../../common/extensionHostKind.js';13import { IExtensionManifestPropertiesService } from '../../common/extensionManifestPropertiesService.js';14import { IReadOnlyExtensionDescriptionRegistry } from '../../common/extensionDescriptionRegistry.js';15import { IWorkbenchEnvironmentService } from '../../../environment/common/environmentService.js';1617function createExtension(id: string, deps?: string[], extensionAffinity?: string[]): IExtensionDescription {18return <IExtensionDescription>{19identifier: new ExtensionIdentifier(id),20extensionLocation: URI.parse(`file:///test/${id}`),21name: id,22publisher: 'test',23version: '1.0.0',24engines: { vscode: '*' },25main: 'main.js',26extensionDependencies: deps,27extensionAffinity: extensionAffinity,28enabledApiProposals: extensionAffinity ? ['extensionAffinity'] : undefined,29};30}3132suite('ExtensionRunningLocationTracker - extensionAffinity', () => {3334ensureNoDisposablesAreLeakedInTestSuite();3536function createTracker(extensions: IExtensionDescription[], configuredAffinities: { [extensionId: string]: number } = {}): ExtensionRunningLocationTracker {37const registry: IReadOnlyExtensionDescriptionRegistry = {38getAllExtensionDescriptions: () => extensions,39getExtensionDescription: (id: string | ExtensionIdentifier) => extensions.find(e => e.identifier.value === (typeof id === 'string' ? id : id.value)),40getExtensionDescriptionByUUID: () => undefined,41getExtensionDescriptionByIdOrUUID: () => undefined,42containsActivationEvent: () => false,43containsExtension: () => false,44getExtensionDescriptionsForActivationEvent: () => [],45};4647const extensionHostKindPicker: IExtensionHostKindPicker = {48pickExtensionHostKind: () => ExtensionHostKind.LocalProcess,49};5051const environmentService = <IWorkbenchEnvironmentService>{52isExtensionDevelopment: false,53extensionDevelopmentKind: undefined,54};5556const configurationService = new TestConfigurationService();57configurationService.setUserConfiguration('extensions.experimental.affinity', configuredAffinities);5859const logService = new NullLogService();6061const extensionManifestPropertiesService = {62getExtensionKind: () => ['workspace'],63} as unknown as IExtensionManifestPropertiesService;6465return new ExtensionRunningLocationTracker(66registry,67extensionHostKindPicker,68environmentService,69configurationService,70logService,71extensionManifestPropertiesService72);73}7475test('extensions with extensionAffinity should have the same affinity', () => {76const extA = createExtension('publisher.extA');77const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);7879const tracker = createTracker([extA, extB]);80const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);8182const locA = runningLocations.get(extA.identifier);83const locB = runningLocations.get(extB.identifier);8485assert.ok(locA, 'Extension A should have a running location');86assert.ok(locB, 'Extension B should have a running location');87assert.strictEqual(locA!.affinity, locB!.affinity, 'Extensions with extensionAffinity should have the same affinity');88});8990test('transitive extensionAffinity should group all extensions together', () => {91const extA = createExtension('publisher.extA');92const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);93const extC = createExtension('publisher.extC', undefined, ['publisher.extB']);9495const tracker = createTracker([extA, extB, extC]);96const runningLocations = tracker.computeRunningLocation([extA, extB, extC], [], true);9798const locA = runningLocations.get(extA.identifier);99const locB = runningLocations.get(extB.identifier);100const locC = runningLocations.get(extC.identifier);101102assert.ok(locA && locB && locC, 'All extensions should have running locations');103assert.strictEqual(locA!.affinity, locB!.affinity, 'A and B should have the same affinity');104assert.strictEqual(locB!.affinity, locC!.affinity, 'B and C should have the same affinity');105});106107test('extensionAffinity with non-installed extension should be ignored', () => {108const extA = createExtension('publisher.extA', undefined, ['publisher.notInstalled']);109const extB = createExtension('publisher.extB');110111const tracker = createTracker([extA, extB]);112const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);113114const locA = runningLocations.get(extA.identifier);115const locB = runningLocations.get(extB.identifier);116117assert.ok(locA && locB, 'Both extensions should have running locations');118// They should not be grouped together since the extensionAffinity target doesn't exist119// (Unless they would naturally have affinity 0, which they both do by default)120});121122test('extensionAffinity combined with extensionDependencies', () => {123const extA = createExtension('publisher.extA');124const extB = createExtension('publisher.extB', ['publisher.extA']);125const extC = createExtension('publisher.extC', undefined, ['publisher.extA']);126127const tracker = createTracker([extA, extB, extC]);128const runningLocations = tracker.computeRunningLocation([extA, extB, extC], [], true);129130const locA = runningLocations.get(extA.identifier);131const locB = runningLocations.get(extB.identifier);132const locC = runningLocations.get(extC.identifier);133134assert.ok(locA && locB && locC, 'All extensions should have running locations');135// B depends on A, C has extensionAffinity to A - all should be in the same group136assert.strictEqual(locA!.affinity, locB!.affinity, 'A and B (dependency) should have the same affinity');137assert.strictEqual(locA!.affinity, locC!.affinity, 'A and C (extensionAffinity) should have the same affinity');138});139140test('user configured affinity should override extensionAffinity', () => {141const extA = createExtension('publisher.extA');142const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);143144const tracker = createTracker([extA, extB], {145'publisher.extA': 1,146'publisher.extB': 2,147});148const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);149150const locA = runningLocations.get(extA.identifier);151const locB = runningLocations.get(extB.identifier);152153assert.ok(locA && locB, 'Both extensions should have running locations');154// With user-configured affinities, they should be in different groups155// Note: The actual behavior depends on the order of operations in _computeAffinity156// The user config creates separate affinities, but grouping happens first157});158159test('one-way extensionAffinity is sufficient', () => {160// Only extB declares extensionAffinity, extA doesn't need to know about extB161const extA = createExtension('publisher.extA');162const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);163164const tracker = createTracker([extA, extB]);165const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);166167const locA = runningLocations.get(extA.identifier);168const locB = runningLocations.get(extB.identifier);169170assert.ok(locA && locB, 'Both extensions should have running locations');171assert.strictEqual(locA!.affinity, locB!.affinity, 'One-way extensionAffinity should be sufficient to group extensions');172});173});174175176