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 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
32
33 #include "mongo/platform/basic.h"
34
35 #include "mongo/rpc/metadata/client_metadata.h"
36
37 #include <boost/filesystem.hpp>
38 #include <map>
39
40 #include "mongo/bson/bsonobj.h"
41 #include "mongo/bson/bsonobjbuilder.h"
42 #include "mongo/s/is_mongos.h"
43 #include "mongo/unittest/unittest.h"
44 #include "mongo/util/log.h"
45 #include "mongo/util/scopeguard.h"
46
47 namespace mongo {
48
49 constexpr auto kMetadataDoc = "client"_sd;
50 constexpr auto kApplication = "application"_sd;
51 constexpr auto kDriver = "driver"_sd;
52 constexpr auto kName = "name"_sd;
53 constexpr auto kType = "type"_sd;
54 constexpr auto kVersion = "version"_sd;
55 constexpr auto kOperatingSystem = "os"_sd;
56 constexpr auto kArchitecture = "architecture"_sd;
57 constexpr auto kMongos = "mongos"_sd;
58 constexpr auto kClient = "client"_sd;
59 constexpr auto kHost = "host"_sd;
60
61 constexpr auto kUnknown = "unkown"_sd;
62
63 #define ASSERT_DOC_OK(...) \
64 do { \
65 auto _swParseStatus = \
66 ClientMetadata::parse(BSON(kMetadataDoc << BSON(__VA_ARGS__))[kMetadataDoc]); \
67 ASSERT_OK(_swParseStatus.getStatus()); \
68 } while (0)
69
70 #define ASSERT_DOC_NOT_OK(...) \
71 do { \
72 auto _swParseStatus = \
73 ClientMetadata::parse(BSON(kMetadataDoc << BSON(__VA_ARGS__))[kMetadataDoc]); \
74 ASSERT_NOT_OK(_swParseStatus.getStatus()); \
75 } while (0)
76
77
TEST(ClientMetadatTest,TestLoopbackTest)78 TEST(ClientMetadatTest, TestLoopbackTest) {
79 // Serialize without application name
80 {
81 BSONObjBuilder builder;
82 ASSERT_OK(ClientMetadata::serializePrivate("a", "b", "c", "d", "e", "f", "g", &builder));
83
84 auto obj = builder.obj();
85 auto swParseStatus = ClientMetadata::parse(obj[kMetadataDoc]);
86 ASSERT_OK(swParseStatus.getStatus());
87 ASSERT_EQUALS("g", swParseStatus.getValue().get().getApplicationName());
88
89 BSONObj outDoc =
90 BSON(kMetadataDoc << BSON(
91 kApplication << BSON(kName << "g") << kDriver
92 << BSON(kName << "a" << kVersion << "b")
93 << kOperatingSystem
94 << BSON(kType << "c" << kName << "d" << kArchitecture << "e"
95 << kVersion
96 << "f")));
97 ASSERT_BSONOBJ_EQ(obj, outDoc);
98 }
99
100 // Serialize without application name
101 {
102 BSONObjBuilder builder;
103 ClientMetadata::serializePrivate("a", "b", "c", "d", "e", "f", &builder);
104
105 auto obj = builder.obj();
106 auto swParseStatus = ClientMetadata::parse(obj[kMetadataDoc]);
107 ASSERT_OK(swParseStatus.getStatus());
108
109 BSONObj outDoc = BSON(
110 kMetadataDoc << BSON(
111 kDriver << BSON(kName << "a" << kVersion << "b") << kOperatingSystem
112 << BSON(kType << "c" << kName << "d" << kArchitecture << "e" << kVersion
113 << "f")));
114 ASSERT_BSONOBJ_EQ(obj, outDoc);
115 }
116
117 // Serialize with the os information automatically computed
118 {
119 BSONObjBuilder builder;
120 ASSERT_OK(ClientMetadata::serialize("a", "b", "f", &builder));
121
122 auto obj = builder.obj();
123
124 auto swParse = ClientMetadata::parse(obj[kMetadataDoc]);
125 ASSERT_OK(swParse.getStatus());
126 ASSERT_EQUALS("f", swParse.getValue().get().getApplicationName());
127 }
128 }
129
130 // Mixed: no client metadata document
TEST(ClientMetadatTest,TestEmptyDoc)131 TEST(ClientMetadatTest, TestEmptyDoc) {
132 {
133 auto parseStatus = ClientMetadata::parse(BSONElement());
134
135 ASSERT_OK(parseStatus.getStatus());
136 }
137
138 {
139 auto obj = BSON("client" << BSONObj());
140 auto parseStatus = ClientMetadata::parse(obj[kMetadataDoc]);
141
142 ASSERT_NOT_OK(parseStatus.getStatus());
143 }
144 }
145
146 // Positive: test with only required fields
TEST(ClientMetadatTest,TestRequiredOnlyFields)147 TEST(ClientMetadatTest, TestRequiredOnlyFields) {
148 // Without app name
149 ASSERT_DOC_OK(kDriver << BSON(kName << "n1" << kVersion << "v1") << kOperatingSystem
150 << BSON(kType << kUnknown));
151
152 // With AppName
153 ASSERT_DOC_OK(kApplication << BSON(kName << "1") << kDriver
154 << BSON(kName << "n1" << kVersion << "v1")
155 << kOperatingSystem
156 << BSON(kType << kUnknown));
157 }
158
159
160 // Positive: test with app_name spelled wrong fields
TEST(ClientMetadatTest,TestWithAppNameSpelledWrong)161 TEST(ClientMetadatTest, TestWithAppNameSpelledWrong) {
162 ASSERT_DOC_OK(kApplication << BSON("extra"
163 << "1")
164 << kDriver
165 << BSON(kName << "n1" << kVersion << "v1")
166 << kOperatingSystem
167 << BSON(kType << kUnknown));
168 }
169
170 // Positive: test with empty application document
TEST(ClientMetadatTest,TestWithEmptyApplication)171 TEST(ClientMetadatTest, TestWithEmptyApplication) {
172 ASSERT_DOC_OK(kApplication << BSONObj() << kDriver << BSON(kName << "n1" << kVersion << "v1")
173 << kOperatingSystem
174 << BSON(kType << kUnknown));
175 }
176
177 // Negative: test with appplication wrong type
TEST(ClientMetadatTest,TestNegativeWithAppNameWrongType)178 TEST(ClientMetadatTest, TestNegativeWithAppNameWrongType) {
179 ASSERT_DOC_NOT_OK(kApplication << "1" << kDriver << BSON(kName << "n1" << kVersion << "v1")
180 << kOperatingSystem
181 << BSON(kType << kUnknown));
182 }
183
184 // Positive: test with extra fields
TEST(ClientMetadatTest,TestExtraFields)185 TEST(ClientMetadatTest, TestExtraFields) {
186 ASSERT_DOC_OK(kApplication << BSON(kName << "1"
187 << "extra"
188 << "v1")
189 << kDriver
190 << BSON(kName << "n1" << kVersion << "v1")
191 << kOperatingSystem
192 << BSON(kType << kUnknown));
193 ASSERT_DOC_OK(kApplication << BSON(kName << "1"
194 << "extra"
195 << "v1")
196 << kDriver
197 << BSON(kName << "n1" << kVersion << "v1"
198 << "extra"
199 << "v1")
200 << kOperatingSystem
201 << BSON(kType << kUnknown));
202 ASSERT_DOC_OK(kApplication << BSON(kName << "1"
203 << "extra"
204 << "v1")
205 << kDriver
206 << BSON(kName << "n1" << kVersion << "v1")
207 << kOperatingSystem
208 << BSON(kType << kUnknown << "extra"
209 << "v1"));
210 ASSERT_DOC_OK(kApplication << BSON(kName << "1"
211 << "extra"
212 << "v1")
213 << kDriver
214 << BSON(kName << "n1" << kVersion << "v1")
215 << kOperatingSystem
216 << BSON(kType << kUnknown)
217 << "extra"
218 << "v1");
219 }
220
221 // Negative: only application specified
TEST(ClientMetadatTest,TestNegativeOnlyApplication)222 TEST(ClientMetadatTest, TestNegativeOnlyApplication) {
223 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << "1"
224 << "extra"
225 << "v1"));
226 }
227
228 // Negative: all combinations of only missing 1 required field
TEST(ClientMetadatTest,TestNegativeMissingRequiredOneField)229 TEST(ClientMetadatTest, TestNegativeMissingRequiredOneField) {
230 ASSERT_DOC_NOT_OK(kDriver << BSON(kVersion << "v1") << kOperatingSystem
231 << BSON(kType << kUnknown));
232 ASSERT_DOC_NOT_OK(kDriver << BSON(kName << "n1") << kOperatingSystem
233 << BSON(kType << kUnknown));
234 ASSERT_DOC_NOT_OK(kDriver << BSON(kName << "n1" << kVersion << "v1"));
235 }
236
237 // Negative: document with wrong types for required fields
TEST(ClientMetadatTest,TestNegativeWrongTypes)238 TEST(ClientMetadatTest, TestNegativeWrongTypes) {
239 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << 1) << kDriver
240 << BSON(kName << "n1" << kVersion << "v1")
241 << kOperatingSystem
242 << BSON(kType << kUnknown));
243 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << "1") << kDriver
244 << BSON(kName << 1 << kVersion << "v1")
245 << kOperatingSystem
246 << BSON(kType << kUnknown));
247 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << "1") << kDriver
248 << BSON(kName << "n1" << kVersion << 1)
249 << kOperatingSystem
250 << BSON(kType << kUnknown));
251 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << "1") << kDriver
252 << BSON(kName << "n1" << kVersion << "v1")
253 << kOperatingSystem
254 << BSON(kType << 1));
255 }
256
257 // Negative: document larger than 512 bytes
TEST(ClientMetadatTest,TestNegativeLargeDocument)258 TEST(ClientMetadatTest, TestNegativeLargeDocument) {
259 bool savedMongos = isMongos();
260 auto unsetMongoS = MakeGuard(&setMongos, savedMongos);
261
262 setMongos(true);
263 {
264 std::string str(350, 'x');
265 ASSERT_DOC_OK(kApplication << BSON(kName << "1") << kDriver
266 << BSON(kName << "n1" << kVersion << "1")
267 << kOperatingSystem
268 << BSON(kType << kUnknown)
269 << "extra"
270 << str);
271 }
272 {
273 std::string str(512, 'x');
274 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << "1") << kDriver
275 << BSON(kName << "n1" << kVersion << "1")
276 << kOperatingSystem
277 << BSON(kType << kUnknown)
278 << "extra"
279 << str);
280 }
281 }
282
283 // Negative: document with app_name larger than 128 bytes
TEST(ClientMetadatTest,TestNegativeLargeAppName)284 TEST(ClientMetadatTest, TestNegativeLargeAppName) {
285 {
286 std::string str(128, 'x');
287 ASSERT_DOC_OK(kApplication << BSON(kName << str) << kDriver
288 << BSON(kName << "n1" << kVersion << "1")
289 << kOperatingSystem
290 << BSON(kType << kUnknown));
291
292 BSONObjBuilder builder;
293 ASSERT_OK(ClientMetadata::serialize("n1", "1", str, &builder));
294 }
295 {
296 std::string str(129, 'x');
297 ASSERT_DOC_NOT_OK(kApplication << BSON(kName << str) << kDriver
298 << BSON(kName << "n1" << kVersion << "1")
299 << kOperatingSystem
300 << BSON(kType << kUnknown));
301
302 BSONObjBuilder builder;
303 ASSERT_NOT_OK(ClientMetadata::serialize("n1", "1", str, &builder));
304 }
305 }
306
307 // Serialize and attach mongos information
TEST(ClientMetadatTest,TestMongoSAppend)308 TEST(ClientMetadatTest, TestMongoSAppend) {
309 BSONObjBuilder builder;
310 ASSERT_OK(ClientMetadata::serializePrivate("a", "b", "c", "d", "e", "f", "g", &builder));
311
312 auto obj = builder.obj();
313 auto swParseStatus = ClientMetadata::parse(obj[kMetadataDoc]);
314 ASSERT_OK(swParseStatus.getStatus());
315 ASSERT_EQUALS("g", swParseStatus.getValue().get().getApplicationName());
316
317 swParseStatus.getValue().get().setMongoSMetadata("h", "i", "j");
318 ASSERT_EQUALS("g", swParseStatus.getValue().get().getApplicationName());
319
320 auto doc = swParseStatus.getValue().get().getDocument();
321
322 constexpr auto kMongos = "mongos"_sd;
323 constexpr auto kClient = "client"_sd;
324 constexpr auto kHost = "host"_sd;
325
326 BSONObj outDoc =
327 BSON(kApplication << BSON(kName << "g") << kDriver << BSON(kName << "a" << kVersion << "b")
328 << kOperatingSystem
329 << BSON(kType << "c" << kName << "d" << kArchitecture << "e" << kVersion
330 << "f")
331 << kMongos
332 << BSON(kHost << "h" << kClient << "i" << kVersion << "j"));
333 ASSERT_BSONOBJ_EQ(doc, outDoc);
334 }
335
336 } // namespace mongo
337