Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/authentication/test/browser/authenticationQueryService.test.ts
3296 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 * as assert from 'assert';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
8
import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';
9
import { ILogService, NullLogService } from '../../../../../platform/log/common/log.js';
10
import { IStorageService } from '../../../../../platform/storage/common/storage.js';
11
import { TestStorageService } from '../../../../test/common/workbenchTestServices.js';
12
import { IAuthenticationQueryService } from '../../common/authenticationQuery.js';
13
import { AuthenticationQueryService } from '../../browser/authenticationQueryService.js';
14
import { IAuthenticationService, IAuthenticationExtensionsService } from '../../common/authentication.js';
15
import { IAuthenticationUsageService } from '../../browser/authenticationUsageService.js';
16
import { IAuthenticationMcpUsageService } from '../../browser/authenticationMcpUsageService.js';
17
import { IAuthenticationAccessService } from '../../browser/authenticationAccessService.js';
18
import { IAuthenticationMcpAccessService } from '../../browser/authenticationMcpAccessService.js';
19
import { IAuthenticationMcpService } from '../../browser/authenticationMcpService.js';
20
import {
21
TestUsageService,
22
TestMcpUsageService,
23
TestAccessService,
24
TestMcpAccessService,
25
TestExtensionsService,
26
TestMcpService,
27
TestAuthenticationService,
28
createProvider,
29
} from './authenticationQueryServiceMocks.js';
30
31
/**
32
* Real integration tests for AuthenticationQueryService
33
*/
34
suite('AuthenticationQueryService Integration Tests', () => {
35
const disposables = ensureNoDisposablesAreLeakedInTestSuite();
36
37
let queryService: IAuthenticationQueryService;
38
let authService: TestAuthenticationService;
39
let usageService: TestUsageService;
40
let mcpUsageService: TestMcpUsageService;
41
let accessService: TestAccessService;
42
let mcpAccessService: TestMcpAccessService;
43
44
setup(() => {
45
const instantiationService = disposables.add(new TestInstantiationService());
46
47
// Set up storage service
48
const storageService = disposables.add(new TestStorageService());
49
instantiationService.stub(IStorageService, storageService);
50
51
// Set up log service
52
instantiationService.stub(ILogService, new NullLogService());
53
54
// Create and register test services
55
authService = disposables.add(new TestAuthenticationService());
56
instantiationService.stub(IAuthenticationService, authService);
57
58
usageService = disposables.add(new TestUsageService());
59
mcpUsageService = disposables.add(new TestMcpUsageService());
60
accessService = disposables.add(new TestAccessService());
61
mcpAccessService = disposables.add(new TestMcpAccessService());
62
63
instantiationService.stub(IAuthenticationUsageService, usageService);
64
instantiationService.stub(IAuthenticationMcpUsageService, mcpUsageService);
65
instantiationService.stub(IAuthenticationAccessService, accessService);
66
instantiationService.stub(IAuthenticationMcpAccessService, mcpAccessService);
67
instantiationService.stub(IAuthenticationExtensionsService, disposables.add(new TestExtensionsService()));
68
instantiationService.stub(IAuthenticationMcpService, disposables.add(new TestMcpService()));
69
70
// Create the query service
71
queryService = disposables.add(instantiationService.createInstance(AuthenticationQueryService));
72
});
73
74
test('usage tracking stores and retrieves data correctly', () => {
75
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
76
77
// Initially no usage
78
assert.strictEqual(extensionQuery.getUsage().length, 0);
79
80
// Add usage and verify it's stored
81
extensionQuery.addUsage(['read', 'write'], 'My Extension');
82
const usage = extensionQuery.getUsage();
83
assert.strictEqual(usage.length, 1);
84
assert.strictEqual(usage[0].extensionId, 'my-extension');
85
assert.strictEqual(usage[0].extensionName, 'My Extension');
86
assert.deepStrictEqual(usage[0].scopes, ['read', 'write']);
87
88
// Add more usage and verify accumulation
89
extensionQuery.addUsage(['admin'], 'My Extension');
90
assert.strictEqual(extensionQuery.getUsage().length, 2);
91
});
92
93
test('access control persists across queries', () => {
94
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
95
96
// Set access and verify
97
extensionQuery.setAccessAllowed(true, 'My Extension');
98
assert.strictEqual(extensionQuery.isAccessAllowed(), true);
99
100
// Create new query object for same target - should persist
101
const sameExtensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
102
assert.strictEqual(sameExtensionQuery.isAccessAllowed(), true);
103
104
// Different extension should be unaffected
105
const otherExtensionQuery = queryService.provider('github').account('[email protected]').extension('other-extension');
106
assert.strictEqual(otherExtensionQuery.isAccessAllowed(), undefined);
107
});
108
109
test('account preferences work across services', () => {
110
const extensionQuery = queryService.provider('github').extension('my-extension');
111
const mcpQuery = queryService.provider('github').mcpServer('my-server');
112
113
// Set preferences for both
114
extensionQuery.setPreferredAccount({ id: 'user1', label: '[email protected]' });
115
mcpQuery.setPreferredAccount({ id: 'user2', label: '[email protected]' });
116
117
// Verify different preferences are stored independently
118
assert.strictEqual(extensionQuery.getPreferredAccount(), '[email protected]');
119
assert.strictEqual(mcpQuery.getPreferredAccount(), '[email protected]');
120
121
// Test preference detection
122
const userExtensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
123
const adminMcpQuery = queryService.provider('github').account('[email protected]').mcpServer('my-server');
124
125
assert.strictEqual(userExtensionQuery.isPreferred(), true);
126
assert.strictEqual(adminMcpQuery.isPreferred(), true);
127
128
// Test non-preferred accounts
129
const wrongExtensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
130
assert.strictEqual(wrongExtensionQuery.isPreferred(), false);
131
});
132
133
test('account removal cleans up all related data', () => {
134
const accountQuery = queryService.provider('github').account('[email protected]');
135
136
// Set up data across multiple services
137
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension 1');
138
accountQuery.extension('ext1').addUsage(['read'], 'Extension 1');
139
accountQuery.mcpServer('mcp1').setAccessAllowed(true, 'MCP Server 1');
140
accountQuery.mcpServer('mcp1').addUsage(['write'], 'MCP Server 1');
141
142
// Verify data exists
143
assert.strictEqual(accountQuery.extension('ext1').isAccessAllowed(), true);
144
assert.strictEqual(accountQuery.extension('ext1').getUsage().length, 1);
145
assert.strictEqual(accountQuery.mcpServer('mcp1').isAccessAllowed(), true);
146
assert.strictEqual(accountQuery.mcpServer('mcp1').getUsage().length, 1);
147
148
// Remove account
149
accountQuery.remove();
150
151
// Verify all data is cleaned up
152
assert.strictEqual(accountQuery.extension('ext1').isAccessAllowed(), undefined);
153
assert.strictEqual(accountQuery.extension('ext1').getUsage().length, 0);
154
assert.strictEqual(accountQuery.mcpServer('mcp1').isAccessAllowed(), undefined);
155
assert.strictEqual(accountQuery.mcpServer('mcp1').getUsage().length, 0);
156
});
157
158
test('provider registration and listing works', () => {
159
// Initially no providers
160
assert.strictEqual(queryService.getProviderIds().length, 0);
161
162
// Register a provider
163
const provider = createProvider({ id: 'github', label: 'GitHub' });
164
authService.registerAuthenticationProvider('github', provider);
165
166
// Verify provider is listed
167
const providerIds = queryService.getProviderIds();
168
assert.ok(providerIds.includes('github'));
169
assert.strictEqual(authService.isAuthenticationProviderRegistered('github'), true);
170
});
171
172
test('MCP usage and access work independently from extensions', () => {
173
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
174
const mcpQuery = queryService.provider('github').account('[email protected]').mcpServer('my-server');
175
176
// Set up data for both
177
extensionQuery.setAccessAllowed(true, 'My Extension');
178
extensionQuery.addUsage(['read'], 'My Extension');
179
180
mcpQuery.setAccessAllowed(false, 'My Server');
181
mcpQuery.addUsage(['write'], 'My Server');
182
183
// Verify they're independent
184
assert.strictEqual(extensionQuery.isAccessAllowed(), true);
185
assert.strictEqual(mcpQuery.isAccessAllowed(), false);
186
187
assert.strictEqual(extensionQuery.getUsage()[0].extensionId, 'my-extension');
188
assert.strictEqual(mcpQuery.getUsage()[0].mcpServerId, 'my-server');
189
190
// Verify no cross-contamination
191
assert.strictEqual(extensionQuery.getUsage().length, 1);
192
assert.strictEqual(mcpQuery.getUsage().length, 1);
193
});
194
195
test('getAllAccountPreferences returns synchronously', () => {
196
// Register providers for the test
197
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
198
const azureProvider = createProvider({ id: 'azure', label: 'Azure' });
199
authService.registerAuthenticationProvider('github', githubProvider);
200
authService.registerAuthenticationProvider('azure', azureProvider);
201
202
const extensionQuery = queryService.extension('my-extension');
203
const mcpQuery = queryService.mcpServer('my-server');
204
205
// Set preferences for different providers
206
extensionQuery.provider('github').setPreferredAccount({ id: 'user1', label: '[email protected]' });
207
extensionQuery.provider('azure').setPreferredAccount({ id: 'user2', label: '[email protected]' });
208
mcpQuery.provider('github').setPreferredAccount({ id: 'user3', label: '[email protected]' });
209
210
// Get all preferences synchronously (no await needed)
211
const extensionPreferences = extensionQuery.getAllAccountPreferences();
212
const mcpPreferences = mcpQuery.getAllAccountPreferences();
213
214
// Verify extension preferences
215
assert.strictEqual(extensionPreferences.get('github'), '[email protected]');
216
assert.strictEqual(extensionPreferences.get('azure'), '[email protected]');
217
assert.strictEqual(extensionPreferences.size, 2);
218
219
// Verify MCP preferences
220
assert.strictEqual(mcpPreferences.get('github'), '[email protected]');
221
assert.strictEqual(mcpPreferences.size, 1);
222
223
// Verify they don't interfere with each other
224
assert.notStrictEqual(extensionPreferences.get('github'), mcpPreferences.get('github'));
225
});
226
227
test('forEach methods work synchronously', () => {
228
const accountQuery = queryService.provider('github').account('[email protected]');
229
230
// Add some usage data first
231
accountQuery.extension('ext1').addUsage(['read'], 'Extension 1');
232
accountQuery.extension('ext2').addUsage(['write'], 'Extension 2');
233
accountQuery.mcpServer('mcp1').addUsage(['admin'], 'MCP Server 1');
234
235
// Test extensions forEach - no await needed
236
const extensionIds: string[] = [];
237
accountQuery.extensions().forEach(extensionQuery => {
238
extensionIds.push(extensionQuery.extensionId);
239
});
240
241
assert.strictEqual(extensionIds.length, 2);
242
assert.ok(extensionIds.includes('ext1'));
243
assert.ok(extensionIds.includes('ext2'));
244
245
// Test MCP servers forEach - no await needed
246
const mcpServerIds: string[] = [];
247
accountQuery.mcpServers().forEach(mcpServerQuery => {
248
mcpServerIds.push(mcpServerQuery.mcpServerId);
249
});
250
251
assert.strictEqual(mcpServerIds.length, 1);
252
assert.ok(mcpServerIds.includes('mcp1'));
253
});
254
255
test('remove method works synchronously', () => {
256
const accountQuery = queryService.provider('github').account('[email protected]');
257
258
// Set up data
259
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension 1');
260
accountQuery.mcpServer('mcp1').setAccessAllowed(true, 'MCP Server 1');
261
262
// Remove synchronously - no await needed
263
accountQuery.remove();
264
265
// Verify data is gone
266
assert.strictEqual(accountQuery.extension('ext1').isAccessAllowed(), undefined);
267
assert.strictEqual(accountQuery.mcpServer('mcp1').isAccessAllowed(), undefined);
268
});
269
270
test('cross-provider extension queries work correctly', () => {
271
// Register multiple providers
272
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
273
const azureProvider = createProvider({ id: 'azure', label: 'Azure' });
274
authService.registerAuthenticationProvider('github', githubProvider);
275
authService.registerAuthenticationProvider('azure', azureProvider);
276
277
// Set up data using provider-first approach
278
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
279
queryService.provider('azure').account('[email protected]').extension('my-extension').setAccessAllowed(false, 'My Extension');
280
281
// Query using extension-first approach should return all providers
282
const extensionQuery = queryService.extension('my-extension');
283
const githubPrefs = extensionQuery.getAllAccountPreferences();
284
285
// Should include both providers
286
assert.ok(githubPrefs.size >= 0); // Extension query should work across providers
287
288
// Test preferences using extension-first query pattern
289
extensionQuery.provider('github').setPreferredAccount({ id: 'user1', label: '[email protected]' });
290
extensionQuery.provider('azure').setPreferredAccount({ id: 'user2', label: '[email protected]' });
291
292
assert.strictEqual(extensionQuery.provider('github').getPreferredAccount(), '[email protected]');
293
assert.strictEqual(extensionQuery.provider('azure').getPreferredAccount(), '[email protected]');
294
});
295
296
test('event forwarding from authentication service works', () => {
297
let eventFired = false;
298
299
// Listen for access change events through the query service
300
const disposable = queryService.onDidChangeAccess(() => {
301
eventFired = true;
302
});
303
304
try {
305
// Trigger an access change that should fire an event
306
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
307
308
// Verify the event was fired
309
assert.strictEqual(eventFired, true);
310
} finally {
311
disposable.dispose();
312
}
313
});
314
315
test('error handling for invalid inputs works correctly', () => {
316
// Test with non-existent provider
317
const invalidProviderQuery = queryService.provider('non-existent-provider');
318
319
// Should not throw, but should handle gracefully
320
assert.doesNotThrow(() => {
321
invalidProviderQuery.account('[email protected]').extension('my-extension').isAccessAllowed();
322
});
323
324
// Test with empty/invalid account names
325
const emptyAccountQuery = queryService.provider('github').account('').extension('my-extension');
326
assert.doesNotThrow(() => {
327
emptyAccountQuery.isAccessAllowed();
328
});
329
330
// Test with empty extension IDs
331
const emptyExtensionQuery = queryService.provider('github').account('[email protected]').extension('');
332
assert.doesNotThrow(() => {
333
emptyExtensionQuery.isAccessAllowed();
334
});
335
});
336
337
test('bulk operations work correctly', () => {
338
const accountQuery = queryService.provider('github').account('[email protected]');
339
340
// Set up multiple extensions with different access levels
341
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension 1');
342
accountQuery.extension('ext2').setAccessAllowed(false, 'Extension 2');
343
accountQuery.extension('ext3').setAccessAllowed(true, 'Extension 3');
344
345
// Add usage for some extensions
346
accountQuery.extension('ext1').addUsage(['read'], 'Extension 1');
347
accountQuery.extension('ext3').addUsage(['write'], 'Extension 3');
348
349
// Test bulk enumeration
350
let extensionCount = 0;
351
let allowedCount = 0;
352
let usageCount = 0;
353
354
accountQuery.extensions().forEach(extensionQuery => {
355
extensionCount++;
356
if (extensionQuery.isAccessAllowed() === true) {
357
allowedCount++;
358
}
359
if (extensionQuery.getUsage().length > 0) {
360
usageCount++;
361
}
362
});
363
364
// Verify bulk operation results
365
assert.strictEqual(extensionCount, 3);
366
assert.strictEqual(allowedCount, 2); // ext1 and ext3
367
assert.strictEqual(usageCount, 2); // ext1 and ext3
368
369
// Test bulk operations for MCP servers
370
accountQuery.mcpServer('mcp1').setAccessAllowed(true, 'MCP 1');
371
accountQuery.mcpServer('mcp2').setAccessAllowed(false, 'MCP 2');
372
373
let mcpCount = 0;
374
accountQuery.mcpServers().forEach(mcpQuery => {
375
mcpCount++;
376
});
377
378
assert.strictEqual(mcpCount, 2);
379
});
380
381
test('data consistency across different query paths', () => {
382
// Set up data using one query path
383
const extensionQuery1 = queryService.provider('github').account('[email protected]').extension('my-extension');
384
extensionQuery1.setAccessAllowed(true, 'My Extension');
385
extensionQuery1.addUsage(['read', 'write'], 'My Extension');
386
387
// Access same data using different query path (cross-provider query)
388
const extensionQuery2 = queryService.extension('my-extension').provider('github');
389
390
// Data should be consistent through provider preference access
391
assert.strictEqual(extensionQuery1.isAccessAllowed(), true);
392
assert.strictEqual(extensionQuery1.getUsage().length, 1);
393
394
// Set preferences and check consistency
395
extensionQuery2.setPreferredAccount({ id: 'user', label: '[email protected]' });
396
assert.strictEqual(extensionQuery2.getPreferredAccount(), '[email protected]');
397
398
// Modify through one path
399
extensionQuery1.setAccessAllowed(false, 'My Extension');
400
401
// Should be reflected when accessing through provider->account path
402
assert.strictEqual(extensionQuery1.isAccessAllowed(), false);
403
});
404
405
test('preference management handles complex scenarios', () => {
406
// Register multiple providers
407
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
408
const azureProvider = createProvider({ id: 'azure', label: 'Azure' });
409
authService.registerAuthenticationProvider('github', githubProvider);
410
authService.registerAuthenticationProvider('azure', azureProvider);
411
412
const extensionQuery = queryService.extension('my-extension');
413
414
// Set different preferences for different providers
415
extensionQuery.provider('github').setPreferredAccount({ id: 'user1', label: '[email protected]' });
416
extensionQuery.provider('azure').setPreferredAccount({ id: 'user2', label: '[email protected]' });
417
418
// Test preference retrieval
419
assert.strictEqual(extensionQuery.provider('github').getPreferredAccount(), '[email protected]');
420
assert.strictEqual(extensionQuery.provider('azure').getPreferredAccount(), '[email protected]');
421
422
// Test account preference detection through provider->account queries
423
assert.strictEqual(
424
queryService.provider('github').account('[email protected]').extension('my-extension').isPreferred(),
425
true
426
);
427
assert.strictEqual(
428
queryService.provider('azure').account('[email protected]').extension('my-extension').isPreferred(),
429
true
430
);
431
assert.strictEqual(
432
queryService.provider('github').account('[email protected]').extension('my-extension').isPreferred(),
433
false
434
);
435
436
// Test getAllAccountPreferences with multiple providers
437
const allPrefs = extensionQuery.getAllAccountPreferences();
438
assert.strictEqual(allPrefs.get('github'), '[email protected]');
439
assert.strictEqual(allPrefs.get('azure'), '[email protected]');
440
assert.strictEqual(allPrefs.size, 2);
441
});
442
443
test('MCP server vs extension data isolation is complete', () => {
444
const accountQuery = queryService.provider('github').account('[email protected]');
445
446
// Set up similar data for extension and MCP server with same IDs
447
const sameId = 'same-identifier';
448
accountQuery.extension(sameId).setAccessAllowed(true, 'Extension');
449
accountQuery.extension(sameId).addUsage(['ext-scope'], 'Extension');
450
451
accountQuery.mcpServer(sameId).setAccessAllowed(false, 'MCP Server');
452
accountQuery.mcpServer(sameId).addUsage(['mcp-scope'], 'MCP Server');
453
454
// Verify complete isolation
455
assert.strictEqual(accountQuery.extension(sameId).isAccessAllowed(), true);
456
assert.strictEqual(accountQuery.mcpServer(sameId).isAccessAllowed(), false);
457
458
const extUsage = accountQuery.extension(sameId).getUsage();
459
const mcpUsage = accountQuery.mcpServer(sameId).getUsage();
460
461
assert.strictEqual(extUsage.length, 1);
462
assert.strictEqual(mcpUsage.length, 1);
463
assert.strictEqual(extUsage[0].extensionId, sameId);
464
assert.strictEqual(mcpUsage[0].mcpServerId, sameId);
465
assert.notDeepStrictEqual(extUsage[0].scopes, mcpUsage[0].scopes);
466
467
// Test preference isolation
468
queryService.extension(sameId).provider('github').setPreferredAccount({ id: 'ext-user', label: '[email protected]' });
469
queryService.mcpServer(sameId).provider('github').setPreferredAccount({ id: 'mcp-user', label: '[email protected]' });
470
471
assert.strictEqual(queryService.extension(sameId).provider('github').getPreferredAccount(), '[email protected]');
472
assert.strictEqual(queryService.mcpServer(sameId).provider('github').getPreferredAccount(), '[email protected]');
473
});
474
475
test('provider listing and registration integration', () => {
476
// Initially should have providers from setup (if any)
477
const initialProviders = queryService.getProviderIds();
478
const initialCount = initialProviders.length;
479
480
// Register a new provider
481
const newProvider = createProvider({ id: 'test-provider', label: 'Test Provider' });
482
authService.registerAuthenticationProvider('test-provider', newProvider);
483
484
// Should now appear in listing
485
const updatedProviders = queryService.getProviderIds();
486
assert.strictEqual(updatedProviders.length, initialCount + 1);
487
assert.ok(updatedProviders.includes('test-provider'));
488
489
// Should be able to query the new provider
490
const providerQuery = queryService.provider('test-provider');
491
assert.strictEqual(providerQuery.providerId, 'test-provider');
492
493
// Should integrate with authentication service state
494
assert.strictEqual(authService.isAuthenticationProviderRegistered('test-provider'), true);
495
});
496
497
/**
498
* Service Call Verification Tests
499
* These tests verify that the AuthenticationQueryService properly delegates to underlying services
500
* with the correct parameters. This is important for ensuring the facade works correctly.
501
*/
502
test('setAccessAllowed calls updateAllowedExtensions with correct parameters', () => {
503
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
504
505
// Clear any previous calls
506
accessService.clearCallHistory();
507
508
// Call setAccessAllowed
509
extensionQuery.setAccessAllowed(true, 'My Extension');
510
511
// Verify the underlying service was called correctly
512
const calls = accessService.getCallsFor('updateAllowedExtensions');
513
assert.strictEqual(calls.length, 1);
514
515
const [providerId, accountName, extensions] = calls[0].args;
516
assert.strictEqual(providerId, 'github');
517
assert.strictEqual(accountName, '[email protected]');
518
assert.strictEqual(extensions.length, 1);
519
assert.strictEqual(extensions[0].id, 'my-extension');
520
assert.strictEqual(extensions[0].name, 'My Extension');
521
assert.strictEqual(extensions[0].allowed, true);
522
});
523
524
test('addUsage calls addAccountUsage with correct parameters', () => {
525
const extensionQuery = queryService.provider('azure').account('[email protected]').extension('test-extension');
526
527
// Clear any previous calls
528
usageService.clearCallHistory();
529
530
// Call addUsage
531
extensionQuery.addUsage(['read', 'write'], 'Test Extension');
532
533
// Verify the underlying service was called correctly
534
const calls = usageService.getCallsFor('addAccountUsage');
535
assert.strictEqual(calls.length, 1);
536
537
const [providerId, accountName, scopes, extensionId, extensionName] = calls[0].args;
538
assert.strictEqual(providerId, 'azure');
539
assert.strictEqual(accountName, '[email protected]');
540
assert.deepStrictEqual(scopes, ['read', 'write']);
541
assert.strictEqual(extensionId, 'test-extension');
542
assert.strictEqual(extensionName, 'Test Extension');
543
});
544
545
test('isAccessAllowed calls underlying service with correct parameters', () => {
546
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
547
548
// Clear any previous calls
549
accessService.clearCallHistory();
550
551
// Call isAccessAllowed
552
extensionQuery.isAccessAllowed();
553
554
// Verify the underlying service was called correctly
555
const calls = accessService.getCallsFor('isAccessAllowed');
556
assert.strictEqual(calls.length, 1);
557
558
const [providerId, accountName, extensionId] = calls[0].args;
559
assert.strictEqual(providerId, 'github');
560
assert.strictEqual(accountName, '[email protected]');
561
assert.strictEqual(extensionId, 'my-extension');
562
});
563
564
test('getUsage calls readAccountUsages with correct parameters', () => {
565
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
566
567
// Clear any previous calls
568
usageService.clearCallHistory();
569
570
// Call getUsage
571
extensionQuery.getUsage();
572
573
// Verify the underlying service was called correctly
574
const calls = usageService.getCallsFor('readAccountUsages');
575
assert.strictEqual(calls.length, 1);
576
577
const [providerId, accountName] = calls[0].args;
578
assert.strictEqual(providerId, 'github');
579
assert.strictEqual(accountName, '[email protected]');
580
});
581
582
test('MCP setAccessAllowed calls updateAllowedMcpServers with correct parameters', () => {
583
const mcpQuery = queryService.provider('github').account('[email protected]').mcpServer('my-server');
584
585
// Clear any previous calls
586
mcpAccessService.clearCallHistory();
587
588
// Call setAccessAllowed
589
mcpQuery.setAccessAllowed(false, 'My MCP Server');
590
591
// Verify the underlying service was called correctly
592
const calls = mcpAccessService.getCallsFor('updateAllowedMcpServers');
593
assert.strictEqual(calls.length, 1);
594
595
const [providerId, accountName, servers] = calls[0].args;
596
assert.strictEqual(providerId, 'github');
597
assert.strictEqual(accountName, '[email protected]');
598
assert.strictEqual(servers.length, 1);
599
assert.strictEqual(servers[0].id, 'my-server');
600
assert.strictEqual(servers[0].name, 'My MCP Server');
601
assert.strictEqual(servers[0].allowed, false);
602
});
603
604
test('MCP addUsage calls addAccountUsage with correct parameters', () => {
605
const mcpQuery = queryService.provider('azure').account('[email protected]').mcpServer('test-server');
606
607
// Clear any previous calls
608
mcpUsageService.clearCallHistory();
609
610
// Call addUsage
611
mcpQuery.addUsage(['admin'], 'Test MCP Server');
612
613
// Verify the underlying service was called correctly
614
const calls = mcpUsageService.getCallsFor('addAccountUsage');
615
assert.strictEqual(calls.length, 1);
616
617
const [providerId, accountName, scopes, serverId, serverName] = calls[0].args;
618
assert.strictEqual(providerId, 'azure');
619
assert.strictEqual(accountName, '[email protected]');
620
assert.deepStrictEqual(scopes, ['admin']);
621
assert.strictEqual(serverId, 'test-server');
622
assert.strictEqual(serverName, 'Test MCP Server');
623
});
624
625
test('account removal calls all appropriate cleanup methods', () => {
626
const accountQuery = queryService.provider('github').account('[email protected]');
627
628
// Set up some data first
629
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension 1');
630
accountQuery.extension('ext1').addUsage(['read'], 'Extension 1');
631
accountQuery.mcpServer('mcp1').setAccessAllowed(true, 'MCP Server 1');
632
accountQuery.mcpServer('mcp1').addUsage(['write'], 'MCP Server 1');
633
634
// Clear call history to focus on removal calls
635
usageService.clearCallHistory();
636
mcpUsageService.clearCallHistory();
637
accessService.clearCallHistory();
638
mcpAccessService.clearCallHistory();
639
640
// Call remove
641
accountQuery.remove();
642
643
// Verify all cleanup methods were called
644
const extensionUsageRemoval = usageService.getCallsFor('removeAccountUsage');
645
const mcpUsageRemoval = mcpUsageService.getCallsFor('removeAccountUsage');
646
const extensionAccessRemoval = accessService.getCallsFor('removeAllowedExtensions');
647
const mcpAccessRemoval = mcpAccessService.getCallsFor('removeAllowedMcpServers');
648
649
assert.strictEqual(extensionUsageRemoval.length, 1);
650
assert.strictEqual(mcpUsageRemoval.length, 1);
651
assert.strictEqual(extensionAccessRemoval.length, 1);
652
assert.strictEqual(mcpAccessRemoval.length, 1);
653
654
// Verify all calls use correct parameters
655
[extensionUsageRemoval[0], mcpUsageRemoval[0], extensionAccessRemoval[0], mcpAccessRemoval[0]].forEach(call => {
656
const [providerId, accountName] = call.args;
657
assert.strictEqual(providerId, 'github');
658
assert.strictEqual(accountName, '[email protected]');
659
});
660
});
661
662
test('bulk operations call readAccountUsages and readAllowedExtensions', () => {
663
const accountQuery = queryService.provider('github').account('[email protected]');
664
665
// Set up some data
666
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension 1');
667
accountQuery.extension('ext2').addUsage(['read'], 'Extension 2');
668
669
// Clear call history
670
usageService.clearCallHistory();
671
accessService.clearCallHistory();
672
673
// Perform bulk operation
674
accountQuery.extensions().forEach(() => {
675
// Just iterate to trigger the underlying service calls
676
});
677
678
// Verify the underlying services were called for bulk enumeration
679
const usageCalls = usageService.getCallsFor('readAccountUsages');
680
const accessCalls = accessService.getCallsFor('readAllowedExtensions');
681
682
assert.strictEqual(usageCalls.length, 1);
683
assert.strictEqual(accessCalls.length, 1);
684
685
// Verify parameters
686
usageCalls.concat(accessCalls).forEach(call => {
687
const [providerId, accountName] = call.args;
688
assert.strictEqual(providerId, 'github');
689
assert.strictEqual(accountName, '[email protected]');
690
});
691
});
692
693
test('multiple operations accumulate service calls correctly', () => {
694
const extensionQuery = queryService.provider('github').account('[email protected]').extension('my-extension');
695
696
// Clear call history
697
accessService.clearCallHistory();
698
usageService.clearCallHistory();
699
700
// Perform multiple operations
701
extensionQuery.setAccessAllowed(true, 'My Extension');
702
extensionQuery.addUsage(['read'], 'My Extension');
703
extensionQuery.isAccessAllowed();
704
extensionQuery.getUsage();
705
extensionQuery.setAccessAllowed(false, 'My Extension');
706
707
// Verify call counts
708
assert.strictEqual(accessService.getCallsFor('updateAllowedExtensions').length, 2);
709
assert.strictEqual(accessService.getCallsFor('isAccessAllowed').length, 1);
710
assert.strictEqual(usageService.getCallsFor('addAccountUsage').length, 1);
711
assert.strictEqual(usageService.getCallsFor('readAccountUsages').length, 1);
712
});
713
714
test('getProvidersWithAccess filters internal providers by default', async () => {
715
// Register multiple providers including internal ones
716
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
717
const azureProvider = createProvider({ id: 'azure', label: 'Azure' });
718
const internalProvider1 = createProvider({ id: '__internal1', label: 'Internal Provider 1' });
719
const internalProvider2 = createProvider({ id: '__internal2', label: 'Internal Provider 2' });
720
721
authService.registerAuthenticationProvider('github', githubProvider);
722
authService.registerAuthenticationProvider('azure', azureProvider);
723
authService.registerAuthenticationProvider('__internal1', internalProvider1);
724
authService.registerAuthenticationProvider('__internal2', internalProvider2);
725
726
// Add accounts to all providers
727
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
728
authService.addAccounts('azure', [{ id: 'user2', label: '[email protected]' }]);
729
authService.addAccounts('__internal1', [{ id: 'user3', label: '[email protected]' }]);
730
authService.addAccounts('__internal2', [{ id: 'user4', label: '[email protected]' }]);
731
732
// Set up access for all providers
733
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
734
queryService.provider('azure').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
735
queryService.provider('__internal1').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
736
queryService.provider('__internal2').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
737
738
// Test extension query - should exclude internal providers by default
739
const extensionQuery = queryService.extension('my-extension');
740
const providersWithAccess = await extensionQuery.getProvidersWithAccess();
741
742
assert.strictEqual(providersWithAccess.length, 2);
743
assert.ok(providersWithAccess.includes('github'));
744
assert.ok(providersWithAccess.includes('azure'));
745
assert.ok(!providersWithAccess.includes('__internal1'));
746
assert.ok(!providersWithAccess.includes('__internal2'));
747
});
748
749
test('getProvidersWithAccess includes internal providers when requested', async () => {
750
// Register multiple providers including internal ones
751
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
752
const internalProvider = createProvider({ id: '__internal1', label: 'Internal Provider' });
753
754
authService.registerAuthenticationProvider('github', githubProvider);
755
authService.registerAuthenticationProvider('__internal1', internalProvider);
756
757
// Add accounts to all providers
758
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
759
authService.addAccounts('__internal1', [{ id: 'user2', label: '[email protected]' }]);
760
761
// Set up access for all providers
762
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
763
queryService.provider('__internal1').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
764
765
// Test extension query - should include internal providers when requested
766
const extensionQuery = queryService.extension('my-extension');
767
const providersWithAccess = await extensionQuery.getProvidersWithAccess(true);
768
769
assert.strictEqual(providersWithAccess.length, 2);
770
assert.ok(providersWithAccess.includes('github'));
771
assert.ok(providersWithAccess.includes('__internal1'));
772
});
773
774
test('MCP server getProvidersWithAccess filters internal providers by default', async () => {
775
// Register multiple providers including internal ones
776
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
777
const azureProvider = createProvider({ id: 'azure', label: 'Azure' });
778
const internalProvider1 = createProvider({ id: '__internal1', label: 'Internal Provider 1' });
779
const internalProvider2 = createProvider({ id: '__internal2', label: 'Internal Provider 2' });
780
781
authService.registerAuthenticationProvider('github', githubProvider);
782
authService.registerAuthenticationProvider('azure', azureProvider);
783
authService.registerAuthenticationProvider('__internal1', internalProvider1);
784
authService.registerAuthenticationProvider('__internal2', internalProvider2);
785
786
// Add accounts to all providers
787
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
788
authService.addAccounts('azure', [{ id: 'user2', label: '[email protected]' }]);
789
authService.addAccounts('__internal1', [{ id: 'user3', label: '[email protected]' }]);
790
authService.addAccounts('__internal2', [{ id: 'user4', label: '[email protected]' }]);
791
792
// Set up MCP access for all providers
793
queryService.provider('github').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
794
queryService.provider('azure').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
795
queryService.provider('__internal1').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
796
queryService.provider('__internal2').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
797
798
// Test MCP server query - should exclude internal providers by default
799
const mcpServerQuery = queryService.mcpServer('my-server');
800
const providersWithAccess = await mcpServerQuery.getProvidersWithAccess();
801
802
assert.strictEqual(providersWithAccess.length, 2);
803
assert.ok(providersWithAccess.includes('github'));
804
assert.ok(providersWithAccess.includes('azure'));
805
assert.ok(!providersWithAccess.includes('__internal1'));
806
assert.ok(!providersWithAccess.includes('__internal2'));
807
});
808
809
test('MCP server getProvidersWithAccess includes internal providers when requested', async () => {
810
// Register multiple providers including internal ones
811
const githubProvider = createProvider({ id: 'github', label: 'GitHub' });
812
const internalProvider = createProvider({ id: '__internal1', label: 'Internal Provider' });
813
814
authService.registerAuthenticationProvider('github', githubProvider);
815
authService.registerAuthenticationProvider('__internal1', internalProvider);
816
817
// Add accounts to all providers
818
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
819
authService.addAccounts('__internal1', [{ id: 'user2', label: '[email protected]' }]);
820
821
// Set up MCP access for all providers
822
queryService.provider('github').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
823
queryService.provider('__internal1').account('[email protected]').mcpServer('my-server').setAccessAllowed(true, 'My Server');
824
825
// Test MCP server query - should include internal providers when requested
826
const mcpServerQuery = queryService.mcpServer('my-server');
827
const providersWithAccess = await mcpServerQuery.getProvidersWithAccess(true);
828
829
assert.strictEqual(providersWithAccess.length, 2);
830
assert.ok(providersWithAccess.includes('github'));
831
assert.ok(providersWithAccess.includes('__internal1'));
832
});
833
834
test('internal provider filtering works with mixed access patterns', async () => {
835
// Register mixed providers
836
const normalProvider = createProvider({ id: 'normal', label: 'Normal Provider' });
837
const internalProvider = createProvider({ id: '__internal', label: 'Internal Provider' });
838
const noAccessProvider = createProvider({ id: 'no-access', label: 'No Access Provider' });
839
840
authService.registerAuthenticationProvider('normal', normalProvider);
841
authService.registerAuthenticationProvider('__internal', internalProvider);
842
authService.registerAuthenticationProvider('no-access', noAccessProvider);
843
844
// Add accounts to all providers
845
authService.addAccounts('normal', [{ id: 'user1', label: '[email protected]' }]);
846
authService.addAccounts('__internal', [{ id: 'user2', label: '[email protected]' }]);
847
authService.addAccounts('no-access', [{ id: 'user3', label: '[email protected]' }]);
848
849
// Set up access only for normal and internal providers
850
queryService.provider('normal').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
851
queryService.provider('__internal').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
852
// Note: no-access provider deliberately has no access set
853
854
const extensionQuery = queryService.extension('my-extension');
855
856
// Without includeInternal: should only return normal provider
857
const providersWithoutInternal = await extensionQuery.getProvidersWithAccess(false);
858
assert.strictEqual(providersWithoutInternal.length, 1);
859
assert.ok(providersWithoutInternal.includes('normal'));
860
assert.ok(!providersWithoutInternal.includes('__internal'));
861
assert.ok(!providersWithoutInternal.includes('no-access'));
862
863
// With includeInternal: should return both normal and internal
864
const providersWithInternal = await extensionQuery.getProvidersWithAccess(true);
865
assert.strictEqual(providersWithInternal.length, 2);
866
assert.ok(providersWithInternal.includes('normal'));
867
assert.ok(providersWithInternal.includes('__internal'));
868
assert.ok(!providersWithInternal.includes('no-access'));
869
});
870
871
test('internal provider filtering respects the __ prefix exactly', async () => {
872
// Register providers with various naming patterns
873
const regularProvider = createProvider({ id: 'regular', label: 'Regular Provider' });
874
const underscoreProvider = createProvider({ id: '_single', label: 'Single Underscore Provider' });
875
const doubleUnderscoreProvider = createProvider({ id: '__double', label: 'Double Underscore Provider' });
876
const tripleUnderscoreProvider = createProvider({ id: '___triple', label: 'Triple Underscore Provider' });
877
const underscoreInMiddleProvider = createProvider({ id: 'mid_underscore', label: 'Middle Underscore Provider' });
878
879
authService.registerAuthenticationProvider('regular', regularProvider);
880
authService.registerAuthenticationProvider('_single', underscoreProvider);
881
authService.registerAuthenticationProvider('__double', doubleUnderscoreProvider);
882
authService.registerAuthenticationProvider('___triple', tripleUnderscoreProvider);
883
authService.registerAuthenticationProvider('mid_underscore', underscoreInMiddleProvider);
884
885
// Add accounts to all providers
886
authService.addAccounts('regular', [{ id: 'user1', label: '[email protected]' }]);
887
authService.addAccounts('_single', [{ id: 'user2', label: '[email protected]' }]);
888
authService.addAccounts('__double', [{ id: 'user3', label: '[email protected]' }]);
889
authService.addAccounts('___triple', [{ id: 'user4', label: '[email protected]' }]);
890
authService.addAccounts('mid_underscore', [{ id: 'user5', label: '[email protected]' }]);
891
892
// Set up access for all providers
893
queryService.provider('regular').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
894
queryService.provider('_single').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
895
queryService.provider('__double').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
896
queryService.provider('___triple').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
897
queryService.provider('mid_underscore').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
898
899
const extensionQuery = queryService.extension('my-extension');
900
901
// Without includeInternal: should exclude only providers starting with exactly "__"
902
const providersWithoutInternal = await extensionQuery.getProvidersWithAccess(false);
903
assert.strictEqual(providersWithoutInternal.length, 3);
904
assert.ok(providersWithoutInternal.includes('regular'));
905
assert.ok(providersWithoutInternal.includes('_single'));
906
assert.ok(!providersWithoutInternal.includes('__double'));
907
assert.ok(!providersWithoutInternal.includes('___triple')); // This starts with __, so should be filtered
908
assert.ok(providersWithoutInternal.includes('mid_underscore'));
909
910
// With includeInternal: should include all providers
911
const providersWithInternal = await extensionQuery.getProvidersWithAccess(true);
912
assert.strictEqual(providersWithInternal.length, 5);
913
assert.ok(providersWithInternal.includes('regular'));
914
assert.ok(providersWithInternal.includes('_single'));
915
assert.ok(providersWithInternal.includes('__double'));
916
assert.ok(providersWithInternal.includes('___triple'));
917
assert.ok(providersWithInternal.includes('mid_underscore'));
918
});
919
920
test('getAllAccountPreferences filters internal providers by default for extensions', () => {
921
// Register providers
922
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
923
authService.registerAuthenticationProvider('azure', createProvider({ id: 'azure', label: 'Azure' }));
924
authService.registerAuthenticationProvider('__internal', createProvider({ id: '__internal', label: 'Internal' }));
925
926
// Set preferences
927
const extensionQuery = queryService.extension('my-extension');
928
extensionQuery.provider('github').setPreferredAccount({ id: 'user1', label: '[email protected]' });
929
extensionQuery.provider('azure').setPreferredAccount({ id: 'user2', label: '[email protected]' });
930
extensionQuery.provider('__internal').setPreferredAccount({ id: 'user3', label: '[email protected]' });
931
932
// Without includeInternal: should exclude internal providers
933
const prefsWithoutInternal = extensionQuery.getAllAccountPreferences(false);
934
assert.strictEqual(prefsWithoutInternal.size, 2);
935
assert.strictEqual(prefsWithoutInternal.get('github'), '[email protected]');
936
assert.strictEqual(prefsWithoutInternal.get('azure'), '[email protected]');
937
assert.strictEqual(prefsWithoutInternal.get('__internal'), undefined);
938
939
// With includeInternal: should include all providers
940
const prefsWithInternal = extensionQuery.getAllAccountPreferences(true);
941
assert.strictEqual(prefsWithInternal.size, 3);
942
assert.strictEqual(prefsWithInternal.get('github'), '[email protected]');
943
assert.strictEqual(prefsWithInternal.get('azure'), '[email protected]');
944
assert.strictEqual(prefsWithInternal.get('__internal'), '[email protected]');
945
946
// Default behavior: should exclude internal providers
947
const prefsDefault = extensionQuery.getAllAccountPreferences();
948
assert.strictEqual(prefsDefault.size, 2);
949
assert.strictEqual(prefsDefault.get('__internal'), undefined);
950
});
951
952
test('getAllAccountPreferences filters internal providers by default for MCP servers', () => {
953
// Register providers
954
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
955
authService.registerAuthenticationProvider('azure', createProvider({ id: 'azure', label: 'Azure' }));
956
authService.registerAuthenticationProvider('__internal', createProvider({ id: '__internal', label: 'Internal' }));
957
958
// Set preferences
959
const mcpQuery = queryService.mcpServer('my-server');
960
mcpQuery.provider('github').setPreferredAccount({ id: 'user1', label: '[email protected]' });
961
mcpQuery.provider('azure').setPreferredAccount({ id: 'user2', label: '[email protected]' });
962
mcpQuery.provider('__internal').setPreferredAccount({ id: 'user3', label: '[email protected]' });
963
964
// Without includeInternal: should exclude internal providers
965
const prefsWithoutInternal = mcpQuery.getAllAccountPreferences(false);
966
assert.strictEqual(prefsWithoutInternal.size, 2);
967
assert.strictEqual(prefsWithoutInternal.get('github'), '[email protected]');
968
assert.strictEqual(prefsWithoutInternal.get('azure'), '[email protected]');
969
assert.strictEqual(prefsWithoutInternal.get('__internal'), undefined);
970
971
// With includeInternal: should include all providers
972
const prefsWithInternal = mcpQuery.getAllAccountPreferences(true);
973
assert.strictEqual(prefsWithInternal.size, 3);
974
assert.strictEqual(prefsWithInternal.get('github'), '[email protected]');
975
assert.strictEqual(prefsWithInternal.get('azure'), '[email protected]');
976
assert.strictEqual(prefsWithInternal.get('__internal'), '[email protected]');
977
978
// Default behavior: should exclude internal providers
979
const prefsDefault = mcpQuery.getAllAccountPreferences();
980
assert.strictEqual(prefsDefault.size, 2);
981
assert.strictEqual(prefsDefault.get('__internal'), undefined);
982
});
983
984
test('clearAllData includes internal providers by default', async () => {
985
// Register providers
986
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
987
authService.registerAuthenticationProvider('__internal', createProvider({ id: '__internal', label: 'Internal' }));
988
989
// Add accounts
990
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
991
authService.addAccounts('__internal', [{ id: 'user2', label: '[email protected]' }]);
992
993
// Set up some data
994
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
995
queryService.provider('__internal').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
996
997
// Verify data exists
998
assert.strictEqual(queryService.provider('github').account('[email protected]').extension('my-extension').isAccessAllowed(), true);
999
assert.strictEqual(queryService.provider('__internal').account('[email protected]').extension('my-extension').isAccessAllowed(), true);
1000
1001
// Clear all data (should include internal providers by default)
1002
await queryService.clearAllData('CLEAR_ALL_AUTH_DATA');
1003
1004
// Verify all data is cleared
1005
assert.strictEqual(queryService.provider('github').account('[email protected]').extension('my-extension').isAccessAllowed(), undefined);
1006
assert.strictEqual(queryService.provider('__internal').account('[email protected]').extension('my-extension').isAccessAllowed(), undefined);
1007
});
1008
1009
test('clearAllData can exclude internal providers when specified', async () => {
1010
// Register providers
1011
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
1012
authService.registerAuthenticationProvider('__internal', createProvider({ id: '__internal', label: 'Internal' }));
1013
1014
// Add accounts
1015
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
1016
authService.addAccounts('__internal', [{ id: 'user2', label: '[email protected]' }]);
1017
1018
// Set up some data
1019
queryService.provider('github').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
1020
queryService.provider('__internal').account('[email protected]').extension('my-extension').setAccessAllowed(true, 'My Extension');
1021
1022
// Clear data excluding internal providers
1023
await queryService.clearAllData('CLEAR_ALL_AUTH_DATA', false);
1024
1025
// Verify only non-internal data is cleared
1026
assert.strictEqual(queryService.provider('github').account('[email protected]').extension('my-extension').isAccessAllowed(), undefined);
1027
assert.strictEqual(queryService.provider('__internal').account('[email protected]').extension('my-extension').isAccessAllowed(), true);
1028
});
1029
1030
test('isTrusted method works with mock service', () => {
1031
// Register provider and add account
1032
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
1033
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
1034
1035
// Add a server with trusted state manually to the mock
1036
mcpAccessService.updateAllowedMcpServers('github', '[email protected]', [{
1037
id: 'trusted-server',
1038
name: 'Trusted Server',
1039
allowed: true,
1040
trusted: true
1041
}]);
1042
1043
// Add a non-trusted server
1044
mcpAccessService.updateAllowedMcpServers('github', '[email protected]', [{
1045
id: 'non-trusted-server',
1046
name: 'Non-Trusted Server',
1047
allowed: true
1048
}]);
1049
1050
// Test trusted server
1051
const trustedQuery = queryService.provider('github').account('[email protected]').mcpServer('trusted-server');
1052
assert.strictEqual(trustedQuery.isTrusted(), true);
1053
1054
// Test non-trusted server
1055
const nonTrustedQuery = queryService.provider('github').account('[email protected]').mcpServer('non-trusted-server');
1056
assert.strictEqual(nonTrustedQuery.isTrusted(), false);
1057
});
1058
1059
test('getAllowedMcpServers method returns servers with trusted state', () => {
1060
// Register provider and add account
1061
authService.registerAuthenticationProvider('github', createProvider({ id: 'github', label: 'GitHub' }));
1062
authService.addAccounts('github', [{ id: 'user1', label: '[email protected]' }]);
1063
1064
// Add servers manually to the mock
1065
mcpAccessService.updateAllowedMcpServers('github', '[email protected]', [
1066
{
1067
id: 'trusted-server',
1068
name: 'Trusted Server',
1069
allowed: true,
1070
trusted: true
1071
},
1072
{
1073
id: 'user-server',
1074
name: 'User Server',
1075
allowed: true
1076
}
1077
]);
1078
1079
// Get all allowed servers
1080
const allowedServers = queryService.provider('github').account('[email protected]').mcpServers().getAllowedMcpServers();
1081
1082
// Should have both servers
1083
assert.strictEqual(allowedServers.length, 2);
1084
1085
// Find the trusted server
1086
const trustedServer = allowedServers.find(s => s.id === 'trusted-server');
1087
assert.ok(trustedServer);
1088
assert.strictEqual(trustedServer.trusted, true);
1089
assert.strictEqual(trustedServer.allowed, true);
1090
1091
// Find the user-allowed server
1092
const userServer = allowedServers.find(s => s.id === 'user-server');
1093
assert.ok(userServer);
1094
assert.strictEqual(userServer.trusted, undefined);
1095
assert.strictEqual(userServer.allowed, true);
1096
});
1097
1098
test('getAllowedExtensions returns extension data with trusted state', () => {
1099
// Set up some extension access data
1100
const accountQuery = queryService.provider('github').account('[email protected]');
1101
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension One');
1102
accountQuery.extension('ext2').setAccessAllowed(true, 'Extension Two');
1103
accountQuery.extension('ext1').addUsage(['read'], 'Extension One');
1104
1105
const allowedExtensions = accountQuery.extensions().getAllowedExtensions();
1106
1107
// Should have both extensions
1108
assert.strictEqual(allowedExtensions.length, 2);
1109
1110
// Find the first extension
1111
const ext1 = allowedExtensions.find(e => e.id === 'ext1');
1112
assert.ok(ext1);
1113
assert.strictEqual(ext1.name, 'Extension One');
1114
assert.strictEqual(ext1.allowed, true);
1115
assert.strictEqual(ext1.trusted, false); // Not in trusted list
1116
assert.ok(typeof ext1.lastUsed === 'number');
1117
1118
// Find the second extension
1119
const ext2 = allowedExtensions.find(e => e.id === 'ext2');
1120
assert.ok(ext2);
1121
assert.strictEqual(ext2.name, 'Extension Two');
1122
assert.strictEqual(ext2.allowed, true);
1123
assert.strictEqual(ext2.trusted, false); // Not in trusted list
1124
assert.strictEqual(ext2.lastUsed, undefined); // No usage
1125
});
1126
1127
suite('Account entities query', () => {
1128
test('hasAnyUsage returns false for clean account', () => {
1129
const entitiesQuery = queryService.provider('github').account('[email protected]').entities();
1130
assert.strictEqual(entitiesQuery.hasAnyUsage(), false);
1131
});
1132
1133
test('hasAnyUsage returns true when extension has usage', () => {
1134
const accountQuery = queryService.provider('github').account('[email protected]');
1135
accountQuery.extension('test-ext').addUsage(['read'], 'Test Extension');
1136
1137
const entitiesQuery = accountQuery.entities();
1138
assert.strictEqual(entitiesQuery.hasAnyUsage(), true);
1139
});
1140
1141
test('hasAnyUsage returns true when MCP server has usage', () => {
1142
const accountQuery = queryService.provider('github').account('[email protected]');
1143
accountQuery.mcpServer('test-server').addUsage(['write'], 'Test Server');
1144
1145
const entitiesQuery = accountQuery.entities();
1146
assert.strictEqual(entitiesQuery.hasAnyUsage(), true);
1147
});
1148
1149
test('hasAnyUsage returns true when extension has access', () => {
1150
const accountQuery = queryService.provider('github').account('[email protected]');
1151
accountQuery.extension('test-ext').setAccessAllowed(true, 'Test Extension');
1152
1153
const entitiesQuery = accountQuery.entities();
1154
assert.strictEqual(entitiesQuery.hasAnyUsage(), true);
1155
});
1156
1157
test('hasAnyUsage returns true when MCP server has access', () => {
1158
const accountQuery = queryService.provider('github').account('[email protected]');
1159
accountQuery.mcpServer('test-server').setAccessAllowed(true, 'Test Server');
1160
1161
const entitiesQuery = accountQuery.entities();
1162
assert.strictEqual(entitiesQuery.hasAnyUsage(), true);
1163
});
1164
1165
test('getEntityCount returns correct counts', () => {
1166
const accountQuery = queryService.provider('github').account('[email protected]');
1167
1168
// Set up test data
1169
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension One');
1170
accountQuery.extension('ext2').setAccessAllowed(true, 'Extension Two');
1171
accountQuery.mcpServer('server1').setAccessAllowed(true, 'Server One');
1172
1173
const entitiesQuery = accountQuery.entities();
1174
const counts = entitiesQuery.getEntityCount();
1175
1176
assert.strictEqual(counts.extensions, 2);
1177
assert.strictEqual(counts.mcpServers, 1);
1178
assert.strictEqual(counts.total, 3);
1179
});
1180
1181
test('getEntityCount returns zero for clean account', () => {
1182
const entitiesQuery = queryService.provider('github').account('[email protected]').entities();
1183
const counts = entitiesQuery.getEntityCount();
1184
1185
assert.strictEqual(counts.extensions, 0);
1186
assert.strictEqual(counts.mcpServers, 0);
1187
assert.strictEqual(counts.total, 0);
1188
});
1189
1190
test('removeAllAccess removes access for all entity types', () => {
1191
const accountQuery = queryService.provider('github').account('[email protected]');
1192
1193
// Set up test data
1194
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension One');
1195
accountQuery.extension('ext2').setAccessAllowed(true, 'Extension Two');
1196
accountQuery.mcpServer('server1').setAccessAllowed(true, 'Server One');
1197
accountQuery.mcpServer('server2').setAccessAllowed(true, 'Server Two');
1198
1199
// Verify initial state
1200
assert.strictEqual(accountQuery.extension('ext1').isAccessAllowed(), true);
1201
assert.strictEqual(accountQuery.extension('ext2').isAccessAllowed(), true);
1202
assert.strictEqual(accountQuery.mcpServer('server1').isAccessAllowed(), true);
1203
assert.strictEqual(accountQuery.mcpServer('server2').isAccessAllowed(), true);
1204
1205
// Remove all access
1206
const entitiesQuery = accountQuery.entities();
1207
entitiesQuery.removeAllAccess();
1208
1209
// Verify all access is removed
1210
assert.strictEqual(accountQuery.extension('ext1').isAccessAllowed(), false);
1211
assert.strictEqual(accountQuery.extension('ext2').isAccessAllowed(), false);
1212
assert.strictEqual(accountQuery.mcpServer('server1').isAccessAllowed(), false);
1213
assert.strictEqual(accountQuery.mcpServer('server2').isAccessAllowed(), false);
1214
});
1215
1216
test('forEach iterates over all entity types', () => {
1217
const accountQuery = queryService.provider('github').account('[email protected]');
1218
1219
// Set up test data
1220
accountQuery.extension('ext1').setAccessAllowed(true, 'Extension One');
1221
accountQuery.extension('ext2').addUsage(['read'], 'Extension Two');
1222
accountQuery.mcpServer('server1').setAccessAllowed(true, 'Server One');
1223
accountQuery.mcpServer('server2').addUsage(['write'], 'Server Two');
1224
1225
const entitiesQuery = accountQuery.entities();
1226
const visitedEntities: Array<{ id: string; type: 'extension' | 'mcpServer' }> = [];
1227
1228
entitiesQuery.forEach((entityId, entityType) => {
1229
visitedEntities.push({ id: entityId, type: entityType });
1230
});
1231
1232
// Should visit all entities that have usage or access
1233
assert.strictEqual(visitedEntities.length, 4);
1234
1235
const extensions = visitedEntities.filter(e => e.type === 'extension');
1236
const mcpServers = visitedEntities.filter(e => e.type === 'mcpServer');
1237
1238
assert.strictEqual(extensions.length, 2);
1239
assert.strictEqual(mcpServers.length, 2);
1240
1241
// Check specific entities were visited
1242
assert.ok(visitedEntities.some(e => e.id === 'ext1' && e.type === 'extension'));
1243
assert.ok(visitedEntities.some(e => e.id === 'ext2' && e.type === 'extension'));
1244
assert.ok(visitedEntities.some(e => e.id === 'server1' && e.type === 'mcpServer'));
1245
assert.ok(visitedEntities.some(e => e.id === 'server2' && e.type === 'mcpServer'));
1246
});
1247
});
1248
});
1249
1250