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