@@ -2,8 +2,9 @@ import Sinon from 'sinon';
2
2
import { expect } from 'chai' ;
3
3
import { AtlasService , throwIfNotOk } from './main' ;
4
4
import { promisify } from 'util' ;
5
- import type { EventEmitter } from 'events' ;
5
+ import { EventEmitter } from 'events' ;
6
6
import { once } from 'events' ;
7
+ import preferencesAccess from 'compass-preferences-model' ;
7
8
8
9
const wait = promisify ( setTimeout ) ;
9
10
@@ -13,20 +14,6 @@ function getListenerCount(emitter: EventEmitter) {
13
14
} , 0 ) ;
14
15
}
15
16
16
- const atlasAIServiceTests : {
17
- functionName : 'getQueryFromUserInput' | 'getAggregationFromUserInput' ;
18
- aiEndpoint : string ;
19
- } [ ] = [
20
- {
21
- functionName : 'getQueryFromUserInput' ,
22
- aiEndpoint : 'mql-query' ,
23
- } ,
24
- {
25
- functionName : 'getAggregationFromUserInput' ,
26
- aiEndpoint : 'mql-aggregation' ,
27
- } ,
28
- ] ;
29
-
30
17
describe ( 'AtlasServiceMain' , function ( ) {
31
18
const sandbox = Sinon . createSandbox ( ) ;
32
19
@@ -52,6 +39,7 @@ describe('AtlasServiceMain', function () {
52
39
53
40
const fetch = AtlasService [ 'fetch' ] ;
54
41
const ipcMain = AtlasService [ 'ipcMain' ] ;
42
+ const createPlugin = AtlasService [ 'createMongoDBOIDCPlugin' ] ;
55
43
const apiBaseUrl = process . env . COMPASS_ATLAS_SERVICE_BASE_URL ;
56
44
const issuer = process . env . COMPASS_OIDC_ISSUER ;
57
45
const clientId = process . env . COMPASS_CLIENT_ID ;
@@ -74,6 +62,7 @@ describe('AtlasServiceMain', function () {
74
62
AtlasService [ 'token' ] = null ;
75
63
AtlasService [ 'initPromise' ] = null ;
76
64
AtlasService [ 'oidcPluginSyncedFromLoggerState' ] = 'initial' ;
65
+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
77
66
78
67
sandbox . resetHistory ( ) ;
79
68
} ) ;
@@ -213,15 +202,46 @@ describe('AtlasServiceMain', function () {
213
202
} ) ;
214
203
} ) ;
215
204
216
- for ( const { functionName, aiEndpoint } of atlasAIServiceTests ) {
205
+ const atlasAIServiceTests = [
206
+ {
207
+ functionName : 'getQueryFromUserInput' ,
208
+ aiEndpoint : 'mql-query' ,
209
+ responses : {
210
+ success : {
211
+ content : { query : { filter : "{ test: 'pineapple' }" } } ,
212
+ } ,
213
+ invalid : [
214
+ { } ,
215
+ { countent : { } } ,
216
+ { content : { qooery : { } } } ,
217
+ { content : { query : { filter : { foo : 1 } } } } ,
218
+ ] ,
219
+ } ,
220
+ } ,
221
+ {
222
+ functionName : 'getAggregationFromUserInput' ,
223
+ aiEndpoint : 'mql-aggregation' ,
224
+ responses : {
225
+ success : {
226
+ content : { aggregation : { pipeline : "[{ test: 'pineapple' }]" } } ,
227
+ } ,
228
+ invalid : [
229
+ { } ,
230
+ { content : { aggregation : { } } } ,
231
+ { content : { aggrogation : { } } } ,
232
+ { content : { aggregation : { pipeline : true } } } ,
233
+ ] ,
234
+ } ,
235
+ } ,
236
+ ] as const ;
237
+
238
+ for ( const { functionName, aiEndpoint, responses } of atlasAIServiceTests ) {
217
239
describe ( functionName , function ( ) {
218
240
it ( 'makes a post request with the user input to the endpoint in the environment' , async function ( ) {
219
241
AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
220
242
ok : true ,
221
243
json ( ) {
222
- return Promise . resolve ( {
223
- content : { query : { filter : "{ test: 'pineapple' }" } } ,
224
- } ) ;
244
+ return Promise . resolve ( responses . success ) ;
225
245
} ,
226
246
} ) as any ;
227
247
@@ -243,10 +263,28 @@ describe('AtlasServiceMain', function () {
243
263
expect ( args [ 1 ] . body ) . to . eq (
244
264
'{"userInput":"test","collectionName":"jam","databaseName":"peanut","schema":{"_id":{"types":[{"bsonType":"ObjectId"}]}},"sampleDocuments":[{"_id":1234}]}'
245
265
) ;
246
- expect ( res ) . to . have . nested . property (
247
- 'content.query.filter' ,
248
- "{ test: 'pineapple' }"
249
- ) ;
266
+ expect ( res ) . to . deep . eq ( responses . success ) ;
267
+ } ) ;
268
+
269
+ it ( 'should fail when response is not matching expected schema' , async function ( ) {
270
+ for ( const res of responses . invalid ) {
271
+ AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
272
+ ok : true ,
273
+ json ( ) {
274
+ return Promise . resolve ( res ) ;
275
+ } ,
276
+ } ) as any ;
277
+ try {
278
+ await AtlasService [ functionName ] ( {
279
+ userInput : 'test' ,
280
+ collectionName : 'test' ,
281
+ databaseName : 'peanut' ,
282
+ } ) ;
283
+ expect . fail ( `Expected ${ functionName } to throw` ) ;
284
+ } catch ( err ) {
285
+ expect ( ( err as Error ) . message ) . to . match ( / U n e x p e c t e d .+ ?r e s p o n s e / ) ;
286
+ }
287
+ }
250
288
} ) ;
251
289
252
290
it ( 'uses the abort signal in the fetch request' , async function ( ) {
@@ -286,7 +324,7 @@ describe('AtlasServiceMain', function () {
286
324
AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
287
325
ok : true ,
288
326
json ( ) {
289
- return Promise . resolve ( { } ) ;
327
+ return Promise . resolve ( responses . success ) ;
290
328
} ,
291
329
} ) as any ;
292
330
@@ -353,13 +391,13 @@ describe('AtlasServiceMain', function () {
353
391
AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
354
392
ok : true ,
355
393
json ( ) {
356
- return Promise . resolve ( { test : 1 } ) ;
394
+ return Promise . resolve ( responses . success ) ;
357
395
} ,
358
396
} ) as any ;
359
397
AtlasService [ 'oidcPluginLogger' ] . emit (
360
398
'mongodb-oidc-plugin:refresh-started'
361
399
) ;
362
- const [ query ] = await Promise . all ( [
400
+ const [ res ] = await Promise . all ( [
363
401
AtlasService [ functionName ] ( {
364
402
userInput : 'test' ,
365
403
collectionName : 'test' ,
@@ -375,7 +413,7 @@ describe('AtlasServiceMain', function () {
375
413
) ;
376
414
} ) ( ) ,
377
415
] ) ;
378
- expect ( query ) . to . deep . eq ( { test : 1 } ) ;
416
+ expect ( res ) . to . deep . eq ( responses . success ) ;
379
417
} ) ;
380
418
} ) ;
381
419
}
@@ -542,7 +580,8 @@ describe('AtlasServiceMain', function () {
542
580
. stub ( )
543
581
. rejects ( new Error ( 'Could not retrieve valid access token' ) ) ;
544
582
const createPlugin = ( ) => mockOidcPlugin ;
545
- const initPromise = AtlasService . init ( createPlugin ) ;
583
+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
584
+ const initPromise = AtlasService . init ( ) ;
546
585
expect ( AtlasService ) . to . have . property (
547
586
'oidcPluginSyncedFromLoggerState' ,
548
587
'restoring'
@@ -558,7 +597,8 @@ describe('AtlasServiceMain', function () {
558
597
mockOidcPlugin . mongoClientOptions . authMechanismProperties . REQUEST_TOKEN_CALLBACK =
559
598
sandbox . stub ( ) . resolves ( { accessToken : 'token' } ) ;
560
599
const createPlugin = ( ) => mockOidcPlugin ;
561
- const initPromise = AtlasService . init ( createPlugin ) ;
600
+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
601
+ const initPromise = AtlasService . init ( ) ;
562
602
expect ( AtlasService ) . to . have . property (
563
603
'oidcPluginSyncedFromLoggerState' ,
564
604
'restoring'
@@ -570,4 +610,68 @@ describe('AtlasServiceMain', function () {
570
610
) ;
571
611
} ) ;
572
612
} ) ;
613
+
614
+ describe ( 'with networkTraffic turned off' , function ( ) {
615
+ let networkTraffic : boolean ;
616
+
617
+ before ( async function ( ) {
618
+ networkTraffic = preferencesAccess . getPreferences ( ) . networkTraffic ;
619
+ await preferencesAccess . savePreferences ( { networkTraffic : false } ) ;
620
+ } ) ;
621
+
622
+ after ( async function ( ) {
623
+ await preferencesAccess . savePreferences ( { networkTraffic } ) ;
624
+ } ) ;
625
+
626
+ for ( const methodName of [
627
+ 'requestOAuthToken' ,
628
+ 'signIn' ,
629
+ 'getUserInfo' ,
630
+ 'introspect' ,
631
+ 'revoke' ,
632
+ 'getAggregationFromUserInput' ,
633
+ 'getQueryFromUserInput' ,
634
+ ] ) {
635
+ it ( `${ methodName } should throw` , async function ( ) {
636
+ try {
637
+ await ( AtlasService as any ) [ methodName ] ( { } ) ;
638
+ expect . fail ( `Expected ${ methodName } to throw` ) ;
639
+ } catch ( err ) {
640
+ expect ( err ) . to . have . property (
641
+ 'message' ,
642
+ 'Network traffic is not allowed'
643
+ ) ;
644
+ }
645
+ } ) ;
646
+ }
647
+ } ) ;
648
+
649
+ describe ( 'signOut' , function ( ) {
650
+ it ( 'should reset service state, revoke tokens, and destroy plugin' , async function ( ) {
651
+ const logger = new EventEmitter ( ) ;
652
+ const plugin = {
653
+ destroy : sandbox . stub ( ) . resolves ( ) ,
654
+ } ;
655
+ AtlasService [ 'openExternal' ] = sandbox . stub ( ) . resolves ( ) ;
656
+ AtlasService [ 'token' ] = { accessToken : '1234' } ;
657
+ AtlasService [ 'createMongoDBOIDCPlugin' ] = ( ( ) => {
658
+ return plugin ;
659
+ } ) as any ;
660
+ AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( { ok : true } ) as any ;
661
+ AtlasService [ 'oidcPluginLogger' ] = logger ;
662
+
663
+ await AtlasService . init ( ) ;
664
+ expect ( getListenerCount ( logger ) ) . to . eq ( 25 ) ;
665
+
666
+ await AtlasService . signOut ( ) ;
667
+ expect ( getListenerCount ( logger ) ) . to . eq ( 0 ) ;
668
+ expect ( logger ) . to . not . eq ( AtlasService [ 'oidcPluginLogger' ] ) ;
669
+ expect ( plugin . destroy ) . to . have . been . calledOnce ;
670
+ expect ( AtlasService [ 'fetch' ] ) . to . have . been . calledOnceWith (
671
+ 'http://example.com/v1/revoke?client_id=1234abcd'
672
+ ) ;
673
+ expect ( AtlasService [ 'token' ] ) . to . eq ( null ) ;
674
+ expect ( AtlasService [ 'openExternal' ] ) . to . have . been . calledOnce ;
675
+ } ) ;
676
+ } ) ;
573
677
} ) ;
0 commit comments