1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #include <exception>
32 #include <stdexcept>
33 #include <string>
34
35 #include <boost/exception/exception.hpp>
36
37 #include "mongo/base/status.h"
38 #include "mongo/unittest/unittest.h"
39 #include "mongo/util/assert_util.h"
40
41 namespace mongo {
42 namespace {
43
TEST(Basic,Accessors)44 TEST(Basic, Accessors) {
45 Status status(ErrorCodes::MaxError, "error");
46 ASSERT_EQUALS(status.code(), ErrorCodes::MaxError);
47 ASSERT_EQUALS(status.reason(), "error");
48 }
49
TEST(Basic,IsA)50 TEST(Basic, IsA) {
51 ASSERT(!Status(ErrorCodes::BadValue, "").isA<ErrorCategory::Interruption>());
52 ASSERT(Status(ErrorCodes::Interrupted, "").isA<ErrorCategory::Interruption>());
53 ASSERT(!Status(ErrorCodes::Interrupted, "").isA<ErrorCategory::ShutdownError>());
54 }
55
TEST(Basic,OKIsAValidStatus)56 TEST(Basic, OKIsAValidStatus) {
57 Status status = Status::OK();
58 ASSERT_EQUALS(status.code(), ErrorCodes::OK);
59 }
60
TEST(Basic,Compare)61 TEST(Basic, Compare) {
62 Status errMax(ErrorCodes::MaxError, "error");
63 ASSERT_EQ(errMax, errMax);
64 ASSERT_NE(errMax, Status::OK());
65 }
66
TEST(Basic,WithContext)67 TEST(Basic, WithContext) {
68 const Status orig(ErrorCodes::MaxError, "error");
69
70 const auto copy = orig.withContext("context");
71 ASSERT_EQ(copy.code(), ErrorCodes::MaxError);
72 ASSERT(str::startsWith(copy.reason(), "context ")) << copy.reason();
73 ASSERT(str::endsWith(copy.reason(), " error")) << copy.reason();
74
75 ASSERT_EQ(orig.code(), ErrorCodes::MaxError);
76 ASSERT_EQ(orig.reason(), "error");
77 }
78
TEST(Cloning,Copy)79 TEST(Cloning, Copy) {
80 Status orig(ErrorCodes::MaxError, "error");
81 ASSERT_EQUALS(orig.refCount(), 1U);
82
83 Status dest(orig);
84 ASSERT_EQUALS(dest.code(), ErrorCodes::MaxError);
85 ASSERT_EQUALS(dest.reason(), "error");
86
87 ASSERT_EQUALS(dest.refCount(), 2U);
88 ASSERT_EQUALS(orig.refCount(), 2U);
89 }
90
TEST(Cloning,MoveCopyOK)91 TEST(Cloning, MoveCopyOK) {
92 Status orig = Status::OK();
93 ASSERT_TRUE(orig.isOK());
94 ASSERT_EQUALS(orig.refCount(), 0U);
95
96 Status dest(std::move(orig));
97
98 ASSERT_TRUE(orig.isOK());
99 ASSERT_EQUALS(orig.refCount(), 0U);
100
101 ASSERT_TRUE(dest.isOK());
102 ASSERT_EQUALS(dest.refCount(), 0U);
103 }
104
TEST(Cloning,MoveCopyError)105 TEST(Cloning, MoveCopyError) {
106 Status orig(ErrorCodes::MaxError, "error");
107 ASSERT_FALSE(orig.isOK());
108 ASSERT_EQUALS(orig.refCount(), 1U);
109
110 Status dest(std::move(orig));
111
112 ASSERT_TRUE(orig.isOK());
113 ASSERT_EQUALS(orig.refCount(), 0U);
114
115 ASSERT_FALSE(dest.isOK());
116 ASSERT_EQUALS(dest.refCount(), 1U);
117 ASSERT_EQUALS(dest.code(), ErrorCodes::MaxError);
118 ASSERT_EQUALS(dest.reason(), "error");
119 }
120
TEST(Cloning,MoveAssignOKToOK)121 TEST(Cloning, MoveAssignOKToOK) {
122 Status orig = Status::OK();
123 ASSERT_TRUE(orig.isOK());
124 ASSERT_EQUALS(orig.refCount(), 0U);
125
126 Status dest = Status::OK();
127 ASSERT_TRUE(dest.isOK());
128 ASSERT_EQUALS(dest.refCount(), 0U);
129
130 dest = std::move(orig);
131
132 ASSERT_TRUE(orig.isOK());
133 ASSERT_EQUALS(orig.refCount(), 0U);
134
135 ASSERT_TRUE(dest.isOK());
136 ASSERT_EQUALS(dest.refCount(), 0U);
137 }
138
TEST(Cloning,MoveAssignErrorToError)139 TEST(Cloning, MoveAssignErrorToError) {
140 Status orig = Status(ErrorCodes::MaxError, "error");
141 ASSERT_FALSE(orig.isOK());
142 ASSERT_EQUALS(orig.refCount(), 1U);
143 ASSERT_EQUALS(orig.code(), ErrorCodes::MaxError);
144 ASSERT_EQUALS(orig.reason(), "error");
145
146 Status dest = Status(ErrorCodes::InternalError, "error2");
147 ASSERT_FALSE(dest.isOK());
148 ASSERT_EQUALS(dest.refCount(), 1U);
149 ASSERT_EQUALS(dest.code(), ErrorCodes::InternalError);
150 ASSERT_EQUALS(dest.reason(), "error2");
151
152 dest = std::move(orig);
153
154 ASSERT_TRUE(orig.isOK());
155 ASSERT_EQUALS(orig.refCount(), 0U);
156
157 ASSERT_FALSE(dest.isOK());
158 ASSERT_EQUALS(dest.refCount(), 1U);
159 ASSERT_EQUALS(dest.code(), ErrorCodes::MaxError);
160 ASSERT_EQUALS(dest.reason(), "error");
161 }
162
TEST(Cloning,MoveAssignErrorToOK)163 TEST(Cloning, MoveAssignErrorToOK) {
164 Status orig = Status(ErrorCodes::MaxError, "error");
165 ASSERT_FALSE(orig.isOK());
166 ASSERT_EQUALS(orig.refCount(), 1U);
167 ASSERT_EQUALS(orig.code(), ErrorCodes::MaxError);
168 ASSERT_EQUALS(orig.reason(), "error");
169
170 Status dest = Status::OK();
171 ASSERT_TRUE(dest.isOK());
172 ASSERT_EQUALS(dest.refCount(), 0U);
173
174 dest = std::move(orig);
175
176 ASSERT_TRUE(orig.isOK());
177 ASSERT_EQUALS(orig.refCount(), 0U);
178
179 ASSERT_FALSE(dest.isOK());
180 ASSERT_EQUALS(dest.refCount(), 1U);
181 ASSERT_EQUALS(dest.code(), ErrorCodes::MaxError);
182 ASSERT_EQUALS(dest.reason(), "error");
183 }
184
TEST(Cloning,MoveAssignOKToError)185 TEST(Cloning, MoveAssignOKToError) {
186 Status orig = Status::OK();
187 ASSERT_TRUE(orig.isOK());
188 ASSERT_EQUALS(orig.refCount(), 0U);
189
190 Status dest = Status(ErrorCodes::MaxError, "error");
191 ASSERT_FALSE(dest.isOK());
192 ASSERT_EQUALS(dest.refCount(), 1U);
193 ASSERT_EQUALS(dest.code(), ErrorCodes::MaxError);
194 ASSERT_EQUALS(dest.reason(), "error");
195
196 orig = std::move(dest);
197
198 ASSERT_FALSE(orig.isOK());
199 ASSERT_EQUALS(orig.refCount(), 1U);
200 ASSERT_EQUALS(orig.code(), ErrorCodes::MaxError);
201 ASSERT_EQUALS(orig.reason(), "error");
202
203 ASSERT_TRUE(dest.isOK());
204 ASSERT_EQUALS(dest.refCount(), 0U);
205 }
206
TEST(Cloning,OKIsNotRefCounted)207 TEST(Cloning, OKIsNotRefCounted) {
208 ASSERT_EQUALS(Status::OK().refCount(), 0U);
209
210 Status myOk = Status::OK();
211 ASSERT_EQUALS(myOk.refCount(), 0U);
212 ASSERT_EQUALS(Status::OK().refCount(), 0U);
213 }
214
TEST(Parsing,CodeToEnum)215 TEST(Parsing, CodeToEnum) {
216 ASSERT_EQUALS(ErrorCodes::TypeMismatch, ErrorCodes::Error(int(ErrorCodes::TypeMismatch)));
217 ASSERT_EQUALS(ErrorCodes::UnknownError, ErrorCodes::Error(int(ErrorCodes::UnknownError)));
218 ASSERT_EQUALS(ErrorCodes::MaxError, ErrorCodes::Error(int(ErrorCodes::MaxError)));
219 ASSERT_EQUALS(ErrorCodes::OK, ErrorCodes::duplicateCodeForTest(0));
220 }
221
TEST(Transformers,ExceptionToStatus)222 TEST(Transformers, ExceptionToStatus) {
223 using mongo::DBException;
224 using mongo::exceptionToStatus;
225
226 auto reason = "oh no";
227
228 Status fromDBExcept = [=]() {
229 try {
230 uasserted(ErrorCodes::TypeMismatch, reason);
231 } catch (...) {
232 return exceptionToStatus();
233 }
234 }();
235
236 ASSERT_NOT_OK(fromDBExcept);
237 ASSERT_EQUALS(fromDBExcept.reason(), reason);
238 ASSERT_EQUALS(fromDBExcept.code(), ErrorCodes::TypeMismatch);
239
240 Status fromStdExcept = [=]() {
241 try {
242 throw std::out_of_range(reason);
243 } catch (...) {
244 return exceptionToStatus();
245 }
246 }();
247
248 ASSERT_NOT_OK(fromStdExcept);
249 // we don't check the exact error message because the type name of the exception
250 // isn't demangled on windows.
251 ASSERT_TRUE(fromStdExcept.reason().find(reason) != std::string::npos);
252 ASSERT_EQUALS(fromStdExcept.code(), ErrorCodes::UnknownError);
253
254 class bar : public boost::exception {};
255
256 Status fromBoostExcept = [=]() {
257 try {
258 throw bar();
259 } catch (...) {
260 return exceptionToStatus();
261 }
262 }();
263
264 ASSERT_NOT_OK(fromBoostExcept);
265 ASSERT_EQUALS(fromBoostExcept, ErrorCodes::UnknownError);
266 // Reason should include that it was a boost::exception
267 ASSERT_TRUE(fromBoostExcept.reason().find("boost::exception") != std::string::npos);
268 }
269
270 } // namespace
271 } // namespace mongo
272