diff options
author | Ted Tuckman <ted.tuckman@mongodb.com> | 2017-07-18 13:33:10 -0400 |
---|---|---|
committer | Ted Tuckman <ted.tuckman@mongodb.com> | 2017-07-20 12:59:09 -0400 |
commit | bfc52fd48fa6fe36761ca2b2bd791ed906b56358 (patch) | |
tree | c5ae5f713d8955b9f2aa26f9496e500bd3555079 | |
parent | 15b82339a87298147fc60b83ba7b3b61bfbb9c5b (diff) | |
download | mongo-bfc52fd48fa6fe36761ca2b2bd791ed906b56358.tar.gz |
SERVER-29981 write transport layer to connect c driver to embedded capi
-rw-r--r-- | SConstruct | 7 | ||||
-rw-r--r-- | src/mongo/client/embedded/SConscript | 36 | ||||
-rw-r--r-- | src/mongo/client/embedded/common-operations.cpp | 247 | ||||
-rw-r--r-- | src/mongo/client/embedded/common-operations.h | 45 | ||||
-rw-r--r-- | src/mongo/client/embedded/embedded_transport_layer.cpp | 208 | ||||
-rw-r--r-- | src/mongo/client/embedded/embedded_transport_layer.h | 40 | ||||
-rw-r--r-- | src/mongo/client/embedded/embedded_transport_layer_test.cpp | 164 |
7 files changed, 747 insertions, 0 deletions
diff --git a/SConstruct b/SConstruct index 1781d5067c2..c56ce5edf87 100644 --- a/SConstruct +++ b/SConstruct @@ -2989,6 +2989,13 @@ def doConfigure(myenv): if conf.CheckExtendedAlignment(size): conf.env.SetConfigHeaderDefine("MONGO_CONFIG_MAX_EXTENDED_ALIGNMENT", size) break + + conf.env['MONGO_HAVE_LIBMONGOC'] = conf.CheckLibWithHeader( + ["mongoc-1.0"], + ["mongoc.h"], + "C", + "mongoc_get_major_version();", + autoadd=False ) # ask each module to configure itself and the build environment. moduleconfig.configure_modules(mongo_modules, conf) diff --git a/src/mongo/client/embedded/SConscript b/src/mongo/client/embedded/SConscript index 5cd9358eb5c..6e9a756957c 100644 --- a/src/mongo/client/embedded/SConscript +++ b/src/mongo/client/embedded/SConscript @@ -33,3 +33,39 @@ capiTest = env.Program( ) env.RegisterUnitTest(capiTest[0]) +env.Alias('embedded_capi', capiTest) + +if not env['MONGO_HAVE_LIBMONGOC']: + Return() + +embeddedTransport = env.Library( + target='mongo_embedded_transport', + source=[ + 'embedded_transport_layer.cpp', + ], + LIBDEPS=[ + 'mongo_embedded_capi', + ], + SYSLIBDEPS=[ + 'mongoc-1.0', + 'bson-1.0', + ] +) + +env.Alias('embedded_capi', embeddedTransport) + +embeddedTransportTest = env.Program( + target='mongo_embedded_transport_test', + source=[ + 'embedded_transport_layer_test.cpp', + 'common-operations.cpp', + ], + LIBDEPS=[ + 'mongo_embedded_transport', + '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/unittest/unittest', + ] +) + +env.Alias('embedded_capi', embeddedTransportTest) +env.RegisterUnitTest(embeddedTransportTest[0]); diff --git a/src/mongo/client/embedded/common-operations.cpp b/src/mongo/client/embedded/common-operations.cpp new file mode 100644 index 00000000000..493c334de62 --- /dev/null +++ b/src/mongo/client/embedded/common-operations.cpp @@ -0,0 +1,247 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage + +#include "mongo/client/embedded/common-operations.h" + +#include <mongoc.h> +#include <stdio.h> + +#include "mongo/client/embedded/embedded_transport_layer.h" +#include "mongo/util/log.h" + +/** + * WARNING: This function is an example lifted directly from the C driver + * for use testing the connection to the c driver. It is written in C, + * and should not be used for anything besides basic testing. + */ +bool mongo::embeddedTest::insert_data(mongoc_collection_t* collection) { + mongoc_bulk_operation_t* bulk; + enum N { ndocs = 4 }; + bson_t* docs[ndocs]; + bson_error_t error; + int i = 0; + bool ret; + + bulk = mongoc_collection_create_bulk_operation(collection, true, NULL); + + docs[0] = BCON_NEW("x", BCON_DOUBLE(1.0), "tags", "[", "dog", "cat", "]"); + docs[1] = BCON_NEW("x", BCON_DOUBLE(2.0), "tags", "[", "cat", "]"); + docs[2] = BCON_NEW("x", BCON_DOUBLE(2.0), "tags", "[", "mouse", "cat", "dog", "]"); + docs[3] = BCON_NEW("x", BCON_DOUBLE(3.0), "tags", "[", "]"); + + for (i = 0; i < ndocs; i++) { + mongoc_bulk_operation_insert(bulk, docs[i]); + bson_destroy(docs[i]); + docs[i] = NULL; + } + + ret = mongoc_bulk_operation_execute(bulk, NULL, &error); + + if (!ret) { + log() << "Error inserting data: " << error.message; + } + + mongoc_bulk_operation_destroy(bulk); + return ret; +} + +/** + * WARNING: This function is an example lifted directly from the C driver + * for use testing the connection to the c driver. It is written in C, + * and should not be used for anything besides basic testing. + */ +bool copydb(mongoc_client_t* client, const char* other_host_and_port) { + mongoc_database_t* admindb; + bson_t* command; + bson_t reply; + bson_error_t error; + bool res; + + BSON_ASSERT(other_host_and_port); + /* Must do this from the admin db */ + admindb = mongoc_client_get_database(client, "admin"); + + command = BCON_NEW("copydb", + BCON_INT32(1), + "fromdb", + BCON_UTF8("test"), + "todb", + BCON_UTF8("test2"), + + /* If you want from a different host */ + "fromhost", + BCON_UTF8(other_host_and_port)); + res = mongoc_database_command_simple(admindb, command, NULL, &reply, &error); + if (!res) { + mongo::log() << "Error with copydb: " << error.message; + goto copy_cleanup; + } + + +copy_cleanup: + bson_destroy(&reply); + bson_destroy(command); + mongoc_database_destroy(admindb); + + return res; +} +/** + * WARNING: This function is an example lifted directly from the C driver + * for use testing the connection to the c driver. It is written in C, + * and should not be used for anything besides basic testing. + */ +bool clone_collection(mongoc_database_t* database, const char* other_host_and_port) { + bson_t* command; + bson_t reply; + bson_error_t error; + bool res; + + BSON_ASSERT(other_host_and_port); + command = BCON_NEW("cloneCollection", + BCON_UTF8("test.remoteThings"), + "from", + BCON_UTF8(other_host_and_port), + "query", + "{", + "x", + BCON_INT32(1), + "}"); + res = mongoc_database_command_simple(database, command, NULL, &reply, &error); + if (!res) { + mongo::log() << "Error with clone: " << error.message; + goto clone_cleanup; + } + + +clone_cleanup: + bson_destroy(&reply); + bson_destroy(command); + + return res; +} +/** + * WARNING: This function is an example lifted directly from the C driver + * for use testing the connection to the c driver. It is written in C, + * and should not be used for anything besides basic testing. + */ +bool mongo::embeddedTest::explain(mongoc_collection_t* collection) { + + bson_t* command; + bson_t reply; + bson_error_t error; + bool res; + + command = BCON_NEW("explain", + "{", + "find", + BCON_UTF8((const char*)"things"), + "filter", + "{", + "x", + BCON_INT32(1), + "}", + "}"); + res = mongoc_collection_command_simple(collection, command, NULL, &reply, &error); + if (!res) { + log() << "Error with explain: " << error.message; + goto explain_cleanup; + } + + +explain_cleanup: + bson_destroy(&reply); + bson_destroy(command); + return res; +} +/** + * WARNING: This function is an example lifted directly from the C driver + * for use testing the connection to the c driver. It is written in C, + * and should not be used for anything besides basic testing. + */ +int mongo::embeddedTest::run_c_driver_all() { + mongoc_database_t* database = NULL; + mongoc_client_t* client = NULL; + mongoc_collection_t* collection = NULL; + char* host_and_port = NULL; + int res = 0; + char* other_host_and_port = NULL; + + + client = mongoc_client_new(NULL); + + if (!client) { + log() << " Invalid client "; + res = 2; + goto cleanup; + } + + mongoc_client_set_error_api(client, 2); + database = mongoc_client_get_database(client, "test"); + collection = mongoc_database_get_collection(database, (const char*)"things"); + + if (!mongo::embeddedTest::insert_data(collection)) { + res = 3; + goto cleanup; + } + + if (!mongo::embeddedTest::explain(collection)) { + res = 4; + goto cleanup; + } + + if (other_host_and_port) { + if (!copydb(client, other_host_and_port)) { + res = 5; + goto cleanup; + } + + if (!clone_collection(database, other_host_and_port)) { + res = 6; + goto cleanup; + } + } + +cleanup: + if (collection) { + mongoc_collection_destroy(collection); + } + + if (database) { + mongoc_database_destroy(database); + } + + if (client) { + mongoc_client_destroy(client); + } + + bson_free(host_and_port); + mongoc_cleanup(); + return res; +} diff --git a/src/mongo/client/embedded/common-operations.h b/src/mongo/client/embedded/common-operations.h new file mode 100644 index 00000000000..b5f91eb1d23 --- /dev/null +++ b/src/mongo/client/embedded/common-operations.h @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#pragma once + +#include <mongoc.h> + +namespace mongo { + +namespace embeddedTest { + +bool explain(mongoc_collection_t* collection); + +bool insert_data(mongoc_collection_t* collection); + +int run_c_driver_all(); + +} // namespace embeddedTest + +} // namespace mongo diff --git a/src/mongo/client/embedded/embedded_transport_layer.cpp b/src/mongo/client/embedded/embedded_transport_layer.cpp new file mode 100644 index 00000000000..7981bdeeeed --- /dev/null +++ b/src/mongo/client/embedded/embedded_transport_layer.cpp @@ -0,0 +1,208 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/client/embedded/embedded_transport_layer.h" + +#include <cstdlib> +#include <deque> +#include <iostream> +#include <iterator> +#include <string> + +#include "mongo/base/data_range.h" +#include "mongo/base/data_range_cursor.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/shared_buffer.h" +enum RPCState { WaitingForMessageLength, WaitingForMessageContent, HaveOutput }; +struct mongoc_stream_embedded_t : mongoc_stream_t { + libmongodbcapi_client* clientHandle; + mongo::DataRangeCursor inputBuf = mongo::DataRangeCursor(nullptr, nullptr); + char* hiddenBuf = nullptr; + mongo::ConstDataRangeCursor outputBuf = mongo::ConstDataRangeCursor(nullptr, nullptr); + + void* libmongo_output; + size_t libmongo_output_size; + // If this is 0, we have recieved a full message and expect another header + u_long input_length_to_go; + RPCState state; +}; + +ssize_t _mongoc_stream_embedded_writev(mongoc_stream_t* s, + mongoc_iovec_t* iov, + size_t iovcnt, + int32_t timeout_msec) { + auto stream = static_cast<mongoc_stream_embedded_t*>(s); + invariant(stream->state == RPCState::WaitingForMessageContent || + stream->state == RPCState::WaitingForMessageLength); + + u_long already_read = 0; + for (size_t i = 0; i < iovcnt; i++) { + char* current_loc = static_cast<char*>(iov[i].iov_base); + u_long remaining_iov = iov[i].iov_len; + + // @TODO for now just not handling vecs of this size + invariant(remaining_iov >= 4); + + // do we need a new message? + if (stream->state == RPCState::WaitingForMessageLength) { + // message length is the first four bytes + // Should use dataview from mongo server + stream->input_length_to_go = + mongo::ConstDataView(current_loc).read<mongo::LittleEndian<int32_t>>(); + stream->hiddenBuf = (char*)malloc(stream->input_length_to_go); + stream->inputBuf = mongo::DataRangeCursor( + stream->hiddenBuf, stream->hiddenBuf + stream->input_length_to_go); + auto writeOK = + stream->inputBuf.writeAndAdvance(mongo::DataRange(current_loc, current_loc + 4)); + invariant(writeOK.isOK()); + current_loc += 4; + remaining_iov -= 4; + stream->input_length_to_go -= 4; + already_read += 4; + stream->state = RPCState::WaitingForMessageContent; + } + + // if there is no more message after reading length, we're done + if (remaining_iov <= 0) + continue; + + // copy message length into buffer + // pipelining is not allowed, so remaining_iov must be less than input_length_to_go + invariant(stream->input_length_to_go >= remaining_iov); + auto writeOK = stream->inputBuf.writeAndAdvance( + mongo::DataRange(current_loc, current_loc + remaining_iov)); + invariant(writeOK.isOK()); + // cleanup number values to reflect the copy + stream->input_length_to_go -= remaining_iov; + already_read += remaining_iov; + remaining_iov = 0; + + // if we found a complete message, send it + if (stream->input_length_to_go == 0) { + auto input_len = (size_t)(stream->inputBuf.data() - stream->hiddenBuf); + int retVal = + libmongodbcapi_db_client_wire_protocol_rpc(stream->clientHandle, + stream->hiddenBuf, + input_len, + &(stream->libmongo_output), + &(stream->libmongo_output_size)); + if (retVal != LIBMONGODB_CAPI_ERROR_SUCCESS) { + return -1; + } + + // We will allocate a new one when we read in the next message length + free(stream->hiddenBuf); + + // and then write the output to our output buffer + auto start = (char*)(stream->libmongo_output); + auto end = ((char*)(stream->libmongo_output)) + stream->libmongo_output_size; + stream->outputBuf = mongo::ConstDataRangeCursor(start, end); + stream->state = RPCState::HaveOutput; + } + } + + return already_read; +} + +ssize_t _mongoc_stream_embedded_readv(mongoc_stream_t* s, + mongoc_iovec_t* iov, + size_t iovcnt, + size_t min_bytes, + int32_t timeout_msec) { + size_t bytes_read = 0; + auto stream = static_cast<mongoc_stream_embedded_t*>(s); + invariant(stream->state == RPCState::HaveOutput); + for (size_t i = 0; i < iovcnt && stream->outputBuf.length() > 0; i++) { + + // for each vector, fill the vector if we are able + size_t bytes_to_copy = std::min(iov[i].iov_len, stream->outputBuf.length()); + memcpy(iov[i].iov_base, stream->outputBuf.data(), bytes_to_copy); + auto x = stream->outputBuf.advance(bytes_to_copy); + invariant(x.isOK()); + bytes_read += bytes_to_copy; + } + stream->state = + stream->outputBuf.length() == 0 ? RPCState::WaitingForMessageLength : RPCState::HaveOutput; + return bytes_read; +} + +void _mongoc_stream_embedded_destroy(mongoc_stream_t* s) { + + auto stream = static_cast<mongoc_stream_embedded_t*>(s); + libmongodbcapi_db_client_destroy(stream->clientHandle); + stream->~mongoc_stream_embedded_t(); +} + +int _mongoc_stream_embedded_close(mongoc_stream_t* s) { + return 0; +} + +ssize_t _mongoc_stream_embedded_poll(mongoc_stream_poll_t* s, + size_t array_length, + int32_t timeout_msec) { + for (size_t i = 0; i < array_length; i++) { + s[i].revents = s[i].events & (POLLIN | POLLOUT); + } + return array_length; +} + +mongoc_stream_t* embedded_stream_initiator(const mongoc_uri_t* uri, + const mongoc_host_list_t* host, + void* user_data, + bson_error_t* error) { + mongoc_stream_embedded_t* stream = + static_cast<mongoc_stream_embedded_t*>(bson_malloc0(sizeof(*stream))); + if (!stream) + return NULL; + + // Create the stream + stream = new (stream) mongoc_stream_embedded_t(); + stream->state = RPCState::WaitingForMessageLength; + // Set up connections to database + stream->clientHandle = libmongodbcapi_db_client_new((libmongodbcapi_db*)user_data); + + // Connect the functions to the stream + // type is not relevant for us. Has to be set for the C Driver, but it has to do with picking + // how to communicate over the networ + stream->type = 1000; + stream->poll = _mongoc_stream_embedded_poll; + stream->close = _mongoc_stream_embedded_close; + stream->readv = _mongoc_stream_embedded_readv; + stream->writev = _mongoc_stream_embedded_writev; + stream->destroy = _mongoc_stream_embedded_destroy; + + return stream; +} +mongoc_client_t* embedded_mongoc_client_new(libmongodbcapi_db* db) { + if (!db) { + return nullptr; + } + auto client = mongoc_client_new(NULL); + mongoc_client_set_stream_initiator(client, embedded_stream_initiator, db); + return client; +} diff --git a/src/mongo/client/embedded/embedded_transport_layer.h b/src/mongo/client/embedded/embedded_transport_layer.h new file mode 100644 index 00000000000..683b0e967ae --- /dev/null +++ b/src/mongo/client/embedded/embedded_transport_layer.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include <bson.h> +#include <mongoc.h> + +#include "mongo/client/embedded/libmongodbcapi.h" +struct mongoc_stream_embedded_t; +struct dbObj; + +/* Creates a client with the correct stream intiator set + * @param db must be a valid db handle created by libmongodbcapi + * @return a mongoc client or null on error + */ +mongoc_client_t* embedded_mongoc_client_new(libmongodbcapi_db* db); diff --git a/src/mongo/client/embedded/embedded_transport_layer_test.cpp b/src/mongo/client/embedded/embedded_transport_layer_test.cpp new file mode 100644 index 00000000000..b082eb75d1b --- /dev/null +++ b/src/mongo/client/embedded/embedded_transport_layer_test.cpp @@ -0,0 +1,164 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + + +#include "mongo/client/embedded/embedded_transport_layer.h" +#include "mongo/client/embedded/common-operations.h" +#include "mongo/client/embedded/libmongodbcapi.h" +#include <mongoc.h> +#include <set> + +#include "mongo/stdx/memory.h" +#include "mongo/unittest/temp_dir.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/quick_exit.h" +#include "mongo/util/signal_handlers_synchronous.h" +namespace { + +std::unique_ptr<mongo::unittest::TempDir> globalTempDir; + +class MongodbEmbeddedTransportLayerTest : public mongo::unittest::Test { +protected: + void setUp() { + if (!globalTempDir) { + globalTempDir = mongo::stdx::make_unique<mongo::unittest::TempDir>("embedded_mongo"); + } + int argc = 4; + const char* argv[] = {"mongo_embedded_transport_layer_test", + "--nounixsocket", + "--dbpath", + globalTempDir->path().c_str()}; + db_handle = libmongodbcapi_db_new(argc, argv, nullptr); + + mongoc_init(); + cd_client = embedded_mongoc_client_new(db_handle); + mongoc_client_set_error_api(cd_client, 2); + cd_db = mongoc_client_get_database(cd_client, "test"); + cd_collection = mongoc_database_get_collection(cd_db, (const char*)"things"); + } + + void tearDown() { + mongoc_collection_drop(cd_collection, NULL); + if (cd_collection) { + mongoc_collection_destroy(cd_collection); + } + + if (cd_db) { + mongoc_database_destroy(cd_db); + } + + if (cd_client) { + mongoc_client_destroy(cd_client); + } + mongoc_cleanup(); + libmongodbcapi_db_destroy(db_handle); + } + + libmongodbcapi_db* getDBHandle() { + return db_handle; + } + + mongoc_database_t* getDB() { + return cd_db; + } + mongoc_client_t* getClient() { + return cd_client; + } + mongoc_collection_t* getCollection() { + return cd_collection; + } + + +private: + libmongodbcapi_db* db_handle; + mongoc_database_t* cd_db; + mongoc_client_t* cd_client; + mongoc_collection_t* cd_collection; +}; + +TEST_F(MongodbEmbeddedTransportLayerTest, CreateAndDestroyDB) { + // Test the setUp() and tearDown() test fixtures +} +TEST_F(MongodbEmbeddedTransportLayerTest, InsertAndExplain) { + auto client = getClient(); + auto collection = getCollection(); + ASSERT(client); + + + ASSERT(mongo::embeddedTest::insert_data(collection)); + + ASSERT(mongo::embeddedTest::explain(collection)); +} +TEST_F(MongodbEmbeddedTransportLayerTest, InsertAndCount) { + auto client = getClient(); + auto collection = getCollection(); + ASSERT(client); + ASSERT(collection); + bson_error_t err; + int64_t count; + ASSERT(mongo::embeddedTest::insert_data(collection)); + count = mongoc_collection_count(collection, MONGOC_QUERY_NONE, nullptr, 0, 0, NULL, &err); + ASSERT(count == 4); +} +TEST_F(MongodbEmbeddedTransportLayerTest, InsertAndDelete) { + auto client = getClient(); + auto collection = getCollection(); + ASSERT(client); + ASSERT(collection); + bson_error_t err; + bson_oid_t oid; + int64_t count; + // done with setup + + auto doc = bson_new(); + bson_oid_init(&oid, NULL); + BSON_APPEND_OID(doc, "_id", &oid); + BSON_APPEND_UTF8(doc, "hello", "world"); + ASSERT(mongoc_collection_insert(collection, MONGOC_INSERT_NONE, doc, NULL, &err)); + count = mongoc_collection_count(collection, MONGOC_QUERY_NONE, nullptr, 0, 0, NULL, &err); + ASSERT(1 == count); + bson_destroy(doc); + doc = bson_new(); + BSON_APPEND_OID(doc, "_id", &oid); + ASSERT(mongoc_collection_remove(collection, MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &err)); + ASSERT(0 == mongoc_collection_count(collection, MONGOC_QUERY_NONE, nullptr, 0, 0, NULL, &err)); + bson_destroy(doc); +} +} // namespace + +// Define main function as an entry to these tests. +// These test functions cannot use the main() defined for unittests because they +// call runGlobalInitializers(). The embedded C API calls mongoDbMain() which +// calls runGlobalInitializers(). +int main(int argc, char** argv, char** envp) { + ::mongo::clearSignalMask(); + ::mongo::setupSynchronousSignalHandlers(); + auto result = ::mongo::unittest::Suite::run(std::vector<std::string>(), "", 1); + globalTempDir.reset(); + mongo::quickExit(result); +} |