Line data Source code
1 : #include "artdaq-database/BasicTypes/basictypes.h"
2 : #include "test/common.h"
3 :
4 : #include "artdaq-database/JsonDocument/JSONDocument.h"
5 : #include "artdaq-database/JsonDocument/JSONDocumentBuilder.h"
6 : #include "artdaq-database/StorageProviders/MongoDB/provider_mongodb.h"
7 : #include "artdaq-database/StorageProviders/storage_providers.h"
8 :
9 : #include <bsoncxx/json.hpp>
10 :
11 : namespace bpo = boost::program_options;
12 : using namespace artdaq::database;
13 :
14 : using artdaq::database::docrecord::JSONDocument;
15 : using artdaq::database::docrecord::JSONDocumentBuilder;
16 : namespace ovl = artdaq::database::overlay;
17 :
18 : using test_case = bool (*)(const std::string&, const std::string&, const std::string&);
19 :
20 : bool test_insert(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*filter*/);
21 : bool test_search1(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*filter*/);
22 : bool test_search2(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*options*/);
23 : bool test_update(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*update*/);
24 : bool test_search_collection(std::string const& /*source*/, std::string const& /*compare*/, std::string const& /*options*/);
25 :
26 5 : int main(int argc, char* argv[]) try {
27 5 : artdaq::database::mongo::debug::enable();
28 : // artdaq::database::docrecord::debug::JSONDocument();
29 :
30 5 : debug::registerUngracefullExitHandlers();
31 5 : artdaq::database::useFakeTime(true);
32 :
33 5 : std::ostringstream descstr;
34 : descstr << argv[0]
35 : << " <-s <source-file>> <-c <compare-with-file>> <-t <test-name>> [<-o <options file>>] "
36 5 : "(available test names: insert,search1,search1,update)";
37 :
38 5 : bpo::options_description desc = descstr.str();
39 :
40 5 : desc.add_options()("source,s", bpo::value<std::string>(), "Input source file.")("compare,c", bpo::value<std::string>(), "Expected result.")(
41 5 : "testname,t", bpo::value<std::string>(), "Test name.")("options,o", bpo::value<std::string>(), "Test options file.")
42 :
43 5 : ("help,h", "produce help message");
44 :
45 5 : bpo::variables_map vm;
46 :
47 : try {
48 5 : bpo::store(bpo::command_line_parser(argc, argv).options(desc).run(), vm);
49 5 : bpo::notify(vm);
50 0 : } catch (bpo::error const& e) {
51 0 : std::cerr << "Exception from command line processing in " << argv[0] << ": " << e.what() << "\n";
52 0 : return process_exit_code::INVALID_ARGUMENT;
53 0 : }
54 :
55 10 : if (vm.count("help") != 0u) {
56 0 : std::cout << desc << std::endl;
57 0 : return process_exit_code::HELP;
58 : }
59 :
60 10 : if (vm.count("source") == 0u) {
61 : std::cerr << "Exception from command line processing in " << argv[0] << ": no source file given.\n"
62 : << "For usage and an options list, please do '" << argv[0] << " --help"
63 0 : << "'.\n";
64 0 : return process_exit_code::INVALID_ARGUMENT | 1;
65 : }
66 :
67 10 : if (vm.count("compare") == 0u) {
68 : std::cerr << "Exception from command line processing in " << argv[0] << ": no compare file given.\n"
69 : << "For usage and an options list, please do '" << argv[0] << " --help"
70 0 : << "'.\n";
71 0 : return process_exit_code::INVALID_ARGUMENT | 2;
72 : }
73 :
74 10 : if (vm.count("testname") == 0u) {
75 : std::cerr << "Exception from command line processing in " << argv[0] << ": no test name given.\n"
76 : << "For usage and an options list, please do '" << argv[0] << " --help"
77 0 : << "'.\n";
78 0 : return process_exit_code::INVALID_ARGUMENT | 3;
79 : }
80 :
81 10 : auto input_name = vm["source"].as<std::string>();
82 10 : auto compare_name = vm["compare"].as<std::string>();
83 5 : auto test_name = vm["testname"].as<std::string>();
84 :
85 5 : auto input = std::string{};
86 5 : db::read_buffer_from_file(input, input_name);
87 :
88 5 : auto compare = std::string{};
89 5 : db::read_buffer_from_file(compare, compare_name);
90 :
91 5 : auto options = std::string();
92 :
93 10 : if (vm.count("options") != 0u) {
94 3 : auto opts_name = vm["options"].as<std::string>();
95 :
96 3 : db::read_buffer_from_file(options, opts_name);
97 3 : }
98 :
99 5 : auto runTest = [](std::string const& name) {
100 : auto tests = std::map<std::string, test_case>{
101 : {"insert", test_insert},
102 : {"update", test_update},
103 : {"search1", test_search1},
104 : {"search2", test_search2},
105 : {"search_collection", test_search_collection},
106 35 : };
107 :
108 5 : std::cout << "Running test:<" << name << ">\n";
109 :
110 10 : return tests.at(name);
111 10 : };
112 :
113 5 : auto testResult = runTest(test_name)(input, compare, options);
114 :
115 5 : if (testResult) {
116 5 : return process_exit_code::SUCCESS;
117 : }
118 :
119 0 : return process_exit_code::FAILURE;
120 5 : } catch (...) {
121 0 : std::cerr << "Process exited with error: " << ::debug::current_exception_diagnostic_information();
122 0 : return process_exit_code::UNCAUGHT_EXCEPTION;
123 0 : }
124 :
125 1 : bool test_insert(std::string const& source, std::string const& compare, std::string const& filter) {
126 1 : confirm(!source.empty());
127 1 : confirm(!compare.empty());
128 :
129 : // validate source
130 1 : auto insert = JSONDocument(source);
131 :
132 : // validate compare
133 1 : auto cmpdoc = JSONDocument(compare);
134 :
135 : using artdaq::database::basictypes::JsonData;
136 :
137 : namespace DBI = artdaq::database::mongo;
138 :
139 1 : auto config = DBI::DBConfig{};
140 1 : auto database = DBI::DB::create(config);
141 1 : auto provider = DBI::DBProvider<JSONDocument>::create(database);
142 :
143 1 : auto collection = std::string("testJSON_V001");
144 :
145 1 : auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
146 :
147 1 : auto object_id = provider->writeDocument(json);
148 :
149 1 : auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? object_id : filter) + ", \"collection\":\"" + collection + "\"}"};
150 :
151 1 : std::cout << "Search criteria " << search << "\n";
152 :
153 1 : auto results = provider->readDocument(search);
154 :
155 1 : if (results.size() != 1) {
156 0 : std::cout << "Search returned " << results.size() << " results.\n";
157 :
158 0 : for (auto&& element : results) {
159 0 : std::cout << element << "\n";
160 : }
161 0 : return false;
162 : }
163 :
164 1 : auto retdoc = JSONDocument{*results.begin()};
165 1 : JSONDocumentBuilder returned{retdoc};
166 1 : JSONDocumentBuilder expected{cmpdoc};
167 :
168 : using namespace artdaq::database::overlay;
169 1 : ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
170 : DOCUMENT_COMPARE_MUTE_COLLECTION);
171 :
172 1 : auto result = returned == expected;
173 :
174 1 : if (result.first) {
175 1 : return true;
176 : }
177 :
178 0 : std::cout << "Error returned!=expected.\n";
179 0 : std::cerr << "returned:\n" << returned << "\n";
180 0 : std::cerr << "expected:\n" << expected << "\n";
181 0 : std::cerr << "error:\n" << result.second << "\n";
182 0 : return false;
183 1 : }
184 :
185 1 : bool test_search1(std::string const& source, std::string const& compare, std::string const& filter) {
186 1 : confirm(!source.empty());
187 1 : confirm(!compare.empty());
188 :
189 : // validate source
190 1 : auto insert = JSONDocument(source);
191 :
192 : // validate compare
193 1 : auto cmpdoc = JSONDocument(compare);
194 :
195 : using artdaq::database::docrecord::JSONDocument;
196 :
197 : namespace DBI = artdaq::database::mongo;
198 :
199 1 : auto config = DBI::DBConfig{};
200 1 : auto database = DBI::DB::create(config);
201 1 : auto provider = DBI::DBProvider<JSONDocument>::create(database);
202 :
203 1 : auto collection = std::string("testJSON_V001");
204 :
205 1 : auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
206 :
207 1 : auto object_id = provider->writeDocument(json);
208 :
209 1 : auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? object_id : filter) + ", \"collection\":\"" + collection + "\"}"};
210 :
211 1 : std::cout << "Search criteria " << search << "\n";
212 :
213 1 : auto results = provider->readDocument(search);
214 :
215 1 : if (results.size() != 1) {
216 0 : std::cout << "Search returned " << results.size() << " results.\n";
217 :
218 0 : for (auto&& element : results) {
219 0 : std::cout << element << "\n";
220 : }
221 0 : return false;
222 : }
223 :
224 1 : auto retdoc = JSONDocument{*results.begin()};
225 1 : JSONDocumentBuilder returned{retdoc};
226 1 : JSONDocumentBuilder expected{cmpdoc};
227 :
228 : using namespace artdaq::database::overlay;
229 1 : ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
230 : DOCUMENT_COMPARE_MUTE_COLLECTION);
231 :
232 1 : auto result = returned == expected;
233 :
234 1 : if (result.first) {
235 1 : return true;
236 : }
237 :
238 0 : std::cout << "Error returned!=expected.\n";
239 0 : std::cerr << "returned:\n" << returned << "\n";
240 0 : std::cerr << "expected:\n" << expected << "\n";
241 0 : std::cerr << "error:\n" << result.second << "\n";
242 0 : return false;
243 1 : }
244 :
245 1 : bool test_search2(std::string const& source, std::string const& compare, std::string const& options [[gnu::unused]]) {
246 1 : confirm(!source.empty());
247 1 : confirm(!compare.empty());
248 :
249 : using artdaq::database::docrecord::JSONDocument;
250 :
251 : namespace DBI = artdaq::database::mongo;
252 :
253 1 : auto config = DBI::DBConfig{};
254 1 : auto database = DBI::DB::create(config);
255 1 : auto provider = DBI::DBProvider<JSONDocument>::create(database);
256 :
257 1 : auto collection = std::string("testJSON_V001");
258 :
259 1 : auto json = JSONDocument{"{\"document\":" + source + ", \"collection\":\"" + collection + "\"}"};
260 :
261 1 : auto repeatCount = std::size_t{10};
262 :
263 1 : auto object_ids = std::vector<std::string>();
264 :
265 1 : std::ostringstream oss;
266 1 : oss << R"({"_id" : { "$in" : [)";
267 :
268 1 : auto nodata_pos = oss.tellp();
269 :
270 11 : for (int i = repeatCount; i != 0; i--) {
271 10 : auto object_id = provider->writeDocument(json);
272 10 : object_ids.push_back(object_id);
273 30 : oss << JSONDocument(object_id).findChildDocument("_id").to_string() << ",";
274 10 : }
275 :
276 1 : if (oss.tellp() != nodata_pos) {
277 1 : oss.seekp(-1, oss.cur);
278 : }
279 :
280 1 : oss << "]} }";
281 :
282 1 : auto filter = oss.str();
283 :
284 1 : auto search = JSONDocument{"{\"filter\":" + (filter.empty() ? options : filter) + ", \"collection\":\"" + collection + "\"}"};
285 :
286 1 : std::cout << "Search criteria " << search << "\n";
287 :
288 1 : auto results = provider->readDocument(search);
289 :
290 1 : if (results.size() != repeatCount) {
291 0 : std::cout << "Search returned " << results.size() << " results.\n";
292 :
293 0 : for (auto&& element : results) {
294 0 : std::cout << element << "\n";
295 : }
296 0 : return false;
297 : }
298 :
299 1 : return true;
300 1 : }
301 :
302 1 : bool test_search_collection(std::string const& source, std::string const& compare, std::string const& options [[gnu::unused]]) {
303 1 : confirm(!source.empty());
304 1 : confirm(!compare.empty());
305 :
306 : using artdaq::database::docrecord::JSONDocument;
307 :
308 : namespace DBI = artdaq::database::mongo;
309 :
310 1 : auto config = DBI::DBConfig{};
311 1 : auto database = DBI::DB::create(config);
312 1 : auto provider = DBI::DBProvider<JSONDocument>::create(database);
313 :
314 1 : auto collection = std::string("testJSON_V002");
315 :
316 1 : auto repeatCount = std::size_t{5};
317 :
318 1 : auto object_ids = std::vector<std::string>();
319 :
320 1 : std::ostringstream oss;
321 1 : oss << R"({"_id" : { "$in" : [)";
322 :
323 1 : auto nodata_pos = oss.tellp();
324 :
325 6 : for (int i = repeatCount; i != 0; i--) {
326 5 : auto version_str = "version_search_" + std::to_string(i);
327 5 : auto json = JSONDocument{"{\"document\":" + source + ", \"version\":\"" + version_str + "\", \"collection\":\"" + collection + "\"}"};
328 5 : auto object_id = provider->writeDocument(json);
329 5 : object_ids.push_back(object_id);
330 15 : oss << JSONDocument(object_id).findChildDocument("_id").to_string() << ",";
331 5 : }
332 :
333 1 : if (oss.tellp() != nodata_pos) {
334 1 : oss.seekp(-1, oss.cur);
335 : }
336 :
337 1 : oss << "]} }";
338 :
339 1 : auto filter = oss.str();
340 :
341 1 : auto search = JSONDocument{"{\"filter\":" + (options.empty() ? filter : options) + ", \"collection\":\"" + collection + "\"}"};
342 :
343 1 : std::cout << "Search criteria " << search << "\n";
344 :
345 1 : auto results = provider->searchCollection(search);
346 :
347 1 : if (results.size() != repeatCount) {
348 0 : std::cout << "Search returned " << results.size() << " results.\n";
349 :
350 0 : for (auto&& element : results) {
351 0 : std::cout << element << "\n";
352 : }
353 0 : return false;
354 : }
355 :
356 1 : return true;
357 1 : }
358 :
359 1 : bool test_update(std::string const& source, std::string const& compare, std::string const& update) {
360 1 : confirm(!source.empty());
361 1 : confirm(!compare.empty());
362 :
363 : // validate source
364 1 : auto insert = JSONDocument(source);
365 :
366 : // validate compare
367 1 : auto cmpdoc = JSONDocument(compare);
368 :
369 1 : auto updates = JSONDocument(update);
370 :
371 : using artdaq::database::docrecord::JSONDocument;
372 :
373 : namespace DBI = artdaq::database::mongo;
374 :
375 1 : auto config = DBI::DBConfig{};
376 1 : auto database = DBI::DB::create(config);
377 1 : auto provider = DBI::DBProvider<JSONDocument>::create(database);
378 :
379 1 : auto collection = std::string("testJSON_V001");
380 :
381 1 : auto json = JSONDocument{"{\"document\":" + insert.to_string() + ", \"collection\":\"" + collection + "\"}"};
382 :
383 1 : auto object_id = provider->writeDocument(json);
384 :
385 1 : auto search = JSONDocument{"{\"filter\":" + object_id + ", \"collection\":\"" + collection + "\"}"};
386 :
387 1 : std::cout << "Search criteria " << search << "\n";
388 :
389 1 : auto results = provider->readDocument(search);
390 :
391 1 : if (results.size() != 1) {
392 0 : std::cout << "Search returned " << results.size() << " results.\n";
393 :
394 0 : for (auto&& element : results) {
395 0 : std::cout << element << "\n";
396 : }
397 0 : return false;
398 : }
399 :
400 1 : auto found = JSONDocument{*results.begin()};
401 :
402 1 : std::cout << "Update candidate=<" << found.to_string() << ">\n";
403 1 : auto displaced = found.replaceChild(updates, "document");
404 1 : std::cout << "Update result=<" << found.to_string() << ">\n";
405 1 : std::cout << "Displaced value=<" << displaced.to_string() << ">\n";
406 :
407 1 : json = JSONDocument{"{\"document\":" + found.to_string() + ", \"filter\":" + object_id + ",\"collection\":\"" + collection + "\"}"};
408 :
409 1 : object_id = provider->writeDocument(json);
410 1 : search = JSONDocument{"{\"filter\":" + object_id + ", \"collection\":\"" + collection + "\"}"};
411 :
412 1 : results = provider->readDocument(search);
413 :
414 1 : if (results.size() != 1) {
415 0 : std::cout << "Search returned " << results.size() << " results.\n";
416 :
417 0 : for (auto&& element : results) {
418 0 : std::cout << element << "\n";
419 : }
420 0 : return false;
421 : }
422 :
423 1 : auto retdoc = JSONDocument{*results.begin()};
424 :
425 1 : JSONDocumentBuilder returned{retdoc};
426 1 : JSONDocumentBuilder expected{cmpdoc};
427 :
428 : using namespace artdaq::database::overlay;
429 1 : ovl::useCompareMask(DOCUMENT_COMPARE_MUTE_TIMESTAMPS | DOCUMENT_COMPARE_MUTE_OUIDS | DOCUMENT_COMPARE_MUTE_UPDATES |
430 : DOCUMENT_COMPARE_MUTE_COLLECTION);
431 :
432 1 : auto result = returned == expected;
433 :
434 1 : if (result.first) {
435 1 : return true;
436 : }
437 :
438 0 : std::cout << "Error returned!=expected.\n";
439 0 : std::cerr << "returned:\n" << returned << "\n";
440 0 : std::cerr << "expected:\n" << expected << "\n";
441 0 : std::cerr << "error:\n" << result.second << "\n";
442 0 : return false;
443 1 : }
|