summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2017-07-18 13:33:10 -0400
committerTed Tuckman <ted.tuckman@mongodb.com>2017-07-20 12:59:09 -0400
commitbfc52fd48fa6fe36761ca2b2bd791ed906b56358 (patch)
treec5ae5f713d8955b9f2aa26f9496e500bd3555079
parent15b82339a87298147fc60b83ba7b3b61bfbb9c5b (diff)
downloadmongo-bfc52fd48fa6fe36761ca2b2bd791ed906b56358.tar.gz
SERVER-29981 write transport layer to connect c driver to embedded capi
-rw-r--r--SConstruct7
-rw-r--r--src/mongo/client/embedded/SConscript36
-rw-r--r--src/mongo/client/embedded/common-operations.cpp247
-rw-r--r--src/mongo/client/embedded/common-operations.h45
-rw-r--r--src/mongo/client/embedded/embedded_transport_layer.cpp208
-rw-r--r--src/mongo/client/embedded/embedded_transport_layer.h40
-rw-r--r--src/mongo/client/embedded/embedded_transport_layer_test.cpp164
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);
+}