@@ -22,6 +22,7 @@ import { runCommand } from './run-command';
2222import { mochaTestServer } from '@mongodb-js/compass-test-server' ;
2323import type { SearchIndex } from './search-index-detail-helper' ;
2424import { range } from 'lodash' ;
25+ import ConnectionString from 'mongodb-connection-string-url' ;
2526
2627const { expect } = chai ;
2728chai . use ( chaiAsPromised ) ;
@@ -535,6 +536,91 @@ describe('DataService', function () {
535536 ) ;
536537 expect ( collections ) . to . have . nested . property ( '[0].type' , 'collection' ) ;
537538 } ) ;
539+
540+ context ( 'with non existant collections' , function ( ) {
541+ let dataService : DataServiceImpl ;
542+ beforeEach ( async function ( ) {
543+ await mongoClient . db ( 'imdb' ) . command ( {
544+ createRole : 'moderator' ,
545+ privileges : [
546+ {
547+ resource : { db : 'imdb' , collection : 'movies' } ,
548+ actions : [ 'find' ] ,
549+ } ,
550+ {
551+ resource : { db : 'imdb' , collection : 'reviews' } ,
552+ actions : [ 'find' ] ,
553+ } ,
554+ {
555+ resource : { db : 'imdb' , collection : 'users' } ,
556+ actions : [ 'find' ] ,
557+ } ,
558+ ] ,
559+ roles : [ ] ,
560+ } ) ;
561+
562+ await mongoClient . db ( 'admin' ) . command ( {
563+ createUser : 'new_user' ,
564+ pwd : 'new_password' ,
565+ roles : [ { role : 'moderator' , db : 'imdb' } ] ,
566+ } ) ;
567+ const cs = new ConnectionString ( connectionOptions . connectionString ) ;
568+ cs . username = 'new_user' ;
569+ cs . password = 'new_password' ;
570+ const newConnectionOptions = {
571+ connectionString : cs . toString ( ) ,
572+ } ;
573+
574+ dataService = new DataServiceImpl ( newConnectionOptions ) ;
575+ await dataService . connect ( ) ;
576+ } ) ;
577+
578+ afterEach ( async function ( ) {
579+ await Promise . all ( [
580+ mongoClient . db ( 'admin' ) . command ( {
581+ dropUser : 'new_user' ,
582+ } ) ,
583+ mongoClient . db ( 'imdb' ) . command ( {
584+ dropRole : 'moderator' ,
585+ } ) ,
586+ mongoClient . db ( 'imdb' ) . dropDatabase ( ) ,
587+ ] ) . catch ( ( ) => null ) ;
588+ await dataService ?. disconnect ( ) ;
589+ } ) ;
590+
591+ it ( 'returns collections from user privileges' , async function ( ) {
592+ const collections = await dataService . listCollections ( 'imdb' ) ;
593+ const mappedCollections = collections . map (
594+ ( { _id, name, is_non_existant } ) => ( { _id, name, is_non_existant } )
595+ ) ;
596+
597+ const expectedCollections = [
598+ { _id : 'imdb.movies' , name : 'movies' , is_non_existant : true } ,
599+ { _id : 'imdb.reviews' , name : 'reviews' , is_non_existant : true } ,
600+ { _id : 'imdb.users' , name : 'users' , is_non_existant : true } ,
601+ ] ;
602+ expect ( mappedCollections ) . to . deep . include . members (
603+ expectedCollections
604+ ) ;
605+ } ) ;
606+
607+ it ( 'gives precedence to the provisioned collections' , async function ( ) {
608+ await dataService . createCollection ( 'imdb.movies' , { } ) ;
609+ const collections = await dataService . listCollections ( 'imdb' ) ;
610+ const mappedCollections = collections . map (
611+ ( { _id, name, is_non_existant } ) => ( { _id, name, is_non_existant } )
612+ ) ;
613+
614+ const expectedCollections = [
615+ { _id : 'imdb.movies' , name : 'movies' , is_non_existant : false } ,
616+ { _id : 'imdb.reviews' , name : 'reviews' , is_non_existant : true } ,
617+ { _id : 'imdb.users' , name : 'users' , is_non_existant : true } ,
618+ ] ;
619+ expect ( mappedCollections ) . to . deep . include . members (
620+ expectedCollections
621+ ) ;
622+ } ) ;
623+ } ) ;
538624 } ) ;
539625
540626 describe ( '#updateCollection' , function ( ) {
@@ -688,6 +774,98 @@ describe('DataService', function () {
688774 }
689775 expect ( databaseNames ) . to . contain ( `${ testDatabaseName } ` ) ;
690776 } ) ;
777+
778+ context ( 'with non existant databases' , function ( ) {
779+ let dataService : DataServiceImpl ;
780+ beforeEach ( async function ( ) {
781+ await mongoClient . db ( 'imdb' ) . command ( {
782+ createRole : 'moderator' ,
783+ privileges : [
784+ {
785+ resource : { db : 'imdb' , collection : 'movies' } ,
786+ actions : [ 'find' ] ,
787+ } ,
788+ {
789+ resource : { db : 'imdb' , collection : 'reviews' } ,
790+ actions : [ 'find' ] ,
791+ } ,
792+ ] ,
793+ roles : [ ] ,
794+ } ) ;
795+
796+ await mongoClient . db ( 'admin' ) . command ( {
797+ createUser : 'new_user' ,
798+ pwd : 'new_password' ,
799+ roles : [
800+ { role : 'readWrite' , db : 'sample_airbnb' } ,
801+ { role : 'read' , db : 'sample_wiki' } ,
802+ { role : 'moderator' , db : 'imdb' } ,
803+ ] ,
804+ } ) ;
805+ const cs = new ConnectionString ( connectionOptions . connectionString ) ;
806+ cs . username = 'new_user' ;
807+ cs . password = 'new_password' ;
808+ const newConnectionOptions = {
809+ connectionString : cs . toString ( ) ,
810+ } ;
811+
812+ dataService = new DataServiceImpl ( newConnectionOptions ) ;
813+ await dataService . connect ( ) ;
814+ } ) ;
815+
816+ afterEach ( async function ( ) {
817+ await Promise . all ( [
818+ mongoClient . db ( 'admin' ) . command ( {
819+ dropUser : 'new_user' ,
820+ } ) ,
821+ mongoClient . db ( 'imdb' ) . command ( {
822+ dropRole : 'moderator' ,
823+ } ) ,
824+ mongoClient . db ( 'imdb' ) . dropDatabase ( ) ,
825+ ] ) . catch ( ( ) => null ) ;
826+ await dataService ?. disconnect ( ) ;
827+ } ) ;
828+
829+ it ( 'returns databases from user roles and privileges' , async function ( ) {
830+ const databases = await dataService . listDatabases ( ) ;
831+ const mappedDatabases = databases . map (
832+ ( { _id, name, is_non_existant } ) => ( { _id, name, is_non_existant } )
833+ ) ;
834+
835+ const expectedDatabases = [
836+ // Based on roles
837+ {
838+ _id : 'sample_airbnb' ,
839+ name : 'sample_airbnb' ,
840+ is_non_existant : true ,
841+ } ,
842+ { _id : 'sample_wiki' , name : 'sample_wiki' , is_non_existant : true } ,
843+ // Based on privileges
844+ { _id : 'imdb' , name : 'imdb' , is_non_existant : true } ,
845+ ] ;
846+ expect ( mappedDatabases ) . to . deep . include . members ( expectedDatabases ) ;
847+ } ) ;
848+
849+ it ( 'gives precedence to the provisioned databases' , async function ( ) {
850+ await dataService . createCollection ( 'imdb.movies' , { } ) ;
851+ await dataService . createCollection ( 'sample_airbnb.whatever' , { } ) ;
852+ const databases = await dataService . listDatabases ( ) ;
853+ const mappedDatabases = databases . map (
854+ ( { _id, name, is_non_existant } ) => ( { _id, name, is_non_existant } )
855+ ) ;
856+
857+ const expectedDatabases = [
858+ {
859+ _id : 'sample_airbnb' ,
860+ name : 'sample_airbnb' ,
861+ is_non_existant : false ,
862+ } ,
863+ { _id : 'sample_wiki' , name : 'sample_wiki' , is_non_existant : true } ,
864+ { _id : 'imdb' , name : 'imdb' , is_non_existant : false } ,
865+ ] ;
866+ expect ( mappedDatabases ) . to . deep . include . members ( expectedDatabases ) ;
867+ } ) ;
868+ } ) ;
691869 } ) ;
692870
693871 describe ( '#createCollection' , function ( ) {
@@ -1609,8 +1787,15 @@ describe('DataService', function () {
16091787 } ,
16101788 } ,
16111789 } ) ;
1612- const dbs = ( await dataService . listDatabases ( ) ) . map ( ( db ) => db . name ) ;
1613- expect ( dbs ) . to . deep . eq ( [ 'pineapple' , 'foo' , 'buz' , 'bar' ] ) ;
1790+ const dbs = ( await dataService . listDatabases ( ) ) . map (
1791+ ( { name, is_non_existant } ) => ( { name, is_non_existant } )
1792+ ) ;
1793+ expect ( dbs ) . to . deep . eq ( [
1794+ { name : 'pineapple' , is_non_existant : true } ,
1795+ { name : 'foo' , is_non_existant : false } ,
1796+ { name : 'buz' , is_non_existant : true } ,
1797+ { name : 'bar' , is_non_existant : false } ,
1798+ ] ) ;
16141799 } ) ;
16151800
16161801 it ( 'returns result from privileges even if listDatabases threw any error' , async function ( ) {
@@ -1629,8 +1814,10 @@ describe('DataService', function () {
16291814 } ,
16301815 } ,
16311816 } ) ;
1632- const dbs = ( await dataService . listDatabases ( ) ) . map ( ( db ) => db . name ) ;
1633- expect ( dbs ) . to . deep . eq ( [ 'foo' ] ) ;
1817+ const dbs = ( await dataService . listDatabases ( ) ) . map (
1818+ ( { name, is_non_existant } ) => ( { name, is_non_existant } )
1819+ ) ;
1820+ expect ( dbs ) . to . deep . eq ( [ { name : 'foo' , is_non_existant : true } ] ) ;
16341821 } ) ;
16351822 } ) ;
16361823
@@ -1723,9 +1910,14 @@ describe('DataService', function () {
17231910 } ,
17241911 } ) ;
17251912 const colls = ( await dataService . listCollections ( 'foo' ) ) . map (
1726- ( coll ) => coll . name
1913+ ( { name , is_non_existant } ) => ( { name, is_non_existant } )
17271914 ) ;
1728- expect ( colls ) . to . deep . eq ( [ 'bar' , 'buz' , 'bla' , 'meow' ] ) ;
1915+ expect ( colls ) . to . deep . eq ( [
1916+ { name : 'bar' , is_non_existant : true } ,
1917+ { name : 'buz' , is_non_existant : false } ,
1918+ { name : 'bla' , is_non_existant : false } ,
1919+ { name : 'meow' , is_non_existant : false } ,
1920+ ] ) ;
17291921 } ) ;
17301922
17311923 it ( 'returns result from privileges even if listCollections threw any error' , async function ( ) {
@@ -1747,9 +1939,9 @@ describe('DataService', function () {
17471939 } ,
17481940 } ) ;
17491941 const colls = ( await dataService . listCollections ( 'foo' ) ) . map (
1750- ( coll ) => coll . name
1942+ ( { name , is_non_existant } ) => ( { name, is_non_existant } )
17511943 ) ;
1752- expect ( colls ) . to . deep . eq ( [ 'bar' ] ) ;
1944+ expect ( colls ) . to . deep . eq ( [ { name : 'bar' , is_non_existant : true } ] ) ;
17531945 } ) ;
17541946 } ) ;
17551947
0 commit comments