diff --git a/include/envoy/mongo/bson.h b/include/envoy/mongo/bson.h index 71d5254056582..0bc003edb1332 100644 --- a/include/envoy/mongo/bson.h +++ b/include/envoy/mongo/bson.h @@ -25,6 +25,7 @@ class Field { STRING = 0x02, DOCUMENT = 0x03, ARRAY = 0x04, + BINARY = 0x05, OBJECT_ID = 0x07, BOOLEAN = 0x08, DATETIME = 0x09, @@ -58,6 +59,7 @@ class Field { virtual const std::string& asString() const PURE; virtual const Document& asDocument() const PURE; virtual const Document& asArray() const PURE; + virtual const std::string& asBinary() const PURE; virtual const ObjectId& asObjectId() const PURE; virtual bool asBoolean() const PURE; virtual int64_t asDatetime() const PURE; @@ -87,6 +89,7 @@ class Document { virtual DocumentPtr addString(const std::string& key, std::string&& value) PURE; virtual DocumentPtr addDocument(const std::string& key, DocumentPtr value) PURE; virtual DocumentPtr addArray(const std::string& key, DocumentPtr value) PURE; + virtual DocumentPtr addBinary(const std::string& key, std::string&& value) PURE; virtual DocumentPtr addObjectId(const std::string& key, Field::ObjectId&& value) PURE; virtual DocumentPtr addBoolean(const std::string& key, bool value) PURE; virtual DocumentPtr addDatetime(const std::string& key, int64_t value) PURE; diff --git a/source/common/mongo/bson_impl.cc b/source/common/mongo/bson_impl.cc index 912fb2cd2b38a..07f65aca6a4aa 100644 --- a/source/common/mongo/bson_impl.cc +++ b/source/common/mongo/bson_impl.cc @@ -88,6 +88,16 @@ std::string BufferHelper::removeString(Buffer::Instance& data) { return ret; } +std::string BufferHelper::removeBinary(Buffer::Instance& data) { + // Read out the subtype but do not store it for now. + int32_t length = removeInt32(data); + removeByte(data); + char* start = reinterpret_cast(data.linearize(length)); + std::string ret(start, length); + data.drain(length); + return ret; +} + void BufferHelper::writeCString(Buffer::Instance& data, const std::string& value) { data.add(value.c_str(), value.size() + 1); } @@ -113,6 +123,14 @@ void BufferHelper::writeString(Buffer::Instance& data, const std::string& value) data.add(value.c_str(), value.size() + 1); } +void BufferHelper::writeBinary(Buffer::Instance& data, const std::string& value) { + // Right now we do not actually store the binary subtype and always use zero. + writeInt32(data, value.size()); + uint8_t subtype = 0; + data.add(&subtype, sizeof(subtype)); + data.add(value.c_str(), value.size()); +} + int32_t FieldImpl::byteSize() const { // 1 byte type, cstring key, field. int32_t total = 1 + key_.size() + 1; @@ -134,6 +152,10 @@ int32_t FieldImpl::byteSize() const { return total + value_.document_value_->byteSize(); } + case Type::BINARY: { + return total + 5 + value_.string_value_.size(); + } + case Type::OBJECT_ID: { return total + sizeof(ObjectId); } @@ -176,6 +198,10 @@ void FieldImpl::encode(Buffer::Instance& output) const { return value_.document_value_->encode(output); } + case Type::BINARY: { + return BufferHelper::writeBinary(output, value_.string_value_); + } + case Type::OBJECT_ID: { return output.add(&value_.object_id_value_[0], value_.object_id_value_.size()); } @@ -229,6 +255,10 @@ bool FieldImpl::operator==(const Field& rhs) const { return asArray() == rhs.asArray(); } + case Type::BINARY: { + return asBinary() == rhs.asBinary(); + } + case Type::OBJECT_ID: { return asObjectId() == rhs.asObjectId(); } @@ -271,7 +301,8 @@ std::string FieldImpl::toString() const { return std::to_string(value_.double_value_); } - case Type::STRING: { + case Type::STRING: + case Type::BINARY: { return fmt::format("'{}'", value_.string_value_); } @@ -361,6 +392,13 @@ void DocumentImpl::fromBuffer(Buffer::Instance& data) { break; } + case Field::Type::BINARY: { + std::string value = BufferHelper::removeBinary(data); + log_trace("BSON binary: {}", value); + addBinary(key, std::move(value)); + break; + } + case Field::Type::OBJECT_ID: { Field::ObjectId value; BufferHelper::removeBytes(data, &value[0], value.size()); diff --git a/source/common/mongo/bson_impl.h b/source/common/mongo/bson_impl.h index de28f2b3a6edb..3e6cf9dd1981c 100644 --- a/source/common/mongo/bson_impl.h +++ b/source/common/mongo/bson_impl.h @@ -21,11 +21,13 @@ class BufferHelper { static int32_t removeInt32(Buffer::Instance& data); static int64_t removeInt64(Buffer::Instance& data); static std::string removeString(Buffer::Instance& data); + static std::string removeBinary(Buffer::Instance& data); static void writeCString(Buffer::Instance& data, const std::string& value); static void writeInt32(Buffer::Instance& data, int32_t value); static void writeInt64(Buffer::Instance& data, int64_t value); static void writeDouble(Buffer::Instance& data, double value); static void writeString(Buffer::Instance& data, const std::string& value); + static void writeBinary(Buffer::Instance& data, const std::string& value); }; class FieldImpl : public Field { @@ -34,7 +36,8 @@ class FieldImpl : public Field { value_.double_value_ = value; } - explicit FieldImpl(const std::string& key, std::string&& value) : type_(Type::STRING), key_(key) { + explicit FieldImpl(Type type, const std::string& key, std::string&& value) + : type_(type), key_(key) { value_.string_value_ = std::move(value); } @@ -86,6 +89,11 @@ class FieldImpl : public Field { return *value_.document_value_; } + const std::string& asBinary() const override { + checkType(Type::BINARY); + return value_.string_value_; + } + const ObjectId& asObjectId() const override { checkType(Type::OBJECT_ID); return value_.object_id_value_; @@ -173,7 +181,7 @@ class DocumentImpl : public Document, } DocumentPtr addString(const std::string& key, std::string&& value) override { - fields_.emplace_back(new FieldImpl(key, std::move(value))); + fields_.emplace_back(new FieldImpl(Field::Type::STRING, key, std::move(value))); return shared_from_this(); } @@ -187,6 +195,11 @@ class DocumentImpl : public Document, return shared_from_this(); } + DocumentPtr addBinary(const std::string& key, std::string&& value) override { + fields_.emplace_back(new FieldImpl(Field::Type::BINARY, key, std::move(value))); + return shared_from_this(); + } + DocumentPtr addObjectId(const std::string& key, Field::ObjectId&& value) override { fields_.emplace_back(new FieldImpl(key, std::move(value))); return shared_from_this(); diff --git a/source/common/mongo/proxy.cc b/source/common/mongo/proxy.cc index daefc2f6b7977..d2454dbf34b1d 100644 --- a/source/common/mongo/proxy.cc +++ b/source/common/mongo/proxy.cc @@ -83,43 +83,43 @@ void ProxyFilter::decodeQuery(QueryMessagePtr&& message) { stats_.op_query_exhaust_.inc(); } - std::string command = MessageUtility::queryCommand(*message); - if (!command.empty()) { + ActiveQueryPtr active_query(new ActiveQuery(*this, *message)); + if (!active_query->query_info_.command().empty()) { // First field key is the operation. - stat_store_.counter(fmt::format("{}cmd.{}.total", stat_prefix_, command)).inc(); + stat_store_.counter(fmt::format("{}cmd.{}.total", stat_prefix_, + active_query->query_info_.command())).inc(); } else { // Normal query, get stats on a per collection basis first. - std::string collection = - MessageUtility::collectionFromFullCollectionName(message->fullCollectionName()); - std::string collection_stat_prefix = fmt::format("{}collection.{}", stat_prefix_, collection); - MessageUtility::QueryType query_type = MessageUtility::queryType(*message); + std::string collection_stat_prefix = + fmt::format("{}collection.{}", stat_prefix_, active_query->query_info_.collection()); + QueryMessageInfo::QueryType query_type = active_query->query_info_.type(); chargeQueryStats(collection_stat_prefix, query_type); // Callsite stats if we have it. - std::string callsite = MessageUtility::queryCallingFunction(*message); - if (!callsite.empty()) { + if (!active_query->query_info_.callsite().empty()) { std::string callsite_stat_prefix = - fmt::format("{}collection.{}.callsite.{}", stat_prefix_, collection, callsite); + fmt::format("{}collection.{}.callsite.{}", stat_prefix_, + active_query->query_info_.collection(), active_query->query_info_.callsite()); chargeQueryStats(callsite_stat_prefix, query_type); } // Global stats. - if (query_type == MessageUtility::QueryType::ScatterGet) { + if (query_type == QueryMessageInfo::QueryType::ScatterGet) { stats_.op_query_scatter_get_.inc(); - } else if (query_type == MessageUtility::QueryType::MultiGet) { + } else if (query_type == QueryMessageInfo::QueryType::MultiGet) { stats_.op_query_multi_get_.inc(); } } - active_query_list_.emplace_back(new ActiveQuery(*this, std::move(message))); + active_query_list_.emplace_back(std::move(active_query)); } void ProxyFilter::chargeQueryStats(const std::string& prefix, - MessageUtility::QueryType query_type) { + QueryMessageInfo::QueryType query_type) { stat_store_.counter(fmt::format("{}.query.total", prefix)).inc(); - if (query_type == MessageUtility::QueryType::ScatterGet) { + if (query_type == QueryMessageInfo::QueryType::ScatterGet) { stat_store_.counter(fmt::format("{}.query.scatter_get", prefix)).inc(); - } else if (query_type == MessageUtility::QueryType::MultiGet) { + } else if (query_type == QueryMessageInfo::QueryType::MultiGet) { stat_store_.counter(fmt::format("{}.query.multi_get", prefix)).inc(); } } @@ -141,26 +141,25 @@ void ProxyFilter::decodeReply(ReplyMessagePtr&& message) { for (auto i = active_query_list_.begin(); i != active_query_list_.end(); i++) { ActiveQuery& active_query = **i; - if (active_query.query_->requestId() != message->responseTo()) { + if (active_query.query_info_.requestId() != message->responseTo()) { continue; } - std::string command = MessageUtility::queryCommand(*active_query.query_); - if (!command.empty()) { - std::string stat_prefix = fmt::format("{}cmd.{}", stat_prefix_, command); + if (!active_query.query_info_.command().empty()) { + std::string stat_prefix = + fmt::format("{}cmd.{}", stat_prefix_, active_query.query_info_.command()); chargeReplyStats(active_query, stat_prefix, *message); } else { // Collection stats first. - std::string collection = MessageUtility::collectionFromFullCollectionName( - active_query.query_->fullCollectionName()); - std::string stat_prefix = fmt::format("{}collection.{}.query", stat_prefix_, collection); + std::string stat_prefix = + fmt::format("{}collection.{}.query", stat_prefix_, active_query.query_info_.collection()); chargeReplyStats(active_query, stat_prefix, *message); // Callsite stats if we have it. - std::string callsite = MessageUtility::queryCallingFunction(*active_query.query_); - if (!callsite.empty()) { + if (!active_query.query_info_.callsite().empty()) { std::string callsite_stat_prefix = - fmt::format("{}collection.{}.callsite.{}.query", stat_prefix_, collection, callsite); + fmt::format("{}collection.{}.callsite.{}.query", stat_prefix_, + active_query.query_info_.collection(), active_query.query_info_.callsite()); chargeReplyStats(active_query, callsite_stat_prefix, *message); } } diff --git a/source/common/mongo/proxy.h b/source/common/mongo/proxy.h index 8b04f1340169f..407d4b5d1f945 100644 --- a/source/common/mongo/proxy.h +++ b/source/common/mongo/proxy.h @@ -107,15 +107,15 @@ class ProxyFilter : public Network::Filter, private: struct ActiveQuery { - ActiveQuery(ProxyFilter& parent, QueryMessagePtr&& query) - : parent_(parent), query_(std::move(query)), start_time_(std::chrono::system_clock::now()) { + ActiveQuery(ProxyFilter& parent, const QueryMessage& query) + : parent_(parent), query_info_(query), start_time_(std::chrono::system_clock::now()) { parent_.stats_.op_query_active_.inc(); } ~ActiveQuery() { parent_.stats_.op_query_active_.dec(); } ProxyFilter& parent_; - QueryMessagePtr query_; + QueryMessageInfo query_info_; SystemTime start_time_; }; @@ -127,7 +127,7 @@ class ProxyFilter : public Network::Filter, POOL_TIMER_PREFIX(store, prefix))}; } - void chargeQueryStats(const std::string& prefix, MessageUtility::QueryType query_type); + void chargeQueryStats(const std::string& prefix, QueryMessageInfo::QueryType query_type); void chargeReplyStats(ActiveQuery& active_query, const std::string& prefix, const ReplyMessage& message); void doDecode(Buffer::Instance& buffer); diff --git a/source/common/mongo/utility.cc b/source/common/mongo/utility.cc index 32e4a1140b087..aa8f06e724e06 100644 --- a/source/common/mongo/utility.cc +++ b/source/common/mongo/utility.cc @@ -6,8 +6,28 @@ namespace Mongo { -std::string -MessageUtility::collectionFromFullCollectionName(const std::string& full_collection_name) { +QueryMessageInfo::QueryMessageInfo(const QueryMessage& query) : request_id_{query.requestId()} { + // First see if this is a command, if so we are done. + const Bson::Document* command = parseCommand(query); + if (command) { + command_ = command->values().front()->key(); + + // Special case the 3.2 'find' command since it is a query. + if (command_ == "find") { + command_ = ""; + parseFindCommand(*command); + } + + return; + } + + // Standard query. + collection_ = parseCollection(query.fullCollectionName()); + callsite_ = parseCallingFunction(query); + type_ = parseType(query); +} + +std::string QueryMessageInfo::parseCollection(const std::string& full_collection_name) { size_t collection_index = full_collection_name.find('.'); if (collection_index == std::string::npos) { throw EnvoyException("invalid full collection name"); @@ -16,54 +36,60 @@ MessageUtility::collectionFromFullCollectionName(const std::string& full_collect return full_collection_name.substr(collection_index + 1); } -std::string MessageUtility::queryCommand(const QueryMessage& query) { +const Bson::Document* QueryMessageInfo::parseCommand(const QueryMessage& query) { if (query.fullCollectionName().find("$cmd") == std::string::npos) { - return ""; + return nullptr; } // See if there is a $query document, and use that to find the command if so. const Bson::Document* doc_to_use = query.query(); - if (query.query()->find("$query", Bson::Field::Type::DOCUMENT)) { - doc_to_use = &query.query()->find("$query", Bson::Field::Type::DOCUMENT)->asDocument(); + const Bson::Field* field = query.query()->find("$query", Bson::Field::Type::DOCUMENT); + if (field) { + doc_to_use = &field->asDocument(); } if (doc_to_use->values().empty()) { throw EnvoyException("invalid query command"); } - return doc_to_use->values().front()->key(); + return doc_to_use; } -std::string MessageUtility::queryCallingFunction(const QueryMessage& query) { +std::string QueryMessageInfo::parseCallingFunction(const QueryMessage& query) { const Bson::Field* field = query.query()->find("$comment", Bson::Field::Type::STRING); if (!field) { return ""; } + return parseCallingFunctionJson(field->asString()); +} + +std::string QueryMessageInfo::parseCallingFunctionJson(const std::string& json_string) { try { - Json::StringLoader json(field->asString()); + Json::StringLoader json(json_string); return json.getString("callingFunction"); } catch (Json::Exception&) { return ""; } } -MessageUtility::QueryType MessageUtility::queryType(const QueryMessage& query) { +QueryMessageInfo::QueryType QueryMessageInfo::parseType(const QueryMessage& query) { // First check the top level for _id. - QueryType type = queryTypeFromDocument(*query.query()); + QueryType type = parseTypeFromDocument(*query.query()); if (type == QueryType::ScatterGet) { // If we didn't find it in the top level, see if we have a top level $query element and look // there. const Bson::Field* field = query.query()->find("$query", Bson::Field::Type::DOCUMENT); if (field) { - type = queryTypeFromDocument(field->asDocument()); + type = parseTypeFromDocument(field->asDocument()); } } return type; } -MessageUtility::QueryType MessageUtility::queryTypeFromDocument(const Bson::Document& document) { +QueryMessageInfo::QueryType +QueryMessageInfo::parseTypeFromDocument(const Bson::Document& document) { const Bson::Field* field = document.find("_id"); if (!field) { return QueryType::ScatterGet; @@ -77,4 +103,17 @@ MessageUtility::QueryType MessageUtility::queryTypeFromDocument(const Bson::Docu return QueryType::PrimaryKey; } +void QueryMessageInfo::parseFindCommand(const Bson::Document& command) { + collection_ = command.values().front()->asString(); + const Bson::Field* comment = command.find("comment", Bson::Field::Type::STRING); + if (comment) { + callsite_ = parseCallingFunctionJson(comment->asString()); + } + + const Bson::Field* filter = command.find("filter", Bson::Field::Type::DOCUMENT); + if (filter) { + type_ = parseTypeFromDocument(filter->asDocument()); + } +} + } // Mongo diff --git a/source/common/mongo/utility.h b/source/common/mongo/utility.h index f17c4dd00eb4e..86bcdd1c4e58b 100644 --- a/source/common/mongo/utility.h +++ b/source/common/mongo/utility.h @@ -5,16 +5,23 @@ namespace Mongo { /** - * General utilities for dealing with mongo messages. + * Parses a query into information that can be used for stat gathering. */ -class MessageUtility { +class QueryMessageInfo { public: enum class QueryType { PrimaryKey, MultiGet, ScatterGet }; + QueryMessageInfo(const QueryMessage& query); + + /** + * @return the query's request ID. + */ + int32_t requestId() { return request_id_; } + /** - * @return the collection name with the database name removed or throw if this cannot be done. + * @return the collection name with the database name removed, or "" if a command. */ - static std::string collectionFromFullCollectionName(const std::string& full_collection_name); + const std::string& collection() { return collection_; } /** * @return calling function if it can be found in the query. The calling function is found by: @@ -23,20 +30,32 @@ class MessageUtility { * 3) Accessing the 'callingFunction' field in the JSON. * "" is returned if any of the above fails. */ - static std::string queryCallingFunction(const QueryMessage& query); + const std::string& callsite() { return callsite_; } /** * @return the type of a query message. */ - static QueryType queryType(const QueryMessage& query); + QueryType type() { return type_; } /** * @return the name of the command if the query is a command, otherwise "". */ - static std::string queryCommand(const QueryMessage& query); + const std::string& command() { return command_; } private: - static QueryType queryTypeFromDocument(const Bson::Document& document); + std::string parseCallingFunction(const QueryMessage& query); + std::string parseCallingFunctionJson(const std::string& json_string); + std::string parseCollection(const std::string& full_collection_name); + const Bson::Document* parseCommand(const QueryMessage& query); + void parseFindCommand(const Bson::Document& command); + QueryType parseType(const QueryMessage& query); + QueryType parseTypeFromDocument(const Bson::Document& document); + + int32_t request_id_; + std::string collection_; + std::string callsite_; + QueryType type_{QueryType::ScatterGet}; + std::string command_; }; } // Mongo diff --git a/test/common/mongo/codec_impl_test.cc b/test/common/mongo/codec_impl_test.cc index 66c8f1305991c..d2ec06a68e501 100644 --- a/test/common/mongo/codec_impl_test.cc +++ b/test/common/mongo/codec_impl_test.cc @@ -76,6 +76,7 @@ TEST_F(MongoCodecImplTest, Query) { ->addString("string", "string_value") ->addDocument("document", Bson::DocumentImpl::create()) ->addArray("array", Bson::DocumentImpl::create()) + ->addBinary("binary", "binary_value") ->addObjectId("object_id", Bson::Field::ObjectId()) ->addBoolean("true", true) ->addBoolean("false", false) diff --git a/test/common/mongo/utility_test.cc b/test/common/mongo/utility_test.cc index 3648850b5e1f6..45e4610a6cf98 100644 --- a/test/common/mongo/utility_test.cc +++ b/test/common/mongo/utility_test.cc @@ -4,65 +4,111 @@ namespace Mongo { -TEST(MongoMessageUtilityTest, QueryType) { +TEST(QueryMessageInfoTest, FindCommand) { + std::string json = R"EOF( + {"hostname":"api-production-iad-canary","httpUniqueId":"VqqX7H8AAQEAAE@8EUkAAAAR","callingFunction":"getByMongoId"} + )EOF"; + + QueryMessageImpl q(0, 0); + q.fullCollectionName("db.$cmd"); + q.query(Bson::DocumentImpl::create() + ->addString("find", "foo_collection") + ->addString("comment", std::move(json)) + ->addDocument("filter", Bson::DocumentImpl::create()->addString("_id", "foo"))); + QueryMessageInfo info(q); + EXPECT_EQ("", info.command()); + EXPECT_EQ("foo_collection", info.collection()); + EXPECT_EQ("getByMongoId", info.callsite()); + EXPECT_EQ(QueryMessageInfo::QueryType::PrimaryKey, info.type()); +} + +TEST(QueryMessageInfoTest, Type) { { - QueryMessageImpl q(0, 0); + QueryMessageImpl q(1, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()); - EXPECT_EQ(MessageUtility::QueryType::ScatterGet, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::ScatterGet, info.type()); + EXPECT_EQ(1, info.requestId()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addInt32("_id", 2)); - EXPECT_EQ(MessageUtility::QueryType::PrimaryKey, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::PrimaryKey, info.type()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addDocument( "_id", Bson::DocumentImpl::create()->addArray("$in", Bson::DocumentImpl::create()))); - EXPECT_EQ(MessageUtility::QueryType::MultiGet, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::MultiGet, info.type()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addDocument("$query", Bson::DocumentImpl::create())); - EXPECT_EQ(MessageUtility::QueryType::ScatterGet, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::ScatterGet, info.type()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addDocument( "$query", Bson::DocumentImpl::create()->addInt32("_id", 2))); - EXPECT_EQ(MessageUtility::QueryType::PrimaryKey, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::PrimaryKey, info.type()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addDocument( "$query", Bson::DocumentImpl::create()->addDocument( "_id", Bson::DocumentImpl::create()->addArray("$in", Bson::DocumentImpl::create())))); - EXPECT_EQ(MessageUtility::QueryType::MultiGet, MessageUtility::queryType(q)); + QueryMessageInfo info(q); + EXPECT_EQ(QueryMessageInfo::QueryType::MultiGet, info.type()); } } -TEST(MongoMessageUtilityTest, CollectionFromFullCollectionName) { - EXPECT_EQ("foo", MessageUtility::collectionFromFullCollectionName("db.foo")); - EXPECT_THROW(MessageUtility::collectionFromFullCollectionName("foo"), EnvoyException); +TEST(QueryMessageInfoTest, CollectionFromFullCollectionName) { + { + QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); + q.query(Bson::DocumentImpl::create()); + QueryMessageInfo info(q); + EXPECT_EQ("foo", info.collection()); + } + + { + QueryMessageImpl q(0, 0); + q.fullCollectionName("foo"); + EXPECT_THROW((QueryMessageInfo(q)), EnvoyException); + } } -TEST(MongoMessageUtilityTest, QueryCallingFunction) { +TEST(QueryMessageInfoTest, Callsite) { { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()); - EXPECT_EQ("", MessageUtility::queryCallingFunction(q)); + QueryMessageInfo info(q); + EXPECT_EQ("", info.callsite()); } { QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addString("$comment", "bad json")); - EXPECT_EQ("", MessageUtility::queryCallingFunction(q)); + QueryMessageInfo info(q); + EXPECT_EQ("", info.callsite()); } { @@ -71,31 +117,35 @@ TEST(MongoMessageUtilityTest, QueryCallingFunction) { )EOF"; QueryMessageImpl q(0, 0); + q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addString("$comment", std::move(json))); - EXPECT_EQ("getByMongoId", MessageUtility::queryCallingFunction(q)); + QueryMessageInfo info(q); + EXPECT_EQ("getByMongoId", info.callsite()); } } -TEST(MongoMessageUtilityTest, QueryCommand) { +TEST(QueryMessageInfoTest, Command) { { QueryMessageImpl q(0, 0); q.fullCollectionName("db.$cmd"); q.query(Bson::DocumentImpl::create()->addString("foo", "bar")); - EXPECT_EQ("foo", MessageUtility::queryCommand(q)); + QueryMessageInfo info(q); + EXPECT_EQ("foo", info.command()); } { QueryMessageImpl q(0, 0); q.fullCollectionName("db.foo"); q.query(Bson::DocumentImpl::create()->addString("foo", "bar")); - EXPECT_EQ("", MessageUtility::queryCommand(q)); + QueryMessageInfo info(q); + EXPECT_EQ("", info.command()); } { QueryMessageImpl q(0, 0); q.fullCollectionName("db.$cmd"); q.query(Bson::DocumentImpl::create()); - EXPECT_THROW(MessageUtility::queryCommand(q), EnvoyException); + EXPECT_THROW((QueryMessageInfo(q)), EnvoyException); } { @@ -103,7 +153,8 @@ TEST(MongoMessageUtilityTest, QueryCommand) { q.fullCollectionName("db.$cmd"); q.query(Bson::DocumentImpl::create()->addDocument( "$query", Bson::DocumentImpl::create()->addInt32("ismaster", 1))); - EXPECT_EQ("ismaster", MessageUtility::queryCommand(q)); + QueryMessageInfo info(q); + EXPECT_EQ("ismaster", info.command()); } }