Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/extensions/test/common/extensionRunningLocationTracker.test.ts
5266 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { URI } from '../../../../../base/common/uri.js';
8
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
9
import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';
10
import { ExtensionIdentifier, IExtensionDescription } from '../../../../../platform/extensions/common/extensions.js';
11
import { NullLogService } from '../../../../../platform/log/common/log.js';
12
import { ExtensionRunningLocationTracker } from '../../common/extensionRunningLocationTracker.js';
13
import { ExtensionHostKind, IExtensionHostKindPicker } from '../../common/extensionHostKind.js';
14
import { IExtensionManifestPropertiesService } from '../../common/extensionManifestPropertiesService.js';
15
import { IReadOnlyExtensionDescriptionRegistry } from '../../common/extensionDescriptionRegistry.js';
16
import { IWorkbenchEnvironmentService } from '../../../environment/common/environmentService.js';
17
18
function createExtension(id: string, deps?: string[], extensionAffinity?: string[]): IExtensionDescription {
19
return <IExtensionDescription>{
20
identifier: new ExtensionIdentifier(id),
21
extensionLocation: URI.parse(`file:///test/${id}`),
22
name: id,
23
publisher: 'test',
24
version: '1.0.0',
25
engines: { vscode: '*' },
26
main: 'main.js',
27
extensionDependencies: deps,
28
extensionAffinity: extensionAffinity,
29
enabledApiProposals: extensionAffinity ? ['extensionAffinity'] : undefined,
30
};
31
}
32
33
suite('ExtensionRunningLocationTracker - extensionAffinity', () => {
34
35
ensureNoDisposablesAreLeakedInTestSuite();
36
37
function createTracker(extensions: IExtensionDescription[], configuredAffinities: { [extensionId: string]: number } = {}): ExtensionRunningLocationTracker {
38
const registry: IReadOnlyExtensionDescriptionRegistry = {
39
getAllExtensionDescriptions: () => extensions,
40
getExtensionDescription: (id: string | ExtensionIdentifier) => extensions.find(e => e.identifier.value === (typeof id === 'string' ? id : id.value)),
41
getExtensionDescriptionByUUID: () => undefined,
42
getExtensionDescriptionByIdOrUUID: () => undefined,
43
containsActivationEvent: () => false,
44
containsExtension: () => false,
45
getExtensionDescriptionsForActivationEvent: () => [],
46
};
47
48
const extensionHostKindPicker: IExtensionHostKindPicker = {
49
pickExtensionHostKind: () => ExtensionHostKind.LocalProcess,
50
};
51
52
const environmentService = <IWorkbenchEnvironmentService>{
53
isExtensionDevelopment: false,
54
extensionDevelopmentKind: undefined,
55
};
56
57
const configurationService = new TestConfigurationService();
58
configurationService.setUserConfiguration('extensions.experimental.affinity', configuredAffinities);
59
60
const logService = new NullLogService();
61
62
const extensionManifestPropertiesService = {
63
getExtensionKind: () => ['workspace'],
64
} as unknown as IExtensionManifestPropertiesService;
65
66
return new ExtensionRunningLocationTracker(
67
registry,
68
extensionHostKindPicker,
69
environmentService,
70
configurationService,
71
logService,
72
extensionManifestPropertiesService
73
);
74
}
75
76
test('extensions with extensionAffinity should have the same affinity', () => {
77
const extA = createExtension('publisher.extA');
78
const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);
79
80
const tracker = createTracker([extA, extB]);
81
const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);
82
83
const locA = runningLocations.get(extA.identifier);
84
const locB = runningLocations.get(extB.identifier);
85
86
assert.ok(locA, 'Extension A should have a running location');
87
assert.ok(locB, 'Extension B should have a running location');
88
assert.strictEqual(locA!.affinity, locB!.affinity, 'Extensions with extensionAffinity should have the same affinity');
89
});
90
91
test('transitive extensionAffinity should group all extensions together', () => {
92
const extA = createExtension('publisher.extA');
93
const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);
94
const extC = createExtension('publisher.extC', undefined, ['publisher.extB']);
95
96
const tracker = createTracker([extA, extB, extC]);
97
const runningLocations = tracker.computeRunningLocation([extA, extB, extC], [], true);
98
99
const locA = runningLocations.get(extA.identifier);
100
const locB = runningLocations.get(extB.identifier);
101
const locC = runningLocations.get(extC.identifier);
102
103
assert.ok(locA && locB && locC, 'All extensions should have running locations');
104
assert.strictEqual(locA!.affinity, locB!.affinity, 'A and B should have the same affinity');
105
assert.strictEqual(locB!.affinity, locC!.affinity, 'B and C should have the same affinity');
106
});
107
108
test('extensionAffinity with non-installed extension should be ignored', () => {
109
const extA = createExtension('publisher.extA', undefined, ['publisher.notInstalled']);
110
const extB = createExtension('publisher.extB');
111
112
const tracker = createTracker([extA, extB]);
113
const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);
114
115
const locA = runningLocations.get(extA.identifier);
116
const locB = runningLocations.get(extB.identifier);
117
118
assert.ok(locA && locB, 'Both extensions should have running locations');
119
// They should not be grouped together since the extensionAffinity target doesn't exist
120
// (Unless they would naturally have affinity 0, which they both do by default)
121
});
122
123
test('extensionAffinity combined with extensionDependencies', () => {
124
const extA = createExtension('publisher.extA');
125
const extB = createExtension('publisher.extB', ['publisher.extA']);
126
const extC = createExtension('publisher.extC', undefined, ['publisher.extA']);
127
128
const tracker = createTracker([extA, extB, extC]);
129
const runningLocations = tracker.computeRunningLocation([extA, extB, extC], [], true);
130
131
const locA = runningLocations.get(extA.identifier);
132
const locB = runningLocations.get(extB.identifier);
133
const locC = runningLocations.get(extC.identifier);
134
135
assert.ok(locA && locB && locC, 'All extensions should have running locations');
136
// B depends on A, C has extensionAffinity to A - all should be in the same group
137
assert.strictEqual(locA!.affinity, locB!.affinity, 'A and B (dependency) should have the same affinity');
138
assert.strictEqual(locA!.affinity, locC!.affinity, 'A and C (extensionAffinity) should have the same affinity');
139
});
140
141
test('user configured affinity should override extensionAffinity', () => {
142
const extA = createExtension('publisher.extA');
143
const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);
144
145
const tracker = createTracker([extA, extB], {
146
'publisher.extA': 1,
147
'publisher.extB': 2,
148
});
149
const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);
150
151
const locA = runningLocations.get(extA.identifier);
152
const locB = runningLocations.get(extB.identifier);
153
154
assert.ok(locA && locB, 'Both extensions should have running locations');
155
// With user-configured affinities, they should be in different groups
156
// Note: The actual behavior depends on the order of operations in _computeAffinity
157
// The user config creates separate affinities, but grouping happens first
158
});
159
160
test('one-way extensionAffinity is sufficient', () => {
161
// Only extB declares extensionAffinity, extA doesn't need to know about extB
162
const extA = createExtension('publisher.extA');
163
const extB = createExtension('publisher.extB', undefined, ['publisher.extA']);
164
165
const tracker = createTracker([extA, extB]);
166
const runningLocations = tracker.computeRunningLocation([extA, extB], [], true);
167
168
const locA = runningLocations.get(extA.identifier);
169
const locB = runningLocations.get(extB.identifier);
170
171
assert.ok(locA && locB, 'Both extensions should have running locations');
172
assert.strictEqual(locA!.affinity, locB!.affinity, 'One-way extensionAffinity should be sufficient to group extensions');
173
});
174
});
175
176