public void DropAllDatabasesTest()
        {
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);
            _mongoDatabaseConnection.Connect();

            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);// uses MONGO_DATABASE_1_NAME
            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);

            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_2_NAME);
            _mongoDatabaseConnection.Connect();
            _reader = new Reader(_mongoDatabaseConnection);
            _writer = new Writer(_mongoDatabaseConnection);// need to reinitialize writer when we change the DatabaseConnection

            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);// uses MONGO_DATABASE_2_NAME
            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);

            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_3_NAME);
            _mongoDatabaseConnection.Connect();

            _reader = new Reader(_mongoDatabaseConnection);
            _writer = new Writer(_mongoDatabaseConnection);// need to reinitialize writer when we change the DatabaseConnection

            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);// uses MONGO_DATABASE_3_NAME
            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);

            List<string> results = _mongoServerConnection.GetDbNamesForConnection();
            Assert.IsTrue(results.Contains(MONGO_DATABASE_1_NAME));
            Assert.IsTrue(results.Contains(MONGO_DATABASE_2_NAME));
            Assert.IsTrue(results.Contains(MONGO_DATABASE_3_NAME));

            List<CommandResult> commandResults = _mongoServerConnection.DropAllDatabases();
            foreach (CommandResult commandResult in commandResults)
            {
                Assert.IsNotNull(commandResult);
                Assert.IsTrue(commandResult.Ok);
                Assert.IsNull(commandResult.ErrorMessage);
            }

            results = _mongoServerConnection.GetDbNamesForConnection();
            Assert.IsFalse(results.Contains(MONGO_DATABASE_1_NAME));
            Assert.IsFalse(results.Contains(MONGO_DATABASE_2_NAME));
            Assert.IsFalse(results.Contains(MONGO_DATABASE_3_NAME));
        }
        public void DropDatabase1Test()
        {
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);
            _mongoDatabaseConnection.Connect();

            AddMongoEntry(collectionName:MONGO_COLLECTION_1_NAME);// uses MONGO_DATABASE_1_NAME
            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);

            List<MongoCollection<Entry>> mongoCollections = _mongoDatabaseConnection.GetCollections<Entry>();
            Assert.AreEqual(3, mongoCollections.Count());// with system.indexes too

            CommandResult commandResult = _mongoServerConnection.DropDatabase(MONGO_DATABASE_1_NAME);
            Assert.IsNotNull(commandResult);
            Assert.IsTrue(commandResult.Ok);
            Assert.IsNull(commandResult.ErrorMessage);

            // the collections that we added will be removed with the database drop
            mongoCollections = _mongoDatabaseConnection.GetCollections<Entry>();
            Assert.AreEqual(0, mongoCollections.Count());

            // this is confusing functionality; the MongoDatabase object returned does not actually exist on the server
            // but will when it is written against
            MongoDatabase mongoDatabase = _mongoServerConnection.GetDatabase(MONGO_DATABASE_1_NAME, _writeConcern);
            Assert.IsNotNull(mongoDatabase);

            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_2_NAME);
            _mongoDatabaseConnection.Connect();
            _reader = new Reader(_mongoDatabaseConnection);
            _writer = new Writer(_mongoDatabaseConnection);// need to reinitialize writer when we change the DatabaseConnection

            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);// uses MONGO_DATABASE_2_NAME
            AddMongoEntry(collectionName: MONGO_COLLECTION_1_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);
            AddMongoEntry(collectionName: MONGO_COLLECTION_2_NAME);

            mongoCollections = _mongoDatabaseConnection.GetCollections<Entry>();
            Assert.AreEqual(3, mongoCollections.Count());//system.indexes too

            commandResult = _mongoServerConnection.DropDatabase(MONGO_DATABASE_2_NAME);
            Assert.IsNotNull(commandResult);
            Assert.IsTrue(commandResult.Ok);
            Assert.IsNull(commandResult.ErrorMessage);

            // the collections that we added will be removed with the database drop
            mongoCollections = _mongoDatabaseConnection.GetCollections<Entry>();
            Assert.AreEqual(0, mongoCollections.Count());

            // see comments above
            mongoDatabase = _mongoServerConnection.GetDatabase(MONGO_DATABASE_2_NAME, _writeConcern);
            Assert.IsNotNull(mongoDatabase);
        }
        public void GetDatabaseNamesForConnectionTest()
        {
            List<string> databaseNames = _mongoServerConnection.GetDbNamesForConnection();
            Assert.AreEqual(0, databaseNames.Count, "There should be no mongo databases on the server");

            _writer.Write(MONGO_COLLECTION_1_NAME, new Entry());//create a db in the process of writing an entry to a child collection

            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_2_NAME);
            _mongoDatabaseConnection.Connect();
            _reader = new Reader(_mongoDatabaseConnection);
            _writer = new Writer(_mongoDatabaseConnection);// need to reinitialize writer when we change the DatabaseConnection

            _writer.Write(MONGO_COLLECTION_1_NAME, new Entry());//create a db in the process of writing an entry to a child collection

            databaseNames = _mongoServerConnection.GetDbNamesForConnection();
            Assert.AreEqual(2, databaseNames.Count, "There should be two mongo databases on the server");
            Assert.AreEqual(MONGO_DATABASE_1_NAME, databaseNames[0], MONGO_DATABASE_1_NAME + " is missing; was expected to be created");
            Assert.AreEqual(MONGO_DATABASE_2_NAME, databaseNames[1], MONGO_DATABASE_2_NAME + " is missing; was expected to be created");
        }
        public void TestMultiThreadedReadsAndWrites()
        {
            Mongo db = new Mongo();
            db.Connect();

            IMongoCollection col = db["tests"]["threadreadinserts"];

            List<string> identifiers = new List<string>{"A", "B", "C", "D"};
            List<string> colnames = new List<string>{"smallreads", "smallreads", "smallreads", "smallreads"};
            List<Thread> threads = new List<Thread>();
            List<Reader> readers = new List<Reader>();
            int writeiterations = 100;
            int readiterations = 50;
            foreach(string identifier in identifiers){
                Inserter ins = new Inserter {Iterations = writeiterations, Identifier = identifier, Collection = col};
                ThreadStart ts = new ThreadStart(ins.DoInserts);
                Thread thread = new Thread(ts);
                threads.Add(thread);
            }
            foreach(string colname in colnames){
                Reader r = new Reader{Iterations = readiterations, Collection = db["tests"][colname]};
                readers.Add(r);
                ThreadStart ts = new ThreadStart(r.DoReads);
                Thread thread = new Thread(ts);
                threads.Add(thread);
            }

            RunAndWait(threads);
            try{
                Assert.AreEqual(identifiers.Count * writeiterations, col.Count());
            }catch(Exception e){
                Assert.Fail(e.Message);
            }
            foreach(Reader r in readers){
                Assert.AreEqual(readiterations, r.Count, "A reader did not read everytime.");
            }
        }
        //[Test]
        public void TestMultiThreadedReads()
        {
            Mongo db = new Mongo();
            db.Connect();

            List<string> colnames = new List<string>{"smallreads", "smallreads", "smallreads", "smallreads"};
            List<Thread> threads = new List<Thread>();
            List<Reader> readers = new List<Reader>();
            int iterations = 50;
            foreach(string colname in colnames){
                Reader r = new Reader{Iterations = iterations, Collection = db["tests"][colname]};
                readers.Add(r);
                ThreadStart ts = new ThreadStart(r.DoReads);
                Thread thread = new Thread(ts);
                threads.Add(thread);
            }
            RunAndWait(threads);

            try{
                //Connection still alive?
                db["tests"]["smallreads"].Count();
            }catch(Exception e){
                Assert.Fail(e.Message);
            }
            foreach(Reader r in readers){
                Assert.AreEqual(iterations, r.Count, "A reader did not read everytime.");
            }
        }
        public async void Test()
        {
            _databaseConnection.Connect();

            /////////////////////////////////////
            // OPERATIONAL, CONTEXUAL SCOPE... //
            /////////////////////////////////////

            // create a Writer to write to the database
            IWriter writer = new Writer(_databaseConnection);
            // create a Reader to read from the database
            IReader reader = new Reader(_databaseConnection);
            // create an Updater to update the database
            IUpdater updater = new Updater(_databaseConnection);

            Entry exampleMongoDBEntry = new Entry();
            exampleMongoDBEntry.Message = "Hello";

            // write the object to the "MyFirstCollection" Collection that exists within the 
            // previously referenced "MyFirstDatabase" that was used to create the "writer" object
            writer.Write<Entry>("MyFirstCollection", exampleMongoDBEntry);

            IEnumerable<Entry> readEntrys = reader.Read<Entry>("MyFirstCollection", // within this collection...
                                                               "Message",// for the object field "Description"
                                                               "Hello");// return matches for 'Hello'
            Assert.AreEqual(1, readEntrys.Count());

            ////////////////////////////////////
            // AND ASYNCHRONOUS OPERATIONS... //
            ////////////////////////////////////

            // read, write and update asynchronously using System.Threading.Task
            IAsyncReader asyncReader = new AsyncReader(reader);
            readEntrys = await asyncReader.ReadAsync<Entry>("MyFirstCollection", "Message", "Hello");
            Assert.AreEqual(1, readEntrys.Count());

            IAsyncWriter asyncWriter = new AsyncWriter(writer);
            IAsyncUpdater asyncUpdater = new AsyncUpdater(updater);

            // or delegate call backs
            IAsyncDelegateReader asyncDelegateReader = new AsyncDelegateReader(reader);
            asyncDelegateReader.AsyncReadCompleted += new ReadCompletedEvent(readerCallBack);
            asyncDelegateReader.ReadAsync<Entry>("MyFirstCollection", "Message", "Hello");
            _readerAutoResetEvent.WaitOne();

            Assert.AreEqual(1, _asyncReadResults.Count());

            IAsyncDelegateWriter asyncDelegateWriter = new AsyncDelegateWriter(writer);
            IAsyncDelegateUpdater asyncDelegateUpdater = new AsyncDelegateUpdater(updater);

            /////////////////////////////////////////////
            // FOR A SERVER, DATABASE OR COLLECTION... //
            /////////////////////////////////////////////

            // get a little higher level with the EasyMongo.Database namespace to target a database for operations
            IDatabaseReader databaseReader = new DatabaseReader(reader, asyncReader);
            IDatabaseWriter databaseWriter = new DatabaseWriter(writer, asyncWriter);
            IDatabaseUpdater databaseUpdater = new DatabaseUpdater(updater, asyncUpdater);

            // or a little lower level with the EasyMongo.Collection namespace to target a specific Collection
            ICollectionReader collectionReader = new CollectionReader(databaseReader, "MyFirstCollection");
            ICollectionWriter collectionWriter = new CollectionWriter(databaseWriter, "MyFirstCollection");
            ICollectionUpdater collectionUpdater = new CollectionUpdater(databaseUpdater, "MyFirstCollection");

            ///////////////////////////////////////////////
            // TO RESTRICT CLIENT SCOPE (LAW OF DEMETER) //
            ///////////////////////////////////////////////

            // operate only against "MyFirstDatabase"'s "MySecondCollection"
            readEntrys = collectionReader.Read<Entry>("Message", "Hello");
            Assert.AreEqual(1, readEntrys.Count());

            /////////////////////
            // GENERIC CLASSES //
            /////////////////////

            // Instead of defining generic type arguments at the method level,
            // you can do it once at the class declaration
            IWriter<Entry> writerT = new Writer<Entry>(writer);
            writerT.Write("MySecondCollection", new Entry() { Message = "Goodbye World (Generically)" });

            ///////////////////////////////
            // SIMPLIFY CREATION VIA IoC //
            ///////////////////////////////

            // because EasyMongo is a componentized framework built with blocks of functionality, EasyMongo
            // works great with DI containers and Inversion of Control. 
            // here's an example of using the nuget Ninject extension to load EasyMongo mappings and a conn 
            // string from configuration
            Ninject.IKernel kernel = new Ninject.StandardKernel();
            ICollectionUpdater<Entry> collectionUpdaterT = kernel.TryGet<ICollectionUpdater<Entry>>();

            // the alternative to this would be:
            IServerConnection serverConn = new ServerConnection(LOCAL_MONGO_SERVER_CONNECTION_STRING);
            IDatabaseConnection databaseConnn = new DatabaseConnection(serverConn, "MyFirstDatabase");
            IDatabaseUpdater databaseUpdatr = new DatabaseUpdater(updater, asyncUpdater);
            ICollectionUpdater collectionUpdaterTheHardWay = new CollectionUpdater(databaseUpdater, "MySecondCollection");

            /////////////////////////
            // SIMPLE QUERIES...   //
            /////////////////////////

            databaseReader.Read<Entry>("MyFirstCollection", "Message", "Hello");
            readEntrys = await databaseReader.ReadAsync<Entry>("MyFirstCollection", "Message", "Hello");
            Assert.AreEqual(1, readEntrys.Count());

            /////////////////////////
            // POWERFUL QUERIES... //
            /////////////////////////

            // when more robust querying is needed leverage power of underlying MongoDB driver IMongoQuery
            IMongoQuery query1 = Query.Matches("Message", new BsonRegularExpression("HE", "i"));

            IEnumerable<Entry> queryResults = reader.Execute<Entry>("MyFirstCollection", query1);
            Assert.AreEqual(1, queryResults.Count());
            Assert.AreEqual("Hello", queryResults.ElementAt(0).Message);

            //////////////////////
            // AND COMBINATIONS //
            //////////////////////

            Entry exampleMongoDBEntry2 = new Entry();
            exampleMongoDBEntry2.Message = "Hello Again";

            Entry exampleMongoDBEntry3 = new Entry();
            exampleMongoDBEntry3.Message = "Goodbye";

            writer.Write<Entry>("MyFirstCollection", exampleMongoDBEntry2);
            writer.Write<Entry>("MyFirstCollection", exampleMongoDBEntry3);

            // "AND" multiple IMongoQueries...
            IMongoQuery query2 = Query.Matches("Message", new BsonRegularExpression("Again"));
            queryResults = reader.ExecuteAnds<Entry>("MyFirstCollection", new []{ query1, query2});
            Assert.AreEqual(1, queryResults.Count());
            Assert.AreEqual("Hello Again", queryResults.ElementAt(0).Message);

            // "OR" multiple IMongoQueries...
            IMongoQuery query3 = Query.Matches("Message", new BsonRegularExpression("Goo"));
            queryResults = reader.ExecuteOrs<Entry>("MyFirstCollection", new[] { query1, query2, query3 });
            Assert.AreEqual(3, queryResults.Count());
            Assert.AreEqual("Hello", queryResults.ElementAt(0).Message);
            Assert.AreEqual("Hello Again", queryResults.ElementAt(1).Message);
            Assert.AreEqual("Goodbye", queryResults.ElementAt(2).Message);         
        }
        public void AsynchronousTest6()
        {
            _mongoServerConnection = new ServerConnection(MONGO_CONNECTION_STRING_BAD);/**/
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);
            // testBase class receives the connection call back after the asynch connection occurs
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            // once the async operation completes, because the connection string is bad, there is no connection
            // -- attempting to use the connection results in a MongoConnectionException
            MongoCollection<Entry> collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
        }

        [Test]
        public void AsynchronousTest7()
        {
            //System.Diagnostics.Debugger.Launch();
            _mongoServerConnection = new ServerConnection(MONGO_CONNECTION_STRING);
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);
            // testBase class receives the connection call back after the asynch connection occurs
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            _databaseConnectionAutoResetEvent.WaitOne();

            MongoCollection<Entry> collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
            Assert.AreEqual(MongoServerState.Connected, _mongoDatabaseConnection.State);
            Assert.AreEqual(0, collection.Count());

            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            _databaseConnectionAutoResetEvent.WaitOne();

            collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
            Assert.AreEqual(MongoServerState.Connected, _mongoDatabaseConnection.State);
            Assert.AreEqual(0, collection.Count());
        }

        [Test]
        public void AsynchronousTest8()
        {
            //System.Diagnostics.Debugger.Launch();
            _mongoServerConnection = new ServerConnection(MONGO_CONNECTION_STRING);
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);
            // testBase class receives the connection call back after the asynch connection occurs
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            _databaseConnectionAutoResetEvent.WaitOne();

            MongoCollection<Entry> collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
            Assert.AreEqual(MongoServerState.Connected, _mongoDatabaseConnection.State);
            Assert.AreEqual(0, collection.Count());

            _mongoServerConnection.Connect();
            _mongoDatabaseConnection.Connect();

            collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
            Assert.AreEqual(MongoServerState.Connected, _mongoDatabaseConnection.State);
            Assert.AreEqual(0, collection.Count());

            _mongoServerConnection.Connect();
            _mongoDatabaseConnection.Connect();
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);
            _mongoServerConnection.Connect();
            _mongoDatabaseConnection.Connect();
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            _databaseConnectionAutoResetEvent.WaitOne();

            collection = _mongoDatabaseConnection.GetCollection<Entry>(MONGO_COLLECTION_1_NAME);
            Assert.AreEqual(MongoServerState.Connected, _mongoDatabaseConnection.State);
            Assert.AreEqual(0, collection.Count());
        }

        [Test]
        public void Asynchronous_DependentProcesses1()
        {
            //System.Diagnostics.Debugger.Launch();
            string entryMessage = "Hello World";
            AddMongoEntry(message: entryMessage);

            // create our asynchronous server connection
            _mongoServerConnection = new ServerConnection(MONGO_CONNECTION_STRING);
            _mongoDatabaseConnection = new DatabaseConnection(_mongoServerConnection, MONGO_DATABASE_1_NAME);

            //_asyncReader = new Reader(_mongoDatabaseConnection);
            //_asyncDelegateReader = new AsyncDelegateReader(_asyncReader);
            //_asyncDelegateReader.AsyncReadCompleted += new ReadCompletedEvent(_readerAsync_AsyncReadCompleted);

            // testBase class receives the connection call back after the asynch connection occurs
            _mongoServerConnection.ConnectAsyncDelegate(_mongoServerConnection_Connected);
            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);

            // this call doesn't wait for asynchronous connection to complete
            _asyncDelegateReader.ReadAsync<Entry>(MONGO_COLLECTION_1_NAME, "Message", entryMessage);

            _readerAutoResetEvent.WaitOne();// wait for async read to return
            Assert.AreEqual(1, _asyncReadResults.Count());
            Assert.AreEqual(entryMessage, _asyncReadResults[0].Message);
        }

        // no thread wait for asynchronous call to complete
        [Test]
        public void Asynchronous_GetInsertedTest1()
        {
            string entryMessage = "Hello World";
            AddMongoEntry(message: entryMessage);

            _mongoDatabaseConnection.ConnectAsyncDelegate(_mongoDatabaseConnection_Connected);// asynchronous connection

            _databaseConnectionAutoResetEvent.WaitOne(); // pause here until the asyncConnection completes to allow for linear testability

            Assert.AreEqual(_databaseConnectionResult, ConnectionResult.Success);/**/
            Assert.AreEqual(_mongoDatabaseConnection.State, MongoServerState.Connected);
            Assert.IsNotNull(_serverConnectionReturnMessage);
            Assert.IsNotNull(_databaseConnectionReturnMessage);
            _reader = new Reader(_mongoDatabaseConnection);

            // this call doesn't wait for asynchronous connection to finish
               _results.AddRange(_reader.Read<Entry>(MONGO_COLLECTION_1_NAME, "Message", entryMessage, "TimeStamp", _beforeTest, DateTime.Now));
               Assert.AreEqual(1, _results.Count());
        }