@@ -2,8 +2,9 @@ import Sinon from 'sinon';
22import { expect } from 'chai' ;
33import { AtlasService , throwIfNotOk } from './main' ;
44import { promisify } from 'util' ;
5- import type { EventEmitter } from 'events' ;
5+ import { EventEmitter } from 'events' ;
66import { once } from 'events' ;
7+ import preferencesAccess from 'compass-preferences-model' ;
78
89const wait = promisify ( setTimeout ) ;
910
@@ -13,20 +14,6 @@ function getListenerCount(emitter: EventEmitter) {
1314 } , 0 ) ;
1415}
1516
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-
3017describe ( 'AtlasServiceMain' , function ( ) {
3118 const sandbox = Sinon . createSandbox ( ) ;
3219
@@ -52,6 +39,7 @@ describe('AtlasServiceMain', function () {
5239
5340 const fetch = AtlasService [ 'fetch' ] ;
5441 const ipcMain = AtlasService [ 'ipcMain' ] ;
42+ const createPlugin = AtlasService [ 'createMongoDBOIDCPlugin' ] ;
5543 const apiBaseUrl = process . env . COMPASS_ATLAS_SERVICE_BASE_URL ;
5644 const issuer = process . env . COMPASS_OIDC_ISSUER ;
5745 const clientId = process . env . COMPASS_CLIENT_ID ;
@@ -74,6 +62,7 @@ describe('AtlasServiceMain', function () {
7462 AtlasService [ 'token' ] = null ;
7563 AtlasService [ 'initPromise' ] = null ;
7664 AtlasService [ 'oidcPluginSyncedFromLoggerState' ] = 'initial' ;
65+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
7766
7867 sandbox . resetHistory ( ) ;
7968 } ) ;
@@ -213,15 +202,46 @@ describe('AtlasServiceMain', function () {
213202 } ) ;
214203 } ) ;
215204
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 ) {
217239 describe ( functionName , function ( ) {
218240 it ( 'makes a post request with the user input to the endpoint in the environment' , async function ( ) {
219241 AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
220242 ok : true ,
221243 json ( ) {
222- return Promise . resolve ( {
223- content : { query : { filter : "{ test: 'pineapple' }" } } ,
224- } ) ;
244+ return Promise . resolve ( responses . success ) ;
225245 } ,
226246 } ) as any ;
227247
@@ -243,10 +263,28 @@ describe('AtlasServiceMain', function () {
243263 expect ( args [ 1 ] . body ) . to . eq (
244264 '{"userInput":"test","collectionName":"jam","databaseName":"peanut","schema":{"_id":{"types":[{"bsonType":"ObjectId"}]}},"sampleDocuments":[{"_id":1234}]}'
245265 ) ;
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+ }
250288 } ) ;
251289
252290 it ( 'uses the abort signal in the fetch request' , async function ( ) {
@@ -286,7 +324,7 @@ describe('AtlasServiceMain', function () {
286324 AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
287325 ok : true ,
288326 json ( ) {
289- return Promise . resolve ( { } ) ;
327+ return Promise . resolve ( responses . success ) ;
290328 } ,
291329 } ) as any ;
292330
@@ -353,13 +391,13 @@ describe('AtlasServiceMain', function () {
353391 AtlasService [ 'fetch' ] = sandbox . stub ( ) . resolves ( {
354392 ok : true ,
355393 json ( ) {
356- return Promise . resolve ( { test : 1 } ) ;
394+ return Promise . resolve ( responses . success ) ;
357395 } ,
358396 } ) as any ;
359397 AtlasService [ 'oidcPluginLogger' ] . emit (
360398 'mongodb-oidc-plugin:refresh-started'
361399 ) ;
362- const [ query ] = await Promise . all ( [
400+ const [ res ] = await Promise . all ( [
363401 AtlasService [ functionName ] ( {
364402 userInput : 'test' ,
365403 collectionName : 'test' ,
@@ -375,7 +413,7 @@ describe('AtlasServiceMain', function () {
375413 ) ;
376414 } ) ( ) ,
377415 ] ) ;
378- expect ( query ) . to . deep . eq ( { test : 1 } ) ;
416+ expect ( res ) . to . deep . eq ( responses . success ) ;
379417 } ) ;
380418 } ) ;
381419 }
@@ -542,7 +580,8 @@ describe('AtlasServiceMain', function () {
542580 . stub ( )
543581 . rejects ( new Error ( 'Could not retrieve valid access token' ) ) ;
544582 const createPlugin = ( ) => mockOidcPlugin ;
545- const initPromise = AtlasService . init ( createPlugin ) ;
583+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
584+ const initPromise = AtlasService . init ( ) ;
546585 expect ( AtlasService ) . to . have . property (
547586 'oidcPluginSyncedFromLoggerState' ,
548587 'restoring'
@@ -558,7 +597,8 @@ describe('AtlasServiceMain', function () {
558597 mockOidcPlugin . mongoClientOptions . authMechanismProperties . REQUEST_TOKEN_CALLBACK =
559598 sandbox . stub ( ) . resolves ( { accessToken : 'token' } ) ;
560599 const createPlugin = ( ) => mockOidcPlugin ;
561- const initPromise = AtlasService . init ( createPlugin ) ;
600+ AtlasService [ 'createMongoDBOIDCPlugin' ] = createPlugin ;
601+ const initPromise = AtlasService . init ( ) ;
562602 expect ( AtlasService ) . to . have . property (
563603 'oidcPluginSyncedFromLoggerState' ,
564604 'restoring'
@@ -570,4 +610,68 @@ describe('AtlasServiceMain', function () {
570610 ) ;
571611 } ) ;
572612 } ) ;
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+ } ) ;
573677} ) ;
0 commit comments