diff options
author | Mathias Stearn <mathias@10gen.com> | 2017-12-11 19:35:05 -0500 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2018-01-04 14:52:27 -0500 |
commit | 7f56cb7f21a4d13dd4c4d39d85f23ec77cd28f9b (patch) | |
tree | 6ebe17c53fba868d4ce80b3ae1516db3412ee485 /src/mongo/rpc | |
parent | 6b1a6cfe77e3c5a3b2d62a3346d19d26694ed2ed (diff) | |
download | mongo-7f56cb7f21a4d13dd4c4d39d85f23ec77cd28f9b.tar.gz |
SERVER-31734 Core ErrorExtraInfo implementation
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r-- | src/mongo/rpc/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/rpc/get_status_from_command_result.cpp | 2 | ||||
-rw-r--r-- | src/mongo/rpc/get_status_from_command_result_test.cpp | 82 | ||||
-rw-r--r-- | src/mongo/rpc/reply_builder_interface.cpp | 4 | ||||
-rw-r--r-- | src/mongo/rpc/reply_builder_test.cpp | 42 |
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 |