summaryrefslogtreecommitdiff
path: root/src/mongo/rpc
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-12-11 19:35:05 -0500
committerMathias Stearn <mathias@10gen.com>2018-01-04 14:52:27 -0500
commit7f56cb7f21a4d13dd4c4d39d85f23ec77cd28f9b (patch)
tree6ebe17c53fba868d4ce80b3ae1516db3412ee485 /src/mongo/rpc
parent6b1a6cfe77e3c5a3b2d62a3346d19d26694ed2ed (diff)
downloadmongo-7f56cb7f21a4d13dd4c4d39d85f23ec77cd28f9b.tar.gz
SERVER-31734 Core ErrorExtraInfo implementation
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r--src/mongo/rpc/SConscript1
-rw-r--r--src/mongo/rpc/get_status_from_command_result.cpp2
-rw-r--r--src/mongo/rpc/get_status_from_command_result_test.cpp82
-rw-r--r--src/mongo/rpc/reply_builder_interface.cpp4
-rw-r--r--src/mongo/rpc/reply_builder_test.cpp42
5 files changed, 130 insertions, 1 deletions
diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript
index 58ded79d586..98ea0e6d64c 100644
--- a/src/mongo/rpc/SConscript
+++ b/src/mongo/rpc/SConscript
@@ -178,6 +178,7 @@ env.CppUnitTest(
'command_reply_test.cpp',
'command_request_builder_test.cpp',
'command_request_test.cpp',
+ 'get_status_from_command_result_test.cpp',
'legacy_request_test.cpp',
'object_check_test.cpp',
'protocol_test.cpp',
diff --git a/src/mongo/rpc/get_status_from_command_result.cpp b/src/mongo/rpc/get_status_from_command_result.cpp
index 3b13923c049..ed0ad38824d 100644
--- a/src/mongo/rpc/get_status_from_command_result.cpp
+++ b/src/mongo/rpc/get_status_from_command_result.cpp
@@ -77,7 +77,7 @@ Status getStatusFromCommandResult(const BSONObj& result) {
code = ErrorCodes::CommandNotFound;
}
- return Status(ErrorCodes::Error(code), errmsg);
+ return Status(ErrorCodes::Error(code), errmsg, result);
}
Status getWriteConcernStatusFromCommandResult(const BSONObj& obj) {
diff --git a/src/mongo/rpc/get_status_from_command_result_test.cpp b/src/mongo/rpc/get_status_from_command_result_test.cpp
new file mode 100644
index 00000000000..0c5e260de7d
--- /dev/null
+++ b/src/mongo/rpc/get_status_from_command_result_test.cpp
@@ -0,0 +1,82 @@
+/**
+ * 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/platform/basic.h"
+
+#include "mongo/db/jsobj.h"
+#include "mongo/db/json.h"
+#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/unittest/unittest.h"
+#include "mongo/unittest/unittest_helpers.h"
+
+namespace mongo {
+
+namespace {
+Status statusFor(const std::string& json) {
+ return getStatusFromCommandResult(fromjson(json));
+}
+} // namespace
+
+TEST(GetStatusFromCommandResult, Ok) {
+ ASSERT_OK(statusFor("{ok: 1.0}"));
+}
+
+TEST(GetStatusFromCommandResult, OkIgnoresCode) {
+ ASSERT_OK(statusFor("{ok: 1.0, code: 12345, errmsg: 'oh no!'}"));
+}
+
+TEST(GetStatusFromCommandResult, SimpleBad) {
+ const auto status = statusFor("{ok: 0.0, code: 12345, errmsg: 'oh no!'}");
+ ASSERT_EQ(status, ErrorCodes::duplicateCodeForTest(12345));
+ ASSERT_EQ(status.reason(), "oh no!");
+}
+
+TEST(GetStatusFromCommandResult, SimpleNoCode) {
+ const auto status = statusFor("{ok: 0.0, errmsg: 'oh no!'}");
+ ASSERT_EQ(status, ErrorCodes::UnknownError);
+ ASSERT_EQ(status.reason(), "oh no!");
+ ASSERT(!status.extraInfo());
+}
+
+TEST(GetStatusFromCommandResult, ExtraInfoParserFails) {
+ const auto status = statusFor("{ok: 0.0, code: 236, errmsg: 'oh no!', data: 123}");
+ ASSERT_EQ(status, ErrorCodes::duplicateCodeForTest(40681));
+ ASSERT(!status.extraInfo());
+}
+
+TEST(GetStatusFromCommandResult, ExtraInfoParserSucceeds) {
+ ErrorExtraInfoExample::EnableParserForTest whenInScope;
+ const auto status = statusFor("{ok: 0.0, code: 236, errmsg: 'oh no!', data: 123}");
+ ASSERT_EQ(status, ErrorCodes::ForTestingErrorExtraInfo);
+ ASSERT_EQ(status.reason(), "oh no!");
+ ASSERT(status.extraInfo());
+ ASSERT(status.extraInfo<ErrorExtraInfoExample>());
+ ASSERT_EQ(status.extraInfo<ErrorExtraInfoExample>()->data, 123);
+}
+
+} // namespace mongo
diff --git a/src/mongo/rpc/reply_builder_interface.cpp b/src/mongo/rpc/reply_builder_interface.cpp
index 99fe2edcb1e..9c5b2998e2f 100644
--- a/src/mongo/rpc/reply_builder_interface.cpp
+++ b/src/mongo/rpc/reply_builder_interface.cpp
@@ -71,6 +71,10 @@ BSONObj augmentReplyWithStatus(const Status& status, BSONObj reply) {
bob.append(kCodeNameField, ErrorCodes::errorString(status.code()));
}
+ if (auto extraInfo = status.extraInfo()) {
+ extraInfo->serialize(&bob);
+ }
+
return bob.obj();
}
}
diff --git a/src/mongo/rpc/reply_builder_test.cpp b/src/mongo/rpc/reply_builder_test.cpp
index 83a449f686b..f4f8ac58ef4 100644
--- a/src/mongo/rpc/reply_builder_test.cpp
+++ b/src/mongo/rpc/reply_builder_test.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/json.h"
#include "mongo/rpc/command_reply.h"
#include "mongo/rpc/command_reply_builder.h"
+#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/rpc/legacy_reply.h"
#include "mongo/rpc/legacy_reply_builder.h"
#include "mongo/rpc/op_msg_rpc_impls.h"
@@ -46,6 +47,9 @@ using namespace mongo;
template <typename T>
void testRoundTrip(rpc::ReplyBuilderInterface& replyBuilder, bool unifiedBodyAndMetadata);
+template <typename T>
+void testErrors(rpc::ReplyBuilderInterface& replyBuilder);
+
TEST(LegacyReplyBuilder, RoundTrip) {
rpc::LegacyReplyBuilder r;
testRoundTrip<rpc::LegacyReply>(r, true);
@@ -61,6 +65,24 @@ TEST(OpMsgReplyBuilder, RoundTrip) {
testRoundTrip<rpc::OpMsgReply>(r, true);
}
+template <typename T>
+void testErrors(rpc::ReplyBuilderInterface& replyBuilder);
+
+TEST(LegacyReplyBuilder, Errors) {
+ rpc::LegacyReplyBuilder r;
+ testErrors<rpc::LegacyReply>(r);
+}
+
+TEST(CommandReplyBuilder, Errors) {
+ rpc::CommandReplyBuilder r;
+ testErrors<rpc::CommandReply>(r);
+}
+
+TEST(OpMsgReplyBuilder, Errors) {
+ rpc::OpMsgReplyBuilder r;
+ testErrors<rpc::OpMsgReply>(r);
+}
+
BSONObj buildMetadata() {
BSONObjBuilder metadataTop;
{
@@ -195,4 +217,24 @@ void testRoundTrip(rpc::ReplyBuilderInterface& replyBuilder, bool unifiedBodyAnd
}
}
+template <typename T>
+void testErrors(rpc::ReplyBuilderInterface& replyBuilder) {
+ ErrorExtraInfoExample::EnableParserForTest whenInScope;
+
+ const auto status = Status(ErrorExtraInfoExample(123), "Why does this keep failing!");
+
+ replyBuilder.setCommandReply(status);
+ replyBuilder.setMetadata(buildMetadata());
+
+ const auto msg = replyBuilder.done();
+
+ T parsed(&msg);
+ const Status result = getStatusFromCommandResult(parsed.getCommandReply());
+ ASSERT_EQ(result, status.code());
+ ASSERT_EQ(result.reason(), status.reason());
+ ASSERT(result.extraInfo());
+ ASSERT(result.extraInfo<ErrorExtraInfoExample>());
+ ASSERT_EQ(result.extraInfo<ErrorExtraInfoExample>()->data, 123);
+}
+
} // namespace