Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/test/browser/mainThreadAuthentication.integrationTest.ts
5220 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 { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
8
import { TestDialogService } from '../../../../platform/dialogs/test/common/testDialogService.js';
9
import { TestInstantiationService } from '../../../../platform/instantiation/test/common/instantiationServiceMock.js';
10
import { INotificationService } from '../../../../platform/notification/common/notification.js';
11
import { TestNotificationService } from '../../../../platform/notification/test/common/testNotificationService.js';
12
import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';
13
import { IStorageService } from '../../../../platform/storage/common/storage.js';
14
import { ITelemetryService } from '../../../../platform/telemetry/common/telemetry.js';
15
import { NullTelemetryService } from '../../../../platform/telemetry/common/telemetryUtils.js';
16
import { MainThreadAuthentication } from '../../browser/mainThreadAuthentication.js';
17
import { ExtHostContext, MainContext } from '../../common/extHost.protocol.js';
18
import { IActivityService } from '../../../services/activity/common/activity.js';
19
import { AuthenticationService } from '../../../services/authentication/browser/authenticationService.js';
20
import { IAuthenticationExtensionsService, IAuthenticationService } from '../../../services/authentication/common/authentication.js';
21
import { IExtensionService } from '../../../services/extensions/common/extensions.js';
22
import { IRemoteAgentService } from '../../../services/remote/common/remoteAgentService.js';
23
import { TestRPCProtocol } from '../common/testRPCProtocol.js';
24
import { TestEnvironmentService, TestHostService, TestQuickInputService, TestRemoteAgentService } from '../../../test/browser/workbenchTestServices.js';
25
import { TestActivityService, TestExtensionService, TestProductService, TestStorageService } from '../../../test/common/workbenchTestServices.js';
26
import { IBrowserWorkbenchEnvironmentService } from '../../../services/environment/browser/environmentService.js';
27
import { IProductService } from '../../../../platform/product/common/productService.js';
28
import { AuthenticationAccessService, IAuthenticationAccessService } from '../../../services/authentication/browser/authenticationAccessService.js';
29
import { IAccountUsage, IAuthenticationUsageService } from '../../../services/authentication/browser/authenticationUsageService.js';
30
import { AuthenticationExtensionsService } from '../../../services/authentication/browser/authenticationExtensionsService.js';
31
import { ILogService, NullLogService } from '../../../../platform/log/common/log.js';
32
import { IHostService } from '../../../services/host/browser/host.js';
33
import { IOpenerService } from '../../../../platform/opener/common/opener.js';
34
import { IUserActivityService, UserActivityService } from '../../../services/userActivity/common/userActivityService.js';
35
import { ISecretStorageService } from '../../../../platform/secrets/common/secrets.js';
36
import { TestSecretStorageService } from '../../../../platform/secrets/test/common/testSecretStorageService.js';
37
import { IDynamicAuthenticationProviderStorageService } from '../../../services/authentication/common/dynamicAuthenticationProviderStorage.js';
38
import { DynamicAuthenticationProviderStorageService } from '../../../services/authentication/browser/dynamicAuthenticationProviderStorageService.js';
39
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
40
import { ServiceCollection } from '../../../../platform/instantiation/common/serviceCollection.js';
41
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
42
43
class TestAuthUsageService implements IAuthenticationUsageService {
44
_serviceBrand: undefined;
45
initializeExtensionUsageCache(): Promise<void> { return Promise.resolve(); }
46
extensionUsesAuth(extensionId: string): Promise<boolean> { return Promise.resolve(false); }
47
readAccountUsages(providerId: string, accountName: string): IAccountUsage[] { return []; }
48
removeAccountUsage(providerId: string, accountName: string): void { }
49
addAccountUsage(providerId: string, accountName: string, scopes: ReadonlyArray<string>, extensionId: string, extensionName: string): void { }
50
}
51
52
suite('MainThreadAuthentication', () => {
53
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
54
55
let mainThreadAuthentication: MainThreadAuthentication;
56
let instantiationService: TestInstantiationService;
57
let rpcProtocol: TestRPCProtocol;
58
59
setup(async () => {
60
// services
61
const services = new ServiceCollection();
62
services.set(ILogService, new SyncDescriptor(NullLogService));
63
services.set(IDialogService, new SyncDescriptor(TestDialogService, [{ confirmed: true }]));
64
services.set(IStorageService, new SyncDescriptor(TestStorageService));
65
services.set(ISecretStorageService, new SyncDescriptor(TestSecretStorageService));
66
services.set(IDynamicAuthenticationProviderStorageService, new SyncDescriptor(DynamicAuthenticationProviderStorageService));
67
services.set(IQuickInputService, new SyncDescriptor(TestQuickInputService));
68
services.set(IExtensionService, new SyncDescriptor(TestExtensionService));
69
services.set(IActivityService, new SyncDescriptor(TestActivityService));
70
services.set(IRemoteAgentService, new SyncDescriptor(TestRemoteAgentService));
71
services.set(INotificationService, new SyncDescriptor(TestNotificationService));
72
services.set(IHostService, new SyncDescriptor(TestHostService));
73
services.set(IUserActivityService, new SyncDescriptor(UserActivityService));
74
services.set(IAuthenticationAccessService, new SyncDescriptor(AuthenticationAccessService));
75
services.set(IAuthenticationService, new SyncDescriptor(AuthenticationService));
76
services.set(IAuthenticationUsageService, new SyncDescriptor(TestAuthUsageService));
77
services.set(IAuthenticationExtensionsService, new SyncDescriptor(AuthenticationExtensionsService));
78
instantiationService = disposables.add(new TestInstantiationService(services, undefined, undefined, true));
79
80
// stubs
81
// eslint-disable-next-line local/code-no-dangerous-type-assertions
82
instantiationService.stub(IOpenerService, {} as Partial<IOpenerService>);
83
instantiationService.stub(ITelemetryService, NullTelemetryService);
84
instantiationService.stub(IBrowserWorkbenchEnvironmentService, TestEnvironmentService);
85
instantiationService.stub(IProductService, TestProductService);
86
87
rpcProtocol = disposables.add(new TestRPCProtocol());
88
mainThreadAuthentication = disposables.add(instantiationService.createInstance(MainThreadAuthentication, rpcProtocol));
89
rpcProtocol.set(MainContext.MainThreadAuthentication, mainThreadAuthentication);
90
});
91
92
test('provider registration completes without errors', async () => {
93
// Test basic registration - this should complete without throwing
94
await mainThreadAuthentication.$registerAuthenticationProvider({
95
id: 'test-provider',
96
label: 'Test Provider',
97
supportsMultipleAccounts: false
98
});
99
100
// Test unregistration - this should also complete without throwing
101
await mainThreadAuthentication.$unregisterAuthenticationProvider('test-provider');
102
103
// Success if we reach here without timeout
104
assert.ok(true, 'Registration and unregistration completed successfully');
105
});
106
107
test('event suppression during explicit unregistration', async () => {
108
let unregisterEventFired = false;
109
let eventProviderId: string | undefined;
110
111
// Mock the ext host to capture unregister events
112
const mockExtHost = {
113
$onDidUnregisterAuthenticationProvider: (id: string) => {
114
unregisterEventFired = true;
115
eventProviderId = id;
116
return Promise.resolve();
117
},
118
$getSessions: () => Promise.resolve([]),
119
// eslint-disable-next-line local/code-no-any-casts
120
$createSession: () => Promise.resolve({} as any),
121
$removeSession: () => Promise.resolve(),
122
$onDidChangeAuthenticationSessions: () => Promise.resolve(),
123
$registerDynamicAuthProvider: () => Promise.resolve('test'),
124
$onDidChangeDynamicAuthProviderTokens: () => Promise.resolve(),
125
$getSessionsFromChallenges: () => Promise.resolve([]),
126
// eslint-disable-next-line local/code-no-any-casts
127
$createSessionFromChallenges: () => Promise.resolve({} as any),
128
};
129
rpcProtocol.set(ExtHostContext.ExtHostAuthentication, mockExtHost);
130
131
// Register a provider
132
await mainThreadAuthentication.$registerAuthenticationProvider({
133
id: 'test-suppress',
134
label: 'Test Suppress',
135
supportsMultipleAccounts: false
136
});
137
138
// Reset the flag
139
unregisterEventFired = false;
140
eventProviderId = undefined;
141
142
// Unregister the provider - this should NOT fire the event due to suppression
143
await mainThreadAuthentication.$unregisterAuthenticationProvider('test-suppress');
144
145
// Verify the event was suppressed
146
assert.strictEqual(unregisterEventFired, false, 'Unregister event should be suppressed during explicit unregistration');
147
assert.strictEqual(eventProviderId, undefined, 'No provider ID should be captured from suppressed event');
148
});
149
150
test('concurrent provider registrations complete without errors', async () => {
151
// Register multiple providers simultaneously
152
const registrationPromises = [
153
mainThreadAuthentication.$registerAuthenticationProvider({
154
id: 'concurrent-1',
155
label: 'Concurrent 1',
156
supportsMultipleAccounts: false
157
}),
158
mainThreadAuthentication.$registerAuthenticationProvider({
159
id: 'concurrent-2',
160
label: 'Concurrent 2',
161
supportsMultipleAccounts: false
162
}),
163
mainThreadAuthentication.$registerAuthenticationProvider({
164
id: 'concurrent-3',
165
label: 'Concurrent 3',
166
supportsMultipleAccounts: false
167
})
168
];
169
170
await Promise.all(registrationPromises);
171
172
// Unregister all providers
173
const unregistrationPromises = [
174
mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-1'),
175
mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-2'),
176
mainThreadAuthentication.$unregisterAuthenticationProvider('concurrent-3')
177
];
178
179
await Promise.all(unregistrationPromises);
180
181
// Success if we reach here without timeout
182
assert.ok(true, 'Concurrent registrations and unregistrations completed successfully');
183
});
184
});
185
186