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